Changes

Redirect to actual page; we don't want to break links that are already bookmarked or shared around
Line 1: Line 1: −
'''Capabilities''' are a Forge system that allows cross-mod interactions by allowing capability ''providers'' to
+
#REDIRECT [[Capabilities]]
dynamically respect contracts and provide specialized behavior without requiring the implementation of many interfaces
  −
or hard dependencies on mods.
  −
 
  −
== History ==
  −
In an ideal world, all that would be needed for a mod to provide the equivalent of a capability would be implementing an
  −
interface. This is in fact how cross-mod interaction used to work prior to the introduction of capabilities.
  −
 
  −
The real world, though, is often much more complicated: users wanted to be free to combine mods the way they wanted and
  −
saw fit, and developers wanted to be able to declare ''soft'' dependencies on other mods, thus reducing the need of
  −
having a huge mod pack just for testing.
  −
 
  −
The first approach used by Forge was conditional stripping of interfaces and methods, but this proved to be problematic.
  −
While the idea works well in theory, in practice the ASM editing of classes relied on complex mechanics and could lead
  −
to hard to spot bugs.
  −
 
  −
For this reason, the entire system was redesigned and the concept of '''capabilities''' was born.
  −
 
  −
== The Concept ==
  −
A capability allows any capability provider to conditionally expose a certain ability to do something, e.g. accepting
  −
power or handling items. A capability provider, moreover, can decide to expose a capability only on certain sides,
  −
allowing for easy interactions with hoppers, cables, etc.
  −
 
  −
Capabilities may also be added and removed dynamically both from the "owner" of the capability provider and other mods,
  −
allowing even easier cross-mod interaction. For example, a mod that isn't compatible with Forge Energy could be
  −
converted into one by dynamically attaching the Forge Energy capability and handling the conversion to a third-party
  −
energy system without having to alter the original mod.
  −
 
  −
== Terminology ==
  −
The high flexibility of the system comes with a cost, though, which is terminology. The following section wants to be a
  −
dictionary of sorts, defining all the terms that you may come across when dealing with capabilities.
  −
 
  −
In the rest of this article, we will refer to these terms frequently, so make sure you are familiar with them.
  −
 
  −
; Capability
  −
: the ability to perform something. In-code this is represented by the <code>Capability</code> class.
  −
; Capability Provider
  −
: something that is able to support capabilities and provides a mean of accessing them. In-code they are represented by implementations of <code>ICapabilityProvider</code>. There are multiple kinds of capability providers:
  −
:; Volatile Provider
  −
:: a provider that doesn't persist data to disk; once the provider ceases to exist for any number of reasons, all capability data gets deleted.
  −
:; Persistent Provider
  −
:: a provider that requires all capabilities to serialize data to disk, in order to persist data even across game restarts. They implement the <code>INBTSerializable</code> interface.
  −
:; Agnostic Provider
  −
:: a provider that isn't neither volatile nor persistent, rather delegates the decision either to the capability directly or to sub-implementations. They also implement the <code>INBTSerializable</code> interface.
  −
; Capability Interface
  −
: the interface that defines the contract of the capability, so what operations the capability exposes.
  −
; Capability Implementation
  −
: one of the possibly many implementations of the capability interface, that actually carries out the work; one of the various implementations may also be considered the '''default capability implementation'''.
  −
; Capability Storage
  −
: the manager that handles loading and storing persistent capabilities data from and to disk, guaranteeing preservation of information; in-code this is represented by an implementation of the <code>Capability.IStorage</code> interface.
  −
 
  −
The wary reader may note that both ''persistent'' and ''agnostic'' providers are represented the same way in code. In
  −
fact, the only difference between them comes from pure semantics in how their serialization methods are designed. This
  −
will be further discussed in their respective sections.
  −
 
  −
Moreover, it is also common to refer to the capability interface as simply the ''capability''. While not strictly
  −
correct, due to common usage we will also use this convention. So, to refer to the capability interface
  −
<code>MyCapability</code>, we will usually talk about the "<code>MyCapability</code> capability".
  −
 
  −
== Forge-provided Capabilities and Providers ==
  −
In order to ensure mods can work together seamlessly, Forge provides a set of default capabilities and capability
  −
providers.
  −
 
  −
The default capability providers in a Forge environment are: <code>TileEntity</code>, <code>Entity</code>,
  −
<code>ItemStack</code>, <code>World</code>, and <code>Chunk</code>. These are all agnostic providers, since they don't
  −
mandate any sort of capability persistency requirements. Rather, it is the job of whoever subclasses these providers to
  −
deal with either volatile or non-volatile capabilities.
  −
 
  −
The default capabilities that forge provides are represented by the interfaces <code>IItemHandler</code>,
  −
<code>IFluidHandler</code>, <code>IFluidHandlerItem</code>, <code>IEnergyStorage</code>, and
  −
<code>IAnimationStateMachine</code>. Each one of these capabilities will be discussed in the corresponding section.
  −
 
  −
=== <tt>IItemHandler</tt> ===
  −
 
  −
The <code>IItemHandler</code> capability refers to the ability for any capability provider to have some sort of internal
  −
'''inventory''' with a certain number of slots, from which items can be inserted and extracted. It is also possible,
  −
though, to expose this capability even if no such inventory is present as long as the capability provider can emulate
  −
its presence (e.g. tools that allow accessing remote inventories).
  −
 
  −
This effectively '''replaces''' the vanilla interfaces <code>IInventory</code> and <code>ISidedInventory</code>. These
  −
interfaces are in fact retained only to allow vanilla code to compile and should not be used in mod code. This extends
  −
to anything that implements those vanilla interfaces, such as <code>LockableLootTileEntity</code>.
  −
 
  −
A default reference implementation for this capability interface is provided in <code>ItemStackHandler</code>.
  −
 
  −
=== <tt>IFluidHandler</tt> ===
  −
 
  −
The <code>IFluidHandler</code> capability refers to the ability for any capability provider to handle and store fluids
  −
in one or multiple fluid tanks. It is effectively the equivalent in terms of fluids of the <code>IItemHandler</code>
  −
capability.
  −
 
  −
A default reference implementation for this capability interface is provided in <code>TileFluidHandler</code>.
  −
 
  −
=== <tt>IFluidHandlerItem</tt> ===
  −
 
  −
The <code>IFluidHandlerItem</code> capability referes to the ability for an <code>ItemStack</code> capability provider
  −
to handle and store fluids in one or multiple fluid tanks. It is basically a specialized version of the
  −
<code>IFluidHandler</code> capability that allows <code>ItemStack</code>s to define a custom container.
  −
 
  −
=== <tt>IEnergyStorage</tt> ===
  −
 
  −
The <code>IEnergyStorage</code> capability refers to the ability for any capability provider to store, consume, and
  −
produce energy. This capability is the base capability for what's commonly known in the modded world as Forge Energy (or
  −
FE), i.e. the energy system most mods use. Its internal design is heavily based on the (now defunct) Redstone Flux
  −
Energy API, supporting both a push and pull system.
  −
 
  −
A default reference implementation for this capability interface is provided in <code>EnergyStorage</code>.
  −
 
  −
=== <tt>IAnimationStateMachine</tt> ===
  −
 
  −
The <code>IAnimationStateMachine</code> capability refers to the ability for any capability provider to leverage the
  −
Forge Animation State Machine API for animations.
  −
 
  −
== Working with Capabilities ==
  −
 
  −
Both capability providers and users need to be able to provide and access capabilities through a common framework,
  −
otherwise the ideal of dynamic and mod-agnostic would not really exist. For this reason, both capability providers and
  −
capability ''accessors'' (which we define as everything that wants to access a capability), also known as '''clients''' or '''users''',
  −
need to work together and with Forge to ensure that the common interface is used sensibly and correctly by all parties.
  −
 
  −
=== Obtaining a Capability ===
  −
 
  −
Before being able to work with a capability, it is necessary to obtain an instance of the <code>Capability</code> object
  −
itself. Since these objects are created by Forge and there is only '''one''' unique instance for each capability that
  −
may exist, this instance cannot be obtained by "common" means. Forge provides two different methods of obtaining such
  −
instances: '''injecting''' into a field, or a '''callback method'''.
  −
 
  −
==== Injecting into a Field ====
  −
 
  −
A <code>Capability</code> can be injected automatically into a field as soon as it gets created by Forge, following the
  −
principle commonly known as '''dependency injection'''. This provides less flexibility, since it doesn't notify the user
  −
that the capability has been injected nor runs arbitrary code. Nevertheless, it is '''suggested''' to use this method
  −
instead of the callback approach.
  −
 
  −
To inject the <code>Capability</code> into a field, all that's needed is to declare a <code>static</code> field of type
  −
<code>Capability&lt;T&gt;</code>, where <code>T</code> represents the capability interface, and annotate it with
  −
<code>@CapabilityInject(T.class)</code>.
  −
 
  −
For a more practical example, consider the following snippet:
  −
 
  −
<syntaxhighlight lang="java">
  −
@CapabilityInject(IItemHandler.class)
  −
public static Capability<IItemHandler> ITEM_HANDLER_CAPABILITY = null;
  −
</syntaxhighlight>
  −
 
  −
The above code will let Forge know that the field <code>ITEM_HANDLER_CAPABILITY</code> should be injected with the
  −
unique instance of the <code>IItemHandler</code> capability. Assigning the field to <code>null</code> allows us to
  −
provide a reasonable fallback in case the capability we want hasn't been registered yet.
  −
 
  −
This injection is, for obvious reasons, redundant, since that capability is also available through
  −
<code>CapabilityItemHandler</code>.
  −
 
  −
==== Declaring a Callback ====
  −
 
  −
Another option is to declare a callback method, meaning a method that will be called with the value of the desired
  −
<code>Capability</code> once the instance is available. This gives more flexibility since the method may perform a
  −
number of arbitrary actions with the received instance prior to storing it in a field, or may even discard the
  −
capability entirely if wanted. Nevertheless, the usage of a field instead of a method is encouraged as a matter of
  −
style.
  −
 
  −
To use a method as a callback, the method must be declared as <code>static</code> and accepting a single parameter of
  −
type <code>Capability&lt;T&gt;</code>, where <code>T</code> represents the capability interface. The method should also
  −
be annotated with <code>@CapabilityInject(T.class)</code>.
  −
 
  −
For a more practical example, consider the following snippet:
  −
 
  −
<syntaxhighlight lang="java">
  −
public static Capability<IEnergyStorage> ENERGY = null;
  −
 
  −
@CapabilityInject(IEnergyStorage.class)
  −
private static void onEnergyStorageInit(Capability<IEnergyStorage> capability) {
  −
    LOGGER.info("Received IEnergyStorage capability '{}': enabling Forge Energy support", capability);
  −
    ENERGY = capability;
  −
}
  −
</syntaxhighlight>
  −
 
  −
The above code declares a callback method that will be invoked when a <code>Capability</code> instance for
  −
<code>IEnergyStorage</code> is available. The callback then prints a log message and stores the capability into a
  −
<code>public</code> field for accessibility. The field is initialized to <code>null</code> to provide a reasonable
  −
fallback in case the capability does not exist.
  −
 
  −
This callback is, for obvious reasons, redundant, since that capability is also available through
  −
<code>CapabilityEnergy</code>.
  −
 
  −
=== Exposing a Capability ===
  −
 
  −
Exposing a capability is a voluntary act by a capability provider that allows the capability to be discovered and
  −
accessed by users.
  −
 
  −
To do so, a capability provider needs to juggle a couple more moving pieces to ensure that the capability state remains
  −
consistent and that the lookup remains fast. It is in fact possible for a capability provider to be asked to provide
  −
many capabilities many times in the same tick. For this reason, a provider is asked to do the following:
  −
 
  −
* the <code>LazyOptional</code>s that get returned '''must be cached''';
  −
* if a capability changes exposure state (more on this later), all listeners '''must be notified''';
  −
* if a capability gets invalidated (more on this later), all listeners '''must be notified'''
  −
* the lookup inside <code>getCapability</code> must be performed with '''an <code>if</code>-<code>else</code> chain''';
  −
* all unexposed but still present capabilities '''should be available''' if the provider is queried with a <code>null</code> direction (see ''Accessing a Capability'' for more information);
  −
* if no capability of a given type is available or accessible, the provider '''must call <code>super</code> as long as it is possible to do so'''.
  −
 
  −
Capability providers must also reflect changes in the ''exposure state'' of a capability, meaning that if the
  −
accessibility of a capability from a certain <code>Direction</code> changes (refer to
  −
[[#Accessing a Capability|Accessing a Capability]] for more information), it is the provider's responsibility to trigger
  −
a state response by invalidating the returned <code>LazyOptional</code> and caching a new one. This should also be
  −
performed when a capability gets ''invalidated'', such as when a capability provider gets removed.
  −
 
  −
With all of the above in mind, part of a capability provider implementation may be similar to the following snippet:
  −
 
  −
<syntaxhighlight lang="java">
  −
// suppose the presence of a field 'inventory' of type 'IItemHandler'
  −
 
  −
private final LazyOptional<IItemhandler> inventoryOptional = LazyOptional.of(() -> this.inventory);
  −
 
  −
@Override
  −
public <T> LazyOptional<T> getCapability(Capability<T> capability, @Nullable Direction direction) {
  −
    if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY
  −
            && (direction == null || direction == Direction.UP || direction == Direction.DOWN)) {
  −
        return this.inventoryOptional.cast();
  −
    }
  −
    return super.getCapability(capability, direction); // See note after snippet
  −
}
  −
 
  −
@Override
  −
protected void invalidateCaps() {
  −
    super.invalidateCaps();
  −
    this.inventoryOptional.invalidate();
  −
}
  −
</syntaxhighlight>
  −
 
  −
This possible implementation of a capability provider exposes an <code>IItemHandler</code> capability and restricts
  −
access only to the <code>UP</code> and <code>DOWN</code> directions. If we assume this capability provider is a
  −
<code>TileEntity</code>, then we may also say that the inventory is only accessible from the top and the bottom of the
  −
block.
  −
 
  −
Moreover, the capability gets automatically invalidated when the provider gets invalidated. Assuming this is a
  −
<code>TileEntity</code>, this usually happens when the block gets removed from the world or unloaded due to distance.
  −
 
  −
The <code>super</code> call at the end of the <code>getCapability</code> method is extremely important, since it's what
  −
allows Attaching external Capabilities to capability providers. Nevertheless, it is not always possible to invoke
  −
<code>super</code>: in those cases, an empty <code>LazyOptional</code> should be returned.
  −
 
  −
=== Attaching a Capability ===
  −
 
  −
Attaching a Capability is a process by which external agents "modify" a Capability Provider, making it expose additional
  −
capabilities other than the already available ones.
  −
 
  −
To do so, the '''attaching agent''' (which means the thing that wants to attach a capability to another provider) must
  −
listen to the <code>AttachCapabilitiesEvent&lt;T&gt;</code>. The <code>T</code> in this case represents the capability
  −
provider you want to attach the capability to. Note that the type of <code>T</code> '''must''' be the base type of the
  −
capability provider, not a subclass. As an example, if you want to attach a capability to a <code>MyTileEntity</code>,
  −
which extends <code>TileEntity</code>, you'll have to listen to <code>AttachCapabilitiesEvent&lt;TileEntity&gt;</code>,
  −
'''NOT''' to <code>AttachCapabilitiesEvent&lt;MyTileEntity&gt;</code>, since the latter will never fire.
  −
 
  −
The attaching agent can use the provided methods <code>getObject</code>, <code>addCapability</code>, and
  −
<code>addListener</code> to check whether the capability should be attached to the current object and perform the
  −
desired action.
  −
 
  −
When attaching a capability, the attaching agent should also provide a name in the form of a
  −
<code>ResourceLocation</code>. The name '''must''' be under the attaching agent's namespace, but no restrictions are
  −
placed on the actual name, as long as it is unique inside the given namespace.
  −
 
  −
Maybe a little counter-intuitively, the process of attaching does not attach a capability nor a capability interface
  −
directly. Rather, the attaching agent should create its own implementation of a '''Capability Provider''' and attach it
  −
via the event. This is done so that the attaching agent can have control over when, how, and where its capabilities are
  −
exposed, instead of relying on the game itself deciding these parameters. For this reason, all considerations given in
  −
the [[#Exposing a Capability|Exposing a Capability]] section on how to correctly create a Capability Provider.
  −
 
  −
With the above in mind, part of an attaching agent may be similar to the following snippet of code:
  −
 
  −
<syntaxhighlight lang="java">
  −
@SubscribeEvent
  −
public void onAttachingCapabilities(final AttachCapabilitiesEvent<TileEntity> event) {
  −
    if (!(event.getObject() instanceof EnergyBasedTileEntity)) return;
  −
 
  −
    EnergyStorage backend = new EnergyStorage(((EnergyBasedTileEntity) event.getObject()).capacity);
  −
    LazyOptional<IEnergyStorage> optionalStorage = LazyOptional.of(() -> backend);
  −
 
  −
    ICapabilityProvider provider = new ICapabilityProvider() {
  −
        @Override
  −
        public <T> LazyOptional<T> getCapability(Capability<T> cap, @Nullable Direction direction) {
  −
            if (cap == CapabilityEnergy.ENERGY) {
  −
                return optionalStorage.cast();
  −
            }
  −
            return LazyOptional.empty();
  −
        }
  −
    };
  −
 
  −
    event.addCapability(new ResourceLocation("examplemod", "fe_compatibility"), provider);
  −
    event.addListener(optionalStorage::invalidate);
  −
}
  −
</syntaxhighlight>
  −
 
  −
This example implementation of an attaching agent attaches a <code>IEnergyStorage</code> capability to all
  −
<code>TileEntity</code> instance that are a subclass of <code>EnergyBasedTileEntity</code>. It also sets up the
  −
<code>LazyOptional</code> for invalidation if the parent capability provider gets invalidated.
  −
 
  −
Note also the call of <code>LazyOptional.empty()</code> rather than a <code>super</code>. This is needed because when
  −
attaching a capability, the parent capability provider isn't known. For this reason, it is necessary to return an empty
  −
<code>LazyOptional</code>. The game will then handle automatic merging of the various different providers into a single
  −
one.
  −
 
  −
The above example is one of a '''Volatile''' Capability Provider. On the other hand, mods may want to persist their
  −
data across sessions. In this case, they should attach a '''Persistent''' Capability Provider: this can be done either
  −
by implementing the <code>INBTSerializable</code> interface along with <code>ICapabilityProvider</code> or by
  −
implementing the <code>ICapabilitySerializable</code> interface.
  −
 
  −
The previous example reworked to use a Persistent Capability Provider may be similar to the following snippet:
  −
 
  −
<syntaxhighlight lang="java">
  −
@SubscribeEvent
  −
public void onAttachingCapabilities(final AttachCapabilitiesEvent<TileEntity> event) {
  −
    if (!(event.getObject() instanceof EnergyBasedTileEntity)) return;
  −
 
  −
    EnergyStorage backend = new EnergyStorage(((EnergyBasedTileEntity) event.getObject()).capacity);
  −
    LazyOptional<IEnergyStorage> optionalStorage = LazyOptional.of(() -> backend);
  −
    Capability<IEnergyStorage> capability = CapabilityEnergy.ENERGY;
  −
 
  −
    ICapabilityProvider provider = new ICapabilitySerializable<IntNBT>() {
  −
        @Override
  −
        public <T> LazyOptional<T> getCapability(Capability<T> cap, @Nullable Direction direction) {
  −
            if (cap == capability) {
  −
                return optionalStorage.cast();
  −
            }
  −
            return LazyOptional.empty();
  −
        }
  −
 
  −
        @Override
  −
        public IntNBT serializeNBT() {
  −
            return capability.getStorage().writeNbt(capability, backend, null);
  −
        }
  −
 
  −
        @Override
  −
        public void deserializeNBT(IntNBT nbt) {
  −
            capability.getStorage().readNBT(capability, backend, null, nbt);
  −
        }
  −
    };
  −
 
  −
    event.addCapabilities(new ResourceLocation("examplemod", "fe_compatibility"), provider);
  −
    event.addListener(optionalStorage::invalidate);
  −
}
  −
</syntaxhighlight>
  −
 
  −
 
  −
=== Accessing a Capability ===
  −
 
  −
Accessing a Capability is the process by which a user is able to '''query''' a Capability Provider for a specific
  −
instance of a capability.
  −
 
  −
This is perhaps the second most important part of the entire capability system, since it is what allows cross-mod
  −
interaction. To obtain an instance of a Capability, the user must first get a hold of the Capability Provider that
  −
should be queried. This can be done in a variety of ways and is outside the scope of this article. The user should
  −
then invoke the <code>getCapability</code> method passing the unique instance of the capability that should be queried
  −
(see [[#Obtaining a Capability|Obtaining a Capability]] for more information) and the querying <code>Direction</code>,
  −
if applicable.
  −
 
  −
The returned object is a <code>LazyOptional</code> wrapping the queried Capability, if the capability provider exposes
  −
it, otherwise it will be empty. The <code>LazyOptional</code> can be either unwrapped via an <code>orElse</code> or
  −
used directly via <code>ifPresent</code>.
  −
 
  −
It is '''highly suggested''' to cache the returned <code>LazyOptional</code> to avoid querying the same provider every
  −
time, in order to improve performance. The user should thus register itself to the invalidation listener via the
  −
<code>addListener</code> method. This ensures that the user will be able to react to the invalidation of the
  −
<code>LazyOptional</code> and remove it from the cache.
  −
 
  −
With the above in mind, part of an user may be similar to the following snippet of code:
  −
 
  −
<syntaxhighlight lang="java">
  −
private final Map<Direction, LazyOptional<IEnergyStorage>> cache = new HashMap<>();
  −
 
  −
private void sendPowerTo(int power, Direction direction) {
  −
    LazyOptional<IEnergyStorage> targetCapability = cache.get(direction);
  −
 
  −
    if (targetCapability == null) {
  −
        ICapabilityProvider provider = world.getTileEntity(pos.offset(direction));
  −
        targetCapability = provider.getCapability(CapabilityEnergy.ENERGY, direction.getOpposite());
  −
        cache.put(direction, targetCapability);
  −
        targetCapability.addListener(self -> cache.put(direction, null));
  −
    }
  −
 
  −
    targetCapability.ifPresent(storage -> storage.receiveEnergy(power, false));
  −
}
  −
</syntaxhighlight>
  −
 
  −
This example implementation of an user is querying via a <code>TileEntity</code> the neighboring capability provider
  −
for an <code>IEnergyStorage</code> capability. Before obtaining the provider, the code performs a cache lookup for the
  −
targeted capability. If the check succeeds, then no lookup is performed; if the check fails, the targeted Capability
  −
Provider is obtained and queried for the Capability. The obtained <code>LazyOptional</code> is then cached and a
  −
listener is attached to it so that the cache would be emptied on invalidation. The code then continues with the
  −
interaction with the capability, which is outside the scope of this article.
  −
 
  −
== Creating Custom Capabilities ==
  −
 
  −
While the various capabilities provided by Forge may satisfy the most common use cases, there is always the chance that
  −
a mod may require a custom solution. For this reason, Forge provides a way to define a custom Capability.
  −
 
  −
Defining a custom Capability requires the user to provide three main components: the Capability Interface, at least one
  −
Capability Implementation, and the Capability Storage. Optionally, a Capability Provider can also be created. In this
  −
case, the provider will be used as described in [[#Attaching a Capability|Attaching a Capability]]. The various details
  −
for all these components are described in the respective sections of this article.
  −
 
  −
In this section, we will refer to the implementation of a <code>MyCapability</code> capability, that can be used to
  −
store a single mutable <code>String</code>.
  −
 
  −
Refer also to [[#Code Examples|Code Examples]] for an example on how the various components may be implemented in a
  −
real-world scenario.
  −
 
  −
=== The Capability Interface and the Capability Implementation ===
  −
 
  −
The Capability Interface is one of the most important parts of a Capability: without it, the Capability effectively does
  −
not exist. Designing a Capability Interface is exactly like designing any Java interface, so the particular details will
  −
be glossed over in this section.
  −
 
  −
The Capability Implementation, on the other hand, is the implementation of the previously defined Capability Interface.
  −
Usual rules for interface implementations follow. There can be more than one Capability Implementation for each
  −
capability, but no less than one.
  −
 
  −
Note that a '''well-formed''' capability implementation should '''not store''' the Capability Provider inside of it: we
  −
call the capability implementation ''provider-agnostic''. This is not a hard-requirement, though, rather it should act
  −
more as a guideline. There are in fact certain situations where this cannot be avoided (e.g. attaching a client-synced
  −
capability to an <code>ItemStack</code>).
  −
 
  −
One of the various Capability Implementation should also act as the default implementation. Other mods can ask the
  −
capability to create an instance of the default implementation without ever referring to such an implementation
  −
themselves. This guarantees separation of API code from implementation code, which is also one of the goals of the
  −
capability system.
  −
 
  −
Given all of the above information, this may be an example implementation of both a Capability Interface and a
  −
Capability Implementation:
  −
 
  −
<syntaxhighlight lang="java">
  −
public interface MyCapability {
  −
    String getValue();
  −
    void setValue(String value);
  −
}
  −
 
  −
public class MyCapabilityImplementation implements MyCapability {
  −
    private String value;
  −
 
  −
    @Override
  −
    public String getValue() {
  −
        return this.value;
  −
    }
  −
 
  −
    @Override
  −
    public void setValue(String value) {
  −
        this.value = value;
  −
    }
  −
}
  −
</syntaxhighlight>
  −
 
  −
Note that in this case, only a single implementation is provided, which will also act as the default implementation for
  −
the <code>MyCapability</code> capability.
  −
 
  −
=== The Capability Storage ===
  −
 
  −
The Capability Storage is that component of the Capability System that is responsible for serializing and deserializing
  −
a capability. All capabilities must provide one, since certain providers may or may not require that their capabilities
  −
are serializable.
  −
 
  −
The Capability Storage implements the <code>Capability.IStorage&lt;T&gt;</code> interface, where <code>T</code> is the
  −
generic type of the Capability Interface the storage refers to. Each capability must have '''one and exactly one'''
  −
Capability Storage.
  −
 
  −
The Storage is usually called by the Capability Provider when serialization or deserialization needs to happen. The
  −
Storage is then responsible of reading the data from the given capability instance and convert that into an NBT-based
  −
structure that can be serialized. A Storage may also return <code>null</code> to indicate that no serialization is
  −
necessary, although some providers may require an empty tag to be supplied instead. At the same time, the Storage is
  −
also responsible for restoring the original state of the capability when deserialization happens. In this case, the
  −
given NBT structure is guaranteed not to be <code>null</code>.
  −
 
  −
In all cases, a <code>Direction</code> is provided for context, if available.
  −
 
  −
Although discouraged as a matter of code cleanliness, it is legal for a Capability Storage to require a specific
  −
Capability Implementation for the serialization and deserialization to be successful. If this is the case, this
  −
requirement '''must''' be documented, though the code should be refactored wherever possible to remove this requirement.
  −
 
  −
Given the above information, an example of an implementation of a Capability Storage may be the following:
  −
 
  −
<syntaxhighlight lang="java">
  −
public class MyCapabilityStorage implements Capability.IStorage<MyCapability> {
  −
    @Override
  −
    @Nullable
  −
    INBT writeNBT(Capability<MyCapability> capability, MyCapability instance, Direction direction) {
  −
        return StringNBT.valueOf(instance.getValue());
  −
    }
  −
 
  −
    @Override
  −
    public void readNBT(Capability<MyCapability> capability, MyCapability instance, Direction direction, INBT nbtData) {
  −
        if (!(nbtData instanceof StringNBT)) {
  −
            throw new IllegalArgumentException("Unable to deserialize 'MyCapability' from a non-String NBT structure");
  −
        }
  −
        instance.setValue(((StringNBT) nbtData).getString());
  −
    }
  −
}
  −
</syntaxhighlight>
  −
 
  −
Note the <code>instanceof</code> check needed to ensure that the given <code>INBT</code> instance is valid for
  −
deserialization. A Capability Storage should always perform this check prior to the cast in order to provide a
  −
meaningful error message, rather than a cryptic <code>ClassCastException</code>.
  −
 
  −
=== The Capability Provider ===
  −
 
  −
The Capability Provider is an optional component of the capability that allows the Capability to be attached to a
  −
component. The details on how a Capability Provider should behave have already been discussed in the two previous
  −
sections [[#Exposing a Capability|Exposing a Capability]] and [[#Attaching a Capability|Attaching a Capability]]: refer
  −
to those for more information.
  −
 
  −
=== Tying it All Together ===
  −
 
  −
Once all components of a Capability have been created, they must be registered so that the game is aware of the
  −
capability's presence. The registration requires specifying the Capability Interface, the Capability Storage, and a
  −
factory for the default capability implementation.
  −
 
  −
The registration can be performed by calling the <code>register</code> method on the <code>CapabilityManager</code>.
  −
This '''needs''' to happen when the <code>FMLCommonSetupEvent</code> is fired on the <code>MOD</code> event bus. The
  −
registration will also automatically inject the created Capability into all relevant fields and methods: refer to
  −
[[#Obtaining a Capability|Obtaining a Capability]] for more information.
  −
 
  −
An example of registration can be found in the snippet that follows:
  −
 
  −
<syntaxhighlight lang="java">
  −
public void onCommonSetup(FMLCommonSetupEvent event) {
  −
    CapabilityManager.INSTANCE.register(MyCapability.class, new MyCapabilityStorage(), MyCapabilityImplementation::new);
  −
}
  −
</syntaxhighlight>
  −
 
  −
== Custom Capability Providers ==
  −
 
  −
Much like custom Capabilities, Forge also allows the creation of custom Capability Providers. The main advantage of this
  −
is allowing mods to create custom providers for their custom objects, in order to promote not only cross-mod
  −
compatibility, but also uniformity in the way users may interact with different mod APIs.
  −
 
  −
This section will only give the basic outline of what is necessary to implement a custom Capability Provider: for more
  −
in-depth explanation, people are referred to the game code.
  −
 
  −
By definition, a custom Capability Provider is everything that implements the <code>ICapabilityProvider</code>
  −
interface. In this section, though, we will only cover people that may want to replicate the functionality of one of
  −
the default providers, such as <code>TileEntity</code> or <code>Chunk</code>.
  −
 
  −
The easiest way of doing this is extending the <code>CapabilityProvider</code> class provided by Forge. This will
  −
automatically set up an ''agnostic'' Capability Provider. To fully initialize the capability provider, the subclass
  −
should then invoke the <code>gatherCapabilities</code> method as the last instruction in its constructor, to ensure that
  −
the game is able to recollect and attach all capabilities that other mods may want to attach to the capability provider.
  −
 
  −
== Code Examples ==
  −
 
  −
* [https://gist.github.com/TheSilkMiner/5cc92ba573e7bdd871dfdbffdd5c2806 A Gist showing a quick and dirty example on how to implement a Capability effectively]