6.6 KiB
AGENTS.md - Custom Functions
Practical guidance for contributors and AI agents working in config/custom_functions/.
This folder is the supported extension point for Luxu Admin. Use it to add custom addon buttons, quick actions, quick toggles, statistic blocks, and map zone handlers without editing core modules.
Folder Purpose
Files in this directory:
client.lua: client-side registrations and handlers (addons, statistics declaration, zone handlers)server.lua: server-side callbacks (addon buttons + statistic block providers)types.lua: type definitions and signatures (Addon,Zone,ZoneHandlerReturn, registration APIs)
Runtime loading:
client.luais loaded fromclient/cl_main.luaserver.luais loaded fromserver/sv_main.luatypes.luais for editor type hints and as reference for expected shapes
Event Flow
Base flow:
UI -> NUI callback -> client handler -> server callback (optional)
Common routes:
- Addon button:
custom_functions:button:{name}on client- optional
callServer(...)tocustom_functions:callback:{name}on server
- Quick action:
custom_functions:quick_action:{name}on client (client-only by built-in API)
- Quick toggle:
custom_functions:quick_toggle:{name}on client (client-only by built-in API)
- Statistic blocks:
custom_functions:statistic_blocks:getfetches all registered server block callbacks
Registration API
| Function | File | Use |
|---|---|---|
RegisterAddons() |
client.lua |
Register buttons, quick actions, quick toggles |
RegisterAddonStatisticBlocks() |
client.lua |
Declare statistic block keys |
RegisterAddonCallback() |
server.lua |
Handle server logic for addon buttons |
RegisterAddonStatisticBlocksCallback() |
server.lua |
Return data for statistic blocks |
RegisterZoneHandler() |
client.lua |
Register map zone behavior |
Addon Types
Definitions come from types.lua.
1) Button (Player Management)
Use when action targets a selected player and may require server authority.
- set
type = "button"inRegisterAddons(...) - handler signature:
function(target, callServer) targetis selected player server ID- if using
callServer(...), registerRegisterAddonCallback(name, callback, permission?)on server
2) Quick Action (Quick Menu Main tab)
Use for fast client-side actions with optional option selection.
- built-in path is client-only
- handler signature:
function(target, option) optionis selected option key ornil
3) Quick Toggle (Quick Menu Toggles tab)
Use for toggled states (god mode, speed mode, noclip state, etc).
- built-in path is client-only
- handler signature:
function(option) - must return a boolean representing new state
4) Statistic Blocks (Statistics page)
Use for custom server-backed metrics.
- client declaration:
RegisterAddonStatisticBlocks({ "block_a", "block_b" })
- server provider:
RegisterAddonStatisticBlocksCallback("block_a", function(source) ... end)
- expected return:
{ title, description, value, formatToCash? }valuecan be string or number
5) Zone Handler (Admin map zones)
Use for custom behavior when entering/exiting/remaining inside a configured zone.
- register in client:
RegisterZoneHandler("handler_name", function() return { onEnter, onExit, inside } end)
- zones reference the handler via
customHandlervalue - zone shape reference: see
Zoneintypes.lua
Security Requirements (Critical)
Treat every client-triggered path as untrusted.
- Validate everything server-side:
source,target, option values, ranges, and expected types
- Use permissions:
- set addon
permissionand enforce matching permission inRegisterAddonCallback(...)
- set addon
- Enforce duty/admin state:
- check
IsOnDuty(source)(or your project equivalent) before privileged actions
- check
- Deny by default:
- reject unknown options and invalid targets early
- Audit sensitive actions:
- log who executed what and on whom
Performance Requirements
FiveM servers are sensitive under player load. Keep custom code lightweight.
- do not run heavy work in per-frame
insidehandlers - cache expensive statistic computations when possible
- avoid large synchronous loops over all players each click/tick
- for large payloads between client/server, prefer latent events
- fail fast on invalid input to avoid unnecessary work
Naming and Style Conventions
- use
snake_casefor addon/block/handler names - names are case-sensitive and must match between client/server registration
- use hex colors like
"#22c55e" - icon examples:
- MDI:
"mdi:heart-pulse" - Material icon theme:
"material-icon-theme:icon-name"
- MDI:
Reference: https://pictogrammers.com/library/mdi/
Quick Implementation Recipes
Add button with server authority
- In
client.lua, add addon withtype = "button"and callcallServer(...)in handler. - In
server.lua, registerRegisterAddonCallback("same_name", function(source, target, ...) ... end, "optional.permission"). - Validate inputs and enforce permission/duty before executing action.
Add quick action
- In
client.lua, add addon withtype = "quick_action". - Add optional
optionsand implementhandler(target, option). - Keep behavior client-safe; do not trust this path for privileged logic.
Add quick toggle
- In
client.lua, add addon withtype = "quick_toggle". - Implement
handler(option)and return new boolean toggle state. - Keep state transitions explicit and deterministic.
Add statistic block
- In
client.lua, include block key inRegisterAddonStatisticBlocks({ ... }). - In
server.lua, implementRegisterAddonStatisticBlocksCallback("same_key", function(source) return {...} end). - Keep callback fast; cache where possible.
Add zone behavior
- In
client.lua, registerRegisterZoneHandler("handler_name", function() return { onEnter, onExit, inside } end). - In admin map zone config, set
customHandlerto"handler_name". - Keep
insidecallback minimal to prevent frame drops.
Pre-merge Checklist
- Names match exactly between UI/client/server registrations
- Required server callbacks exist for every
callServer(...)path - Permission and duty checks are in place for privileged actions
- Invalid input paths are handled safely
- High-frequency handlers (
inside) are lightweight