Parent : [[INDEX-FIVEM-FRAMEWORK]]
FiveM - Status Persistence JSON : sauvegarde/restauration d'état joueur en MySQL
Problème
Les états joueur (faim, soif, stress, saleté) doivent persister entre les sessions de jeu. Sans persistence, le joueur recommence à zéro à chaque connexion.
Solution
Sauvegarde/restauration d'état joueur en JSON dans MySQL, chargé sur esx:playerLoaded, sauvegardé sur esx:playerDropped.
-- Chargement au spawn
AddEventHandler('esx:playerLoaded', function(src, xPlayer)
local status = MySQL.scalar.await('SELECT status FROM users WHERE identifier = ?', {
xPlayer.getIdentifier()
})
status = status and json.decode(status) or {}
xPlayer.set('status', status)
TriggerClientEvent('esx_status:load', xPlayer.source, status)
end)
-- Sauvegarde à la déconnexion
AddEventHandler('esx:playerDropped', function(src, reason)
local xPlayer = ESX.Player(src)
if not xPlayer then return end
local status = xPlayer.get('status') or {}
MySQL.update('UPDATE users SET status = ? WHERE identifier = ?', {
json.encode(status),
xPlayer.getIdentifier()
})
end)
-- Tick périodique (toutes les 5 minutes)
CreateThread(function()
while true do
Wait(300000)
local players = ESX.GetPlayers()
for i = 1, #players do
local xPlayer = ESX.GetPlayerFromId(players[i])
local status = xPlayer.get('status') or {}
MySQL.update('UPDATE users SET status = ? WHERE identifier = ?', {
json.encode(status),
xPlayer.getIdentifier()
})
end
end
end)
Pourquoi
- JSON permet de stocker un objet arbitraire (faim, soif, stress, maladie, addictions) dans une seule colonne
scalar.awaitévite les callbacks imbriqués- Sauvegarde périodique + au drop garantit la cohérence même en cas de crash
Quand l'utiliser
- Besoins complexes (faim/soif/stress/santé mentale)
- Systèmes de progression long terme (gym, addiction, fatigue)
Quand NE PAS l'utiliser
- Un seul statut simple → colonne dédiée (
hunger INT) plus performante - Si les stats ne doivent pas persister (death reset)
Exemples
Correct
-- Structure JSON extensible
{
"hunger": 85,
"thirst": 72,
"stress": 15,
"hygiene": 90,
"addictions": {
"alcohol": 0.2,
"nicotine": 0.05
}
}
Incorrect
-- Pas de await → race condition au spawn
AddEventHandler('esx:playerLoaded', function(src, xPlayer)
MySQL.query('SELECT status FROM users WHERE identifier = ?', {xPlayer.getIdentifier()}, function(result)
-- Le joueur peut déjà être en jeu avant que ce callback ne resolve
TriggerClientEvent('esx_status:load', src, result[1].status)
end)
end)
Références
- esx_status/server/main.lua L1-50