Chat Categories
Chat Categories
Categories are the tabs in the chat input. Each one is a separate channel with its own colors, tags, permissions, delivery rules and identity badges. They are defined in shared/config/categories.lua as config.chatCategories.
The built-in Commands tab
A command category is always injected as the first tab at runtime (from shared/main.lua) — you do not define it yourself:
table.insert(config.chatCategories, 1, {
label = "CATEGORY_COMMANDS_LABEL",
type = "command",
icon = "terminal",
placeholder = "CATEGORY_COMMANDS_PLACEHOLDER",
})Anything typed in this tab is executed as a command. With config.allowNoSlashCommands = true, a known command name works with or without a leading slash (typing me hi runs /me hi).
What ships enabled
Out of the box only the Admin category is active in config.chatCategories. Ready-to-use examples for OOC (Global), OOC (Local/closest), Police, EMS and Gang are included in the file but commented out — uncomment and tune them as needed.
| Category | type |
How access is gated |
|---|---|---|
| Commands | command |
Always present (auto-injected) |
| Admin | admin |
ACE permissions command / admin / adminchat |
| OOC (Global) | ooc |
Open to everyone (example) |
| OOC (Local) | oocclosest |
Proximity — distance in meters (example) |
| Police | pdchat |
jobs = { police = {...grades} } (example) |
| EMS | emschat |
jobs = { ambulance = true } (example) |
| Gang | gang |
gangs = { ... } (example) |
Default category
config.defaultChatCategory decides which tab is focused when chat opens:
config.defaultChatCategory = "command"Slash vs. no-slash commands
--- true = commands work WITH and WITHOUT a leading slash ("me hi" runs /me)
--- false = commands only trigger with a leading slash ("/me hi")
config.allowNoSlashCommands = trueCategory parameters
Every category supports a rich set of fields. A trimmed example:
{
label = "CATEGORY_ADMIN_LABEL", -- translation key for the tab name
type = "admin", -- unique id for this category
icon = "shield-alt", -- FontAwesome icon
webhookKey = "chatMessage", -- Discord log webhook (see Discord Logging)
placeholder = "CATEGORY_ADMIN_PLACEHOLDER",
permissions = { "command", "admin", "adminchat" }, -- required ACE perms
maxLength = 500, -- max message length
tags = { -- fixed tag(s) shown before the message
{ tag = "Admin", textColor = { 51, 51, 51 }, bgColor = { 255, 105, 97 } },
},
color = { 255, 105, 97 }, -- default message text color
showPlayerName = { active = true, censored = false, showWearingMask = true },
showPlayerId = { active = false, type = "serverId" },
showPlayerJob = { active = false, showLabel = true, showGrade = false },
discordTag = { active = false, maxShow = 1, roles = { ... } },
showHour = { active = true },
}Full field reference (all optional unless noted):
| Field | Type | Description |
|---|---|---|
label |
string | Translation key for the tab display name |
type |
string | Required. Unique identifier for the category |
icon |
string | FontAwesome icon name |
webhookKey |
string | Discord webhook key to log this category's messages |
command |
string / string[] | Chat command(s) that route into this category |
placeholder |
string | Translation key for the input placeholder |
distance |
number | Max delivery distance in meters; omit for global |
maxLength |
number | Maximum message character length |
permissions |
string[] | Required ACE permissions to see/use the category |
jobs |
table | Required jobs — true = all grades, number[] = specific grades |
gangs |
table | Required gangs — same shape as jobs |
tags |
table[] | Fixed tags shown before messages (tag, textColor, bgColor) |
color |
RGB | Default message text color { r, g, b } |
showPlayerName |
table | active, censored, bgColor, textColor, showWearingMask |
showPlayerId |
table | active, type = "serverId", colors |
showPlayerJob |
table | active, showLabel, showGrade, colors, per-job overrides |
discordTag |
table | active, maxShow, roles[] (Discord role → tag) |
showHour |
table | active, colors — appends the message time |
Name censoring shows a masked name (e.g. J*** D**). If a player is wearing a mask, their name is hidden as Unknown unless showWearingMask = true — the mask check is driven by config.noneMask in general.lua.