Skip to content

Architecture

BetterSpawn Wiki edited this page Oct 21, 2026 · 1 revision

Architecture

Package layout

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

Data layers

World spawn (WorldSpawnData)

Stored as betterspawn_world_spawn in the Overworld's DataStorage.

  • one SpawnPoint per dimension
  • version for migration
  • spawn_dimension for the experimental first-join dimension
  • Overworld spawn is mirrored to level.dat through ServerLevel#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.

Player state (PlayerSpawnData)

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.

Respawn chain

SpawnPointResolver.resolveRespawn:

  1. command slot / bed-anchor slot, in the order from respawnPolicy
  2. player world spawn for the death dimension
  3. world spawn for the death dimension
  4. 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.

Event timing

  • LevelEvent.CreateSpawnPosition: new world, before vanilla chooses a spawn. The mod resolves the Overworld rule, sets level.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 the DimensionTransition.
  • 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.

Terrain search

TerrainScanner owns:

  • chunk force-loading with a budget
  • heightmap reads
  • surface scans (limited depth for the default/floating_island methods)
  • 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.

Method dispatch

SpawnMethodResolver:

  • looks up the method by id
  • times it and catches method exceptions
  • tries fallback on 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.

Compatibility choices

  • Bed/anchor recording uses PlayerSetSpawnEvent, not global Mixin, so it works with vanilla and other mods that call setRespawnPosition.
  • 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.

Clone this wiki locally