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

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_idstringИмя модели-шаблона (например, "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)

Проигрывает названную анимацию на модели реквизита.

ПараметрТипПо умолчаниюЗаметки
namestringобязательныйИмя анимации, заданное в файле модели
blendbooleantrueСмешивать ли с текущей анимацией
loopbooleantrueЗацикливать ли анимацию

Возвращает 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.player или context.event.player)

Возвращает true, когда игрок был найден, у реквизита есть точки посадки и действие посадки поставлено в очередь. Возвращает false, когда эти базовые ссылки невалидны. Возврат true не доказывает, что сиденье в итоге оказалось свободным на момент выполнения поставленного в очередь действия.

Пример
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таблица сущностиТаблица сущности игрока

Возвращает true, когда игрок был найден, у реквизита есть менеджер посадки и проверка высадки поставлена в очередь. Возвращает false, когда эти базовые ссылки невалидны.

Пример
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 был установлен на сервере.

ПараметрТипЗаметки
filenamestringИмя файла пользовательского босса (например, "my_boss.yml")
xnumberКоордината X
ynumberКоордината Y
znumberКоордината 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таблица сущностиобязательныйИгрок, которому показать инвентарь
titlestringобязательныйЗаголовок инвентаря (поддерживает цветовые коды &)
rowsint3Число рядов (1–6, где 6 = 54 слота = двойной сундук)

Возвращает true, если ссылки на реквизит/игрока были валидны и действие открытия поставлено в очередь, иначе false. Число рядов ограничивается диапазоном 1–6 перед созданием инвентаря.


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 армор-стенда реквизита. Эти данные переживают перезапуски сервера и выгрузки чанков.

ПараметрТипЗаметки
keystringУникальное имя ключа (внутри хранится под fmm_lua_<key>)
valuestringЗначение для сохранения. Для чисел и булевых используйте tostring().

Возвращает true при успехе, false, если у реквизита нет базового армор-стенда.


prop:get_persistent_data(key)

Извлекает строковое значение, ранее сохранённое через set_persistent_data. Возвращает nil, если ключ не был установлен.

ПараметрТипЗаметки
keystringИмя ключа, использованное в 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.idstringID типа предмета (fmm_item_id из YML-конфига)

item:material()

Возвращает имя материала предмета в виде строки (например, "DIAMOND_SWORD", "STICK").


item:get_amount() / item:set_amount(n)

Получает или задаёт размер стака предмета.

ПараметрТипЗаметки
nintНовое количество в стаке

item:consume(n)

Уменьшает количество в стаке на n (по умолчанию 1). Если итоговое количество 0 или меньше, предмет удаляется из инвентаря игрока.

ПараметрТипПо умолчаниюЗаметки
nint1Сколько потреблять

item:get_uses() / item:set_uses(n)

Получает или задаёт пользовательский счётчик использований, хранящийся в PersistentDataContainer предмета. Он не зависит от ванильной прочности и подходит для реализации собственной прочности или системы зарядов.

ПараметрТипЗаметки
nintНовое число использований

item:get_name() / item:set_name(s)

Получает или задаёт отображаемое имя предмета. Поддерживает цветовые коды через &.

ПараметрТипЗаметки
sstringНовое отображаемое имя (например, "&b&lFrost Sword")

item:get_lore() / item:set_lore(table)

Получает или задаёт lore предмета. get_lore() возвращает таблицу строк (по одной на строку). set_lore() принимает таблицу строк.

ПараметрТипЗаметки
tabletableМассив строк, по одной на строку 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)

Уменьшает ванильную прочность предмета на фиксированную величину.

ПараметрТипПо умолчаниюЗаметки
amountintобязательныйСколько единиц прочности потратить
can_breakbooleanfalseЕсли true, предмет уничтожается при обнулении прочности. Если false, прочность останавливается на 1.

item:use_durability_percentage(fraction, can_break)

Уменьшает ванильную прочность предмета на долю от максимума.

ПараметрТипПо умолчаниюЗаметки
fractionnumberобязательныйДоля максимальной прочности для траты (например, 0.1 = 10%)
can_breakbooleanfalseЕсли true, предмет уничтожается при обнулении прочности. Если false, прочность останавливается на 1.

context.event

Данные события для текущего хука. Доступны в хуках кликов, боя, взаимодействия и в общих хуках зон для скриптов как реквизита, так и предметов. Возвращает nil в хуках без связанного события или игрока-актора (on_spawn, on_game_tick, on_destroy, on_equip).

В таблицах справочника хуков ниже указан базовый тип Bukkit-события для ориентира. Lua-обёртка по-прежнему предоставляет только перечисленные здесь поля и методы.

Поля и методы

Поле или методТипЗаметки
event.playerтаблица сущности игрокаИгрок, инициировавший событие или пересёкший границу наблюдаемой общей зоны. Доступен в хуках реквизита on_left_click, on_right_click, on_zone_enter и on_zone_leave, а также в хуках предметов, вызванных игроком. См. Методы сущности игрока для всех полей и методов.
event.is_cancelledbooleanСостояние отмены на момент построения контекста. Это поле не обновляется после вызова cancel() или uncancel().
event.cancel()functionОтменяет событие (например, предотвращает урон или взаимодействие)
event.uncancel()functionСнимает отмену с ранее отменённого события
Точка или двоеточие — работает и то, и другое

cancel и uncancel игнорируют то, что им передаётся, поэтому context.event.cancel() и context.event:cancel() ведут себя одинаково. Готовые скрипты, поставляемые с FMM, используют форму с двоеточием; на этой странице используется форма с точкой. Ни одна из них не «правильнее».

к сведению

Не все события можно отменить. Если базовое Bukkit-событие не реализует Cancellable либо если хук — это общий хук зоны без Bukkit-события за ним, event.cancel() и event.uncancel() отсутствуют, а event.is_cancelled всегда будет false.

Считайте event.is_cancelled снимком начального состояния. Если ваш скрипт сам вызывает event.cancel() или event.uncancel(), храните собственный локальный флаг, если вам нужно помнить это изменение далее в том же хуке.

Текущая таблица события FMM не предоставляет специфичных для Bukkit полей вроде target, block, projectile или item. Используйте context.player, context.event.player, player:get_target_entity(range), context.world:raycast(...) или запросы ближайших сущностей, когда вам нужен дополнительный контекст.

Пример: сделать реквизит неуязвимым

Пример
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 мира FreeMinecraftModels/MagmaCore. Полную справку см. в context.world.

к сведению

Все методы, описанные на общей странице (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, place_temporary_block, drop_item, spawn_firework), доступны в FMM. См. MagmaCore world API для полных подробностей по world:raycast() (бросить луч и определить попадание по сущностям/блокам), world:place_temporary_block() (временная подмена блока) и world:spawn_firework() (запуск ракет фейерверков с пользовательскими цветами и формами). Силы боссов EliteMobs исходят из той же базовой таблицы мира и добавляют специфичные для боссов методы таблицы локаций для спавна боссов, подкреплений, падающих блоков, временных блоков и прочего — см. EliteMobs World & Environment.

Дополнения к миру, специфичные для FMM

FreeMinecraftModels добавляет поверх context.world три опциональных помощника лута EliteMobs. Они присутствуют всегда, но каждый возвращает false и ничего не делает, когда EliteMobs не установлен:

МетодЗаметки
world:drop_elitemobs_procedural_loot(player, level, location?)Выбрасывает один процедурно сгенерированный предмет EliteMobs для игрока. Возвращает false, когда выпадение процедурных предметов отключено
world:drop_elitemobs_random_loot(player, level, location?)Прокидывает таблицы лута EliteMobs для игрока на заданном уровне
world:drop_elitemobs_custom_loot(player, file, level, location?)Выбрасывает конкретный файл пользовательского предмета EliteMobs для игрока. Возвращает false, когда файл не разрешается

Полные сигнатуры находятся в Справочнике Lua API. Эквивалент со стороны реквизита для боссов — prop:spawn_elitemobs_boss(...), описанный выше.


Методы сущности игрока

Таблицы сущности игрока возвращаются из context.player, context.event.player и context.world:get_nearby_players(). Общие хуки MagmaCore on_zone_enter / on_zone_leave задают context.player и context.event.player как входящего или выходящего игрока.

Таблицы сущностей MagmaCore

Таблицы сущностей, методы живых сущностей, специфичные для игрока методы и методы Player UI, описанные на общей странице, — это таблицы MagmaCore, используемые FMM. Силы боссов EliteMobs предоставляют похожие, но специфичные для боссов таблицы сущностей, описанные в Boss & Entities. См. Движок Lua-скриптов MagmaCore для полной справки по FMM, охватывающей базовые поля сущности, поля и методы живых сущностей, специфичные для игрока поля и методы, а также методы 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_modeledbooleantrue, если эта Bukkit-сущность является базовой сущностью какого-то ModeledEntity
entity.is_propbooleantrue, если эта сущность — армор-стенд, лежащий в основе PropEntity
entity.modelтаблица или nilЗаполнено только когда is_modeled = true (см. ниже)

Когда entity.model присутствует, оно раскрывает:

Поле / методЗаметки
model.model_idИмя модели-шаблона (например, "dragon")
model.is_dynamictrue, если это DynamicEntity (привязанный к живой сущности)
model:play_animation(name, blend, loop)Проигрывает названную анимацию. В мосте модели сущности blend и loop по умолчанию равны false. Возвращает true при успехе
model:stop_animations()Останавливает все текущие анимации
model:remove()Немедленно удаляет моделированную сущность и все её кости
on_right_click = function(context)
local player = context.event and context.event.player
if not player then return end

local target = player:get_target_entity(8)
if target and target.is_modeled then
target.model:play_animation("hurt", true, false)
end
end

Поля сущностей EliteMobs

Когда установлен EliteMobs, FMM пробрасывает вызов к enricher-у EliteMobs, поэтому те же таблицы сущностей дополнительно раскрывают:

ПолеТипЗаметки
entity.is_elitebooleantrue, если сущность отслеживается EliteMobs
entity.is_custom_bossbooleantrue, если это конфигурация пользовательского босса
entity.is_significant_bossbooleantrue для пользовательских боссов с 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 зон FreeMinecraftModels/MagmaCore. Полную справку см. в context.zones. Силы боссов EliteMobs используют другую таблицу context.zones с нативными определениями зон EliteMobs — см. EliteMobs Zones & Targeting.


context.scheduler

Описанный здесь API планировщика — это планировщик MagmaCore, используемый скриптами FreeMinecraftModels и скриптами NPC EliteMobs. Имена в стиле EliteMobs (run_after, run_every и cancel_task) являются псевдонимами в общем планировщике, поэтому работает любой стиль наименования. Силы боссов предоставляют те же псевдонимы через свой специфичный для боссов контекст. Полную справку по FMM см. в context.scheduler.


context.state

API состояния является общим для скриптов FreeMinecraftModels, сил боссов EliteMobs и скриптов NPC EliteMobs. Полную справку см. в context.state.


context.log

Описанный здесь API логирования — это логгер FreeMinecraftModels/MagmaCore (info, warn, error). Скрипты NPC EliteMobs используют тот же логгер; силы боссов EliteMobs предоставляют info, warn и debug. Полную справку см. в context.log.


context.cooldowns

Описанный здесь API перезарядок — это общий порядок аргументов MagmaCore/FMM, используемый скриптами FreeMinecraftModels и скриптами NPC EliteMobs: check_local(key?, duration). Силы боссов EliteMobs используют тот же порядок аргументов с собственными хранилищами для боссов. Полную справку см. в context.cooldowns.

МетодЗаметки
local_ready(key?)Проверяет, готова ли локальная перезарядка.
local_remaining(key?)Возвращает оставшиеся тики локальной перезарядки либо 0.
check_local(key?, duration)Атомарно проверяет и запускает локальную перезарядку.
set_local(duration, key?)Задаёт локальную перезарядку без проверки.
global_ready()Проверяет общую глобальную перезарядку владельца скрипта.
set_global(duration)Задаёт общую глобальную перезарядку владельца скрипта.

Для обычных перезарядок действий реквизита или предмета используйте context.cooldowns:check_local("my_key", 40).


Модель времени выполнения

Один runtime на один экземпляр скрипта

Каждая сущность реквизита с прицепленными скриптами получает собственный независимый экземпляр runtime Lua. Когда реквизит спавнится, FMM загружает исходник Lua, выполняет его в свежей песочнице и сохраняет возвращённую таблицу. Когда реквизит удаляется, runtime завершается.

Для скриптов предметов один runtime создаётся на пару (игрок, itemId). Когда игрок экипирует пользовательский предмет, FMM создаёт экземпляр скрипта для этого игрока и типа предмета. Когда предмет снимают, runtime завершается.

Это значит:

  • Локальные переменные, объявленные на уровне файла, приватны для данного экземпляра скрипта.
  • context.state полностью изолирован между экземплярами, даже если они используют один и тот же файл скрипта.

Владение запланированными задачами

Все задачи, созданные через context.scheduler, принадлежат runtime, который их создал. Когда реквизит удаляется:

  1. Runtime завершается.
  2. Все принадлежащие ему задачи — одноразовые и повторяющиеся — автоматически отменяются.
  3. Все наблюдения за зонами сбрасываются.

Область видимости cooldown-ов

Общий движок скриптов предоставляет помощники локальных перезарядок (local_ready, local_remaining, check_local, set_local) и глобальных перезарядок (global_ready, set_global). FMM ограничивает их области так:

Тип скриптаОбласть локального хранилищаОбласть глобального хранилища
Скрипт реквизитаНа ScriptInstance (реквизит + файл скрипта)На PropEntity (общее для всех скриптов, прицепленных к этому реквизиту)
Скрипт предметаНа тройку (player, itemId, scriptFile) — сохраняется между переэкипировками, хотя экземпляр скрипта разрушается каждый раз при выходе предмета из активного слотаНа игрока (общее для всех FMM-скриптов предметов, которые запускает этот игрок)

Поскольку скрипты предметов разрушаются и пересобираются на каждом цикле equip/unequip, cooldown-ы предметов хранятся в статической мапе по UUID игрока, а не на ScriptInstance. Именно поэтому cooldown предмета продолжает действовать, даже если вы поменяли предмет местами в хотбаре и вернули обратно.

Это сохранение ограничено текущим временем работы FMM. /fmm reload, отключение плагина и перезапуск сервера очищают и хранилища перезарядок предметов, и глобальные хранилища перезарядок реквизита при завершении работы менеджеров скриптов.

Бюджет выполнения

Каждый вызов хука, каждый запланированный коллбэк и первоначальное вычисление самого файла скрипта выполняются под жёстким бюджетом выполнения. Бюджет применяется внутри Lua VM, поэтому он действует, пока ваш код ещё выполняется, а не только проверяет часы постфактум.

ОграничениеЗначение
Процессорное время текущего потока50 миллисекунд
Выполненных инструкций Lua250,000

То ограничение, которое достигнуто первым, прерывает вызов с ошибкой Lua и отключает экземпляр скрипта. Сообщения такие:

Lua instruction budget exceeded (250000 instruction limit)
Lua CPU-time budget exceeded (50ms current-thread CPU limit)

Поскольку проверка происходит на каждой инструкции, while true do end не может заморозить сервер.

Временная половина бюджета измеряется как процессорное время текущего потока, а не астрономическое время, поэтому скрипту не засчитывается время, когда поток сервера был снят с исполнения. На JVM, где замер процессорного времени текущего потока недоступен, MagmaCore откатывается к намеренно более щедрому ограничению в 250 миллисекунд затраченного времени (Lua elapsed-time fallback budget exceeded (250ms fallback; current-thread CPU time unavailable)), сохраняя тот же потолок в 250 000 инструкций, так что незавершающиеся скрипты остаются ограниченными в любом случае.

Вложенные вызовы разделяют один бюджет: если хук вызывает коллбэк, который вызывает ещё один, вся цепочка измеряется как единая квота 50 мс процессорного времени / 250 000 инструкций, а не по квоте на каждый.

Во время первоначального вычисления файла скрипта экземпляра ещё не существует, поэтому определение отклоняется и никогда не регистрируется, а не отключается.

Чтобы укладываться в бюджет:

  • Избегайте безграничных циклов внутри хуков.
  • Держите обработчики on_game_tick лёгкими — они выполняются каждый тик.
  • Используйте context.scheduler:run_repeating(...), чтобы размазать работу по тикам.

Полная справка по хукам

В этой таблице перечислены все хуки, доступные в скриптах реквизита и предметов.

В столбце context.event описано базовое семейство Bukkit-событий. Lua-обёртка события FMM по-прежнему предоставляет только event.player, event.is_cancelled, event.cancel() и event.uncancel() там, где это применимо.

Активные хуки реквизита (7)

ХукКогда срабатываетcontext.event
on_spawnРеквизит появляется в миреnil
on_game_tickКаждый серверный тик (50 мс)nil
on_destroyРеквизит удалёнnil
on_left_clickИгрок кликает по реквизиту левой кнопкойсобытие урона
on_right_clickИгрок кликает по реквизиту правой кнопкойсобытие взаимодействия
on_zone_enterИгрок входит в наблюдаемую зонуигрок-актор зоны (context.player / context.event.player; не отменяемо)
on_zone_leaveИгрок покидает наблюдаемую зонуигрок-актор зоны (context.player / context.event.player; не отменяемо)
Зарезервированный хук реквизита

Текущий валидатор скриптов принимает on_projectile_hit для скриптов реквизита, но текущая среда выполнения пока не рассылает попадания снарядов скриптам реквизита. Используйте хук предмета on_projectile_hit для поведения снарядов, привязанного к скриптуемому предмету, либо Bukkit-API ModeledEntityHitByProjectileEvent для обработки снарядов по моделированным сущностям на стороне плагина.

Хуки предметов (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

Дальнейшие шаги