Server Hooks

LuxU Admin exposes moderation and report lifecycle hooks in two ways:

  1. Lua AddEventHandler — recommended for most servers. Uncomment or add handlers in config/hooks/server.lua (or any server script that loads after luxu_admin).
  2. exports['luxu_admin']:registerHook(name, callback) — for JavaScript/TypeScript resources; returns an unregister function.

When a hook fires, LuxU Admin also emits a server event named luxu_admin:server:<hook_name> (snake_case). These are not networked client events — they run server-side only.

See also: Events · Exports · Connection Queue


Available hooks

Hook name Event When it fires
report_created luxu_admin:server:report_created A player submits a new report
report_closed luxu_admin:server:report_closed A report is closed by staff or the player
player_banned luxu_admin:server:player_banned A ban is created (panel, command, or API)
player_unbanned luxu_admin:server:player_unbanned A ban is removed
player_warned luxu_admin:server:player_warned A player is warned
player_jailed luxu_admin:server:player_jailed A player is jailed
player_unjailed luxu_admin:server:player_unjailed A jail sentence is removed
player_kicked luxu_admin:server:player_kicked A player is kicked
queue_player_admitted luxu_admin:server:queue_player_admitted A queued player joins after the queue reserved a slot
queue_player_removed luxu_admin:server:queue_player_removed An attempt leaves the queue without being admitted

Note: luxu_admin:server:playerBanned (camelCase) is a separate legacy event that emits the raw ban database row. Prefer player_banned / luxu_admin:server:player_banned for new integrations — the payload is normalized and documented below.


Example — report created

The report hook payload uses reportId (replacing the old chat_id field).

-- config/hooks/server.lua

AddEventHandler("luxu_admin:server:report_created", function(data)
    local reportId = data.reportId       -- number
    local authorSource = data.author_source -- number (server id)
    local authorName = data.author_name  -- string

    print(("[Reports] #%s opened by %s (%s)"):format(reportId, authorName, authorSource))

    -- e.g. ping staff on Discord, create a ticket, etc.
end)

Example — player banned

-- config/hooks/server.lua

AddEventHandler("luxu_admin:server:player_banned", function(data)
    local banId = data.banId           -- number
    local playerName = data.playerName -- string
    local playerId = data.playerId     -- string (character / unique id)
    local reason = data.reason         -- string
    local identifiers = data.identifiers -- string[] (license, discord, etc.)
    local staffId = data.staffId       -- number | nil (nil for system / external bans)
    local staffName = data.staffName   -- string | nil
    local createdAt = data.createdAt   -- number (unix ms)
    local expiresAt = data.expiresAt   -- number (unix ms, 0 = permanent)

    print(("[Ban] %s (%s) banned by %s — reason: %s"):format(
        playerName,
        banId,
        staffName or "System",
        reason
    ))

    -- e.g. sync to external ban list, notify anticheat, audit log
end)

Example — report closed

AddEventHandler("luxu_admin:server:report_closed", function(data)
    local reportId = data.reportId     -- number
    local closedBy = data.closed_by    -- "player" | "staff"
    local staffId = data.staffId       -- number | nil (set when closed_by == "staff")

    if closedBy == "staff" then
        print(("[Reports] #%s closed by staff %s"):format(reportId, staffId))
    else
        print(("[Reports] #%s closed by the reporting player"):format(reportId))
    end
end)

Example — player unbanned

AddEventHandler("luxu_admin:server:player_unbanned", function(data)
    local playerName = data.playerName   -- string
    local reason = data.reason           -- string (original ban reason)
    local identifiers = data.identifiers -- string[]
    local staffId = data.staffId         -- number
    local staffName = data.staffName     -- string
end)

Example — kick / warn / jail

AddEventHandler("luxu_admin:server:player_kicked", function(data)
    local target = data.target       -- number (server id at kick time)
    local reason = data.reason
    local staffId = data.staffId
    local staffName = data.staffName
end)

AddEventHandler("luxu_admin:server:player_warned", function(data)
    local target = data.target       -- number (server id)
    local staffId = data.staffId
    local reason = data.reason
end)

AddEventHandler("luxu_admin:server:player_jailed", function(data)
    local targetCharId = data.targetCharId -- string
    local duration = data.duration         -- number (seconds)
    local reason = data.reason
    local staffId = data.staffId
    local staffName = data.staffName
end)

AddEventHandler("luxu_admin:server:player_unjailed", function(data)
    local targetCharId = data.targetCharId
    local staffId = data.staffId
    local staffName = data.staffName
end)

Example — registerHook export (JavaScript / TypeScript)

// From another resource's server script (must load after luxu_admin)

const unregister = exports.luxu_admin.registerHook(
  'player_banned',
  (data: {
    banId: number;
    identifiers: string[];
    reason: string;
    staffId: number | null;
    staffName: string | null;
    playerName: string;
    playerId: string;
    createdAt: number;
    expiresAt: number;
  }) => {
    console.log(`Ban #${data.banId}: ${data.playerName} — ${data.reason}`);
  }
);

// Later, to remove the listener:
// unregister();

Invalid hook names throw at registration time. Available names match the table above (report_created, player_banned, queue_player_admitted, etc.).


Example — connection queue

Queue hook payloads, remove reasons, and Lua/registerHook examples: Connection Queue.

AddEventHandler("luxu_admin:server:queue_player_admitted", function(data)
    print(("%s admitted after %d s (priority %s)"):format(
        data.name,
        math.floor(data.waitedMs / 1000),
        data.priority
    ))
end)

AddEventHandler("luxu_admin:server:queue_player_removed", function(data)
    print(("%s left the queue (%s)"):format(data.name, data.reason))
end)