Most settings live in shared/config.lua. Departments are in shared/departments.lua and the penal code in shared/penalcode.lua. These files, together with editable/ and locales/, are not escrowed, so you can edit them freely. Restart the resource after changes.
The quick interaction menu for officers: ask for ID, write a citation, run a plate, parking citation, open the MDT. It works with a radial menu or a target resource.
Option
Default
Description
enabled
true
Turn the interaction menu on or off.
key
'LMENU'
Default key (left Alt). Hidden when a radial or target provider takes over.
command
'mdtinteract'
Command behind the key (registered as +mdtinteract).
radial
'auto'
Radial menu provider: 'auto', a resource name (koja-police, ox_lib, qb-radialmenu), or false / 'off' / 'none'.
target
'auto'
Target provider: 'auto', a resource name (ox_target, koja-interactions, qb-target), or false / 'off' / 'none'.
keyWithProvider
false
Keep the key binding even when a provider is active.
replacePoliceItems
true
With koja-police, replaces its own radial items (check ID, check plate, bill, MDT) with the MDT versions.
distance
4.0
Maximum distance to a person.
vehicleDistance
7.0
Maximum distance to a vehicle.
askConsent
true
The other player is asked before their ID card is shown.
Turn dispatch and the public call commands on or off.
publicCommands
/911 (priority 1), /311 (priority 3)
Commands players use to call. Each entry: command, code, title, priority.
publicCooldown
30
Seconds between public calls from one player.
anonymousCommand
'911a'
Anonymous call command. Empty disables it.
panicKey
'F9'
Default key for the panic button (10-99). Empty disables the key.
panicCooldown
15
Seconds between panic presses.
keepCallsMinutes
30
How long closed calls stay in the log.
maxCalls
80
Maximum calls kept.
blipSeconds
90
How long a call blip stays on the map.
alertSound
true
Play a sound for new priority calls.
toastSeconds
8
How long the call toast shows.
callCodes
six fire codes
Extra call codes { code, title, priority, types }. types is the department types that receive the call (leo, ems, fire). Defaults: F-STR, F-VEH, F-BRU, F-ALM, F-RES, F-HAZ.
Automatic "shots fired" calls. The player's client watches for gunfire and the server turns it into a dispatch call to law enforcement, with a witness as the caller.
Option
Default
Description
enabled
true
Turn gunshot alerts on or off. Also needs Config.Dispatch.enabled.
code
'10-71'
Call code.
title
'Shots fired'
Call title.
priority
1
Call priority.
message
'Caller reports gunshots in the area.'
Call message.
vehicleMessage
'Caller reports shots fired from a vehicle: %s %s.'
Message when the shooter is in a vehicle. The two values are the vehicle color and model.
reportDelay
{ 3, 8 }
Random delay in seconds, { min, max }, before the call appears.
cooldownSeconds
30
Seconds between alerts from one player.
mergeRadius
120.0
Shots within this distance of a recent alert do not create a new call.
mergeSeconds
60
How long a recent alert blocks new ones inside mergeRadius.
fuzzRadius
35.0
The call location is moved by a random distance up to this value, so it is not exact.
ignoreOnDuty
true
Players on duty in one of the ignoreJobs do not trigger alerts.
ignoreJobs
{ 'police', 'sheriff', 'sahp' }
Jobs ignored while ignoreOnDuty is on.
ignoreSilenced
true
Silenced weapons do not trigger alerts.
ignoreWeapons
stun gun, fire extinguisher, petrol and hazard cans, flares, snowball, ball, Up-n-Atomizer
Weapons that never trigger alerts. Weapon names, for example 'WEAPON_STUNGUN'.
ignoreZones
three zones
Places where shooting is ignored, such as gun ranges. Each entry: { coords = vector3(...), radius = 25.0 }.
The Take a photo button for mugshots, evidence and reports. Needs screenshot-basic.
Option
Default
Description
enabled
true
Turn the photo button on or off.
uploadUrl
''
Keyless upload endpoint, for example a Discord webhook. This file is sent to every client, so never put an API key here. For Fivemanage or S3 use Config.Storage (below) with images = 'storage' instead, which uploads through the server. When both are empty the photo button is hidden. Image links can always be pasted by hand.
Where bodycam footage and MDT images are kept. The default keeps everything on the server disk and images inline in the database, exactly as before. See Storage and CDN for step by step setup of Cloudflare R2, AWS S3, Backblaze B2, MinIO and Fivemanage.
Option
Default
Description
driver
'local'
'local', 's3' (any S3-compatible service) or 'fivemanage'.
images
'inline'
'inline' stores uploaded pictures as data URLs in the database. 'storage' uploads them through the server to the driver and saves the public URL.
footage
'local'
'local' keeps bodycam segments in recordings/ inside the resource. 'storage' uploads each segment to the driver and removes the local copy.
segmentSeconds
10
Seconds of footage packed into one segment file (2 to 60). At 8 fps that is 80 frames and 360 uploads per recording hour.
concurrency
3
Parallel uploads and deletes.
maxBacklog
400
Jobs held in memory. Extra segments wait on disk and are picked up every 30 seconds.
s3.endpoint
''
S3 API endpoint, for example https://<accountid>.r2.cloudflarestorage.com.
s3.region
'auto'
'auto' for R2. AWS, B2 and MinIO need their real region, for example 'eu-central-1'.
s3.bucket
''
Bucket name.
s3.publicUrl
''
Public base URL of the bucket (r2.dev, a custom domain or a CDN). Required for images = 'storage'. When set, footage is also served from it instead of presigned links.
Secrets never go in shared/config.lua, because that file is sent to every player. Set them as server convars in server.cfg. Use set, not setr or sets, so they stay on the server:
server.cfg
set koja_mdt_s3_access_key "your-access-key-id"set koja_mdt_s3_secret_key "your-secret-access-key"set koja_mdt_fivemanage_key "your-fivemanage-api-key"
You can also fill editable/server/storage.lua instead. It is loaded on the server only and a non-empty value there wins over the convar.
The startup banner prints a Storage line with the driver and the result of a self-test (HeadBucket for S3, a tiny upload and delete for Fivemanage). Any missing option is printed as a warning and the MDT falls back to local disk and inline images.
The bucket must allow GET from the MDT interface and from your web portal. Paste this CORS policy and replace the last origin with your portal address:
Profile pictures taken from the character's head shot.
Option
Default
Description
enabled
true
Turn avatars on or off.
captureOnLoad
true
Capture when the player loads in.
loadDelaySeconds
10
Delay after load before capture.
refreshMinutes
20
Automatic refresh interval.
command
'mdtphoto'
Command to refresh your photo. Empty disables it.
transparent
true
Transparent background.
size
128
Image size in pixels.
format
'image/webp'
Image format.
quality
0.85
Image quality.
minUploadSeconds
60
Minimum seconds between uploads.
maxLength
150000
Maximum stored image size.
selfie.enabled
true
Selfie photo for the profile. Needs screenshot-basic.
selfie.size
256
Selfie size.
selfie.quality
0.88
Selfie quality.
selfie.cooldownSeconds
20
Cooldown between selfies.
selfie.maxLength
400000
Maximum size of a selfie image in characters. The effective limit is the larger of this and maxLength. A bigger selfie is rejected and the reason is printed in the server console.
Footage is captured by the wearer's client as a series of pictures (needs screenshot-basic), sent to the server in batches and packed into segments. See Storage and CDN for where segments are kept.
Option
Default
Description
enabled
true
Record footage. Live view still works without it.
intervalMs
125
Milliseconds between frames (50 to 10000). 125 is 8 frames per second. See the table below.
maxInFlight
4
Frames captured at the same time on the client (1 to 8). Higher keeps the frame rate steady on a slow machine but uses more CPU.
width
560
Frame width in pixels (160 to 1920).
quality
0.42
Image quality (0.1 to 1.0).
format
'jpg'
'jpg' or 'webp'.
batchFrames
16
Frames sent to the server in one message (1 to 24).
latentBps
400000
Upload speed limit in bytes per second for frame batches. Raise it if frames are dropped at a high frame rate.
maxFrameKB
80
Largest accepted frame (8 to 512). Bigger frames are dropped.
keepDays
14
Days footage is kept (0 keeps it forever). Separate from Config.Bodycams.keepDays, which keeps the session data.
keepLinked
true
Footage attached to an incident is deleted last when the disk limit is reached and is not deleted by keepDays.
maxMinutesPerSession
60
Longest footage per recording (1 to 720).
maxDiskMB
20480
Total disk limit for footage in MB. The oldest footage is deleted when it is exceeded. 0 turns the limit off.
http
true
Serve footage to the player over the web route.
baseUrl
''
Public base URL for footage links. Empty uses the web portal address (Config.Web.publicUrl).
tokenMinutes
10
Lifetime of a playback link in minutes (1 to 120).
List of default divisions created for each department on first start. Each entry has name, short, icon, color, description. Defaults: Firearms, Traffic Enforcement, Detective Bureau, K-9 Unit, S.W.A.T and Human Resources.
Report types { id, label, icon, template }. The template is the starting text of the narrative. Defaults: arrest, citation, traffic, pursuit, investigation, use_of_force, death, other.