Skip to the content
Docs

Police, MDT & Evidence

On this page7

Three separate integrations that often live in the same script.

  • Police — who cuffed, robbed, searched or escorted whom, for the proof log.
  • MDT — where camera reports and witness statements are filed.
  • Evidence — fingerprint and DNA matches, which grant a Lab ID.

Police jobs first

None of this works until the job names are right.

Both lists ship with 'police' only, the one police job stock QBCore, Qbox and ESX all have. config.lua keeps a commented example line under each list for your other departments:

lua
Config.Jobs = {
    Police = { 'police' },
    -- Police = { 'police', 'sheriff', 'fib' },   -- example: add your other departments
    HintJobs = { 'police' },
    -- HintJobs = { 'police', 'sheriff', 'fib' },   -- example: add your other departments
    AcceptTypes = { 'leo' },
}

Police scripts

lua
Config.PoliceSystem = 'auto'
SystemSupportAuto orderWhat it adds
generic cuff state bagsSupportedalways onCuff and uncuff proofs, on any police script that sets one of the common keys.
wasabi_police_v2Supported1State bags plus its isPlayerCuffed.
wasabi_policeStub2Same, older shape.
ak47_qb_policejobStub3Its IsCuffed poll.
ak47_policejobStub4Same.
qbx_policeSupported5Metadata event, observed robbery.
qb-policejobSupported6Observed net events.
esx_policejobSupported7Observed net events plus its isHandcuffed state.
ox_inventory hooksSupportedindependentRobberies, through openInventory and swapItems.
lua
Config.Proof.CuffStateKeys = { 'ishandcuffed', 'isHandcuffed', 'isCuffed', 'cuffed', 'cuffs' }
Config.Proof.OxInventoryHooks = true

When nobody is named

Some scripts cuff a player without saying who did it. Then the nearest facing player within Config.Proof.InferActorRadius (2.5 m) is logged as the likely actor — marked as such, never as proven. Treat it as a lead in the timeline.

MDTs

lua
Config.MDTSystem = 'auto'
SystemSupportAuto orderWhat we can do
lb-tabletSupported1Statement + camera report + alert.
tk_mdtSupported2Statement + camera report with image + alert.
redutzu-mdtSupported3Statement + camera report, text.
drx_mdtDetect only4Nothing pushed — a person BOLO needs a real state id.
origen_policeStub5Alert only.
wasabi_mdtStub6Alert only.
ps-mdtDetect only7No create export. Paper only.

Auto-detect checks the exports, not just the name

A resource that runs under the right name can still be a build without the export the bridge calls. lb-tablet 1.5.3 is one: it has no CreateMDTReport. So before an MDT is used, the bridge checks that the export it would call is really there. It only looks at the export and never runs it.

MDTMust export to be pickedOptional export (only that feature turns off)
lb-tabletCreateMDTReportAddDispatch (alert)
tk_mdtcreatePoliceReport or registerEvidencethe other one of those two, and addCall (alert)
redutzu-mdtCreateEvidence—
origen_policeSendAlert—
wasabi_mdtCreateDispatch—
  • 'auto' skips a running MDT whose build has none of the exports it would be picked for, prints one line with the resource, its version and the missing export, and moves on to the next MDT in the auto order. If nothing is left, it uses 'none'.
  • A named MDT (for example Config.MDTSystem = 'lb-tablet') gets the same check. If it has none of those exports, you get one warning and the bridge uses 'none' until it has them, so pushes are not tried and then failed one by one.
  • A missing optional export turns off only that feature. An lb-tablet without AddDispatch still takes statements and camera reports, and only the dispatch alert is off. A tk_mdt with createPoliceReport but no registerEvidence still takes statements, and only camera reports are off. This is also checked at the moment of each push, so a resource restarted into a different build is picked up without restarting 5code-recognition.
  • A skip is never final. Many MDTs create their exports a moment after they start, once their database is up. So a skipped MDT is checked again a few times in the first minute after the server (or that MDT) starts, and after that each time a statement or camera report is sent, at most every 10 seconds. When the export is there, the MDT is used from then on, without a restart, and the console says so once.
  • Updating the MDT is enough. When the resource that was skipped starts again with a build that has the export, it is picked up, even if auto had picked another MDT lower in the list in the meantime.
Code
[5code-recognition] MDT auto-detect skips lb-tablet (version 1.5.3) for now: it does not export CreateMDTReport (yet), which statements and camera reports need. It is checked again, so an export that turns up later is used without a restart.
[5code-recognition] MDT lb-tablet (version <its version>) has its export(s) now, so statements and camera reports go to it.

The second line only appears if the export turns up later.

Per-MDT options

Case-sensitive. Only the selected MDT's entry is used.

lua
Config.MDT = {
    ['lb-tablet']     = { Mdt = 'Police', TabId = 'reports', TextFieldId = 'description' },
    ['tk_mdt']        = { Page = 'police' },
    ['redutzu-mdt']   = {},
    ['drx_mdt']       = {},
    ['origen_police'] = { Job = 'police' },
    ['wasabi_mdt']    = {},
}
MDTOptionMust match
lb-tabletMdt, TabId, TextFieldIdlb-tablet/config/mdts.json, and your report tab's text-field id.
tk_mdtPageIts page name.
origen_policeJobIts job name.

Report and statement settings

KeyDefaultWhat it does
Config.Report.PushToMDTtrueSend camera reports to the MDT where supported.
Config.Report.MDTOnlyForPolicetrueOnly camera owners with a police job push.
Config.Statement.Delivery'both'paper, mdt, both, or choice.
Config.Statement.AllowAnonymoustrueOnly where the MDT can actually hide the author.
Config.Statement.MDTZones{}Places from which an MDT copy can be sent. Empty = anywhere.
Config.Statement.MdtPerDay5Per author per day.
Config.Statement.MdtMaxAgeHours48Only memories seen in the last 48 h can be sent.

Evidence and Lab ID

lua
Config.EvidenceSystem = 'auto'

A fingerprint or DNA match produces a Lab ID — a separate record that says "the lab matched this sample to this person". It is not a memory and it is not a recognition.

SystemSupportAuto orderNotes
any script, via our exportSupported—GrantLabIdentification. The recommended route.
evidences (noobsystems)Stub1Keep its config.citizens.synced = true. Some v1.3.0 / v1.3.1 builds need a known one-line fix; test one fingerprint analysis after installing.
kartik-evidenceSnippet2A snippet into its own file.
wasabi_evidenceSnippet3Runs on the client, so the client-side settings below apply.

Any evidence script

lua
exports['5code-recognition']:GrantLabIdentification(officerSrc, targetCharKey, opts)

Add your resource to ServerConfig.Api.TrustedResources, and call it from your server code after your own checks — never straight from a client event.

Lab settings

KeyDefaultWhat it does
Config.Lab.Enabledtrue
Seconds604800 (7 days)How long a Lab ID lasts.
RequireCorrectLinktrueGrant only when the police link points at the real owner. A wrong link grants nothing and warns admins.
Recipients'officer'officer, onduty, officer_mdt, or none (admin log only).
RepeatWindowSeconds600The same lab event again within this only refreshes the timer.
PerTargetPerDay3Per officer, per person.

Client-side evidence scripts

Some evidence resources run the whole match on the player's own game instead of on the server. Lab IDs from those get these extra settings:

KeyDefaultWhat it does
ClientTrust.RequireJobtrueMust have a police job.
ClientTrust.RequireDutytrueMust be on duty.
ClientTrust.Zones{}Lab rooms. Empty = anywhere.
ClientTrust.RatePerHour10Per officer.
ClientTrust.CountsForActfalseWhether a client-sourced lab ID also counts for "may act" and for proofs.

Camera reports and the police cap

A hidden-camera recording does not drop a paper by itself. Once the camera's recording reaches 50 % (the HUD shows REC n%, green from 50 %), it waits in the owner's F3 menu → Camera recordings (last 24 h). The owner prints it there once, with the hidden camera in their inventory (3 s "Printing..."). Where an MDT is supported and the owner is police, the MDT copy is sent when the recording is saved. See Hidden Camera & Reports.

An officer who reads a hidden-camera report gets a memory of that person capped:

KeyDefaultWhat it does
Config.Report.PoliceCap60Maximum % from reading a report.
Config.Report.PoliceSeconds604800 (7 days)How long it lasts.
Config.Report.KeepDays60How long the paper stays readable.

The "possible match" hint

After any scan, a player holding a matching report or description may see "Looks like someone you were told about".

KeyDefaultWhat it does
Config.Describe.HinttrueShow the hint at all.
Config.Describe.HintMinPct25From this %. It can never reach the act line.
Config.Describe.HintPoliceOnlytrueOnly Config.Jobs.HintJobs see it.
Config.Jobs.HintRequireDutyfalseWhether the hint job must be on duty.

An empty Config.Jobs.HintJobs = {} turns the hint off for everyone.

Custom

Set Config.PoliceSystem, Config.MDTSystem or Config.EvidenceSystem to 'custom' and fill the branch in bridge/police_server.lua, bridge/mdt.lua or bridge/evidence.lua.

See Writing a Custom Adapter.