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.