Parent : [[INDEX-FIVEM-GAMEPLAY]]
FiveM - Inventory Transaction avec Validation : possession, taxe, ticket, durée
Problème
Les transactions d'inventaire (blanchiment, craft, échange) doivent vérifier que le joueur possède bien les items requis, appliquer des taxes, consommer des tickets, et respecter une durée de traitement.
Solution
Transaction server-side avec 4 validations :
- Possession :
ox_inventory:SearchougetInventoryItem - Taxe : calcul du montant final après déduction
- Ticket : consommation d'un item requis (optionnel)
- Durée :
Citizen.Waitou progress bar côté client avec vérification serveur
RegisterServerEvent('stevo_moneywash:cleanmoney')
AddEventHandler('stevo_moneywash:cleanmoney', function(Amount)
local Player = source
-- 1. Validation possession argent sale
local black_money = exports.ox_inventory:Search(Player, 'count', 'black_money')
if black_money < Amount then
TriggerClientEvent('ox_lib:notify', Player, { type = 'error', description = 'Pas assez d\'argent sale' })
return
end
-- 2. Validation ticket (optionnel)
if Config.UseTickets then
local ticket = exports.ox_inventory:Search(Player, 'count', 'moneywash_ticket')
if ticket < 1 then
TriggerClientEvent('ox_lib:notify', Player, { type = 'error', description = 'Ticket de blanchiment requis' })
return
end
exports.ox_inventory:RemoveItem(Player, 'moneywash_ticket', 1)
end
-- 3. Retrait argent sale
exports.ox_inventory:RemoveItem(Player, 'black_money', Amount)
-- 4. Durée de traitement (progressive)
local duration = math.min(Amount * Config.TimePerDollar, Config.MaxDuration)
TriggerClientEvent('stevo_moneywash:startProgress', Player, duration)
-- 5. Après durée → ajout argent propre (avec taxe)
Citizen.SetTimeout(duration, function()
local finalAmount = math.floor(Amount * (1 - Config.TaxRate))
exports.ox_inventory:AddItem(Player, 'money', finalAmount)
TriggerClientEvent('ox_lib:notify', Player, {
type = 'success',
description = ('Blanchiment terminé : $%s (taxe %d%%)'):format(finalAmount, Config.TaxRate * 100)
})
end)
end)
Pourquoi
ox_inventory:Searchest server-side et non spoofable- La taxe et le ticket créent une économie de friction réaliste
- La durée empêche le spam instantané de blanchiment
Quand l'utiliser
- Blanchiment d'argent, craft d'items illégaux
- Échanges avec intermédiaire (pawn shop, revente)
- Toute transaction où le joueur doit attendre
Quand NE PAS l'utiliser
- Transferts directs P2P (pas besoin de durée)
- Achat instantané en shop (sauf si volontairement frictionné)
Exemples
Correct
-- Transaction avec rollback si le joueur déconnecte pendant le wait
local pendingTransactions = {}
RegisterNetEvent('craft:start')
AddEventHandler('craft:start', function(item, amount)
local src = source
local cost = Config.CraftRecipes[item].materials
-- Vérification possession
for mat, qty in pairs(cost) do
if exports.ox_inventory:Search(src, 'count', mat) < qty * amount then
return TriggerClientEvent('notify', src, 'Matériaux manquants')
end
end
-- Retrait
for mat, qty in pairs(cost) do
exports.ox_inventory:RemoveItem(src, mat, qty * amount)
end
pendingTransactions[src] = { item = item, amount = amount, startTime = os.time() }
end)
AddEventHandler('playerDropped', function(reason)
local src = source
if pendingTransactions[src] then
-- Remboursement si déconnexion pendant craft
local tx = pendingTransactions[src]
for mat, qty in pairs(Config.CraftRecipes[tx.item].materials) do
exports.ox_inventory:AddItem(src, mat, qty * tx.amount)
end
pendingTransactions[src] = nil
end
end)
Incorrect
-- Le client envoie le montant → spoof possible
RegisterNetEvent('wash:finish')
AddEventHandler('wash:finish', function(amount)
-- Le client dit "j'ai blanchi 100000$" → le serveur fait confiance
exports.ox_inventory:AddItem(source, 'money', amount)
end)
Références
- moneywash-fivemroleplay/server/server.lua L1-31
- rm_trainheist/server.lua L58-72
Liens connexes
- [[KNOW-ANT-FIVEM-002-client-side-validation-only|KNOW-ANT-FIVEM-002]]