Player
Player is a server-side Lua service for connected-player moderation/control operations.
Error Handling Pattern​
- Success:
err == nil - Failure:
errcontains an error code string
Scope Model​
Playeris available on server runtime only.- There is no client
Playertable API.
Identifier Model​
- Player targeting uses a unified selector:
number->playerId(session id)stringprefixedc_->clientIdstringprefixeda_->accountId- For persistent systems, use
accountIdfirst (fallbackclientId), not sessionplayerId.
playerId is not a long-term persistence key.
Function List​
| Function | Description | Scope |
|---|---|---|
Player.Kick | Sends a kick notification to a player. | S |
Player.Ban | Sends a ban notification to a player. | S |
Player.Unban | Removes a persisted ban entry. | S |
Player.GetBans | Lists persisted bans. | S |
Event List​
| Event | Description | Scope |
|---|---|---|
player:connected | Event-bus event emitted when a player session connects. | S |
player:disconnected | Event-bus event emitted when a player session disconnects. | S |
player:updated | Event-bus event emitted when runtime player identity fields change. | S |
player:kicked | Event-bus event emitted after Player.Kick(...). | S |
player:banned | Event-bus event emitted after Player.Ban(...). | S |
player:unbanned | Event-bus event emitted after Player.Unban(...). | S |
Event Payload Contract​
Every player event handler receives the standard event envelope:
event.nameevent.payloadevent.sourceevent.targetevent.timestampevent.correlationIdevent.version
event.payload fields by event:
| Event | Payload Fields |
|---|---|
player:connected | playerId, clientId, accountId, displayName, role, connectedAt, loggedIn |
player:disconnected | playerId, clientId, accountId, displayName, role, connectedAt, loggedIn, reason |
player:updated | playerId, clientId, accountId, displayName, role, connectedAt, loggedIn, reason |
player:kicked | playerId, clientId, accountId, displayName, role, connectedAt, loggedIn, reason |
player:banned | playerId, clientId, accountId, displayName, role, connectedAt, loggedIn, reason |
player:unbanned | targetKind, targetId, updatedBy |
Functions​
Player.Kick​
S Server Only
local err = Player.Kick(target, reason)
Parameters:
target(number|string)reason(string, optional)
target resolution rules:
- number ->
playerId(session id) - string prefixed
c_->clientId - string prefixed
a_->accountId - otherwise ->
ERR_INVALID_TARGET
Behavior:
clientId/accountIdtargets must resolve to an online session.- If no online match exists, return
ERR_NOT_ONLINE. - Client-side admin UIs cannot call
Player.Kickdirectly; they must send a server-targeted event/command and let server Lua callPlayer.Kick.
Example:
local err = Player.Kick(12, "AFK")
if err then
print("Kick failed: " .. err)
end
Player.Ban​
S Server Only
local err = Player.Ban(target, reason)
Parameters:
target(number|string)reason(string)
Notes:
- Runtime sends a ban notification and disconnect reason.
- Ban records are persisted in server SQLite storage (
runtime/mtadm.db,banstable) usingclientId,accountId, and IP when available. - Active client-id bans are enforced on reconnect.
targetresolution rules are identical toPlayer.Kick.- Client-side admin UIs cannot call
Player.Bandirectly; they must send a server-targeted event/command and let server Lua callPlayer.Ban.
Example:
local err = Player.Ban("a_8c1d2e3f", "cheat_detected")
if err then
print("Ban failed: " .. err)
end
Player.Unban​
S Server Only
local err = Player.Unban(target)
Parameters:
target(table|string)
Supported target formats:
{ targetKind = "account", targetId = "a_123" }{ targetKind = "client", targetId = "c_123" }{ targetKind = "ip", targetId = "127.0.0.1" }"account:a_123""client:c_123""ip:127.0.0.1"
Example:
local err = Player.Unban({
targetKind = "account",
targetId = "a_8c1d2e3f"
})
if err then
print("Unban failed: " .. err)
end
Player.GetBans​
S Server Only
local bans, err = Player.GetBans(options)
Parameters:
options.limit(number, optional)
Returns:
bans(table)err(string|nil)
Each ban row contains:
keytargetKindtargetIdreasoncreatedAtupdatedAtupdatedBybannedBy
Example:
local bans, err = Player.GetBans({ limit = 100 })
if not err then
for _, ban in ipairs(bans) do
print(ban.targetKind .. ":" .. ban.targetId .. " -> " .. ban.reason)
end
end
Related APIs​
- Role/account management:
Auth - Runtime identity/roster lookup:
Connection - Replicated player view data:
Node(/NodePlayers, read model)
NodePlayers Relationship​
Playeris for control/moderation actions (Kick,Ban).NodePlayersis for replicated read state (position/visual state), not moderation authority.- Do not store moderation state in
NodePlayers; persist moderation via storage/auth flows.
Events​
player:connected (Event Bus)​
S Server Only
AddEventHandler("player:connected", function(event)
print(
"Connected pid=" .. tostring(event.payload.playerId) ..
" cid=" .. tostring(event.payload.clientId) ..
" aid=" .. tostring(event.payload.accountId)
)
end)
player:disconnected (Event Bus)​
S Server Only
AddEventHandler("player:disconnected", function(event)
print(
"Disconnected pid=" .. tostring(event.payload.playerId) ..
" cid=" .. tostring(event.payload.clientId) ..
" aid=" .. tostring(event.payload.accountId) ..
" reason=" .. tostring(event.payload.reason)
)
end)
player:updated (Event Bus)​
S Server Only
AddEventHandler("player:updated", function(event)
print(
"Updated pid=" .. tostring(event.payload.playerId) ..
" role=" .. tostring(event.payload.role) ..
" loggedIn=" .. tostring(event.payload.loggedIn) ..
" reason=" .. tostring(event.payload.reason)
)
end)
player:kicked (Event Bus)​
S Server Only
AddEventHandler("player:kicked", function(event)
local playerId = event.payload.playerId
local clientId = event.payload.clientId
local accountId = event.payload.accountId
local reason = event.payload.reason
print(
"Player kicked: pid=" .. tostring(playerId) ..
" cid=" .. tostring(clientId) ..
" aid=" .. tostring(accountId) ..
" reason=" .. tostring(reason)
)
end)
player:banned (Event Bus)​
S Server Only
AddEventHandler("player:banned", function(event)
local playerId = event.payload.playerId
local clientId = event.payload.clientId
local accountId = event.payload.accountId
local reason = event.payload.reason
print(
"Player banned: pid=" .. tostring(playerId) ..
" cid=" .. tostring(clientId) ..
" aid=" .. tostring(accountId) ..
" reason=" .. tostring(reason)
)
end)
player:unbanned (Event Bus)​
S Server Only
AddEventHandler("player:unbanned", function(event)
print(
"Player unbanned: " ..
tostring(event.payload.targetKind) .. ":" ..
tostring(event.payload.targetId) ..
" by " .. tostring(event.payload.updatedBy)
)
end)
Function/Event Mapping​
| Function | Emitted Event |
|---|---|
Player.Kick(target, reason) | player:kicked |
Player.Ban(target, reason) | player:banned |
Player.Unban(target) | player:unbanned |
Error Codes​
Player.Kick should return:
ERR_INVALID_TARGETERR_NOT_ONLINEERR_PERMISSION_DENIEDERR_TRANSPORT_FAILEDERR_NOT_CONNECTED
Player functions currently use direct runtime actions unless otherwise documented.
Player.Ban may additionally return:
ERR_STORAGE_UNAVAILABLE
Player.Unban / Player.GetBans may additionally return:
ERR_STORAGE_UNAVAILABLEERR_NOT_FOUND
Quick Example​
Kick and react using event bus:
AddEventHandler("player:kicked", function(event)
print("Audit: kicked aid=" .. tostring(event.payload.accountId) .. " pid=" .. tostring(event.payload.playerId))
end)
local err = Player.Kick("a_8c1d2e3f", "AFK")
Server moderation + player read-model correlation:
AddEventHandler("player:kicked", function(event)
local kickedPlayerId = event.payload.playerId
local node, err = Node.Get("/NodePlayers/" .. tostring(kickedPlayerId))
if not err and node then
-- correlate moderation event with latest replicated player view data
-- for audit/telemetry pipelines
end
end)