Epic Core API
Библиотечный мод, предоставляющий мощные API для манипуляции сущностями через технологии CoreMod (ITransformationService), Java Agent и Mixin.
- Загрузчики
- Forge
- Скачиваний на Modrinth
- 31,6 тыс.
- Подписчиков на Modrinth
- 5
- версий
- 39
- Обновлён
- 16 октября 202616 окт.
- Опубликован
- в 2025
Коротко о моде
Нужен и в игре, и на сервере
По личным причинам этот мод не будет получать обновления в течение следующих двух месяцев. В этот период я не буду отвечать на сообщения. Этот мод предоставляет API для манипуляции сущностями и команды на основе технологий CoreMod (ITransformationService), Java Agent и Mixin, а также набор функциональных модулей: BossShow, расширения сущностей, модель ECA Blender, расширения блоков, расширения предметов, экранные фильтры, генератор шейдеров ECA, пользовательские фракции и пользовательские рейды. Учтите, что хотя методы манипуляции сущностями могут совпадать по названиям с ванильной логикой, их внутренняя реализация полностью отличается. Например, API установки здоровья может изменять сущности с помощью пользовательских значений здоровья (включая, помимо прочего, данные сущности, числовые поля и хеш-таблицы); API удаления выполняет низкоуровневую очистку контейнеров Minecraft; API установки неуязвимости предлагает более мощную реализацию, чем неуязвимость ванильного творческого режима. Кроме того, этот мод по умолчанию снимает ограничения ванильных атрибутов до Double.MAX_VALUE. Это можно отключить в файле конфигурации опцией "Unlock Attribute Limits". Изначальная цель этого мода — предоставить разработчикам упрощённые API для манипуляции сущностями, достигая определённого уровня мощности при условии обеспечения производительности и совместимости. Поэтому, пожалуйста, не используйте этот мод для сравнения силы модов или бесконечных гонок вооружений в коде. Кроме того, в условиях выживания в модпаках лучше всего убедиться, что опции конфигурации Attack и Defence Radical Logic отключены. Этот мод также предоставляет плагин для MCreator, чтобы пользователи MCreator могли удобно использовать API этого мода. Community Edition (если вы хотите играть на более новых версиях Minecraft): https://www.curseforge.com/minecraft/mc-mods/epic-core-api-community-port-neoforge
Использование для игроков
Игроки могут использовать следующие команды /eca (требуется уровень разрешений ≥ 2):
- `/eca setHealth [report]
— Установить здоровье сущности. Добавьтеreport, чтобы записать один структурированный файлhealth_report.txtдля каждой живой цели прямо в папкуlogs/`; отчёт включает определение модели здоровья, результат по каналам, отложенную проверку, полную трассировку инверсии потока данных по каждому источнику и связанный фоновый анализ. - `/eca setMaxHealth ` — Установить максимальное здоровье сущности (обратный пересчёт базового значения атрибута)
- `/eca setInvulnerable <true|false>` — Установить неуязвимость сущности
- `/eca lockHealth true ` — Заблокировать здоровье сущности на определённом значении
- `/eca lockHealth false` — Разблокировать здоровье сущности
- `/eca lockMaxHealth true ` — Заблокировать максимальное здоровье сущности на определённом значении
- `/eca lockMaxHealth false` — Разблокировать максимальное здоровье сущности
- `/eca banHealing true [value]` — Не позволять затронутым сущностям превышать заданное значение запрета лечения (необязательно; по умолчанию — текущее здоровье).
- `/eca banHealing false` — Снять запрет лечения с сущностей
- `/eca hurt ` — Принудительно нанести урон сущности (сначала ванильный урон, принудительная запись, если потеря здоровья не сработала; при выполнении живой сущностью засчитывается убийство исполнителю)
- `/eca kill ` — Убить сущности
- `/eca remove [reason]` — Удалить сущности из мира
- `/eca memoryRemove ` — ОПАСНО! Требуется конфигурация Attack Radical Logic. Удалить сущности с помощью внутреннего экземпляра Unsafe из LWJGL
- `/eca teleport ` — Телепортировать сущности на указанные координаты в их текущем измерении.
- `/eca lockLocation <true|false> [x y z]` — Заблокировать/разблокировать местоположение сущности
- `/eca cleanBossBar ` — Очистить полосы боссов
- `/eca allReturn <true|false>` — ОПАСНО! Требуется Attack Radical Logic. Включить или отключить AllReturn по запросу; для игроков целью являются моды, владеющие предметами в четырёх слотах брони и двух слотах рук, а для остальных сущностей — их собственный мод. Применяются белые списки трансформаций.
/eca allReturn global <true|false>— ОПАСНО! Включить/отключить глобальный AllReturn для всех модов, не входящих в белый список- `/eca banSpawn ` — Запретить спавн типов выбранных сущностей на указанное время
/eca banSpawn clear— Снять все запреты спавна в текущем измерении- `/eca setForceLoading <true|false>` — Включить/отключить принудительную загрузку чанков для сущностей
/eca setInvulnerable show_all— Показать все неуязвимые сущности/eca entityExtension get_registry— Показать реестр расширений сущностей/eca entityExtension get_active— Показать активные типы расширений сущностей в текущем измерении/eca entityExtension get_current— Показать текущее действующее расширение сущности/eca entityExtension clear— Очистить таблицу активных расширений сущностей и все глобальные эффекты в текущем измерении- `/eca entityExtension set_skybox ` — Установить глобальный пресет шейдера неба
- `/eca setFilter true ` — Применить экранный фильтр к игрокам (тип: sketch, spotlight, matrix, rain, desert, snow, toxic, cosmos)
- `/eca setFilter false` — Убрать все активные фильтры с игроков
/eca bossShow edit— Открыть внутриигровой редактор катсцен (переключает в режим наблюдателя)/eca bossShow exit— Выйти из редактора и восстановить предыдущий режим игры/eca bossShow list— Показать все загруженные катсцены- `/eca bossShow play ` — Принудительно воспроизвести катсцену
- `/eca bossShow stop ` — Остановить текущую катсцену у зрителя
/eca bossShow reload— Перезагрузить все JSON-определения катсцен с диска- `/eca bossShow clearHistory ` — Очистить записи «уже просмотрено» у игрока
/eca shaderGenerator— Открыть внутриигровой генератор пресетов шейдеров/eca resurrection start— Запустить демон-поток воскрешения/eca resurrection stop— Остановить демон-поток воскрешения/eca resurrection status— Показать состояние демон-потока и количество воскрешений/проверок- `/eca resurrection add ` — добавить сущности в отслеживание воскрешения (автоматически возрождаются при смерти каждый цикл опроса)
- `/eca resurrection remove ` — убрать сущности из отслеживания воскрешения
/eca resurrection list— список всех отслеживаемых сущностей со статусом целостности контейнера- `/eca resurrection check ` — разовая проверка целостности контейнера для сущности
- `/eca resurrection revive ` — вручную немедленно возродить отслеживаемую сущность
- `/eca resurrection interval ` — задать интервал опроса в миллисекундах (100–10000; по умолчанию 25)
- `/eca faction create [color]` — создать фракцию (color принимает имя пресета, например red/gold/teal)
- `/eca faction remove ` — удалить определение фракции и отбросить все привязки сущностей, указывающие на неё
- `/eca faction join [targets]` — привязать сущности к фракции (по умолчанию — сущность-источник команды)
/eca faction leave [targets]— отвязать сущности от текущей фракции/eca faction list— список всех зарегистрированных фракций/eca faction info [factionId]— показать цвет фракции, участников и переопределения отношений- `/eca faction relation
— задать отношение A к B.hostile/neutral/friendlyсохраняют переопределение отношения;same_faction` вместо этого сливает B в A (участники B перепривязываются к A, отношения складываются, а B удаляется) - `/eca faction leader ` — показать лидера фракции и загружен ли он сейчас
- `/eca faction leader set [target]` — назначить лидера (по умолчанию — сущность-источник команды; автоматически вступает во фракцию)
- `/eca faction leader clear` — очистить лидера; бывший лидер остаётся участником
/eca raid defs— список всех зарегистрированных определений рейдов/eca raid list— список активных рейдов в текущем измерении- `/eca raid start [pos]` — начать рейд в позиции внутри его целевой структуры (по умолчанию — позиция источника команды)
- `/eca raid startat ` — начать рейд с явным центром, пропуская поиск структуры
- `/eca raid info ` — показать подробности одного запущенного рейда
- `/eca raid end <victory|defeat>` — завершить рейд и очистить всех выживших рейдеров Добавлены новые селекторы команд, разрешаемые через собственный поиск сущностей ECA:
@eca_e[...]— все сущности@eca_p[...]— ближайший игрок@eca_a[...]— все игроки@eca_r[...]— случайный игрок@eca_s[...]— сущность-источник команды (сам)
Использование для разработчиков
Добавление ECA как зависимости
Шаг 1: Добавьте репозиторий Modrinth Maven (build.gradle)
repositories {
maven { url = "https://api.modrinth.com/maven"; content { includeGroup "maven.modrinth" } }
}Шаг 2: Добавьте зависимость ECA (build.gradle)
dependencies {
implementation fg.deobf("maven.modrinth:epic-core-api:VERSION")
}Замените
VERSIONна нужную версию (например,1.1.7-fix-fix). Доступные версии ищите на странице ECA на Modrinth. Шаг 3: Объявите зависимость (mods.toml)[[dependencies.your_mod_id]] modId="eca" mandatory=true versionRange="[1.1.5,)" ordering="NONE" side="BOTH"Справочник API
lockHealth(entity, value)— зафиксировать здоровье сущности на конкретном значении (для неуязвимости, отмены лечения и т.п.)unlockHealth(entity)— снять фиксацию здоровьяgetLockedHealth(entity)— получить текущее зафиксированное значение здоровья (null, если не зафиксировано)isHealthLocked(entity)— проверить, зафиксировано ли здоровье сущностиbanHealing(entity, value)— не позволять здоровью затронутой сущности превышать заданное значение запрета лечения.unbanHealing(entity)— снять запрет лечения для сущностиgetHealBanValue(entity)— получить текущее значение запрета лечения (null, если запрета нет)isHealingBanned(entity)— проверить, запрещено ли лечение сущностиgetHealth(entity)— если анализ модификации здоровья ECA определил реальное здоровье сущности, вернуть его; иначе вернуть ванильные данные здоровья сущности. Это чтение не запускает анализ и не откатывается кgetHealth()сущности; для null-сущности возвращает 0.0f, для нечитаемого хранилища — NaN.getRealHealth(entity)— использует те же правила чтения, что иgetHealth(entity), но для null-сущности возвращает NaN.setHealth(entity, health)— попытка проверенного изменения здоровья через ванильную прямую запись → обращение потока данных → внешнее сканирование → зондирование метода → числовую инверсию; для игроков используется только ванильная запись. Анализ потока данных находит хранилище и инвертирует выражения чтения, включая отслеживаемый доступ через рефлексию, Unsafe и VarHandle. Новые данные зондирования могут вернуть к более ранним каналам. Каналы ограничены данными, конфигурацией и бюджетами, с проверкой после попыток и снимками/откатом для зондирующих записей. Немедленная проверка не гарантирует, что логика сущности сохранит значение на последующих тиках; отложенная проверка проверяет это отдельно. Базовое обращение потока данных доступно по умолчанию, если не включён Force Compatibility Mode. Const Override, External Scan, Method Probe и Numeric Inversion требуют Attack Radical Logic и соответствующих переключателей вAttack → setHealth, которые по умолчанию выключены.setMaxHealth(entity, maxHealth)— задать максимальное здоровье, обратно вычисляя базовое значение атрибута из текущих модификаторовlockMaxHealth(entity, value)— зафиксировать максимальное здоровье сущности на конкретном значении (применяется каждый тик)unlockMaxHealth(entity)— снять фиксацию максимального здоровьяgetLockedMaxHealth(entity)— получить текущее зафиксированное значение максимального здоровья (null, если не зафиксировано)isMaxHealthLocked(entity)— проверить, зафиксировано ли максимальное здоровье сущностиaddHealthWhitelistKeyword(keyword)— добавить ключевое слово в белый список модификации здоровьяremoveHealthWhitelistKeyword(keyword)— удалить ключевое слово из белого списка модификации здоровьяgetHealthWhitelistKeywords()— получить все ключевые слова белого списка здоровьяaddHealthBlacklistKeyword(keyword)— добавить ключевое слово в чёрный список модификации здоровья
removeHealthBlacklistKeyword(keyword)— удалить ключевое слово из чёрного списка изменения здоровьяgetHealthBlacklistKeywords()— получить все ключевые слова чёрного списка здоровьяhurt(entity, damageSource, amount)— нанести урон сущности и гарантировать, что потеря здоровья действительно произойдёт. Ванильныйhurtзаписывает здоровье только один раз, внутриactuallyHurt, какsetHealth(getHealth() - damage)— через собственные геттер и сеттер сущности, поэтому сущность с переопределёнными методами или отделённым хранилищем проходит весь конвейер и вызывает все события, не теряя здоровья. Этот метод сбрасывает кулдаун неуязвимости и сначала вызывает ванильныйhurt(снижение урона, отбрасывание, агро и анимация получения урона происходят как обычно), затем сравнивает опорное значение здоровья сbefore - amountв пределахmin(1.0, amount * 50%). При несовпадении он восстанавливает учёт источника урона, который оставил бы ванильный код (lastHurtByMob, lastHurtByPlayer/Time, lastDamageSource/Stamp, боевой трекер, анимация получения урона), и принудительно задаёт здоровье черезsetHealthс ограничением снизу нулём. Смертельный результат здесь никогда не форсируется в путь смерти: сущность остаётся с нулевым здоровьем, чтобы ванильныйtickDeathпроиграл анимацию смерти и удалил её — используйтеkill, если нужно немедленное убийство. Сущности под собственным локом здоровья или неуязвимостью ECA оставляются этим системам — ванильныйhurtвсё равно выполняется, но принудительная запись не предпринимается.hurt(entity, attacker, amount)— тот же конвейер с источником урона, выведенным из атакующего:playerAttackдля игроков,mobAttackдля любой другой живой сущности, чтобы засчитывание убийства и распределение добычи работали как ожидаетсяkill(entity, damageSource)— убить сущность (добыча + достижения + удаление)revive(entity)— сбросить состояние смерти и восстановить здоровьеrevive(level, uuid)— сбросить состояние смерти и восстановить здоровье по UUID в указанном измеренииreviveAllContainers(entity)— оживить все критичные контейнеры сущности (tickList, lookup, sections, tracker)reviveAllContainers(level, uuid)— оживить все критичные контейнеры по UUID в указанном измеренииteleport(entity, x, y, z)— принудительно телепортировать сущность в указанные координаты в её текущем измерении и синхронизировать клиентов. Должно выполняться в главном потоке сервера.lockLocation(entity)— зафиксировать местоположение сущности на текущей позицииlockLocation(entity, position)— зафиксировать местоположение сущности на указанной позицииunlockLocation(entity)— снять фиксацию местоположения сущностиisLocationLocked(entity)— проверить, зафиксировано ли местоположение сущностиgetLockedLocation(entity)— получить зафиксированную позицию (null, если не зафиксирована)remove(entity, reason)— полное удаление (ИИ, босс-бары, контейнеры, пассажиры)memoryRemove(entity, reason)— ОПАСНО! Требуется конфиг Attack Radical Logic. Удалить сущность с помощью внутреннего экземпляра Unsafe из LWJGLcleanupBossBar(entity)— удалить босс-бары без удаления сущностиisInvulnerable(entity)— проверить, неуязвима ли сущность (внутренняя логика неуязвимости ECA)setInvulnerable(entity, invulnerable)— задать неуязвимость (включение: оживление + лок здоровья + блокировка урона + удаление вредных эффектов каждый тик + предотвращение нацеливания мобов + защита инвентаря игрока; выключение: снятие всех защит)enableAllReturn(entity)— ОПАСНО! Требуется Attack Radical Logic. Включает AllReturn для мода сущности; для игроков нацеливается на моды, владеющие их бронёй и снаряжением в основной и побочной руке. Преобразуются только подходящие boolean- и void-методы согласно белым спискам преобразований.disableAllReturn(entity)— отключить AllReturn по тем же правилам выбора цели, что и включение: моды брони и снаряжения в основной и побочной руке для игроков или собственный мод сущности для остальных сущностей.setGlobalAllReturn(enable)— ОПАСНО! Требуется конфиг Attack Radical Logic. Включить/отключить глобальный AllReturn для всех модов вне белого спискаdisableAllReturn()— отключить AllReturn и очистить целиisAllReturnEnabled()— проверить, включён ли AllReturnaddAllReturnWhitelist(prefix)— добавить префикс пакета в белый список AllReturn (пропуск AllReturn, защитные хуки всё равно применяются)removeAllReturnWhitelist(prefix)— удалить префикс пакета из белого списка AllReturn (встроенные записи удалить нельзя)addTransformWhitelist(prefix)— добавить префикс пакета в белый список преобразований (пропуск ВСЕХ преобразований ECA, включая защитные хуки)removeTransformWhitelist(prefix)— удалить префикс пакета из белого списка преобразований (встроенные записи удалить нельзя)isAllReturnWhitelisted(className)— проверить, защищён ли класс от AllReturnisTransformWhitelisted(className)— проверить, защищён ли класс от всех преобразований ECAgetAllWhitelistedPackages()— получить все префиксы белого списка (оба уровня, встроенные + пользовательские)getEntityExtensionRegistry()— получить все зарегистрированные расширения сущностей (Map<EntityType, EntityExtension>)getActiveEntityExtensionTypes(level)— получить активные типы расширений сущностей в текущем измерении (Map<EntityType, Integer>)getActiveEntityExtension(level)— получить текущее действующее расширение сущности (наивысший приоритет)clearActiveEntityExtensionTable(level)— очистить таблицу активных расширений сущностей в текущем измеренииplayAnimation(entity, animation)— вручную взять управление и запустить именованное действие модели со скоростью 1 без зацикливания (логический поток сервера)playAnimation(entity, animation, speed, loop)— вручную запустить/перезапустить именованное действие модели с заданной скоростью и зацикливанием (логический поток сервера)stopAnimation(entity)— остановить управляемое воспроизведение, отменить активный навык, если он есть, и вернуть управление контроллеру/резервной логикеpauseAnimation(entity)— приостановить тайминг управляемого действия/навыка, не замораживая решения жизненного циклаresumeAnimation(entity)— возобновить тайминг управляемого действия/навыка с сохранённой позицииisAnimationPlaying(entity[, animation])— запросить состояние управляемого воспроизведения, включая приостановленные/удерживаемые позы, при желании с совпадением имени действияtriggerBlenderSkill(entity, skillId)— запустить настроенный навык согласно его политике прерыванияcancelBlenderSkill(entity)— отменить активный навык без колбэка завершенияisBlenderSkillActive(entity)— проверить выполнение активного навыка, включая паузыgetBlenderSkillExecution(entity)— получить текущий снимок выполнения или nullsetGlobalFog(level, fogData)— задать глобальное переопределение эффекта тумана для измерения (не меняет приоритет эффектов)clearGlobalFog(level)— очистить глобальное переопределение эффекта туманаsetGlobalSkybox(level, skyboxData)— задать глобальное переопределение эффекта скайбокса для измерения (не меняет приоритет эффектов)clearGlobalSkybox(level)— очистить глобальное переопределение эффекта скайбоксаsetGlobalMusic(level, musicData)— задать глобальное переопределение эффекта боевой музыки для измерения (не меняет приоритет эффектов)clearGlobalMusic(level)— очистить глобальное переопределение эффекта боевой музыкиclearAllGlobalEffects(level)— очистить все глобальные переопределения эффектов (туман, скайбокс, музыка) для измеренияenableFilter(player, filterType)— применить экранный фильтр к игроку (FilterType: SKETCH, SPOTLIGHT, MATRIX, RAIN, DESERT, SNOW, TOXIC, COSMOS)disableFilter(player, filterType)— убрать экранный фильтр с игрокаisFilterEnabled(player, filterType)— проверить, активен ли фильтр у игрокаgetActiveFilters(player)— получить активные фильтры игрока (неизменяемый Set)playBossShow(viewer, target, cutsceneId)— принудительно проиграть катсцену BossShow для зрителя (игнорирует историю просмотров)playBossShowIfNew(viewer, target, cutsceneId)— проиграть катсцену BossShow, только если зритель её ещё не виделstopBossShow(viewer)— остановить текущую катсцену BossShow у зрителяisBossShowPlaying(viewer)— проверить, находится ли зритель сейчас в катсцене BossShowlaunchBossShowEvent(eventName, viewer, target)— запустить все BossShow с триггером Custom, совпадающие с именем события (возвращает число запущенных)banSpawn(level, entityType, seconds)— запретить спавн типа сущности на указанное времяisSpawnBanned(level, entityType)— проверить, запрещён ли спавн типа сущностиgetSpawnBanTime(level, entityType)— получить оставшееся время запрета спавна в секундахunbanSpawn(level, entityType)— снять запрет спавна с типа сущности, разрешив ему снова появлятьсяgetAllSpawnBans(level)— получить все запреты спавна в измерении (Map<EntityType, Integer>)unbanAllSpawns(level)— снять все запреты спавна в измеренииsetForceLoading(entity, level, forceLoad)— включить/выключить принудительную загрузку чанков для сущностиisForceLoaded(entity)— проверить, принудительно ли загружена сущность (через EntityExtension или API)getEntity(level, entityId)— найти сущность по runtime id в указанном измерении (путь селектора ECA)getEntity(level, uuid)— найти сущность по UUID в указанном измерении (путь селектора ECA)getEntity(level, entityId, entityClass)— найти типизированную сущность по idgetEntity(level, uuid, entityClass)— найти типизированную сущность по UUIDgetEntity(server, entityId)— найти сущность по id во всех измеренияхgetEntity(server, uuid)— найти сущность по UUID во всех измеренияхgetEntities(level)— получить все сущности в измеренииgetEntities(level, area)— получить сущности в области AABBgetEntities(level, filter)— получить сущности по пользовательскому предикатуgetEntities(level, area, filter)— получить сущности в области по пользовательскому предикатуgetEntities(level, entityClass)— получить все сущности указанного типа в измеренииgetEntities(level, area, entityClass)— получить сущности указанного типа в областиgetEntities(server)— получить все сущности во всех измерениях сервераgetEntities(server, filter)— получить сущности во всех измерениях по пользовательскому предикатуgetNearestEntity(level, pos, filter)— получить ближайшую сущность, подходящую под предикат (резолвер ECA, поэтому неуязвимые сущности тоже учитываются)getNearestEntity(level, pos, area, filter)— то же, но в пределах AABBgetNearestEntity(level, pos, entityClass)— получить ближайшую сущность заданного типаgetNearestEntity(level, pos, area, entityClass)— получить ближайшую сущность заданного типа внутри AABBshaderPreset(id)— получить шейдерный пресет по id, предоставляющий готовые цели рендераstartResurrection()— запустить демон-поток воскрешения (идемпотентно)stopResurrection()— остановить демон-поток воскрешенияisResurrectionRunning()— проверить, запущен ли демонaddResurrectionTarget(entity)— добавить сущность в набор отслеживания воскрешенияremoveResurrectionTarget(entity)— убрать сущность из набора отслеживания воскрешенияisResurrectionTracked(entity)— проверить, отслеживается ли сущность для воскрешенияgetResurrectionTrackedCount()— получить число отслеживаемых сущностей в данный моментclearAllResurrectionTargets()— убрать все сущности из набора отслеживанияsetResurrectionPollInterval(ms)— задать интервал опроса демона (мс, ограничен 1–10000, по умолчанию 25)getResurrectionPollInterval()— получить текущий интервал опроса в мсgetResurrectionTotalRevived()— получить общее число воскрешённых сущностей с момента запускаgetResurrectionTotalChecks()— получить общее число проверок сущностей с момента запускаcheckResurrectionTarget(level, entity)— выполнить разовую проверку целостности контейнераreviveResurrectionTarget(level, entity)— вручную немедленно воскресить отслеживаемую сущностьcreateFaction(id, displayName, color)— создать и зарегистрировать фракцию (только в памяти)createFaction(id, displayName, color, level)— создать и зарегистрировать фракцию с сохранением в SavedData мираremoveFaction(id)— удалить определение фракции (только в памяти)removeFaction(id, level)— удалить определение фракции и отбросить все привязки сущностей, указывающие на неёmergeFactions(intoId, fromId, level)— слить одну фракцию в другую: участники перепривязываются, переопределения отношений объединяются, а поглощённая фракция удаляется. Возвращает число перемещённых участников или -1, если слияние не удалось выполнитьgetFaction(id)— получить определение фракции по idgetAllFactions()— получить все зарегистрированные фракцииjoinFaction(entity, factionId)— привязать сущность к фракцииleaveFaction(entity)— отвязать сущность от её фракцииgetEntityFaction(entity)— получить id фракции, к которой принадлежит сущность (null, если нет; прирученные животные наследуют фракцию владельца)areSameFaction(a, b)— проверить, принадлежат ли две сущности к одной фракцииisFriendly(a, b)— проверить полное дружественное отношение: одна/дружественная фракция ECA, альянс по ванильному скорборду или альянс владельца с питомцем (исключает creative, spectator и неуязвимость ECA)getFactionMembers(level, factionId)— преобразовать таблицу участников фракции в живые сущности в одном измеренииkickAllFromFaction(factionId, level)— удалить всех явных участников глобально, включая невыгруженных и находящихся в других измеренияхsetFactionRelation(a, b, relation)— задать отношение фракции A к фракции B (только в памяти)setFactionRelation(a, b, relation, level)— задать отношение фракции A к B с сохранениемgetFactionRelation(a, b)— получить явное отношение от A к B (null, если переопределения нет)getEffectiveFactionRelation(source, target)— определить действующее отношение между двумя сущностямиcanHarm(source, target)— проверить, позволяют ли отношения фракций ECA источнику навредить целиcanTarget(source, target)— проверить, позволяют ли полные правила фракций и защиты источнику намеренно выбрать цельalertFactionMembers(factionId, attacker, victim, level)— заставить ближайших союзников без цели ответить атакующемуjoinFaction(uuid, typeId, isPlayer, factionId, level)— привязать сущность к фракции по UUID, не требуя её загрузкиleaveFaction(uuid, level)— удалить участника из его фракции по UUID, не требуя его загрузкиgetEntityFaction(uuid)— получить фракцию, привязанную к UUID (чистый поиск по индексу; без наследования питомцев, для которого нужна живая сущность)isFactionMember(uuid, factionId)— проверить, принадлежит ли UUID к конкретной фракцииgetFactionMemberRecords(factionId)— получить все записи участников (UUID + тип сущности) без загрузки сущностейgetFactionMemberUuids(factionId)— получить все UUID участников без загрузки сущностейgetFactionMembersByType(factionId, typeId)— отфильтровать участников по типу сущности без загрузки сущностейgetFactionMemberCount(factionId)— получить количество участников фракции без загрузки сущностейresolveFactionMembers(factionId, level)— преобразовать участников фракции в живые сущности в одном измеренииsetFactionLeader(factionId, leader, level)— назначить лидера фракции (при необходимости автоматически вступает во фракцию)clearFactionLeader(factionId, level)— снять лидера; бывший лидер остаётся участникомgetFactionLeader(factionId)— получить запись лидера без загрузки сущностиgetFactionLeaderUuid(factionId)— получить UUID лидераresolveFactionLeader(factionId, server)— преобразовать лидера в живую сущность, ища во всех измеренияхisFactionLeader(entity)— проверить, возглавляет ли сущность какую-либо фракциюgetFactionByLeader(uuid)— найти, какую фракцию возглавляет сущностьstartRaid(level, pos, raidId)— начать рейд в позиции внутри целевой структуры (центр берётся из структуры)startRaidAt(level, center, raidId)— начать рейд с явным центром, пропуская поиск структурыendRaid(level, raid, victory)— завершить рейд, удалив всех выживших рейдеровendRaid(level, raidId, victory)— завершить рейд по id экземпляра, удалив всех выживших рейдеровgetRaid(level, raidId)— получить активный рейд по id экземпляраgetActiveRaids(level)— получить все активные рейды в измеренииgetNearestRaid(level, pos, maxDistance)— найти ближайший активный рейд в пределах расстоянияgetAllRaidDefinitions()— получить все зарегистрированные определения рейдов
Расширения сущностей
Этот мод также предоставляет настраиваемое расширение типов сущностей для добавления особых визуальных эффектов вашим сущностям. Нужно создать подкласс, расширяющий EntityExtension, и пометить его аннотацией @RegisterEntityExtension, чтобы зарегистрировать расширение. Расширения сущностей могут включить собственный боссбар через enableBossBar(), управлять видимостью с помощью shouldShowBossBar(LivingEntity) и задавать внешний вид на клиенте через bossBarExtension(). BossBarExtension.showValueText() включает центрированный текст current/max; переопределите getDisplayCurrentValue(LivingEntity) и getDisplayMaxValue(LivingEntity), чтобы задать собственные отображаемые значения. По умолчанию значения берутся из здоровья сущности и максимального здоровья. Шейдерные оверлеи сущностей, предметов и блоков используют один и тот же конвейер ShaderMaskPass. Каждый проход задаёт RenderType, необязательную UV-выровненную текстуру маски, целевой цвет RGB (по умолчанию чёрный), допуск по близости цвета и непрозрачность. Расширение может вернуть несколько проходов, чтобы разные цвета в одной маске использовали разные шейдеры. Проходы рендерятся в порядке списка, и более поздние проходы рисуются поверх более ранних там, где выбранные области пересекаются. Прозрачные и несовпадающие пиксели маски отбрасываются.
Модель ECA Blender
ECA Blender Model позволяет использовать нативные файлы .blend или экспортированные GLB-файлы для моделей и анимаций сущностей. Модели могут заменять исходный внешний вид сущности или рендериться вместе с ним. Можно настроить анимации покоя, движения, получения урона и смерти, запускать именованные навыки и использовать колбэки анимаций для эффектов по времени или логики попаданий. Контроллеры можно настраивать, переопределяя их методы. Поддерживаемые узлы геометрии и материалов также могут анимироваться независимо от действий персонажа, что полезно для эффектов вроде вращающихся колец. Нативная поддержка .blend экспериментальна и рассчитана на Blender 5.2.1. Примеры настройки, API воспроизведения и поддерживаемые узлы см. в README.
Расширения блоков
Расширения блоков добавляют шейдерные оверлеи без замены обычной модели. Обычные запечённые и падающие блоки используют проходы профиля BLOCK из getBlockShaderPasses(); блок-сущности GeckoLib используют проходы профиля NEW_ENTITY из getGeoShaderPasses(texture). Логический id пресета по-прежнему задаёт RenderType по умолчанию для обоих профилей. Внешние маски на запечённых блоках сэмплируются с UV-координатами спрайта, хотя модель использует атлас. Гео-маски используют обычную UV-разметку текстуры модели и объединяются с overlayGeoBones() как пересечение. Обычные блоки мира индексируются по секциям и группируются в отдельный проход оверлея; падающие блоки и блок-сущности GeckoLib обрабатываются автоматически. Блок-предметы остаются частью ItemExtension. Старые геттеры Color-Key и одиночной маски объявлены устаревшими адаптерами совместимости.
Расширения предметов
Вы можете создавать расширения предметов, чтобы добавлять шейдерные эффекты рендеринга конкретным предметам: создайте подкласс, наследующий ItemExtension, и пометьте его аннотацией @RegisterItemExtension для регистрации. Структурированные строки подсказок могут выбирать собственное место вставки:
EcaTooltipLine.head(...): под названием предмета.EcaTooltipLine.body(...): в основном теле подсказки, перед строками advanced item id/NBT/disabled, если они есть.EcaTooltipLine.tail(...): в конце подсказки. Каждая строка принимает либо обычныйComponent, либоEcaText, созданный черезItemUtil.of(...), поэтому текст подсказки поддерживает те же богатые эффекты, что и названия предметов: градиент, радугу, сплошной цвет, мерцание, глитч, жирный, курсив, подчёркивание и зачёркивание. Старый хук `appendTooltip(ItemStack, TooltipFlag, List)по-прежнему доступен, когда нужно напрямую отредактировать итоговый список подсказки. Проходы масок предметов автоматически используют UV-координаты спрайта.ShaderMaskPass.masked(...)сэмплирует внешнюю текстуру маски, аShaderMaskPass.baseTexture(...)выбирает цвета напрямую из текстуры предмета. Старые геттерыgetRenderType(), Color-Key и одиночной маски объявлены устаревшими адаптерами совместимости. Примечание: как и расширения сущностей, каждый предмет может иметь только одно расширение. Повторные регистрации отклоняются с записью ошибки в лог. И расширения слоёв сущностей (EntityLayerExtension.getAlpha(), по умолчанию 0.5), и расширения предметов (ItemExtension.getAlpha()`, по умолчанию 1.0) поддерживают настраиваемую прозрачность своих шейдерных слоёв оверлея.
Пресеты шейдеров
Упакованные файлы, специфичные для ECA, используют общую структуру `assets//eca//. Серверные определения используют соответствующую структуру data//eca//, а стандартные ресурсы Minecraft, такие как текстуры и языковые файлы, остаются в своих ванильных каталогах. Устаревшие расположения, описанные в более ранних версиях ECA, продолжают загружаться как запасные варианты.
Этот мод также предоставляет несколько пресетов шейдеров для систем расширения сущностей и расширения предметов, которые можно использовать напрямую в своих расширениях. Просто используйте соответствующий класс пресета вместо собственного держателя RenderType. Каждый встроенный класс пресета предоставляет 4 готовых RenderType — BOSS_BAR, BOSS_LAYER, SKYBOXдля расширений сущностей иITEMдля расширений предметов — плюсcreateEntityEffect(texture)для текстурных оверлеев сущностей. Текстурные оверлеи сущностей поддерживаются черезEntityLayerExtension.getTexture()` — верните текстуру, чтобы наложить её на модель сущности, при желании в сочетании с шейдерным RenderType для эффекта «текстура плюс шейдер» (по той же технике, что и оверлей полосы босса). Доступные пресеты:
TheLastEndRenderTypes— The Last EndDreamSakuraRenderTypes— Dream SakuraForestRenderTypes— ForestOceanRenderTypes— OceanStormRenderTypes— StormVolcanoRenderTypes— VolcanoArcaneRenderTypes— ArcaneAuroraRenderTypes— AuroraHackerRenderTypes— HackerStarlightRenderTypes— StarlightCosmosRenderTypes— CosmosBlackHoleRenderTypes— Black Hole
Экранные фильтры
Этот мод предоставляет набор пресетов полноэкранных фильтров постобработки, которые сервер может применять каждому игроку — командой или через API. Фильтр синхронизируется с клиентом и рендерится как шейдерный проход поверх уровня. У каждого игрока одновременно может быть активен только один фильтр — применение нового заменяет текущий. Пресеты фильтров:
SKETCH— набросокSPOTLIGHT— прожекторMATRIX— матрицаRAIN— дождьDESERT— пустыняSNOW— снегTOXIC— токсичныйCOSMOS— космос
Генератор шейдеров
ECA предоставляет внутриигровой генератор пресетов шейдеров для создания переносимых пресетов ядерных шейдеров Minecraft без ручного написания GLSL. Откройте его командой:
/eca shaderGeneratorГенератор редактирует проект слоистой композиции. Каждый слой может содержать несколько визуальных модулей, включая базовые фигуры, эффекты звёздного неба, магические символы и элементы изображений. Редактор поддерживает живой предпросмотр, отмену/повтор, видимость слоёв, порядок слоёв, режимы смешивания, редактирование холста, сохранение/загрузку проекта, экспорт шейдера из пяти файлов и удаление проекта (File -> Delete Current Project, что запрашивает подтверждение и затем безвозвратно удаляет каталог проекта вместе с исходниками, текстурами и импортированными зависимостями).
У каждого проекта также есть рабочее пространство исходников из пяти файлов. Используйте File -> Source Editor, чтобы переключить тот же проект на ручное редактирование GLSL/JSON с меню в одну строку, быстрой навигацией по комментариям, отменой/повтором, сохранением, горячими клавишами компиляции и живым предпросмотром с задержкой. Справа предпросмотр расположен над прокручиваемой панелью вывода компилятора. Сгенерированные фрагментные шейдеры выводят маркеры // @eca-nav layer: ... и // @eca-nav element: ...; вручную написанные комментарии // @eca-nav ... создают пользовательские точки навигации. Возврат в визуальный редактор не отбрасывает ни одно из представлений. File -> Import Shader Folder открывает системный выбор папки в канонической игровой директории Forge и копирует выбранный шейдер JSON/VSH/FSH в новый локальный проект ECA. Папка может содержать несколько шейдерных программ — в этом случае редактор спросит, какую импортировать. Если путь к исходникам находится ниже `assets//, диалог проекта заранее заполняет этот Mod ID; иначе поле остаётся пустым. Стандартные трёхфайловые шейдеры дублируются в слоты исходников BLOCK и NEW_ENTITY для независимой проверки компиляции; папки с пятифайловой раскладкой ECA с общими фрагментами _block/_entityсохраняют оба профиля напрямую. Папка исходников никогда не изменяется.
Импорт поддерживает стандартные ресурсы ядровых шейдеров Minecraft JSON/VSH/FSH. Общие юниформы времени, камеры, масштаба, непрозрачности и cosmic-UV получают привязки для предпросмотра. Шейдеру, который зависит от специфичного для мода конвейера рендера, Java-колбэков, текстур или юниформов, всё ещё может понадобиться отдельный адаптер; неподдерживаемая структура фрагмента сообщается как ошибка компиляции, а не переписывается молча.
Зависимости от текстур также разрешаются. Когда импортированный шейдер ссылается на нумерованную последовательность PNG-файлов, ECA пытается скопировать эти файлы, объединить их в одну текстуру предпросмотра и предоставить соответствующий сэмплер и юниформ с UV-диапазоном каждого изображения. PNG с анимационной секцией.mcmeta` обновляется кадр за кадром внутри этой объединённой текстуры, сохраняя порядок кадров, длительность каждого кадра и интерполяцию. Если ECA не может определить, как файлы соответствуют сэмплеру или юниформу, панель вывода компилятора называет неразрешённую зависимость и просканированную директорию вместо молчаливого сбоя; сама компиляция шейдера при этом может пройти успешно. Цели предпросмотра сейчас включают плоскость, предмет, сущность, скайбокс и полосу босса. Экспортированный пресет использует стандартную пятифайловую раскладку ядрового шейдера:
assets/<namespace>/eca/shader_presets/<name>.fsh
assets/<namespace>/eca/shader_presets/<name>_block.vsh
assets/<namespace>/eca/shader_presets/<name>_block.json
assets/<namespace>/eca/shader_presets/<name>_entity.vsh
assets/<namespace>/eca/shader_presets/<name>_entity.jsonФрагментный шейдер общий для обоих профилей. Два вершинных профиля генерируются отдельно, потому что Minecraft использует разные форматы вершин для разных целей рендера:
- `_block.*
используетDefaultVertexFormat.BLOCK` — для скайбокса, предпросмотра плоскости и рендера полосы босса. - `_entity.*
используетDefaultVertexFormat.NEW_ENTITY` — для слоёв сущностей, слоёв предметов и текстурированных эффектов сущностей. Режимы экспорта: PORTABLE: вывод стандартного ядрового шейдера Minecraft без специфичных для ECA юниформов.PORTABLE_WITH_ECA_HINTS: включает хуки юниформов ECA с безвредными значениями по умолчанию, оставаясь работоспособным без ECA.ECA_ENHANCED: включает специфичные для ECA юниформы и требует расширенного рантайма шейдеров ECA. Файлы проекта сохраняются в `config/eca/shadergenerator///project.json`. Используйте **File -> Export As **, чтобы экспортировать загружаемый в рантайме пятифайловый пресет в `config/eca/shadergenerator///. ECA автоматически обнаруживает пресеты как в ресурсах мода, так и в экспортированных пресетах конфига. ID пресета всегда имеет вид:. Для пресетов, упакованных в мод, разместите пять файлов вsrc/main/resources/assets//eca/shader_presets/. Устаревшее расположениеassets//shaders/core/по-прежнему поддерживается, но канонический путь ECA имеет приоритет, когда оба определяют один и тот же ID. Вы также можете объявить пресет с помощью@RegisterShaderPreset. Аннотация регистрирует ID пресета во время сканирования при запуске и полезна для модов, которые хотят предоставить пользовательские пресеты через явный Java-маркерный класс. В рантайме получайте сгенерированные RenderType черезEcaPresetsили запрашивайте объект пресета черезEcaAPI.shaderPreset(id). ВозвращаемыйShaderPresetпредоставляетbossBar(),bossLayer(),skybox(),item(),block(),geoBlock(texture)иentityForPreview(texture);EcaPresetsповторяет первые шесть как статические поиски по id пресета.block()иgeoBlock(texture)— это профили BLOCK и NEW_ENTITY, используемые расширениями блоков. Для наложений текстур сущностей используйтеEntityLayerExtension.getTexture()сbossLayer()`.
AI Assistant
В редакторе исходников также есть AI-ассистент, который управляет тем же проектом через выбранную вами модель. Поддерживаются три формата API — OpenAI Responses, совместимый с OpenAI Chat и Anthropic Messages — каждый хранится как профиль с собственным базовым URL, моделью, API-ключом или переменной окружения для ключа, пользовательскими заголовками и таймаутом от 10 до 600 секунд в config/eca/shadergenerator/settings.json. Модель действует через инструменты, а не свободным текстом: читает сводку проекта и схемы модулей, редактирует слои и элементы, импортирует PNG-изображения, изменяет любой из пяти файлов исходников, сохраняет проект, экспортирует пять файлов шейдера, компилирует и читает диагностику, делает снимок предпросмотра и отменяет или повторяет собственные изменения. Три переключателя ограничивают, насколько далеко она действует самостоятельно — разрешить автоматические правки, компилировать после каждой правки, отправлять изображения предпросмотра моделям с поддержкой зрения. При выключенном автоматическом редактировании она всё ещё может изучать и объяснять, но каждая запись отклоняется; при включённой автоматической компиляции она перекомпилирует после каждой правки и исправляет по диагностике, ограничиваясь лимитом автоматических исправлений и общим лимитом раундов инструментов.
MCP
Кнопка MCP на странице AI-ассистента запускает локальный ECA Shader MCP, который позволяет внешнему агенту управлять текущим проектом шейдеров. Сервис работает по Streamable HTTP, привязан только к 127.0.0.1 и не требует токена доступа; на странице MCP отображаются порт и подключённые агенты, а порт хранится в config/eca/shadergenerator/mcp_settings.json. Порт в URL должен совпадать с портом на странице MCP, и Minecraft, и сервис MCP должны оставаться запущенными. Порядок действий: сначала запусти сервис в игре через Shader Generator → AI Assistant → MCP, затем запускай и подключай агента. Агент не сможет подключиться, пока сервис не запущен.
Codex
Регистрация из командной строки:
codex mcp add eca_shader --url http://localhost:8767/mcpClaude Code
Регистрация из командной строки:
claude mcp add --transport http eca_shader http://127.0.0.1:8767/mcpBossShow Cinematics
BossShow проигрывает катсцену, которая привязывает камеру игрока к заранее записанному пути вокруг целевой сущности, с субтитрами и серверными колбэками событий. Пути камеры записываются встроенным редактором в игре — писать кейфреймы вручную не нужно. Клавиши редактора по умолчанию:
| Клавиша | Действие |
|---|---|
J | Начать / продолжить запись |
I | Приостановить запись |
ENTER | Сохранить запись |
ESC | Отменить запись |
Работа в редакторе:
- Выполни
/eca bossShow editрядом хотя бы с одной LivingEntity (в пределах 64 блоков). - В главном GUI нажми + New cutscene from entity → наведись на сущность → кликни правой кнопкой, чтобы выбрать её якорем камеры. Или нажми Edit у существующей катсцены.
- Настрой тип триггера (Range / Custom), тип целевой сущности, кинематографические полосы, разрешение повтора и т. д.
- Нажми ● Record, затем
J, чтобы начать. Свободно двигай камеру в режиме наблюдателя — каждый тик записывается как редактируемый кадр. - После записи кликни любой тик на таймлайне, чтобы отредактировать его позицию и ориентацию камеры. Используй Preview, чтобы проиграть таймлайн. Чтобы переснять позу из игрового вида, нажми Free camera write, подвинь камеру и нажми Enter, чтобы записать текущий тик.
- Нажми
ENTER, чтобы сохранить,ESC— чтобы отменить. Сохранённые файлы попадают в `config/eca/bossshow//.json. **Редактирование таймлайна** (после записи, в GUI редактора): каждый кадр можно выбрать. Кликай или тяни полосу для прокрутки, используй стрелки для перехода по одному тику и редактируйdx/dy/dz/yaw/pitchв инспекторе. Используй **Add content**, чтобы прикрепить событие или субтитр к текущему тику. Для редактирования таймлайна доступны **Set In** / **Set Out**, **Copy** / **Cut** / **Delete**, **Paste**, равномерные и нарастающие смещения диапазона, а такжеCtrl+Z/Ctrl+Y. Инерция полёта во время записи по умолчанию отключена. ВключиBossShow -> Enable Recording Flight Inertia` в конфигурации, чтобы сохранить ванильную инерцию. Для разработчиков модов Есть два способа задать катсцену: - Только JSON — положи файл в `data//eca/bossshow/.json
. Загружается автоматически при запуске. Старый путьdata//bossshow/.json` по-прежнему поддерживается. Java-код не нужен, если тебе не нужна обработка событий на сервере. - Java + JSON — наследуй
BossShowи добавь аннотацию@RegisterBossShow, чтобы получать серверные колбэки событий во время проигрывания. Пример JSON текущей версии v4. Этот минимальный пример содержит всего 3 кадра (тики 0–2, 0.15 секунды при 20 TPS), поэтому его события, субтитры и эффекты тоже укладываются в этот диапазон. Для полноценной катсцены запиши в редакторе более длинный трек камеры и размести контент на нужных тиках:
{
"format_version": 4,
"target_type": "minecraft:warden",
"trigger": { "type": "range", "effect_radius": 32.0 },
"cinematic": true,
"allow_repeat": false,
"anchor_yaw": 0.0,
"frames": [
{ "dx": 0.0, "dy": 1.8, "dz": -6.0, "yaw": 0.0, "pitch": 10.0 },
{ "dx": 0.0, "dy": 1.8, "dz": -5.8, "yaw": 2.0, "pitch": 10.0 },
{ "dx": 0.0, "dy": 1.8, "dz": -5.6, "yaw": 4.0, "pitch": 10.0 }
],
"events": [
{ "tick": 0, "event_id": "intro" },
{ "tick": 2, "event_id": "finisher" }
],
"subtitles": [
{ "tick": 0, "text": "mymod.bossshow.warden.intro" }
],
"effects": [
{ "tick": 0, "type": "camera_shake", "duration": 2, "fade_out": 1,
"parameters": { "yaw": 1.5, "pitch": 1.0, "roll": 0.5, "frequency": 1.2 } },
{ "tick": 2, "type": "shader_effect", "effect": "chromatic_aberration",
"duration": 1,
"parameters": { "strength": 0.012, "angle": 15.0, "pulse_amount": 0.4, "pulse_speed": 2.0 } }
]
}format_version: текущий вывод —4; смещения позиции и поворот камеры используют одно и то же соглашение о повороте относительно якоря. Старые файлы на основе кадров конвертируются при загрузке с помощьюanchor_yaw; не переноси их, меняя только номер версии.frames: один объект на тик, в порядке проигрывания. Индекс кадра в массиве — это его тик, отдельного поля времени нет. Генерируется редактором.frames[].dx/dy/dz: смещение камеры в координатах относительно якоря.frames[].yaw/pitch: ориентация камеры (yaw относительно якоря).events: независимая дорожка событий. Каждая запись содержитtickиevent_id; записи передаются вBossShow.onKeyframeEvent()на этом тике.subtitles: независимая дорожка субтитров. Каждая запись содержитtickиtext; текст может быть буквальным или ключом перевода.effects: клиентская дорожка экранных эффектов с длительностью, затуханием, сглаживанием и параметрами конкретного эффекта. Типы:camera_shake,shader_effectиfilter.frames[].keyframe: устаревшее поле совместимости. Новые файлы должны использоватьeventsиsubtitles.trigger:{"type":"range","effect_radius":N}срабатывает автоматически, когда игрок входит в радиус подходящей сущности.{"type":"custom","event_name":"..."}срабатывает только черезEcaAPI.launchBossShowEvent(...).
Старый формат
samples+markersбольше не распознаётся — файлы с ним загружаются как катсцены с нулём кадров. Перезапиши их или перенеси наframes.
Строки event_id из JSON выше передаются в onKeyframeEvent на сервере в соответствующий тик, а катсцены также можно запускать из кода через EcaAPI.playBossShow(...) / launchBossShowEvent(...).
Если у класса с
@RegisterBossShowпри первом запуске нет соответствующего JSON, пустой шаблон JSON автоматически создаётся по пути `config/eca/bossshow//.json`. Для разработчиков модпаков
- Переопределение катсцен — положите изменённый JSON в `config/eca/bossshow//.json
. Файлы конфигурации переопределяют определения из мода (data//eca/bossshow/, с поддержкой устаревшего путиdata//bossshow/`) с тем же id.- Редактирование в игре —
/eca bossShow editпозволяет заново записывать пути камеры, редактировать позу любого тика, настраивать триггеры, добавлять события и субтитры, а также работать с диапазонами кадров (копировать / вырезать / удалять / вставлять). Сохранения идут вconfig/eca/bossshow/, не затрагивая jar мода.Перевод или переписывание субтитров — создайте `config/eca/bossshow/lang/.json
(например,en_us.json,zh_cn.json`). Они имеют приоритет над собственными lang-файлами мода для ключей субтитров:{ "mymod.bossshow.warden.intro": "A sound echoes from the deep..." }- Горячая перезагрузка —
/eca bossShow reloadподхватывает все изменения JSON без перезапуска.Пользовательские фракции
ECA предоставляет систему фракций, управляющую выбором целей и отношениями урона. Привязка сущности заставляет ванильные проверки союзников и назначение целей учитывать правила своей фракции, дружественных и нейтральных отношений без необходимости реализовывать интерфейс. Мобы, привязанные к фракции, периодически выбирают в качестве цели ближайших привязанных к фракции сущностей с отношением
HOSTILEчерезMob.setTarget; их существующие боевые цели по-прежнему выполняют движение и атаки. Сущности без фракции никогда не выбираются этим проходом выбора целей. Стандартные пути нанесения уронаLivingEntityобеспечивают защиту дружественных; прямые API, изменяющие состояние, остаются на ответственности вызывающего.FactionUtil.isFriendlyопределяет союзы, аFactionUtil.canAttackдополнительно учитывает защиту в творческом/наблюдательном режиме и неуязвимость ECA.EcaAPI.isFriendly(a, b)— публичная полная проверка дружественности. Она возвращает true для одной и той же фракции ECA, дружественных фракций ECA, ванильных союзников по таблице очков, пар владелец-питомец, питомцев с одним владельцем и питомцев, чьи владельцы — союзники по таблице очков. Творческий режим, наблюдательный режим и неуязвимость ECA намеренно исключены, поскольку это защита от атак, а не союзные отношения. ИспользуйтеareSameFaction, только когда важна точная идентичность фракции ECA;canHarmпроверяет только отношения фракций ECA, аcanTargetдополнительно отклоняет нейтральные отношения и полную невосприимчивость к выбору цели. Фракции регистрируются путём наследованияFactionDefinitionи аннотирования класса@RegisterFaction. Определения сканируются во времяFMLLoadCompleteEvent; дублирующиеся id логируются и пропускаются (побеждает первый отсканированный). Фракции также можно создавать во время выполнения черезEcaAPI.createFaction, с сохранением или без.EntityExtensionможет объявитьgetFactionId(), чтобы каждая сущность этого типа автоматически вступала во фракцию — фракция должна быть зарегистрирована до появления этих сущностей, иначе привязка отклоняется и логируется. Доступны четыре отношения:
SAME_FACTION— одинаковый id фракции, полная взаимная неуязвимость и никогда не выбираются в качестве целейFRIENDLY— разные фракции, но союзные, без урона и без выбора целейNEUTRAL— намеренно не выбираются в качестве целей, но случайный урон всё равно применяетсяHOSTILE— обычный бойSAME_FACTIONвычисляется, а не хранится: оно возникает всякий раз, когда обе стороны разрешаются в один и тот же id фракции, поэтому хранение его как межфракционного переопределения никогда не было бы прочитано обратно. Сделать две фракции действительно одной значит объединить их —EcaAPI.mergeFactions(intoId, fromId, level), который/eca faction relation A B same_factionвызывает, оставляя A выжившей. Члены B перепривязываются к A, переопределения отношений B наследуются только там, где у A нет своих, сторонние записи, указывающие на B, перенаправляются на A или отбрасываются, после чего B удаляется. A сохраняет своё отображаемое имя, цвет, отношение по умолчанию и лидера, наследуя лидера B только если у неё его нет. Разрешение отношений выполняется в таком порядке, и первое совпадение побеждает:
- Одинаковый id фракции →
SAME_FACTION- Условное переопределение
getRelation(self, target)у A- Статические массивы
hostileTo/friendlyTo/neutralToу A- Симметричный запасной вариант — те же две проверки, вычисленные со стороны B
- Условное переопределение
getDefaultRelation(self, target)у A (только когда у другой стороны нет фракции)- Статическое отношение по умолчанию у A Каждая фракция владеет своей таблицей членов. Член записывается как UUID плюс его тип сущности, поэтому список можно перечислить, отфильтровать по типу и подсчитать, не загружая ни одной сущности — члены в незагруженных чанках или других измерениях всё равно полностью видны и управляемы. Фракции хранятся в SavedData оверворлда, поэтому членство глобально для всех измерений и переживает перезапуски. Привязка сбрасывается, когда сущность удаляется навсегда; выгрузка чанков и смена измерения её сохраняют, а игроки сохраняют свою при смерти и возрождении. Членство не может пережить свою фракцию — отмена регистрации фракции сбрасывает всю её таблицу членов, а вступление во фракцию, которой не существует, отклоняется, а не записывается молча. Прирученные животные автоматически наследуют фракцию своего владельца, поэтому питомец защищён союзниками владельца и может откликаться на оповещения фракции поблизости. Наследование разрешается во время поиска, а не хранится: унаследованный питомец не включается в постоянную таблицу членов, офлайн-запросы, подсчёты или распространение лидера на всю таблицу. Он следует за владельцем при смене фракции и никогда не создаёт собственную привязку — поэтому вызов
leaveFactionдля такого питомца ничего не делает. Привяжите питомца явно, если он должен принадлежать к другой фракции или участвовать в операциях с таблицей членов; явная привязка всегда имеет приоритет над наследованием.
Фракция владеет только составом участников, отношениями и руководством. FactionDefinition не предоставляет API для состава сущностей или весов спавна; эти значения принадлежат системе, выполняющей спавн, поэтому разные системы могут использовать одну и ту же фракцию, не разделяя правила спавна. Лидеры: Фракция может назначить одного участника своим лидером. Установка лидера автоматически добавляет его во фракцию, если он не был участником — лидер вне собственной фракции был бы противоречивым состоянием. Выход из фракции также освобождает пост, а лидер, удалённый навсегда, очищается автоматически. Распространение угрозы: Когда лидер атакует враждебного участника фракции или подвергается его атаке, эта сущность предлагается в качестве цели каждому разрешимому мобу из таблицы участников фракции. Существующие цели и разрешения на цели фракции всё ещё могут помешать переключению. На обычные оповещения участников откликаются ближайшие мобы как из собственной фракции жертвы, так и из дружественных фракций. Сосуществуют два механизма:
| Триггер | Радиус | |
|---|---|---|
| Защита лидера | лидер атакует или подвергается атаке | вся таблица участников |
| Оповещение участников | любой участник получает урон | настраиваемый радиус вокруг жертвы |
Защита лидера намеренно не ограничена радиусом: таблица участников обходится напрямую, поэтому призванные существа вдали от хозяина всё равно откликаются. Участники, которых нельзя разрешить в измерении лидера, пропускаются, и распространение никогда не выдаёт участнику цель, которую ему запрещено атаковать. Повторное распространение одной и той же цели в пределах одного тика отбрасывается, поэтому быстро атакующий лидер не обходит таблицу при каждом ударе. Оба механизма полностью управляются конфигом — переопределений на уровне фракций нет, поэтому каждая фракция ведёт себя одинаково на данном сервере:
Leader Protection Enabled(по умолчаниюtrue)Immediate Leader Protection(по умолчаниюfalse)Alert Enabled(по умолчаниюtrue) /Alert Range(по умолчанию32) /Immediate Member Alert(по умолчаниюfalse) «Immediate» выключено означает, что вступят в бой только участники, у которых сейчас нет цели; включено — они бросают то, с чем сражались. Запросы: Членство можно проверить с обеих сторон, а методы, не разрешающие сущности, работают полностью офлайн:Направление Методы связь сущностей areSameFaction(a, b)(только одна и та же фракция ECA),isFriendly(a, b)(полная проверка ECA + ванильная дружественность),getEffectiveFactionRelation(a, b),canHarm(a, b)(только правила вреда фракций ECA),canTarget(a, b)(проверка цели с учётом нейтралитета и иммунитета)участник → фракция getEntityFaction(entity)(включает наследование питомцев),getEntityFaction(uuid),isFactionMember(uuid, id)фракция → участники getFactionMemberRecords(id),getFactionMemberUuids(id),getFactionMembersByType(id, typeId),getFactionMemberCount(id)фракция → сущности resolveFactionMembers(id, level)фракция → лидер getFactionLeader(id),getFactionLeaderUuid(id),resolveFactionLeader(id, server)(ищет во всех измерениях)лидер → фракция getFactionByLeader(uuid),isFactionLeader(entity)У
joinFactionиleaveFactionесть перегрузки с UUID для управления участниками, чья сущность не загружена. Участники фракции также могут светиться для ближайших игроков цветом своих отношений — это настраивается и по умолчанию выключено.
Пользовательские рейды
ECA предоставляет настраиваемую систему рейдов. Ванильный рейд работает только с деревнями, принимает только сущности, реализующие Raider, и жёстко задаёт условие победы и награды; рейд ECA может нацеливаться на любую структуру, использовать любой тип сущности и заменять каждое правило, определяющее его ход и завершение. Рейды регистрируются путём расширения RaidDefinition с аннотацией @RegisterRaid. Сканирование выполняется после сканирования фракций, поэтому определение рейда может свободно ссылаться на id фракций. Обязательны только getId(), getDisplayName() и getWaves() — всё остальное имеет рабочее значение по умолчанию, смоделированное по ванильному рейду. Нацеливание: Переопределите getTargetStructure() для одной структуры или getTargetStructureTag() для совпадения с любой структурой, несущей тег, чтобы один рейд применялся к нескольким типам структур. Привязка определяет условие поражения по умолчанию: рейд проигран, когда целевая структура больше не покрывает центр рейда. Если не объявлено ни то, ни другое, рейд идёт без привязки, и в этом случае он может завершиться только победой, таймаутом или явным вызовом завершения. Волны: Каждый RaidWave свободно смешивает два источника спавна — явные записи сущностей и addFaction(String factionId, int count, Map<EntityType<?>, Integer> typeWeights), чьи типы сущностей и веса настраиваются прямо на этой волне. Разные волны могут использовать разные составы и веса для одной и той же фракции. Рейдеры: Явные записи, добавленные через addEntry(...), привязываются к getRaiderFactionId(), а каждая группа addFaction(...) привязывается к собственному id фракции этой записи. Лидеры волн также используют getRaiderFactionId(). Заспавненные экземпляры Mob получают внедрённую цель, которая ведёт их к центру рейда. Цель по умолчанию имеет приоритет 3, как ванильная PathfindToRaidGoal — ниже обычной цели ближней атаки, поэтому рейдеры сражаются с уже захваченной целью враждебной фракции, а иначе продвигаются вперёд. Можно заспавнить любой тип сущности, и никакой интерфейс не требуется, но сущности, не являющиеся Mob, не получают ни захвата цели фракции, ни навигационной цели, ни колбэков мобов. Переопределите getRaiderGoalPriority() или верните отрицательное значение, чтобы изменить или отключить внедрение цели. Босс: Волна может объявить лидера через RaidWave.setLeader(type). Заспавненная сущность становится лидером фракции рейдеров рейда, поэтому распространение угрозы фракции применяется к ней бесплатно. Подходящие загруженные мобы без существующей цели откликаются по умолчанию; Immediate Leader Protection позволяет им заменить существующую цель. Объявление лидера требует getRaiderFactionId(); без фракции вести некого, и запись спавнится как обычный рейдер.
Учтите, что распространение обходит всю таблицу участников фракции, а не только участников этого рейда. Если у фракции рейдеров есть другие члены в мире, они тоже откликнутся. Используйте фракцию, специфичную для рейда, если хотите ограничить отклик только рейдом. Валидация: запуск рейда проверяет фракции, на которые он ссылается. Непустая, но незарегистрированная фракция рейдеров отклоняет запуск сразу, поскольку запрошенные правила дружественного огня и оповещения не могут быть применены. Намеренный возврат null разрешён и оставляет каждую заспавненную сущность под управлением её собственного ИИ. Волна, берущая данные из незарегистрированной фракции или без положительных весов сущностей, логирует ошибку и пропускает эту группу, но рейд всё равно начинается. Прогрессия: shouldAdvanceWave, checkVictory и checkDefeat можно переопределять. Значения по умолчанию воспроизводят ванильную семантику: следующая волна спавнится, когда предыдущая мертва, а защитники побеждают, когда все волны заспавнены и все рейдеры уничтожены. Тайминги и колбэки: getMaxDurationTicks() по умолчанию равен 48000, getWaveCooldownTicks() — 300, getParticipantRadius() — 96 блоков, а getCelebrationTicks() — 600. Волна может добавить свои spawnDelay() и spawnRadius(). Хуки жизненного цикла — onStart, onWaveStart, onWaveEnd, onVictory, onDefeat и onStop. Клиентский bossBarExtension() может заменить внешний вид полосы рейда, сохраняя синхронизированное с сервером состояние рейда. Бесконечные рейды: isEndless() зацикливает список волн навсегда и никогда не выполняет условие победы по умолчанию. Завершите такой рейд через EcaAPI.endRaid, который уничтожает всех выживших рейдеров. Рейды выполняются отдельно для каждого измерения и автоматически восстанавливают последний периодический чекпоинт после перезапуска. Безвозвратные потери и терминальные операции сохраняются немедленно; обычная прогрессия чекпоинтится раз в секунду. Центральный чанк принудительно загружается на всё время рейда, но рейдеры, уходящие в другие незагруженные чанки, вместе с ним не подгружаются. Регистрация определения ничего не запускает. Рейды запускаются явно через EcaAPI.startRaid(...) / startRaidAt(...), чтобы их могло запускать любое условие-триггер — вход в регион, использование предмета, команда, запланированное событие.
Белый список ECA Transformer
Хотя я добавил в белый список ECA Transformer как можно больше распространённых библиотек и модов, всё ещё могут найтись моды, падающие из-за трансформации ECA. Поэтому я подготовил JSON-конфигурацию для разработчиков модпаков, чтобы добавлять префиксы пакетов в белый список. Вы можете добавлять JSON-файлы в папку config/eca/. Если при первом запуске папка пуста, примеры файлов будут сгенерированы автоматически. Обязательны только поля type и packages, остальные поля игнорируются: Пример одного мода (allreturn — пропускать только AllReturn, защитные хуки всё равно применяются):
{
"type": "allreturn",
"packages": [
"com.example.yourmod."
]
}Пример нескольких модов (transform — пропускать ВСЕ трансформации ECA):
{
"type": "transform",
"packages": [
"com.example.modA.",
"com.example.modB.",
"net.example.modC."
]
}Подходит любое имя файла .json, и файлов может быть несколько.
Частые вопросы
Как установить Epic Core API?
Установите Forge под свою версию Minecraft, скачайте Epic Core API под ту же версию и загрузчик, положите файл в папку mods и запустите игру с профилем загрузчика.
Для каких версий Minecraft есть Epic Core API?
У Epic Core API есть сборки для Minecraft 1.20.1.
Нужен ли Epic Core API на сервере?
Нужен и в игре, и на сервере