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

Маскировки игроков

FreeMinecraftModels умеет маскировать любого онлайн-игрока под загруженную модель. Маскировки управляются через команды, публичный DisguiseAPI и PlayerDisguiseEntity на каждого игрока, который отвечает за невидимость и отрисовку модели для замаскированного игрока.

Команды​

КомандаПравоЗаметки
/fmm disguise <modelID>freeminecraftmodels.disguise.selfМаскирует отправителя. Только для игрока
/fmm disguise <modelID> <player>freeminecraftmodels.disguise.self + freeminecraftmodels.disguise.othersМаскирует указанного игрока. Работает из консоли
/fmm undisguisefreeminecraftmodels.disguise.selfСнимает маскировку с отправителя. Только для игрока
/fmm undisguise <player>freeminecraftmodels.disguise.self + freeminecraftmodels.disguise.othersСнимает маскировку с указанного игрока. Работает из консоли
/fmm disguiselistfreeminecraftmodels.disguise.othersПеречисляет всех замаскированных игроков и их модели

Wildcard freeminecraftmodels.* выдаёт admin, deleteall, disguise.self и disguise.others при дефолте OP. Он также выдаёт отдельно зарегистрированное право freeminecraftmodels.bypassregionprotection.

Поведение​

  • Маскировка игрока, который уже замаскирован, аккуратно заменяет предыдущую маскировку — снимать её сначала не нужно.
  • FMM скрывает игрока от других наблюдателей через setVisibleByDefault(false) и добавляет эффект зелья невидимости, если его ещё нет. Подмена отображения экипировки скрывает броню и предметы в руках от других наблюдателей, не меняя инвентарь. Собственный вид игрока исключён из этой подмены; отображение его тела по-прежнему зависит от обработки видимости клиентом.
  • FMM повторно применяет невидимость через один тик после соответствующих событий удаления или изменения эффекта либо возрождения, только если эта маскировка изначально добавила эффект. Эффект невидимости, существовавший до начала маскировки, не сохраняется и не восстанавливается. Снятие маскировки возвращает видимость по умолчанию в true, удаляет добавленный FMM эффект и повторно отправляет текущую экипировку игрока.
  • Скрытие экипировки повторно отправляется для подключающихся наблюдателей и при смене мира. Реальная броня и предметы в руках игрока не заменяются.
  • Хитбокс игрока не меняется. Декоративная маскировка не создаёт пакетную сущность взаимодействия, а её обработчики кликов ничего не делают, поэтому отдельной цели для атак или посадки она не предоставляет. Невидимость может влиять на поведение вне FMM; неизменность выбора целей мобами не гарантируется.
  • Маскировки не переживают перезапуск сервера, /fmm reload или выход игрока из игры — они отслеживаются в памяти, и обработчик DisguiseListeners.onQuit снимает маскировку по PlayerQuitEvent. Смерть и смена мира не снимают маскировку.
  • Успешный /fmm reload удаляет активные маскировки при выключении; после него их нужно применить заново. Если перезагрузка отклонена на этапе подготовки нового содержимого, активное состояние сохраняется.

Анимации маскировки​

У каждой маскировки есть контроллер, выбирающий анимации по состоянию игрока перед запуском общего механизма воспроизведения моделируемых сущностей. Он не обходит этот механизм. Зарезервированные имена должны быть в нижнем регистре, поскольку проверка наличия анимаций учитывает регистр.

Распознаются пять зарезервированных имён анимаций, в следующем порядке приоритета (от высшего к низшему):

ПриоритетАнимацияТипЧто запускает
1attackодноразоваяИгрок взмахнул рукой
2jumpодноразоваяИгрок оторвался от земли, двигаясь вверх
3sneakциклИгрок крадётся
4walkциклПозиция игрока изменилась более чем на 0,01 блока с прошлого тика, включая вертикальное движение
5idleциклНичто другое не подходит

Что стоит знать о поведении:

  • Учитываются только те анимации, которые действительно есть у модели. Модель без анимации sneak просто проваливается к walk или idle.

  • Одноразовая анимация запрашивает немедленное воспроизведение без цикла и приостанавливает любой новый выбор на фиксированные 20 тиков (1 секунда при 20 TPS). Этот отсчёт не измеряет длительность анимации. Более длинная анимация может прерваться следующим выбором, а короткая — завершиться до возобновления выбора. Взмахи рукой во время паузы объединяются в одну ожидающую атаку, а переходы к прыжку не ставятся в очередь.

  • Циклы перезапускаются только тогда, когда выбранная анимация действительно меняется, поэтому ровная ходьба не начинается заново каждый тик.

  • jump действительно подключён для маскировок, в отличие от (сейчас неактивного) состояния прыжка у обычных моделируемых сущностей. См. Анимации.

  • Модель маскировки без анимации idle выводит предупреждение при каждой маскировке:

    Disguise model '<model>' has no 'idle' animation — disguised players using this model will freeze on the last animation frame whenever no other action is active.

    Поставляйте анимацию idle с любой моделью, которую собираетесь использовать как маскировку.

Клиенты Bedrock​

Маскировки зависят от отрисовки пользовательской модели средствами FMM. Значение по умолчанию sendCustomModelsToBedrockClientsV2: true в config.yml включает отправку моделей Bedrock. При false модель не поступает наблюдателям Bedrock, а замаскированный игрок остаётся невидимым. Устаревший ключ sendCustomModelsToBedrockClients больше не читается. Даже при включённом V2 клиенту нужны преобразованный ресурс-пак и работающая интеграция Geyser/Floodgate.

DisguiseAPI​

Сторонние плагины могут управлять маскировками программно через com.magmaguy.freeminecraftmodels.api.DisguiseAPI.

import com.magmaguy.freeminecraftmodels.api.DisguiseAPI;

// Disguise (returns false if the model ID is not loaded)
boolean ok = DisguiseAPI.disguise(player, "dragon");

// Undisguise (returns true if a disguise was removed)
DisguiseAPI.undisguise(player);

// Queries
boolean isDisguised = DisguiseAPI.isDisguised(player);
String modelID = DisguiseAPI.getDisguiseModelID(player); // null if not disguised

// Unmodifiable snapshot of all disguised players
Collection<Player> all = DisguiseAPI.getDisguisedPlayers();

Этот API — публичная, безопасная при рефакторингах точка входа. Плагинам следует обращаться к DisguiseAPI, а не к внутреннему DisguiseManager.

API не проверяет права команд и не нормализует ID моделей. Передавайте онлайн-игрока и точный ID загруженной модели. disguise удаляет существующую маскировку до попытки создать замену, поэтому неизвестный ID возвращает false уже после удаления прежней маскировки. Команда сначала проверяет модель и при неверном ID сохраняет старую маскировку. Успешный результат API подтверждает создание, а не отрисовку клиентом или принятие ресурс-пака.

Типичные сценарии​

  • Ролевые и RPG-серверы: маскировка игроков под модели боссов для синематиков или квестовых скриптов.
  • Проведение событий: маскировка ведущего под гигантскую пользовательскую модель.
  • Маунты и транспорт: комбинируйте /fmm mount с /fmm disguise для креативных схем передвижения.
  • Интеграция с EliteMobs: скрипты боссов могут маскировать игрока, инициировавшего событие, для временного эффекта трансформации.

Решение проблем​

Ничего не происходит после /fmm disguise dragon. ID модели должен в точности совпадать с загруженной моделью. Проверьте имя модели через /fmm admin или автодополнение команды. Форма с указанием игрока проверяет freeminecraftmodels.disguise.others до того, как разрешает модель или игрока, и сообщает об отсутствии этого права напрямую.

Моя маскировка исчезла после /fmm reload. Это ожидаемо после успешной полной перезагрузки. Для автоматического повторного применения маскировок слушайте FmmReloadedEvent, запланированное на основном потоке через 40 тиков после инициализации. Отклонённая подготовка не удаляет активное состояние.

Bedrock-игроки не видят маскировку. См. Клиенты Bedrock выше.

Замаскированный игрок всё ещё виден другим. Проверьте, был ли игрок невидимым до начала маскировки: FMM не берёт этот эффект под управление и не восстанавливает его после исчезновения. Также проверьте плагины, меняющие видимость игроков, эффекты или пакеты экипировки. FMM использует видимость игрока, реальный эффект зелья и подмену отображения экипировки; подтвердите конфликт, прежде чем менять настройки другого плагина.