Proteggere Economia e Item

INFO

Denaro, item e veicoli sono le risorse più attaccate in un server RP. Questa nota raccoglie i pattern sicuri per gestirli.

ObiettivoDettagli
Cosa imparerai• Pattern sicuri per soldi e acquisti
• Gestione inventario e trading
• Proteggere spawn veicoli
• Logging degli eventi economici
Prerequisiti• Validazione eventi (nota 12/02)
• ESX o framework con inventario

1. Denaro: Mai Calcolato dal Client

Non sicuro ❌

RegisterNetEvent('payday:setMoney')
AddEventHandler('payday:setMoney', function(amount)
    local xPlayer = ESX.GetPlayerFromId(source)
    xPlayer.setMoney(amount)   -- L'attaccante invia amount = 999999
end)

Sicuro ✅ — Il server decide

-- Il server conosce il job e il suo stipendio
RegisterNetEvent('payday:claim')
AddEventHandler('payday:claim', function()
    local xPlayer = ESX.GetPlayerFromId(source)
    local job = xPlayer.getJob()
    local salary = Config.Jobs[job.name].salary or 0
    xPlayer.addMoney(salary)
end)

2. Acquisti: Prezzo dal Server

Pattern “server-only”

-- Il client manda SOLO quale item vuole, il server sa il prezzo
RegisterNetEvent('shop:buy')
AddEventHandler('shop:buy', function(item)
    local xPlayer = ESX.GetPlayerFromId(source)
    if not xPlayer then return end
    if type(item) ~= 'string' then return end
 
    local shopItem = Config.Shop[item]
    if not shopItem then return end
 
    local price = shopItem.price   -- prezzo da config, non dal client!
    if xPlayer.getAccount('money').money >= price then
        xPlayer.removeAccountMoney('money', price)
        xPlayer.addInventoryItem(item, 1)
    end
end)

WARNING

Mai ricevere price dal client. Anche se sembra banale, è il pattern che permette di comprare item a 1$ inviando price = 1.


3. Inventario: Usa le API del Framework

Con ox_inventory le transazioni sono già server-side validate. Usa le sue export invece di scrivere logica tua.

-- Aggiungere item (ritorna quantità effettiva)
local added = exports.ox_inventory:AddItem(source, 'apple', 1)
if added < 1 then
    -- Inventario pieno: gestisci
end
 
-- Controllare presenza
local count = exports.ox_inventory:Search(source, 'count', 'apple')
if count >= 3 then
    exports.ox_inventory:RemoveItem(source, 'apple', 3)
end

Trading Sicuro

-- server.lua
RegisterNetEvent('trade:sendItem')
AddEventHandler('trade:sendItem', function(target, item, quantity)
    local sender = source
    local xPlayer = ESX.GetPlayerFromId(sender)
    local tPlayer = ESX.GetPlayerFromId(target)
    if not xPlayer or not tPlayer then return end
 
    quantity = tonumber(quantity) or 1
    if quantity < 1 then return end
    if type(item) ~= 'string' then return end
 
    -- Verifica che il mittente abbia davvero l'item
    if xPlayer.getInventoryItem(item).count < quantity then return end
 
    -- Rimuovi dal mittente, aggiungi al destinatario
    xPlayer.removeInventoryItem(item, quantity)
    tPlayer.addInventoryItem(item, quantity)
end)

4. Spawn Veicoli: Solo Se Posseduto

-- server.lua
RegisterNetEvent('garage:spawn')
AddEventHandler('garage:spawn', function(plate)
    local xPlayer = ESX.GetPlayerFromId(source)
    if not xPlayer then return end
    if type(plate) ~= 'string' then return end
 
    -- Verifica che il veicolo appartenga davvero al giocatore
    MySQL.query('SELECT * FROM owned_vehicles WHERE plate = ? AND owner = ?', {
        plate, xPlayer.identifier
    }, function(result)
        if result[1] then
            -- Solo se esiste una riga con owner = giocatore
            TriggerClientEvent('garage:spawnClient', source, result[1].vehicle)
        end
    end)
end)

WARNING

Mai spawnare un veicolo in base alla targa inviata dal client senza verificare che owner combaci con il giocatore.


5. Job e Gradi

-- Il server valida job e grado (non il client)
RegisterNetEvent('police:takeArmour')
AddEventHandler('police:takeArmour', function()
    local xPlayer = ESX.GetPlayerFromId(source)
    if not xPlayer then return end
 
    local job = xPlayer.getJob()
    if job.name ~= 'police' then return end
    if job.grade < 2 then return end
 
    xPlayer.addInventoryItem('armour', 1)
end)

6. Logging e Audit

Logga le transazioni importanti per individuare exploit e contestazioni.

-- server.lua
local function logEconomy(playerId, action, detail)
    local name = GetPlayerName(playerId)
    print(('[ECONOMY] %s (%s) -> %s: %s'):format(name, playerId, action, detail))
    -- Oppure invia a un webhook Discord (nota 14)
end
 
RegisterNetEvent('shop:buy')
AddEventHandler('shop:buy', function(item)
    -- ... acquisto ...
    logEconomy(source, 'shop:buy', item)
end)

Verifica

  • Nessun prezzo/quantità accettato dal client
  • source verificato in ogni evento economico
  • Inventario manipolato solo tramite API framework
  • Veicoli spawnati solo se owner combacia
  • Job/grado validati server-side
  • Log delle transazioni importanti

TIP


Torna alla: Indice Generale