Lua-скриптинг: Начало работы
Что вы узнаете
Эта страница научит вас писать первый Lua-пауэр для EliteMobs -- от пустого файла до работающей способности босса. К концу вы поймете хуки, контекст, кулдауны и общую структуру каждого файла Lua-пауэра.
Освоив основы, переходите к сопутствующим страницам:
- Хуки и жизненный цикл -- имена хуков, порядок выполнения и доступность контекста
- Босс и сущности -- API
context.boss,context.player,context.playersиcontext.entities - Мир и окружение -- частицы, звуки, молнии, спавн и API
context.world - Зоны и нацеливание -- нативные Lua-зоны, утилиты Script для нацеливания и API
context.zones/context.script - Примеры и шаблоны -- полностью работающие пауэры для изучения и адаптации
- Перечисления и значения -- ссылки на Javadoc Spigot для Particle, Material, PotionEffectType и других строковых констант
- Устранение неполадок -- частые ошибки, советы по отладке и чек-лист QC
Файлы Lua-пауэров в настоящее время экспериментальны. Имена хуков, вспомогательные методы и поведение могут измениться по мере развития EliteMobs, поэтому тщательно тестируйте перед использованием на продакшн-сервере.
Lua не заменяет существующую YAML-систему eliteScript:.
- Используйте EliteScript, когда вам нужен декларативный YAML-скриптинг с существующими страницами Действий, Целей, Зон, Условий, Кулдаунов и Относительных векторов.
- Используйте файлы Lua-пауэров, когда нужны переменные, циклы, случайный выбор, многоразовые вспомогательные функции, персистентное состояние для каждого босса и более традиционный программный поток.
У Lua есть собственная система нацеливания и зон, использующая те же знакомые имена enum и концепции из EliteScript. API Script Utilities (context.script) позволяет создавать зоны, цели и относительные векторы с теми же именами полей, задокументированных на страницах EliteScript.
Что такое Lua-пауэры
Lua-пауэры -- это автономные файлы .lua, расположенные в обычном дереве каталогов powers EliteMobs и ссылающиеся точно так же, как обычные файлы пауэров.
В чем Lua-пауэры хороши
Lua-пауэры отлично подходят, когда вам нужны:
- Ротации атак и случайный выбор приемов
- Персистентное состояние между хуками с
context.state - Отложенные и повторяющиеся действия без построения всего из YAML-ожиданий
- Пользовательские вспомогательные функции внутри одного файла
- Сложное ветвление, которое было бы неудобно в чистом EliteScript
- Логика босса, которая хочет переиспользовать определения целей и зон в стиле EliteScript
Если ваш пауэр в основном "сработало событие, выполнить пару скриптовых действий", существующие документы EliteScript по-прежнему самый быстрый и понятный способ. Если пауэру нужен настоящий программный поток, Lua -- инструмент для этого.
Для кого эта страница
Эта страница написана для трех типов читателей:
- Тех, кто уже знает EliteScript и хочет изучить Lua, не изучая "настоящее программирование" сразу целиком
- Тех, кто новичок в скриптинге EliteMobs и нуждается в полном справочнике с точными именами
- Тех, кто использует ИИ для создания пауэров и нуждается в достаточной детализации, чтобы понять, когда ИИ выдумал что-то ложное
Вам не нужно становиться полноценным Lua-разработчиком, чтобы писать полезные пауэры. Для большинства практических пауэров EliteMobs вам нужно только:
- Как разместить допустимый хук в возвращаемой таблице
- Как читать значения из
context - Как досрочно выйти с помощью
if ... then return end - Как правильно вызвать несколько вспомогательных методов
- Как скопировать правильные спецификации целей и зон из существующих документов EliteScript
Ментальная модель: EliteScript vs. Lua
Если вы знаете EliteScript, это сравнение -- самый быстрый путь к пониманию Lua-пауэров:
| Если вы мыслите в терминах EliteScript | В Lua это обычно означает |
|---|---|
| Events | Имена хуков, такие как on_spawn или on_boss_damaged_by_player |
| Cooldowns | context.cooldowns (см. context.cooldowns ниже) |
| Actions | Прямые вызовы методов, например context.world:spawn_particle_at_location(...) или context.script:damage(...) |
| Targets | context.script:target({...}) -- использует имена полей EliteScript Target |
| Zones | context.script:zone({...}) или нативные хелперы context.zones -- см. Зоны и нацеливание |
| Relative vectors | context.script:relative_vector({...}) или context.vectors |
| Script flow | Ваши собственные if в Lua, вспомогательные функции, таймеры и состояние |
Главное отличие:
- EliteScript описывает в YAML, что должно произойти.
- Lua позволяет вам решать с помощью кода, когда, почему и какая ветвь должна выполняться.
Если EliteScript ощущается как "конфигурация", то Lua ощущается как "конфигурация плюс принятие решений".
Краткий курс Lua для авторов EliteMobs
Это минимальный синтаксис Lua, который нужен большинству авторов пауэров.
Переменные
Используйте local для сохранения значения:
local cooldown_key = "fire_burst"
local damage_multiplier = 1.5
local означает, что переменная принадлежит только этому файлу или блоку.
Функции
Функции -- это многоразовые блоки логики:
local function warn_player(player)
player:send_message("&cMove!")
end
Позже вы можете вызвать её:
warn_player(context.player)
Проверки if
Используйте if, когда что-то должно происходить только иногда:
if context.player == nil then
return
end
Это означает: "если для этого хука нет игрока, остановиться здесь".
nil
nil означает "нет значения". Это Lua-версия "здесь ничего нет".
Вы часто будете проверять nil:
if context.event ~= nil then
-- сделать что-то с событием
end
~= означает "не равно".
Таблицы
Lua использует таблицы для нескольких задач:
- Списки
- Объекты с именованными ключами
- Финальное определение пауэра
Пример таблицы с именованными ключами:
local particle = {
particle = "FLAME",
amount = 1,
speed = 0.05
}
Возврат определения пауэра
В конце файла вы возвращаете одну таблицу:
return {
api_version = 1,
on_spawn = function(context)
end
}
Эта возвращенная таблица и есть файл пауэра.
Комментарии
Используйте -- для написания заметки:
-- Этот кулдаун не дает атаке срабатывать при каждом попадании
context.cooldowns:set_local(60, "fire_burst")
Ваш первый работающий пауэр, шаг за шагом
Если вы совершенно новичок, это лучшая прогрессия для "первой победы".
Перед шагом 1: Сохраните и прикрепите к боссу
Сохраните Lua-файл в обычную папку пауэров EliteMobs:
plugins/
EliteMobs/
powers/
first_test.lua
Затем добавьте имя файла в конфиг босса, используя обычный список powers::
powers:
- first_test.lua
Полный цикл для новичка:
- Сохранить файл в
plugins/EliteMobs/powers/ - Добавить имя файла
.luaв списокpowers:босса - Заспавнить или перезагрузить босса
- Протестировать хук, который вы сейчас строите
Если нужна дополнительная информация о файлах боссов, списках пауэров или структуре кастомных боссов, см. Создание кастомных боссов.
Шаг 1: Заставить файл загрузиться
return {
api_version = 1,
on_spawn = function(context)
end
}
Если это загрузилось без ошибок, вы уже доказали:
- Файл является валидным Lua
- EliteMobs нашел его
- Структура возвращаемой таблицы корректна
on_spawn-- допустимое имя хука
Шаг 2: Заставить босса сделать что-то видимое
return {
api_version = 1,
on_spawn = function(context)
context.boss:play_sound_at_self("entity.blaze.ambient", 1.0, 1.0)
end
}
Теперь у вас есть самое важное доказательство для новичка: ваш хук срабатывает.
Шаг 3: Отреагировать на удар игрока
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then
return
end
context.player:send_message("&eYou hit the boss.")
end
}
Это учит трем ключевым идеям:
on_boss_damaged_by_player-- это имя хукаcontext.player-- это игрок, участвующий в хукеreturnдосрочно выходит, когда нужные данные отсутствуют
Шаг 4: Предотвратить спам с помощью кулдауна
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then
return
end
if not context.cooldowns:local_ready("hello_message") then
return
end
context.player:send_message("&eYou woke up the boss.")
context.cooldowns:set_local(60, "hello_message")
end
}
Это первый по-настоящему полезный паттерн, который нужен большинству авторов. Если вы поняли этот паттерн, вы уже можете создавать много практических пауэров.
Шаг 5: Добавить реальный эффект
return {
api_version = 1,
on_boss_damaged_by_player = function(context)
if context.player == nil then
return
end
if not context.cooldowns:local_ready("shock") then
return
end
context.player:send_message("&cStatic jumps from the boss into your armor!")
context.world:strike_lightning_at_location(context.player.current_location)
context.cooldowns:set_local(100, "shock")
end
}
На этом этапе вы уже пишете настоящий пауэр.
Первый реальный рабочий процесс
При создании нового Lua-пауэра используйте такой порядок:
- Создать файл и заставить
on_spawnработать. - Переключиться на нужный хук.
- Убедиться, что хук содержит ожидаемые данные, такие как
context.playerилиcontext.event. - Сначала добавить сообщение или звук, до урона или частиц.
- Добавить кулдауны.
- Добавить один игровой эффект.
- Только после этого добавлять хелперы, состояние, логику планировщика или зоны.
Такой порядок значительно упрощает отладку, потому что за раз меняется только одна вещь.
Где хранятся Lua-файлы
Размещайте файлы .lua в том же дереве папок, что и обычные файлы пауэров .yml:
plugins/
EliteMobs/
powers/
mycoolpower.lua
attack_push.yml
subfolder/
myotherpower.lua
Lua-пауэры автоматически обнаруживаются из каталогов пауэров, которые EliteMobs уже загружает.
Как боссы ссылаются на Lua-пауэры
Файлы боссов по-прежнему используют обычный список powers::
powers:
- attack_push.yml
- mycoolpower.lua
Специальных полей не требуется. Lua-пауэры не загружаются через eliteScript:.
Правила именования файлов
- Боссы ссылаются на Lua-пауэры по имени файла, а не по пути к папке.
- EliteMobs в настоящее время регистрирует обнаруженные Lua-пауэры только по базовому имени.
- Избегайте дублирования имен, например
powers/fire.luaиpowers/bosses/fire.lua, так как один может перезаписать другой при обнаружении.
Готовые Lua-пауэры
EliteMobs поставляется с десятками готовых Lua-пауэров в папке powers, таких как attack_fire.lua, frost_cone.lua, meteor_shower.lua и многие другие. Это отличные справочные материалы для изучения -- просто откройте любой файл .lua в каталоге plugins/EliteMobs/powers/. Для обратной совместимости готовые пауэры также регистрируются под их устаревшими именами .yml.
Минимальный контракт файла
Каждый Lua-пауэр должен возвращать таблицу с помощью return. Эта таблица намеренно строгая.
Обязательные и необязательные поля верхнего уровня
| Поле | Обязательно | Тип | Примечания |
|---|---|---|---|
api_version | Да | Number | В настоящее время должно быть 1 |
priority | Нет | Number | Приоритет выполнения. Меньшие значения выполняются первыми. По умолчанию 0 |
| Поддерживаемые ключи хуков | Нет | Function | Должен использовать одно из точных имен хуков, перечисленных в Справочнике хуков |
Правила валидации
- Файл должен возвращать таблицу.
api_versionобязательно и в настоящее время должно быть1.priorityдолжен быть числовым, если присутствует.- Каждый дополнительный ключ верхнего уровня должен быть поддерживаемым именем хука.
- Каждый ключ хука должен указывать на функцию.
- Неизвестные ключи верхнего уровня отклоняются.
Это означает, что вспомогательные функции и локальные константы должны находиться выше финального return, а не внутри возвращаемой таблицы, если они не являются реальными хуками.
Шаблоны для копирования
Минимальный валидный Lua-пауэр
return {
api_version = 1,
on_spawn = function(context)
end
}
Рекомендуемый стартовый шаблон
local ATTACK_COOLDOWN = "my_attack"
local function can_run_attack(context)
return context.cooldowns:local_ready(ATTACK_COOLDOWN)
and context.cooldowns:global_ready()
end
local function run_attack(context)
context.boss:play_sound_at_self("entity.blaze.shoot", 1.0, 1.0)
context.cooldowns:set_local(100, ATTACK_COOLDOWN)
context.cooldowns:set_global(20)
end
return {
api_version = 1,
priority = 0,
on_boss_damaged_by_player = function(context)
if context.player == nil then
return
end
if not can_run_attack(context) then
return
end
run_attack(context)
end
}
Структура для больших файлов
local CONSTANT_NAME = "value"
local function helper_function(context)
end
local function another_helper(context, value)
end
return {
api_version = 1,
priority = 0,
on_spawn = function(context)
end,
on_enter_combat = function(context)
end,
on_boss_damaged_by_player = function(context)
end,
on_exit_combat = function(context)
end
}
Хуки
Хуки -- это специально именованные функции в таблице, которую вы возвращаете. EliteMobs вызывает их, когда что-то происходит -- босс спавнится, получает урон, вступает в бой и т.д. Вы уже видели on_spawn и on_boss_damaged_by_player в уроке выше.
Самые распространенные хуки для начала -- on_spawn, on_boss_damaged_by_player, on_enter_combat и on_exit_combat. Полный список всех хуков, доступные ключи контекста в каждом и порядок выполнения см. в Хуки и жизненный цикл.
Что такое context?
Каждая функция хука получает один аргумент -- context. Представьте его как набор инструментов, который EliteMobs передает вам каждый раз, когда что-то происходит -- он содержит все необходимое для взаимодействия с боссом, игроком, миром, кулдаунами и многим другим.
on_boss_damaged_by_player = function(context)
-- context.boss = босс, которого ударили
-- context.player = игрок, который ударил
-- context.world = инструменты для спавна частиц, звуков и т.д.
-- context.cooldowns = управление кулдаунами
-- context.state = ваше собственное постоянное хранилище
end
Вы не создаете context сами -- EliteMobs создает его и передает в ваш хук. Вы просто читаете из него и вызываете методы.
context создается заново при каждом вызове хука, кроме context.state, который сохраняется на протяжении всей жизни босса. Это означает, что вы можете хранить данные в context.state и читать их позже в другом хуке.
Ключевые API context
Вот самые важные API, которые вы будете использовать из context:
-
context.state-- Простая Lua-таблица, сохраняющаяся на протяжении жизни босса. Используйте для хранения номеров фаз, ID задач, флагов и всего, что нужно помнить между хуками. Толькоcontext.stateсохраняется -- все остальные таблицы контекста создаются заново при каждом вызове. -
context.log-- Логирование в консоль сlog:info(msg),log:warn(msg)иlog:debug(msg). Незаменимо при разработке. -
context.cooldowns-- Локальные кулдауны для каждого пауэра и глобальные для каждого босса. Ключевой метод --cooldowns:check_local(key, ticks), который атомарно проверяет И устанавливает кулдаун. См. страницу Хуки и жизненный цикл для полного API кулдаунов. -
context.scheduler-- Отложенные и повторяющиеся задачи сscheduler:run_after(ticks, callback)иscheduler:run_every(ticks, callback). Колбэки получают свежий context -- всегда используйте параметр колбэка, а не внешнийcontext. Отменяйте повторяющиеся задачи вon_exit_combat. Подробности в Хуки и жизненный цикл. -
context.boss/context.player-- Босс и игрок, участвующие в текущем событии. См. Босс и сущности для всех полей и методов. -
context.world-- Спавн частиц, сущностей, звуков, молний, блоков. См. Мир и окружение. -
context.zones/context.script-- Геометрия зон, нацеливание, урон, частицы. См. Зоны и нацеливание.
Синтаксис методов: : vs. .
В Lua object:method(arg) -- это сокращение для object.method(object, arg). API EliteMobs принимает обе формы, так что обе работают:
context.cooldowns:set_local(60, "test")
context.cooldowns.set_local(60, "test") -- то же самое
Во всей документации последовательно используется :.
Следующие шаги
Теперь, когда вы знаете основы, изучите остальную документацию по Lua-скриптингу:
- Хуки и жизненный цикл -- имена хуков, порядок выполнения и какие ключи контекста доступны в каждом хуке
- Босс и сущности --
context.boss,context.player,context.players,context.entitiesиcontext.event - Мир и окружение -- частицы, звуки, молнии, спавн и
context.world - Зоны и нацеливание -- нативные Lua-зоны, утилиты Script для нацеливания/зон/частиц и относительные векторы
- Примеры и шаблоны -- полностью работающие пауэры с пошаговым разбором
- Перечисления и значения -- ссылки на Javadoc Spigot для Particle, Material, PotionEffectType и другого
- Устранение неполадок -- частые ошибки, советы по отладке и чек-лист QC
Для YAML-скриптинга страницы EliteScript остаются каноническим справочником:
