Statebags β
On the client, BLN Society keeps a local copy of everything you need about organizations. Read these bags directly β no server callback required.
This page covers bag keys and shapes only. To call functions, see API Reference. When a bag updates, see Events.
Society ids in bag keys are always strings β use tostring(societyId) when looking up entries.
Three tiers β
| Tier | Bags | Location | Who can read | Use case |
|---|---|---|---|---|
| Global | society:ready, society:directory, society:revision | GlobalState | Every client | Boot flag, public directory, cache invalidation |
| Player (replicated) | society:memberships, society:duty | Player(serverId).state | Any client | Inspect another player's membership or duty |
| Local (owner only) | society:finance, society:paychecks, society:storage | LocalPlayer.state | Local player only | Balances, wages, storage β never replicated |
Memberships and duty replicate on purpose so other resources can inspect other players. Money, wages, and storage stay private β pushed only to the owner.
Global β
Bags on GlobalState β same data on every client.
society:ready β
Boot flag. true once migrations ran and the cache is warm. Do not read other bags until this is true.
Read:
local ready = GlobalState['society:ready']
if not ready then return endReturns:
truesociety:directory β
Public list of every society on the server β name, member counts, world points. Safe for maps, phones, and job boards. No sensitive data.
Read:
local directory = GlobalState['society:directory'] or {}
local sheriff = directory['3']Returns:
{
['3'] = {
id = 3,
name = 'Valentine Sheriff',
isState = true,
status = 'active',
members = 4,
onDuty = 2,
point = {
enabled = true,
coords = { x = -324.1, y = 776.5, z = 117.8, h = 90.0 },
blip = { enabled = true, sprite = 'blip_shop_store', name = 'Sheriff' },
marker = { type = 'default', color = { r = 255, g = 255, b = 255, a = 180 }, scale = 1.0, distance = 15.0 },
prompt = { enabled = true, name = 'Open', key = 0xCEFD9220, distance = 2.0 },
},
},
}point is absent when the society has no world presence.
society:revision β
Integer bumped on any structural change β society created, rank edited, member added, balance changed. Compare against a cached value to know when to rebuild directory-derived UI.
Read:
local revision = GlobalState['society:revision'] or 0
if revision ~= myCachedRevision then
RebuildSocietyList()
myCachedRevision = revision
endReturns:
42Player (replicated) β
Bags on Player(serverId).state β readable for any player, including your own via LocalPlayer.state.
society:memberships β
Every society the player belongs to. Keyed by society id as a string. perms is flattened with wildcards already expanded.
Read:
-- Local player
local memberships = LocalPlayer.state['society:memberships'] or {}
local mine = memberships[tostring(societyId)]
-- Another player
local theirs = Player(serverId).state['society:memberships'] or {}
local entry = theirs[tostring(societyId)]Returns:
{
['3'] = {
id = 3,
name = 'Valentine Sheriff',
isState = true,
status = 'active',
memberStatus = 'active',
isOwner = false,
joinedAt = '2026-05-02 11:20:00',
dutySeconds = 7420,
rank = {
id = 12,
name = 'Deputy',
level = 40,
salary = 30.0,
salaryCurrency = 0,
isOwnerRank = false,
},
perms = {
['members.view'] = true,
['duty.use'] = true,
['storage.use'] = true,
},
},
}Check permissions with mine.perms['storage.use']. Returns an empty table {} when the player belongs to no societies.
society:duty β
The society the player is currently on duty for, or false when off duty.
Read:
-- Local player
local duty = LocalPlayer.state['society:duty']
-- Another player
local theirDuty = Player(serverId).state['society:duty']Returns (on duty):
{
id = 3,
name = 'Valentine Sheriff',
rankId = 12,
since = 1754939200,
}Returns (off duty):
falseLocal (owner only) β
Bags on LocalPlayer.state β never replicated. Only the owning client can read these.
society:finance β
Balances for societies where the local player holds finances.view. Both society id and currency are string-keyed.
Read:
local finance = LocalPlayer.state['society:finance'] or {}
local balances = finance[tostring(societyId)]
local cash = balances and balances['0']Returns:
{
['3'] = {
['0'] = 4820.5,
['1'] = 12.0,
},
}Returns nil for societies where the player lacks finances.view.
society:paychecks β
Uncollected wages waiting at the society point.
Read:
local paychecks = LocalPlayer.state['society:paychecks'] or {}
local pending = paychecks[tostring(societyId)]
if pending and pending.count > 0 then ShowCollectPrompt() endReturns:
{
['3'] = {
count = 2,
amounts = { ['0'] = 240.0 },
},
}society:storage β
Storages the local player can see based on rank level. Only present when storage is enabled in config. Keyed by society id, then by storage key.
Read:
local storage = LocalPlayer.state['society:storage'] or {}
local storages = storage[tostring(societyId)]
local safe = storages and storages.main_safeReturns:
{
['3'] = {
main_safe = {
invId = 'society_3_main_safe',
label = 'Main Safe',
slots = 50,
maxWeight = 120,
minRankLevel = 10,
},
},
}