Custom servers
On this page
bridge/server.lua and bridge/client.lua are open in every edition. They hold everything SAF Anticheat asks
your server. You can edit them, but the better place for your changes is custom/: updates never touch it.
How custom/ works
Files in custom/ load after config.lua and bridge/, so anything defined there replaces the original.
| Folder | Use it for |
|---|---|
custom/shared/*.lua | Changing Config values and setting hooks |
custom/client/*.lua | Replacing the client Bridge.Notify |
custom/server/*.lua | Replacing any server Bridge.* function and setting hooks |
Config overrides
custom/shared/config.lua
Config.ShadowMode = true
Config.Movement.Limits.plane = 260
Config.Health.MaxHealth = 300Server hooks
| Function | What it does | Default |
|---|---|---|
Bridge.GetName(src) | Name in the panel and logs | Character name if loaded, else the FiveM name |
Bridge.GetJob(src) | Job name and whether they're a boss, for the known exploitable events | From the framework |
Bridge.Can(src, perm) | Panel and alert permissions: view, alerts, case, screenshot, warn, teleport, clear, kick, ban, unban, ip, exempt, settings | The ACEs in Config.Permissions, plus Config.AdminGroups |
Bridge.IsStaff(src) | The staff tag in the panel. No special treatment | From the permissions |
Bridge.Notify(src, msg, kind) | A message to a player | Framework notification |
Bridge.Log(entry) | Where logs go. entry = { title, text, color, fields, src, image } | Console and Config.Discord.Webhook |
Bridge.CaptureScreenshot(src, cb) | Take a screenshot, cb(dataUri or nil) | screenshot-basic |
Bridge.UploadScreenshot(dataUri, name, cb) | Store it, cb(url or nil) | Posts it to Config.Screenshots.Webhook |
Bridge.ExternalBan(src, ban), Bridge.ExternalUnban(ban) | Copy bans to another ban list, with Config.Bans.UseTxAdmin on | Nothing |
Your own ranks
custom/server/ranks.lua
function Bridge.Can(src, perm)
if perm == 'ip' or perm == 'exempt' then
return exports['my-ranks']:IsOwner(src)
end
return exports['my-ranks']:IsStaff(src)
endLogs somewhere else
custom/server/logs.lua
function Bridge.Log(entry)
exports['my-logger']:Send('anticheat', entry.title, entry.text, entry.fields)
endAnother ban list
txAdmin has no public ban API for resources, so Bridge.ExternalBan does nothing by default. Point it at
whatever your panel offers and set Config.Bans.UseTxAdmin = true:
custom/server/bans.lua
function Bridge.ExternalBan(src, ban)
exports['my-panel']:AddBan(src, ban.reason)
endHooks
Hooks change any check without touching the resource. Set them from custom/shared/ or custom/server/.
| Hook | Return |
|---|---|
Hooks.BeforeFlag(src, code, severity, data) | false drops the flag, a number replaces the severity |
Hooks.AfterFlag(src, flag) | Nothing. Runs after every flag |
Hooks.BeforeAction(src, flag, action) | false does nothing, or a new action name |
Hooks.BeforeBan(src, ban) | false stops the ban |
Hooks.AllowEntity(src, model, kind, handle) | true lets it through every entity check |
Hooks.AllowExplosion(src, ev) | true lets it through every explosion check |
Hooks.Exempt(src, code) | 'ignore', 'log', 'normal' or nil |
Hooks.Grace(src, kind, seconds) | Runs when a grace window opens |
custom/server/hooks.lua
-- boats are fast on this server
Hooks.BeforeFlag = function(src, code, severity, data)
if code == 'SPD' and data.vehicle == 'boat' then return false end
end
-- the event props script spawns cones in bulk
Hooks.AllowEntity = function(src, model, kind, handle)
return model == `prop_roadcone02a` and IsPlayerAceAllowed(src, 'props.place')
end