-
Notifications
You must be signed in to change notification settings - Fork 3
Ingredient Components
As of CommonCapabilities 2.0.0, IngredientComponent
was introduced as an abstraction layer over "ingredients" such as items and fluids. This Ingredient Components API offers a way to interact with any kind of ingredient in a generic way, and new types of ingredients can simply be added by implementing a couple methods.
One example of where this API is beneficial, is the IIngredientComponentStorage
interface, which is an abstract way of handling with storages, such as item or fluid handler capabilities.
Another example where this is used is in the CyclopsCore Ingredient Collections API, which is a set of interfaces and classes that make it possible to store and query ingredient component instances in a generic way
The motivation behind this Ingredient Components API is that logic for handling things like items, fluids and energy is very similar. Instead of writing really similar code for each of these types, it is better to write all of this code once, but in an abstract way, so that it can be reused for each type. Furthermore, writing this logic only once reduces the chances of bugs. This abstract has been fully unit-tested to make this abstraction as robust as possible.
Each IngredientComponent
represents a type of ingredient.
As such, each ingredient component should only be created once,
and should be saved for later usage.
By default CommonCapabilities will provide instances for items (IngredientComponent.ITEMSTACK
), fluids (IngredientComponent.FLUIDSTACK
) and energy (IngredientComponent.ENERGY
).
According to the Java class, each ingredient component has two parameters: T
and M
.
T
represents the type of instances, for example, ItemStack
or FluidStack
.
M
represents the type of match condition, an object that is used internally to compare different instances by, for example Integer
or Boolean
.
When a new ingredient component is constructed, four things are required:
-
ResourceLocation
: A unique name -
IIngredientMatcher
: A helper class to handle and match instances of this type. -
IIngredientSerializer
: A helper class to (de)serialize instances of this type to and from NBT. -
List<IngredientComponentCategoryType<T, M, ?>>
: A list ofIngredientComponentCategoryType
's an instance is composed of, and what its link with the match condition is. This is used to internally to efficiently compare instances with each other.
An example of how CommonCapabilities instantiates ingredient components can be found here: https://github.com/CyclopsMC/CommonCapabilities/blob/master-1.12/src/main/java/org/cyclops/commoncapabilities/IngredientComponents.java
All ingredient components are available in an IForgeRegistry
(IngredientComponent.REGISTRY
), so that new ingredient components can be registered using Forge's registry events.
A match condition for an ingredient component can be used to compare instances by.
For example, the match condition for items is a bit sequence represented by an Integer
.
All relevant bits for items can be found in ItemMatch
.
The table below show several examples of how (Integer
) match conditions can be used to compare items.
Instance 1 | Instance 2 | Match Condition | Result |
---|---|---|---|
new ItemStack(Items.APPLE, 1) |
new ItemStack(Items.APPLE, 1) |
ItemMatch.EXACT |
true |
new ItemStack(Items.APPLE, 1) |
new ItemStack(Items.APPLE, 1) |
ItemMatch.ITEM |
true |
new ItemStack(Items.APPLE, 1) |
new ItemStack(Items.APPLE, 1) |
ItemMatch.STACKSIZE |
true |
new ItemStack(Items.BOW, 1) |
new ItemStack(Items.APPLE, 1) |
ItemMatch.EXACT |
false |
new ItemStack(Items.BOW, 1) |
new ItemStack(Items.APPLE, 1) |
ItemMatch.ITEM |
false |
new ItemStack(Items.BOW, 1) |
new ItemStack(Items.APPLE, 1) |
ItemMatch.STACKSIZE |
true |
Each ingredient component is a capability provider. As such, it can hold capabilities of any type.
Capabilities can be attached using the AttachCapabilitiesEventIngredientComponent
event.
The IIngredientComponentStorage
interface allows abstract storage of ingredients.
It is a way to generically interact with for example the IItemHandler
and IFluidHandler
interfaces.
The easiest way to use this abstraction, is by converting capabilities to an IIngredientComponentStorage
via the IngredientComponent#getStorage()
method. For example:
IIngredientComponentStorage<ItemStack, Integer> myStorage = IngredientComponent.ITEMSTACK
.getStorage(myTileEntity, EnumFacing.EAST);
At the time of writing, the following capabilities can be converted for the given ingredient components:
Ingredient component | Capabilities |
---|---|
IngredientComponent.ItemStack |
IItemHandler , ISlotlessItemHandler
|
IngredientComponent.FluidStack |
IFluidHandler , IFluidHandlerItem
|
IngredientComponent.Energy |
IEnergyStorage |
Support for new capabilities can be added via IngredientComponent#setStorageWrapperHandler()
.