EternalTD-Level & Karten
Ein "Level" in EternalTD ist eine YAML-Konfiguration in plugins/EternalTD/levels/, gepaart mit einem Vorlagen-Weltordner in plugins/EternalTD/worlds/. Wenn ein Spieler beitritt, klont EternalTD die Vorlagenwelt in den Server-Weltcontainer und führt die Sitzung in dieser geklonten Kopie aus.
Felder der Level-Konfiguration
| Feld | Typ | Standard | Hinweise |
|---|---|---|---|
isEnabled | bool | true | Deaktivierte Level werden beim Laden übersprungen |
levelName | string | null | Anzeigename, der in Nachrichten, Scoreboards und NPC-Menüs angezeigt wird |
levelDescription | string list | [] | Zeilen, die in NPC-Menüs angezeigt werden. Unterstützt die Platzhalter $highscoreWave und $highscorePlayer |
worldName | string | null | Der Name des Vorlagenordners unter plugins/EternalTD/worlds/ |
startLocation | string list | null | Liste serialisierter Positionen, an denen Mobs spawnen |
endLocation | string list | null | Liste serialisierter Positionen, zu denen die Mobs laufen (die "roten" Felder) |
levelLocations | string list | null | Jedes begehbare Rasterfeld im Level, automatisch generiert, wenn du eine Bodenauswahl registrierst |
wavesConfigFile | string | erforderlich | Dateiname der verknüpften Wellenkonfiguration (waves/<name>.yml) |
waveCount | int | -1 | Zwischengespeicherte Wellenanzahl, derzeit nur informativ |
highscoreWave | int | 0 | Beste erreichte Welle in diesem Level |
highscorePlayerName | string | "no one" | Anzeigename des Spielers, der den Punktestand aufgestellt hat |
environment | enum | NORMAL | Weltumgebung, die beim Laden der geklonten Welt verwendet wird |
Die durchgängig verwendete Rastergröße beträgt 3 Blöcke pro logischem Feld (Konstante GRID_SIZE im Code).
Format der Positions-Strings
Positionen in EternalTD werden als kommagetrennte Strings in folgender Form serialisiert:
worldName,x,y,z,yaw,pitch
Normalerweise schreibst du diese nicht von Hand — /etd selectfloor zusammen mit den Register-Befehlen berechnet und speichert sie für dich.
Welt-Lebenszyklus
Wenn ein Spieler einem Level beitritt:
- EternalTD sucht den Vorlagenordner anhand von
worldNameinplugins/EternalTD/worlds/. - Es wählt das nächste freie numerische Suffix (
<worldName>_0,<worldName>_1, ...) und schreibt den Klon in den Server-Weltcontainer, wobei zuvor veraltete Kopien im Legacy- oder modernen Layout bereinigt werden. - Die geklonte Welt wird über MagmaCores
TemporaryWorldManagerals temporäre Void-Welt geladen, sodass die Migration unter Paper 26.1+ in Quarantäne gehalten wird. - Der Spieler wird in die neue Welt teleportiert; ein interner
InstanceProtectorwendet die Schutzregeln von EternalTD an.
Wenn die Sitzung endet:
- Alle verbleibenden Spieler in der geklonten Welt werden zur Spawn-Position aus
config.ymlzurückteleportiert oder gekickt, wenn kein Spawn konfiguriert ist. - Die geklonte Welt wird entladen und von der Festplatte gelöscht (
TemporaryWorldManager.permanentlyDeleteWorld).
Instanz-Schutzregeln
Während ein Level aktiv ist, gelten für die geklonte Welt diese Regeln:
- Explosionen deaktiviert
- Flüssigkeitsfluss deaktiviert
- Elytra deaktiviert
- Umschalten des Flugmodus verhindert
- Friendly Fire verhindert
- Vanilla-Mob-Spawning verhindert
Workflow zur Kartenerstellung
Der aktuelle Ablauf zur Kartenerstellung nutzt die spielinternen Werkzeuge:
- Lege einen Vorlagen-Weltordner unter
plugins/EternalTD/worlds/<worldName>/ab. - Erstelle oder lade eine passende Level-YAML in
plugins/EternalTD/levels/. - Führe
/etd reloadaus und tritt der Level-Welt manuell bei (oder öffne sie im Einzelspielermodus zur Einrichtung). - Verwende
/etd selectfloorund klicke mit Rechts-/Linksklick zwei Ecken an, um den Spielbereich zu markieren, oder verwende/etd selectfloorcoordinates <x1> <y1> <z1> <x2> <y2> <z2>, um sie direkt anzugeben. - Führe
/etd showselection <level>aus, um zu bestätigen, dass die Auswahl korrekt aussieht. - Führe
/etd register <level>aus, um die Auswahl zu löschen. Beachte, dass im aktuellen Build wederregisternochshowselectionden Bodenbereich tatsächlich speichern — der Helfer, derlevelLocationsspeichern würde (LevelsConfigFields#addLevelLocations), ist zwar definiert, wird aber von keinem Befehl aufgerufen. Du musstlevelLocationsderzeit von Hand in die Level-YAML schreiben, falls es nicht bereits durch ein heruntergeladenes Paket befüllt ist. - Stelle dich auf ein Start-Spawnfeld und führe
/etd register <level> startaus. Wiederhole dies für jedes Startfeld (dieser Befehl speichert tatsächlich instartLocation). - Stelle dich auf ein Endfeld und führe
/etd register <level> endaus. Wiederhole dies für jedes Endfeld (dieser Befehl speichert tatsächlich inendLocation). - Lade erneut neu und teste das Level, indem du ihm über das NPC-Menü oder
/etd join <level>beitrittst.
Die Auswahlbefehle generieren Rasterfelder mithilfe folgender Formel:
size = abs(corner1 - corner2 + 1) / 3
Felder, deren oberster Block Luft ist (oder deren Bodenblock durchlässig ist), werden übersprungen, sodass Bodenblöcke solide sein müssen, damit ein Feld als bespielbar registriert wird.
Pfadvalidierung
EternalTD führt bei jeder Platzierung eines Turms eine A*-Wegfindungsprüfung durch. Wenn das Platzieren des Turms dazu führen würde, dass ein Startfeld keinen begehbaren Pfad zu einem Endfeld mehr hat, wird die Platzierung abgelehnt und das Gold nicht ausgegeben.
Luft-Gegner verwenden einen separaten Pfad, der Türme vollständig ignoriert und stattdessen dem Luftoffset folgt (4 Blöcke über dem konfigurierten Pfad).
NPCs und Level-Menüs
NPC-Konfigurationen in plugins/EternalTD/npcs/ verknüpfen Dorfbewohner-NPCs mit einem oder mehreren Levels. Ein Rechtsklick auf den NPC öffnet ein Inventar mit 9 Slots, in dem jedes Level als grün gefärbte Glasscheibe mit dem Level-Namen und der Beschreibung aufgeführt ist.
| Feld | Typ | Standard | Hinweise |
|---|---|---|---|
isEnabled | bool | true | Deaktivierte NPCs werden übersprungen |
levelIDs | string list | erforderlich | Dateinamen der Levels, die dieser NPC anbietet |
location | string | null | Spawn-Position im Standardformat worldName,x,y,z,yaw,pitch |
name | string | "Default Name" | NPC-Anzeigename |
difficulty | string | "Difficulty: Not Set" | Schwierigkeitslabel, das über dem NPC angezeigt wird |
disguise | string | null | LibsDisguises-Deskriptor (z. B. custom:etd_tutorial_npc) |
customDisguiseData | string | null | Zusätzliche LibsDisguises-Befehlsdaten — meist der lange Spieler-Skin-String |
Der Dorfbewohner wird unverwundbar, mit deaktivierter KI, persistent und mit dem namensraumbasierten NPC-Schlüssel von EternalTD getaggt gespawnt. Wenn LibsDisguises installiert ist und sowohl disguise als auch customDisguiseData gesetzt sind, wird der Dorfbewohner beim Spawnen verkleidet.
Ein schwebender Rüstungsständer mit dem difficulty-Label wird 2,3 Blöcke über dem NPC gespawnt.
Spawn-Verhalten
DefaultConfig steuert, wie Spieler in der Hub-Welt verwaltet werden:
setupDone— Flag, das verfolgt, ob die Ersteinrichtungs-Anleitung abgeschlossen wurde (Standardfalse).spawnLocations— Standard istetd_spawn,0,65,0,0,0. Wird nur verwendet, wenn die Weltetd_spawnexistiert.manageSpawn— Standard isttrue. Wenn aktiviert, werden beitretende Spieler 1 Tick nach dem Login zur Spawn-Position teleportiert.playerGuide— der Text des spielinternen Anleitungsbuchs.nightbreak.autoDownloadPluginUpdates— gemeinsame MagmaCore-Einstellung (Standardfalse). Wenn aktiviert, werden Plugin- und Inhalts-Updates beim Start automatisch heruntergeladen.
Wenn manageSpawn auf true gesetzt und die Spawn-Welt geladen ist, wird jeder Spieler, der dem Server beitritt, zu spawnLocations teleportiert.