Admin Tools
Console commands for server administration and recovery.
mdt_setadmin
Promotes a player to department admin from the server console. Handles every edge case — missing departments, missing ranks, inactive staff, offline players — so you never need to touch raw SQL.
mdt_setadmin <identifier> <job>| Parameter | Description |
|---|---|
identifier | Player's framework identifier (e.g. citizen ID, license, etc.) |
job | Job name matching a key in your departments config (e.g. police, bcso, ambulance) |
This command only works from the server console (source 0). It cannot be run by players in-game.
What it does
- Resolves the department — looks up the job in the database. If it doesn't exist yet but is defined in your config, the department is auto-created (including its default admin rank, templates, and licenses).
- Finds or creates an admin rank — searches for a rank with the wildcard (
*) permission. If none exists, creates an "Admin" rank at the highest priority. - Resolves the staff record — if the player already has a staff record that is fired, suspended, on leave, or inactive, it reactivates them. If no staff record exists, it creates one (using the player's real name if they're online, or a placeholder "Admin Recovery" if offline).
- Promotes to admin — sets the staff member's rank to the admin rank.
- Syncs live state — if the player is online, updates their rank via state bags immediately. Invalidates all rank and permission caches.
Examples
mdt_setadmin license:abc123 police
mdt_setadmin AB12CD34 bcsoEdge cases
| Scenario | Behavior |
|---|---|
| Job not in config or database | Prints error, no changes made |
| Job in config but not in database | Auto-creates department with defaults |
No rank with * permission exists | Creates "Admin" rank at top priority |
| Staff record doesn't exist + player offline | Creates staff with placeholder name "Admin Recovery" |
| Staff record doesn't exist + player online | Creates staff with player's real character name |
| Staff is fired / suspended / on leave / inactive | Reactivates to "active" then promotes |
| Player is online | Live rank sync via state bags |
| Player is offline | Database updated, sync applies on next join |
mdt_runmigration
Re-runs the full database migration pipeline from the server console. Useful for recovery scenarios or after manual database changes.
mdt_runmigrationThis command only works from the server console (source 0). It cannot be run by players in-game.
What it does
- Schema transaction — runs all
CREATE TABLE IF NOT EXISTSstatements for every core table, preserving existing data. - Planner queries — executes post-schema changes: column additions (
ADD COLUMN IF NOT EXISTS), index creation, ENUM modifications, and framework-specific generated columns. - Seed — re-runs the default charges seed (
INSERT IGNORE), adding any missing charge entries without duplicating existing ones. - Updates KVP — sets the migration version key so the next server boot knows the migration is current.
All steps are idempotent — running this on a healthy database is safe and changes nothing.
When to use
| Scenario | Why |
|---|---|
| Tables were accidentally dropped or corrupted | Recreates missing tables without affecting existing ones |
| Updated to a new version and migration didn't run | Forces the full pipeline regardless of KVP state |
| Manual schema changes caused inconsistencies | Planner re-applies column/index fixes |
mdt_fixweaponmodels
Repairs existing weapon rows where the model column stores a human-readable label (e.g. AP Pistol) instead of the weapon hash name (e.g. weapon_appistol). Older inventory bridge hooks wrote labels by mistake, which prevented the MDT from resolving weapon images and display names from data/weapons.json.
mdt_fixweaponmodelsThis command only works from the server console (source 0). It cannot be run by players in-game.
What it does
- Loads
data/weapons.json— the canonical map of hash name → label shipped with the resource. - Builds a reverse lookup (label → hash) so rows whose
modelis a known label can be remapped. - Scans
vx_mdt_weaponsfor every row with a non-emptymodel. - Classifies each row:
- Already valid —
modelis a known hash name (case-insensitive). Skipped. - Remappable —
modelmatches a known label. Queued for update to the correct hash. - Unmatched —
modelmatches neither. Left untouched and listed at the end of the run.
- Already valid —
- Runs one transaction — all remaps are applied in a single
MySQL.transaction.awaitcall.
Example output
[mdt_fixweaponmodels] Scanned 184 rows — 12 already valid, 169 to remap, 3 unmatched
[mdt_fixweaponmodels] Updated 169 weapon row(s).
[mdt_fixweaponmodels] 3 unmatched row(s) left untouched:
- XJ829S (model: Custom Relic)
- QQ3341 (model: RP Hammer)
- MM22C9 (model: Lost MC Blade)When to use
| Scenario | Why |
|---|---|
| Upgrading from a pre-fix version where the ox/qb/jaksam/origen/tgiann inventory bridge wrote labels | Remaps stale rows so weapon images and labels resolve correctly in the MDT |
| Weapon records show "AP Pistol" instead of a proper weapon icon | Indicates the model column holds a label — this command converts it |
| Custom weapons are listed as unmatched | Expected — unmatched rows are left untouched. Add entries to data/weapons.json (hash → label) and re-run to pick them up |
The command is idempotent — running it on a healthy database does nothing. Rows whose model is already a valid hash (or lowercased hash) are skipped.
mdt_refresh_vehicle_cache
Forces a refresh of the vehicle label cache (data/vehicles.json) from a connected client. The cache maps vehicle hashes to display labels and is used to resolve vehicle model names throughout the MDT without needing a connected client on every lookup.
mdt_refresh_vehicle_cacheThis command only works from the server console (source 0). At least one client must be connected — the server picks the first online player and enumerates the full vehicle table from their GTA client.
What it does
- Guards against re-entry — aborts if a refresh is already in progress (boot, manual, or another concurrent call).
- Picks the first connected client — issues a server → client callback that enumerates every loaded vehicle model and its
GetLabelText-resolved display name. - Applies sanity threshold — rejects results below
vehicleCache.minExpectedEntries(default100) to guard against partial client-side failures. - Atomic swap + persist — rebinds
GLOBAL.STORAGE.VEHICLES(never mutates in place) and writesdata/vehicles.jsonwith schema version, count, timestamp, andsv_enforceGameBuildvalue.
When to use
| Scenario | Why |
|---|---|
| GTA game build changed after a DLC update | New vehicles won't resolve until the cache is refreshed |
data/vehicles.json was deleted or corrupted | Auto-refresh will eventually pick it up on next player connect, but manual refresh is faster |
vehicleCache.ttlSeconds = 0 (auto-refresh disabled) | Manual refresh is the only way to update the cache |
| Boot refresh gave up after 5 failed attempts | The warning in the console instructs to run this command to retry |
The cache is populated automatically on the first player connect after a resource start/restart if it's empty or stale. This command is only needed for recovery scenarios or when auto-refresh is disabled.