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

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

webapp_banner.jpg

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


Распространённые проблемы

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_enter_combat и on_exit_combat не имеют игрока. Всегда добавляйте проверку на nil перед использованием context.player.

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

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

[Lua]   -> Your script took 73ms in 'on_tick' (limit: 50ms) — power disabled to prevent lag.

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

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

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

Для нативных зон kind должен быть в нижнем регистре ("sphere"). Для скриптовых утилит shape должен быть в верхнем регистре ("CONE").

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

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

8. Перезарядка не работает

Используйте check_local(key, duration) (который проверяет И устанавливает за один вызов), а не local_ready(key) с последующим отдельным set_local(duration, key).

9. Босс продолжает выполнять способность после смерти

Добавьте логику очистки в on_exit_combat и/или on_death для отмены задач планировщика.


Чтение сообщений об ошибках

Когда что-то идёт не так в 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] -> Power has been disabled for this boss to prevent further errors.
Сырая ошибка LuaЧто говорит консоль
attempt to call nilВы попытались вызвать несуществующий метод или функцию.
index expected, got nilВы попытались обратиться к полю чего-то, что равно nil.
attempt to indexВы попытались обратиться к свойству nil или недопустимого значения.
bad argumentПоказывает детали несоответствия аргументов.
TimeoutВаш скрипт выполнялся 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. Используйте context.boss:get_location(), context.player.current_location или методы context.world.
  • em.vector(...) — нет глобальной em. Используйте context.vectors.get_vector_between_locations(loc1, loc2) или простые таблицы {x=0, y=1, z=0}.
  • em.zone.sphere(...) — нет глобальной em. Используйте таблицу определения зоны вроде {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. Только потом переходите к вращающимся атакам, конечным автоматам и многоэтапным механикам.

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