Epic Core API

Epic Core API

A library mod that provides powerful entity manipulation APIs through CoreMod (ITransformationService), Java Agent, and VarHandle technologies.

by
8.5K Downloads
forgelibrary
Rent Server with this Mod

Screenshots

Eca Command
Boss Show

About this Mod

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.

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

Usage for Players

Use /eca command (requires OP 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 restore <targets> <true|false> - DANGER! Requires Attack Radical Logic config. Force/cancel an entity instance delegating its core lifecycle methods (getHealth, setHealth, hurt, die, etc.) to vanilla LivingEntity behaviour
  • /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)
  • /eca setFilter <targets> false - Remove all active filters from players
  • /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.2-fix-dev). Go to ECA Modrinth page to find available versions. Use the -dev version for development environments to avoid mixin remapping issues.

Step 3: Declare dependency (mods.toml)

[[dependencies.your_mod_id]]
modId="eca"
mandatory=true
versionRange="[1.1.2,)"
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) - Three-phase health modification: (1) write vanilla DATA_HEALTH_ID directly; (2) reflectively invoke the entity's own setter (set/modify/update + health/hp); (3) ASM bytecode dataflow analysis to locate and write the real health storage. Players skip phases 2–3.
  • 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)
  • addProtectedPackage(prefix) - Add a package prefix to the system-protected list (never transformed by ECA)
  • removeProtectedPackage(prefix) - Remove a package prefix from the protected list (built-in entries cannot be removed)
  • isPackageProtected(className) - Check if a class is system-protected
  • getAllProtectedPackages() - Get all protected package prefixes (built-in + custom)
  • restoreEntity(entity) - DANGER! Requires Attack Radical Logic config. Retransform the entity's custom class chain so this instance delegates getHealth/getMaxHealth/setHealth/hurt/die and other core lifecycle methods to vanilla LivingEntity behaviour (per-instance, reversible)
  • unrestoreEntity(entity) - Cancel the class-restore, returning the entity to its custom implementation
  • 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)
  • 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
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

Runs a dedicated daemon thread outside the Forge event bus and MC tick loop, continuously watching a set of tracked entities and auto-reviving any that die or lose container registration. Gives a stronger liveness guarantee than a one-shot reviveAllContainers call.

Commands (OP level 2):

  • /eca resurrection start — Start the daemon thread
  • /eca resurrection stop — Stop the daemon thread
  • /eca resurrection status — Show thread state + total revival / check counts
  • /eca resurrection add <targets> — Add entities to tracking
  • /eca resurrection remove <targets> — Remove entities from tracking
  • /eca resurrection list — List tracked entities with per-container status
  • /eca resurrection check <target> — One-shot container integrity check (does not revive)
  • /eca resurrection revive <target> — Manually force-revive a tracked entity right now
  • /eca resurrection interval <ms> — Set poll interval (100–10000 ms; default 25 ms)

Direct API (not exposed through EcaAPI; import net.eca.util.ResurrectionManager):

ResurrectionManager.start();                          // start daemon (idempotent)
ResurrectionManager.add(entity);                      // begin tracking
ResurrectionManager.remove(entity);                   // stop tracking
boolean tracked = ResurrectionManager.isTracked(uuid);
ResurrectionManager.setPollIntervalMs(50);            // adjust poll frequency
ResurrectionManager.stop();                           // stop daemon

The daemon thread runs at slightly below normal priority. Default poll interval is 25 ms, meaning a tracked entity is revived within ~25 ms of death. Do not use on entities that spawn in large numbers.

Entity Extensions

Attach special effects to a specific entity type by extending EntityExtension and annotating the subclass with @RegisterEntityExtension.

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
        };
    }

    // 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

Add shader rendering effects to a specific item by extending ItemExtension and annotating the subclass with @RegisterItemExtension. Item extensions are client-only — no network synchronization is needed.

import net.eca.api.RegisterItemExtension;
import net.eca.client.render.StarlightRenderTypes;
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;

@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
    }
}

Activation condition switches:

  • enabled() — global master switch. Return false to completely disable this extension without removing the registration.
  • shouldRender(ItemStack stack) — per-stack runtime check. Called every frame for every rendered stack, so you can gate the effect on NBT, enchantments, custom names, durability, etc.

Notes:

  • Each Item can only have ONE extension. Duplicate registrations are rejected with an error log.
  • The shader is rendered as an additional overlay pass on top of normal item rendering (works in GUI, first-person, third-person, ground item, and item frames).
  • Color-Key masking uses local UV bounds automatically, so centered shader math (spiral, stars, rings) stays centered on the item geometry regardless of where the texture lives on the block atlas.

Shader Presets

ECA ships several built-in shader presets for both entity and item extensions. Just replace CustomRenderTypes in the examples above with a preset name. Each preset provides 4 RenderTypes: BOSS_BAR, BOSS_LAYER, SKYBOX for entity extensions, and ITEM for item extensions.

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

A set of full-screen post-processing filters 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 — and a player's filter is cleared automatically on logout.

Filter types (net.eca.util.filter.FilterType):

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

Apply a filter with /eca setFilter <targets> true <type> or EcaAPI.enableFilter(player, FilterType.SKETCH); clear filters with /eca setFilter <targets> false or EcaAPI.disableFilter(player, type).

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.

Commands (OP level 2):

  • /eca bossShow edit — Open the in-game editor (switches to spectator mode; /eca bossShow exit to restore)
  • /eca bossShow list — List all loaded cutscenes
  • /eca bossShow play <viewer> <target> <id> — Force-play a cutscene
  • /eca bossShow stop <viewer> — Stop the current cutscene
  • /eca bossShow reload — Reload all JSON definitions from disk
  • /eca bossShow clearHistory <player> — Clear "already seen" records for a player

Editor Keybindings (rebindable under Controls → EpicCoreAPI):

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:
    {
      "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.


Available Versions

Epic Core API 1.1.5-fix-fixrelease
MC 1.20.1forge
June 3, 2026
Epic Core API 1.1.5-fixrelease
MC 1.20.1forge
June 2, 2026
Epic Core API 1.1.5release
MC 1.20.1forge
May 27, 2026
Epic Core API 1.1.4-fix-fixrelease
MC 1.20.1forge
April 2, 2026
Epic Core API 1.1.4-fixrelease
MC 1.20.1forge
March 31, 2026

How to Install Epic Core API on Your Server

1

Order Server

Order a Minecraft Java server with at least 3 GB RAM (4 GB recommended).

2

Set forge Loader

In the panel under "Egg", select the forge loader and matching Minecraft version (1.20.1).

3

Install Mod

Open the mod browser in the dashboard and search for "Epic Core API". Click "Install" – done! Alternatively, upload the .jar via SFTP to the /mods folder.

Compatibility

Mod Loaders

forge

Minecraft Versions

1.20.1

Server-side

Required

Recommended RAM

4 GB(min. 3 GB)

Frequently Asked Questions

Epic Core API server crashes on startup – what to do?

Most common cause: wrong forge version or insufficient RAM. Check the server log (latest.log) for "OutOfMemoryError" or "Mixin" errors. With Mado Hosting: ensure at least 3 GB RAM is allocated and the loader matches the mod version (1.20.1). You can switch loaders with one click in the panel.

Is Epic Core API compatible with forge?

Epic Core API officially supports forge for Minecraft 1.20.1. The Mado dashboard automatically detects incompatible loader combinations.

Server lagging with Epic Core API – how to optimize performance?

Recommended RAM: 4 GB (per 8 players). Use /spark profiler to check if Epic Core API consumes the most tick time. Common fixes: reduce server view-distance to 8-10, install "performant" or "starlight" as supplementary mods on Forge. With Mado Hosting, your server runs on NVMe SSDs with dedicated CPU cores for minimal latency.

Rent Modded Server

Install Epic Core API with just one click on your server.

Recommended RAM
4 GBab €8/mo
Min. 3 GB | +1 GB pro 8 Spieler
Create Server Now
1-Click Mod Install
NVMe SSD Storage
DDoS Protection included

Details

License
MIT License
Server-side
Required

Supported Versions

1.20.1