In-game modules
Each module is switched on in Config.Modules (see Configuration). All of them identify a player by their Discord id, so players need a linked Discord account. For the API key each module needs, see Installation.
Who is this player in the MDT?
The core links a player to their employee record in the MDT through their Discord id (GET /integrations/ingame/employees/:userId). Results are cached for a minute, and parallel lookups for the same person share one request. Other resources can use this too, see GetEmployee.
dispatch
Brings calls from the game onto the dispatch board, under Meldungen aus dem Spiel (calls from the game). The dispatcher takes a call as an incident there, or dismisses it.
- From other resources: phones, robbery scripts, alarm systems call
ReportCallon the server, or trigger the server eventnp_mdt:dispatch:report. Resources you don't want to edit are bound withConfig.Dispatch.hooks. None of these can be triggered by a client. - Chat command:
/notruf <text>(off by default,Config.Dispatch.command). - Resident reports (
Config.Dispatch.auto, off by default): gunshots and heavy crashes turn into calls with a chance and a delay, the way a resident would call them in. The client only reports the event. Location, quiet zones, exempt jobs, chance and delay are decided on the server. Suppressed weapons report nothing. Several shots in the same area and time window become one call, "N× gemeldet" (reported N times). - Back into the game: when dispatch assigns a unit to a call, its crew gets a blip with a route and a hint. The blip disappears when the call ends or the unit changes. The resource polls every
pollSseconds (scopecalls:read). Turn it off withConfig.Dispatch.notifyUnits = false.
Calls wait in a small in-memory outbox, not on disk: in order, with growing back-off on network errors, and at most maxAgeS (15 minutes) old. A call from a quarter of an hour ago doesn't help anyone.
funk
Funk (radio): the own unit's status and a panic button.
/status <label>sets the status of the unit you're crewing on the dispatch board. Statuses inkeyStatusesalso get bindable keys (Settings → Key Bindings → FiveM, "MDT: Status …"). The MDT checks that you're in the unit and that the status exists.- Panic button (bindable key "MDT: Panikknopf", command
np_mdt_panic): only for people on duty in the MDT. The location comes from the server. It shows up as a high-priority Panikknopf call. Optionally the own unit jumps to an alarm status (panic.status).
tablet
Instead of rebuilding MDT views in game, the tablet shows the real web MDT in a window. /mdt or F10 opens and closes it, and Esc closes it too. The character holds a tablet prop while it's open.
- The client asks the server for a link. The request carries nothing: who is meant is decided by
sourcealone. At most one link per player everycooldownMs, optionally only for certainjobs. - The server requests a one-time link with its key (
POST /integrations/ingame/tablet-links). The link is valid for 60 seconds. The server only passes it on if it points at this exact MDT. - The NUI loads the link in an iframe. The MDT creates a 12-hour session with exactly that person's rights, limited to the key's instance. Until then, reopening the tablet just shows it again. Neu anmelden (log in again) in the frame fetches a fresh link.
Requirements:
Config.Modules.tablet = trueand a scoped key withsessions:ingame.tablet_login.- The person is an active, non-suspended employee.
- The person has logged in to the MDT once in a browser with Discord. The tablet never creates an account.
Every tablet login is recorded in the MDT's audit log with the key and the Discord id.
Cookies in FiveM's browser
The tablet session uses a third-party cookie (SameSite=None; Secure; Partitioned). If FiveM's CEF has trouble with Partitioned, the MDT operator can turn it off with INGAME_TABLET_COOKIE_PARTITIONED=false.
ranks
Maps job grades to rank keys (Config.Ranks). On join and on job change, the resource sends the keys to PUT /integrations/ingame/employees/:discordId/ranks. That replaces only the person's InGame ranks. Discord and manual ranks stay. It only sends when something changed. In the MDT, set each rank's InGame-Schlüssel (inGameKey) under Einstellungen → Ränge.
timeclock
Anyone in one of the configured jobs who goes on duty is clocked in in the MDT. Going off duty, changing jobs or (if enabled) leaving the server clocks them out.
- "On duty" comes from
job.onduty(QBCore),job.onDuty(ESX 1.10+) or the ESXoff<job>convention. - Someone who is already clocked in through Discord when they join isn't clocked out just because they aren't on duty in game yet.
- Like the Discord panel, clocking in requires the badge in the server nickname.
kiosk
A queue ticket machine (Wartenummer-Automat). At a configured location, /wartenummer draws a ticket in the facility's queue, just like at the counter. The server checks that the player is actually at the machine. Queue tickets must be enabled in the facility's settings in the MDT.
ausweis
A service ID card (Dienstausweis) as a usable item (default mdt_dienstausweis). Using it shows players within radius the holder's name, badge number, rank and duty status, read fresh from the MDT each time. Suspended people and non-employees show an invalid card.
The NUI shell
The resource has a single NUI page, a shell with one view per module, built with the Nimbus UI design system. Fonts and icons are bundled offline.
| View | Opened by | Focus |
|---|---|---|
tablet | The tablet module (/mdt) | Keyboard and mouse |
menu | Treatment menu, when ox_lib isn't running | Keyboard and mouse |
progress | Timed actions, when ox_lib isn't running | None |
cpr, intubation, iv, decompression | The four medic minigames | Keyboard and mouse |
debug | /medic panel (debug switch and ACE) | Keyboard and mouse |
A modal view replaces the previous one (a minigame closes the tablet). The progress bar stays on top. Esc closes the most recently opened modal view. Anything that comes back from the NUI is only a request: whatever changes the game is decided on the server.