Events
On this page5
All public events are local: they are fired with TriggerEvent on the side
they belong to, and you handle them with AddEventHandler (not
RegisterNetEvent). None of them crosses the network.
Public client events
| Event | Args |
|---|---|
5code-recognition:client:onRecognitionChanged | (targetServerId, info | nil) |
5code-recognition:client:onHudVisibilityChanged | (visible) |
5code-recognition:client:onScanStateChanged | (scanning) |
info is a RecognitionInfo, or nil when
the live result about that person has ended. While a quick look is still below
the act line ("Not sure"), info has a pct but no label and no
introducedName.
The nametag & chat snippet
This is the one pattern to use for anything that draws per frame. The server pushes, you cache, your loop reads a table.
1. The cache (client side, paste once)
-- === 5code-recognition link ===========================================
-- Names this viewer's character may use right now. Filled by a push;
-- never polled, never replicated, never shared.
local recogKnown = {}
-- Keep this equal to Config.Scoring.ActThreshold in 5code-recognition/config.lua.
local RECOG_MIN_PCT = 80
AddEventHandler('5code-recognition:client:onRecognitionChanged', function(sid, info)
-- A live result also exists for a FIRST look at a stranger, worth whatever
-- that scan was worth, so the threshold is not optional: without it you
-- would draw a label over somebody the character never recognised.
if info and (tonumber(info.pct) or 0) >= RECOG_MIN_PCT then
recogKnown[sid] = info.introducedName or info.label
else
recogKnown[sid] = nil
end
end)
-- If the recognition resource restarts, forget everything it told us.
AddEventHandler('onResourceStop', function(res)
if res == '5code-recognition' then recogKnown = {} end
end)
-- === end 5code-recognition link =======================================2. The draw loop (one line)
local sid = GetPlayerServerId(player)
local text = recogKnown[sid] or 'Stranger'One table lookup per player per frame. No export call, no server round trip.
3. Chat, per recipient
A chat line is sent by the server, so it can carry a different name for every recipient:
RegisterCommand('me', function(src, args)
local text = table.concat(args, ' ')
if text == '' then return end
local origin = GetEntityCoords(GetPlayerPed(src))
for _, id in ipairs(GetPlayers()) do
local viewer = tonumber(id)
if #(GetEntityCoords(GetPlayerPed(viewer)) - origin) <= 20.0 then
local name = (viewer == src) and 'You'
or exports['5code-recognition']:GetRecognitionLabel(viewer, src)
or 'Stranger'
TriggerClientEvent('chat:addMessage', viewer, { args = { name, text } })
end
end
end, false)Ready-to-paste versions for specific nametag and chat resources are in Nametags & Chat.
Public server events
Scanning
| Event | Args |
|---|---|
5code-recognition:server:onScanCompleted | (observerSrc, targetSrc, info{result, reliability, source, expiresAt?, usedCamera}) |
5code-recognition:server:onRecognized | (observerSrc, targetSrc, info{reliability, source, sceneEndsAt}) |
5code-recognition:server:onScanCancelled | (observerSrc, targetSrc, reason) |
info.result is 'saved', 'recognized', 'failed' or 'discarded'.
usedCamera is true when the scanner's hidden camera recorded the look.
AddEventHandler('5code-recognition:server:onRecognized', function(obs, tgt, info)
print(('%s recognized %s at %d%%'):format(obs, tgt, info.reliability))
end)Identity and death
| Event | Args |
|---|---|
5code-recognition:server:onIdentityReset | (charKey, src | nil, info{faceGen, reason, rotatedVoice, via, renamed, erased{memories, familiarity, introductions}}) |
5code-recognition:server:onImplantEnded | (src, charKey, info{result, code?, via, price, charged}) |
5code-recognition:server:onDeathReset | (src | nil, charKey, info{sessionId, erasedMemories, erasedFamiliarity, witnesses}) |
onImplantEnded result is 'done', 'cancelled', 'failed', 'expired' or
'dropped'.
Devices and papers
| Event | Args |
|---|---|
5code-recognition:server:onVoiceChangerChanged | (src, active, serial) |
5code-recognition:server:onCameraChanged | (src, active, serial) |
5code-recognition:server:onMagneticSweep | (src, info{strength, serial}) |
5code-recognition:server:onReportCreated | (src, reportId, kind) |
5code-recognition:server:onReportRead | (src, reportId, info{kind, police, granted}) |
kind is 'camera', 'statement' or 'description'. A camera report is
created when the recording is filed — when the look ends, or when a look that is
still running is printed. The player prints the paper from
F3 → Camera recordings.
Social and evidence
| Event | Args |
|---|---|
5code-recognition:server:onIntroduced | (speakerSrc, listenerSrc, info{name, attached, via}) |
5code-recognition:server:onLabIdentified | (officerSrc, targetCharKey, info{evidenceType, source, expiresAt, trust, countsForAct, recipients, memoryId}) |
Staff and configuration
| Event | Args |
|---|---|
5code-recognition:server:onProof | (snapshot{...}) — see below |
5code-recognition:server:onAdminAction | (adminSrc | nil, action, fields{observerKey?, targetKey?, memoryId?, reason?, meta?}) |
5code-recognition:server:onSettingsChanged | (adminSrc | nil, changes{[path] = value}, info{reason?, restartNeeded, reset}) |
5code-recognition:server:onNewClothingItems | (info{total, byModel, bySlot, baselineAt, checkedAt}) |
onSettingsChanged is how another script learns that a staff member changed a
value live. If you cached anything from our Config, this is your invalidation
signal.
The onProof snapshot
onProof is a staff-evidence payload and carries considerably more than the
other events. Treat it as admin data.
| Group | Fields |
|---|---|
| Who | id, actorSrc, targetSrc, actorKey, targetKey, actor{charKey, name, serverId}, target{charKey, name, serverId} |
| The act | cause, detail, createdAt, weapon, coords |
| The two numbers | reliability (what the attacker remembered), nowReliability (what they could reach right then), belowThreshold, threshold |
| The memory behind them | memorySource, memoryAgeS, validUntil |
| Context | actorJob, actorOnDuty, concealment |
The first three groups are the contract. concealment is present only when
there is something to say, so read it defensively. The payload can carry a few
more fields for our own Discord log; ignore what you do not use.
What you will never see in a client event
No payload on any client-side public event carries a real character name, a character key or a licence identifier — only what the player's own character knows. That is a contract, not an oversight.
See also
- Hooks — for changing behaviour, not just observing it
- Server Exports — and the return shapes