opx_infinityspawn
spawn
Last updated on
The spawn menu — where a character starts when it enters the world, chosen from a fixed list of places.
Shows a menu of places when a character enters the world and puts the character where the player clicks. Which joins get the menu is set by OFFER_POLICY: the shipped 'first' asks only a character that has never been placed, so a returning player resumes where they left. A player who picks nothing before the deadline is placed by character from their stored position, or at DEFAULT_SPAWN. The coordinates live in the config and never cross the wire: the client sends only the id of a place. Turn it off and every character is placed by character alone.
| Side | both |
| Requires | character (read with OPX.Api.Require at start) |
| Optional | entry (client: the menu waits for it) |
| Contract | spawn v1 — server |
| Config | config/spawn.lua (shared) |
| Data | none |
How a choice runs
- When a joining character gets a living body,
charactercallsspawn.Offer(source, citizenId). A/opx.selectswitch inside the world is placed directly and never offered the menu; a menu still open for the previous character is dropped when it unloads (or replaced by an offer for the new one). Offeranswersfalse(character places the body itself, at once) when the module is off, the policy is'never', no location is usable, a choice is already open, or the policy is'first'and the character already has a stored position.- Otherwise it sends
opx:net:spawn:offer. The client opens the menu as soon asentryreports itself idle (name form and fitting room done) and reportsopx:net:spawn:opened. - The player's window (
TIMEOUT_SECONDS) starts at that report. Before it, onlyHOLD_MAX_SECONDScan end the offer.- While the name form or the fitting room is up, the client tells the server every 30 s (
opx:net:spawn:waiting). Each report pushes the hold a fullHOLD_MAX_SECONDSon, never past 30 minutes from the offer, and stops once the menu is on screen. A slow new player is no longer placed under an open modal.
- While the name form or the fitting room is up, the client tells the server every 30 s (
- A character whose row holds a position gets a first card, Where I left off (Là où j'étais, id
resume): choosing it places the character with no target, so the stored position decides. A character that has never stood anywhere does not get it. - A click sends the place id. The server looks it up in its own list and calls
character.PlaceCharacter. A timeout places the character with no target (stored position, thenDEFAULT_SPAWN). The menu goes down at once; "Spawned at …" is said only once the body has moved, and a refused placement says "You could not be moved there."
Configuration
config/spawn.lua sets OPX.Config.MODULES.spawn.
{ id = 'stoop', label = 'King Stoop forecourt', district = 'Watson', x = -410.22, y = 722.73, z = 115.0, heading = 147.0 },id: 1–32 characters of letters, digits,_ : - .; unique. Sent on the wire, so do not rename one.resumeis reserved for the Where I left off card: an entry with that id is dropped with a warning.label: 1–48 characters, shown on the card.district: up to 32 characters, the hint line. Optional.- Both are translatable: the menu and the Spawned at toast show the locale lines
spawn.place.<id>andspawn.place.<id>.districtwhen they exist (en and fr ship for every shipped place), else this config text. x,y,z: finite numbers. Copy them from the game; a guessed coordinate can drop the player through the world.heading: degrees; missing means0.0(north).- A bad entry is dropped with a warning at start. At most 64 entries are used.
Refusal codes
| Code | Meaning |
|---|---|
spawn.noChoice | No choice is open for you, the id is not in the list, or resume was asked by a character with no stored position. |
error.tooFast | Clicked again inside CHOOSE_COOLDOWN_MS. |