Skip to main content

EternalTD Levels & Maps

A "level" in EternalTD is a YAML config in plugins/EternalTD/levels/ paired with a template world folder in plugins/EternalTD/worlds/. When a player joins, EternalTD clones the template world into the server world container and runs the session in that cloned copy.

Level Config Fields

FieldTypeDefaultNotes
isEnabledbooltrueDisabled levels are skipped during load
levelNamestringnullDisplay name shown in messages, scoreboards, and NPC menus
levelDescriptionstring list[]Lines shown in NPC menus. Supports $highscoreWave and $highscorePlayer placeholders
worldNamestringnullThe template folder name under plugins/EternalTD/worlds/
startLocationstring listnullList of serialized locations where mobs spawn
endLocationstring listnullList of serialized locations the mobs walk to (the "red" tiles)
levelLocationsstring listnullEvery walkable grid square in the level, generated automatically when you register a floor selection
wavesConfigFilestringrequiredFilename of the linked wave config (waves/<name>.yml)
waveCountint-1Cached wave count, currently informational
highscoreWaveint0Best wave reached on this level
highscorePlayerNamestring"no one"Display name of the player who set the score
environmentenumNORMALWorld environment used when the cloned world is loaded

The grid size used throughout is 3 blocks per logical square (constant GRID_SIZE in code).

Location String Format

Locations in EternalTD are serialized as comma-separated strings of the form:

worldName,x,y,z,yaw,pitch

You normally do not write these by hand — /etd selectfloor plus the register commands compute and save them for you.

World Lifecycle

When a player joins a level:

  1. EternalTD looks up the template folder by worldName in plugins/EternalTD/worlds/.
  2. It picks the next free numeric suffix (<worldName>_0, <worldName>_1, ...) and writes the clone into the server world container, cleaning up any stale legacy or modern layout copies first.
  3. The cloned world is loaded as a temporary void world through MagmaCore's TemporaryWorldManager, so Paper 26.1+ migration is quarantined.
  4. The player is teleported into the new world; an internal InstanceProtector applies EternalTD's protection rules.

When the session ends:

  • Any remaining players in the cloned world are teleported back to the spawn location from config.yml, or kicked if no spawn is configured.
  • The cloned world is unloaded and deleted from disk (TemporaryWorldManager.permanentlyDeleteWorld).

Instance Protection Rules

While a level is active, the cloned world has these rules applied:

  • Explosions disabled
  • Liquid flow disabled
  • Elytra disabled
  • Fly toggling prevented
  • Friendly fire prevented
  • Vanilla mob spawning prevented

Map Authoring Workflow

The current map authoring flow uses the in-game tooling:

  1. Place a template world folder under plugins/EternalTD/worlds/<worldName>/.
  2. Create or download a matching level YAML in plugins/EternalTD/levels/.
  3. Run /etd reload and join the level world manually (or open it in single-player to set up).
  4. Use /etd selectfloor and right-/left-click two corners to mark the play area, or use /etd selectfloorcoordinates <x1> <y1> <z1> <x2> <y2> <z2> to supply them directly.
  5. Run /etd showselection <level> to confirm the selection looks right.
  6. Run /etd register <level> to clear the selection. Note that in the current build neither register nor showselection actually persist the floor region — the helper that would save levelLocations (LevelsConfigFields#addLevelLocations) is defined but never invoked by a command. You currently have to write levelLocations into the level YAML by hand if it isn't already populated by a downloaded package.
  7. Stand on a start spawn tile and run /etd register <level> start. Repeat for every start tile (this command does persist into startLocation).
  8. Stand on an end tile and run /etd register <level> end. Repeat for every end tile (this command does persist into endLocation).
  9. Reload again and test the level by joining it through the NPC menu or /etd join <level>.

The selection commands generate grid squares using:

size = abs(corner1 - corner2 + 1) / 3

Squares whose top block is air (or whose floor block is passable) are skipped, so floor blocks must be solid for a square to register as playable.

Path Validation

EternalTD runs an A* pathfinding check whenever a tower is placed. If placing the tower would leave any start tile with no walkable path to any end tile, the placement is rejected and the gold is not spent.

Air enemies use a separate path that ignores towers entirely and instead follows the airborne offset (4 blocks above the configured path).

NPCs and Level Menus

NPC configs in plugins/EternalTD/npcs/ link villager NPCs to one or more levels. Right-clicking the NPC opens a 9-slot inventory listing each level as a green stained-glass pane labelled with the level name and description.

FieldTypeDefaultNotes
isEnabledbooltrueDisabled NPCs are skipped
levelIDsstring listrequiredFilenames of the levels this NPC offers
locationstringnullSpawn location in the standard worldName,x,y,z,yaw,pitch format
namestring"Default Name"NPC display name
difficultystring"Difficulty: Not Set"Difficulty label shown above the NPC
disguisestringnullLibsDisguises descriptor (e.g. custom:etd_tutorial_npc)
customDisguiseDatastringnullExtra LibsDisguises command data — usually the long player-skin string

The villager is spawned invulnerable, AI-disabled, persistent, and tagged with EternalTD's NPC namespaced key. If LibsDisguises is installed and both disguise and customDisguiseData are set, the villager is disguised on spawn.

A floating armor stand with the difficulty label is spawned 2.3 blocks above the NPC.

Spawn Behavior

DefaultConfig controls how players are managed in the hub world:

  • setupDone — flag tracking whether first-time setup guidance has been completed.
  • spawnLocations — defaults to etd_spawn,0,65,0,0,0. Only used when the etd_spawn world exists.
  • manageSpawn — defaults to true. When enabled, joining players are teleported to the spawn location 1 tick after login.
  • playerGuide — the in-game guide book text.

When manageSpawn is true and the spawn world is loaded, every player that joins the server is teleported to spawnLocations.