Staff (tm.staff)
Context: client and server. One staff check for every resource, so none keeps its own copy.
Staff means what the admin hub means: the framework's admin permission or the group.admin ace, read through tm.fw.isAdmin (see docs/bridge.md). The rule lives in the framework adapters, not in this import.
Server
| Function | Description |
|---|---|
tm.staff.is(source) | true for a player who is staff. false for the console (0), for anything that is not a player and when the bridge fails. Never raises. |
tm.staff.isOrConsole(source) | Like is, but the console passes. For RegisterCommand handlers only, never for callbacks or net events. |
tm.staff.guard() | A function you can hand to modules that take a guard, for example tm.state.setStaffGuard(tm.staff.guard()). |
RegisterCommand('spawnthing', function(source)
if not tm.staff.isOrConsole(source) then return end
-- ...
end, false)Client
For showing or hiding UI only. The server must still check every action.
| Function | Description |
|---|---|
tm.staff.is() | The last answer the server gave, read without any call. false until the first answer arrives. |
tm.staff.await(timeout?) | Inside a thread: waits (3000 ms by default) for the first answer and returns it. false on timeout. |
tm.staff.refresh() | Asks again now, for example after permissions changed. |
tm.staff.onChange(cb) | cb(isStaff) when the answer changes. Returns the event handler. |
tm.staff.guard() | A function that returns is(). |
How it works: tm_lib's server answers each client privately when it asks, and again when the character loads, changes job or unloads. The answer is kept in the local player state (not replicated), so every resource shares one copy and is() never costs a round trip. A read that finds the answer older than a minute asks again in the background. A client can ask at most once a second.