Lua-скриптинг: Устранение неполадок
Эта страница охватывает распространённые проблемы, с которыми вы можете столкнуться при написании или отладке Lua-способностей, а также советы по миграции для авторов, переходящих с EliteScript. Если вы отлаживаете NPC-скрипты, см. NPC-скрипты. Для рабочих примеров см. Примеры и паттерны. Если вы только начинаете, см. Начало работы.
EliteMobs использует движок Lua-скриптинга MagmaCore, общий для плагинов Nightbreak. Документацию по общим концепциям, таким как песочница, планировщик, зоны, API мира, таблицы сущностей и методы UI игрока, см. на странице Движок Lua-скриптинга MagmaCore.
Распространённые проблемы
1. Способность вообще не загружается
Проверьте серверную консоль на наличие ошибок при запуске сервера. Самая частая причина — синтаксическая ошибка Lua (отсутствие end, несовпадающие скобки и т.д.). Также убедитесь, что файл заканчивается на .lua и находится в правильном каталоге powers.
2. Хук никогда не срабатывает
Убедитесь, что имя хука написано точно так, как указано в списке хуков. Частые ошибки: on_boss_hit (неправильно) vs. on_boss_damaged_by_player (правильно), или on_tick (неправильно) vs. on_game_tick (правильно).
3. context.player равен nil
context.player заполняется только у тех хуков, чьё базовое событие несёт игрока. Он всегда равен nil в on_spawn, on_game_tick, on_boss_damaged, on_boss_damaged_by_elite, on_exit_combat, on_heal, on_death и on_phase_switch.
Он заполняется в on_boss_damaged_by_player, on_player_damaged_by_boss, on_enter_combat и on_boss_target_changed, а также в on_zone_enter / on_zone_leave, когда участвующая сущность оказывается игроком. Всегда добавляйте проверку на nil перед использованием. Полную таблицу см. в Хуках и жизненном цикле.
4. Таймаут / превышен бюджет выполнения
Каждый хук, запланированный коллбэк и вычисление файла делят с вложенными вызовами бюджет в 250 000 инструкций Lua и 50 мс процессорного времени потока. Если JVM не может измерить это время, используется резервный предел в 250 мс прошедшего времени. Ошибка указывает превышенный предел:
Lua instruction budget exceeded (250000 instruction limit)
Lua CPU-time budget exceeded (50ms current-thread CPU limit)
Lua elapsed-time fallback budget exceeded (250ms fallback; current-thread CPU time unavailable)
VM прерывает неуправляемые циклы Lua во время выполнения, но не может прервать выполняющийся вызов Java API. Отдельного предела в 50 мс после возврата вызова нет. Используйте перезарядки, меньше точек выборки или context.scheduler:run_every(...), чтобы распределить работу между тиками.
5. Колбэк планировщика использует устаревшие данные
Вы, вероятно, используете внешний context вместо параметра колбэка. Измените function() ... context.boss ... end на function(tick_context) ... tick_context.boss ... end.
6. Запрос зоны не возвращает сущности
Дважды проверьте определение зоны. Для нативных зон убедитесь, что kind указан в нижнем регистре ("sphere", а не "SPHERE"). Для скриптовых утилит убедитесь, что shape указан в верхнем регистре ("CONE", а не "cone"). Также проверьте, что origin или Target действительно разрешаются в допустимую локацию.
7. Частицы не появляются
Используйте допустимое имя Bukkit Particle: и "FLAME", и "flame" приводятся к верхнему регистру. Проверьте позицию, количество и необходимые данные. Для BLOCK нужны данные блока, которые этот помощник мира не передаёт; используйте поддерживаемую частицу или API частиц скрипта с параметром материала.
8. Перезарядка, похоже, не работает
Убедитесь, что вы используете check_local(key, duration) (который проверяет И устанавливает за один вызов), а не local_ready(key) с последующим отдельным set_local(duration, key). Если вы используете только local_ready, вы лишь проверяете, но никогда не устанавливаете перезарядку.
9. Босс продолжает выполнять способность после смерти
Добавьте логику очистки в on_exit_combat и/или on_death для отмены задач планировщика. Если босс умирает, on_exit_combat должен сработать, но добавление явной очистки в оба хука безопаснее.
Чтение сообщений об ошибках
Когда что-то идёт не так в Lua-способности, консоль выводит дружественный блок ошибки с префиксом [Lua]. Эти сообщения сообщают вам точно, какой файл, какая строка, какой хук и что именно пошло не так — простым языком. Всегда читайте полное сообщение перед отладкой.
Типичная ошибка выглядит так:
[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] -> Script has been disabled for this entity to prevent further errors.
Система переводит распространённые ошибки Lua на простой язык. Вот самые частые из них:
| Сырая ошибка Lua | Что говорит консоль |
|---|---|
attempt to call nil | Вы попытались вызвать несуществующий метод или функцию. Проверьте имя метода на опечатки или убедитесь, что используете : (двоеточие) для вызовов методов, а не . (точку). |
index expected, got nil | Вы попытались обратиться к полю чего-то, что равно nil. Проверьте, что более ранний код инициализировал это. |
attempt to index | Вы попытались обратиться к свойству nil или недопустимого значения. |
bad argument | Показывает конкретные детали несоответствия аргумента (ожидаемый тип vs. фактический тип). |
| Превышен бюджет | Вызов прерывается при превышении лимита в 250 000 инструкций Lua или 50 мс процессорного времени текущего потока. Если измерение процессорного времени недоступно, используется резервный лимит в 250 мс реального времени. Ошибка отключает экземпляр скрипта. |
Когда вы видите ошибку [Lua] в консоли, сообщение об ошибке точно сообщает вам, какой файл, какая строка, какой хук и что пошло не так простым языком. Прочитайте полное сообщение, прежде чем погружаться в код — обычно оно указывает прямо на решение.
Не предполагайте существование недокументированных псевдонимов
Lua API предоставляет определённый набор имён методов. Если вы пишете способности вручную или с помощью ИИ, не предполагайте, что существуют сокращённые или альтернативные имена. Следующие имена приведены как примеры тех, что не существуют и вызовут ошибки:
show_temporary_boss_bar()— используйтеplayer:show_boss_bar(title, color, style, duration).run_command_as_player()— используйтеplayer:run_command(command).em.location(...)— неправильное имя метода. Используйтеem.create_location(x, y, z), либоcontext.boss:get_location()/context.player.current_location.em.vector(...)— неправильное имя метода. Используйтеem.create_vector(x, y, z)или простые таблицы{x=0, y=1, z=0}.em.zone.sphere(...)— неправильное имя метода. Используйтеem.zone.create_sphere_zone(radius)или таблицу определения зоны вроде{kind = "sphere", radius = 5, origin = location}.entity:teleport_to(...)— используйтеentity:teleport_to_location(location).entity:set_velocity(...)— используйтеentity:set_velocity_vector(vector).entity:set_facing(...)— используйтеentity:face_direction_or_location(direction_or_location).
Если сомневаетесь, проверьте страницы Справочника API (Босс и сущности, Мир и окружение, Зоны и нацеливание). Если что-то не задокументировано там, оно не существует.
Советы по миграции для авторов EliteScript
Если вы уже пишете хорошие EliteScripts, самый простой способ изучить Lua-способности:
-
Продолжайте думать в терминах событий, целей, зон, относительных векторов и частиц. Концепции те же — меняется только синтаксис. События EliteScript становятся именами хуков вроде
on_spawnилиon_boss_damaged_by_player. Цели и зоны передаются как таблицы вcontext.scriptс использованием тех же имён полей, что задокументированы на страницах Зоны EliteScript и Цели EliteScript. -
Перенесите поток управления в Lua. Случайные броски, общие вспомогательные функции, циклы, постоянное состояние (
context.state) и планирование задач (context.scheduler) — это то, что Lua добавляет и что чистый EliteScript не может легко сделать. Начните с преобразования одной ветвящейся или условной способности в Lua, сохраняя всё остальное без изменений. -
Используйте
context.scriptдля нацеливания и геометрии зон. Это не имитация — передаваемая вами таблица-спецификация попадает в настоящий движок EliteScript, поэтому каждое поле, описанное на страницах EliteScript (targetType,shape,Target,Target2,FinalTarget,range,offset,relativeOffset,coverage,filter, ...), работает дословно, с теми же значениями по умолчанию и той же расстановкой заглавных букв. Держите документацию EliteScript открытой как справочник по спецификациям и используйте Lua исключительно для логического слоя. -
Следите за двумя системами зон.
context.script:zone({shape = "SPHERE", ...})— это движок EliteScript (ЗАГЛАВНЫЕ перечисления, таблицы-спецификацииTarget).context.zones— отдельная облегчённая реализация (строчныйkind, простые локацииorigin/destination). Смешивание их стилей ключей молча даёт пустую зону.
Путь обучения для начинающих
Если вы хотите изучить эту систему с нуля, хорошо работает такая последовательность:
- Напишите файл только с
api_version = 1иon_spawn. - Заставьте босса отправить сообщение или воспроизвести звук.
- Добавьте перезарядку с
context.cooldowns. - Добавьте один хук, вызываемый игроком, например
on_boss_damaged_by_player. - Добавьте одно отложенное действие с
context.scheduler:run_after(...). - Добавьте один простой запрос нативной Lua-зоны или один простой
context.script:target(...). - Только потом переходите к вращающимся атакам, конечным автоматам и многоэтапным механикам.
Каждый шаг строится на предыдущем, и вы можете тестировать на каждом этапе. Не пытайтесь написать многофазного босса в качестве своей первой Lua-способности.
Следующие шаги
- Начало работы — структура файлов, хуки, пошаговый разбор первой способности, шаблоны для копирования
- NPC-скрипты — скрипты близости, взаимодействия и жизненного цикла NPC
- Примеры и паттерны — полностью рабочие способности для изучения и адаптации
