[VORP] [RSG] - GM Mdt

Hello everyone,

GM MDT is the premium centerpiece that ties a police department together: a full Mobile Data Terminal for RedM, presented in-game as an open dossier/ledger book. It’s the record-keeping backbone for serious law-enforcement roleplay containing reports, a citizen database, a serial-numbered weapon registry, bounties, multi-part investigations, a roster with discipline, gangs, and issued papers.

Like the rest of the GM lineup it runs on GM inventory (RSGCore), stock RSG, and VORP, with a bridge layer so you can mix your inventory / jail / notify scripts freely (e.g. gm_inventory for evidence + rsg-prison for jail). The database is self-migrating and the web UI ships pre-built - no SQL import, no build step for a normal install.


Video Preview


What’s included

  • Reports: incident reports & witness statements with suspects, hostages, charges, contraband, an evidence locker, drafts, locking, and live multi-officer collaboration (two officers can edit the same report at once).

  • Charges & sentencing: a configurable penal code; stacked charges compute a proposed fine/jail, and Apply Sentence jails/fines captured suspects through your framework.

  • Citizens: a people database (known & unknown), in-field Identify (walk up, enter a server ID, an identify animation plays), tags, photos, and a lifetime record of total jail time & fines.

  • Weapons registry: serial-numbered firearms with a full lifecycle: register → transfer → stolen → seized → repurpose → retire, plus weapon permits and batch actions.

  • Bounties: wanted bounties on citizens or gangs, with rewards, payouts, and posting to in-world boards.

  • Investigations: multi-section case files linking people, orgs, locations, evidence, reports, notes, and officers, with relationship diagrams, merge, and export.

  • Officers: department roster with offices/ranks, leave of absence, training-role tags (FTI/FTO/FTL/FTC), auto-computed command tiers, and disciplinary strikes.

  • Groups: gang/organization records and membership.

  • Papers: issue official documents to citizens.

  • Discord audit logging: optional, per-event, per-channel webhook logging.

  • Rank-gated everywhere: every tab and button is controlled by a single Config.Permissions rank table; officers only see what they’re allowed to use.


Configurable & extensible

The config, locales, and the framework adapter files are left open, point jail, fines, evidence and notifications at your own scripts without touching the escrow-protected core.


Dependencies

  • oxmysql

  • ox_lib

  • Optional: Our resources are plug and play with the MDT, but remember, you are not limited to those.


Links

Author: ๖ۣۜζ͜͡KiriNoGadian · Built for RedM (RSG / GM / VORP).

Code is accessible No
Subscription-based No
Lines (approximately) More than one could count
Requirements ox_lib,
Support Yes
8 Likes

1.1.0 Officer hiring, weapon control & self-registration

Released 2026-07-22

This update lets the MDT hire, promote, demote, and fire officers for real and the job change is written straight to your framework. It also adds a button to remove the police flag from a weapon, and a small utility to copy a weapon’s serial number on click.

For servers that don’t want every player put on the police record automatically, it adds a registrar’s office: put a clerk on the map and players can walk up, fill out their papers, and enter themselves onto the record.

The database updates itself when the server starts. You do not need to run any SQL.


:warning: Before you update, add these settings

You must add a few new settings to your config. If you skip this, the new buttons will not work.

Open configs/config.lua and do the 3 steps below.

1. Add the new “Employment” block (needed)

Paste this near the top of the file, with your other Config lines:

Config.Employment = {
    civilianJob       = 'unemployed',  -- the job an officer gets when you FIRE them
    defaultStartGrade = 0,             -- the rank a NEW hire starts on
}

  • civilianJob must be a job that exists in your framework (RSG uses unemployed).
  • Hiring an officer replaces the job they had before.

2. Add two new permissions (needed)

Find your Config.Permissions = { ... } list and add these two lines inside it:

    setOfficerRank  = { police = 9 },   -- who can promote / demote officers
    removeWeaponLeo = { police = 13 },  -- who can remove a weapon's police flag

  • police is the job name and the number is the minimum rank.
  • If your police job has a different name or ranks, copy the style of the lines next to it and change the name and number to match your server.

3. (Optional) Give one office the power to hire across all forces

If you run more than one police force and want one top office that can hire and manage every force, add superHire = true to that office. Example:

{ name = 'Marshals Office', assignRank = 15, signature = 'us_marshal.png', superHire = true },

  • An officer in this office can hire, promote, demote, transfer, and fire in any police job, at any rank.
  • Leave it out if you want each force to manage only itself.
  • Normally used for admins, Marshals or DOJ

4. (Optional) Let players register themselves

Only needed if you switch automatic citizen records OFF. If you leave them on, skip this — every player is already on the record and none of the below ever happens.

Find your Config.Citizens = { ... } block and add the Manual part:

Config.Citizens = {
    autoCreate      = false,   -- must be false for any of this to happen
    searchMinLength = 3,

    Manual = {
        enabled = true,

        pedSpawnDistance = 50.0,   -- how close you must be for the clerk to appear
        promptDistance   = 2.0,    -- how close you must stand to get the prompt
        duration         = 5000,   -- how long the paperwork takes, in milliseconds

        locations = {
            Blackwater = {
                loc      = vec4(-798.62, -1194.32, 42.95, -178.08),
                ped      = 'msp_industry1_males_01',
                scenario = 'WORLD_HUMAN_WRITE_NOTEBOOK',
                skipPed  = false,
            },
        },
    },
}

  • autoCreate must be false. With it on, the whole Manual section is ignored.
  • loc is used for both the clerk and the prompt, the four numbers are X, Y, Z and the direction the clerk faces.
  • Add as many locations as you like. Copy the Blackwater = { ... } block, give it a different name, and change the coordinates. The names only exist to keep the file readable.
  • Don’t want a clerk standing there? Add skipPed = true to that location and you get the prompt on its own.
  • Set duration = 0 to skip the paperwork bar entirely.

5. (Optional) Tidy up your Identify settings

The Identify settings moved into one block. Your old settings still work, but the server prints a yellow warning on every start until you move them, so it’s worth two minutes. The old settings will be deprecated and removed in a future release.

If your config has either of these lines:

Config.IdentifyRange     = 2.0
Config.IdentifyMaskCheck = true

replace them with:

Config.Identify = {
    enabled   = true,   -- false = turn Identify off completely
    range     = 2.0,    -- how close an officer must stand, in metres
    maskCheck = true,   -- true = a masked person can't be identified
}

  • The values mean exactly what they did before — only where you write them has changed.
  • enabled is new. It’s the proper way to switch Identify off: the whole feature stops working and the Identify box disappears from the MDT.
  • Don’t use range = 0 to switch it off. range is a real distance, and 0 means “standing in exactly the same spot”, which nobody can do — so Identify just silently never worked. The server now warns you if it finds range = 0. Use enabled = false instead.

Using Discord logging? (only if you set up webhooks)

If you use the Discord audit log, open configs/webhooks.lua and add these new events to the events = { ... } list so the new actions are logged:

        officerRankChanged    = { enabled = true, title = 'MDT — Officer Rank Changed' },
        officerTransferred    = { enabled = true, title = 'MDT — Officer Transferred' },
        weaponLeoRemoved      = { enabled = true, title = 'MDT — Weapon LEO Flag Removed' },
        citizenSelfRegistered = { enabled = true, title = 'MDT — Citizen Self-Registered' },

If you don’t use Discord logging, you can skip this.


Added

  • Real officer hiring and rank control. The Officers tab can now hire, promote, demote, and fire officers, writing the change straight to your framework’s job whether the player is online or offline.
  • Rank rules. An officer can only manage same or lower ranks in their own force and grant a rank at or below their own, unless their office is marked superHire.
  • Move an officer to another force. A superHire officer can change someone’s department, moving them to the new force and station in one step, but not themselves.
  • Works with rsg-multijob (RSG servers). The MDT auto-detects rsg-multijob with no setup and adds, removes, or transfers the law job cleanly.
  • Remove a weapon’s police flag. An officer with the removeWeaponLeo permission can strip the police flag off a weapon that ended up with a civilian.
  • Copy weapon serial. A copy button next to a weapon’s serial number puts it on your clipboard.
  • Register with the authorities. On servers without automatic records, a player can walk up to a clerk and enter themselves onto the police record, fully tied to their real player. This is a must for lawmen as their entries need real ties with the player.
  • The clerk only exists when someone is nearby. Nothing is placed in the world until a player comes within range, and it’s removed again once they leave.
  • Players already on the record get no prompt. The clerk is still there but offers nothing to do, so you can’t register twice by accident.
  • Your name, gender and telegram come from your character, not typed in. The record matches your character exactly, and the server checks you really are at a clerk before filing.

Changed

  • Identify can now be switched off properly, and its settings live in one place. Config.IdentifyRange and Config.IdentifyMaskCheck are now one Config.Identify block with a new enabled switch, while the old lines keep working with a console warning.
  • Citizen records tied to a real player are now protected in the MDT. Linked records show a locked Known status with their telegram no longer hand-editable, while unlinked officer-created records stay fully editable.
  • Pasting report and paper text from Notepad or a document now keeps its layout. Plain-text markers become real formatting and alignment from Word / Docs / web is preserved, with unsupported formatting flattened on paste (use Ctrl+Shift+V for none).
  • The Department field now shows your job’s proper name. An officer’s department reads from the framework job label, so police shows as Lawman, falling back to the plain job name if none is set.
  • The Discord log for a new officer now reads “Officer Hired” (it was “Officer Registered”).
  • Works on GM (RSGCore), plain RSG, and VORP, the hiring works the same on all three.
  • An officer’s station must now be a real station of the force they are in; blank stations are no longer accepted.

Fixed

  • Sentencing no longer marks a report “fully applied” when it wasn’t. Captured suspects with no linked player account are now counted, so the report stays “not fully applied” until every linkable suspect is dealt with and the Apply button never offers one it can’t action.
  • The hire picker no longer lists people who can’t be hired. Citizens with no player account behind them are left out of the Officers-tab hire search instead of appearing and failing with a generic error when picked.
1 Like