Skip to content

Registering and using a component

Pyrofab edited this page Aug 11, 2020 · 15 revisions

1) Implementing your component

To get started, you only need a class implementing the Component interface. It is good practice to make an interface for your component separate from the implementation, so that internals get properly encapsulated and so that the component itself can be used as an API by other mods.

Example:

public interface IntComponent extends Component {
    int getValue();
}

class RandomIntComponent implements IntComponent {
    private int value = (int) (Math.random() * 20);
    @Override public int getValue() { return this.value; }
    @Override public void fromTag(CompoundTag tag) { this.value = tag.getInt("value"); }
    @Override public CompoundTag toTag(CompoundTag tag) { tag.putInt("value", this.value); return tag; }
}

A Component implementation can also implement some extended interfaces to help with tasks such as server-client synchronization or data transfers. More information on those interfaces is available in the javadoc and in the documentation for each module.

2) Registering your component

Components are provided by various objects through the ComponentProvider interface. To interact with those, you need to obtain a ComponentType instance - a unique key made up of an identifier and of the component's type information. Such an instance can be retrieved in a few ways, all using the ComponentRegistry. Note that the same Component implementation can be reused between several ComponentTypes.

Dynamic registration

Most commonly, mods use ComponentRegistry#getOrRegister(Identifier, Class). This method must be called at least once to make the component usable in a game instance, but it can be called an arbitrary amount of times with no side-effects (idempotent).

// retrieving a type for my component or for a required dependency's
public static final ComponentType<IntComponent> MAGIK = 
        ComponentRegistry.INSTANCE.registerIfAbsent(new Identifier("mymod:magik"), IntComponent.class);

Static registration

Since 2.4, components can be declared and attached statically. These components will have runtime-generated dedicated fields in the relevant component containers, guaranteeing a ComponentType#get performance comparable to direct field access.

Static registration is very similar to dynamic registration, but it requires first declaring your component type id in your fabric.mod.json's custom properties:

{
    "schemaVersion": 1,
    "id": "mymod",

    "custom": {
        "cardinal-components": [
            "mymod:magik"
        ]
    }
}

It is safe to declare a static component type that belongs to another mod in this array. It is also safe to declare an id that may not be registered at runtime.

Then, to retrieve the ComponentKey (V3 equivalent of a ComponentType):

// retrieving a type for my component or for a required dependency's
public static final ComponentKey<IntComponent> MAGIK = 
        ComponentRegistry.INSTANCE.registerStatic(new Identifier("mymod", "magik"), IntComponent.class);

Retrieval of an already registered type

If your mod uses another mod's component, you may not want to (or may not be able to) register it yourself - in which case you can use the get method. In this case, you may also be interested in ComponentRegisteredCallback.

// retrieving a component type registered by an optional dependency
public static final Lazy</*@Nullable*/ComponentType<?>> BLUE = 
        new Lazy<>(() -> ComponentRegistry.INSTANCE.get(new Identifier("theirmod:blue")));

Next page: Attaching components

Clone this wiki locally