Перейти к основному содержимому

Lua-скриптинг: Устранение неполадок

webapp_banner.jpg

Эта страница охватывает распространённые проблемы, с которыми вы можете столкнуться при написании или отладке Lua-способностей, а также советы по миграции для авторов, переходящих с EliteScript. Если вы отлаживаете NPC-скрипты, см. NPC-скрипты. Для рабочих примеров см. Примеры и паттерны. Если вы только начинаете, см. Начало работы.

Общий движок Lua

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

Не все хуки предоставляют игрока. on_spawn, on_game_tick и on_exit_combat не имеют игрока. on_enter_combat предоставляет context.player (игрока, который начал бой). В on_boss_damaged (общий урон) наносящий урон может не быть игроком. Всегда добавляйте проверку на nil перед использованием context.player.

4. Таймаут / превышен бюджет выполнения

Если хук или колбэк выполняется слишком долго, способность автоматически отключается, чтобы предотвратить лаги. Сообщение в консоли выглядит так:

[Lua] my_power.lua took 73ms in 'on_game_tick' (limit: 50ms) — script disabled to prevent lag.

Частые причины: перебор слишком большого числа сущностей, создание слишком большого числа зон за тик или выполнение затратных строковых операций в on_game_tick. Перенесите затратную работу за барьер перезарядки или уменьшите объём работы, выполняемой за один вызов.

5. Колбэк планировщика использует устаревшие данные

Вы, вероятно, используете внешний context вместо параметра колбэка. Измените function() ... context.boss ... end на function(tick_context) ... tick_context.boss ... end.

6. Запрос зоны не возвращает сущности

Дважды проверьте определение зоны. Для нативных зон убедитесь, что kind указан в нижнем регистре ("sphere", а не "SPHERE"). Для скриптовых утилит убедитесь, что shape указан в верхнем регистре ("CONE", а не "cone"). Также проверьте, что origin или Target действительно разрешаются в допустимую локацию.

7. Частицы не появляются

Убедитесь, что имя частицы — допустимое значение перечисления Particle Bukkit в UPPER_CASE. Частая ошибка: "flame" (неправильно) vs. "FLAME" (правильно). Также проверьте, что amount равен хотя бы 1, а локация находится в загруженном чанке.

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. фактический тип).
Timeout<filename> выполнялся Xмс в 'hook_name' (лимит: 50мс) — скрипт отключён для предотвращения лагов.
подсказка

Когда вы видите ошибку [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-способности:

  1. Продолжайте думать в терминах событий, целей, зон, относительных векторов и частиц. Концепции те же — меняется только синтаксис. События EliteScript становятся именами хуков вроде on_spawn или on_boss_damaged_by_player. Цели и зоны передаются как таблицы в context.script с использованием тех же имён полей, что задокументированы на страницах Зоны EliteScript и Цели EliteScript.

  2. Перенесите поток управления в Lua. Случайные броски, общие вспомогательные функции, циклы, постоянное состояние (context.state) и планирование задач (context.scheduler) — это то, что Lua добавляет и что чистый EliteScript не может легко сделать. Начните с преобразования одной ветвящейся или условной способности в Lua, сохраняя всё остальное без изменений.

  3. Используйте context.script для нацеливания и геометрии зон. Скриптовые утилиты принимают те же имена полей, что и EliteScript (targetType, shape, Target, Target2, range, offset, coverage), поэтому вы можете продолжать использовать существующую документацию EliteScript как справочник для этих спецификаций. Это позволяет использовать знакомые паттерны, получая при этом гибкость Lua для логического слоя.


Путь обучения для начинающих

Если вы хотите изучить эту систему с нуля, хорошо работает такая последовательность:

  1. Напишите файл только с api_version = 1 и on_spawn.
  2. Заставьте босса отправить сообщение или воспроизвести звук.
  3. Добавьте перезарядку с context.cooldowns.
  4. Добавьте один хук, вызываемый игроком, например on_boss_damaged_by_player.
  5. Добавьте одно отложенное действие с context.scheduler:run_after(...).
  6. Добавьте один простой запрос нативной Lua-зоны или один простой context.script:target(...).
  7. Только потом переходите к вращающимся атакам, конечным автоматам и многоэтапным механикам.

Каждый шаг строится на предыдущем, и вы можете тестировать на каждом этапе. Не пытайтесь написать многофазного босса в качестве своей первой Lua-способности.


Следующие шаги

  • Начало работы — структура файлов, хуки, пошаговый разбор первой способности, шаблоны для копирования
  • NPC-скрипты — скрипты близости, взаимодействия и жизненного цикла NPC
  • Примеры и паттерны — полностью рабочие способности для изучения и адаптации