API и руководство разработчика FreeMinecraftModels
FreeMinecraftModels — это одновременно автономный плагин и API-поверхность для других плагинов.
Репозиторий Maven
<repository>
<id>magmaguy-repo-releases</id>
<name>MagmaGuy's Repository</name>
<url>https://repo.magmaguy.com/releases</url>
</repository>
<repository>
<id>magmaguy-repo-snapshots</id>
<name>MagmaGuy's Snapshot Repository</name>
<url>https://repo.magmaguy.com/snapshots</url>
</repository>
Зависимость
<dependency>
<groupId>com.magmaguy</groupId>
<artifactId>FreeMinecraftModels</artifactId>
<version>LATEST.VERSION.HERE</version>
<scope>provided</scope>
</dependency>
Используйте как compileOnly/provided. Не включайте плагин в свой jar через shade.
Основные точки входа
ModeledEntityManager.modelExists(String)ModeledEntityManager.reload()ModeledEntityManager.getAllEntities()ModeledEntityManager.getDynamicEntities()ModeledEntityManager.propEntities()
Основные типы среды выполнения
ModeledEntityStaticEntityDynamicEntityPropEntity
Создание сущностей
StaticEntity preview = StaticEntity.create("example_model", location);
DynamicEntity mobModel = DynamicEntity.create("example_model", livingEntity);
DynamicEntity mount = DynamicEntity.createWithInvisibility("example_model", livingEntity);
PropEntity prop = PropEntity.spawnPropEntity("example_model", location);
Все пути создания возвращают null, если запрашиваемый идентификатор модели не загружен.
createWithInvisibility — вариант, который применяет зелье невидимости вместо скрытия сущности от клиентов. Это сохраняет отслеживание сущности на стороне клиента, что необходимо для управления транспортом (используется внутренне командой /fmm mount).
Полезные методы среды выполнения
ModeledEntity#setDisplayName(String)ModeledEntity#setDisplayNameVisible(boolean)ModeledEntity#setLeftClickCallback(...)ModeledEntity#setRightClickCallback(...)ModeledEntity#setHitboxContactCallback(...)ModeledEntity#setModeledEntityHitByProjectileCallback(...)ModeledEntity#playAnimation(String, boolean, boolean)ModeledEntity#stopCurrentAnimations()ModeledEntity#hasAnimation(String)DynamicEntity#setSyncMovement(boolean)Bone#getBoneLocation()
Поверхность событий
Общие события взаимодействия:
ModeledEntityLeftClickEventModeledEntityRightClickEventModeledEntityHitboxContactEventModeledEntityHitByProjectileEvent
Также существуют типизированные варианты для StaticEntity, DynamicEntity и PropEntity.
ModeledEntityHitByProjectileEvent и OBB-обнаружение снарядов
FMM использует OBB (ориентированный ограничивающий параллелепипед) для обнаружения попадания снарядов в моделированные сущности. Когда снаряд пересекает OBB-хитбокс моделированной сущности, FMM генерирует ModeledEntityHitByProjectileEvent. Это стандартное отменяемое событие Bukkit.
Ключевые детали:
- Урон от стрел рассчитывается с поддержкой бонуса от чар
POWER - Чары
PIERCINGучитываются — стрелы могут проходить сквозь к дополнительным целям - Отмена события предотвращает урон и полностью блокирует попадание
@EventHandler
public void onProjectileHitModel(ModeledEntityHitByProjectileEvent event) {
ModeledEntity target = event.getModeledEntity();
Projectile projectile = event.getProjectile();
// Отмена для предотвращения урона
event.setCancelled(true);
}
Утилиты предметов и моделей
ModelItemFactory
Фабричный класс для программного создания ItemStack, связанных с моделями.
// Создание предмета для размещения пропса (использует PDC-ключ "model_id")
ItemStack placementItem = ModelItemFactory.createModelItem("lamp_post", Material.STICK);
// Создание пользовательского предмета из конфига (использует PDC-ключ "fmm_item_id")
PropScriptConfigFields config = ItemScriptManager.getItemDefinitions().get("magic_sword");
ItemStack customItem = ModelItemFactory.createCustomItem("magic_sword", config);
createModelItem(String modelId, Material material)— создаёт предмет для размещения пропсов. На 1.21.4+ автоматически применяет рендеринг отображаемой модели, если существует display JSON.createCustomItem(String itemId, PropScriptConfigFields config)— создаёт пользовательский предмет с именем, описанием, чарами и отображаемой моделью из унифицированного конфига.formatModelName(String modelId)— утилита, преобразующая ID модели вида01_em_flame_swordвFlame Sword.
DisplayModelRegistry
Простой реестр, отслеживающий, какие модели имеют доступный display JSON.
// Проверка, есть ли у модели зарегистрированный display model JSON
boolean has3D = DisplayModelRegistry.hasDisplayModel("magic_sword");
register(String modelId)— регистрирует ID модели (вызывается внутренне при перезагрузке)hasDisplayModel(String modelId)— возвращаетtrue, если для этой модели существует.jsonотображаемая модельshutdown()— очищает все регистрации
ItemScriptManager
Управляет жизненным циклом Lua-скриптов для каждого игрока для пользовательских предметов (моделей с установленным material: в YML-конфиге).
// Получение всех зарегистрированных определений пользовательских предметов
Map<String, PropScriptConfigFields> items = ItemScriptManager.getItemDefinitions();
// Получение активного экземпляра Lua-скрипта для игрока + предмета
ScriptInstance instance = ItemScriptManager.getActiveScript(playerUUID, "magic_sword");
// Получение всех активных скриптов для игрока
Map<String, ScriptInstance> scripts = ItemScriptManager.getActiveScripts(playerUUID);
scanForCustomItems(File modelsFolder)— сканирует YML-конфиги моделей для поиска пользовательских предметовupdateEquippedScripts(Player player)— сравнивает экипированные предметы с запущенными скриптами, вызывая хуки equip/unequipremovePlayer(Player player)— завершает все скрипты для игрока (вызывайте при выходе)getItemDefinitions()— возвращает карту ID предмета кPropScriptConfigFields
ScriptedItemAPI
Публичный API для внешних плагинов для интеграции со скриптовой системой предметов FMM. Позволяет другим плагинам ставить свои собственные ItemStack данные скриптовых предметов FMM (PDC-тег + модель предмета), чтобы Lua-скрипт хуки FMM срабатывали для этих предметов, без перезаписи имени, описания или чар предмета.
// Проверка существования определения скриптового предмета
boolean exists = ScriptedItemAPI.isValidItemId("flame_blade");
// Применение данных скриптового предмета FMM к существующему ItemStack
// Устанавливает:
// - PDC-тег fmm_item_id (чтобы система скриптов FMM распознавала предмет)
// - Модель предмета (1.21.4+) из реестра отображаемых моделей FMM
// НЕ изменяет имя, описание, чары или другие свойства предмета.
boolean success = ScriptedItemAPI.applyScriptedItemData(itemStack, "flame_blade");
// Получение конфига скриптового предмета
PropScriptConfigFields config = ScriptedItemAPI.getItemConfig("flame_blade");
isValidItemId(String itemId)— возвращаетtrue, если ID предмета зарегистрирован в определениях предметов FMMapplyScriptedItemData(ItemStack itemStack, String itemId)— ставит PDC-тег и модель предмета на существующий ItemStack. Возвращаетtrueпри успехе,falseесли ID предмета недействителен или ItemStack не имеет мета. Примечание по лукам/арбалетам: если у данногоitemIdнет отображаемой модели, но уitemId + "_idle"есть (т.е. предмет имеет модели состояний лука/арбалета), метод автоматически использует модель_idleкак отображаемую модельgetItemConfig(String itemId)— возвращаетPropScriptConfigFieldsдля данного ID предмета илиnull, если не найден
EliteMobs использует этот API внутренне через поле конфигурации scriptedItem. Когда пользовательский предмет EliteMobs устанавливает scriptedItem: flame_blade, EliteMobs создаёт предмет обычным образом (имя, описание, чары, уровень), а затем вызывает ScriptedItemAPI.applyScriptedItemData() для добавления модели и скриптового поведения FMM.
PropScriptConfigFields
Унифицированный класс конфигурации для YML-файлов конфигурации моделей. Используется как скриптами пропсов, так и пользовательскими предметами.
# Пример: torch_01.yml
isEnabled: true
scripts:
- torch_glow.lua
material: STICK # Если задано, модель становится пользовательским предметом
name: "&eMagic Torch" # Пользовательское отображаемое имя (необязательно)
lore: # Пользовательские строки описания (необязательно)
- "&7Glows in the dark"
enchantments: # Чары (необязательно, формат: NAME,LEVEL)
- "FIRE_ASPECT,1"
Ключевые методы: isCustomItem(), getParsedMaterial(), getParsedEnchantments(), getScripts().
Lua-скриптинг
FreeMinecraftModels поддерживает Lua-скрипты как для пропсов, так и для пользовательских предметов через скриптовый движок MagmaCore 2.0. Файлы скриптов размещаются в plugins/FreeMinecraftModels/scripts/ и привязываются к моделям через сопутствующий YML-конфиг рядом с файлом модели.
Хуки скриптов пропсов
| Хук | Триггер |
|---|---|
on_spawn | Пропс появляется в мире |
on_game_tick | Каждый тик, пока пропс активен |
on_zone_enter | Игрок входит в зону пропса |
on_zone_leave | Игрок покидает зону пропса |
on_destroy | Пропс удаляется |
on_left_click | Игрок кликает левой кнопкой по пропсу |
on_right_click | Игрок кликает правой кнопкой по пропсу |
on_projectile_hit | Снаряд попадает в пропс |
Хуки скриптов предметов
Пользовательские предметы (модели с установленным material:) поддерживают 22 Lua-хука:
| Хук | Триггер |
|---|---|
on_equip | Предмет попадает в отслеживаемый слот экипировки |
on_unequip | Предмет покидает отслеживаемый слот экипировки |
on_game_tick | Каждый тик, пока предмет экипирован |
on_attack_entity | Игрок атакует сущность, держа предмет |
on_kill_entity | Игрок убивает сущность, держа предмет |
on_take_damage | Игрок получает урон при экипированном предмете |
on_shield_block | Игрок блокирует щитом |
on_shoot_bow | Игрок стреляет из лука |
on_projectile_hit | Снаряд, выпущенный игроком, попадает в цель |
on_projectile_launch | Игрок запускает снаряд |
on_right_click | Игрок кликает правой кнопкой с предметом |
on_left_click | Игрок кликает левой кнопкой с предметом |
on_shift_right_click | Игрок кликает Shift+ПКМ с предметом |
on_shift_left_click | Игрок кликает Shift+ЛКМ с предметом |
on_interact_entity | Игрок кликает правой кнопкой по сущности с предметом |
on_swap_hands | Игрок меняет предмет между руками |
on_drop | Игрок выбрасывает предмет |
on_break_block | Игрок ломает блок, держа предмет |
on_consume | Игрок потребляет предмет |
on_item_damage | Предмет получает урон прочности |
on_fish | Игрок использует удочку |
on_death | Игрок умирает при экипированном предмете |
Скрипты предметов получают context.item (с ID предмета и информацией об игроке) вместо context.prop.
Таблица context скриптов пропсов
Скрипты пропсов получают таблицу context. Вот краткое описание ключевых API — подробности см. в Lua Prop API.
context.prop:
model_id— имя модели-чертежаcurrent_location— текущее местоположение пропсаplay_animation(name, blend, loop)— воспроизводит указанную анимацию (blend и loop по умолчаниюtrue)stop_animation()— останавливает все текущие анимацииhurt_visual()— воспроизводит визуальный эффект повреждения (красная вспышка) на пропсеpickup()— удаляет пропс и выбрасывает его предмет размещенияmount(player)— сажает игрока на пропсdismount(player)— снимает игрока с пропсаget_passengers()— возвращает список игроков, которые сейчас сидят на пропсеspawn_elitemobs_boss(filename, x, y, z)— спавнит босса EliteMobs относительно пропса
context.event:
- Доступен в
on_left_click,on_right_clickиon_projectile_hit cancel(),uncancel(),is_cancelledplayer— игрок, вызвавший событие
context.world:
spawn_entity(entity_type, location)— спавнит ванильную сущностьset_block_at(location, material)— устанавливает блок в мире- А также частицы, звуки, запросы блоков, молнии и поиск ближайших сущностей
Объекты игрока (из context.event.player):
get_held_item()— возвращает предмет, который держит игрокconsume_held_item()— убирает один предмет из рукиhas_item(material)— проверяет, есть ли у игрока предметsend_message(text)— отправляет сообщение в чат игрокуgame_mode— текущий режим игры игрока
Пример скрипта пропса
function on_spawn(context)
context.prop.play_animation("idle", true, true)
end
function on_right_click(context)
context.prop.play_animation("activate", false, false)
end
Пример скрипта предмета
function on_equip(context)
context.event.player.send_message("&6You equipped the Flame Blade!")
end
function on_attack_entity(context)
-- Огненный эффект при попадании
context.event.player.send_message("&cBurn!")
end
function on_unequip(context)
context.event.player.send_message("&7Flame Blade sheathed.")
end
Примечания
- FreeMinecraftModels — это зависимость в виде установленного плагина, а не встраиваемая библиотека.
- Если вашему плагину нужны свежеимпортированные модели, вызывайте
ModeledEntityManager.reload()вместо попытки самостоятельно пересобрать состояние FreeMinecraftModels. - Все плагины в экосистеме Nightbreak теперь зависят от MagmaCore 2.0.0-SNAPSHOT, который включает общий Lua-скриптовый движок, используемый скриптами пропсов FreeMinecraftModels и Lua-способностями EliteMobs.