Lua-скрипты: API реквизита и предметов
На этой странице описаны все API, доступные скриптам реквизита и предметов FreeMinecraftModels: context.prop, context.item, context.event, context.player, context.world, context.zones, context.scheduler, context.state и context.log. Если вы только начинаете писать скрипты, сначала прочтите Начало работы.
context.prop
Таблица реквизита предоставляет информацию о сущности реквизита и методы управления её анимациями. Она пересобирается заново для каждого вызова хука.
Поля
| Поле | Тип | Заметки |
|---|---|---|
prop.model_id | string | Имя модели-шаблона (например, "torch_01") |
prop.current_location | таблица локации | Позиция реквизита на момент сборки контекста |
Таблица локации имеет стандартные поля: x, y, z, world, yaw, pitch.
Пример: чтение данных реквизита
return {
api_version = 1,
on_spawn = function(context)
context.log:info("Prop spawned: " .. (context.prop.model_id or "unknown"))
local loc = context.prop.current_location
if loc then
context.log:info("Location: " .. loc.x .. ", " .. loc.y .. ", " .. loc.z)
end
end
}
prop:play_animation(name, blend, loop)
Проигрывает названную анимацию на модели реквизита.
| Параметр | Тип | По умолчанию | Заметки |
|---|---|---|---|
name | string | обязательный | Имя анимации, заданное в файле модели |
blend | boolean | true | Смешивать ли с текущей анимацией |
loop | boolean | true | Зацикливать ли анимацию |
Возвращает true, если анимация найдена и запущена, иначе false.
Пример
return {
api_version = 1,
on_right_click = function(context)
local success = context.prop:play_animation("open", true, false)
if not success then
context.log:warn("Animation 'open' not found on this model!")
end
end
}
prop:stop_animation()
Останавливает все воспроизводимые в данный момент анимации на реквизите.
Параметров не принимает.
Пример
return {
api_version = 1,
on_right_click = function(context)
context.prop:stop_animation()
end
}
prop:hurt_visual()
Проигрывает визуальную анимацию урона (вспышка красным оттенком) на реквизите, не нанося ему реального урона.
Параметров не принимает.
Пример
return {
api_version = 1,
on_left_click = function(context)
-- Мигаем красным при ударе, но не получаем урон
if context.event then
context.event.cancel()
end
context.prop:hurt_visual()
end
}
prop:pickup()
Убирает реквизит из мира и роняет в его позиции бумажный предмет размещения. По дроп-предмету можно кликнуть правой кнопкой по блоку, чтобы снова разместить реквизит.
Параметров не принимает.
Пример
return {
api_version = 1,
on_right_click = function(context)
-- Позволяем игрокам подбирать реквизит правым кликом
context.prop:pickup()
end
}
prop:mount(player)
Сажает игрока на первое доступное сиденье в точке посадки реквизита. У модели должны быть определены кости точек посадки.
| Параметр | Тип | Заметки |
|---|---|---|
player | таблица сущности | Таблица сущности игрока (например, из context.event.player) |
Пример
return {
api_version = 1,
on_right_click = function(context)
local player = context.event and context.event.player
if player then
context.prop:mount(player)
end
end
}
prop:dismount(player)
Снимает игрока с его сиденья в точке посадки на реквизите.
| Параметр | Тип | Заметки |
|---|---|---|
player | таблица сущности | Таблица сущности игрока |
Пример
return {
api_version = 1,
on_right_click = function(context)
local player = context.event and context.event.player
if player then
-- Переключаем mount/dismount
local passengers = context.prop:get_passengers()
for i = 1, #passengers do
if passengers[i].uuid == player.uuid then
context.prop:dismount(player)
return
end
end
context.prop:mount(player)
end
end
}
prop:get_passengers()
Возвращает Lua-массив таблиц сущностей всех текущих пассажиров реквизита.
Параметров не принимает.
Пример
return {
api_version = 1,
on_game_tick = function(context)
local passengers = context.prop:get_passengers()
if #passengers > 0 then
context.log:info("Prop has " .. #passengers .. " passenger(s)")
end
end
}
prop:has_mount_points()
Возвращает, определены ли у этого реквизита кости точек посадки в его модели.
Параметров не принимает. Возвращает true или false.
Пример
return {
api_version = 1,
on_right_click = function(context)
local player = context.event and context.event.player
if player and context.prop:has_mount_points() then
context.prop:mount(player)
end
end
}
prop:spawn_elitemobs_boss(filename, x, y, z)
Спавнит пользовательского босса EliteMobs в указанной позиции. Требует, чтобы EliteMobs был установлен на сервере.
| Параметр | Тип | Заметки |
|---|---|---|
filename | string | Имя файла пользовательского босса (например, "my_boss.yml") |
x | number | Координата X |
y | number | Координата Y |
z | number | Координата Z |
Возвращает таблицу живой сущности для заспавненного босса или nil, если EliteMobs не установлен либо файл босса не существует.
Пример
return {
api_version = 1,
on_right_click = function(context)
local loc = context.prop.current_location
if loc then
local boss = context.prop:spawn_elitemobs_boss("dungeon_guardian.yml", loc.x, loc.y + 1, loc.z)
if boss then
context.log:info("Spawned boss: " .. (boss.name or "unknown"))
else
context.log:warn("Could not spawn boss -- is EliteMobs installed?")
end
end
end
}
prop:open_inventory(player, title, rows)
Открывает игроку постоянный GUI-инвентарь типа сундука. Содержимое сохраняется в PersistentDataContainer реквизита при закрытии инвентаря и восстанавливается при следующем открытии.
| Параметр | Тип | По умолчанию | Заметки |
|---|---|---|---|
player | таблица сущности | обязательный | Игрок, которому показать инвентарь |
title | string | обязательный | Заголовок инвентаря (поддерживает цветовые коды &) |
rows | int | 3 | Число рядов (1–6, где 6 = 54 слота = двойной сундук) |
Возвращает true, если инвентарь открылся, иначе false.
prop:is_viewing_inventory(player)
Возвращает, открыт ли у указанного игрока сейчас инвентарь этого реквизита.
| Параметр | Тип | Заметки |
|---|---|---|
player | таблица сущности | Игрок для проверки |
Возвращает true или false.
Пример: анимация закрытия при закрытии инвентаря
context.state["task_" .. player.uuid] = context.scheduler:run_repeating(5, 5, function(tick_context)
if not tick_context.prop:is_viewing_inventory(player) then
tick_context.prop:play_animation("close", true, false)
tick_context.scheduler:cancel(tick_context.state["task_" .. player.uuid])
end
end)
prop:place_book(player)
Забирает у игрока книгу для письма или подписанную книгу из основной руки и кладёт её на реквизит.
| Параметр | Тип | Заметки |
|---|---|---|
player | таблица сущности | Игрок, держащий книгу |
Возвращает true при успехе.
prop:read_book(player)
Открывает игроку сохранённую книгу для чтения.
| Параметр | Тип | Заметки |
|---|---|---|
player | таблица сущности | Игрок, которому показать книгу |
Возвращает true, если книга была открыта.
prop:take_book(player)
Возвращает сохранённую книгу в инвентарь игрока и удаляет её с реквизита.
| Параметр | Тип | Заметки |
|---|---|---|
player | таблица сущности | Игрок, которому выдать книгу |
Возвращает true при успехе.
prop:has_book()
Возвращает, хранится ли на этом реквизите книга. Параметров не принимает.
prop:drop_inventory()
Роняет всё сохранённое содержимое инвентаря в позиции реквизита в виде предметов-сущностей, затем очищает сохранённые данные. Автоматически закрывает инвентарь у всех игроков, которые его сейчас смотрят.
Параметров не принимает. Возвращает true при успехе.
prop:drop_book()
Роняет сохранённую книгу в позиции реквизита как предмет-сущность и очищает сохранённые данные книги.
Параметров не принимает. Возвращает true при успехе.
prop:set_persistent_data(key, value)
Сохраняет строковое значение в PersistentDataContainer армор-стенда реквизита. Эти данные переживают перезапуски сервера и выгрузки чанков.
| Параметр | Тип | Заметки |
|---|---|---|
key | string | Уникальное имя ключа (внутри хранится под fmm_lua_<key>) |
value | string | Значение для сохранения. Для чисел и булевых используйте tostring(). |
Возвращает true при успехе, false, если у реквизита нет базового армор-стенда.
prop:get_persistent_data(key)
Извлекает строковое значение, ранее сохранённое через set_persistent_data. Возвращает nil, если ключ не был установлен.
| Параметр | Тип | Заметки |
|---|---|---|
key | string | Имя ключа, использованное в set_persistent_data |
Пример: постоянное состояние переключателя
return {
api_version = 1,
on_spawn = function(context)
local saved = context.prop:get_persistent_data("active")
context.state.active = saved == "true"
end,
on_right_click = function(context)
context.state.active = not context.state.active
context.prop:set_persistent_data("active", tostring(context.state.active))
end
}
context.item
Таблица предмета доступна только в скриптах предметов (не в скриптах реквизита). Она предоставляет информацию о пользовательском предмете и методы для манипуляций с ним. Таблица пересобирается заново для каждого вызова хука.
Поля
| Поле | Тип | Заметки |
|---|---|---|
item.id | string | ID типа предмета (fmm_item_id из YML-конфига) |
item:material()
Возвращает имя материала предмета в виде строки (например, "DIAMOND_SWORD", "STICK").
item:get_amount() / item:set_amount(n)
Получает или задаёт размер стака предмета.
| Параметр | Тип | Заметки |
|---|---|---|
n | int | Новое количество в стаке |
item:consume(n)
Уменьшает количество в стаке на n (по умолчанию 1). Если итоговое количество 0 или меньше, предмет удаляется из инвентаря игрока.
| Параметр | Тип | По умолчанию | Заметки |
|---|---|---|---|
n | int | 1 | Сколько потреблять |
item:get_uses() / item:set_uses(n)
Получает или задаёт пользовательский счётчик использований, хранящийся в PersistentDataContainer предмета. Он не зависит от ванильной прочности и подходит для реализации собственной прочности или системы зарядов.
| Параметр | Тип | Заметки |
|---|---|---|
n | int | Новое число использований |
item:get_name() / item:set_name(s)
Получает или задаёт отображаемое имя предмета. Поддерживает цветовые коды через &.
| Параметр | Тип | Заметки |
|---|---|---|
s | string | Новое отображаемое имя (например, "&b&lFrost Sword") |
item:get_lore() / item:set_lore(table)
Получает или задаёт lore предмета. get_lore() возвращает таблицу строк (по одной на строку). set_lore() принимает таблицу строк.
| Параметр | Тип | Заметки |
|---|---|---|
table | table | Массив строк, по одной на строку lore |
Пример: скрипт предмета, отслеживающий использования
return {
api_version = 1,
on_right_click = function(context)
local uses = context.item:get_uses()
if uses <= 0 then
context.player:send_message("&cThis item is out of charges!")
return
end
context.item:set_uses(uses - 1)
context.player:send_message("&aUsed! Charges remaining: " .. (uses - 1))
end
}
item:get_durability()
Возвращает таблицу с полями current и max, представляющими ванильную прочность предмета, либо nil, если у предмета нет полосы прочности.
Пример
local dur = context.item:get_durability()
if dur then
context.player:send_message("Durability: " .. dur.current .. "/" .. dur.max)
end
item:get_durability_percentage()
Возвращает оставшуюся прочность как долю от 0.0 до 1.0 или nil, если у предмета нет полосы прочности.
item:use_durability(amount, can_break)
Уменьшает ванильную прочность предмета на фиксированную величину.
| Параметр | Тип | По умолчанию | Заметки |
|---|---|---|---|
amount | int | обязательный | Сколько единиц прочности потратить |
can_break | boolean | false | Если true, предмет уничтожается при обнулении прочности. Если false, прочность останавливается на 1. |
item:use_durability_percentage(fraction, can_break)
Уменьшает ванильную прочность предмета на долю от максимума.
| Параметр | Тип | По умолчанию | Заметки |
|---|---|---|---|
fraction | number | обязательный | Доля максимальной прочности для траты (например, 0.1 = 10%) |
can_break | boolean | false | Если true, предмет уничтожается при обнулении прочности. Если false, прочность останавливается на 1. |
context.event
Данные события для текущего хука. Доступны в хуках кликов, боя и взаимодействия для скриптов как реквизита, так и предметов. Возвращает nil в хуках без связанного события (on_spawn, on_game_tick, on_destroy, on_zone_enter, on_zone_leave, on_equip).
Поля и методы
| Поле или метод | Тип | Заметки |
|---|---|---|
event.player | таблица сущности игрока | Игрок, инициировавший событие. Доступен в on_left_click, on_right_click и on_projectile_hit (стрелявший, если это был игрок). См. Методы сущности игрока для всех полей и методов. |
event.is_cancelled | boolean | Отменено ли событие в данный момент |
event.cancel() | function | Отменяет событие (например, предотвращает урон или взаимодействие) |
event.uncancel() | function | Снимает отмену с ранее отменённого события |
Не все события можно отменить. Если базовое Bukkit-событие не реализует Cancellable, event.cancel() и event.uncancel() отсутствуют, а event.is_cancelled всегда будет false.
Пример: сделать реквизит неуязвимым
Пример
return {
api_version = 1,
on_left_click = function(context)
if context.event then
context.event.cancel()
end
end
}
Пример: проверка состояния отмены
Пример
return {
api_version = 1,
on_left_click = function(context)
if context.event and not context.event.is_cancelled then
context.event.cancel()
context.log:info("Damage cancelled!")
end
end
}
Внутри запланированных колбэков (scheduler:run_later, scheduler:run_repeating) context.event всегда nil. Изменение события возможно только во время самого хука события.
context.world
API мира общий для всех плагинов Nightbreak. Полную справку см. в context.world.
Реквизит FMM использует ту же таблицу мира MagmaCore, что и боссы EliteMobs. Все методы, описанные на общей странице (get_block_at, set_block_at, spawn_particle, play_sound, strike_lightning, get_time, set_time, get_nearby_entities, get_nearby_players, spawn_entity, get_highest_block_y, raycast, spawn_firework), доступны в FMM. См. MagmaCore world API для полных подробностей по world:raycast() (бросить луч и определить попадание по сущностям/блокам) и world:spawn_firework() (запуск ракет фейерверков с пользовательскими цветами и формами). EliteMobs расширяет таблицу мира дополнительными методами для спавна боссов, подкреплений и прочего — см. EliteMobs World & Environment.
Методы сущности игрока
Таблицы сущности игрока возвращаются из context.event.player, context.world:get_nearby_players() и колбэков зон.
Таблицы сущностей, методы живых сущностей, специфичные для игрока методы и методы Player UI общие для всех плагинов Nightbreak. См. MagmaCore Lua Scripting Engine для полной справки по базовым полям сущности, полям и методам живых сущностей, специфичным для игрока полям и методам и методам Player UI. Новые методы игрока включают player:get_target_entity() (наведение через raycast), player:get_eye_location(), player:get_look_direction(), player:send_block_change() (фейковые блоки для конкретного игрока) и player:reset_block() — подробности см. в Player-Specific Methods.
Поля сущностей, специфичные для FMM
Каждая таблица сущности, построенная внутри FMM-скрипта, автоматически получает эти дополнительные поля (через LuaEntityEnricher FMM):
| Поле | Тип | Заметки |
|---|---|---|
entity.is_modeled | boolean | true, если эта Bukkit-сущность является базовой сущностью какого-то ModeledEntity |
entity.is_prop | boolean | true, если эта сущность — армор-стенд, лежащий в основе PropEntity |
entity.model | таблица или nil | Заполнено только когда is_modeled = true (см. ниже) |
Когда entity.model присутствует, оно раскрывает:
| Поле / метод | Заметки |
|---|---|
model.model_id | Имя модели-шаблона (например, "dragon") |
model.is_dynamic | true, если это DynamicEntity (привязанный к живой сущности) |
model:play_animation(name, blend, loop) | Проигрывает названную анимацию. Возвращает true при успехе |
model:stop_animations() | Останавливает все текущие анимации |
model:remove() | Немедленно удаляет моделированную сущность и все её кости |
on_attack_entity = function(context)
local target = context.event.target
if target and target.is_modeled then
target.model:play_animation("hurt", true, false)
end
end
Поля сущностей EliteMobs
Когда установлен EliteMobs, FMM пробрасывает вызов к enricher-у EliteMobs, поэтому те же таблицы сущностей дополнительно раскрывают:
| Поле | Тип | Заметки |
|---|---|---|
entity.is_elite | boolean | true, если сущность отслеживается EliteMobs |
entity.is_custom_boss | boolean | true, если это конфигурация пользовательского босса |
entity.is_significant_boss | boolean | true для пользовательских боссов с healthMultiplier > 1 (отсеивает «мусорных» именованных мобов) |
entity.elite | таблица или nil | Заполнено только когда is_elite = true. Содержит level, name, health, max_health, health_multiplier, damage_multiplier, is_custom_boss, плюс elite:remove() |
context.zones
API зон общий для всех плагинов Nightbreak. Полную справку см. в context.zones.
context.scheduler
API планировщика общий для всех плагинов Nightbreak. Полную справку см. в context.scheduler.
context.state
API состояния общий для всех плагинов Nightbreak. Полную справку см. в context.state.
context.log
API логирования общий для всех плагинов Nightbreak. Полную справку см. в context.log.
Модель времени выполнения
Один runtime на один экземпляр скрипта
Каждая сущность реквизита с прицепленными скриптами получает собственный независимый экземпляр runtime Lua. Когда реквизит спавнится, FMM загружает исходник Lua, выполняет его в свежей песочнице и сохраняет возвращённую таблицу. Когда реквизит удаляется, runtime завершается.
Для скриптов предметов один runtime создаётся на пару (игрок, itemId). Когда игрок экипирует пользовательский предмет, FMM создаёт экземпляр скрипта для этого игрока и типа предмета. Когда предмет снимают, runtime завершается.
Это значит:
- Локальные переменные, объявленные на уровне файла, приватны для данного экземпляра скрипта.
context.stateполностью изолирован между экземплярами, даже если они используют один и тот же файл скрипта.
Владение запланированными задачами
Все задачи, созданные через context.scheduler, принадлежат runtime, который их создал. Когда реквизит удаляется:
- Runtime завершается.
- Все принадлежащие ему задачи — одноразовые и повторяющиеся — автоматически отменяются.
- Все наблюдения за зонами сбрасываются.
Область видимости cooldown-ов
Общий движок скриптов предоставляет context.cooldowns:set_local, :check_local, :set_global и :check_global (см. справку по cooldown-ам MagmaCore). FMM ограничивает их области так:
| Тип скрипта | Область локального хранилища | Область глобального хранилища |
|---|---|---|
| Скрипт реквизита | На ScriptInstance (реквизит + файл скрипта) | На PropEntity (общее для всех скриптов, прицепленных к этому реквизиту) |
| Скрипт предмета | На тройку (player, itemId, scriptFile) — сохраняется между переэкипировками, хотя экземпляр скрипта разрушается каждый раз при выходе предмета из активного слота | На игрока (общее для всех FMM-скриптов предметов, которые запускает этот игрок) |
Поскольку скрипты предметов разрушаются и пересобираются на каждом цикле equip/unequip, cooldown-ы предметов хранятся в статической мапе по UUID игрока, а не на ScriptInstance. Именно поэтому cooldown предмета продолжает действовать, даже если вы поменяли предмет местами в хотбаре и вернули обратно.
Бюджет выполнения
Каждый вызов хука и каждый вызов колбэка хронометрируется. Если один вызов занимает больше 50 миллисекунд, скрипт отключается с предупреждением в консоли:
[Lua] my_script.lua took 73ms in 'on_game_tick' (limit: 50ms) -- script disabled to prevent lag.
Чтобы укладываться в бюджет:
- Избегайте безграничных циклов внутри хуков.
- Держите обработчики
on_game_tickлёгкими — они выполняются каждый тик. - Используйте
context.scheduler:run_repeating(...), чтобы размазать работу по тикам.
Полная справка по хукам
В этой таблице перечислены все хуки, доступные в скриптах реквизита и предметов.
Хуки реквизита (8)
| Хук | Когда срабатывает | context.event |
|---|---|---|
on_spawn | Реквизит появляется в мире | nil |
on_game_tick | Каждый серверный тик (50 мс) | nil |
on_destroy | Реквизит удалён | nil |
on_left_click | Игрок кликает по реквизиту левой кнопкой | событие урона |
on_right_click | Игрок кликает по реквизиту правой кнопкой | событие взаимодействия |
on_projectile_hit | Снаряд попадает в реквизит | событие попадания снаряда |
on_zone_enter | Игрок входит в наблюдаемую зону | nil |
on_zone_leave | Игрок покидает наблюдаемую зону | nil |
Хуки предметов (22)
| Хук | Категория | Когда срабатывает | context.event |
|---|---|---|---|
on_attack_entity | Бой | Игрок атакует сущность | событие урона |
on_kill_entity | Бой | Игрок убивает сущность | событие смерти |
on_take_damage | Бой | Игрок получает урон | событие урона |
on_shield_block | Бой | Игрок блокирует щитом | событие урона |
on_shoot_bow | Бой | Игрок стреляет из лука | событие выстрела из лука |
on_projectile_hit | Бой | Снаряд игрока попадает | событие попадания снаряда |
on_projectile_launch | Бой | Игрок выпускает снаряд | событие запуска |
on_right_click | Взаимодействие | Игрок кликает правой кнопкой | событие interact |
on_left_click | Взаимодействие | Игрок кликает левой кнопкой | событие interact |
on_shift_right_click | Взаимодействие | Игрок делает shift+правый клик | событие interact |
on_shift_left_click | Взаимодействие | Игрок делает shift+левый клик | событие interact |
on_interact_entity | Взаимодействие | Игрок кликает правой по сущности | событие entity interact |
on_equip | Экипировка | Предмет попадает в активный слот | nil |
on_unequip | Экипировка | Предмет покидает активный слот | nil |
on_swap_hands | Экипировка | Меняет основную/off-руку | событие swap |
on_drop | Экипировка | Игрок выбрасывает предмет | событие drop |
on_break_block | Утилиты | Игрок ломает блок | событие block break |
on_consume | Утилиты | Игрок употребляет предмет | событие consume |
on_item_damage | Утилиты | Предмет теряет прочность | событие item damage |
on_fish | Утилиты | Игрок использует удочку | событие fish |
on_death | Утилиты | Игрок умирает с экипированным предметом | событие смерти |
on_game_tick | Жизненный цикл | Каждый тик, пока предмет экипирован | nil |
Дальнейшие шаги
- Примеры и шаблоны -- полностью рабочие скрипты для реквизита и предметов с пояснениями
- Решение проблем -- частые проблемы, советы по отладке и чек-лист QC
- Начало работы -- структура файлов, хуки, разбор первого скрипта