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.
| Obiettivo | Dettagli |
|---|---|
| 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
pricedal client. Anche se sembra banale, è il pattern che permette di comprare item a 1$ inviandoprice = 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)
endTrading 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
ownercombaci 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
-
sourceverificato in ogni evento economico - Inventario manipolato solo tramite API framework
- Veicoli spawnati solo se
ownercombacia - Job/grado validati server-side
- Log delle transazioni importanti
TIP
Prossimo passo: 04 - Anti-Cheat e Configurazione
Torna alla: Indice Generale