Revive and Ambulance Scripts

How Revive works with your ambulance script, which scripts MonoAdmin supports, and how to pick one or write your own revive code in Settings > Advanced.

Revive brings a downed player back. On a roleplay server, though, “dead” is not only the game’s idea: your ambulance script keeps its own death screen, timers and a saved “dead” state, and only that script’s own revive lets go of them. So MonoAdmin sends Revive through your ambulance script when it can, which ends the script’s death state along with the player’s. This page lists the scripts MonoAdmin supports, how Auto-detect chooses, what happens when no script, or the wrong one, is running, and how to write your own revive code for a script that is not on the list.

How Revive Works

When staff use Revive on a player (from the profile in the panel, from the players sheet in game, or on themselves from the Self tab), the resource:

  1. Looks up the ambulance script your project is set to use.
  2. Calls that script’s own revive, so its death screen and state end too. With Custom, your own code runs here instead.
  3. Reads the player back on the server to confirm they are alive. It checks their health and, where your framework can say, that the framework no longer holds them as dead.

If no script is involved, because you chose None or none is running, MonoAdmin’s own revive brings the player back in the game only. If you chose Custom, your own code runs instead of a script (see Custom: Your Own Revive Code). Some frameworks keep a dead flag of their own, and MonoAdmin handles it as follows:

  • ESX: for esx_ambulancejob and brutal_ambulancejob, MonoAdmin first clears the dead flag ESX stores with the character, the same step esx_ambulancejob’s own admin revive takes, and then calls the script. Clearing the stored flag uses oxmysql. With Custom, clearing it is your code’s job. On ESX 1.16 and later, esx_death keeps the death state, and esx_ambulancejob has no revive of its own any more. When esx_death is running, MonoAdmin revives through esx_death, which clears the flag itself.
  • QBCore: the isdead and inlaststand flags are cleared whichever script revives, with Custom as well.
  • Qbox: those flags are cleared when no script is called. When a script is called, such as qbx_medical, the script clears its own. With Custom, clearing them is your code’s job.

Revive needs the Revive permission, and Heal and Revive must be on under Settings > Features. See Player Actions.

Choose the Script: Settings > Advanced

  1. Open Settings > Advanced. You need View Settings to see it and Edit Settings to change it. The default Admin role does not have Edit Settings.
  2. Under Ambulance script, pick one from the list for your framework. The page shows only the choices for the framework your project uses.
  3. The choice saves at once and a toast says Ambulance script saved. Servers that are connected pick it up right away. Custom (your own code) is the one choice that does not save at once, because it needs code: see Custom: Your Own Revive Code.

Under the list, the panel tells you what your server found:

Hint Meaning
Detected on your server: script That script is running and is what Auto-detect would use.
No ambulance script found: MonoAdmin brings players back itself. None of the supported scripts is running.
Connect your server to see which script it runs. The server is offline or not linked.

The hint always names what Auto-detect would use, even while Custom is picked.

Auto-detect (recommended) is the default and is right for most servers. A standalone server has no ambulance script to pick or to detect, so its list has no hint and only two choices: None: MonoAdmin’s own revive, which is the default, and Custom (your own code).

The choice is saved separately for each framework, standalone included. If you change your project’s framework later, each framework keeps its own saved choice. The custom code is not saved per framework: a project has one piece of it.

Supported Scripts

Option in the panel Resource name ESX QBCore Qbox
esx_ambulancejob (ESX’s own) esx_ambulancejob Yes - -
qb-ambulancejob (QBCore’s own) qb-ambulancejob - Yes -
qbx_medical (Qbox’s own) qbx_medical - - Yes
Wasabi Ambulance v1 wasabi_ambulance Yes Yes -
Wasabi Ambulance v2 wasabi_ambulance_v2 Yes Yes Yes
OSP Ambulance osp_ambulance Yes Yes Yes
ARS Ambulance Job ars_ambulancejob Yes Yes -
Brutal Ambulance Job brutal_ambulancejob Yes Yes -
Piotreq Ambulance Job p_ambulancejob Yes Yes Yes
TK Ambulance Job tk_ambulancejob Yes Yes -
Custom (your own code) - Yes Yes Yes
None: MonoAdmin’s own revive - Yes Yes Yes

A script that is not on the list is not supported. With Auto-detect or None, MonoAdmin still brings the player back in the game, but your script’s own death screen or state may stay. To make Revive go through a script that is not on the list, write your own revive code with Custom. On a standalone server the table does not apply: its choices are None and Custom only.

What MonoAdmin Calls

For the curious, or for a server that watches events: this is everything MonoAdmin uses to revive through a supported script. It is a fixed table inside the resource. With a script from the list, the cloud only sends the script’s name, never an event or export, so nothing can make your server trigger some other event. Custom is the one exception, because there the project’s own code is what runs: see Custom: Your Own Revive Code.

Script What MonoAdmin calls
esx_ambulancejob (ESX) On ESX 1.16 and later, with esx_death running: export Revive of esx_death. Otherwise: event esx_ambulancejob:revive on the player
qb-ambulancejob (QBCore) Event hospital:client:Revive on the player
qbx_medical (Qbox) Export Revive
wasabi_ambulance Export RevivePlayer
wasabi_ambulance_v2 Export RevivePlayer
osp_ambulance Event esx_ambulancejob:revive on ESX, hospital:client:Revive on QBCore and Qbox
ars_ambulancejob Event ars_ambulancejob:healPlayer with its revive option on
brutal_ambulancejob Event esx_ambulancejob:revive on ESX, hospital:client:Revive on QBCore
p_ambulancejob Event p_ambulancejob/client/death/revive on the player
tk_ambulancejob Export revive with its revive option on

Events go to the player being revived. Exports are called with the player’s server ID.

On ESX 1.16 and later, esx_death owns the death state, and the old esx_ambulancejob:revive event does nothing there. So when esx_death is running, the esx_ambulancejob choice calls esx_death’s Revive export instead. esx_death saves to your database before it answers, so Revive waits for it, for up to 10 seconds. If esx_death is not running, or has no such export, MonoAdmin sends the old event.

How Auto-Detect Picks

Auto-detect takes the first script on your framework’s list that is started. Your framework’s own script comes first.

Framework Order
ESX esx_ambulancejob, wasabi_ambulance_v2, wasabi_ambulance, osp_ambulance, ars_ambulancejob, brutal_ambulancejob, p_ambulancejob, tk_ambulancejob
QBCore qb-ambulancejob, wasabi_ambulance_v2, wasabi_ambulance, osp_ambulance, ars_ambulancejob, brutal_ambulancejob, p_ambulancejob, tk_ambulancejob
Qbox qbx_medical, wasabi_ambulance_v2, osp_ambulance, p_ambulancejob

If none of them is started, Auto-detect means None. Auto-detect only looks at these scripts. It never runs your custom code: only picking Custom does.

On ESX 1.16 and later, Auto-detect finds esx_death through esx_ambulancejob. If esx_death runs without esx_ambulancejob, Auto-detect finds no script. Then pick another script, or write Custom code that calls exports.esx_death:Revive(source).

Pick a script yourself instead of Auto when you run more than one ambulance script, for example during a move from one to another, and want Revive to go through a specific one.

None: MonoAdmin’s Own Revive

None: MonoAdmin’s own revive calls no script. It restores the player in the game only. Use it when your server has no ambulance script, or when your script has no revive that MonoAdmin knows. The script’s own state, such as a death screen or timers, may stay in place.

Custom: Your Own Revive Code

Custom (your own code) is for a server whose ambulance script is not on the list, or one that needs something different from what MonoAdmin calls. You write Lua in the panel, and the game server runs it every time staff revive a player. In the list for ESX, QBCore and Qbox it sits between the scripts and None, and on a standalone server it is the choice next to None. The guided setup does not offer it: you set it here, in Settings > Advanced.

Custom is for someone who can read and write Lua, and what you write runs on your game server.

Who Can Write It

Two permissions are involved:

  • Edit Settings lets someone pick which revive the project uses, Custom included. Custom needs code to run, so it can be picked only when code is already saved, or saved together with the pick. Until code is saved, the option is greyed out for someone without Advanced Settings.
  • Advanced Settings lets someone write or change the code, on top of Edit Settings, which saving needs. It is a permission of its own (settings.advanced, in the Team & Settings group of the Permission Reference). The project owner has it. The default Admin role does not, and neither does a role that already exists: the owner switches it on for a role on purpose.

Without Advanced Settings the code shows read-only, with the note “Changing this code needs the Advanced Settings permission.” Every change of the code goes into the Audit Logs with who changed it and the new code.

Write the Code

  1. Open Settings > Advanced and pick Custom (your own code) under Ambulance script. Unlike the other choices it does not save at once. A warning that the code runs on your game server appears, with a box for your code, and Cancel puts the list back to its old value.
  2. Type or paste your Lua into Revive code. A counter under the box shows the bytes you use against the limit of 8192.
  3. Press Save Code. A toast says “Custom revive code saved”, and servers that are connected pick the code up right away.
  4. Revive a test player and watch the server console.

An empty box is refused with a message under it. Over the limit, the counter turns red and Save Code stays off. You cannot empty saved code, only replace it. Picking another choice in the list stops the code from running, and the saved code stays stored.

What Your Code Can Use

In your code, source is the player’s server ID: the player being revived. Beyond that it works like a server script, apart from what is blocked below.

  • Natives.
  • Other resources’ exports, such as exports.some_script:SomeFunction(source).
  • TriggerClientEvent, to send an event to a player’s game, and TriggerEvent, to trigger one on the server.
  • Wait, SetTimeout and CreateThread, to do something a little later. Your code runs in a thread of its own, so Wait works anywhere, at the top level too. Use the plain names: Citizen.CreateThread and Citizen.Wait do not work, because Citizen is blocked (see below). Threads and timers you start stop when you save different code.
  • Plain Lua, such as string, table, math, utf8 and json, and os.time, os.clock and os.date. You can read these shared tables but not change them: assigning into string or table is an error.

Keep any wait short, because the player has to be alive within the time described under What Happens After the Code Runs.

What Is Blocked

So that a mistake or a careless script can do less harm, these do not exist inside your code. Reading one gives nothing, and calling one is an error.

Blocked What it covers
The file system io, and reading or writing resource files
OS commands os, except os.time, os.clock and os.date
Debugging debug
Loading other code load, require and dofile
Natives by hash Citizen, which includes InvokeNative
Console commands ExecuteCommand
Convars GetConvar* and SetConvar*
Stored data (KVP) Every key-value storage native: MonoAdmin’s own storage, where the server link’s credential is kept, and other resources’
HTTP requests PerformHttpRequest
Registering things Events, commands and exports: RegisterNetEvent, AddEventHandler, RegisterCommand and exports(...), and also AddStateBagChangeHandler and RegisterResourceAsEventHandler
Console output RegisterConsoleListener and GetConsoleBuffer
Packing data msgpack, which can rebuild a reference to a function that another resource registered
Events raised under another name Every native with Internal in its name, such as TriggerEventInternal, and the natives that copy, delete or call function references
Finalizers __gc in setmetatable: it is an error. getmetatable only answers for your own tables
Starting and stopping resources StartResource and StopResource
MonoAdmin itself MonoAdmin’s own exports and internals

Events Your Code Cannot Raise

TriggerEvent, TriggerClientEvent and TriggerLatentClientEvent refuse some events. Calling one with such a name is an error, whatever the capital letters.

Refused What it covers
MonoAdmin’s own events Any name that starts with monoadmin:, or with the name MonoAdmin runs under (normally monoadmin) and a colon
FXServer’s internal events Any name that starts with __cfx_
Resource and player lifecycle events onResourceStart, onResourceStarting, onResourceStop, onServerResourceStart, onServerResourceStop, onResourceListRefresh, playerConnecting, playerJoining, playerDropped, entityCreated, entityCreating and entityRemoved

Raising these would stop or restart resources, or drop players, for everyone. Every other event goes through as you wrote it.

How Long the Code Can Run

A loop that never ends would freeze your game server. So MonoAdmin counts the work your code does: every pass of a loop, every function call and every goto is one step. If the code, together with the threads and timers it starts, takes more than 1 million steps without waiting (a Wait, or an export that waits), it is stopped with an error. A pcall in your code does not catch that stop. Waiting starts the count again, so code that waits between its steps never reaches the limit. One long call into Lua’s own library, such as string.rep with a huge size, counts as one step, so keep the code simple.

What Happens After the Code Runs

MonoAdmin does not run its own in-game revive after your code. Your code has to bring the player back, usually by triggering your ambulance script’s own revive event or export.

If your code waits, either with Wait or by calling an export that waits for your database, the revive does not hold up the game server. The code goes on in its own thread while MonoAdmin checks the player.

MonoAdmin waits up to 3 seconds for the player to be up. They are up when their health is above 100 and, on ESX with esx_death, on QBCore and on Qbox, the framework no longer holds them as dead. On ESX the health of a dead player stays full, so health alone says nothing there. On a standalone server only health is read. If the player is not up in time, Revive reports that the game server did not confirm. The panel says “The game server did not confirm in time. It may or may not have happened.” and the Audit Logs show Unknown. The server console notes that the revive was still running. Your code keeps going either way, so it can still finish the revive a moment later.

On QBCore, MonoAdmin still clears the isdead and inlaststand metadata itself, as for every QBCore revive. On ESX and Qbox, clearing the framework’s dead state is your code’s job.

When the Code Has an Error

If your code does not compile or raises an error, the revive fails. The panel says “Your custom revive code ran into an error. The game server’s console shows what went wrong.” The console has a warning with the Lua error. Fix the code in Settings > Advanced and revive again.

If the error comes after your code waited, the revive has been answered already. The panel is not told. The console prints revive_code_failed: the custom revive code failed for player ... after it waited, with the Lua error. A thread or timer your code started prints one line, a thread of the custom revive code failed, with the error.

If Custom is picked but no code is saved, Revive falls back to MonoAdmin’s own revive and the console prints a warning. The panel normally prevents this, because Custom cannot be saved without code.

Standalone Servers

A standalone server has no ambulance script MonoAdmin knows, so its list in Settings > Advanced is None: MonoAdmin’s own revive, the default, and Custom (your own code). With None, Revive on a player uses MonoAdmin’s own revive, which restores the player in the game only. With Custom, Revive on a player runs your code, and the in-game menu’s Self tab shows its Revive row, which a standalone server otherwise hides because it needs a framework that revives. When you switch Custom on or off, the server’s link reconnects by itself so the row appears or goes away.

On a standalone server the row’s Down or Not down uses the generic check: the isDead state bag, QBCore-style metadata or the game’s own death. See The Self Tab.

Examples

The scripts in the table above already have presets, so pick the preset for them. These examples only show the shape of the code. For another script, use the event or export it documents.

An event, sent to the player being revived. my_ambulance stands for your script’s own name:

TriggerClientEvent('my_ambulance:revive', source)

An export, called with the player’s server ID. On ESX 1.16 and later the death state belongs to esx_death, and esx_ambulancejob has no revive event any more, so sending esx_ambulancejob:revive does nothing there. This call works:

exports.esx_death:Revive(source)

esx_death saves to your database before it answers, so your code waits at this line. That is fine: see What Happens After the Code Runs.

When the Chosen Script Is Not Running

If you pick a script by name and it is not started at that moment, Revive does not fail. The player is revived the None way, and the server console prints a warning once per revive:

[    script:monoadmin] [warn] [act] the ambulance script chosen in the panel is not running; the player was revived without it script=wasabi_ambulance_v2

Fix it by starting the script, or by switching the panel to Auto-detect or None if you no longer run it. The Detected on your server hint under the list shows what is running.

What Has Been Checked

  • Checked on real servers: esx_ambulancejob on ESX 1.15 (through its own revive event), qb-ambulancejob on QBCore 1.3.0 and qbx_medical on Qbox 1.24.0, each with Auto-detect. Revive ended both death and last stand, and cleared the script’s state.
  • Not yet checked on real servers: the revive through esx_death on ESX 1.16 and later. It is written against esx_death of ESX 1.16.0 and covered by MonoAdmin’s automated tests, but it has not run on a live server yet. If it does not end the death state on yours, pick Custom and call exports.esx_death:Revive(source) yourself, or switch to None. Also not checked: the other scripts in the table. Each one is written against its own documented revive and covered by MonoAdmin’s automated tests, but none has been run on a live server. If one of them does not end its death screen on yours, switch to Auto-detect or None.
  • Custom: it runs code you write, so the check is yours. After you save, revive a test player and read the server console for errors. What the code can use, which events it can raise and how long it can run are covered by MonoAdmin’s automated tests.

The Revive Row in the In-Game Menu

On the in-game menu’s Self tab, Revive shows whether you are Down or Not down, using your script’s own signal where MonoAdmin knows it, and the game’s own death state otherwise. With Custom it uses the generic check: the isDead state bag, QBCore-style metadata or the game’s own death. If you are not down, it answers “You’re not down, so there’s nothing to revive. Heal Self tops up your health.” The row appears on a server with a framework, and on a standalone server only while Revive is set to Custom. See The Self Tab.

On a standalone server there is no ambulance script, so the Self tab hides the row unless Revive is set to Custom. Revive on a player from the panel works either way: with None it uses MonoAdmin’s own revive, which restores the player in the game only, and with Custom it runs your code.