The server owns spawn-point selection, apart from the world baseline and the spawn packets
Status: Accepted (2026-06-24)
Context
A player materializes in two places: the connect spawn (SpawnPlayer) and every respawn (RespawnPlayer, broadcast to the others as PlayerSpawned). Where that happens is a gameplay decision the server must make: a client that picked its own spawn could put itself anywhere. If the point were a constant written into each packet builder, connect and respawn could drift apart, and a gamemode would have no single place to change it.
The spawn point also looks like a "server default", next to the clock and the weather of the world baseline (ADR 0010). It is a different kind of authority, though: time and weather are one global environment, while a spawn point is a per-player choice of where to place someone.
Decision
- A spawn policy owns the choice.
SpawnPolicy(src/spawn.rs) answersselect()with aSpawnPoint: position, heading in degrees and the interior the point is in (0 = outside). The packets only carry the chosen point; the policy decides it. The gamemode API takes the heading in degrees, the spawn packets carry radians. - A core default plus a gamemode override. The server has one fixed default point. A gamemode replaces it server-wide with
dlmp.set_spawn_point{x, y, z, heading, interior}(facadeset_spawn, validated like every spawn point); clearing the override restores the default. Changing the policy does not move players who are already in the world: it applies to the next selection. - One source for every spawn path.
player:spawn{...}without a position spawns at the policy point (ADR 0023); a respawn without a per-death decision of the gamemode uses it too (ADR 0020); the first streaming of a newcomer is seeded around it. The facade reads the current choice withspawn_point(). - The spawn point is not part of the world baseline. The baseline keeps only time and weather.
- No player argument yet.
select()returns one point for everyone. Per-player spawn classes are not built until a gamemode needs them; a respawn point for one particular death is a separate, short-lived decision (ADR 0020).
Consequences
- Connect and respawn cannot disagree about the default point, and changing spawn rules never changes the wire.
- The client places its player only at points the server sends; it has no gameplay spawn coordinates of its own.
- A per-player spawn choice, when it comes, extends
select()with player context instead of adding a second source.
Alternatives considered
- Keep the spawn point in the world defaults. Rejected: it mixes a per-player placement with the global environment, and every spawn path would still read a bare constant.
- Per-player spawn storage in the policy right away. Rejected: no gamemode needed it, and the per-death respawn point has a different lifetime from a persistent per-player spawn class (ADR 0020).
