Parent : [[INDEX-FIVEM-GAMEPLAY]]
FiveM - Motel IPL + Stash : ox_inventory RegisterStash, achat, society percentage, raid
Problème
Un système de motel nécessite : intérieurs IPL, stockage d'items par chambre, achat avec 2 modes de paiement, commission société, et possibilité de raid par le staff/police.
Solution
Insertion DB pour persistence, ox_inventory:RegisterStash dynamique par chambre, 2 modes de paiement (cash/bank), commission automatique vers la société, et webhook logging.
-- Achat chambre
RegisterNetEvent('pw-motel:buyRoom')
AddEventHandler('pw-motel:buyRoom', function(motelId, roomNumber, days, paymentMethod)
local src = source
local xPlayer = ESX.GetPlayerFromId(src)
local identifier = xPlayer.getIdentifier()
local motel = Config.Motels[motelId]
local pricePerDay = motel.price
local totalPrice = pricePerDay * days
-- Vérification paiement
if paymentMethod == 'cash' then
if xPlayer.getMoney() < totalPrice then
TriggerClientEvent('ox_lib:notify', src, { type = 'error', description = 'Fonds insuffisants' })
return
end
xPlayer.removeMoney(totalPrice)
elseif paymentMethod == 'bank' then
if xPlayer.getAccount('bank').money < totalPrice then
TriggerClientEvent('ox_lib:notify', src, { type = 'error', description = 'Fonds bancaires insuffisants' })
return
end
xPlayer.removeAccountMoney('bank', totalPrice)
end
-- Insertion BDD
MySQL.insert('INSERT INTO motel (owner, labelMotel, numberChambre, day, expire) VALUES (?, ?, ?, ?, ?)', {
identifier,
motel.label,
roomNumber,
days,
os.time() + (days * 86400)
}, function(insertId)
if insertId then
-- Registration du stash ox_inventory
local stashName = ('motel_%s_%s'):format(motelId, roomNumber)
exports.ox_inventory:RegisterStash(
stashName,
('Chambre %s - %s'):format(roomNumber, motel.label),
motel.slots or 50,
motel.maxWeight or 100000,
false,
false
)
-- Commission société (optionnel)
if Config.pourcentageSociety then
TriggerEvent('esx_addonaccount:getSharedAccount', Config.societyname, function(account)
local commission = math.floor(totalPrice * (Config.pourcentage / 100))
account.addMoney(commission)
end)
end
-- Logging webhook
SendWebhook('Motel Purchase', ('%s a acheté chambre %s à %s pour $%s (%s jours)'):format(
xPlayer.getName(), roomNumber, motel.label, totalPrice, days
))
TriggerClientEvent('pw-motel:purchaseSuccess', src, motelId, roomNumber)
end
end)
end)
-- Raid staff/police
RegisterNetEvent('pw-motel:raidRoom')
AddEventHandler('pw-motel:raidRoom', function(motelId, roomNumber)
local src = source
local xPlayer = ESX.GetPlayerFromId(src)
-- Vérification permission
local hasPermission = false
if Config.RaidPermission.job then
if Config.RaidPermission.jobs[xPlayer.job.name] and
xPlayer.job.grade >= Config.RaidPermission.jobs[xPlayer.job.name] then
hasPermission = true
end
end
if Config.RaidPermission.ace and IsPlayerAceAllowed(src, 'motel.raid') then
hasPermission = true
end
if not hasPermission then
TriggerClientEvent('ox_lib:notify', src, { type = 'error', description = 'Permission insuffisante' })
return
end
-- Ouverture du stash en raid
local stashName = ('motel_%s_%s'):format(motelId, roomNumber)
exports.ox_inventory:forceOpenInventory(src, 'stash', stashName)
SendWebhook('Motel Raid', ('%s (%s) a forcé la chambre %s de %s'):format(
xPlayer.getName(), xPlayer.job.name, roomNumber, Config.Motels[motelId].label
))
end)
Pourquoi
ox_inventory:RegisterStashcrée un stockage unique par chambre sans thread custom- Commission société crée une économie de service
- Expiration timestamp permet le renouvellement automatique
Quand l'utiliser
- Motels, appartements, garages, stockages de gang
- Tout système de location avec stockage
Quand NE PAS l'utiliser
- Stockages globaux (pas de propriété) → ox_inventory stashes classiques suffisent
Exemples
Correct
-- Cleanup des stashes expirés (cron ou au démarrage)
CreateThread(function()
while true do
Wait(3600000) -- Toutes les heures
local expired = MySQL.query.await('SELECT * FROM motel WHERE expire < ?', { os.time() })
for _, room in ipairs(expired) do
local stashName = ('motel_%s_%s'):format(room.motelId, room.numberChambre)
-- Vider le stash avant suppression
local stashItems = exports.ox_inventory:GetInventoryItems(stashName)
for _, item in ipairs(stashItems or {}) do
exports.ox_inventory:RemoveItem(stashName, item.name, item.count)
end
MySQL.update('DELETE FROM motel WHERE id = ?', { room.id })
SendWebhook('Motel Expired', ('Chambre %s expirée et nettoyée'):format(room.numberChambre))
end
end
end)
Incorrect
-- Pas de vérification du propriétaire → n'importe qui ouvre le stash
RegisterNetEvent('motel:openStash')
AddEventHandler('motel:openStash', function(stashName)
exports.ox_inventory:forceOpenInventory(source, 'stash', stashName)
end)
Références
- pw-motel/server/server.lua L26-91
- pw-motel/config/config.lua L70+
- REF-003 (ox_inventory documentation)