ATY Scripts Logo
ATY Scripts/Docs/MDT/Introduction

Introduction

aty_mdt — Advanced Mobile Data Terminal

A professional-grade, multi-department Mobile Data Terminal for FiveM servers running ESX or QBCore, authored by atiysu.


Overview

aty_mdt is a comprehensive, full-featured Mobile Data Terminal built on a modern Vue.js NUI frontend. It is designed from the ground up to serve Police, Sheriff, and EMS departments with a rich set of tools for record-keeping, surveillance, evidence management, and real-time communication.

Key design goals:

  • Multi-Framework: Native support for ESX (Legacy & Modern) and QBCore/Qbox.
  • Permission-Driven: Every action is gated by a per-job, per-grade permission system configurable in config.lua.
  • Live Sync: Data updates (dispatches, unit statuses, chat messages, new records) are pushed in real-time to all open MDTs using GlobalState and client events.
  • Dynamic Themes: The tablet's color scheme, logo, and department title auto-adapt to the player's current job.
  • OneSync Compatible: Bodycam and vehicle cam positions are broadcast server-side at 100ms intervals, ensuring compatibility with OneSync Infinity where entity streaming is limited.

Features

🏛️ Law Enforcement Suite

Feature Description
Citizen Records Full profile view with mugshot, DOB, licenses, vehicles, properties, warrants, notes, reports, and charges
Vehicle Records Lookup by plate, view owner details, registered notes, BOLOs, and vehicle history
Reports Create, update, and delete detailed incident reports with officer/suspect tagging
Incidents Track open/closed major incidents with citizens, priority, and tags
Warrants Issue and close arrest warrants for specific citizens
BOLOs Issue and resolve "Be On the Lookout" notices for people and vehicles
Penal Code Manage charge categories and individual charges with fine/sentence ranges
Judgements Issue fines and prison sentences; automatically creates billing entries
Weapons Registry Register and track weapon serial numbers and owners
License Management Add or suspend any of the configured license types per citizen
GPS Codes Store and share named GPS waypoints within the department
Outfit Codes Store and share saved outfit configurations by rank
Staff Management HR-level ability to fire staff members directly from the MDT
Internal Chat Real-time, job-isolated messaging for on-duty officers
Mugshot Camera First-person mode integration to capture in-game citizen mugshots

🏥 EMS Suite

Feature Description
Treatment Logs Full patient treatment history with body regions and tags
Medications Database Manage a medication catalog with price and dosage information
Medical Bills Issue and view medical bills; integrates with billing scripts
Blood Tests Request a voluntary blood draw from an online citizen; result stored to their profile
Death Records Formal documentation of in-game deaths with cause and damage details

📹 Surveillance System

Feature Description
Static CCTVs View any configured fixed camera around the map
Live Bodycams View the real-time position and heading of any officer wearing their bodycam
Vehicle Cameras Attach a live feed to any vehicle the officer is in
CCTV Creator In-world prop placement tool to add new cameras to the database
CCTV Editor In-world editor to rename, delete, or move existing cameras
Vision Modes Cycle between Normal, Thermal, and Night Vision
Zoom Mouse scroll wheel zooming for static cameras (10°–60° FOV)
Entity Detection Raycast hover shows player name/DOB and vehicle make/plate while in camera view

🧬 Evidence System

Feature Description
Shell Drops Every player firing a weapon drops a shell at their location with a configurable timeout
Flashlight Detection Officers holding a flashlight item can see nearby shells highlighted on screen
Shell Collection Pick up shells (requires evidence bag item) for submission to the locker
DNA Lab Process shells at a dedicated lab location to link them to a weapon/suspect
Evidence Locker Secure storage for collected evidence entries

Dependencies

Resource Purpose Required
aty_lib Core multi-framework library (ESX/QBCore), callbacks, SQL ✅ Yes
ox_lib Blood test progress bar UI and alert dialogs ⚠️ Recommended
aty_dispatchv2 Dispatch system integration for incoming calls ⚠️ Optional
aty_fingerprint Fingerprint merge into citizen profiles ⚠️ Optional

Installation Guide

Step 1 — Download & Place

Place the aty_mdt folder inside your resources directory, typically inside a category folder:

resources/
  [aty]/
    aty_lib/       ← must be present and started first
    aty_mdt/       ← this resource

Step 2 — Database Setup

[!CAUTION] The drop_create.sql file will DROP and recreate all MDT tables. Only run it on a fresh installation. For existing servers, import only the tables you are missing.

Execute the SQL files in the data/ folder in this order:

File When to Run Description
drop_create.sql Fresh install only Creates all MDT tables and seeds default charges and medications
cctv.sql Fresh install Pre-populates the cctv table with city-wide camera positions
esx.sql If using ESX Framework-specific column additions for ESX user tables
qb.sql If using QBCore Framework-specific column additions for QBCore player tables
seed.sql Optional Additional seed data for charges and categories

For ESX servers, the following columns are automatically added to your users table:

ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `blood_type` VARCHAR(10) DEFAULT NULL;
ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `mugshot` LONGTEXT DEFAULT NULL;

Step 3 — Add Items to Inventory

The MDT uses up to five items. Register them with your inventory of choice.

For ox_inventory — Copy from items/ox.lua and paste into your ox_inventory/data/items.lua:

['mdt']          = { label = 'MDT',             weight = 1200, stack = true, close = true },
['bodycam']      = { label = 'Bodycam',          weight = 1200, stack = true, close = true },
['vehcam']       = { label = 'Vehicle Camera',   weight = 1200, stack = true, close = true },
['bullet_shell'] = { label = 'Bullet Shell',     weight = 1200, stack = true, close = true },
['evidence_bag'] = { label = 'Evidence Bag',     weight = 1200, stack = true, close = true },

For QBCore — Copy from items/qb.lua and paste into your qb-core/shared/items.lua. Item images (mdt.png, bodycam.png, etc.) should be placed in qb-inventory/html/images/.

For ESX — Add items via your database items table or through your ESX admin panel. Item names must match exactly.

Step 4 — Resource Startup

Add both resources to your server.cfg. Order mattersaty_lib must start first:

ensure aty_lib
ensure aty_mdt

Configuration Manual

All configuration is done in shared/config.lua. This file is shared between the client and server.

Core Settings

Config.UseQbox = false  -- Set to true if using Qbox (a modified QBCore)
Config.Phone = "none"   -- Phone integration: "none" or "lb" (lb-phone)

Access & Opening Methods

Config.Command = "mdt"               -- Slash command to open the MDT  (/mdt)
Config.Key = "F6"                    -- Default keybind (configurable per-player in GTA settings)
Config.ItemRequired = true           -- If true, player must have the item in their inventory
Config.ItemName = "mdt"             -- The exact item name required
Config.OpenWithItem = true           -- Allow opening via item use
Config.OpenWithCommand = true        -- Allow opening via the command/keybind

[!NOTE] If ItemRequired is true, the server validates the item server-side before the tablet opens, preventing exploits.

Billing Integration

The MDT's judgement system and medical bills can automatically send invoices via a supported billing script.

Config.BillingScript = "esx_billing"  -- Options: "none", "auto", "esx_billing", "okokBilling", "RxBilling"
Config.BillingAccount = "society_police"  -- The society account fines are paid into
Value Behavior
"none" Bills are recorded in the MDT database only; no in-game money is deducted
"auto" Automatically detects which billing script is running on the server
"esx_billing" Uses the standard ESX billing script
"okokBilling" Uses okokBilling or okokBillingV2
"RxBilling" Uses the RxBilling resource

Tablet Themes & Branding

Each job can have its own custom theme. The theme is applied dynamically when the MDT is opened.

Config.TabletTypes = {
    ["police"] = {
        logo = "police_logo.png",       -- Filename in web/build/assets/
        title = "Police Department",    -- Department name shown in the UI header
        primaryColor = "#69FFEC",       -- Main accent/highlight color (hex)
        accentColor = "#69FFEC",        -- Secondary accent (usually same as primary)
        backgroundColor = "#0e1117",    -- Main background color
        secondaryColor = "#161922",     -- Card/panel background color
    },
    ["sheriff"] = { ... },
    ["ambulance"] = { ... },
}

[!TIP] Logo files must be placed inside web/build/assets/. The title field appears in the top-left of the tablet header.

Adding a new department:

  1. Add a new entry to Config.TabletTypes with your job name as the key.
  2. Add the job name as a key in Config.Permissions with the allowed actions.
  3. Restart the resource.

Evidence System

Config.EvidenceSystem = {
    Enable = true,                              -- Toggle the entire evidence system on/off
    MenuCoords = vector3(0, 0, 0),             -- Location of the evidence submission menu (set your coords)
    LockerCoords = vector3(0, 0, 0),           -- Location of the evidence storage locker
    ShellItem = "bullet_shell",                -- Item name for bullet casings
    EmptyBagItem = "evidence_bag",             -- Item required to pick up shells from the ground
    FlashlightItems = {
        "weapon_flashlight",                    -- Weapon model name that acts as a flashlight
        "flashlight",                           -- Alternative item name
    },
    DnaTestDuration = 12,                      -- Duration of the DNA test animation (in seconds)
    DropTimeout = 10000,                       -- Minimum cooldown between shell drops (milliseconds)
    LabCoords = vector4(441.39, -993.46, 30.68, 251.28), -- Location of the DNA Lab (MRPD default)
    SaveInterval = 600000,                     -- How often (ms) shell data is saved to DB (10 minutes)
}

[!IMPORTANT] Set MenuCoords and LockerCoords to real in-world locations on your server. The default vector3(0, 0, 0) will spawn the interaction points at the world origin.

CCTV & Surveillance

Config.AllowCopsEditCCTV = true     -- If true, authorized grades can use the CCTV Creator/Editor
Config.JobRestrictedCCTV = true     -- If true, officers only see cameras tagged with their own job

Config.CCTVJobs = {                 -- Jobs that appear in the "Active Units" list and can use bodycams
    "police",
    "ambulance",
}

Config.BodycamItem = "bodycam"      -- Item name required to toggle bodycam (if itemRequired logic applies)
Config.VehcamItem = "vehcam"        -- Item name required to toggle vehicle cam

[!NOTE] When JobRestrictedCCTV = true, a police officer will NOT see CCTV cameras tagged with job = "ambulance" in the database, and vice versa. Cameras with a NULL or empty job column are visible to all departments.

Personal Lockers

Lockers are personal stash points per-job, using your inventory's stash system via aty_lib.

Config.Lockers = {
    ["police"] = {
        { coords = vector3(450.44, -992.33, 30.68), label = "Personal Locker" }, -- MRPD
        { coords = vector3(-1107.82, -825.21, 19.31), label = "Personal Locker" }, -- Vespucci
    },
    ["sheriff"] = {
        { coords = vector3(1851.52, 3690.62, 34.22), label = "Personal Locker" },
    },
    ["ambulance"] = {
        { coords = vector3(301.88, -597.51, 43.28), label = "Personal Locker" },
    }
}

Each entry creates an interaction zone near the specified coordinates. The stash holds up to 50 slots and 100,000 weight units.

Permissions System

This is the most powerful part of the configuration. Every action in the MDT is gated by this table.

Config.Permissions = {
    ["police"] = {
        -- Set to `true` to allow ALL grades in the job to perform this action.
        -- Set to a table of grade numbers (e.g., {2, 3, 4}) to restrict to those grades only.

        ["create_report"]             = true,      -- All police can create reports
        ["update_report"]             = {4},        -- Only grade 4 can edit reports
        ["delete_report"]             = {4},
        ["create_evidence"]           = true,
        ["delete_evidence"]           = {4},
        ["create_warrant"]            = true,
        ["close_warrant"]             = {1, 2, 3, 4},
        ["create_bolo"]               = true,
        ["update_bolo"]               = true,
        ["resolve_bolo"]              = true,
        ["create_incident"]           = true,
        ["update_incident"]           = true,
        ["delete_incident"]           = {4},
        ["create_weapon"]             = {2, 3, 4},
        ["delete_weapon"]             = {2, 3, 4},
        ["add_license"]               = {2, 3, 4},
        ["suspend_license"]           = {2, 3, 4},
        ["create_note"]               = true,
        ["delete_note"]               = {2, 3, 4},
        ["manage_cctv"]               = {4},        -- Only grade 4 can add/edit/delete CCTV cameras
        ["use_bodycam"]               = true,
        ["use_vehcam"]                = true,
        ["declare_deceased"]          = {2, 3, 4},
        ["create_judgement"]          = true,       -- All officers can issue fines/sentences
        ["create_charge"]             = {4},        -- Only grade 4 can add new penal code charges
        ["update_charge"]             = {4},
        ["delete_charge"]             = {4},
        ["create_charge_category"]    = {4},
        ["update_charge_category"]    = {4},
        ["delete_charge_category"]    = {4},
        ["manage_gps_codes"]          = {3, 4},
        ["manage_outfit_codes"]       = {3, 4},
        ["manage_staff"]              = {4},        -- Only grade 4 can fire staff from MDT
    },
    ["ambulance"] = {
        ["create_treatment"]  = true,
        ["delete_treatment"]  = {3},
        ["create_medication"] = {3},
        ["delete_medication"] = {3},
        ["create_bill"]       = true,
        ["create_note"]       = true,
        ["delete_note"]       = {2, 3},
        ["manage_gps_codes"]  = {2, 3},
        ["manage_outfit_codes"] = {2, 3},
        ["manage_staff"]      = {3},
        ["declare_deceased"]  = {2, 3},
        ["create_evidence"]   = true,
        ["delete_evidence"]   = {3},
        ["create_report"]     = true,
        ["update_report"]     = {3},
        ["delete_report"]     = {3},
    },
}

[!IMPORTANT] Jobs NOT listed in Config.TabletTypes cannot open the MDT at all, regardless of permissions. Config.Permissions only controls what actions are available to jobs that CAN open the tablet.

Firing (HR action):

Config.FireJob = "unemployed"  -- The job name assigned when firing a staff member
Config.FireGrade = 0           -- The grade assigned after firing

Licenses Configuration

These are the in-game licenses that can be added/suspended per-citizen.

Config.Licenses = {
    { id = 1, type = "drivers_license", label = "driver_license"  },
    { id = 2, type = "pilot_license",   label = "pilot_license"   },
    { id = 3, type = "weapon_license",  label = "weapon_license"  },
    { id = 4, type = "boat_license",    label = "boating_license" },
}

The type field is the value stored in the database; label is what is displayed in the UI locale system.

Database Table Names

If your server uses non-standard table names (e.g., QBCore uses players instead of users), update these:

Config.Tables = {
    Users    = "users",           -- Main player table (ESX: "users", QBCore: "players")
    Vehicles = "owned_vehicles",  -- Vehicle table (ESX: "owned_vehicles", QBCore: "player_vehicles")
    -- All other tables are MDT-specific and do not need to be changed normally
    Note = "mdt_user_notes", Warrant = "mdt_user_warrants", Report = "mdt_reports",
    Evidence = "mdt_evidences", Treatment = "mdt_treatments", Medication = "mdt_medications",
    Bill = "mdt_bills", ChatMessage = "mdt_chat_messages", CCTV = "cctv",
    Incident = "mdt_incidents", Charge = "mdt_charges", ChargeCategory = "mdt_charge_categories",
    Bolo = "mdt_bolos", Weapon = "mdt_weapons", Death = "mdt_deaths",
    Judgement = "mdt_user_judgement", UserReports = "mdt_user_reports",
    VehicleBolos = "mdt_vehicle_bolos", GpsCode = "mdt_gps_codes",
    OutfitCode = "mdt_outfit_codes", BloodTest = "mdt_user_bloodtests",
}

BOLO Settings

Controls the date picker range when setting a BOLO's expiration date.

Config.BoloSettings = {
    MinDays = 1,   -- Minimum days from today the expiration date can be set
    MaxDays = 30,  -- Maximum days from today the expiration date can be set
}

Date Formats

Controls how dates are displayed throughout the MDT UI.

Config.DateFormat     = "%d/%m/%Y"           -- Used for dates (e.g., 05/04/2026)
Config.DateTimeFormat = "%d/%m/%Y %H:%M"     -- Used for timestamps (e.g., 05/04/2026 14:30)

These use standard Lua os.date format strings.

Fingerprint Integration

If you run aty_fingerprint alongside the MDT, citizen profiles can be automatically enriched with fingerprint data.

Config.FingerprintMerge = {
    Enabled  = false,              -- Set to true to enable
    Resource = "aty_fingerprint",  -- The resource name of your fingerprint script
}

When enabled, the MDT citizen list is merged with fingerprint records. Only DB fields that exist in both systems are overwritten. Matching is done by identifier (ESX) or citizenid (QBCore/Qbox).

Phone Integration

Config.Phone = "lb"  -- Set to "lb" to enable lb-phone integration for phone number lookups

Other Settings

Config.EnableTransparencyOnLeave = true  -- Tablet becomes semi-transparent when mouse is outside the NUI area,
                                          -- allowing the player to move while the MDT is open
Config.AutoRegisterWeapons = true        -- Automatically pulls weapons from player inventories and
                                          -- displays them in the Weapons Registry

Config.BloodTypes = {"A+","A-","B+","B-","AB+","AB-","O+","O-"}  -- Valid blood type options
Config.BloodTestDuration = 10000         -- How long the blood draw animation takes (ms)

Config.DefaultProfileImage = "https://..."  -- URL for citizens who have not had a mugshot taken
Config.ImageWebhook = "https://discord.com/api/webhooks/..."  -- Discord webhook for uploading mugshot photos

Config.ReportLocations = {               -- World positions where officers can create a report by pressing E
    vector3(441.21, -981.85, 30.69),    -- MRPD
    vector3(-1098.37, -830.7, 19.3),    -- Vespucci
}

Localization

The MDT supports multiple languages. The language is set at the top of shared/locale.lua:

Locale = "en"  -- Change this to switch language

Supported languages out of the box:

Code Language
en English
tr Turkish
fr French
es Spanish
de German
pt Portuguese

Adding a new language:

  1. Open shared/locale.lua
  2. Find the ["en"] = { ... } block and copy it entirely
  3. Paste it below, rename the key to your language code (e.g., ["it"])
  4. Translate all string values inside the block
  5. Change Locale = "it" at the top of the file

Usage Guide — Law Enforcement

Opening the MDT

There are three ways to open the MDT:

Method Requirement Notes
Keybind (default F6) Player must be a valid job Rebindable in GTA V key settings
Command (/mdt) OpenWithCommand = true in config Can be disabled
Item Use ItemRequired = true and possess mdt item Item is validated server-side

When the MDT opens, the player's character plays a tablet-holding animation and a physical tablet prop (prop_cs_tablet) is attached to the left hand.

Dashboard & Active Units

The Dashboard is the first screen shown. It displays:

  • Your profile card: Name, rank, department, and current status
  • Active Units: A real-time list of all online officers that belong to Config.CCTVJobs, showing their name, rank, callsign, and current street location (updated every 10 seconds)
  • Recent Dispatches: The last 50 incoming dispatch alerts from aty_dispatchv2

Changing Your Status: Click your status button on your profile card to cycle through:

  • Available
  • Busy
  • Off Duty
  • On Scene

Your status is broadcast server-side via GlobalState and appears on all other officers' dashboards in real-time.

Responding to a Dispatch: Click Approve on any incoming dispatch to set your GPS waypoint to the incident location. Click Decline to dismiss it from your view.

Citizen Records

Navigate to the Citizens tab to search and browse all players registered in your server's database.

Search: Type any part of a citizen's name or identifier to filter the list instantly.

Citizen Profile View: Click on a citizen to expand their full profile, which includes:

Section Contents
Personal Info Mugshot, full name, DOB, sex, phone number, blood type
Licenses Active/suspended status for all configured license types
Vehicles All registered vehicles with model, make, and plate
Properties Any registered properties
Notes Internal department notes (visible/restricted by job)
Reports All reports the citizen is linked to
Warrants Active and closed warrants
Judgements All issued fines and prison sentences across all departments
Blood Tests Results from any blood tests conducted by EMS

Taking a Mugshot: From the citizen profile, click the Take Mugshot button. The MDT will close and put you into a first-person camera mode. Press Left Click or D-Pad Down (controller) to capture the screenshot. The image is uploaded to your configured Discord webhook and saved to the citizen's profile.

Vehicle Records

Navigate to the Vehicles tab to search all registered vehicles.

Search by Plate: Type a plate number to instantly filter.

Vehicle Profile View:

  • Owner name and identifier
  • Vehicle make and model (resolved from GTA V game hashes)
  • Registration status
  • Attached notes and BOLOs

Reports

Action Required Permission Description
Create create_report Opens a form to document an incident with officers, suspects, vehicles, weapons, and evidence fields
Update update_report Edit an existing report's content
Delete delete_report Permanently remove a report

Reports support a risk level (Low / Medium / High / Critical) with color coding.

Reports can also be created in-world by walking up to one of the Config.ReportLocations coordinates and pressing E.

Incidents

Incidents are for tracking ongoing major events (e.g., a bank robbery in progress).

Field Description
Name The incident title
Priority Low / Medium / High / Critical
Status Open / Closed
Citizens Tag citizens involved
Tags Freeform tags
Description Detailed narrative

Warrants

Action Permission Notes
Create Warrant create_warrant Must specify citizen, reason, and expiration date
Close Warrant close_warrant Requires selecting a closure type (e.g., "Served", "Dismissed")

Active warrants appear prominently on a citizen's profile.

BOLOs (Be On the Lookout)

BOLOs are broadcast alerts for suspects or vehicles that officers should watch for.

BOLO Fields:

  • Title and description
  • Suspect tags (dangerous, armed)
  • Optional vehicle information
  • Priority (Low / Medium / High / Critical)
  • Expiration date (within the MinDaysMaxDays configured range)

Charges & Penal Code

The Charges tab lists all configured penal code entries. These are used when creating a Judgement against a citizen.

Action Permission
Create charge category create_charge_category
Create charge create_charge
Update charge update_charge
Delete charge delete_charge

Each charge has: category, title, type (Infraction/Misdemeanor/Felony), minimum/maximum fine, minimum/maximum sentence, and priority.

Weapons Registry

Weapons can be registered manually or automatically:

  • Manual: From the Weapons tab (requires create_weapon permission)
  • Automatic: Set Config.AutoRegisterWeapons = true to pull all weapons from player inventories
  • Via Export: Other scripts can register weapons using exports['aty_mdt']:RegisterWeapon(data)

Each weapon has: serial number, type, label (friendly name), owner name, date registered, and created-by officer.

Evidence System Usage

Shell Collection Workflow:

  1. An officer fires their weapon → a shell is automatically dropped at their position (subject to DropTimeout cooldown).
  2. Any officer holding a flashlight item (see Config.EvidenceSystem.FlashlightItems) will see nearby shells highlighted with yellow markers.
  3. Walk within 1.5m of a shell and press E (while holding the flashlight) to pick it up. You must have an evidence_bag in your inventory.
  4. The collected shell appears in the MDT Evidence tab.

DNA Testing: Go to the Config.EvidenceSystem.LabCoords location. Open the MDT Evidence tab and click Run DNA Test on a collected shell. After a short animation, the shell is linked to the weapon used to fire it (and by extension, to the weapon's registered owner).

Evidence Locker: Evidence can be submitted to a secure locker at Config.EvidenceSystem.LockerCoords. This changes the evidence status from collected to deposited.

GPS & Outfit Codes

Officers with manage_gps_codes or manage_outfit_codes permission can access these sections.

  • GPS Codes: Named waypoints that any officer in the department can quickly set as their GPS destination (e.g., MRPD Front, Hospital).
  • Outfit Codes: Stored outfit configurations indexed by rank/grade. Officers can apply a saved outfit instantly.

Internal Chat

The Chat tab provides a department-isolated messaging channel. Messages are stored in the database and loaded on MDT open. New messages are pushed in real-time to all online officers of the same job.

The chat is visible to all grades of the department but cannot be seen by officers of other departments.

Staff Management

Officers with the manage_staff permission (typically grade 4) can access the Staff tab to view all online/offline staff and fire them. Firing a staff member assigns them Config.FireJob and Config.FireGrade.


Usage Guide — EMS / Ambulance

EMS players see a different set of tabs when they open their MDT (with a red ambulance theme).

Patient Management (Treatments)

Action Permission
Create treatment log create_treatment
Delete treatment log delete_treatment

Treatment logs include: patient name, citizen identifier, treatment title, description, body regions affected, and tags.

Medications Database

Action Permission
Add medication create_medication
Delete medication delete_medication

Medications have: name, description, price, and optional dosage range (min/max). These are used as a reference catalog for available medications.

Medical Bills

Action Permission
Create bill create_bill

Bills can be sent to an online citizen. If Config.BillingScript is set (not "none"), the money is deducted from the citizen's in-game bank account. Bills also appear in the citizen's Judgements tab for the police to see (labeled [EMS]).

Blood Tests

The blood test system allows EMS to formally document a citizen's blood type.

Workflow:

  1. EMS officer opens a citizen profile in the MDT.
  2. Clicks Request Blood Test.
  3. If the citizen is online, they receive an ox_lib alert dialog asking them to consent.
  4. If they accept, a progress bar animation plays (ox_lib required).
  5. Once complete, the citizen's blood type is determined (from DB or randomly assigned) and saved to the mdt_user_bloodtests table.
  6. The result appears on the citizen's profile in the MDT.

[!NOTE] Blood tests require ox_lib to be installed and started. Without it, only a basic notification is shown and the interactive flow does not work.

Death Records

Action Permission
Declare deceased declare_deceased

Death records include: citizen identifier, name, reason, damage description, status (e.g., DOA), tags, date of death, and the declaring officer.


Surveillance System

Static CCTV Cameras

The MDT Surveillance tab displays all cameras from the cctv database table. Clicking View on a camera closes the tablet and activates the camera feed.

CCTV camera props are dynamically spawned in-world when a player gets within 50 meters of the camera's coordinates. They are automatically cleaned up when the player moves beyond that distance.

Live Bodycams

When an officer activates their bodycam item (bodycam), they register a "dynamic camera" on the server under type = "bodycam". This feed appears in the MDT Surveillance list and can be viewed by any authorized officer.

Server-Side Position Broadcast: Due to OneSync Infinity limitations (entities outside a viewer's streaming range cannot be found by network ID), the bodycam position is broadcast server-side every 100ms directly from the owner's ped coordinates. This ensures the camera feed follows the officer accurately regardless of distance.

Vehicle Cameras (Vehcam)

Similar to bodycam but attached to a vehicle. The officer must be inside a vehicle to activate it. The vehicle's plate and model are used as the camera label.

Only one vehicle camera can be active per player at a time.

CCTV Creator Mode

Officers with the manage_cctv permission can add new cameras to the world.

How to Start: From the MDT Surveillance tab → Add Camera button (or via a server event trigger aty_mdt:startCCTVCreator).

Creator Controls:

Key Action
Move mouse The camera prop follows your gameplay camera raycast
/ Arrow Keys Rotate camera heading
Arrow Key Cycle to next camera prop model
Arrow Key Cycle to previous camera prop model
G Toggle pole attachment on/off
Enter Confirm placement (opens name input)
Backspace Cancel and exit creator

Prop Models Available:

  • prop_cctv_cam_06a
  • prop_cctv_cam_02a
  • m24_1_prop_m24_1_carrier_bank_cctv_02
  • prop_cctv_cam_05a
  • p_cctv_s
  • prop_cctv_cam_04c
  • hei_prop_bank_cctv_01
  • xm_prop_x17_server_farm_cctv_01

After pressing Enter, a text input appears. Type the camera name and submit to save it to the database.

CCTV Editor Mode

Hover your gameplay camera over any existing CCTV prop to select it (it will highlight in red). When selected:

Key Action
DEL Delete the camera from the database
R Rename the camera (opens name input)
E Delete and re-enter Creator mode with the same prop model to reposition
Backspace / ESC Exit editor mode

Camera View Controls

When viewing any camera (static or dynamic):

Key Action
W / S Tilt camera up / down
A / D Pan camera left / right
Mouse Scroll Up Zoom in (static cams only, min FOV: 10°)
Mouse Scroll Down Zoom out (static cams only, max FOV: 60°)
E Cycle vision mode (Normal → Thermal → Night Vision)
Backspace Exit camera view and return to normal

Vision Modes are disabled for dynamic (bodycam/vehcam) feeds; they only work on static CCTV cameras.

Entity Detection: While in camera view, a raycast runs continuously from the camera's crosshair. If it hits a player, their name, DOB, and sex are shown in a HUD overlay. If it hits a vehicle, the make, plate, and class are displayed.


Dispatch Integration

aty_mdt listens for the aty_dispatchv2:client:sendDispatch event from aty_dispatchv2. When a dispatch is received:

  1. It's added to an in-memory list (max 50 entries)
  2. It's pushed to the MDT NUI in real-time
  3. Officers can Approve (sets GPS waypoint) or Decline (dismisses) the call

Expected Dispatch Data Format:

TriggerClientEvent("aty_dispatchv2:client:sendDispatch", -1, {
    title = "Armed Robbery",
    code = "10-30",
    message = "Armed robbery in progress",
    jobs = {"police", "sheriff"},            -- Which jobs receive this dispatch
    coords = vector3(441.0, -981.0, 30.0),  -- Map blip location
    image = "https://...",                   -- Optional image URL
    information = {
        description = "Suspect armed with pistol",
        caller = "John Doe",
        gender = "Male",
        street = "Elgin Avenue, Downtown LS",
        phone = "555-0100",
    }
})

Personal Lockers Usage

Once configured in Config.Lockers, a persistent stash interaction appears near each locker coordinate.

  • Walk within interaction range and press E to open your personal locker.
  • The stash is linked to your player identifier, so only you can access it.
  • Capacity: 50 slots / 100,000 weight units.
  • Lockers use your server's inventory system via aty_lib's RegisterStash module.

Developer Exports

Server-Side: RegisterWeapon

Register a weapon serial number into the MDT database from any other resource. Triggers a live update for all open MDT tablets.

---@param data table
---@return boolean success
local success = exports['aty_mdt']:RegisterWeapon({
    serialNumber = "SN-123456",   -- required: unique serial number string
    owner        = "John Doe",    -- required: the owner's display name
    type         = "WEAPON_PISTOL", -- optional: weapon type/model string
    label        = "Combat Pistol"  -- optional: friendly weapon label
})

if success then
    print("Weapon registered in MDT successfully.")
end

Use Cases:

  • A gun shop script can call this when a weapon is sold.
  • A crafting script can register crafted weapons.
  • An admin script can bulk-register weapons.

Database Schema Reference

The following tables are created by data/drop_create.sql:

Table Purpose
mdt_user_licenses Citizen license records (type, status)
mdt_user_judgement Police fines and prison sentences
mdt_user_notes Internal department notes per citizen
mdt_user_warrants Active and closed arrest warrants
mdt_user_reports Reports that a citizen appears in
mdt_user_bloodtests Blood test results (auto-created on first run)
mdt_reports Full report documents with all linked data
mdt_incidents Major incident tracking
mdt_evidences Physical evidence entries
mdt_evidences_shells Bullet casings collected from crime scenes
mdt_bolos "Be On the Lookout" notices
mdt_vehicle_bolos Vehicle-specific BOLOs
mdt_vehicle_photos Photos attached to vehicle records
mdt_vehicle_notes Notes attached to vehicle records
mdt_weapons Weapon serial number registry
mdt_charges Penal code charges
mdt_charge_categories Categories for penal code charges
mdt_treatments EMS treatment logs
mdt_medications EMS medication catalog
mdt_bills Medical bills issued by EMS or fines recorded internally
mdt_deaths Death records declared by EMS or police
mdt_chat_messages Persistent department chat history
cctv Static CCTV camera locations
mdt_gps_codes Named department GPS waypoints
mdt_outfit_codes Saved outfit configurations by grade

Columns added to your framework's player table:

-- For ESX (users table):
ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `blood_type` VARCHAR(10) DEFAULT NULL;
ALTER TABLE `users` ADD COLUMN IF NOT EXISTS `mugshot` LONGTEXT DEFAULT NULL;

Troubleshooting

MDT won't open

  • Ensure aty_lib is started before aty_mdt in server.cfg.
  • Ensure your player's job name exists as a key in Config.TabletTypes.
  • If ItemRequired = true, confirm the player has the mdt item in their inventory.
  • Check the server console for errors from aty_lib or aty_mdt.

"You do not have permission" when trying an action

  • Check Config.Permissions for the player's job.
  • Verify the player's grade matches the required grade list for that action.
  • Grades in QBCore start at 0, in ESX they may start at 0 or 1 depending on your setup.

Blank citizen profiles / "Could not retrieve MDT data"

  • Verify Config.Tables.Users matches your database's player table name.
  • Ensure your database user has SELECT privileges on that table.
  • Check that aty_lib's SQL module is correctly initialized.

"Camera not found" error

  • Ensure you imported data/cctv.sql into your database.
  • Try refreshing cameras from the CCTV tab in the MDT.
  • Wait a few seconds after opening — the server throttles CCTV loads to every 5 seconds.

Bodycam / Vehcam feed is frozen or not moving

  • This is normal if the officer is not moving — the server only updates every 100ms.
  • Ensure the officer is online and within rendering range is not required due to the server-side broadcast system.
  • If aty_mdt:forceCloseDynamicCam was triggered, the officer's camera was deactivated (they disconnected or died).

Blood test doesn't work / no prompt appears

  • Install and ensure ox_lib is started on your server.
  • Without ox_lib, only a notification is shown; no interactive flow is triggered.

MDT UI is blank after modifying the web source

  • Run npm install followed by npm run build inside the web/ directory.
  • Ensure the built files exist in web/build/.

Dispatch calls not appearing in MDT

  • Ensure aty_dispatchv2 is started and sending the aty_dispatchv2:client:sendDispatch client event.
  • Check that the dispatch's jobs array includes the officer's job name.
  • The MDT only receives dispatches if the tablet is already open at the time the event fires; previously received dispatches are stored in memory for the session.

FAQ

Q: Can I add more than 3 jobs (police, sheriff, ambulance)?
A: Yes. Add a new entry to Config.TabletTypes and Config.Permissions with your custom job name. Any job listed in TabletTypes can open the MDT.

Q: Can civilians open the MDT?
A: No. Only jobs listed in Config.TabletTypes can open the tablet, regardless of item possession.

Q: Do I need to restart the resource after editing config.lua?
A: Yes. The config is loaded at startup on both client and server. A full restart aty_mdt is required for config changes to take effect.

Q: How do I change the CCTV camera range for prop spawning?
A: The prop spawning range (50m) and the locker interaction range are hardcoded in client/system/cctv.lua. You can modify the dist < 50.0 check to your desired value.

Q: Does this work with ox_inventory?
A: Yes. aty_lib abstracts the inventory interaction, supporting ox_inventory, qb-inventory, ESX's default inventory, and others.

Q: Can two officers view the same bodycam simultaneously?
A: Yes. The server-side observer system (DynamicCamObservers) supports multiple viewers per dynamic camera. Each viewer receives position broadcasts independently.

Q: Is there a way to programmatically open the MDT for a player?
A: Yes. Trigger the following event from the server:

TriggerClientEvent("aty_mdt:client:open", playerSource)

This runs all the same item and job checks as the keybind/command.


Developed by atiysu — part of the [aty] resource collection.

ATY Scripts LogoATY SCRIPTS

Creamos scripts de FiveM altamente optimizados para QBCore y ESX. Máximo rendimiento, código preciso, cero lag.

Unirse a la comunidad

Socio

Socios oficiales de Tebex. Pago seguro e integración con Cfx.re Keymaster.

Legal

Sin afiliación con Rockstar Games, Cfx.re, FiveM ni Take-Two Interactive. Las compras se rigen por los Términos de Servicio de Tebex.

© 2026 ATY SCRIPTS. Todos los derechos reservados.