ngd-chat
A feature-rich custom chat system for FiveM with multi-channel support, 3D bubbles, staff tools, Discord/FiveManage logging, and full player customization.
Installation
- Place
ngd-chatinto your [ngd] folder. This script must be started after ngd-Bridge. - Remove the default FiveM
chatresource - Configure your
server.cfgconvars (see below)
ngd-chat replaces the default FiveM chat. Do not run both at the same time.
Server.cfg Setup
Add these convars to your server.cfg as needed:
# Discord webhook for chat logging (required if Config.UseDiscordLog = true)
set ngd_chat_webhook "https://discord.com/api/webhooks/YOUR_WEBHOOK_HERE"
# FiveManage API key for log ingest (required if Config.UseFivemanageLog = true)
set ngd_chat_fivemanage_key "YOUR_API_KEY"
Chat Channels
ngd-chat ships with the following channels out of the box. All channels are configurable in config.lua.
| Channel | Command(s) | Scope | Description |
|---|---|---|---|
| Global | /g, /global | Server-wide | Default chat channel |
| Proximity | /p, /proximity | 15m radius | Nearby players only |
| Advertisement | /ad, /advert | Server-wide | Job-locked with 60s cooldown |
| Police | /police | Job-only | Police announcements with animated border |
| EMS | /ems, /e | Job-only | EMS announcements |
| Me | /me | 20m radius | Action bubble above head |
| Do | /do | 20m radius | Narration bubble above head |
| Anonymous | /anon | Server-wide | Hidden sender identity, blocked from configured jobs |
| Staff | /staff | Staff-only | Requires staff permission |
| Announce | /announce | Server-wide | Toast notification with sound |
Adding a Custom Channel
Add a new entry to Config.Channels in config.lua:
mychannel = {
command = {'mychannel', 'mc'},
color = '#ff6b6b',
label = 'MY CHANNEL',
description = 'A custom channel',
scope = 'all', -- 'all', 'proximity', 'job', 'staff'
-- distance = 15.0, -- required for 'proximity' scope
-- jobs = {'police'}, -- required for 'job' scope
-- permission = 'command', -- required for 'staff' scope
-- cooldown = 30, -- optional cooldown in seconds
-- bubble = true, -- show as 3D bubble above head
-- bubbleOnly = true, -- only show as bubble, not in chat
-- icon = 'myicon.png', -- image from /icons folder
-- animated = true, -- snake border animation
}
Configuration
General Settings
Config.DefaultChannel = 'global' -- channel used when typing without a /prefix
Config.MaxMessageLength = 256 -- max characters per message
Config.BubbleDuration = 8 -- seconds /me and /do bubbles stay visible
Config.StaffPermission = 'command' -- framework permission group for staff tools
Config.ShowPlayerIdForStaff = true -- show [ID] next to names for staff members
Rate Limiting
Config.RateLimit = {
messages = 3, -- max messages allowed
seconds = 3, -- within this time window
}
Word Filter
Config.WordFilter = {
enabled = true,
action = 'censor', -- 'censor' replaces with ***, 'block' prevents the message
words = {
'badword',
'slur',
},
}
The word filter is case-insensitive.
Logging
-- Discord webhook logging
Config.UseDiscordLog = true
-- FiveManage log ingest
Config.UseFivemanageLog = false
Both can be enabled simultaneously.
Timed Messages
Automatically broadcast rotating messages at a set interval:
Config.TimedMessages = {
enabled = true,
interval = 15, -- minutes between each message
name = 'Server', -- display name
color = '#3fb0e5', -- message color (CSS hex)
messages = {
'Join our Discord at discord.gg/example!',
'Report bugs using /report in-game.',
'Check out our store at store.example.com!',
},
}
Messages cycle through the list in order, one per interval.
Announcements
Config.AnnouncePosition = 'top-center' -- toast position on screen
Config.AnnounceDuration = 8 -- seconds the toast stays visible
Config.AnnounceSound = true -- play chime sound
Custom Emojis
Config.CustomEmojis = {
{ emoji = '🏎️', name = 'race car' }, -- unicode emoji
{ image = 'PepeHands.png', name = 'pepecry' }, -- image emoji
}
Image files go in the /emojis folder. PNG, JPG, and GIF are supported. Recommended source size is 64x64 or 128x128 — images are auto-scaled to 20x20 in chat. Players select emojis from a picker in the chat input.
Player Settings
Players can customize their chat with /chatsettings:
Config.DefaultSettings = {
x = 20, -- pixels from left edge
y = 20, -- pixels from top edge
width = 500, -- chat window width (px)
height = 400, -- chat window height (px)
visibility = 'fade', -- 'fade', 'always', 'hidden'
fadeTimeout = 10, -- seconds before chat fades
fontSize = 14, -- font size (px)
}
Settings are saved per-player in the ngdchat_settings database table.
Staff Commands
| Command | Description |
|---|---|
/mute [id] | Toggle mute on a player (prevents them from sending messages) |
/clearchat | Clear chat for all players |
/staff [message] | Send a staff-only message |
/announce [message] | Broadcast a toast announcement to all players |
Staff members can also left-click messages in the chat UI to delete messages or mute players directly.
Staff commands require the permission group set in Config.StaffPermission (default: 'command').
Editable Files
| File | Purpose |
|---|---|
config.lua | All configuration settings and channel definitions |
translate.lua | All translatable strings |
client/editableclient.lua | Client-side hooks |
server/editableserver.lua | Server-side hooks |
Hooks
Hooks let you add custom logic without modifying locked files. They fire automatically at specific points in the chat pipeline.
Server Hooks
Located in server/editableserver.lua:
OnMessageSent
Fires after a message is sent and routed to all recipients. Use this for custom logging, external API calls, or moderation integrations.
function OnMessageSent(source, channel, message, playerName)
-- source: number — server ID of the sender
-- channel: string — channel name (e.g., 'global', 'police', 'anon')
-- message: string — the message text (post-filter, post-sanitize)
-- playerName: string — real display name, even for anonymous messages
end
This hook fires regardless of Config.UseDiscordLog. The built-in Discord/FiveManage logging runs separately before this hook. Use this for your own custom integrations.
OnPlayerMuted
Fires when a player is muted or unmuted by staff.
function OnPlayerMuted(source, targetSource, muted)
-- source: number — server ID of the staff member
-- targetSource: number — server ID of the muted/unmuted player
-- muted: boolean — true if muted, false if unmuted
end
OnMessageDeleted
Fires when a staff member deletes a message.
function OnMessageDeleted(source, msgId)
-- source: number — server ID of the staff member
-- msgId: number — the message ID that was deleted
end
OnChatCleared
Fires when chat is cleared by a staff member.
function OnChatCleared(source, global)
-- source: number — server ID of the staff member
-- global: boolean — true if /clearchat (all players), false if /clear (self only)
end
Client Hooks
Located in client/editableclient.lua:
OnChatOpen
Fires when the player opens chat (T key).
function OnChatOpen()
-- Use this to hide HUD elements, pause systems, etc.
end
OnChatClose
Fires when the player closes chat (Enter or Escape).
function OnChatClose()
-- Use this to restore HUD elements, resume systems, etc.
end
OnBubbleShow
Fires when a /me or /do bubble appears above a player's head.
function OnBubbleShow(serverId, channel, text)
-- serverId: number — server ID of the player with the bubble
-- channel: string — 'me' or 'do'
-- text: string — the bubble text
end