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

Заметки по созданию моделей FreeMinecraftModels

Эта страница документирует текущие детали создания моделей, видимые в кодовой базе FreeMinecraftModels. Она намеренно консервативна: сосредоточена на контракте импорта/среды выполнения, а не на каждом предпочтении рабочего процесса Blockbench.

Исходные форматы

FreeMinecraftModels в настоящее время принимает:

  • файлы .bbmodel для редактируемых исходных импортов
  • файлы .fmmodel для облегчённых данных моделей, готовых к выполнению

Обычный процесс импорта:

  1. поместите модель в plugins/FreeMinecraftModels/imports
  2. выполните /fmm reload
  3. позвольте FreeMinecraftModels импортировать модель в активный набор моделей и пересобрать сгенерированный ресурспак

Роли папок

plugins/FreeMinecraftModels/imports
plugins/FreeMinecraftModels/models
plugins/FreeMinecraftModels/models_disabled
  • imports — это входная папка для ручного импорта моделей и загрузки официальных пакетов до обработки
  • models содержит активный установленный контент моделей
  • models_disabled содержит загруженный или установленный контент пакетов, который в данный момент отключён

В старых установках вместо этого может быть папка Models с заглавной буквы. FreeMinecraftModels решает это, предпочитая каноническую строчную models, когда она существует, и откатываясь на устаревшую Models, только когда её нет. На Windows и macOS это в любом случае один и тот же каталог; на чувствительной к регистру файловой системе Linux старая установка продолжает работать, но если обе директории каким-то образом существуют, читается только строчная models. Если вы нашли обе — сведите их в models.

Идентификаторы моделей

  • Идентификаторы моделей в среде выполнения берутся из имени файла без расширения .bbmodel или .fmmodel
  • Используйте стабильные, уникальные имена файлов, поскольку идентификатор — это то, к чему обращаются команды и вызовы API
  • Ссылки на анимации в Blockbench основаны на именах, поэтому дублирующиеся или неясные имена внутри модели чаще вызывают проблемы, чем чистая, явная схема именования
  • Сопоставление расширения не учитывает регистр, поэтому .BBModel и .FMModel тоже принимаются

Нормализация ID и коллизии

Имя файла нормализуется, прежде чем стать ID модели во время выполнения и именем файла в ресурс-паке:

  1. приводится к нижнему регистру
  2. каждый символ вне a-z, 0-9, ., _ и - заменяется на _

Поэтому My Table.bbmodel, my table.bbmodel и my_table.bbmodel нормализуются в один и тот же ID, my_table.

Перед запуском любого преобразования FreeMinecraftModels обходит всё дерево моделей и проверяет файлы, нормализующиеся в один ID. Когда коллизия найдена:

  • отклоняется каждый конфликтующий файл — ни один из них не загружается, поэтому нет молчаливого «побеждает последний»
  • ID модели блокируется на весь оставшийся проход загрузки
  • отклонённые модели также исключаются из экспорта комплекта кастомных Bedrock-сущностей
  • в консоль выводится:
[FMM Models] Rejected normalized model ID collision '<id>'. These files normalize to the same ID: <paths>. Rename the files so every normalized model ID is unique; no colliding model was loaded.

Решение всегда одно — переименовать файлы так, чтобы нормализованные ID различались. Самая безопасная привычка — с самого начала называть файлы моделей в нижнем регистре с подчёркиваниями (stone_table.bbmodel), что делает имя файла и ID времени выполнения идентичными и полностью убирает шанс неожиданной коллизии.

Совместимость с Blockbench

  • FreeMinecraftModels читает meta.format_version из .bbmodel и ветвится по его мажорному номеру
  • Отсутствующий блок meta, отсутствующий format_version или значение, которое не удаётся разобрать, — всё это откатывается к версии 4, с информационной строкой или предупреждением, называющим модель
  • Отсутствующий массив textures принимается и трактуется как пустой список текстур, а не приводит к падению импортёра. Экспортёр кастомных Bedrock-сущностей затем пропускает такую модель, потому что экспорт в Bedrock требует хотя бы одной текстуры
  • Имена извлечённых файлов текстур нормализуются к одному расширению .png. Исходное имя вроде body.jpg, body.PNG или body записывается и указывается как body.png
  • format_version 4.x и старше: кости читаются напрямую из дерева outliner, которое несёт имена костей внутри себя
  • format_version 5.x и новее: схема outliner изменилась. outliner теперь — вложенное дерево из голых строк UUID и словарей {uuid, isOpen, children} без ключа имени, тогда как отдельный плоский массив groups содержит фактические данные костей (включая name). FMM соединяет их по UUID — каждый узел outliner заменяется соответствующей записью groups, затем дочерние узлы объединяются рекурсивно, — поэтому имена костей, origin'ы и повороты разрешаются нормально
  • Следствия, о которых стоит знать при ручной правке или генерации файлов .bbmodel:
    • Файл v5, в котором отсутствует массив groups, пропускается без объединения, поэтому его кости теряют имена, а зарезервированные префиксы (tag_, h_, b_, m_, hitbox) перестают распознаваться
    • UUID должны точно совпадать между outliner и groups; узел outliner без соответствующей группы сохраняется как есть, а не отбрасывается
    • Не смешивайте format_version v5 с outliner в форме v4 и наоборот — ветка выбирается по объявленной версии, а не по фактической форме
  • Если журналы импорта сообщают, что формат модели несовместим с FreeMinecraftModels, рассматривайте это в первую очередь как проблему формата модели, а не вики или команды

Соглашения об именовании костей, значимые для среды выполнения

Текущий конвертер и конвейер скелета распознают несколько соглашений об именовании:

  • hitbox
    • зарезервировано для генерации хитбоксов
    • должно чётко определять хитбокс модели, а не использоваться как визуальная кость
    • обязана быть костью верхнего уровня в outliner. Импортёр ищет её только на корневом уровне; группа hitbox, вложенная внутрь другой кости, считается обычной костью
    • обязана содержать ровно один куб, который задаёт ширину (x), глубину (z) и высоту (y) во время выполнения. Лишние кубы приводят к записи в лог has more than one value defining a hitbox! Only the first cube will be used; пустая кость hitbox даёт has a hitbox bone but no hitbox cube!, и хитбокс не генерируется
    • никогда не анимируется (треки анимации, нацеленные на hitbox, пропускаются), никогда не отрисовывается и исключается из экспорта геометрии Bedrock. На Bedrock модель без кости hitbox откатывается к 1.0 x 2.0
  • tag_...
  • h_...
    • обрабатывается как кости головы
  • b_...
    • неотображаемые кости (скрыты в среде выполнения). Используйте их для структурных или организационных костей, которые не должны рендериться в игре.
  • m_...
    • кости точек посадки. Каждая кость с этим префиксом создаёт ездовую позицию для посадки на модели. Игроки или сущности могут быть посажены на эти позиции во время выполнения. Несколько m_-костей создают несколько мест. Управляется внутренне через MountPointManager.

Это не просто стилистические соглашения; они влияют на конвертацию и поведение среды выполнения.

Для тегов имён нужна кость tag_

Это самая частая причина безымянных мобов в поставляемом контенте, поэтому стоит сказать прямо:

Модель получает тег имени, только если содержит кость, чьё имя начинается с tag_. Запасного варианта нет.

Как это работает:

  • При импорте любая кость с именем tag_... получает параллельную автогенерируемую «мета»-кость (fmm_nametag_bone_<name>), помеченную как кость тега имени. Больше ничто в конвейере этот флаг не выставляет
  • Во время выполнения скелет собирает эти помеченные кости, и в origin'е кости tag_ спавнится text display. Его позиция и текст следуют за этой костью
  • ModeledEntity.setDisplayName(...) и setDisplayNameVisible(...) проходят по этой коллекции. Без кости tag_ коллекция пуста, и оба вызова молча ничего не делают — ни ошибки, ни предупреждения, ни имени

Почему ванильный тег имени вас не выручает:

  • Динамическая модель скрывает от клиентов лежащую в основе живую сущность (setVisibleByDefault(false) плюс флаг невидимости), поэтому собственный тег имени ванильного моба тоже не отрисовывается
  • В итоге получается совершенно безымянный моб, хотя вызывающий плагин успешно задал отображаемое имя

Практические правила:

  • Если модель представляет именованную сущность (босса EliteMobs, квестового NPC, что угодно, для чего плагин вызывает setDisplayName), добавьте кость tag_
  • Разместите её там, где должен парить тег имени — обычно чуть выше головы
  • Кости не нужны кубы; это позиционный якорь. В частности, tag_name пропускается при генерации определений моделей предметов, поэтому она никогда не отрисовывается как геометрия
  • Несколько костей tag_ допустимы; каждая из них получает собственный text display с тем же именем
  • Если вы видите в консоли nametag bone did not spawn name tag, кость была распознана, но её text display не смог заспавниться — это другая проблема, чем полное отсутствие кости tag_

Свободно парящие кубы

Кубы, объявленные в верхней части outliner без содержащей их группы, приходят как «голые» строки UUID, а не как записи костей. FreeMinecraftModels присоединяет их к автогенерируемой корневой кости (freeminecraftmodels_autogenerated_root), чтобы они всё же отрисовывались. Анимации к ним обращаться не могут, поэтому всё, что вы собираетесь анимировать, помещайте внутрь настоящей группы.

IK, нулевые объекты и локаторы

Текущий код подтверждает поддержку:

  • нулевых объектов Blockbench в качестве контроллеров IK
  • чертежей цепей IK и решения IK во время выполнения (FABRIK)
  • парсинга локаторов

Нулевой объект становится контроллером IK только тогда, когда его запись в .bbmodel несёт оба поля: ik_source (кость, с которой начинается цепь) и ik_target (кость или локатор, к которому цепь тянется). Также считывается lock_ik_target_rotation. Цепь обнаруживается обходом иерархии костей вверх от цели к источнику, поэтому эти двое должны быть действительно связаны.

Важные практические ограничения:

  • Связь источника и цели идёт по UUID, поэтому она переживает переименования — но если какого-то UUID нет в модели, в консоль пишется IK chain in model <model>: Could not find source bone with UUID ... / Could not find target with UUID ..., и эта цепь пропускается
  • Если обход не находит пути от источника к цели, вы получите Could not find path from source to target, и цепь пропускается
  • Поиск анимации для контроллера основан на именах, поэтому именование контроллеров должно оставаться стабильным между структурой модели и данными анимации
  • Значение имеют только ключевые кадры позиции на нулевом объекте — они становятся смещением цели IK. Треки поворота и масштаба на нулевом объекте игнорируются

О том, как IK управляется покадрово, см. Анимации.

Разделение вывода для 1.21.4+

FreeMinecraftModels объявляет api-version: 1.21.4, поэтому 1.21.4 — это минимальная версия сервера, и современная раскладка определений моделей предметов — единственная, которую вы получите:

plugins/FreeMinecraftModels/output/FreeMinecraftModels/assets/freeminecraftmodels/items

В коде всё ещё существуют устаревшие (до 1.21.4) ветки с переопределениями через кожаную конскую броню, но ни один сервер, способный загрузить текущий плагин, до них не доходит. Если вы читаете старые заметки или смотрите на старую папку вывода — вот в чём разница.

Отображаемая модель JSON (1.21.4+)

Администраторы могут поместить файл .json рядом с файлом .bbmodel или .fmmodel с тем же базовым именем (например, table.bbmodel + table.json). Этот JSON должен быть экспортирован из Blockbench как модель «Java Block/Item» и определяет, как предмет выглядит при удержании в руке или отображении в инвентаре.

При импорте FMM копирует JSON в вывод ресурспака и автоматически переписывает голые ссылки на текстуры внутри него для указания на извлечённые текстуры модели. Если сопутствующий JSON отсутствует, предмет отображается в игре как обычная бумага.

Настройка пользовательских предметов в YML

Сопутствующий файл конфигурации .yml (с тем же базовым именем, что и модель) теперь поддерживает необязательные поля предметов. Если установлен material:, модель также доступна как пользовательский предмет для удержания в руке. Полный формат YML:

isEnabled: true
scripts:
- my_script.lua
material: DIAMOND_SWORD # optional — if set, model is also a custom item
name: '&b&lMy Custom Sword' # optional — display name
lore: # optional
- '&7A custom weapon'
enchantments: # optional — format: ENCHANTMENT_NAME,LEVEL
- SHARPNESS,5
- FIRE_ASPECT,2

Когда material: присутствует, модель появляется в браузере контента администратора наряду с пропсами и может быть выдана игрокам как функциональный предмет.

Заметки о Bedrock и пути рендеринга

  • Поддержка Bedrock зависит от sendCustomModelsToBedrockClientsV2 (по умолчанию true; заменяет более старый ключ sendCustomModelsToBedrockClients) и окружающего пути Floodgate/Geyser/ресурспака
  • Java-клиенты на поддерживаемых версиях могут использовать рендеринг через display-сущности, когда useDisplayEntitiesWhenPossible включен
  • Не предполагайте, что модель, которая выглядит правильно на Java-клиенте, автоматически безопасна для вашего пути Bedrock

Практические советы по созданию моделей

  • сохраняйте стабильные имена файлов, потому что они становятся идентификаторами среды выполнения
  • сохраняйте явные имена контроллеров и анимаций, потому что поиск анимаций в Blockbench основан на именах
  • используйте зарезервированные имена виртуальных костей осознанно (hitbox, tag_, h_, b_, m_) — и помните, что любой модели, которая должна показывать имя, нужна кость tag_, иначе она молча останется безымянной
  • называйте анимации состояний spawn, idle, walk, attack и death, если хотите, чтобы они запускались автоматически; всё остальное — пользовательские анимации, которые вы запускаете сами (см. Анимации)
  • модель, предназначенная для /fmm disguise, должна как минимум поставляться с idle и может добавлять sneak и jump, которые распознаёт только контроллер маскировки (см. Маскировки игроков)
  • проверяйте импортированный вывод после /fmm reload, а не только внутри Blockbench
  • проверяйте содержимое сгенерированного пака для вашей целевой версии Minecraft, особенно на 1.21.4+

Модели состояний лука и арбалета

FMM поддерживает автоматические состояния анимации натяжения для пользовательских предметов-луков и арбалетов. Настройка не требуется — просто назовите файлы моделей с правильными суффиксами, и FMM автоматически обнаружит набор состояний при генерации ресурспака.

Соглашение об именовании

СуффиксНазначениеЛукАрбалет
_idleПредмет в руке, не натягивается и не заряженобязательнообязательно
_draw_startНачало натяженияобязательнообязательно
_draw_halfНатянут наполовинуобязательнообязательно
_draw_fullПолностью натянутобязательнообязательно
_chargedЗаряженный арбалет (стрела или ракета)--обязательно

Для лука нужны четыре модели (все кроме _charged). Для арбалета нужны все пять.

Пример расположения файлов

plugins/FreeMinecraftModels/imports/
cool_bow_idle.bbmodel
cool_bow_draw_start.bbmodel
cool_bow_draw_half.bbmodel
cool_bow_draw_full.bbmodel
cool_bow.yml <-- config uses the base name, not _idle

Для арбалета добавьте пятый файл cool_bow_charged.bbmodel.

Как работает обнаружение

  • Обнаружение происходит автоматически при генерации ресурспака (при запуске или /fmm reload).
  • Только модель _idle получает JSON-файл определения предмета в выходном паке. Состояния натяжения и зарядки указываются как условные записи внутри этого определения.
  • Только базовое имя получает файл конфигурации YML. В примере выше конфиг — это cool_bow.yml, а не cool_bow_idle.yml.

Отображаемая модель JSON

Каждая модель состояния может иметь свой сопутствующий .json файл отображаемой модели (например, cool_bow_idle.json, cool_bow_draw_full.json). FMM автоматически подключает их к сгенерированному определению предмета. Точную JSON-структуру, которая генерируется, см. в Вывод ресурспака.

За рамками данной страницы

Эта страница не пытается гарантировать:

  • точные шаги в интерфейсе Blockbench
  • предпочтения художественного рабочего процесса
  • каждую особенность устаревших .bbmodel, описанную в более ранних локальных README-материалах

Эти детали меняются быстрее, чем проверенный контракт среды выполнения выше.

Имена текстур нормализуются к нижнему регистру и должны оканчиваться на .png: например, body.PNG и body.jpg разрешаются как textures/body.png. Не используйте имена, различающиеся только регистром.