Explorer
KNOW-PAT-085

FiveM - Validation en cascade activites illegales : policiers, cooldown, items

Domaine
fivem
Type
pattern
Priorité
P1

Parent : [[INDEX-FIVEM-GAMEPLAY]]

FiveM - Validation en cascade activites illegales : policiers, cooldown, items

Problème

Les activités illégales (braquages, blanchiment, vol) doivent être équilibrées : il faut assez de policiers en ligne, un délai entre deux activations, et les items requis en possession.

Solution

Validation en cascade server-side avec 4 étapes :

  1. Nombre de policiers en ligne (ESX.GetPlayers() loop)
  2. Cooldown global entre activations (os.time())
  3. Possession des items requis
  4. Notification dispatch aux policiers
local lastRob = 0

ESX.RegisterServerCallback('trainheist:checkPoliceCount', function(source, cb)
    local policeCount = 0
    local players = ESX.GetPlayers()
    for i = 1, #players do
        local player = ESX.GetPlayerFromId(players[i])
        for k, v in pairs(Config.dispatchJobs) do
            if player.job.name == v then policeCount = policeCount + 1 end
        end
    end
    cb(policeCount >= Config.requiredPoliceCount)
end)

RegisterNetEvent('trainheist:startHeist')
AddEventHandler('trainheist:startHeist', function()
    local src = source
    local xPlayer = ESX.GetPlayerFromId(src)

    -- 1. Cooldown
    if os.time() - lastRob < Config.nextRob then
        xPlayer.showNotification('Cooldown actif')
        return
    end

    -- 2. Item requis
    if xPlayer.getInventoryItem(Config.requiredItem).count < 1 then
        xPlayer.showNotification('Item manquant')
        return
    end

    -- 3. Validation policiers
    local policeCount = 0
    local players = ESX.GetPlayers()
    for i = 1, #players do
        local p = ESX.GetPlayerFromId(players[i])
        if p.job.name == 'police' then policeCount = policeCount + 1 end
    end
    if policeCount < Config.requiredPoliceCount then
        xPlayer.showNotification('Pas assez de policiers')
        return
    end

    lastRob = os.time()
    TriggerClientEvent('trainheist:startClient', src)
    TriggerClientEvent('trainheist:alertPolice', -1)
end)

Pourquoi

  • Server-side uniquement : le client ne peut pas bypass la validation
  • Cooldown global (pas par joueur) pour éviter le spam en groupe
  • Item check empêche le lancement sans préparation

Quand l'utiliser

  • Braquages, vols, blanchiment, activités illégales PvE
  • Systèmes de mission/contract avec conditions d'activation

Quand NE PAS l'utiliser

  • Activités légales sans contrainte (farming libre)
  • Events PvP compétitifs où le cooldown global pénalise trop

Exemples

Correct

-- Cooldown global + item + police + distance
local cooldowns = {}
RegisterNetEvent('robbery:start')
AddEventHandler('robbery:start', function(storeId)
    local src = source
    if cooldowns[storeId] and os.time() - cooldowns[storeId] < Config.cooldown then
        return TriggerClientEvent('notify', src, 'Cooldown')
    end
    local cops = CountPoliceOnline()
    if cops < Config.minCops then return TriggerClientEvent('notify', src, 'Pas assez de policiers') end
    cooldowns[storeId] = os.time()
    StartRobbery(src, storeId)
end)

Incorrect

-- Validation côté client → bypassable par menu/trainer
RegisterNetEvent('robbery:start')
AddEventHandler('robbery:start', function()
    -- Le client dit "je peux braquer" → serveur fait confiance
    TriggerClientEvent('robbery:success', source)
end)

Références

  • rm_trainheist/server.lua L20-72
  • loffe_robbery/server.lua L37-55
  • moneywash-fivemroleplay/server/server.lua

Liens connexes

  • [[KNOW-ANT-FIVEM-002-client-side-validation-only|KNOW-ANT-FIVEM-002]]