State bag is a feature of OneSync in FiveM and RedM, enabling data sharing between client and server. Whether you're a beginner or an experienced developer, state bags make scripts clearer and more efficient by simplifying data handling. In this article, you'll learn what state bag is, how it works, and how to implement it in your projects.
State bags help manage player status, track entities like vehicles or horses, and sync data across clients and servers. Mastering state bags can save development time and boost script efficiency.
What Are State Bags in FiveM and RedM?
A state bag is like a data table attached to any network entity, such as:
- Players (peds)
- Vehicles
- Network objects
State bags store and share data, accessible by the server and clients in range. They act like variables tied to specific entities and shared globally. A global state bag can also share general information between all clients and the server, making it easier to manage universal data.
Types of State Bags:
- Global State Bag: Shared between all clients and the server, modifiable only by the server.
- Player State: Specific to each player; modifiable by the owning client or server.
- Entity State: Linked to entities like vehicles or objects, accessible as long as they are in scope.
How to Use State Bags in FiveM and RedM
Example 1: Using Global State Bags to Track Player Counters
Imagine a global counter tracking a value across all players.
Server-side:
GlobalState.counter = 0
RegisterCommand("increment", function()
GlobalState.counter = globalState.counter + 1
end)
Client-side:
CreateThread(function()
while true do
Wait(500)
print("Counter: ", GlobalState.counter)
end
end)
The /increment
command increases the counter server-side, and all clients see the change automatically, reducing manual event triggers.
Example 2: Managing Player Status with State Bags
Track player-specific data, such as whether they are handcuffed.
Client-side:
LocalPlayer.state:set("isCuffed", true, true)
Server-side:
local isCuffed = Player(playerId).state.isCuffed
print("Is the player cuffed: ", isCuffed)
This makes it easy for the server and other clients to verify the player's current state.
Example 3: Assigning Entity State Bags to Horses in RedM
Link data to entities like horses, such as ownership.
Server-side:
RegisterNetEvent("horse:claimed", function(horseNetId, ownerId)
local horseEntity = NetworkGetEntityFromNetworkId(horseNetId)
if horseEntity ~= 0 then
Entity(horseEntity).state:set("owner", ownerId, true)
end
end)
Client-side:
RegisterCommand("getHorseOwner", function()
local horse = GetPlayerTargetedHorse()
if horse ~= 0 then
print("Horse owner: ", Entity(horse).state.owner)
else
print("No horse targeted.")
end
end)
This example allows players to check the horse's owner by interacting with it.
Tracking Changes with AddStateBagChangeHandler
AddStateBagChangeHandler
tracks changes to a state bag and responds automatically.
- It triggers when the entity enters scope, even if the player arrives later. If the player leaves and comes back, the event triggers again.
- React in real-time to changes without constantly checking status.
Example:
AddStateBagChangeHandler("owner", nil, function(bagName, key, value, reserved, replicated)
local entity = GetEntityFromStateBagName(bagName)
if entity ~= 0 then
print("Change detected on entity: ", entity, ", key: ", key, ", new value: ", value)
end
end)
Use AddStateBagChangeHandler
to listen for changes to an entity’s "owner"
attribute and respond accordingly.
Why State Bag is better than TriggerClientEvent?
State bags offer several advantages over TriggerClientEvent
:
- Less Manual Communication: State bags handle data sharing automatically, reducing complexity.
- Better Performance: Reduce network load by only sharing necessary information.
- Centralized Data: State bags keep data centralized with each entity, ensuring consistency.
- Automatic Sync: Synchronize automatically when clients enter or leave an entity's scope.
State bags save time and make your code scalable and efficient compared to manual TriggerClientEvent
calls.
How to Handle State Bag Synchronization Issues?
AddStateBagChangeHandler
may trigger before an entity is fully synced, causing GetEntityFromStateBagName()
to return 0
. To handle this, use the following function:
function GetEntityFromStateBagName(bagName)
-- Prevent issues if bagName is nil
if not bagName then return 0 end
-- Prevent issues if bagName is not a string
if type(bagName) ~= "string" then return 0 end
-- Verify that bagName starts with "entity:"
if not bagName:find("entity:") then return 0 end
-- Extract the network ID of the entity
local netId = tonumber(bagName:sub(8) or 0)
-- Wait for the entity to be synchronized for a maximum of 2000ms
local endWhile = GetGameTimer() + 2000
while not NetworkDoesNetworkIdExist(netId) do
Wait(200)
if GetGameTimer() > endWhile then break end
end
-- If the entity is not networked
if not NetworkDoesNetworkIdExist(netId) then
-- Return the ID if the entity exists, otherwise 0
if DoesEntityExist(netId) then
return netId
end
return 0
end
-- Return the entity ID from its network ID
return NetworkGetEntityFromNetworkId(netId)
end
This function waits for the entity to sync before returning its ID, preventing errors.
Practical Use Cases for State Bags in FiveM and RedM
- Horse Owner ID: Store horse ownership for verification.
- Player Group: Store a player’s group or faction for managing permissions.
- Player Status: Track if a player is injured, unconscious, or asleep.
- Chest or Door ID: Assign state bags to manage ownership or lock status.
Conclusion: Why You Should Use State Bags
State bags are essential for developers looking to optimize scripts and manage entity data effectively. They reduce the need for constant client-server communication, making game development smoother and more efficient.
For more details, explore the official documentation:
Feel free to join our Discord community for questions and support!
Need more advanced features? Check out our other articles or contact us for personalized help with your FiveM and RedM projects.