Lua-скриптинг: Начало работы
Эта страница научит вас написать первый Lua-скрипт для пропса FreeMinecraftModels — от пустого файла до работающего интерактивного пропса. К концу вы поймёте хуки, context, API пропсов и общую структуру каждого файла скрипта пропса.
Когда освоите основы, переходите к сопутствующим страницам:
- Prop API — API
context.prop,context.event,context.worldи другие - Примеры и паттерны — полные рабочие скрипты для изучения и адаптации
- Устранение неполадок — типичные ошибки, советы по отладке и чеклист контроля качества
Lua-скрипты пропсов в настоящее время являются экспериментальными. Имена хуков, вспомогательные методы и поведение ещё могут измениться по мере развития FreeMinecraftModels, поэтому тщательно тестируйте перед использованием на продакшн-сервере.
FreeMinecraftModels использует тот же Lua-движок (Magmacore), что и EliteMobs. Если вы уже пишете Lua-способности для EliteMobs, основные концепции — хуки, context, api_version, планировщик, зоны и песочница — идентичны. Разница в следующем:
- Скрипты EliteMobs работают на боссах и имеют хуки вроде
on_boss_damaged_by_player,on_enter_combatи т.д. - Скрипты FMM работают на пропсах и имеют хуки вроде
on_right_click,on_left_click,on_projectile_hitи т.д.
API context.world, context.zones, context.scheduler, context.state и context.log одинаковы в обоих плагинах. Эта страница охватывает только то, что специфично для пропсов FMM.
Что такое скрипты пропсов
Скрипты пропсов — это отдельные файлы .lua, которые находятся в папке plugins/FreeMinecraftModels/scripts/. Они указываются в YAML-конфиге, расположенном рядом с файлом модели, и запускаются при каждом спавне пропса в мире.
Для чего хороши скрипты пропсов
Скрипты пропсов отлично подходят, когда вам нужны:
- Интерактивные пропсы, реагирующие на клики игроков (двери, рычаги, кнопки)
- Неуязвимые декоративные пропсы, которые не могут быть сломаны игроками
- Триггеры приближения, определяющие, когда игроки входят или покидают область
- Анимированные пропсы, воспроизводящие анимации при взаимодействии или по таймеру
- Звуковые пропсы, воспроизводящие звуки при клике или приближении
- Любое поведение пропса, требующее логики помимо статичного украшения
Если ваш пропс чисто декоративный и не требует взаимодействия, скрипт вам не нужен.
Для кого эта страница
Эта страница написана для трёх категорий читателей:
- Тех, кто уже знает Lua-скриптинг EliteMobs и хочет изучить хуки и API, специфичные для FMM
- Тех, кто новичок в Lua-скриптинге и нуждается в полном, точном справочнике имён для пропсов
- Тех, кто использует ИИ для создания скриптов пропсов и нуждается в достаточных деталях, чтобы понять, когда ИИ придумал что-то несуществующее
Вам не нужно становиться полноценным Lua-разработчиком, чтобы писать полезные скрипты пропсов. Для большинства практических скриптов вам действительно нужно только:
- Как разместить валидный хук в возвращаемой таблице
- Как читать значения из
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 означает «нет значения». Вы будете часто проверять на nil:
if context.event ~= nil then
context.event.cancel()
end
Таблицы
Lua использует таблицы для объектов с именованными ключами и для возвращаемого определения скрипта:
return {
api_version = 1,
on_spawn = function(context)
end
}
Комментарии
Используйте -- для заметок:
-- Отменяем событие урона, чтобы пропс нельзя было сломать
context.event.cancel()
Для более подробного введения в Lua см. страницу Начало работы с EliteMobs. Основы синтаксиса идентичны.
Расположение файлов
Файлы скриптов
Размещайте файлы .lua в центральной папке скриптов:
plugins/
FreeMinecraftModels/
scripts/
invulnerable.lua
interactive_door.lua
proximity_sound.lua
FMM обнаруживает все файлы .lua в plugins/FreeMinecraftModels/scripts/ при запуске.
Файлы моделей и конфигурации
Каждый файл модели может иметь соседний файл конфигурации .yml в той же директории:
plugins/
FreeMinecraftModels/
models/
torch_01.fmmodel
torch_01.yml <-- конфиг скрипта для torch_01
scripts/
invulnerable.lua <-- указан в torch_01.yml
Файл .yml — это то, что связывает модель с её скриптами.
Формат файла конфигурации
YAML-файл конфигурации, расположенный рядом с файлом модели, имеет два поля:
isEnabled: true
scripts:
- invulnerable.lua
| Поле | Тип | По умолчанию | Примечания |
|---|---|---|---|
isEnabled | boolean | true | Активны ли скрипты для этого пропса |
scripts | список строк | [] | Имена файлов .lua скриптов в папке scripts/ |
Вы можете привязать несколько скриптов к одному пропсу. Каждый скрипт является независимым экземпляром.
Ленивая генерация конфигурации
Когда пропс спавнится и не существует соседнего файла .yml, FMM автоматически создаёт файл конфигурации по умолчанию с isEnabled: true и пустым списком scripts:. Это происходит асинхронно, поэтому при первом спавне у пропса не будет скриптов — только после создания конфига и добавления имён файлов скриптов.
Это означает:
- Поместите файл модели в
models/ - Заспавните пропс один раз (FMM создаст
.ymlавтоматически) - Отредактируйте сгенерированный
.yml, чтобы добавить имена файлов скриптов - Переспавните пропс или перезагрузите (скрипты теперь активны)
Справочник хуков
Каждый файл Lua-скрипта пропса возвращает таблицу. Каждый ключ в этой таблице (кроме api_version и priority) должен быть одним из хуков, перечисленных ниже. Среда выполнения вызывает соответствующую функцию всякий раз, когда происходит соответствующее игровое событие.
| Хук | Срабатывает когда | Примечания |
|---|---|---|
on_spawn | Пропс появляется в мире | Выполняется один раз при привязке скрипта |
on_game_tick | Каждый серверный тик (50 мс) | Активен только если скрипт определяет этот хук |
on_destroy | Пропс удаляется из мира | Хук очистки |
on_left_click | Игрок кликает левой кнопкой (бьёт) по пропсу | context.event — событие урона |
on_right_click | Игрок кликает правой кнопкой по пропсу | context.event — событие взаимодействия |
on_projectile_hit | Снаряд попадает в пропс | context.event — событие попадания снаряда |
on_zone_enter | Игрок входит в наблюдаемую зону | Требует настроенного наблюдения за зоной |
on_zone_leave | Игрок покидает наблюдаемую зону | Требует настроенного наблюдения за зоной |
Минимальный контракт файла
Каждый Lua-скрипт пропса должен возвращать (return) таблицу.
Обязательные и необязательные поля верхнего уровня
| Поле | Обязательно | Тип | Примечания |
|---|---|---|---|
api_version | Да | Number | В настоящее время должно быть 1 |
priority | Нет | Number | Приоритет выполнения. Меньшие значения выполняются первыми. По умолчанию 0 |
| поддерживаемые ключи хуков | Нет | Function | Должны использовать одно из точных имён хуков из справочника |
Правила валидации
- Файл должен возвращать таблицу.
api_versionобязателен и в настоящее время должен быть1.priorityдолжен быть числом, если указан.- Каждый дополнительный ключ верхнего уровня должен быть поддерживаемым именем хука.
- Каждый ключ хука должен указывать на функцию.
- Неизвестные ключи верхнего уровня отклоняются.
Вспомогательные функции и локальные константы должны располагаться над финальным return, а не внутри возвращаемой таблицы.
Ваш первый рабочий скрипт пропса, пошагово
Перед шагом 1: Настройка конфигурации
- Поместите файл модели (например,
my_prop.fmmodel) вplugins/FreeMinecraftModels/models/ - Заспавните пропс один раз для генерации конфига
.yml - Создайте файл скрипта в
plugins/FreeMinecraftModels/scripts/first_test.lua - Отредактируйте
plugins/FreeMinecraftModels/models/my_prop.yml:
isEnabled: true
scripts:
- first_test.lua
- Переспавните пропс или перезагрузите сервер
Шаг 1: Загрузка файла
return {
api_version = 1,
on_spawn = function(context)
end
}
Если это загружается без ошибок в консоли, вы подтвердили:
- Файл является валидным Lua
- FMM нашёл его в папке
scripts/ - Конфиг правильно на него ссылается
- Структура возвращаемой таблицы корректна
Шаг 2: Пропс делает что-то видимое
return {
api_version = 1,
on_spawn = function(context)
context.log:info("Prop script loaded for: " .. (context.prop.model_id or "unknown"))
end
}
Проверьте консоль сервера. Если вы видите сообщение в логе, ваш хук работает.
Шаг 3: Реакция на клик игрока
return {
api_version = 1,
on_right_click = function(context)
context.log:info("Prop was right-clicked!")
end
}
Кликните правой кнопкой по пропсу в игре. Если консоль показывает сообщение, хук клика работает.
Шаг 4: Отмена урона для неуязвимости пропса
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
Это паттерн, используемый готовым скриптом invulnerable.lua. Он отменяет событие урона, чтобы стойку для брони, лежащую в основе пропса, нельзя было уничтожить.
Шаг 5: Воспроизведение анимации по клику
return {
api_version = 1,
on_right_click = function(context)
context.prop:play_animation("open", true, false)
end
}
Это воспроизводит анимацию «open» на модели пропса, с плавным переходом и без зацикливания.
Что такое context?
Каждая функция хука получает один аргумент, называемый context. Думайте о нём как о наборе инструментов, который FMM передаёт вам каждый раз, когда что-то происходит — он содержит всё необходимое для взаимодействия с пропсом, миром, зонами и многим другим.
on_right_click = function(context)
-- context.prop = пропс, по которому кликнули
-- context.event = событие клика (можно отменить)
-- context.world = инструменты для частиц, звуков, запросов блоков
-- context.state = ваше собственное постоянное хранилище
-- context.log = логирование в консоль
-- context.scheduler = отложенные и повторяющиеся задачи
-- context.zones = создание и наблюдение пространственных зон
end
Вы не создаёте context сами — FMM создаёт его и передаёт в ваш хук.
context создаётся заново для каждого вызова хука, за исключением context.state, который сохраняется на протяжении всего времени жизни пропса. Это означает, что вы можете хранить данные в context.state и считывать их позже в другом хуке.
Ключевые API context
Вот краткое описание доступного. Подробности см. в Prop API.
-
context.prop— Сущность пропса. Предоставляетmodel_id,current_location,play_animation()иstop_animation(). -
context.event— Событие Bukkit, вызвавшее этот хук. Доступен вon_left_click,on_right_clickиon_projectile_hit. Предоставляетcancel(),uncancel()иis_cancelled. Равенnilв хуках без события (например,on_spawnиon_game_tick). -
context.state— Обычная Lua-таблица, которая сохраняется на протяжении жизни пропса. Используйте для хранения флагов, состояний переключения, идентификаторов задач и всего, что нужно запоминать между хуками. -
context.log— Логирование в консоль сlog:info(msg),log:warn(msg)иlog:error(msg). -
context.scheduler— Отложенные и повторяющиеся задачи сscheduler:run_later(ticks, callback)иscheduler:run_repeating(delay, interval, callback). Обратные вызовы получают новый context. Отмена задач черезscheduler:cancel(taskId). -
context.world— Взаимодействие с миром: частицы, звуки, запросы блоков, молнии, ближайшие сущности. Полный список методов см. в Prop API. -
context.zones— Создание и наблюдение пространственных зон (сферы, цилиндры, кубоиды). Полный список методов см. в Prop API.
Синтаксис методов: : и .
В Lua object:method(arg) — это сокращение для object.method(object, arg). API FMM принимает обе формы:
context.log:info("hello")
context.log.info("hello") -- то же самое
Вся документация последовательно использует :.
Готовые шаблоны для копирования
Минимальный валидный скрипт пропса
return {
api_version = 1,
on_spawn = function(context)
end
}
Шаблон неуязвимого пропса
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
Шаблон интерактивного пропса
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
}
Первый реальный рабочий процесс
При создании совершенно нового скрипта пропса используйте этот порядок:
- Создайте файл
.luaи заставьтеon_spawnработать. - Добавьте имя файла скрипта в конфиг
.ymlпропса. - Переключитесь на нужный хук (например,
on_right_click). - Сначала добавьте сообщение в лог, до анимаций и эффектов.
- Добавьте один реальный эффект (анимацию, звук, частицы).
- Только после этого добавляйте вспомогательные функции, состояние, логику планировщика или зоны.
Такой порядок значительно упрощает отладку, потому что меняется только одна вещь за раз.
Готовые скрипты
FMM поставляется с двумя готовыми Lua-скриптами:
invulnerable.lua— Отменяет события урона при левом клике, делая пропс неразрушимым. Это простейший полезный скрипт пропса.pickupable.lua— Позволяет игрокам подбирать пропс, ударив его три раза. Каждый удар воспроизводит анимацию повреждения на пропсе, а при третьем ударе пропс удаляется и выбрасывает свой предмет размещения для сбора игроком.
Больше примеров можно найти на странице Примеры и паттерны.
Песочница Lua
Скрипты пропсов работают в той же песочнице LuaJ, что и EliteMobs. Ограничения песочницы идентичны. Полный список удалённых глобальных переменных и доступных функций стандартной библиотеки см. на странице Хуки и жизненный цикл EliteMobs.
Вкратце:
- Удалены:
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) для вывода. Сообщения логов имеют префикс с именем файла скрипта, что облегчает определение того, какой скрипт произвёл сообщение.
Следующие шаги
- Prop API — полный справочник
context.prop,context.event,context.world,context.zonesиcontext.scheduler - Примеры и паттерны — полные рабочие скрипты с разбором
- Устранение неполадок — типичные проблемы, советы по отладке и чеклист контроля качества
Если вы также пишете Lua-способности для EliteMobs, общие API (context.world, context.zones, context.scheduler, context.state, context.log) работают идентично. См. документацию Lua для EliteMobs для API, специфичных для боссов.