Skip to Content
ReferenceSpawnmanager Export Contracts

Spawnmanager exports and respawn behavior

The stock spawnmanager controls the local player’s spawning. These are client exports, not server-side character or inventory APIs. A resource using them should declare dependency 'spawnmanager' and have one clearly identified owner of the spawn flow.

Do not add this lab alongside a framework’s character selector, hospital or spawn controller on a live server. Test on an isolated server first. This guide documents the provider implementation at c6afa39 , not every replacement resource with the same export names.

All seven client exports

Call on exports.spawnmanagerInput and resultImportant behavior
addSpawnPoint(spawn)A spawn table; returns its assigned IDValidates coordinates, heading and ped model; changes the table’s model to a hash and adds idx.
removeSpawnPoint(id)The ID returned by addSpawnPointRemoves that registration. Keep the ID rather than guessing it.
loadSpawns(jsonString)JSON text containing a spawns arrayAdds those registrations. It does not read a filename, replace the existing list or return their IDs.
spawnPlayer(spawn, callback)A spawn table, current list position, or omitted selectionStarts asynchronous spawning. The optional callback receives the spawn table, not a new player ID.
setAutoSpawn(enabled)BooleanControls the automatic-spawn monitor.
setAutoSpawnCallback(callback)Callback, or nil to clear itReplaces the monitor’s default action and also enables autospawn. Your callback must perform the spawn.
forceRespawn()No argumentsRequests a monitor-driven respawn; the player must be active and autospawn enabled.

spawnPlayer is not a boolean success function. In the reviewed implementation an existing spawn lock can cause an early return without calling the callback. Model loading can also delay completion. Do not build a retry loop that repeatedly forces respawns or assumes a callback always arrives immediately.

Registered IDs are not always list positions

addSpawnPoint allocates an increasing idx, and removeSpawnPoint searches for that value. However, the numeric overload of spawnPlayer selects an array position. Removing an earlier registration can make these two numbers differ.

For example, add A and B, remove A, and B can retain registration ID 2 while occupying list position 1. Passing B’s registration ID to spawnPlayer is then unsafe. Use the returned ID for removal and a fresh, explicit spawn table for deterministic spawning. Do not rely on an invalid selection being rejected cleanly: the reviewed provider accesses spawn data before its later invalid-index check.

A minimal manual-spawn resource

This lab deliberately does not enable automatic spawning or replace another resource’s callback. It still changes the local player’s model and spawn state, so use it only in a disposable test session with other spawn owners stopped.

Create resources/[local]/doc_spawn/fxmanifest.lua:

fx_version 'cerulean' game 'gta5' dependency 'spawnmanager' client_script 'client.lua'

Create client.lua:

local registeredId local pending = false local model = joaat('a_m_y_business_01') local function spawnDefinition() return { x = -1037.7, y = -2737.8, z = 20.2, heading = 330.0, model = model } end local function registerPoint() if registeredId then return end if not IsModelInCdimage(model) or not IsModelAPed(model) then print('doc_spawn: the configured ped model is unavailable') return end registeredId = exports.spawnmanager:addSpawnPoint(spawnDefinition()) end AddEventHandler('onClientResourceStart', function(name) if name == GetCurrentResourceName() or name == 'spawnmanager' then registerPoint() end end) RegisterCommand('docspawn', function() if pending or not registeredId then return end if GetResourceState('spawnmanager') ~= 'started' then return end if not NetworkIsPlayerActive(PlayerId()) then return end pending = true exports.spawnmanager:spawnPlayer(spawnDefinition(), function(spawn) pending = false print(('Spawn completed at %.1f, %.1f, %.1f'):format(spawn.x, spawn.y, spawn.z)) end) end, false) AddEventHandler('onClientResourceStop', function(name) if name == 'spawnmanager' then registeredId = nil pending = false return end if name ~= GetCurrentResourceName() then return end if registeredId and GetResourceState('spawnmanager') == 'started' then exports.spawnmanager:removeSpawnPoint(registeredId) end registeredId = nil end)

In the server console run refresh, ensure spawnmanager and ensure doc_spawn. Once connected and active, run docspawn in F8. The expected callback reports the configured coordinates. The provider also emits the local playerSpawned event before calling this callback.

The pending flag prevents this lab from starting overlapping requests; it is not a timeout or an override of another resource’s lock. If no callback arrives, inspect F8 for model/loading errors and competing spawn owners. Do not clear the flag in a repeating timer to conceal a stuck spawn.

The stock implementation clears weapons and wanted state during spawning. This is another reason not to use the lab as a production character selector. A client playerSpawned event is not trustworthy evidence for granting server-side items or money.

Load JSON, not a path

This separate example shows the accepted data shape; it is not required by the lab:

local definitions = { spawns = { { x = -1037.7, y = -2737.8, z = 20.2, heading = 330.0, model = 'a_m_y_business_01' } } } exports.spawnmanager:loadSpawns(json.encode(definitions))

Do not pass 'spawns.json' or the Lua table directly. Reading a file is a separate operation. The JSON needs the outer spawns field, and each registration needs valid coordinates, heading and a ped model. When you need to remove exactly the entries you added, call addSpawnPoint individually and retain each returned ID instead.

Mapmanager’s spawnpoint directive is a separate integration; it is not what loadSpawns means.

Automatic-spawn ownership and cleanup

Calling setAutoSpawnCallback also enables the monitor. A callback that only logs a message replaces the default spawn without actually spawning anyone. An empty spawn list is not a valid random-spawn configuration, and forceRespawn() alone does not enable the monitor.

For a dedicated resource that owns autospawn, cleanup order matters:

-- Only the resource that owns the automatic-spawn policy should do this. exports.spawnmanager:setAutoSpawnCallback(nil) exports.spawnmanager:setAutoSpawn(false)

Clearing the callback first avoids unintentionally re-enabling autospawn after disabling it. The manual lab above never acquires this ownership and therefore does not alter either setting during cleanup.

Acceptance checklist and scope

Test one manual spawn, a repeated command during spawning, a doc_spawn restart and a spawnmanager restart. Confirm only the lab’s registration is removed on stop and the point is registered again after the provider restarts. Stop the lab, remove its startup entry and reconnect to restore your normal character flow; stopping a resource does not undo an already completed model change.

This is a source-reviewed example, not an in-game certified spawn resource. Native dispatch, collision at the chosen coordinates and track-specific behavior still require a recorded client/server run. See the stock-resource overview, playerSpawned event and official spawnmanager manual  for related contracts.