Skip to content

State ​

How Shiva manages server-side and client-side state.

Server State ​

Server state lives in services. Services are singletons (by default) managed by the container. State is loaded from the database on startup and cached in memory.

lua
-- PlayerService holds player state in memory
local PlayerService = {}
local _players = {}  -- { [serverId] = PlayerData }

function PlayerService:get(serverId)
    return _players[serverId]
end

function PlayerService:load(serverId)
    local data = DB:first('SELECT * FROM players WHERE server_id = ?', serverId)
    _players[serverId] = data
end

Persisting State ​

Use the Database API for persistence. Shiva provides a thin wrapper around oxmysql:

lua
local DB = require('shiva-fw.database')

-- Async query
DB:execute('UPDATE accounts SET amount = ? WHERE player_id = ?', { amount, playerId })

-- Sync scalar
local balance = DB:scalar('SELECT amount FROM accounts WHERE player_id = ?', playerId)

Client State ​

Client state is managed through FiveM's StateBag system and mirrored from the server:

lua
-- Server: set state
local ped = GetPlayerPed(source)
Entity(ped).state:set('health', health, true)

-- Client: read state
local health = LocalPlayer.state.health

Shared State ​

For state that needs to be shared between client and server but doesn't need to be in the database, use the Cache API:

lua
local Cache = require('shiva-fw.cache')
local cache = Cache.new({ ttl = 60 })  -- 60 second TTL

cache:set('player:' .. playerId .. ':coords', coords)
local coords = cache:get('player:' .. playerId .. ':coords')

State Lifecycle ​

EventWhenWhat to do
player:connectedPlayer joinsLoad player data into memory
player:spawnedCharacter selectedLoad character data
player:disconnectedPlayer leavesFlush state to DB, clean up memory

See Also ​

Released under the MIT License.