Feature Starter Train - bh679/dungeon-train-mc GitHub Wiki

Starter train on login + configurable spawn Y

Since: v0.15.0 โ€” PR #19 v0.27.0 โ€” PR #37: train assembled at world-gen time; player spawn avoids water and the void. v0.83.0 โ€” PR #120: login spawn rewritten โ€” cached placement + PlayerFudgeSpawnMixin deliver the player at the final position from frame 1 (no visible jump). Now its own feature page; see Login spawn placement for the full pipeline.

The mod starts itself โ€” no /dungeontrain spawn needed. When the server starts, if no Dungeon Train is present, a 10-carriage train is auto-assembled at (0, trainY, 0) before any player joins, so the world's first frame already contains the train. Every joining player (including the first) is then placed off-corridor, on natural ground, looking at the nearest above-ground stretch of track โ€” see the dedicated Login spawn placement page for that pipeline.

Train assembly โ€” at server start

TrainBootstrapEvents subscribes to ServerStartedEvent with EventPriority.LOW so the client-side WorldLifecycleEvents handler commits any pending Create-World-screen choices (trainY, dims, startsWithTrain) into DungeonTrainWorldData first. The bootstrap then:

  1. Reads per-world DungeonTrainWorldData from the overworld.
  2. Skips if startsWithTrain=false or any carriage of a Dungeon Train already exists.
  3. Otherwise calls TrainAssembler.spawnTrain(level, (0, trainY, 0), TRAIN_VELOCITY, 10, origin, dims). Internally this delegates to spawnGroup to place a seed group of carriages with half-flatbed pads on each end (see Feature-Train ยง Per-carriage architecture for the full mechanism). The append-only TrainCarriageAppender extends from there once a player gets within range.
  4. Calls PlayerJoinEvents.computeAndCacheBootstrapPlacement(...) to compute and cache the player's eventual login spawn position, then writes it to the level's default spawn point. This is what lets first-time players land at the cached placement directly via the PlayerFudgeSpawnMixin (no visible vanilla-spawn flash).

Common-scope (no @Dist guard), so dedicated servers also auto-spawn โ€” previously the train only appeared on first player login.

Player placement โ€” on login

The full pipeline (cached placement, mixin, buffered-X scan, perpendicular walk, on-train-roof last resort, leaves rejection, no-water guarantee) lives on its own page: Login spawn placement.

For this page, the short version: every joining player is placed off-corridor on natural ground within ~50 blocks of the train, facing the nearest above-ground stretch of track. The placement is computed at ServerStartedEvent time (right after the bootstrap above) and cached, so the very first frame the player sees on a fresh world is already correct โ€” no (0, 64, 0) flash, no visible teleport, no rotation snap.

trainY config

The spawn altitude is a server-scoped Forge config value (same config file as numCarriages / speed):

Field Range Default
Train Y [-64, 320] 78

Default 78 is ~15 blocks above vanilla sea level (63) โ€” high enough to clear most coastline terrain but low enough that the train visibly plows through hills and shorelines. Editable via Esc โ†’ Mods โ†’ Dungeon Train โ†’ Config (new "Train Y:" row) or directly in <save>/serverconfig/dungeontrain-server.toml:

[train]
    trainY = 78

Applies to next spawn only. Changing the config doesn't move an existing train โ€” its Y is baked into the ship when it was assembled. To apply a new Y: delete the current train (e.g. /dungeontrain spawn 10 re-assembles) or rejoin a world where no train is loaded.

Dev/admin override

The existing /dungeontrain spawn [count] command keeps working โ€” it still spawns 10 blocks in front of the player's look direction, independent of trainY. Treat auto-spawn as the default path and /dungeontrain spawn as the admin/testing override.

Files

Known limitations

  • Starting dimension is configurable per world. The bootstrap runs in whichever dimension the world's startingDimension says (default Overworld). See Feature-World-Type for the Nether / End starting-dimension flow.
  • Login event only. Respawning after death fires PlayerRespawnEvent, which is not hooked โ€” the player respawns at their bed or world spawn. The level's default spawn point is the cached placement, so dying without a bed lands the player back on natural ground next to the train.
  • No cross-dimension teleport on login. If the player's last-logged-in dimension differs from startingDimension, they stay where they were. Teleporting them across dimensions on every login would feel invasive.
  • Placement is fixed at server start, not per-login. The cached placement is computed once at ServerStartedEvent from the train's then-current position. By login time the train has moved a few blocks; the appender extends the train back over the cached placement, so the player still spawns next to a carriage. Long server uptimes between bootstrap and first login are fine โ€” the train is append-only.
  • On-train-roof last resort in tiny-island biomes. If neither the buffered-X scan nor the perpendicular walk (capped at 60 blocks) finds dry ground, the player is placed on top of the carriage roof rather than underwater on a seabed. See Login spawn placement ยง Fallback chain for the full ladder.
โš ๏ธ **GitHub.com Fallback** โš ๏ธ