Mineuniverse
Log in Register
Mods

Epic Core API

A library mod that provides powerful entity manipulation APIs through CoreMod (ITransformationService), Java Agent, and VarHandle technologies.
by cjiangqiu
Download Claim this project
9,815 downloads
0 likes
Updated Jul 6, 2026
0 hypes
API and Library

EpicCoreAPI

This mod provides entity manipulation APIs and commands based on CoreMod (ITransformationService), Java Agent, and VarHandle technologies. Note that while method names may resemble vanilla logic, the underlying implementation is completely different. For example, the set health API can modify entities using custom health values (including but not limited to entity data, numeric fields, and hash tables); the remove API performs low-level Minecraft container cleanup; the set invulnerable API provides a more powerful implementation than vanilla creative mode invulnerability. Additionally, this mod unlocks vanilla attribute limits to Double.MAX_VALUE by default. You can disable this in the config file with "Unlock Attribute Limits" option.

The original intent of this mod is to provide developers with simplified entity manipulation APIs while achieving a certain level of strength under the premise of ensuring performance and compatibility. Therefore, please do not use this mod for mod power comparisons or endless code arms races. Additionally, in modpack survival environments, it is best to ensure that the Attack and Defence Radical Logic config options are disabled.

This mod also provides an MCreator plugin for MCreator users to conveniently use the APIs in this mod.

Usage for Players

Players can use the following /eca commands (requires permission level ≥ 2):

  • /eca setHealth <targets> <health> - Set entity health
  • /eca setMaxHealth <targets> <maxHealth> - Set entity max health (reverse-calculates attribute base value)
  • /eca setInvulnerable <targets> <true|false> - Set entity invulnerability
    • /eca lockHealth <targets> true <value> - Lock entity health at specific value
    • /eca lockHealth <targets> false - Unlock entity health
    • /eca lockMaxHealth <targets> true <value> - Lock entity max health at specific value
    • /eca lockMaxHealth <targets> false - Unlock entity max health
    • /eca banHealing <targets> true [value] - Ban healing for entities (value optional, defaults to current health)
    • /eca banHealing <targets> false - Unban healing for entities
    • /eca kill <targets> - Kill entities
  • /eca remove <targets> [reason] - Remove entities from world
  • /eca memoryRemove <targets> - DANGER! Requires Attack Radical Logic config. Remove entities via LWJGL internal channel
  • /eca teleport <targets> <x> <y> <z> - Teleport entities
  • /eca lockLocation <targets> <true|false> [x y z] - Lock/unlock entity location
  • /eca cleanBossBar <targets> - Clean up boss bars
  • /eca allReturn <targets> <true|false> - DANGER! Requires Attack Radical Logic config. Enable/disable return transformation on all boolean and void methods of the target entity's mod
  • /eca allReturn global <true|false> - DANGER! Enable/disable global AllReturn for all non-whitelisted mods
  • /eca banSpawn <targets> <seconds> - Ban spawning of selected entities' types for specified duration
  • /eca banSpawn clear - Unban all spawns in current dimension
  • /eca setForceLoading <targets> <true|false> - Enable/disable force chunk loading for entities
  • /eca setInvulnerable show_all - Show all invulnerable entities
  • /eca entityExtension get_registry - Show entity extension registry
  • /eca entityExtension get_active - Show active entity extension types in current dimension
  • /eca entityExtension get_current - Show the currently effective entity extension
  • /eca entityExtension clear - Clear active entity extension table and all global effects in current dimension
  • /eca entityExtension set_skybox <preset> - Set global skybox shader preset
  • /eca setFilter <targets> true <type> - Apply a screen filter to players (type: sketch, spotlight, matrix, rain, desert, snow, toxic, cosmos)
  • /eca setFilter <targets> false - Remove all active filters from players
  • /eca bossShow edit - Open the in-game cinematic editor (switches to spectator mode)
  • /eca bossShow exit - Exit the editor and restore the previous game mode
  • /eca bossShow list - List all loaded cutscenes
  • /eca bossShow play <viewer> <target> <id> - Force-play a cutscene
  • /eca bossShow stop <viewer> - Stop the viewer's current cutscene
  • /eca bossShow reload - Reload all cutscene JSON definitions from disk
  • /eca bossShow clearHistory <player> - Clear a player's "already seen" records
  • /eca resurrection start - Start the resurrection daemon thread
  • /eca resurrection stop - Stop the resurrection daemon thread
  • /eca resurrection status - Show daemon thread state and revival/check counts
  • /eca resurrection add <targets> - Add entities to resurrection tracking (auto-revived on death every poll cycle)
  • /eca resurrection remove <targets> - Remove entities from resurrection tracking
  • /eca resurrection list - List all tracked entities with container integrity status
  • /eca resurrection check <target> - One-shot container integrity check for an entity
  • /eca resurrection revive <target> - Manually force-revive a tracked entity immediately
  • /eca resurrection interval <ms> - Set poll interval in milliseconds (100–10000; default 25)

Added new command selectors, resolved through ECA's own entity lookup:

  • @eca_e[...] - all entities
  • @eca_p[...] - nearest player
  • @eca_a[...] - all players
  • @eca_r[...] - random player
  • @eca_s[...] - command source entity (self)

Usage for Developers

Adding ECA as Dependency

Step 1: Add Modrinth Maven repository (build.gradle)

repositories {
    maven { url = "https://api.modrinth.com/maven"; content { includeGroup "maven.modrinth" } }
}

Step 2: Add ECA dependency (build.gradle)

dependencies {
    implementation fg.deobf("maven.modrinth:epic-core-api:VERSION")
}

Replace VERSION with the version you need (e.g. 1.1.5-fix-fix). Go to ECA Modrinth page to find available versions.

Step 3: Declare dependency (mods.toml)

[[dependencies.your_mod_id]]
modId="eca"
mandatory=true
versionRange="[1.1.5,)"
ordering="NONE"
side="BOTH"

API Reference

  • lockHealth(entity, value) - Lock entity health at specific value (for invincibility, heal negation, etc.)
  • unlockHealth(entity) - Remove health lock
  • getLockedHealth(entity) - Get current health lock value (null if not locked)
  • isHealthLocked(entity) - Check if entity health is locked
  • banHealing(entity, value) - Ban healing for entity at specified value (entity cannot heal but can take damage)
  • unbanHealing(entity) - Unban healing for entity
  • getHealBanValue(entity) - Get current heal ban value (null if not banned)
  • isHealingBanned(entity) - Check if entity has healing banned
  • getHealth(entity) - Get vanilla health via VarHandle
  • setHealth(entity, health) - Staged health modification that escalates only when a verify step fails: Vanilla (write vanilla DATA_HEALTH_ID directly) → Symbolic (ASM bytecode dataflow analysis of getHealth() to locate and invert the real storage, with numeric fallback on a located storage) → Probe (behavioral probing of candidate numeric setters, name-agnostic) → Dynamic (runtime bytecode instrumentation, requires Attack Radical Logic config). Players only run the Vanilla stage. Each stage is verified against getHealth() within max(1.0, abs(target) * 2%); the first to pass is cached per entity class.
  • setMaxHealth(entity, maxHealth) - Set max health by reverse-calculating attribute base value from current modifiers
  • lockMaxHealth(entity, value) - Lock entity max health at specific value (enforced every tick)
  • unlockMaxHealth(entity) - Unlock entity max health
  • getLockedMaxHealth(entity) - Get current max health lock value (null if not locked)
  • isMaxHealthLocked(entity) - Check if entity max health is locked
  • addHealthWhitelistKeyword(keyword) - Add keyword to health modification whitelist
  • removeHealthWhitelistKeyword(keyword) - Remove keyword from health modification whitelist
  • getHealthWhitelistKeywords() - Get all health whitelist keywords
  • addHealthBlacklistKeyword(keyword) - Add keyword to health modification blacklist
  • removeHealthBlacklistKeyword(keyword) - Remove keyword from health modification blacklist
  • getHealthBlacklistKeywords() - Get all health blacklist keywords
  • kill(entity, damageSource) - Kill entity (loot + advancements + removal)
  • revive(entity) - Clear death state and restore health
  • revive(level, uuid) - Clear death state and restore health by UUID in specified level
  • reviveAllContainers(entity) - Revive all critical entity containers (tickList, lookup, sections, tracker)
  • reviveAllContainers(level, uuid) - Revive all critical entity containers by UUID in specified level
  • teleport(entity, x, y, z) - Teleport via VarHandle with client sync
  • lockLocation(entity) - Lock entity location at current position
  • lockLocation(entity, position) - Lock entity location at specified position
  • unlockLocation(entity) - Unlock entity location
  • isLocationLocked(entity) - Check if entity location is locked
  • getLockedLocation(entity) - Get locked position (null if not locked)
  • remove(entity, reason) - Complete removal (AI, boss bars, containers, passengers)
  • memoryRemove(entity, reason) - DANGER! Requires Attack Radical Logic config. Remove entity via LWJGL internal channel
  • cleanupBossBar(entity) - Remove boss bars without removing entity
  • isInvulnerable(entity) - Check if entity is invulnerable (ECA internal invulnerability logic)
  • setInvulnerable(entity, invulnerable) - Set invulnerability (enable: revive + lock health + block damage + remove harmful effects per tick + prevent mob targeting + protect player inventory; disable: clear all protections)
  • enableAllReturn(entity) - DANGER! Requires Attack Radical Logic config. Performs return transformation on all boolean and void methods of the target entity's mod
  • setGlobalAllReturn(enable) - DANGER! Requires Attack Radical Logic config. Enable/disable global AllReturn for all non-whitelisted mods
  • disableAllReturn() - Disable AllReturn and clear targets
  • isAllReturnEnabled() - Check if AllReturn is enabled
  • addAllReturnWhitelist(prefix) - Add package prefix to AllReturn whitelist (skip AllReturn, defensive hooks still apply)
  • removeAllReturnWhitelist(prefix) - Remove package prefix from AllReturn whitelist (built-in entries cannot be removed)
  • addTransformWhitelist(prefix) - Add package prefix to transform whitelist (skip ALL ECA transformations including defensive hooks)
  • removeTransformWhitelist(prefix) - Remove package prefix from transform whitelist (built-in entries cannot be removed)
  • isAllReturnWhitelisted(className) - Check if a class is protected from AllReturn
  • isTransformWhitelisted(className) - Check if a class is protected from all ECA transformations
  • getAllWhitelistedPackages() - Get all whitelist prefixes (both levels, built-in + custom)
  • getEntityExtensionRegistry() - Get all registered entity extensions (Map<EntityType, EntityExtension>)
  • getActiveEntityExtensionTypes(level) - Get active entity extension types in current dimension (Map<EntityType, Integer>)
  • getActiveEntityExtension(level) - Get the currently effective entity extension (highest priority)
  • clearActiveEntityExtensionTable(level) - Clear active entity extension table in current dimension
  • setGlobalFog(level, fogData) - Set global fog effect override for a dimension (does not change effect priority)
  • clearGlobalFog(level) - Clear global fog effect override
  • setGlobalSkybox(level, skyboxData) - Set global skybox effect override for a dimension (does not change effect priority)
  • clearGlobalSkybox(level) - Clear global skybox effect override
  • setGlobalMusic(level, musicData) - Set global combat music effect override for a dimension (does not change effect priority)
  • clearGlobalMusic(level) - Clear global combat music effect override
  • clearAllGlobalEffects(level) - Clear all global effect overrides (fog, skybox, music) for a dimension
  • enableFilter(player, filterType) - Apply a screen filter to a player (FilterType: SKETCH, SPOTLIGHT, MATRIX, RAIN, DESERT, SNOW, TOXIC, COSMOS)
  • disableFilter(player, filterType) - Remove a screen filter from a player
  • isFilterEnabled(player, filterType) - Check whether a filter is active on a player
  • getActiveFilters(player) - Get a player's active filters (unmodifiable Set<FilterType>)
  • playBossShow(viewer, target, cutsceneId) - Force-play a BossShow cutscene for a viewer (ignores watch history)
  • playBossShowIfNew(viewer, target, cutsceneId) - Play a BossShow cutscene only if the viewer hasn't seen it before
  • stopBossShow(viewer) - Stop the viewer's current BossShow cutscene
  • isBossShowPlaying(viewer) - Check whether the viewer is currently in a BossShow cutscene
  • launchBossShowEvent(eventName, viewer, target) - Trigger all Custom-trigger BossShows matching the event name (returns count launched)
  • banSpawn(level, entityType, seconds) - Ban entity type from spawning for specified duration
  • isSpawnBanned(level, entityType) - Check if entity type is banned from spawning
  • getSpawnBanTime(level, entityType) - Get remaining spawn ban time in seconds
  • unbanSpawn(level, entityType) - Unban entity type, allowing it to spawn again
  • getAllSpawnBans(level) - Get all spawn bans in level (Map<EntityType, Integer>)
  • unbanAllSpawns(level) - Unban all entity types in level
  • setForceLoading(entity, level, forceLoad) - Enable/disable force chunk loading for entity
  • isForceLoaded(entity) - Check if entity is force loaded (via EntityExtension or API)
  • getEntity(level, entityId) - Resolve entity by runtime id in specified level (ECA selector path)
  • getEntity(level, uuid) - Resolve entity by UUID in specified level (ECA selector path)
  • getEntity(level, entityId, entityClass) - Resolve typed entity by id
  • getEntity(level, uuid, entityClass) - Resolve typed entity by UUID
  • getEntity(server, entityId) - Resolve entity by id across all levels
  • getEntity(server, uuid) - Resolve entity by UUID across all levels
  • getEntities(level) - Get all entities in level
  • getEntities(level, area) - Get entities in AABB area
  • getEntities(level, filter) - Get entities using custom predicate
  • getEntities(level, area, filter) - Get entities in area using custom predicate
  • getEntities(level, entityClass) - Get all entities of specified type in level
  • getEntities(level, area, entityClass) - Get entities of specified type in area
  • getEntities(server) - Get all entities across all server levels
  • getEntities(server, filter) - Get entities across all levels using custom predicate
  • startResurrection() - Start the resurrection daemon thread (idempotent)
  • stopResurrection() - Stop the resurrection daemon thread
  • isResurrectionRunning() - Check whether the daemon is running
  • addResurrectionTarget(entity) - Add an entity to the resurrection tracking set
  • removeResurrectionTarget(entity) - Remove an entity from the resurrection tracking set
  • isResurrectionTracked(entity) - Check whether an entity is tracked for resurrection
  • getResurrectionTrackedCount() - Get the number of currently tracked entities
  • clearAllResurrectionTargets() - Remove all entities from the tracking set
  • setResurrectionPollInterval(ms) - Set the daemon poll interval (ms, clamped 1–10000, default 25)
  • getResurrectionPollInterval() - Get the current poll interval in ms
  • getResurrectionTotalRevived() - Get the total number of entities revived since start
  • getResurrectionTotalChecks() - Get the total number of entity checks performed since start
  • checkResurrectionTarget(level, entity) - Perform a one-shot container integrity check
  • reviveResurrectionTarget(level, entity) - Manually force-revive a tracked entity immediately

Here is a simple example:

import net.eca.api.EcaAPI;
import net.eca.network.EntityExtensionOverridePacket.FogData;
import net.eca.network.EntityExtensionOverridePacket.MusicData;
import net.eca.network.EntityExtensionOverridePacket.SkyboxData;
import net.eca.util.entity_extension.EntityExtension;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;

import java.util.Map;
import java.util.Set;

// Health Lock
EcaAPI.lockHealth(entity, 20.0f);
Float locked = EcaAPI.getLockedHealth(entity);
EcaAPI.unlockHealth(entity);

// Heal Ban
EcaAPI.banHealing(entity, entity.getHealth());  // Ban healing at current health
Float banValue = EcaAPI.getHealBanValue(entity);
EcaAPI.unbanHealing(entity);

// Basic Health Access
float realHealth = EcaAPI.getHealth(entity);
EcaAPI.setHealth(entity, 50.0f);

// Max Health
EcaAPI.setMaxHealth(entity, 1024.0f);
EcaAPI.lockMaxHealth(entity, 1024.0f);
Float lockedMax = EcaAPI.getLockedMaxHealth(entity);
EcaAPI.unlockMaxHealth(entity);

// Keyword Management
EcaAPI.addHealthWhitelistKeyword("mana");
EcaAPI.addHealthBlacklistKeyword("timer");
Set<String> whitelist = EcaAPI.getHealthWhitelistKeywords();
Set<String> blacklist = EcaAPI.getHealthBlacklistKeywords();
EcaAPI.removeHealthWhitelistKeyword("mana");
EcaAPI.removeHealthBlacklistKeyword("timer");

// Entity Control
EcaAPI.kill(entity, damageSource);
EcaAPI.revive(entity);
EcaAPI.revive(serverLevel, uuid);  // Revive by UUID
Map<String, Boolean> containerResults = EcaAPI.reviveAllContainers(entity);  // Revive all containers
EcaAPI.reviveAllContainers(serverLevel, uuid);  // Revive all containers by UUID
EcaAPI.teleport(entity, x, y, z);
EcaAPI.lockLocation(entity);  // Lock at current position
EcaAPI.lockLocation(entity, new Vec3(100, 64, 200));  // Lock at specified position
boolean locationLocked = EcaAPI.isLocationLocked(entity);
Vec3 lockedPos = EcaAPI.getLockedLocation(entity);
EcaAPI.unlockLocation(entity);
EcaAPI.remove(entity, Entity.RemovalReason.KILLED);
EcaAPI.memoryRemove(entity, Entity.RemovalReason.CHANGED_DIMENSION);  // Remove using LWJGL internal Unsafe instance
EcaAPI.cleanupBossBar(entity);

// ECA Entity Selector API
Entity byId = EcaAPI.getEntity(level, 123);
Entity byUuid = EcaAPI.getEntity(level, uuid);
List<Entity> allInLevel = EcaAPI.getEntities(level);
List<Entity> inArea = EcaAPI.getEntities(level, new AABB(0, 0, 0, 16, 256, 16));
List<Entity> filtered = EcaAPI.getEntities(level, e -> e.getType() == EntityType.ZOMBIE);
List<LivingEntity> livingInArea = EcaAPI.getEntities(level, new AABB(0, 0, 0, 32, 256, 32), LivingEntity.class);
List<Entity> allServerEntities = EcaAPI.getEntities(server);

// Invulnerability
EcaAPI.setInvulnerable(entity, true);
boolean isInv = EcaAPI.isInvulnerable(entity);
EcaAPI.setInvulnerable(entity, false);

// AllReturn (DANGER! Requires Attack Radical Logic config)
EcaAPI.enableAllReturn(entity);  // Enable for entity's mod
EcaAPI.setGlobalAllReturn(true);  // Enable for ALL non-whitelisted mods
boolean enabled = EcaAPI.isAllReturnEnabled();
EcaAPI.disableAllReturn();  // Disable and clear all AllReturn

// Whitelist — AllReturn level (skip AllReturn only, defensive hooks still apply)
EcaAPI.addAllReturnWhitelist("com.yourmod.");
boolean removed = EcaAPI.removeAllReturnWhitelist("com.yourmod.");
boolean isProtected = EcaAPI.isAllReturnWhitelisted("com.yourmod.YourClass");

// Whitelist — Transform level (skip ALL ECA transformations including defensive hooks)
EcaAPI.addTransformWhitelist("com.yourmod.");
boolean removedTransform = EcaAPI.removeTransformWhitelist("com.yourmod.");
boolean isFullyProtected = EcaAPI.isTransformWhitelisted("com.yourmod.YourClass");

Set<String> allWhitelisted = EcaAPI.getAllWhitelistedPackages();

// Spawn Ban
EcaAPI.banSpawn(serverLevel, EntityType.ZOMBIE, 300);  // Ban zombies for 5 minutes
boolean banned = EcaAPI.isSpawnBanned(serverLevel, EntityType.ZOMBIE);
int remaining = EcaAPI.getSpawnBanTime(serverLevel, EntityType.ZOMBIE);
EcaAPI.unbanSpawn(serverLevel, EntityType.ZOMBIE);
Map<EntityType<?>, Integer> allBans = EcaAPI.getAllSpawnBans(serverLevel);
EcaAPI.unbanAllSpawns(serverLevel);

// Force Loading
EcaAPI.setForceLoading(livingEntity, serverLevel, true);
boolean forceLoaded = EcaAPI.isForceLoaded(livingEntity);
EcaAPI.setForceLoading(livingEntity, serverLevel, false);

// Entity Extension
Map<EntityType<?>, EntityExtension> registry = EcaAPI.getEntityExtensionRegistry();
Map<EntityType<?>, Integer> activeTypes = EcaAPI.getActiveEntityExtensionTypes(serverLevel);
EntityExtension active = EcaAPI.getActiveEntityExtension(serverLevel);
EcaAPI.clearActiveEntityExtensionTable(serverLevel);

// Global Effect Override (directly override fog/skybox/music without entity extension, does not change effect priority)
EcaAPI.setGlobalFog(serverLevel, new FogData(true, 8.0f, 0.0f, 0.0f, 0.0f, 0.02f, 0.25f, 0.0f, 1.0f, 0));
EcaAPI.clearGlobalFog(serverLevel);
EcaAPI.setGlobalSkybox(serverLevel, new SkyboxData(false, null, true, new ResourceLocation("eca", "the_last_end"), 1.0f, 100.0f, 1.0f, 1.0f, 1.0f, 1.0f));
EcaAPI.clearGlobalSkybox(serverLevel);
EcaAPI.setGlobalMusic(serverLevel, new MusicData(new ResourceLocation("your_mod", "music.boss"), 0, 1.0f, 1.0f, true, true));
EcaAPI.clearGlobalMusic(serverLevel);
EcaAPI.clearAllGlobalEffects(serverLevel);

// Resurrection
EcaAPI.startResurrection();
EcaAPI.addResurrectionTarget(entity);
boolean tracked = EcaAPI.isResurrectionTracked(entity);
EcaAPI.removeResurrectionTarget(entity);
EcaAPI.setResurrectionPollInterval(50);
EcaAPI.stopResurrection();

Entity Extensions

This mod also provides a customizable entity type extension feature for adding special visual effects to your entities. You need to create a subclass extending EntityExtension and annotate it with @RegisterEntityExtension to register the extension. Here is a quick start example:

@RegisterEntityExtension
public class MyBossExtension extends EntityExtension {

    static {
        EntityExtensionManager.register(new MyBossExtension());
    }

    public MyBossExtension() {
        super(EntityType.WITHER, 8);  // entity type + priority (in a dimension, some global extension effects like fog, skybox, combat music only apply to the entity extension with the highest priority among existing entities)
    }

    @Override
    public boolean enableForceLoading() {
        return true;  // mark this entity type as force-loaded, avoid using on entities that spawn in large numbers to prevent lag
    }

    @Override
    protected String getModId() {
        return "your_mod_id";  // your mod id, used for all resource path resolution (textures, sounds, etc.)
    }

    @Override
    public boolean enableBossBar() {
        return true;  // master switch for boss bar takeover: whether ECA clears the entity's native boss bar and replaces it with ECA's. Default false — when not enabled, ECA never touches the entity's own boss bar. Must be true for bossBarExtension() / shouldShowBossBar() / custom health override to have any effect
    }

    @Override
    public boolean shouldShowBossBar(LivingEntity entity) {
        return entity != null && entity.isAlive();  // boss bar display condition (only effective when enableBossBar() is true)
    }

    @Override
    public boolean enableCustomHealthOverride() {
        return true;  // if true, ECA custom boss bar current health will be read from getCustomHealthValue() instead of vanilla getHealth()
    }

    @Override
    public Number getCustomHealthValue(LivingEntity entity) {
        return entity.getEntityData().get(YOUR_CUSTOM_HEALTH_DATA);  // the actual value to use as current health (e.g. entity data, custom field), null = fallback to vanilla
    }

    @Override
    public boolean enableCustomMaxHealthOverride() {
        return true;  // if true, ECA custom boss bar max health will be read from getCustomMaxHealthValue() instead of vanilla getMaxHealth()
    }

    @Override
    public Number getCustomMaxHealthValue(LivingEntity entity) {
        return entity.getEntityData().get(YOUR_CUSTOM_MAX_HEALTH_DATA);  // the actual value to use as max health (e.g. entity data, custom field), null = fallback to vanilla
    }

    // Custom boss health bar (requires enableBossBar() = true)
    @Override
    public BossBarExtension bossBarExtension() {
        return new BossBarExtension() {
            @Override public boolean enabled() { return true; }  // enable boss bar
            @Override public ResourceLocation getFrameTexture() { return texture("boss/frame.png"); }  // frame texture (null to skip). If both texture and RenderType are set, shader renders masked by texture alpha
            @Override public ResourceLocation getFillTexture() { return texture("boss/fill.png"); }  // fill texture (null to skip)
            @Override public RenderType getFrameRenderType() { return CustomRenderTypes.BOSS_BAR; }  // frame shader/render type (null to skip)
            @Override public RenderType getFillRenderType() { return CustomRenderTypes.BOSS_BAR; }  // fill shader/render type (null to skip), can use a different preset
            @Override public int getFrameWidth() { return 420; }  // frame pixel width (RenderType-only mode requires this, texture mode auto-detects)
            @Override public int getFrameHeight() { return 40; }  // frame pixel height
            @Override public int getFillWidth() { return 400; }  // fill pixel width (RenderType-only mode requires this, texture mode auto-detects)
            @Override public int getFillHeight() { return 30; }  // fill pixel height
            @Override public int getFrameOffsetX() { return 0; }  // frame X offset
            @Override public int getFrameOffsetY() { return -10; }  // frame Y offset
            @Override public int getFillOffsetX() { return 0; }  // fill X offset
            @Override public int getFillOffsetY() { return 0; }  // fill Y offset
            @Override public float getAlpha() { return 1.0f; }  // overall boss bar opacity, 0.0~1.0 (default 1.0)
        };
    }

    // Entity extra render layer
    @Override
    public EntityLayerExtension entityLayerExtension() {
        return new EntityLayerExtension() {
            @Override public boolean enabled() { return true; }  // enable render layer
            @Override public RenderType getRenderType() { return CustomRenderTypes.BOSS_LAYER; }  // render layer shader/render type
            @Override public boolean isGlow() { return true; }  // extra render layer glowing
            @Override public boolean isHurtOverlay() { return true; }  // show hurt overlay effect on this layer
            @Override public float getAlpha() { return 0.8f; }  // render layer transparency (0.0 ~ 1.0)
        };
    }

    // Global fog
    @Override
    public GlobalFogExtension globalFogExtension() {
        return new GlobalFogExtension() {
            @Override public boolean enabled() { return true; }  // enable fog
            @Override public boolean globalMode() { return true; }  // global mode (ignore radius, always active in dimension)
            @Override public float radius() { return 8.0f; }  // fog activation radius around entity
            @Override public int fogColor() { return 0x000000; }  // fog color as packed RGB int (e.g. 0xFF0000 = red, 0x800080 = purple, 0x000000 = black). Override fogRed/Green/Blue() instead to mix your own color.
            @Override public float terrainFogStart(float renderDistance) { return renderDistance * 0.02f; }  // terrain fog start distance
            @Override public float terrainFogEnd(float renderDistance) { return renderDistance * 0.25f; }  // terrain fog end distance
            @Override public float skyFogStart(float renderDistance) { return 0.0f; }  // sky fog start distance
            @Override public float skyFogEnd(float renderDistance) { return renderDistance; }  // sky fog end distance
            @Override public FogShape fogShape() { return FogShape.SPHERE; }  // fog shape (SPHERE or CYLINDER)
        };
    }

    // Global custom skybox
    @Override
    public GlobalSkyboxExtension globalSkyboxExtension() {
        return new GlobalSkyboxExtension() {
            @Override public boolean enabled() { return true; }  // enable skybox
            @Override public boolean enableTexture() { return true; }  // enable texture-based skybox rendering
            @Override public ResourceLocation texture() { return texture("sky/skybox.png"); }  // skybox texture resource location
            @Override public boolean enableShader() { return true; }  // enable shader-based skybox rendering
            @Override public RenderType shaderRenderType() { return CustomRenderTypes.SKYBOX; }  // skybox shader/render type
            @Override public float alpha() { return 0.9f; }  // skybox transparency (0.0 ~ 1.0)
            @Override public float size() { return 100.0f; }  // skybox quad size
            @Override public float textureUvScale() { return 16.0f; }  // texture UV scale
            @Override public float textureRed() { return 1.0f; }  // texture color red (0.0 ~ 1.0)
            @Override public float textureGreen() { return 1.0f; }  // texture color green (0.0 ~ 1.0)
            @Override public float textureBlue() { return 1.0f; }  // texture color blue (0.0 ~ 1.0)
        };
    }

    // Global combat music
    @Override
    public CombatMusicExtension combatMusicExtension() {
        return new CombatMusicExtension() {
            @Override public boolean enabled() { return true; }  // enable combat music
            @Override public ResourceLocation soundEventId() { return sound("music.boss_battle"); }  // sound event id (must be registered in sounds.json)
            @Override public SoundSource soundSource() { return SoundSource.MUSIC; }  // sound category
            @Override public float volume() { return 1.0f; }  // playback volume (0.0 ~ 1.0)
            @Override public float pitch() { return 1.0f; }  // playback pitch
            @Override public boolean loop() { return true; }  // loop playback
            @Override public boolean strictMusicLock() { return true; }  // block all other MUSIC sounds while active
        };
    }

    // Conditional gate: fog/skybox/music activate only when the matching shouldEnableXxx returns true; re-checked ~once/sec against the dimension's primary entity
    @Override
    public boolean shouldEnableFog(LivingEntity entity) {
        return entity.getHealth() < entity.getMaxHealth() * 0.5f;  // example: fog activates when entity is below 50% health
    }

    @Override
    public boolean shouldEnableSkybox(LivingEntity entity) {
        return true;  // skybox activation condition per entity instance
    }

    @Override
    public boolean shouldEnableMusic(LivingEntity entity) {
        return true;  // combat music activation condition per entity instance
    }

    /*
     * Conditional switching — override the entity-aware overload (on all five extension methods: bossBar / entityLayer / globalFog /
     * globalSkybox / combatMusic) to return a different extension object based on entity state. ECA invokes the entity-aware overload only
     * with a non-null entity (other cases use the no-arg variant) and catches any exception it throws, falling back to the no-arg variant.
     * Global effects re-evaluate ~once/sec against the dimension's primary entity; instance effects (boss bar/render layer) re-evaluate per frame.
     */
    @Override
    public GlobalSkyboxExtension globalSkyboxExtension(LivingEntity entity) {
        if (entity.getHealth() < entity.getMaxHealth() * 0.5f) {
            return phase2Skybox;  // below 50% health: switch to another GlobalSkyboxExtension you defined
        }
        return globalSkyboxExtension();  // default: the no-arg skybox above
    }
}

Item Extensions

You can create item extensions to add shader rendering effects to specific items: create a subclass extending ItemExtension and annotate it with @RegisterItemExtension to register.

import net.eca.api.RegisterItemExtension;
import net.eca.client.render.StarlightRenderTypes;
import net.eca.util.ItemUtil;
import net.eca.util.item_extension.EcaTooltipLine;
import net.eca.util.item_extension.ItemExtension;
import net.eca.util.item_extension.ItemExtensionManager;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.TooltipFlag;

import java.util.List;

@RegisterItemExtension
public class DiamondSwordExtension extends ItemExtension {

    static {
        ItemExtensionManager.register(new DiamondSwordExtension());
    }

    public DiamondSwordExtension() {
        super(Items.DIAMOND_SWORD);  // target item
    }

    @Override
    protected String getModId() {
        return "your_mod_id";
    }

    @Override
    public boolean enabled() {
        return true;  // global master switch — return false to disable this extension entirely
    }

    @Override
    public boolean shouldRender(ItemStack stack) {
        return true;  // per-stack activation condition (e.g. check NBT, enchantment, custom name)
    }

    @Override
    public RenderType getRenderType() {
        return StarlightRenderTypes.ITEM;  // shader overlay RenderType
    }

    @Override
    public float[] getColorKey() {
        /*
         * Only pixels matching this RGB (0.0~1.0) will be overlaid with the shader.
         * Return null to apply the shader to the entire item texture.
         */
        return new float[]{0.25f, 0.83f, 0.73f};
    }

    @Override
    public float getColorKeyTolerance() {
        return 0.3f;  // RGB distance tolerance, 0.0~1.0
    }

    @Override
    public float getAlpha() {
        return 0.8f;  // shader layer transparency, 0.0~1.0 (default 1.0 = fully opaque)
    }

    @Override
    public List<EcaTooltipLine> getTooltipLines(ItemStack stack, TooltipFlag flag) {
        return List.of(
            EcaTooltipLine.head(ItemUtil.of("Starlight Forged")
                .addEffect.GRADIENT(0x7C4DFF, 0x00E5FF)
                .addEffect.BOLD()),
            EcaTooltipLine.body(ItemUtil.of("Arcane resonance: unstable")
                .addEffect.SOLID(0xFFAA00)
                .addEffect.ITALIC()),
            EcaTooltipLine.tail(ItemUtil.of("Hold Shift for hidden lore")
                .addEffect.RAINBOW())
        );
    }
}

Structured tooltip lines can choose their own insertion position:

  • EcaTooltipLine.head(...): below the item name.
  • EcaTooltipLine.body(...): in the main tooltip body, before advanced item id/NBT/disabled lines when present.
  • EcaTooltipLine.tail(...): at the end of the tooltip.

Each line accepts either a normal Component or an EcaText built through ItemUtil.of(...), so tooltip text supports the same rich effects as item names: gradient, rainbow, solid color, shimmer, glitch, bold, italic, underline, and strikethrough. The older appendTooltip(ItemStack, TooltipFlag, List<Component>) hook is still available when you need to directly edit the final tooltip list.

Note: Like entity extensions, each item can only have one extension. Duplicate registrations are rejected with an error log. Both entity layer extensions (EntityLayerExtension.getAlpha(), default 0.5) and item extensions (ItemExtension.getAlpha(), default 1.0) support adjustable transparency for their shader overlay layers.

Shader Presets

This mod also provides several shader presets for the entity extension and item extension systems, which can be used directly in your extensions. Simply replace CustomRenderTypes in the example code with the corresponding preset name. Each preset provides 4 RenderTypes: BOSS_BAR, BOSS_LAYER, SKYBOX for entity extensions, and ITEM for item extensions. Entity texture overlays are supported through EntityLayerExtension.getTexture() — return a texture to overlay it on the entity model, optionally combined with the shader RenderType for a texture‑plus‑shader effect (matching the boss‑bar overlay technique).

Available presets:

  • TheLastEndRenderTypes — The Last End
  • DreamSakuraRenderTypes — Dream Sakura
  • ForestRenderTypes — Forest
  • OceanRenderTypes — Ocean
  • StormRenderTypes — Storm
  • VolcanoRenderTypes — Volcano
  • ArcaneRenderTypes — Arcane
  • AuroraRenderTypes — Aurora
  • HackerRenderTypes — Hacker
  • StarlightRenderTypes — Starlight
  • CosmosRenderTypes — Cosmos
  • BlackHoleRenderTypes — Black Hole

Screen Filters

This mod provides a set of full-screen post-processing filter presets that the server can apply per player, either by command or through the API. A filter is synced to the client and rendered as a shader pass over the level. Each player can have only one filter active at a time — applying a new one replaces the current one.

Filter presets:

  • SKETCH — sketch
  • SPOTLIGHT — spotlight
  • MATRIX — matrix
  • RAIN — rain
  • DESERT — desert
  • SNOW — snow
  • TOXIC — toxic
  • COSMOS — cosmos

Shader Generator

ECA provides an in-game shader preset generator for building portable Minecraft core shader presets without writing GLSL by hand. Open it with:

/eca shaderGenerator

The generator edits a layered composition project. Each layer can contain multiple visual modules, including basic shapes, starry sky effects, magic symbols, and image elements. The editor supports live preview, undo/redo, layer visibility, layer ordering, blend modes, canvas editing, project save/load, and five-file shader export.

Preview targets currently include plane, item, entity, skybox, and Boss bar. The exported preset uses the standard core shader five-file layout:

assets/<namespace>/shaders/core/<name>.fsh
assets/<namespace>/shaders/core/<name>_block.vsh
assets/<namespace>/shaders/core/<name>_block.json
assets/<namespace>/shaders/core/<name>_entity.vsh
assets/<namespace>/shaders/core/<name>_entity.json

The fragment shader is shared by both profiles. The two vertex profiles are generated separately because Minecraft uses different vertex formats for different render targets:

  • <name>_block.* uses DefaultVertexFormat.BLOCK, for skybox, plane preview, and Boss bar rendering.
  • <name>_entity.* uses DefaultVertexFormat.NEW_ENTITY, for entity layers, item layers, and textured entity effects.

Export modes:

  • PORTABLE: standard Minecraft core shader output with no ECA-specific uniforms.
  • PORTABLE_WITH_ECA_HINTS: includes ECA uniform hooks with harmless defaults, while remaining usable without ECA.
  • ECA_ENHANCED: includes ECA-specific uniforms and expects ECA's enhanced shader runtime.

Project files are saved under config/eca/shadergenerator/<namespace>/<name>/project.json. Use File -> Export As <shader> to export a runtime-loadable five-file preset into config/eca/shadergenerator/<namespace>/<name>/. ECA automatically discovers presets from both mod assets and exported config presets. A preset ID is always <namespace>:<name>.

For mod-packaged presets, place the five files under src/main/resources/assets/<namespace>/shaders/core/. You may also declare the preset with @RegisterShaderPreset. The annotation registers the preset ID during startup scanning and is useful for mods that want to expose custom presets through an explicit Java marker class:

import net.eca.api.RegisterShaderPreset;

@RegisterShaderPreset("mymod:my_nebula")
public final class MyNebulaPreset {
}

At runtime, use EcaPresets to obtain the generated RenderTypes:

import net.eca.client.render.preset.EcaPresets;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.resources.ResourceLocation;

public final class MyPresetRenderTypes {
    public static RenderType bossBar() {
        return EcaPresets.bossBar("mymod:my_nebula");
    }

    public static RenderType bossLayer() {
        return EcaPresets.bossLayer("mymod:my_nebula");
    }

    public static RenderType skybox() {
        return EcaPresets.skybox("mymod:my_nebula");
    }

    public static RenderType item() {
        return EcaPresets.item("mymod:my_nebula");
    }
}

You can also query the preset object through EcaAPI:

import net.eca.api.EcaAPI;
import net.eca.client.render.preset.ShaderPreset;
import net.minecraft.resources.ResourceLocation;

ShaderPreset preset = EcaAPI.shaderPreset(new ResourceLocation("mymod", "my_nebula"));

The returned ShaderPreset exposes four ready-made render targets: bossBar(), bossLayer(), skybox(), and item(). For entity texture overlays, use EntityLayerExtension.getTexture() with bossLayer().

BossShow Cinematics

BossShow plays a cutscene that locks the player's camera onto a pre-recorded path around a target entity, with subtitles and server-side event callbacks. Camera paths are recorded with the built-in in-game editor — you don't need to write keyframes by hand.

Default Editor Keybindings:

Key Action
J Start / resume recording
I Pause recording
K Mark current frame as keyframe
ENTER Save recording
ESC Discard recording

Editor Workflow:

  1. Run /eca bossShow edit near at least one LivingEntity (within 64 blocks).
  2. In the Home GUI, click + New cutscene from entity → aim at an entity → right-click to select it as the camera anchor. Or click Edit on an existing cutscene.
  3. Configure trigger type (Range / Custom), target entity type, cinematic bars, allow repeat, etc.
  4. Click ● Record, press J to start. Move the camera freely in spectator mode — each tick is captured as a frame. Press K to mark the current frame as a keyframe at any point.
  5. Edit each keyframe's event_id (triggers server-side Java callbacks), subtitle (displayed text), and curve (easing from this keyframe to the next).
  6. Press ENTER to save, ESC to discard. Saved files go to config/eca/bossshow/<namespace>/<path>.json.

Timeline editing (after recording, in the editor GUI): the bottom timeline bar shows the playhead, keyframe ticks, and the in/out range. Click or drag the bar to scrub — the camera previews that frame in first person. Use Set In / Set Out to mark a range, then Copy / Cut / Delete to operate on it, and Paste to insert the clipboard at the playhead. All edits ripple: frames after the cut shift to close the gap, since a frame's array index is its tick.

For Mod Developers

Two ways to define a cutscene:

  1. JSON only — place a file at data/<modid>/bossshow/<path>.json. Loaded automatically on startup. No Java code needed if you don't need server-side event handling.

  2. Java + JSON — extend BossShow and annotate with @RegisterBossShow to get server-side event callbacks during playback.

JSON example — frames are generated by the recorder; you typically only hand-edit the keyframe sub-objects:

{
  "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,
      "keyframe": { "event_id": "intro", "subtitle": "mymod.bossshow.warden.intro", "curve": "ease_in_out" } },
    { "dx": 0.0, "dy": 1.8, "dz": -4.0, "yaw": 8.0, "pitch": 10.0,
      "keyframe": { "event_id": "finisher", "curve": "step" } }
  ]
}
  • frames: one object per tick, in playback order. A frame's index in the array is its tick — there is no separate time field. Generated by the editor.
  • frames[].dx/dy/dz: camera offset in anchor-local coordinates.
  • frames[].yaw/pitch: camera orientation (yaw is anchor-local).
  • frames[].keyframe: optional. Its presence marks this frame as a keyframe (an empty object {} is a valid bare keyframe). Fields inside:
    • event_id: delivered to BossShow.onKeyframeEvent() on the server. Optional.
    • subtitle: shown on the viewer's screen. Plain text or a translation key (see subtitle override below). Optional.
    • curve: playback easing from this keyframe to the next keyframe — none (default), ease_in, ease_out, ease_in_out, ease_out_in, step, bezier. Only affects camera interpolation speed, not event timing.
  • trigger: {"type":"range","effect_radius":N} auto-triggers when a player enters range of a matching entity. {"type":"custom","event_name":"..."} only fires via EcaAPI.launchBossShowEvent(...).

The old samples + markers format is no longer recognized — files using it load as zero-frame cutscenes. Re-record or migrate to frames.

Event handler example — the event_id strings in the JSON above are dispatched to onKeyframeEvent on the server at the corresponding tick:

@RegisterBossShow
public class WardenIntroShow extends BossShow {
    public static final ResourceLocation ID = new ResourceLocation("mymod", "warden_intro");
    static { BossShowManager.register(new WardenIntroShow()); }

    public WardenIntroShow() { super(ID, EntityType.WARDEN); }

    @Override
    public void onKeyframeEvent(String eventId, BossShowContext ctx) {
        LivingEntity target = ctx.target();
        ServerPlayer viewer = ctx.viewer();
        if (target == null || !target.isAlive()) return;

        switch (eventId) {
            case "intro" -> target.level().playSound(null, target.blockPosition(),
                                SoundEvents.WARDEN_ROAR, SoundSource.HOSTILE, 2f, 1f);
            case "phase2" -> EcaAPI.setInvulnerable(target, true);
            case "finisher" -> EcaAPI.kill(target, target.level().damageSources().generic());
        }
    }

    @Override
    public void onStart(BossShowContext ctx) {
        // called when playback begins
    }

    @Override
    public void onEnd(BossShowContext ctx, boolean skipped) {
        // called when playback ends; skipped = true if the viewer pressed ESC
    }
}

Triggering from code:

EcaAPI.playBossShow(viewer, target, cutsceneId); // force play (ignores history)
EcaAPI.playBossShowIfNew(viewer, target, cutsceneId); // only if viewer hasn't seen it
EcaAPI.launchBossShowEvent("phase2", viewer, target); // match all Custom triggers with this event name
EcaAPI.stopBossShow(viewer); // stop current cutscene
EcaAPI.isBossShowPlaying(viewer); // check if viewer is in a cutscene

If a @RegisterBossShow class has no matching JSON on first launch, an empty template JSON is auto-generated at config/eca/bossshow/<namespace>/<path>.json.

For Modpack Developers

  • Override cutscenes — place your modified JSON at config/eca/bossshow/<namespace>/<path>.json. Config files override mod-bundled definitions (data/<modid>/bossshow/) with the same id.
  • Edit in-game/eca bossShow edit lets you re-record camera paths, adjust triggers, or re-time keyframes (split / copy / cut / delete / paste frame ranges on the timeline). Saves go to config/eca/bossshow/, leaving the mod jar untouched.
  • Translate or rewrite subtitles — create config/eca/bossshow/lang/<locale>.json (e.g. en_us.json, zh_cn.json). These take priority over the mod's own lang files for subtitle keys: json { "mymod.bossshow.warden.intro": "A sound echoes from the deep..." }
  • Hot reload/eca bossShow reload picks up all JSON changes without restarting.

ECA Transformer Whitelist

Although I've added as many common libraries and mods to the ECA Transformer whitelist as possible, there may still be mods that crash due to ECA transformation. So I've prepared a JSON configuration for modpack developers to add package prefixes to the whitelist. You can add JSON files under the config/eca/ folder. If the folder is empty on first launch, example files will be generated automatically.

Only the type and packages fields are required, other fields are ignored:

Single mod example (allreturn — skip AllReturn only, defensive hooks still apply):

{
  "type": "allreturn",
  "packages": [
    "com.example.yourmod."
  ]
}

Multiple mods example (transform — skip ALL ECA transformations):

{
  "type": "transform",
  "packages": [
    "com.example.modA.",
    "com.example.modB.",
    "net.example.modC."
  ]
}

Any .json filename works, and you can have multiple files.

epic-core-api-1.1.5-fix-fix.jar
MC Client, 1.20.1, Forge, Server
Release 2026-06-03 Get
epic-core-api-1.1.5-beta.jar
MC Client, 1.20.1, Forge, Server
Beta 2026-05-06 Get

More from cjiangqiu

Epic journey:Reforge
469
Epic Engine
156
The Last Sword You Never Forgot
12,058

You Might Also Like

Vivecraft
A Minecraft VR mod on a loader of your choice!
9,988,339
Athena
A crossplatform (Forge/Fabric) solution to connected block textures for 1.19.4+
99,799,527
Lodestone
A collection of code used throughout projects under the Lodestar team.
9,914,417
TheDragonLib
A library for most of sokratis12GR's Mods
9,910,232
Multi Mob Library
A library mod containing essential files for Daveyx0's mob mods
9,892,767
FTB Library (Forge) (Legacy)
FTB Library is a library mod that is used for some of our mods.
98,265,314