Capability Helpers

Attach persistent data to players, entities, items, and tile entities — with a single annotation instead of six files.

Package: fr.eri.eriapi.capability Forge Capabilities Auto Sync

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.

One annotation, zero boilerplate

Instead of creating 6 files (interface, impl, storage, provider, event handler, packet), a single @EriCapability annotation on your data class is enough.

01
Annotate your class

Add @EriCapability to any plain Java class holding your data fields.

02
Register in preInit

Call EriCap.register(YourClass.class) once and the capability is live.

03
Read, write, sync

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.

Java — Mana.java
@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

ParameterTypeDefaultDescription
modId String required Your mod ID. Used to namespace the capability key.
target AttachTarget required What the capability is attached to. See AttachTarget.
persistOnDeath boolean true Whether the data is copied to the new player instance after death.
Fields not annotated with @Sync

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.

ValueAttached toNotes
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.
Java — AttachTarget usage examples
// 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.

Java — preInit
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
    EriCap.register(Mana.class);
    EriCap.register(SoulBound.class);
    EriCap.register(MachineData.class);
}

Reading and writing data

Java — get() from various targets
// 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

MethodReturnsDescription
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.
sync() is server-side only

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()
Java — @Sync field annotations
@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;
}
Supported field types for @Sync

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.

EventFramework action
preInit You call EriCap.register(). The capability is registered with Forge.
AttachCapabilitiesEvent Framework automatically attaches the provider to the correct target (player, entity, item, tile).
Player login All @Sync fields are sent to the client automatically.
Player death If persistOnDeath = true, all fields are copied to the new player instance.
Respawn / Dimension change All @Sync fields are re-sent to the client automatically.
Manual EriCap.sync() All @Sync fields are immediately sent to the specified player's client.
World save / Player disconnect All fields (synced or not) are serialized to NBT and saved automatically.
When to call EriCap.sync() manually

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

Java — Mana.java
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

Java — MyRPGMod.java
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

Java — SpellHandler.java
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;
    }
}
What the framework does for you

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)

Java — ManaHud.java (client side)
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;