Changes

Add description on how to attach a capability
Line 136: Line 136:  
// suppose the presence of a field 'inventory' of type 'IItemHandler'
 
// suppose the presence of a field 'inventory' of type 'IItemHandler'
   −
private static final LazyOptional<IItemhandler> INVENTORY_OPTIONAL = LazyOptional.of(() -> inventory);
+
private final LazyOptional<IItemhandler> inventoryOptional = LazyOptional.of(() -> this.inventory);
    
@Override
 
@Override
Line 142: Line 142:  
     if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY
 
     if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY
 
             && (direction == null || direction == Direction.UP || direction == Direction.DOWN)) {
 
             && (direction == null || direction == Direction.UP || direction == Direction.DOWN)) {
         return INVENTORY_OPTIONAL.cast();
+
         return this.inventoryOptional.cast();
 
     }
 
     }
 
     return super.getCapability(capability, direction); // See note after snippet
 
     return super.getCapability(capability, direction); // See note after snippet
Line 150: Line 150:  
protected void invalidateCaps() {
 
protected void invalidateCaps() {
 
     super.invalidateCaps();
 
     super.invalidateCaps();
     INVENTORY_OPTIONAL.invalidate();
+
     this.inventoryOptional.invalidate();
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 161: Line 161:     
=== Attaching a Capability ===
 
=== 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.
 +
 +
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''' 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.addCapabilities(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.
    
=== Accessing a Capability ===
 
=== Accessing a Capability ===