Capability Helpers
Attach persistent data to players, entities, items, and tile entities — with a single annotation instead of six files.
Introduction
Forge capabilities are a powerful system, but they come with a high setup cost. To attach custom data to a player in a standard Forge mod, you need to write six separate files: an interface, an implementation, a storage handler, a capability provider, an event handler, and a sync packet. That is a lot of boilerplate for something conceptually simple.
The Capability Helpers module reduces all of that to a single annotation:
@EriCapability. Annotate your data class, call EriCap.register() in
preInit, and the framework handles everything else — storage, provider attachment,
death persistence, and client synchronization.
Instead of creating 6 files (interface, impl, storage, provider, event handler, packet),
a single @EriCapability annotation on your data class is enough.
Add @EriCapability to any plain Java class holding your data fields.
Call EriCap.register(YourClass.class) once and the capability is live.
Use EriCap.get() to retrieve data and EriCap.sync() to push it to the client.
@EriCapability — Annotation
Place @EriCapability on any plain Java class. The class acts as a plain data holder
(POJO) — no interface to implement, no parent class to extend.
@EriCapability(modId = "mymod", target = AttachTarget.PLAYER)
public class Mana {
@Sync public int current = 100;
@Sync public int max = 100;
public float regenRate = 0.5f;
}
Annotation parameters
modId
String
required
Your mod ID. Used to namespace the capability key.
persistOnDeath
boolean
true
Whether the data is copied to the new player instance after death.
Fields without @Sync are still stored and persisted on the server but are
never sent to the client. Use this for server-only data like regenRate
in the example above.
AttachTarget — Enum
The AttachTarget enum tells the framework which game object the capability is attached to.
PLAYER
Any EntityPlayer
Most common target. Supports persistOnDeath and client sync.
ENTITY
Any EntityLivingBase
Attached to mobs and animals as well as players.
ITEM
ItemStack
Stored inside the item NBT. Follows the item, not the player.
TILE_ENTITY
TileEntity
Attached to block entities like machines, chests, etc.
// Attached to the player
@EriCapability(modId = "myrpg", target = AttachTarget.PLAYER)
public class PlayerStats { ... }
// Attached to any living entity (mobs, players, animals)
@EriCapability(modId = "myrpg", target = AttachTarget.ENTITY)
public class EntityAI { ... }
// Stored inside an ItemStack
@EriCapability(modId = "myrpg", target = AttachTarget.ITEM)
public class SoulBound { ... }
// Attached to a TileEntity (machine, chest, etc.)
@EriCapability(modId = "myrpg", target = AttachTarget.TILE_ENTITY)
public class MachineData { ... }
EriCap — Static API
EriCap is the single entry point for all capability operations. All methods are static —
you never need to instantiate anything.
Registering a capability
Call register() in your preInit event handler, before any world loads.
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
EriCap.register(Mana.class);
EriCap.register(SoulBound.class);
EriCap.register(MachineData.class);
}
Reading and writing data
// Read from a player (Entity target)
Mana mana = EriCap.get(player, Mana.class);
mana.current -= 10;
EriCap.sync((EntityPlayerMP) player, Mana.class);
// Read from an ItemStack
SoulBound data = EriCap.get(stack, SoulBound.class);
data.bound = true;
// Read from a TileEntity
MachineData machine = EriCap.get(tile, MachineData.class);
Method reference
register(Class<T>)
void
Registers the capability. Must be called in preInit.
get(Entity, Class<T>)
T
Retrieves the capability instance from an entity (player or any living entity).
get(ItemStack, Class<T>)
T
Retrieves the capability instance from an ItemStack.
get(TileEntity, Class<T>)
T
Retrieves the capability instance from a TileEntity.
sync(EntityPlayerMP, Class<T>)
void
Forces immediate sync of all @Sync fields to the client.
EriCap.sync() takes an EntityPlayerMP (the server-side player class).
Never call it on the client side. On the client, always read data from EriCap.get() —
it will already contain the last synced values.
@Sync — Automatic Synchronization
Any field on your capability class that is annotated with @Sync will automatically
be sent from the server to the client at the following moments:
- Player login — when the player first joins the server
- Respawn — after the player dies and respawns
- Dimension change — when traveling between dimensions
- Manual sync — whenever you call
EriCap.sync()
@EriCapability(modId = "myrpg", target = AttachTarget.PLAYER)
public class PlayerStats {
// Synced: the client needs to display these in the HUD
@Sync public int level = 1;
@Sync public int experience = 0;
@Sync public int health = 100;
// Not synced: only the server needs this
public long lastAttackTime = 0;
public int ticksInCombat = 0;
}
All primitive types and their boxed equivalents are supported: int, float,
double, long, boolean, byte, short,
and String. NBT-serializable objects are also supported.
Lifecycle
Understanding when the framework acts on your capability helps you avoid common mistakes.
EriCap.register(). The capability is registered with Forge.
@Sync fields are sent to the client automatically.
persistOnDeath = true, all fields are copied to the new player instance.
@Sync fields are re-sent to the client automatically.
EriCap.sync()
All @Sync fields are immediately sent to the specified player's client.
Call sync() any time you mutate a @Sync field on the server and want the
client to reflect the change immediately — for example, after a spell is cast, a level-up occurs,
or a stat changes mid-game.
Complete Example — Mana System
The following example shows a complete mana system: a data class, registration, and usage inside a spell handler. Everything — storage, sync, and death persistence — is handled by EriAPI.
Step 1 — Define the capability
package com.example.myrpg.capability;
import fr.eri.eriapi.capability.EriCapability;
import fr.eri.eriapi.capability.AttachTarget;
import fr.eri.eriapi.capability.Sync;
@EriCapability(modId = "myrpg", target = AttachTarget.PLAYER)
public class Mana {
@Sync public int current = 100;
@Sync public int max = 100;
public float regenRate = 0.5f; // server-only
}
Step 2 — Register in preInit
import fr.eri.eriapi.capability.EriCap;
@Mod(modid = "myrpg", version = "1.0")
public class MyRPGMod {
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
EriCap.register(Mana.class);
}
}
Step 3 — Use in a spell handler
import fr.eri.eriapi.capability.EriCap;
import net.minecraft.entity.player.EntityPlayerMP;
public class SpellHandler {
public static boolean castFireball(EntityPlayerMP player) {
Mana mana = EriCap.get(player, Mana.class);
if (mana.current < 20) {
// Not enough mana — reject the cast
return false;
}
// Deduct mana and sync the new value to the client
mana.current -= 20;
EriCap.sync(player, Mana.class);
// ... launch the fireball projectile ...
return true;
}
}
Behind the scenes, EriAPI generated the ICapabilityProvider, registered the
Capability<Mana> token with Forge, wired up the AttachCapabilitiesEvent
listener, wrote the NBT serialization/deserialization, set up the death-copy handler, and
created the sync packet — none of which you had to write.
Reading mana on the client (HUD)
import fr.eri.eriapi.capability.EriCap;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
// Called from a RenderGameOverlayEvent handler
EntityPlayer player = Minecraft.getMinecraft().player;
Mana mana = EriCap.get(player, Mana.class);
// mana.current and mana.max are always up to date on the client
// because they are annotated with @Sync
String text = "Mana: " + mana.current + " / " + mana.max;