Integration events
Raven tells your scripts the moment it bans, kicks, or warns someone, and can hold the drop back while you show your own screen.
When Raven acts on a player, your server usually wants to know. Raven fires a server event for every action it records, with the detail already assembled, so you never have to poll the dashboard for it. This page lists the four events, what each payload carries, and how to hold the drop back while you show your own screen.
The four events
| Event | When it fires | Can delay the drop |
|---|---|---|
rac:onPlayerBanned | Every ban, from a detection or from your own script, once the dashboard has issued the ban id and before the player is dropped. | Yes |
rac:onPlayerGlobalBanned | In addition to onPlayerBanned, and with the same payload, when that ban was global. | Yes |
rac:onPlayerKicked | Every kick, after the kick has been sent to the dashboard and before the player is dropped. It also fires for a ban the dashboard refused, because the player is kicked instead. | Yes |
rac:onPlayerWarned | A detection warning. Nothing is recorded and nobody is dropped. | No |
Only a ban is confirmed before its event fires: Raven waits for the dashboard to issue the ban id and passes it to you, so the id in the payload is real and already reviewable. A kick is sent to the dashboard without waiting, so rac:onPlayerKicked tells you the player is being dropped rather than that the record landed. A warning records nothing at all, which is why there is nothing to delay.
Handler arguments
| Argument | Type | What it is |
|---|---|---|
src | number | The player server id. |
token | string | Compare it against the rac_token convar before you trust the rest. |
data | table | The detail, laid out below. |
delayDrop | function or nil | Only passed on the ban and kick events. It is nil on a warning. |
The payload table
Every field below is on the data table. A field the event does not carry is not there at all, so data.banId reads nil on a kick and data.name reads nil on a warning. Test for a field before you format it.
| Field | Events | What it holds |
|---|---|---|
banId | Banned, Global banned | The id your dashboard now lists the ban under, as a string. |
global | Banned, Global banned | true when the ban was global, false when it was only yours. |
warnId | Warned | The detection name and the warning number joined with a colon, such as AntiNoclip:3. |
count and max | Warned | Which warning this is and how many it takes to act. |
reason | All four | What the player was shown, or the detection name on a warning. |
description | All four | The description you passed to the export, or the detection that fired. On a warning it is "Warning 3 of 5". |
screenshotUrl | Banned, Global banned, Kicked | The capture taken with the action, or nil. |
name | Banned, Global banned, Kicked | The player name as Raven had it when it acted. |
Usage
AddEventHandler('rac:onPlayerBanned', function(src, token, data)
if token ~= GetConvar('rac_token', '') then return end
print(('%s was banned: %s (ban %s)'):format(data.name, data.reason, data.banId))
end)Checking the token
Any resource can trigger an event by name. The token is how your handler tells a real Raven event from one something else fired. Raven generates a fresh 32-character random value the first time it fires an integration event in a run and publishes it as the rac_token server convar, so a client can never read it.
Delaying the drop
Raven drops the player as soon as the ban or kick is recorded. Call delayDrop with a number of milliseconds to hold that back while you show your own screen.
AddEventHandler('rac:onPlayerBanned', function(src, token, data, delayDrop)
if token ~= GetConvar('rac_token', '') then return end
delayDrop(4000)
TriggerClientEvent('myserver:banScreen', src, data.reason, data.banId)
end)| Rule | Detail |
|---|---|
| The largest ask wins | Handlers asking for 2000 and 5000 give you 5000, not 7000. |
| The ceiling is 20000 ms | Exactly 20000 is accepted. Anything higher, anything negative, and anything that is not a number are ignored. |
| 0 is accepted | It asks for no hold, which is the same as not calling it at all. |
| Call it before you yield | After a Wait or inside a callback it arrives too late to count. |
| A numeric string works | The value is read with tonumber, so "4000" is the same as 4000. |
What waits and what does not
The hold sits between the event and the drop, so everything the dashboard had already done is finished, and everything Raven does on the way out is pushed behind it.
| What | Does it wait |
|---|---|
| The dashboard record | Already written. The ban event only fires once the id exists. |
| The cloud Discord log | Already sent, because the dashboard writes it when it takes the ban. |
| The drop itself | Waits for the whole window you asked for. |
| The in-game admin notification | Waits with the drop. It goes out after the hold, not during it. |
| The menu ban list refresh | Waits with the drop, for the same reason. |