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

Lua Scripting: Начало работы

Эта страница научит вас писать ваш первый Lua script для prop в FreeMinecraftModels -- от пустого файла до работающего интерактивного prop. К концу вы поймёте hooks, context, Prop API и общую структуру каждого файла script для prop.

Освоив основы, переходите к сопутствующим страницам:

Экспериментальная функция

Lua script для prop в настоящее время являются экспериментальными. Названия hook, вспомогательные методы и поведение могут изменяться по мере развития FreeMinecraftModels, поэтому тщательно тестируйте их перед использованием на рабочем сервере.

Связь с EliteMobs Lua

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
ПолеТипПо умолчаниюПримечания
isEnabledbooleantrueАктивны ли scripts для данного prop
scriptsсписок строк[]Имена файлов .lua в папке scripts/

К одному prop можно прикрепить несколько scripts. Каждый script является отдельным независимым экземпляром.

Отложенная генерация config

Когда prop появляется и связанный файл .yml не существует, FMM автоматически создаёт файл config по умолчанию с isEnabled: true и пустым списком scripts:. Это происходит асинхронно, поэтому при первом появлении у prop не будет scripts -- только после создания config и добавления имён файлов script.

Это означает:

  1. Поместите файл модели в models/
  2. Создайте prop один раз (FMM автоматически создаст .yml)
  3. Отредактируйте сгенерированный .yml, добавив имена файлов script
  4. Создайте prop повторно или перезагрузите сервер (scripts теперь активны)

Справочник hooks

Каждый файл Lua script для prop возвращает таблицу. Каждый ключ в этой таблице (кроме api_version и priority) должен быть одним из перечисленных ниже hooks. Среда выполнения вызывает соответствующую функцию каждый раз, когда срабатывает связанное игровое событие.

HookСрабатывает, когдаПримечания
on_spawnProp появляется в миреВыполняется один раз при привязке script
on_game_tickОдин раз за серверный тик (50 мс)Активен только если script определяет этот hook
on_destroyProp удаляется из мираHook очистки
on_left_clickИгрок кликает левой кнопкой (бьёт) propcontext.event -- событие урона
on_right_clickИгрок кликает правой кнопкой по propcontext.event -- событие взаимодействия
on_projectile_hitСнаряд попадает в propcontext.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

  1. Поместите файл модели (например, my_prop.fmmodel) в plugins/FreeMinecraftModels/models/
  2. Создайте prop один раз для генерации config .yml
  3. Создайте файл script в plugins/FreeMinecraftModels/scripts/first_test.lua
  4. Отредактируйте plugins/FreeMinecraftModels/models/my_prop.yml:
isEnabled: true
scripts:
- first_test.lua
  1. Создайте 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 используйте следующий порядок:

  1. Создайте файл .lua и добейтесь работы on_spawn.
  2. Добавьте имя файла script в config .yml prop.
  3. Переключитесь на нужный hook (например, on_right_click).
  4. Сначала добавьте сообщение в лог, до анимаций или эффектов.
  5. Добавьте один реальный эффект (анимацию, звук, частицы).
  6. Только после этого добавляйте вспомогательные функции, 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 произвёл сообщение.


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

Если вы также пишете Lua-способности для EliteMobs, общие API (context.world, context.zones, context.scheduler, context.state, context.log) работают идентично. См. документацию Lua для EliteMobs для API, специфичных для боссов.