esx_status
esx_status stores and syncs player needs like hunger, thirst and drunk in ESX Legacy. Covers the server-authoritative model, config, events and examples.
esx_status is the engine behind player needs in ESX Legacy. It keeps a list of named values per player (for example hunger, thirst, drunk), saves them in users.status, decays them over time and broadcasts them to the client every tick. esx_basicneeds and esx_optionalneeds build on it, and HUDs such as esx_hud read from it.
Overview
| Fact | Value |
|---|---|
| Resource | esx_status |
| Side | Server (authoritative values, saving) and client (status objects, ticks, optional bars) |
| Dependencies | esx_lib, es_extended (oxmysql is loaded by the manifest) |
| SQL | esx_status.sql adds users.status |
| UI | Optional NUI bars (html/ui.html), off by default |
Two kinds of statuses
| Kind | Examples | Who owns the value |
|---|---|---|
| Authoritative | Statuses listed in Config.AuthoritativeStatuses (default hunger, thirst) | The server. It decays them and pushes the result to the client with esx_status:sync. |
| Custom | Everything else, for example drunk | The client. It ticks them and sends them to the server every Config.UpdateInterval. |
Since version 1.1 hunger and thirst are decided on the server. Change them with the server events. Client-side changes only last until the next sync.
Installation
Import the SQL
ALTER TABLE `users` ADD COLUMN `status` LONGTEXT NULL;Start it before resources that register statuses
ensure esx_status
ensure esx_basicneeds
ensure esx_optionalneedsConfiguration
| Key | Default | Description |
|---|---|---|
Config.StatusMax | 1000000 | Value that equals 100 percent. Values are clamped between 0 and this number on the server. |
Config.TickTime | 1000 | Client tick length in ms. Also the time unit for decay in AuthoritativeStatuses. |
Config.UpdateInterval | 30000 | How often (ms) the server syncs authoritative statuses and the client sends custom statuses. |
Config.SyncSlices | 30 | The server spreads one sync round over this many batches to avoid spikes. |
Config.MinUpdateInterval | 10000 | Minimum time (ms) between two accepted esx_status:update messages from one client. |
Config.LoadRetryInitial | 5000 | First retry delay (ms) when loading statuses fails. Doubles on each failure. |
Config.LoadRetryMax | 60000 | Upper limit for the retry delay. |
Config.Display | false | Show the built-in esx_status bars. Keep false when you use another HUD. |
Config.AuthoritativeStatuses | hunger = { default = 1000000, decay = 100 }, thirst = { default = 1000000, decay = 75 } | Statuses the server owns. default is the start value for new players, decay the amount removed per Config.TickTime. |
With the defaults, hunger drops from full to zero in about 2 hours 47 minutes (1,000,000 / 100 seconds) and thirst in about 3 hours 42 minutes.
Config.AuthoritativeStatuses = {
hunger = { default = 1000000, decay = 100 },
thirst = { default = 1000000, decay = 75 },
stress = { default = 0, decay = 0 }, -- server-owned, changed only by your scripts
}Status data shape
Every status entry sent between server and client looks like this:
| Field | Type | Description |
|---|---|---|
name | string | Unique name, 1 to 64 characters. |
val | number | Current value, 0 to Config.StatusMax. |
percent | number | val / Config.StatusMax * 100. |
A player can hold at most 64 statuses. The loaded list is also mirrored to ESX.PlayerData.variables.status on the client.
Server API
All server events below are local (AddEventHandler). Only other server scripts can trigger them.
esx_status:set
Sets a status to an exact value.
TriggerEvent('esx_status:set', playerId, name, value)| Name | Type | Description |
|---|---|---|
playerId | number | Server ID of the player. |
name | string | Status name. |
value | number | New value. Clamped to 0 … Config.StatusMax. |
-- fill hunger and thirst after a revive
TriggerEvent('esx_status:set', source, 'hunger', 1000000)
TriggerEvent('esx_status:set', source, 'thirst', 1000000)esx_status:add
Adds to a status. Use a negative value to remove.
TriggerEvent('esx_status:add', playerId, name, value)| Name | Type | Description |
|---|---|---|
playerId | number | Server ID of the player. |
name | string | Status name. |
value | number | Amount to add (negative to subtract). The result is clamped. |
ESX.RegisterUsableItem('sandwich', function(source)
local xPlayer = ESX.Player(source)
xPlayer.removeInventoryItem('sandwich', 1)
TriggerEvent('esx_status:add', source, 'hunger', 250000)
end)set and add only change a status the player already has. After the change the server sends esx_status:sync to the client right away.
esx_status:getStatus
Reads one status of a player.
TriggerEvent('esx_status:getStatus', playerId, name, cb)| Name | Type | Description |
|---|---|---|
playerId | number | Server ID. |
name | string | Status name. |
cb | function | Receives { name, val, percent }. |
TriggerEvent('esx_status:getStatus', source, 'thirst', function(status)
if status.percent < 10 then
TriggerClientEvent('esx:showNotification', source, 'You are very thirsty')
end
end)The callback is not called when the player is not loaded or does not have that status. Do not wait on it forever.
Client API
esx_status:registerStatus
Creates a status object on the client. Register custom statuses in a handler for esx_status:loaded so the saved value is applied.
TriggerEvent('esx_status:registerStatus', name, default, color, visible, tickCallback)| Name | Type | Description |
|---|---|---|
name | string | Status name. |
default | number | Start value when nothing is saved. |
color | string | CSS color for the built-in bar, for example '#CFAD0F'. |
visible | function | function(status) return boolean end. Decides if the bar is shown. Called when Config.Display is on, so always pass a function. |
tickCallback | function | function(status) end, called every Config.TickTime. Usually status.remove(x). |
AddEventHandler('esx_status:loaded', function()
TriggerEvent('esx_status:registerStatus', 'stress', 0, '#E74C3C',
function(status) return status.val > 0 end,
function(status) status.remove(500) end
)
end)If a status with the same name exists, the new object replaces it and keeps the current value.
Status object
esx_status:getStatus and esx_status:getAllStatus return status objects with these members:
| Member | Description |
|---|---|
name, val, default, color | Fields. |
set(val) | Set the value (no clamping). |
add(val) | Add, capped at Config.StatusMax. |
remove(val) | Subtract, floored at 0. |
getPercent() | Value as percent. |
onTick() | Runs the tick callback. |
_set(key, value), _get(key) | Raw field access. |
esx_status:unregisterStatus
TriggerEvent('esx_status:unregisterStatus', name)Removes the status from the client list. It stops ticking and is no longer sent to the server.
esx_status:getStatus (client)
TriggerEvent('esx_status:getStatus', name, cb)TriggerEvent('esx_status:getStatus', 'hunger', function(status)
print(('Hunger: %.1f%%'):format(status.getPercent()))
end)esx_status:getAllStatus
TriggerEvent('esx_status:getAllStatus', function(statuses)
for i = 1, #statuses do
print(statuses[i].name, statuses[i].val)
end
end)esx_status:set / add / remove (client)
TriggerEvent('esx_status:set', name, val)
TriggerEvent('esx_status:add', name, val)
TriggerEvent('esx_status:remove', name, val)These change the local status object. They are also net events, so the server can send them with TriggerClientEvent('esx_status:add', playerId, 'drunk', 250000). For custom statuses the new value reaches the server with the next update. For authoritative statuses (hunger, thirst) the change is overwritten by the next server sync, so use the server events instead.
esx_status:setDisplay
TriggerEvent('esx_status:setDisplay', 0.5)Sets the opacity of the built-in bars (0.0 hides them). Only useful with Config.Display = true.
Events you can listen to
| Event | Side | Payload | When |
|---|---|---|---|
esx_status:loaded | client | none | Saved statuses arrived from the server. Register custom statuses here. |
esx_status:onTick | client | array of { name, val, percent } | Every Config.TickTime after loading. Ideal for HUDs and effects. |
esx_status:load | client (from server) | full status list | Sent by the server after esx:playerLoaded or on request. Internal. |
esx_status:sync | client (from server) | changed entries | Server pushes authoritative values. Internal. |
AddEventHandler('esx_status:onTick', function(statuses)
for _, status in ipairs(statuses) do
if status.name == 'thirst' then
SendNUIMessage({ action = 'thirst', value = status.percent })
end
end
end)Network events (client to server)
| Event | Payload | Protection |
|---|---|---|
esx_status:requestLoad | none | Ignored while loading; rate limited with the load retry delay. |
esx_status:update | array of { name, val } | Accepted at most every Config.MinUpdateInterval. Entries are validated (max 64, names 1-64 chars, finite numbers, clamped). Authoritative statuses in the payload are ignored. |
Custom statuses are client-controlled
A modified client can send any value for custom statuses. Do not base money, items or permissions on them. If a status matters, add it to Config.AuthoritativeStatuses and change it only through the server events.
Saving
The server loads users.status on esx:playerLoaded and writes it back on esx:playerDropped. During the session values live in the xPlayer variable status. Authoritative values are advanced from elapsed time whenever they are read, synced or saved.
Common issues
- Hunger or thirst jumps back after eating: your item script changes them on the client. Use
TriggerEvent('esx_status:add', source, 'hunger', amount)on the server. - Status bars do not show:
Config.Displayisfalseby default. Enable it or use a HUD. - Custom status always starts at the default: it was registered before
esx_status:loadedfired and then never received the saved value, or the player never stayed long enough for an update. Register insideesx_status:loaded. users.statuscolumn missing: importesx_status.sql. Loading fails and is retried with backoff.- Changing an unknown status on the server does nothing:
setandaddonly touch statuses that already exist for the player.
Related
Frequently asked questions
Independent documentation
Last updated on
esx_society
esx_society adds shared job accounts, the boss menu, hiring, salaries, grade labels, uniforms and money washing to ESX Legacy. Full API and config reference.
esx_taxijob
Set up esx_taxijob for ESX Legacy. NPC taxi missions, payout split, billing, config keys with defaults, server events, callbacks and fixes for common issues.