Niveles y mapas de EternalTD
Un "nivel" en EternalTD es una configuración YAML en plugins/EternalTD/levels/ emparejada con una carpeta de mundo plantilla en plugins/EternalTD/worlds/. Cuando un jugador se une, EternalTD clona el mundo plantilla en el contenedor de mundos del servidor y ejecuta la sesión en esa copia clonada.
Campos de configuración del nivel
| Campo | Tipo | Por defecto | Notas |
|---|---|---|---|
isEnabled | bool | true | Los niveles deshabilitados se omiten durante la carga |
levelName | string | null | Nombre para mostrar en mensajes, marcadores y menús de NPC |
levelDescription | lista de strings | [] | Líneas mostradas en los menús de NPC. Soporta los placeholders $highscoreWave y $highscorePlayer |
worldName | string | null | Nombre de la carpeta de plantilla bajo plugins/EternalTD/worlds/ |
startLocation | lista de strings | null | Lista de ubicaciones serializadas donde aparecen los mobs |
endLocation | lista de strings | null | Lista de ubicaciones serializadas a las que caminan los mobs (las casillas "rojas") |
levelLocations | lista de strings | null | Cada casilla transitable de la cuadrícula del nivel; en la compilación actual deben venir del paquete o escribirse a mano en el YAML |
wavesConfigFile | string | requerido | Nombre del archivo de configuración de oleadas vinculado (waves/<name>.yml) |
highscoreWave | int | 0 | Mejor oleada alcanzada en este nivel |
highscorePlayerName | string | "no one" | Nombre para mostrar del jugador que estableció la puntuación |
environment | enum | NORMAL | Entorno del mundo usado cuando se carga el mundo clonado |
El tamaño de cuadrícula utilizado en todo momento es de 3 bloques por casilla lógica (constante GRID_SIZE en el código).
waveCount ya no existe. Los archivos de nivel antiguos que todavía llevan la clave simplemente se ignoran — el plugin nunca la lee ni la vuelve a escribir.
Formato de cadena de ubicación
Las ubicaciones en EternalTD se serializan como cadenas separadas por comas con el formato:
worldName,x,y,z,yaw,pitch
Los paquetes descargados normalmente proporcionan estos valores. Para un mapa personalizado, los comandos actuales de selección y registro no guardan levelLocations, así que tienes que escribir a mano en el YAML del nivel las ubicaciones de cuadrícula generadas.
Ciclo de vida del mundo
Cuando un jugador se une a un nivel:
- EternalTD comprueba que este jugador no tenga ya una copia en curso. Un segundo
/etd joinmientras la primera sigue copiándose se rechaza con «Your level is already being prepared.» - Busca la carpeta de plantilla por
worldNameenplugins/EternalTD/worlds/, y rechaza la unión si falta la carpeta del mundo, si el archivo de oleadas vinculado no se pudo cargar o si el nombre del mundo no es un nombre de carpeta seguro. - Reserva el siguiente sufijo numérico libre (
<worldName>_0,<worldName>_1, ...). La reserva está sincronizada y recuerda los nombres reservados que todavía no están en disco, así que dos jugadores que se unan a la vez no pueden colisionar en el mismo nombre de instancia. - La plantilla se copia al contenedor de mundos del servidor fuera del hilo principal, para que el servidor no se atasque con un mapa grande.
- El mundo clonado se carga como un mundo void temporal a través del
TemporaryWorldManagerde MagmaCore, por lo que la migración de Paper 26.1+ queda en cuarentena y los chunks que falten vuelven como void en lugar de como terreno recién generado. - El jugador es teletransportado al nuevo mundo; un
InstanceProtectorinterno aplica las reglas de protección de EternalTD.
Requisitos de la plantilla
La copia se valida antes de escribir nada, y una plantilla se rechaza si:
- no es un directorio, o es un enlace simbólico
- no tiene
level.daten su raíz - contiene un enlace simbólico en cualquier punto de su interior
- contiene un archivo llamado
.eternaltd-instance(ese nombre está reservado, ver más abajo)
Una copia fallida se revierte y se informa al jugador de que el nivel no se inició.
Marcadores de propiedad de instancia
Cada clon recibe un archivo .eternaltd-instance escrito en su raíz que registra el nombre de la plantilla y el nombre de la instancia. EternalTD solo borrará una carpeta de mundo cuyo marcador coincida con la instancia que cree estar borrando. Esta es la salvaguarda que impide que una colisión de nombres obsoleta, una carpeta hecha a mano o una sesión desincronizada acaben con un mundo que EternalTD no creó: si el marcador falta o no coincide, la carpeta se deja intacta y se registra una advertencia en su lugar.
Las instancias obsoletas que queden tras un fallo se limpian al cargar los niveles, e incluso entonces solo para carpetas que lleven un marcador válido y no estén cargadas en ese momento.
Validación de inicio de sesión
Una sesión solo pasa a ser jugable si se cumple todo lo siguiente. Cualquier fallo aborta la partida, restaura al jugador (inventario, modo de juego, vuelo, marcador) y elimina el mundo temporal:
levelLocations,startLocationyendLocationestán todos presentes y no vacíos; de lo contrario, «This level doesn't have a complete play area, start, and end configuration!»- la propia zona de juego se interpreta como una cuadrícula válida; de lo contrario, «This level's play area is invalid!»
- cada casilla de inicio tiene tanto un camino terrestre como un camino aéreo hasta alguna casilla final; de lo contrario, «This level does not have complete land and air paths from every start to an end!»
Cuando la sesión termina:
- Cualquier jugador restante en el mundo clonado es teletransportado de vuelta a la ubicación de spawn de
config.yml, o expulsado si no hay spawn configurado. - Se retiran las reglas de protección del mundo y se desmontan todas las torres restantes (una torre que dé error al retirarse se registra y se omite, en lugar de dejar tiradas al resto).
- Se liberan los tickets de chunk tomados sobre el área de juego (ver Validación de camino).
- El mundo clonado se descarga y se elimina del disco (
TemporaryWorldManager.permanentlyDeleteWorld), tanto en la disposición antigua como en la migrada de Paper 26.1+. - Terminar es idempotente: un segundo
end()(por ejemplo/etd quitseguido inmediatamente de/etd hub) no hace nada.
Reglas de protección de instancia
Mientras un nivel está activo, el mundo clonado tiene estas reglas aplicadas:
- Explosiones deshabilitadas
- Flujo de líquidos deshabilitado
- Elytra deshabilitado
- Alternar vuelo prevenido
- Fuego amigo prevenido
- Aparición de mobs vanilla prevenida
Flujo de creación de mapas
El flujo actual de creación de mapas usa las herramientas dentro del juego:
- Coloca una carpeta de mundo plantilla bajo
plugins/EternalTD/worlds/<worldName>/. - Crea o descarga un YAML de nivel correspondiente en
plugins/EternalTD/levels/. - Ejecuta
/etd reloady únete al mundo del nivel manualmente (o ábrelo en un jugador para configurarlo). - Usa
/etd selectfloory haz clic derecho/izquierdo en dos esquinas para marcar el área de juego, o usa/etd selectfloorcoordinates <x1> <y1> <z1> <x2> <y2> <z2>para proporcionarlas directamente. - Ejecuta
/etd showselection <level>para confirmar que la selección se ve correcta. - Ejecuta
/etd register <level>para limpiar la selección. Ten en cuenta que en la compilación actual niregisternishowselectionpersisten realmente la región de piso — el ayudante que guardaríalevelLocations(LevelsConfigFields#addLevelLocations) está definido pero nunca es invocado por un comando. Actualmente tienes que escribirlevelLocationsen el YAML del nivel a mano si aún no está poblado por un paquete descargado. - Sitúate sobre una casilla de spawn de inicio y ejecuta
/etd register <level> start. Repítelo para cada casilla de inicio (este comando sí persiste enstartLocation). - Sitúate sobre una casilla de fin y ejecuta
/etd register <level> end. Repítelo para cada casilla de fin (este comando sí persiste enendLocation). - Recarga de nuevo y prueba el nivel uniéndote a él a través del menú de NPC o
/etd join <level>.
Los comandos de selección generan casillas de cuadrícula usando:
size = abs(corner1 - corner2 + 1) / 3
Una casilla se omite cuando su bloque de suelo es atravesable, o cuando el bloque directamente encima del suelo no es atravesable. Dicho de otro modo, el suelo debe ser sólido y el espacio encima debe estar despejado para que la casilla se registre como jugable — selecciona el suelo, no el aire que hay sobre él.
Validación de camino
EternalTD guarda en caché, para cada casilla de inicio, el camino A* más barato hasta cualquier casilla de fin — un camino terrestre y un camino aéreo. Con varias casillas de fin compara los caminos terminados por coste y se queda con el más corto, así que un mapa con varias salidas encamina a los enemigos a la más cercana alcanzable en lugar de a la primera que encuentre.
La caché terrestre se reconstruye cuando arranca la sesión, cada vez que se coloca una torre y cada vez que se vende una torre. La caché aérea solo se calcula una vez, en la primera reconstrucción: los caminos aéreos ignoran las torres por completo, así que nada de lo que construya un jugador puede invalidarlos.
Los enemigos aéreos usan ese camino aéreo separado, que ignora por completo el bloqueo de torres y en su lugar sigue el desplazamiento aéreo (4 bloques por encima del camino configurado).
Cargar el área de juego también fuerza la carga de cada chunk que contiene una casilla de cuadrícula, así que una partida larga no puede atascarse en un chunk descargado. Esos tickets de chunk se liberan cuando termina la sesión, justo antes de que se elimine el mundo de la instancia.
La caché es además la condición que determina si un nivel es jugable siquiera: si a cualquier casilla de inicio le falta su camino terrestre o su camino aéreo, la sesión se rechaza al unirse en lugar de iniciar una partida que los enemigos no pueden terminar. La misma comprobación se ejecuta al colocar una torre, así que una torre que amurallaría una casilla de inicio es rechazada y el oro no se gasta.
Una ubicación de inicio o de fin que no esté en el centro de su casilla de cuadrícula 3x3 se descarta con una advertencia en consola, que es la causa habitual de que un nivel informe de un conjunto de caminos incompleto.
Cada casilla de inicio y de fin resuelta se marca además como no construible, para que los jugadores no puedan amurallar un spawn o una salida construyendo encima. Esas casillas aparecen en azul claro bajo el resaltado de colocación.
NPCs y menús de nivel
Las configuraciones de NPC en plugins/EternalTD/npcs/ vinculan NPCs aldeanos a uno o más niveles. Hacer clic derecho en el NPC abre un inventario de 9 slots que lista cada nivel como un panel de cristal teñido verde etiquetado con el nombre y la descripción del nivel.
| Campo | Tipo | Por defecto | Notas |
|---|---|---|---|
isEnabled | bool | true | Los NPCs deshabilitados se omiten |
levelIDs | lista de strings | requerido | Nombres de archivo de los niveles que ofrece este NPC |
location | string | null | Ubicación de spawn en el formato estándar worldName,x,y,z,yaw,pitch |
name | string | "Default Name" | Nombre para mostrar del NPC |
difficulty | string | "Difficulty: Not Set" | Etiqueta de dificultad mostrada sobre el NPC |
disguise | string | null | Descriptor de LibsDisguises (p. ej. custom:etd_tutorial_npc) |
customDisguiseData | string | null | Datos adicionales del comando de LibsDisguises — normalmente la cadena larga de skin de jugador |
El aldeano se genera invulnerable, con IA deshabilitada, persistente y etiquetado con la NamespacedKey de NPC de EternalTD. Si LibsDisguises está instalado y tanto disguise como customDisguiseData están establecidos, el aldeano se disfraza al aparecer.
Un armor stand flotante con la etiqueta difficulty se genera 2.3 bloques por encima del NPC.
Comportamiento del spawn
DefaultConfig controla cómo se gestiona a los jugadores en el mundo del hub:
setupDone— flag que rastrea si la guía de configuración inicial se ha completado (por defectofalse).spawnLocations— por defectoetd_spawn,0,65,0,0,0y siempre se escribe en la configuración. Solo se resuelve y se usa cuando existe el mundoetd_spawn.manageSpawn— por defectotrue. Cuando está activado, los jugadores que se unen son teletransportados a la ubicación de spawn 1 tick después de iniciar sesión.playerGuide— el texto del libro guía dentro del juego.nightbreak.autoDownloadPluginUpdates— ajuste compartido de MagmaCore (por defectofalse). Cuando está activado, las actualizaciones del plugin y del contenido se descargan automáticamente al iniciar.
Cuando manageSpawn es true y el mundo de spawn está cargado, cada jugador que se une al servidor es teletransportado a spawnLocations. Los jugadores que ya estaban conectados mientras EternalTD todavía se inicializaba son llevados al mismo spawn una vez terminada la inicialización, salvo que ya estén en el mundo hub.