Skip to content

Ingredient Components

Ruben Taelman edited this page Jan 14, 2019 · 15 revisions

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.

Basics

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).

Generic Types

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.

Parameters

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 of IngredientComponentCategoryType'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

Registry

All ingredient components are available in an IForgeRegistry (IngredientComponent.REGISTRY), so that new ingredient components can be registered using Forge's registry events.

Match Conditions

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

Capabilities

Each ingredient component is a capability provider. As such, it can hold capabilities of any type.

Capabilities can be attached using the AttachCapabilitiesEventIngredientComponent event.

Storage

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().

Clone this wiki locally