Lua Scripting: Начало работы
Эта страница научит вас писать ваш первый Lua script для prop в FreeMinecraftModels -- от пустого файла до работающего интерактивного prop. К концу вы поймёте hooks, context, Prop API и общую структуру каждого файла script для prop.
Освоив основы, переходите к сопутствующим страницам:
- Prop API -- API
context.prop,context.event,context.worldи другие context API - Примеры и шаблоны -- полностью рабочие scripts для изучения и адаптации
- Устранение неполадок -- распространённые ошибки, советы по отладке и чек-лист QC
Lua script для prop в настоящее время являются экспериментальными. Названия hook, вспомогательные методы и поведение могут изменяться по мере развития FreeMinecraftModels, поэтому тщательно тестируйте их перед использованием на рабочем сервере.
FreeMinecraftModels использует тот же движок Lua (Magmacore), что и EliteMobs. Если вы уже пишете Lua-способности для EliteMobs, основные концепции -- hooks, context, api_version, scheduler, зоны и sandbox -- идентичны. Разница в следующем:
- Scripts EliteMobs запускаются на боссах и имеют hooks вроде
on_boss_damaged_by_player,on_enter_combatи т.д. - Scripts FMM запускаются на props и имеют hooks вроде
on_right_click,on_left_click,on_projectile_hitи т.д.
API context.world, context.zones, context.scheduler, context.state и context.log одинаковы в обоих plugins. Эта страница охватывает только то, что специфично для prop FMM.
Что такое scripts для prop
Scripts для prop -- это автономные файлы .lua, расположенные в папке plugins/FreeMinecraftModels/scripts/. Они указываются в YAML config файле, который находится рядом с файлом модели, и запускаются каждый раз, когда prop появляется в мире.
Для чего хороши scripts для prop
Scripts для prop отлично подходят, когда вам нужны:
- Интерактивные props, реагирующие на клики игроков (двери, рычаги, кнопки)
- Неуязвимые декоративные props, которые игроки не могут сломать
- Триггеры приближения, определяющие, когда игроки входят в область или покидают её
- Анимированные props, воспроизводящие анимации при взаимодействии или по таймеру
- Props, воспроизводящие звуки при клике или приближении
- Любое поведение prop, требующее логики помимо статичного оформления
Если ваш prop является чисто декоративным и не требует взаимодействия, script не нужен.
Для кого эта страница
Эта страница написана для трёх типов читателей:
- Тех, кто уже знает Lua scripting в EliteMobs и хочет изучить hooks и API, специфичные для FMM
- Тех, кто новичок в Lua scripting и нуждается в полном справочнике с точными именами для props
- Тех, кто использует ИИ для создания scripts для prop и нуждается в достаточной детализации, чтобы определить, когда ИИ выдумал что-то несуществующее
Вам не нужно становиться полноценным Lua-разработчиком, чтобы писать полезные scripts для prop. Для большинства практических scripts для prop вам нужно только:
- Как разместить валидный hook в возвращаемой таблице
- Как читать значения из
context - Как досрочно выйти с помощью
if ... then return end - Как точно вызвать несколько вспомогательных методов
Краткое введение в Lua
Если вы совсем новичок в Lua, вот минимальный синтаксис, который вам нужен.
Переменные
Используйте local для сохранения значения:
local animation_name = "open"
local sound_volume = 1.0
Функции
Функции -- это многоразовые блоки логики:
local function log_click(context)
context.log:info("Prop was clicked!")
end
Проверки if
Используйте if, когда что-то должно происходить только иногда:
if context.event == nil then
return
end
nil
nil означает "нет значения". Вы будете часто проверять его:
if context.event ~= nil then
context.event.cancel()
end
Таблицы
Lua использует таблицы для объектов с именованными ключами и для возвращаемого определения script:
return {
api_version = 1,
on_spawn = function(context)
end
}
Комментарии
Используйте -- для заметок:
-- Cancel the damage event so the prop cannot be broken
context.event.cancel()
Для более подробного введения в Lua см. страницу Начало работы с EliteMobs. Основы синтаксиса идентичны.
Расположение файлов
Файлы script
Размещайте файлы .lua в центральной папке scripts:
plugins/
FreeMinecraftModels/
scripts/
invulnerable.lua
interactive_door.lua
proximity_sound.lua
FMM обнаруживает все файлы .lua в plugins/FreeMinecraftModels/scripts/ при запуске.
Файлы моделей и файлы config
Каждый файл модели может иметь связанный файл .yml config в том же каталоге:
plugins/
FreeMinecraftModels/
models/
torch_01.fmmodel
torch_01.yml <-- config script для torch_01
scripts/
invulnerable.lua <-- указан в torch_01.yml
Файл .yml config связывает модель с её scripts.
Формат файла config
YAML config файл, расположенный рядом с файлом модели, имеет два поля:
isEnabled: true
scripts:
- invulnerable.lua
| Поле | Тип | По умолчанию | Примечания |
|---|---|---|---|
isEnabled | boolean | true | Активны ли scripts для данного prop |
scripts | список строк | [] | Имена файлов .lua в папке scripts/ |
К одному prop можно прикрепить несколько scripts. Каждый script является отдельным независимым экземпляром.
Отложенная генерация config
Когда prop появляется и связанный файл .yml не существует, FMM автоматически создаёт файл config по умолчанию с isEnabled: true и пустым списком scripts:. Это происходит асинхронно, поэтому при первом появлении у prop не будет scripts -- только после создания config и добавления имён файлов script.
Это означает:
- Поместите файл модели в
models/ - Создайте prop один раз (FMM автоматически создаст
.yml) - Отредактируйте сгенерированный
.yml, добавив имена файлов script - Создайте prop повторно или перезагрузите сервер (scripts теперь активны)
Справочник hooks
Каждый файл Lua script для prop возвращает таблицу. Каждый ключ в этой таблице (кроме api_version и priority) должен быть одним из перечисленных ниже hooks. Среда выполнения вызывает соответствующую функцию каждый раз, когда срабатывает связанное игровое событие.
| Hook | Срабатывает, когда | Примечания |
|---|---|---|
on_spawn | Prop появляется в мире | Выполняется один раз при привязке script |
on_game_tick | Один раз за серверный тик (50 мс) | Активен только если script определяет этот hook |
on_destroy | Prop удаляется из мира | Hook очистки |
on_left_click | Игрок кликает левой кнопкой (бьёт) prop | context.event -- событие урона |
on_right_click | Игрок кликает правой кнопкой по prop | context.event -- событие взаимодействия |
on_projectile_hit | Снаряд попадает в prop | context.event -- событие попадания снаряда |
on_zone_enter | Игрок входит в наблюдаемую зону | Требуется настройка наблюдения за зоной |
on_zone_leave | Игрок покидает наблюдаемую зону | Требуется настройка наблюдения за зоной |
Минимальный контракт файла
Каждый Lua script для prop должен возвращать (return) таблицу.
Обязательные и необязательные поля верхнего уровня
| Поле | Обязательно | Тип | Примечания |
|---|---|---|---|
api_version | Да | Number | В настоящее время должно быть 1 |
priority | Нет | Number | Приоритет выполнения. Меньшие значения выполняются первыми. По умолчанию 0 |
| Поддерживаемые ключи hook | Нет | Function | Должен использоваться один из точных имён hook из Справочника hooks |
Правила валидации
- Файл должен возвращать таблицу.
api_versionобязателен и в настоящее время должен быть1.priorityдолжен быть числовым, если указан.- Каждый дополнительный ключ верхнего уровня должен быть поддерживаемым именем hook.
- Каждый ключ hook должен указывать на функцию.
- Неизвестные ключи верхнего уровня отклоняются.
Вспомогательные функции и локальные константы должны находиться над финальным return, а не внутри возвращаемой таблицы.
Ваш первый рабочий script для prop, шаг за шагом
Перед шагом 1: Настройка config
- Поместите файл модели (например,
my_prop.fmmodel) вplugins/FreeMinecraftModels/models/ - Создайте prop один раз для генерации config
.yml - Создайте файл script в
plugins/FreeMinecraftModels/scripts/first_test.lua - Отредактируйте
plugins/FreeMinecraftModels/models/my_prop.yml:
isEnabled: true
scripts:
- first_test.lua
- Создайте prop повторно или перезагрузите сервер
Шаг 1: Убедиться, что файл загружается
return {
api_version = 1,
on_spawn = function(context)
end
}
Если файл загружается без ошибок в консоли, вы доказали:
- Файл является валидным Lua
- FMM нашёл его в папке
scripts/ - Config правильно ссылается на него
- Структура возвращаемой таблицы корректна
Шаг 2: Заставить prop сделать что-то видимое
return {
api_version = 1,
on_spawn = function(context)
context.log:info("Prop script loaded for: " .. (context.prop.model_id or "unknown"))
end
}
Проверьте серверную консоль. Если вы видите сообщение в логе, ваш hook срабатывает.
Шаг 3: Реагировать на клик игрока
return {
api_version = 1,
on_right_click = function(context)
context.log:info("Prop was right-clicked!")
end
}
Кликните правой кнопкой по prop в игре. Если консоль показывает сообщение, hook клика работает.
Шаг 4: Отменить урон, чтобы сделать prop неуязвимым
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
Это паттерн, используемый готовым script invulnerable.lua. Он отменяет событие урона, чтобы armor stand, лежащий в основе prop, не мог быть уничтожен.
Шаг 5: Воспроизвести анимацию по клику
return {
api_version = 1,
on_right_click = function(context)
context.prop:play_animation("open", true, false)
end
}
Это воспроизводит анимацию "open" на модели prop со смешиванием и без зацикливания.
Что такое context?
Каждая функция hook получает один аргумент -- context. Представьте его как набор инструментов, который FMM передаёт вам каждый раз, когда что-то происходит -- он содержит всё необходимое для взаимодействия с prop, миром, зонами и прочим.
on_right_click = function(context)
-- context.prop = prop, по которому кликнули
-- context.event = событие клика (можно отменить)
-- context.world = инструменты для частиц, звуков, запросов блоков
-- context.state = ваше собственное постоянное хранилище
-- context.log = логирование в консоль
-- context.scheduler = отложенные и повторяющиеся задачи
-- context.zones = создание и наблюдение за пространственными зонами
end
Вы не создаёте context самостоятельно -- FMM создаёт его и передаёт в ваш hook.
context создаётся заново для каждого вызова hook, за исключением context.state, который сохраняется на протяжении всего времени жизни prop. Это означает, что вы можете сохранять данные в context.state и читать их позже в другом hook.
Ключевые API context
Вот краткое описание доступных возможностей. Подробности см. в Prop API.
-
context.prop-- Сущность prop. Предоставляетmodel_id,current_location,play_animation()иstop_animation(). -
context.event-- Событие Bukkit, вызвавшее этот hook. Доступно вon_left_click,on_right_clickиon_projectile_hit. Предоставляетcancel(),uncancel()иis_cancelled. Равноnilв hooks без события (например,on_spawnиon_game_tick). -
context.state-- Простая Lua-таблица, сохраняющаяся на протяжении жизни prop. Используйте для хранения флагов, состояний переключения, ID задач и всего, что нужно помнить между hooks. -
context.log-- Логирование в консоль с помощьюlog:info(msg),log:warn(msg)иlog:error(msg). -
context.scheduler-- Отложенные и повторяющиеся задачи с помощьюscheduler:run_later(ticks, callback)иscheduler:run_repeating(delay, interval, callback). Callbacks получают свежий context. Отмена задач черезscheduler:cancel(taskId). -
context.world-- Взаимодействие с миром: частицы, звуки, запросы блоков, молнии, ближайшие сущности. См. Prop API для полного списка методов. -
context.zones-- Создание и наблюдение за пространственными зонами (сферы, цилиндры, кубоиды). См. Prop API для полного списка методов.
Синтаксис методов: : vs .
В Lua object:method(arg) -- это сокращение для object.method(object, arg). API FMM принимает обе формы:
context.log:info("hello")
context.log.info("hello") -- то же самое
Вся документация последовательно использует :.
Готовые шаблоны для копирования
Минимальный валидный script для prop
return {
api_version = 1,
on_spawn = function(context)
end
}
Шаблон неуязвимого prop
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
Шаблон интерактивного prop
return {
api_version = 1,
on_spawn = function(context)
context.state.is_active = false
end,
on_right_click = function(context)
context.state.is_active = not context.state.is_active
if context.state.is_active then
context.prop:play_animation("activate", true, true)
else
context.prop:stop_animation()
end
end
}
Расширенная структура файла
local ANIMATION_NAME = "idle"
local function do_something(context)
context.log:info("Doing something!")
end
return {
api_version = 1,
priority = 0,
on_spawn = function(context)
context.state.task_id = nil
end,
on_right_click = function(context)
do_something(context)
end,
on_destroy = function(context)
if context.state.task_id ~= nil then
context.scheduler:cancel(context.state.task_id)
end
end
}
Первый реальный рабочий процесс
При создании совершенно нового script для prop используйте следующий порядок:
- Создайте файл
.luaи добейтесь работыon_spawn. - Добавьте имя файла script в config
.ymlprop. - Переключитесь на нужный hook (например,
on_right_click). - Сначала добавьте сообщение в лог, до анимаций или эффектов.
- Добавьте один реальный эффект (анимацию, звук, частицы).
- Только после этого добавляйте вспомогательные функции, state, логику scheduler или зоны.
Такой порядок значительно упрощает отладку, поскольку за раз меняется только одна вещь.
Готовые scripts
FMM поставляется с одним готовым Lua script:
invulnerable.lua-- Отменяет события урона от левого клика, делая prop неразрушимым. Это самый простой полезный script для prop.
Больше примеров можно найти на странице Примеры и шаблоны.
Lua Sandbox
Scripts для prop запускаются в той же изолированной среде LuaJ, что и EliteMobs. Ограничения sandbox идентичны. Полный список удалённых глобальных переменных и доступных функций стандартной библиотеки см. на странице EliteMobs Hooks & Lifecycle.
Кратко:
- Удалены:
debug,dofile,io,load,loadfile,luajava,module,os,package,require - Доступны: Все функции
math.*,string.*,table.*,pairs,ipairs,type,tostring,tonumber,pcall,printи другие
print выводит в серверную консоль, но предпочтительнее использовать context.log:info(msg). Сообщения лога содержат префикс с именем файла script, что упрощает определение того, какой script произвёл сообщение.
Следующие шаги
- Prop API -- полный справочник по
context.prop,context.event,context.world,context.zonesиcontext.scheduler - Примеры и шаблоны -- полностью рабочие scripts с разбором
- Устранение неполадок -- распространённые проблемы, советы по отладке и чек-лист QC
Если вы также пишете Lua-способности для EliteMobs, общие API (context.world, context.zones, context.scheduler, context.state, context.log) работают идентично. См. документацию Lua для EliteMobs для API, специфичных для боссов.