Custom Integrations
Send messages and register server message hooks or modes
Checked against local FS-Chat 1.3.0; the local release-version repository also lists 1.3.0. Add these calls to your own resource. You do not need to edit protected FS-Chat Lua. Start FS-Chat before your integration and stop the default chat resource to avoid two chat interfaces.
fx_version 'cerulean'
game 'gta5'
dependency 'FS-Chat'
server_script 'server.lua'Messages and suggestions
On the server, exports['FS-Chat']:addMessage(target, message) sends to a player ID or -1 for everyone. With one argument it broadcasts that message. No result is returned. Prefer an explicit target so a private message is not accidentally broadcast.
RegisterCommand('integrationhello', function(src)
if src == 0 then return end
exports['FS-Chat']:addMessage(src, {
args = { 'Server', 'Your integration is connected.' },
color = { 80, 180, 255 },
})
end, false)On the client, addMessage(message) displays locally and addSuggestion(command, help, params) adds a local command suggestion. params is an array of { name, help } entries. Both return nothing. Adding a suggestion does not register or authorize the command.
Compatible client events include chat:addMessage, chat:addSuggestion, chat:addSuggestions, and chat:removeSuggestion. Server-local events include chat:addMessage, chat:addSuggestion, chat:addSuggestions, chat:removeSuggestion, chat:addTemplate(id, html), and chat:clear. Do not turn server-only publishing into an unrestricted network relay. Keep custom template HTML trusted.
Server message hooks
registerMessageHook(callback) returns a numeric hook ID, or false for a non-function. The callback receives (src, message, controls) and its return value is ignored. Use the controls to change handling:
| Control | Effect |
|---|---|
controls.updateMessage(table) | Merge message fields; params is merged, and {} in a replacement template inserts the previous template. |
controls.cancel() | Stop delivery after the pipeline finishes. |
controls.setRouting(target) | Route to one player, -1, or an array of player IDs. |
controls.setSeObject(ace) | Route to players matching an ACE object. |
local hookId = exports['FS-Chat']:registerMessageHook(function(src, message, controls)
if src > 0 and IsPlayerAceAllowed(src, 'chat.muted') then
controls.cancel()
end
end)
assert(hookId, 'Could not register chat hook')Hooks run in the chat message pipeline, not on every direct addMessage call. They are not a universal filter for all messages other scripts publish. Keep callbacks fast and handle errors inside your callback: the inspected pipeline invokes hooks directly. Hook iteration uses pairs, so do not depend on registration order for conflicting edits.
Server modes
registerMode({ name, displayName, cb, color, isChannel, isGlobal, seObject }) returns boolean success. name, displayName, and cb are required; cb must be your callback function. The callback receives the same arguments and controls as a hook. Optional seObject restricts which players receive the mode registration; enforce any operation-specific permissions in the callback as well.
Hooks and modes are removed when their owning resource stops. Restart your integration after restarting FS-Chat so they are registered again. Use a unique mode name to avoid replacing another resource's mode.
Verification and updates
Test the command with two players and confirm only the caller sees the message. Test hook cancellation with an allowed and denied ACE, direct scripted messages, and normal player chat separately. Restart the integration and then FS-Chat to check lifecycle handling. Keep your integration in its own resource and compare these contracts after FS-Chat updates. Custom chat commands configured through the editor are a separate feature; see Usage.