Scripting Lua: Solución de problemas
Esta página cubre problemas comunes que puedes encontrar al escribir o depurar poderes Lua, además de consejos de migración para autores que vienen de EliteScript. Si buscas ejemplos funcionales, consulta Ejemplos y patrones. Si recién empiezas, consulta Primeros pasos.
EliteMobs usa el motor de scripting Lua de MagmaCore compartido entre los plugins de Nightbreak. Para documentación sobre conceptos compartidos como el sandbox, scheduler, zonas, API del mundo, tablas de entidades y métodos de UI de jugador, consulta la página del Motor de Scripting Lua de MagmaCore.
Problemas comunes
1. El poder no carga en absoluto
Revisa la consola del servidor en busca de errores al iniciar. La causa más común es un error de sintaxis Lua (falta end, paréntesis no coincidentes, etc.). También verifica que el archivo termine en .lua y esté en el directorio powers correcto.
2. El hook nunca se dispara
Verifica que el nombre del hook esté escrito exactamente como aparece en la lista de hooks. Errores comunes: on_boss_hit (incorrecto) vs. on_boss_damaged_by_player (correcto), o on_tick (incorrecto) vs. on_game_tick (correcto).
3. context.player es nil
No todos los hooks proporcionan un jugador. on_spawn, on_game_tick y on_exit_combat no tienen jugador. on_enter_combat sí proporciona context.player (el jugador que inició el combate). En on_boss_damaged (daño genérico), el atacante puede no ser un jugador. Siempre agrega una guardia nil antes de usar context.player.
4. Timeout / presupuesto de ejecución excedido
Si un hook o callback tarda demasiado, el poder se desactiva automáticamente para prevenir lag. El mensaje de consola se ve así:
[Lua] -> Your script took 73ms in 'on_tick' (limit: 50ms) — power disabled to prevent lag.
Causas comunes: iterar sobre demasiadas entidades, crear demasiadas zonas por tick, o ejecutar operaciones de cadena costosas en on_game_tick. Mueve el trabajo pesado detrás de un gate de cooldown o reduce el trabajo por llamada.
5. El callback del scheduler usa datos obsoletos
Probablemente estás usando el context externo en lugar del parámetro del callback. Cambia function() ... context.boss ... end a function(tick_context) ... tick_context.boss ... end.
6. La consulta de zona no devuelve entidades
Verifica la definición de zona. Para zonas nativas, asegúrate de que kind esté en minúsculas ("sphere", no "SPHERE"). Para utilidades de script, asegúrate de que shape esté en mayúsculas ("CONE", no "cone"). También verifica que origin o Target realmente resuelva a una ubicación válida.
7. Las partículas no aparecen
Verifica que el nombre de partícula sea un valor de enum Particle de Bukkit válido en UPPER_CASE. Error común: "flame" (incorrecto) vs. "FLAME" (correcto). También verifica que amount sea al menos 1 y que la ubicación esté en un chunk cargado.
8. El cooldown no parece funcionar
Asegúrate de usar check_local(key, duration) (que verifica Y establece en una llamada), no local_ready(key) seguido de un set_local(duration, key) separado. Si usas local_ready solo, solo verificas pero nunca estableces el cooldown.
9. El boss sigue ejecutando el poder después de morir
Agrega lógica de limpieza en on_exit_combat y/o on_death para cancelar tareas del scheduler. Cuando el boss muere, on_exit_combat debería dispararse, pero agregar limpieza explícita en ambos hooks es más seguro.
Lectura de mensajes de error
Cuando algo sale mal en un poder Lua, la consola imprime un bloque de error amigable con el prefijo [Lua]. Estos mensajes te dicen exactamente qué archivo, qué línea, qué hook y qué salió mal -- en lenguaje simple. Siempre lee el mensaje completo antes de depurar.
Un error típico se ve así:
[Lua] Error in 'push_zone.lua' at line 35 during 'on_boss_damaged_by_player':
[Lua] -> You tried to call a method or function that doesn't exist.
[Lua] -> Check the method name for typos, or make sure you're using ':' (colon) for method calls, not '.' (dot).
[Lua] -> Power has been disabled for this boss to prevent further errors.
El sistema traduce errores comunes de Lua a lenguaje simple. Aquí están los más comunes:
| Error Lua crudo | Lo que la consola te dice |
|---|---|
attempt to call nil | Intentaste llamar un método o función que no existe. Revisa el nombre del método por errores tipográficos, o asegúrate de usar : (dos puntos) para llamadas a métodos, no . (punto). |
index expected, got nil | Intentaste acceder a un campo de algo que es nil. Verifica que código anterior lo haya inicializado. |
attempt to index | Intentaste acceder a una propiedad de un valor nil o inválido. |
bad argument | Muestra los detalles específicos de discrepancia de argumentos (tipo esperado vs. tipo real). |
| Timeout | Tu script tardó Xms en 'hook_name' (límite: 50ms) -- poder desactivado para prevenir lag. |
Cuando veas un error [Lua] en la consola, el mensaje te dice exactamente qué archivo, qué línea, qué hook y qué salió mal en lenguaje simple. Lee el mensaje completo antes de sumergirte en el código -- generalmente te señala directamente la solución.
No asumas que existen alias no documentados
La API Lua expone un conjunto específico de nombres de métodos. Si escribes poderes a mano o con asistencia de IA, no asumas que existen nombres abreviados o alternativos. Los siguientes son ejemplos de nombres que no existen y causarán errores:
show_temporary_boss_bar()-- usaplayer:show_boss_bar(title, color, style, duration)en su lugar.run_command_as_player()-- usaplayer:run_command(command)en su lugar.em.location(...)-- el nombre del método es incorrecto. Usaem.create_location(x, y, z)en su lugar, ocontext.boss:get_location()/context.player.current_location.em.vector(...)-- el nombre del método es incorrecto. Usaem.create_vector(x, y, z)en su lugar, o tablas simples{x=0, y=1, z=0}.em.zone.sphere(...)-- el nombre del método es incorrecto. Usaem.zone.create_sphere_zone(radius)en su lugar, o una tabla de definición de zona como{kind = "sphere", radius = 5, origin = location}.entity:teleport_to(...)-- usaentity:teleport_to_location(location).entity:set_velocity(...)-- usaentity:set_velocity_vector(vector).entity:set_facing(...)-- usaentity:face_direction_or_location(direction_or_location).
En caso de duda, consulta las páginas de Referencia de API (Boss y entidades, Mundo y entorno, Zonas y objetivos). Si no está documentado ahí, no existe.
Consejos de migración para autores de EliteScript
Si ya escribes buenos EliteScripts, la forma más fácil de aprender poderes Lua es:
-
Sigue pensando en términos de eventos, objetivos, zonas, vectores relativos y partículas. Los conceptos son los mismos -- solo la sintaxis cambia. Los eventos de EliteScript se convierten en nombres de hooks como
on_spawnuon_boss_damaged_by_player. Los objetivos y zonas se pasan como tablas acontext.scriptusando los mismos nombres de campo documentados en las páginas de Zonas de EliteScript y Objetivos de EliteScript. -
Mueve tu flujo de control a Lua. Tiradas aleatorias, funciones auxiliares compartidas, bucles, estado persistente (
context.state) y programación de tareas (context.scheduler) son las cosas que Lua agrega y que EliteScript puro no puede hacer fácilmente. -
Usa
context.scriptpara targeting y geometría de zonas. Las utilidades de script aceptan los mismos nombres de campo que EliteScript (targetType,shape,Target,Target2,range,offset,coverage), por lo que puedes seguir usando la documentación existente de EliteScript como referencia.
Camino de progresión para principiantes
Si quieres aprender este sistema desde cero, esta progresión funciona bien:
- Escribe un archivo con solo
api_version = 1yon_spawn. - Haz que el boss envíe un mensaje o reproduzca un sonido.
- Agrega un cooldown con
context.cooldowns. - Agrega un hook activado por jugador como
on_boss_damaged_by_player. - Agrega una acción retrasada con
context.scheduler:run_after(...). - Agrega una consulta de zona nativa Lua simple o un
context.script:target(...)simple. - Solo entonces pasa a ataques rotatorios, máquinas de estado y mecánicas de múltiples pasos.
Cada paso se basa en el anterior, y puedes probar en cada etapa. No intentes escribir un boss multifase como tu primer poder Lua.
Próximos pasos
- Primeros pasos -- estructura de archivos, hooks, primera explicación de poder, plantillas para copiar y pegar
- Ejemplos y patrones -- poderes funcionales completos que puedes estudiar y adaptar
