Flight API
Простой API без зависимостей для управления полётом и выявления модов, нарушающих систему полёта.
Flight API — библиотека для Minecraft (Fabric/NeoForge), решающая проблему конфликтов между модами при управлении полётом игрока. С Flight API предотвращаются ситуации, когда игроки случайно падают или не могут летать из-за того, что несколько модов постоянно переключают player.getAbilities().flying
и player.getAbilities().allowFlying
.
Текущие возможности
- Система управления полётом на основе очереди для улучшения координации модов при работе с ванильной системой полёта путём перехвата вызовов, изменяющих способности
allowFlying
иflying
. - Понятное логирование для игроков с целью выявления проблем с модами, связанными с полётом. Позволяет легко обнаруживать конфликты и автоматически их разрешать. Данная система реализована как решение для диагностики причин сбоев полёта в режимах creative или spectator, а также для анализа совместимости модов — например, выявления проблемного мода в крупных сборках.
Для пользователей
Поместите файл .jar
в папку mods
— готово! При возникновении проблем с полётом предоставьте автору мода файл debug.log
из папки logs. Благодаря Flight API автор сможет идентифицировать проблемный мод.
Для разработчиков
Основная концепция
В ванильном Minecraft (и многих модах) логика полёта может выглядеть так:
player.getAbilities().flying = true;
player.getAbilities().allowFlying = true;
Если два или более модов делают это несогласованно, состояние полёта игрока может хаотично переключаться.
Flight API предотвращает это через следующие принципы:
Только один мод («владелец») может управлять полётом игрока в каждый момент времени. Все остальные запросы помещаются в очередь. Когда текущий владелец освобождает контроль, следующий запрос в очереди активируется, обеспечивая предсказуемое продолжение или остановку полёта.
Любая прямая модификация
flying
илиallowFlying
перехватывается или блокируется при отсутствии авторизации через миксины.Разработчикам модов следует (и настоятельно рекомендуется) использовать:
FlightAPI.requestFlight(String modId, ServerPlayerEntity player); // ... FlightAPI.releaseFlight(String modId, ServerPlayerEntity player);
вместо прямого доступа к
player.getAbilities().flying
. Эта единая точка контроля гарантирует, что только один мод управляет полётом одновременно.
Настройка зависимости (Fabric/NeoForge)
В build.gradle
укажите maven Flight API (или CurseMaven) и используйте обработчик зависимостей modImplementation
для загрузки библиотеки в среду разработки.
Официальный maven в настоящее время недоступен, поэтому для загрузки библиотеки временно можно использовать CurseMaven.
Также вы можете использовать jar-in-jar для встраивания этого API в свой мод, чтобы упростить установку без необходимости отдельной загрузки Flight API. Однако можно просто указать зависимость, как для любого другого мода.
Использование
Запрос полёта
Когда требуется включить полёт для игрока (например, при нажатии кнопки «Включить реактивный ранец», применении заклинания левитации и т.д.), не используйте player.abilities.flying = true
.
Вместо этого вызовите метод requestFlight(String modId, ServerPlayerEntity player)
:
boolean gotControl = FlightAPI.requestFlight(modId, player);
if (gotControl) {
// Вы немедленно получили управление полётом.
// Внутри FlightManager устанавливает allowFlying/flying = true для игрока.
// Игрок теперь может летать (если не в режиме creative/spectator и т.д.).
} else {
// Другой мод уже контролирует полёт этого игрока.
// Ваш запрос поставлен в очередь. Когда текущий владелец освободит контроль,
// управление автоматически перейдёт к вам. Здесь можно обработать это поведение.
}
Примечание: modId
— уникальная строка, идентифицирующая ваш мод (например, "mymod").
Освобождение полёта
Когда ваш мод завершает управление полётом (игрок выключает реактивный ранец, заклинание заканчивается и т.д.), вызовите метод releaseFlight(String modId, ServerPlayerEntity player)
.
FlightAPI.releaseFlight("MyAwesomeMod", player);
Если в очереди нет ожидающих, полёт игрока отключается. Если есть другой мод в очереди, он немедленно получает управление. Игрок продолжит полёт под контролем нового владельца (или будет приземлён, в зависимости от логики нового мода).
Проверка текущего владельца
Можно проверить, кто сейчас управляет полётом:
Optional<String> currentOwner = FlightAPI.getCurrentOwner(player);
if (currentOwner.isPresent()) {
System.out.println("Управление полётом в настоящее время у: " + currentOwner.get());
} else {
System.out.println("Сейчас никто не управляет полётом");
}
Примеры сценариев
Моды «Реактивный ранец» и «Заклинание левитации»
JetpackMod
предоставляет полёт при ношении реактивного ранца.
MagicSpellMod
предоставляет полёт при применении заклинания левитации.
Без Flight API оба мода могут постоянно переключать flying = true/false, вызывая рывки игрока вверх-вниз (например, если два мода, созданных в MCreator, пытаются управлять полётом).
С Flight API JetpackMod
вызывает FlightAPI.requestFlight("JetpackMod", player)
. MagicSpellMod
вызывает FlightAPI.requestFlight("MagicSpellMod", player)
, но JetpackMod
уже владеет полётом, поэтому MagicSpellMod
ставится в очередь. Когда у JetpackMod заканчивается топливо и он вызывает FlightApi.releaseFlight("JetpackMod", player)
, управление немедленно передаётся MagicSpellMod
. Игрок не теряет полёт резко, и заклинание продолжит действие (если соблюдены его условия).
Мод «BuggyMod» ломает мой полёт! Что делать?
Предположим, «BuggyMod» принудительно выполняет player.getAbilities().flying = false;
каждый тик. Благодаря миксину, перехватывающему прямое присваивание, Flight API проверяет: «Является ли BuggyMod текущим владельцем? Нет?»
Присваивание блокируется, и игрок не падает.
В debug.log вашей сборки будет постоянно отображаться:
[MixinPlayerAbilities] Полётом управляет JetpackMod, игнорируем flying=false из NBT
что поможет выявить проблему и сообщить о ней автору мода.
Логика приоритета
По умолчанию FlightManager обрабатывает запросы по принципу FIFO (первым пришёл — первым ушёл). Первый запросивший становится владельцем.