## Introduction
State Bags are a powerful feature in FiveM/RedM that enable efficient data synchronization across multiple players and entities. Introduced in version v2843 as a OneSync feature, State Bags provide a more robust alternative to traditional Decors, offering server-side access and modification capabilities.
Before diving into State Bags, ensure you have:
There are three main types of State Bags in FiveM/RedM:
Entity State Bags
Player State Bags
Global State Bags
-- Server-side
local vehicle = GetVehiclePedIsIn(ped, false)
local state = Entity(vehicle).state
-- Setting state
state.damage = 100
-- Getting state
local currentDamage = state.damage
-- Setting with replication control
Entity(vehicle).state:set('damage', 100, true) -- replicate to clients-- Server-side
local player = Player(source).state
player.health = 100
-- Client-side
LocalPlayer.state.health = 100
-- Accessing other player's state
local playerHealth = Player(id).state.health
-- Replicating from client
LocalPlayer.state:set('health', 75, true) -- replicate to server-- Server-side setting
GlobalState.weatherType = 'RAIN'
-- Client-side reading
local currentWeather = GlobalState.weatherType
-- Note: Clients cannot modify GlobalStateServer-Side
-- Automatically replicates to all clients
Entity(vehicle).state.fuel = 100
-- Optional non-replication
Entity(vehicle).state:set('localData', 'value', false)
Client-Side
-- Local only by default
Entity(vehicle).state.customData = 'value'
-- Explicit replication
Entity(vehicle).state:set('customData', 'value', true)
-- Server controls replication
Player(source).state.isAlive = true -- replicates
-- Client needs explicit replication
LocalPlayer.state:set('isReady', true, true) -- replicates to serverState Bag change handlers allow you to monitor and react to state changes in real-time.
-- Basic change handler
AddStateBagChangeHandler('health', nil, function(bagName, key, value, _unused, replicated)
print(string.format("Health changed to: %s", value))
end)
-- Entity-specific handler
AddStateBagChangeHandler('fuel', 'entity:5', function(bagName, key, value, _unused, replicated)
if value < 10 then
print("Low fuel warning!")
end
end)-- Explosion handler based on state
AddStateBagChangeHandler('exploded', nil, function(bagName, key, value, _unused, replicated)
-- Only process when value is true
if not value then return end
-- Get entity from bag name
local entity = GetEntityFromStateBagName(bagName)
if entity == 0 then return end
-- Get coordinates and create explosion
local coords = GetEntityCoords(entity)
AddExplosion(coords, 0xFFFFFFFF, 1.0, true, false, 1.0)
end)-- Inefficient
local x = Entity(vehicle).state.data.x
local y = Entity(vehicle).state.data.y
-- Better Approach
local state = Entity(vehicle).state
local x = state.data.x
local y = state.data.y-- Won't work (nested modification)
Entity(vehicle).state.data.subset = 'value'
-- Correct approach
Entity(vehicle).state['data:subset'] = 'value'-- For large data, use latent events instead
-- Bad:
Entity(vehicle).state.hugeData = veryLargeTable
-- Better:
TriggerLatentClientEvent('syncLargeData', player, 1000, veryLargeTable)-- Server-side initialization
RegisterNetEvent('vehicleSpawned', function(netId)
local vehicle = NetworkGetEntityFromNetworkId(netId)
Entity(vehicle).state.damage = 0
Entity(vehicle).state.engineHealth = 1000
end)
-- Client-side damage handler
AddStateBagChangeHandler('damage', nil, function(bagName, key, value)
local vehicle = GetEntityFromStateBagName(bagName)
if vehicle == 0 then return end
-- Apply visual damage
SetVehicleDamageModifier(vehicle, value / 100)
end)-- Server-side player status
RegisterNetEvent('playerLoaded', function()
Player(source).state.hunger = 100
Player(source).state.thirst = 100
end)
-- Client-side status update
CreateThread(function()
while true do
Wait(60000) -- Every minute
LocalPlayer.state:set('hunger', (LocalPlayer.state.hunger or 100) - 1, true)
LocalPlayer.state:set('thirst', (LocalPlayer.state.thirst or 100) - 1.5, true)
end
end)-- Server-side weather control
CreateThread(function()
local weatherTypes = {'CLEAR', 'CLOUDY', 'RAIN', 'THUNDER'}
while true do
Wait(300000) -- Every 5 minutes
local newWeather = weatherTypes[math.random(#weatherTypes)]
GlobalState.currentWeather = newWeather
end
end)
-- Client-side weather sync
AddStateBagChangeHandler('currentWeather', nil, function(_, _, value)
SetWeatherTypeOverTime(value, 15.0)
end)State Not Syncing
-- Check network ownership
if not NetworkGetEntityOwner(entity) then
return
end
Undefined States
-- Always check if state exists
local damage = Entity(vehicle).state.damage
if damage == nil then
damage = 0
end
Replication Issues
-- Ensure proper replication flags
LocalPlayer.state:set('status', 'ready', true) -- Must set true for client->server
State Bags provide a powerful and efficient way to synchronize data across your FiveM/RedM server. By following these best practices and understanding the limitations, you can create robust and performant systems for your server.
Remember key points: