Skip to the content
Docs

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

EventArgs
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)

lua
-- === 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)

lua
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:

lua
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

EventArgs
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.

lua
AddEventHandler('5code-recognition:server:onRecognized', function(obs, tgt, info)
    print(('%s recognized %s at %d%%'):format(obs, tgt, info.reliability))
end)

Identity and death

EventArgs
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

EventArgs
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

EventArgs
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

EventArgs
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.

GroupFields
Whoid, actorSrc, targetSrc, actorKey, targetKey, actor{charKey, name, serverId}, target{charKey, name, serverId}
The actcause, detail, createdAt, weapon, coords
The two numbersreliability (what the attacker remembered), nowReliability (what they could reach right then), belowThreshold, threshold
The memory behind themmemorySource, memoryAgeS, validUntil
ContextactorJob, 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