Repository navigation
Architecture
com.proto781m.betterspawn
api/ SpawnMethod, SpawnContext, ResolveResult, SearchTrace, registry
command/ worldspawn, spawnpoint, gotodim
data/ WorldSpawnData, PlayerSpawnData, SpawnPoint, slots
event/ command registration, respawn interception, spawn-slot mirroring
logic/ SpawnPointResolver, DimensionSpawnInitializer, VerifyTaskManager,
CreateWorldSpawnSelection
method/ the eight spawn methods
resolver/ SpawnMethodResolver, SpawnSafetyValidator, TerrainScanner
template/ JSON loader/manager and built-in defaults
util/ SafePosFinder, PlatformBuilder, SpawnAdapter, TeleportHelper
client/ create-world screen button
mixin/ client-only CreateWorldScreen MoreTab injection
Stored as betterspawn_world_spawn in the Overworld's DataStorage.
- one
SpawnPointper dimension -
versionfor migration -
spawn_dimensionfor the experimental first-join dimension - Overworld spawn is mirrored to
level.datthroughServerLevel#setDefaultSpawnPos
Legacy data version 0 is migrated. If the Overworld level.dat spawn differs from the
old stored value (for example after vanilla /setworldspawn), that value is preserved and
other dimensions are re-resolved.
Stored under NeoForgeData/PlayerPersisted/BetterSpawn, not directly under
NeoForgeData. This matters because ServerPlayer#restoreFrom only copies
PlayerPersisted to the new player on death.
Contents:
-
dimensionSpawns: player world spawn per dimension -
COMMAND,BED,ANCHOR: spawn slots -
initialDimensionApplied: first-join marker
Bed and anchor slots record the anchor block position and are validated on respawn. Command slots record an exact feet position.
SpawnPointResolver.resolveRespawn:
- command slot / bed-anchor slot, in the order from
respawnPolicy - player world spawn for the death dimension
- world spawn for the death dimension
- optional Overworld world spawn when no personal/dimension spawn exists
Invalid slots and unsafe positions fall through to the next layer. The result is applied
in PlayerRespawnPositionEvent.
-
LevelEvent.CreateSpawnPosition: new world, before vanilla chooses a spawn. The mod resolves the Overworld rule, setslevel.dat, and cancels vanilla selection when it has a position. -
ServerStartedEvent: levels exist and spawn chunks are prepared, but players have not joined. Missing dimension spawns are resolved and legacy data is migrated. -
PlayerRespawnPositionEvent: applies the respawn chain and constructs theDimensionTransition. -
PlayerSetSpawnEvent: mirrors vanilla/spawnpoint, bed and anchor interactions into the mod's slots. -
PlayerLoggedInEvent: applies the experimental initial spawn dimension once.
Do not run spawn searches during LevelEvent.Load or ServerAboutToStartEvent: chunks
are not ready and getHeight returns the minimum build height.
TerrainScanner owns:
- chunk force-loading with a budget
- heightmap reads
- surface scans (limited depth for the
default/floating_islandmethods) - downward scans for
top - safety checks through
SafePosFinder
Level#getHeight returns the feet Y. For unloaded chunks it returns minBuildHeight, so
chunk loading must happen first.
SpawnMethodResolver:
- looks up the method by id
- times it and catches method exceptions
- tries
fallbackon failure - bounds recursion and prevents cycles
- converts a successful fallback to status
FALLBACK
ResolveResult contains the position, dimension, angle, used method, fallback flag,
elapsed time, sample count, max radius, status and warnings.
- Bed/anchor recording uses
PlayerSetSpawnEvent, not global Mixin, so it works with vanilla and other mods that callsetRespawnPosition. - The only common Mixin is the client-only create-world screen injection; it adds the spawn-dimension button to the More tab.
- The template registry is held in a volatile immutable map, so datapack reloads are safe to read while resolving.