Skip to content

Doors and containers

The level’s AnimDoor and Stash entities are in sync on every client by default — a mode needs nothing for it. A mode may veto (OnPlayerUseDoor, OnPlayerOpenContainer) or drive them (SetDoorState, SetContainerItems).

A key is the entity’s level name, e.g. AnimDoor[Door/door_village_left32_77d417c2-...]. An untouched object is the level’s default: GetDoorState and GetContainerItems return nil for it.

A door’s state of record is written by whoever uses it — their game already did it; the server checks the reach and tells everyone else, and a client entering the world gets every touched door.

Function
GetDoors(){key, ...} every door anyone touched
GetDoorState(key)open, locked | nil nil: never touched
SetDoorState(key, open, locked) on every client at once
function OnPlayerUseDoor(pid, key, open, locked) -- the state as it is now on their client
local _, wasLocked = GetDoorState(key) -- nil = never touched: the level's default
if wasLocked and not locked and not IsPlayerAdmin(pid) then
SendClientMessage(pid, COLOUR_RED, "that lock is not yours to pick")
return false -- their door is put back; nobody else hears of it
end
end

A container’s contents are the server’s: the first opener’s own loot seeds the record, one player holds a container at a time (“Someone is rummaging in it.” for the next), the client’s inventory is rewritten from the record before the loot UI opens, and the contents come back when it closes — the server logs the delta (took [...], put [...]).

Function
GetContainers(){key, ...} every stash anyone opened
GetContainerItems(key){{class=, amount=, health=}, ...} | nil the record; health in percent; nil: never opened
SetContainerItems(key, items) rewrites the record (health optional); whoever has it open sees the new list
GetContainerUser(key)pid | nil who has it open
function OnPlayerOpenContainer(pid, key) -- nothing opened yet; false refuses
return not IsPlayerInZone(pid, vaultZone) or IsPlayerAdmin(pid)
end
function OnPlayerCloseContainer(pid, key)
local items = GetContainerItems(key) -- what they left in it
Log(GetPlayerName(pid) .. " closed " .. key .. " with " .. #items .. " stack(s)")
end
Function
GetPlayerInventory(pid){{class=, amount=, health=}, ...} as their client last reported it: 1.5 s after a spawn, then every 10 s or within a second of a change; {} before the first report
GetPlayerAuditViolations(pid)n violations the [audit] action was applied to this session

The inventory audit ([audit] in server.toml) compares those reports with what the server’s records explain — the spawn outfit, GivePlayerItem, pickups, takes from containers — and calls OnPlayerAuditViolation on an excess of a guarded class.