Niveles y mapas de EternalTD
Un nivel de EternalTD es una configuración YAML en plugins/EternalTD/levels/ asociada a una plantilla de mundo en plugins/EternalTD/worlds/. Al entrar un jugador, EternalTD clona la plantilla en el contenedor de mundos del servidor y ejecuta la sesión en esa copia.
Campos de configuración del nivel
| Campo | Tipo | Predeterminado | Notas |
|---|---|---|---|
isEnabled | booleano | true | Los niveles deshabilitados se omiten al cargar |
levelName | cadena | null | Nombre visible en mensajes, marcadores y menús de NPC |
levelDescription | lista de cadenas | [] | Líneas de los menús de NPC; admiten $highscoreWave y $highscorePlayer |
worldName | cadena | null | Nombre de la carpeta de plantilla en plugins/EternalTD/worlds/ |
startLocation | lista de cadenas | null | Ubicaciones serializadas donde aparecen los mobs |
endLocation | lista de cadenas | null | Ubicaciones serializadas a las que caminan los mobs, las casillas rojas |
levelLocations | lista de cadenas | null | Todas las casillas transitables del nivel. Los paquetes la proporcionan; en un mapa personalizado, /etd register <level> la escribe a partir de una selección de suelo, o puedes escribirla a mano |
wavesConfigFile | cadena | obligatorio | Nombre del archivo de oleadas asociado, waves/<name>.yml |
highscoreWave | entero | 0 | Mejor oleada alcanzada en este nivel |
highscorePlayerName | cadena | "No one" | Nombre visible del jugador que logró el récord |
environment | enum | NORMAL | Entorno usado al cargar el mundo clonado |
Cada casilla lógica mide 3 bloques, según la constante GRID_SIZE.
waveCount no se usa. Su presencia en un archivo antiguo no fija el número de oleadas; EternalTD usa la configuración de oleadas asociada.
Formato de ubicaciones
Las ubicaciones se serializan como cadenas separadas por comas:
worldName,x,y,z,pitch,yaw
También se aceptan cadenas de cuatro partes worldName,x,y,z, con pitch y yaw a cero, y cadenas de cinco partes x,y,z,pitch,yaw sin mundo. Para la cuadrícula y los puntos de inicio y final de una sesión, EternalTD sustituye el mundo indicado por el de la instancia. Las ubicaciones del hub y los NPC necesitan que su mundo indicado esté cargado.
Los paquetes descargados suelen proporcionar estos valores. En un mapa personalizado, levelLocations contiene una coordenada entera del bloque central por cada casilla jugable de suelo de 3×3, separadas por tres bloques. El cargador suma 0.5 a X y Z para obtener el centro en el mundo. /etd register <level> escribe esta lista a partir de una selección de suelo (consulta Crear mapas); también puedes escribirla a mano.
Ciclo de vida del mundo
Cuando un jugador entra en un nivel:
- EternalTD busca
worldNameentre las subcarpetas directas deplugins/EternalTD/worlds/. Excluye los nombres que contengan cualquier.. Rechaza plantillas ausentes, configuraciones de oleadas no disponibles y nombres inseguros. También rechaza los niveles cuyolevelLocations,startLocationoendLocationfalte, esté vacío o contenga una entrada que no se pueda interpretar: "This level has missing or invalid floor, entrance, or exit coordinates. Nothing was started." - Rechaza una segunda solicitud de preparación mientras la primera del jugador siga pendiente, y rechaza a los jugadores que ya estén en una partida, aunque sea de otro plugin de Nightbreak ("You are already in a match!"). La solicitud pendiente reserva al jugador en el sistema compartido de partidas, así que las partidas de otros plugins lo rechazan hasta que termine. Desconectarse, o pasar 10 minutos sin que el mundo esté listo, la cancela y elimina la copia parcial.
- Reserva el siguiente sufijo numérico libre:
<worldName>_0,<worldName>_1, etc. La reserva está sincronizada y recuerda nombres reservados aún ausentes en disco, evitando colisiones entre jugadores que entren simultáneamente. - Copia la plantilla en el contenedor de mundos fuera del hilo principal. La carga del mundo y la inicialización de la sesión siguen ejecutándose en el hilo principal.
- Carga el clon como mundo vacío temporal mediante
TemporaryWorldManagerde MagmaCore, que aparta los restos de migración de Paper 26.1+ y hace que los chunks ausentes sean vacío en lugar de terreno nuevo. - EternalTD valida la cuadrícula (consulta Validación al iniciar la sesión) y
InstanceProtectoraplica sus reglas de protección. Después, el sistema de partidas admite al jugador: guarda su registro de recuperación, lo teletransporta al punto de aparición del nuevo mundo en el tick siguiente y le entrega los objetos de la partida. Si otro plugin rechaza ese teletransporte, el jugador sale de la partida y esta termina. Espera a "Created your world! We're ready to go." antes de empezar. El mensaje anterior "Joined level!" por sí solo no confirma que la sesión se haya creado correctamente.
Requisitos de las plantillas
EternalTD valida la raíz antes de crear el clon y comprueba cada elemento interno durante la copia. Si alguno no es válido, revierte el clon parcial. Rechaza una plantilla si:
- No es una carpeta o es un enlace simbólico.
- No tiene
level.daten la raíz. - Contiene un enlace simbólico en cualquier punto.
- Contiene
.eternaltd-instance, un nombre reservado que se explica a continuación.
Una copia fallida inicia la reversión y muestra un mensaje de error. Si la limpieza falla, revisa la consola; el mensaje no demuestra que se haya eliminado cada archivo.
Marcadores de propiedad de instancias
Cada clon recibe .eternaltd-instance con sus nombres de plantilla e instancia. EternalTD comprueba este marcador antes de borrar una instancia abandonada y antes de borrar un mundo copiado que no haya superado la validación. Una copia parcial se elimina en cuanto falla la copia, y el sistema de partidas borra el mundo de una sesión creada cuando esta termina (consulta más abajo).
Las instancias abandonadas tras un fallo se limpian al cargar los niveles, y únicamente si tienen un marcador válido y no están cargadas.
Validación al iniciar la sesión
Una sesión solo es jugable si cumple todas estas condiciones:
levelLocations,startLocationyendLocationestán presentes y no vacíos; de lo contrario, informa de una configuración incompleta del área, inicio y final.- El área de juego se interpreta como una cuadrícula válida; de lo contrario, informa de un área no válida.
- Cada casilla de inicio tiene una ruta terrestre y otra aérea hasta alguna casilla final; de lo contrario, informa de que faltan rutas completas.
Estas comprobaciones se ejecutan después de cargar el mundo copiado y antes de admitir al jugador, así que un fallo no modifica el estado del propio jugador. A continuación, EternalTD borra el mundo temporal e informa con "Failed to start the level. Your player and the temporary world were rolled back." Si la propia admisión falla después de guardar el registro de recuperación, ese registro se restaura de inmediato.
Al terminar la sesión:
- Se desmontan todas las torres restantes. Si una torre falla al eliminarse, se registra y se continúa con las demás.
- Se restaura el registro de recuperación del jugador y este vuelve al lugar donde estaba justo antes de entrar en el nivel, o al punto de aparición del mundo principal si ese mundo ya no está cargado.
- Se retiran las reglas de protección del mundo. Cualquier otra persona que siga en el clon, como miembros del staff con
eternaltd.match.bypass, se envía al punto de aparición del hub definido enconfig.yml, o al del mundo principal si no hay hub configurado. - Se liberan los tickets que mantienen cargados los chunks del área; consulta Validación de rutas.
- La limpieza solicita descargar el mundo de memoria y eliminarlo en ambas ubicaciones. Si se rechaza la descarga, no se borran archivos. Mientras el plugin está habilitado, el borrado se ejecuta de forma asíncrona 5 segundos después de la descarga. También se omite un mundo que vuelva a cargarse antes de la limpieza, y se registran los borrados incompletos.
- El cierre es idempotente: un segundo
end(), por ejemplo/etd quitseguido inmediatamente de/etd hub, no tiene efecto.
Protecciones de la instancia
Durante el nivel, el mundo clonado aplica estas reglas:
- Explosiones deshabilitadas.
- Flujo de líquidos deshabilitado.
- Uso de élitros deshabilitado.
- Cambio de estado de vuelo bloqueado.
- Fuego amigo bloqueado.
- Aparición de mobs normales de Minecraft bloqueada.
El sistema de partidas también protege el mundo: el jugador de la partida no puede teletransportarse hacia el mundo, fuera de él ni dentro de él salvo mediante los movimientos propios de EternalTD, y los demás jugadores sin eternaltd.match.bypass no pueden teletransportarse a él. Consulta Reglas de la partida.
Crear mapas
Usa la plantilla como original editable y escribe la cuadrícula en el YAML del nivel:
- Edita el mapa en otro mundo o en una partida individual, guárdalo y coloca la plantilla en
plugins/EternalTD/worlds/<worldName>/. Editar el clon de una partida no actualiza la plantilla. - Crea su YAML, enlaza una configuración de oleadas cargada y rellena
levelLocations,startLocationyendLocation. Usa centros de bloques del suelo para la cuadrícula y puntos de inicio y final que correspondan a esas casillas. - Si usas las herramientas del juego en el mundo de edición, ejecuta
/etd reloadpara cargar la configuración y después/etd selectfloor. El clic izquierdo fija la esquina 1 y el derecho fija la esquina 2. Ambas esquinas deben estar en el mismo mundo y a la misma Y del suelo, con longitudes X/Z que incluyan ambos extremos y sean múltiplos de 3. - Como alternativa,
/etd selectfloorcoordinates <x1> <y1> <z1> <x2> <y2> <z2>fija las esquinas en el mundo actual y resta 1 de cada Y indicada. Introduce la Y del suelo más uno. /etd showselection <level>muestra una partículaEND_ROD, visible solo para ti, sobre cada casilla de suelo que registraría la selección. No guarda nada.- Mantén la selección activa al ejecutar
/etd register <level> startoend. Añaden las coordenadas enteras de bloque del jugador y guardan inmediatamente, sin restar 1 de Y ni comprobar que el punto pertenezca a la cuadrícula. Inicializa ambas listas antes de usarlos. También puedes editarlas directamente en el YAML. - Después de registrar esos puntos, ejecuta
/etd register <level>. EscribelevelLocationsa partir de la selección, sustituyendo la lista existente, guarda el archivo del nivel y borra la selección. Desactivar el modo de selección también la descarta. - Guarda la plantilla editada, recarga y entra desde el menú del NPC o con
/etd join <level>. Espera al mensaje final de mundo listo y comprueba el mapa jugando.
El comprobador de selección calcula las dimensiones así, truncando el resultado a entero:
size = (abs(corner1 - corner2) + 1) / 3
El orden de las esquinas no importa. Comprueba los bloques centrales desde la esquina con X/Z menores más uno, cada tres bloques, a la Y de la esquina 1 en el mundo actual del jugador. Omite una casilla si su bloque central de suelo es transitable o el bloque superior no lo es. Este comprobador no valida todos los bloques de cada casilla de 3×3.
Validación de rutas
EternalTD guarda para cada inicio la ruta A* de menor coste hasta cualquier final, tanto terrestre como aérea. Si hay varias salidas, compara el coste de las rutas completas y conserva la más corta, dirigiendo a los enemigos a la salida alcanzable más cercana.
La caché terrestre se reconstruye al empezar la sesión y cada vez que se coloca o vende una torre. La caché aérea se calcula una sola vez, en la primera reconstrucción: ignora las torres, por lo que ninguna construcción puede invalidarla.
Los enemigos aéreos usan esa ruta independiente, que ignora el bloqueo de torres y pasa 4 bloques por encima del camino configurado.
Cargar el área también fuerza la carga de cada chunk con casillas, evitando que una partida larga se detenga por un chunk descargado. Los tickets se liberan al terminar, justo antes de borrar el mundo.
La caché también determina si se puede jugar el nivel: si a cualquier inicio le falta la ruta terrestre o aérea, se rechaza la entrada en lugar de empezar una partida que los enemigos no puedan completar. Se aplica la misma comprobación al colocar torres; si una bloquearía un inicio, se rechaza sin gastar oro.
La búsqueda de inicios y finales usa X/Z para resolver una casilla; no exige un centro exacto ni compara Y. Si una entrada no corresponde a ninguna casilla, se omite con un aviso. Aunque el aviso sugiera un centro incorrecto, comprueba también que la casilla exista en levelLocations.
Las casillas de inicio y final resueltas también se marcan como no construibles para impedir bloquearlas con torres. Aparecen en azul claro en el resaltado de colocación.
NPC y menús de niveles
Las configuraciones de plugins/EternalTD/npcs/ vinculan aldeanos con niveles. El clic derecho abre un menú de 9 ranuras con entradas en 0, 2, 4, 6 y 8. Solo se consideran los cinco primeros IDs configurados; los ausentes dejan huecos y los posteriores se omiten con un aviso. Un NPC sin ningún nivel referenciado cargado se omite por completo. Haz clic izquierdo en un panel de cristal verde para solicitar su nivel.
| Campo | Tipo | Predeterminado | Notas |
|---|---|---|---|
isEnabled | booleano | true | Se omiten los NPC deshabilitados |
levelIDs | lista de cadenas | obligatorio | Nombres de archivos de los niveles que ofrece |
location | cadena | null | Ubicación de aparición en formato worldName,x,y,z,pitch,yaw |
name | cadena | null en una configuración personalizada | Nombre visible del NPC; las definiciones prediseñadas pueden proporcionar uno |
difficulty | cadena | null en una configuración personalizada | Etiqueta sobre el NPC; defínela explícitamente |
disguise | cadena | null | Descriptor de LibsDisguises, como custom:etd_tutorial_npc |
customDisguiseData | cadena | null | Datos adicionales del comando de LibsDisguises, normalmente la cadena larga de aspecto de un jugador |
La aparición del NPC se programa cuatro segundos después de crear su configuración y requiere que el mundo de su ubicación esté cargado. El aldeano es invulnerable, no tiene IA, es persistente y lleva la clave de NPC de EternalTD. Con LibsDisguises habilitado y ambos campos de disfraz definidos, EternalTD intenta aplicarlo; un descriptor incorrecto puede dejar un aldeano normal.
Un soporte para armaduras flotante muestra difficulty a 2.3 bloques sobre el NPC.
Gestión del punto de aparición
DefaultConfig controla a los jugadores en el mundo central:
setupDone: registra si se ha completado la configuración inicial; predeterminadofalse.spawnLocations: predeterminadoetd_spawn,0,65,0,0,0, escrito siempre en la configuración. Solo se resuelve y usa si existeetd_spawn.manageSpawn: predeterminadotrue. Si está habilitado y el destino está cargado, solicita un teletransporte al punto de aparición 1 tick después de conectarse.playerGuide: texto del libro de instrucciones del juego.nightbreak.autoDownloadPluginUpdates: ajuste compartido de MagmaCore, predeterminadofalse, para descargar automáticamente al arrancar actualizaciones del plugin y del contenido.nightbreak.applyPluginUpdatesWithoutRestart: ajuste compartido de MagmaCore, predeterminadonever; también admitewhen-emptyoimmediately. Controla cuándo se aplica sin reiniciar una actualización del plugin descargada. Consulta Configuración inicial.
Al terminar la inicialización, EternalTD también solicita ese teletransporte para los jugadores conectados, salvo que ya estén en el mundo de destino. Esto también requiere manageSpawn y un destino cargado. Estas rutas no comprueban el resultado del teletransporte, por lo que otro plugin puede impedir la llegada.