Skip to main content
Version: 1.20.x

Slot Modifiers

A tutorial on how to add and remove slots from the curios inventory on entities.

Overview

Slot modifiers are a way to dynamically add and/or remove slots from entities the same way developers could add and/or remove health or attack damage. In fact, it uses the exact same AttributeModifier system to accomplish this.

Getting Started

The main way to interact with and add slot modifiers is through the top.theillusivec4.curios.api.type.capability.ICuriosItemHandler interface. A developer can grab the specific instance of this on the entity by following the steps from the inventory guide to query the capability from Curios.

Adding or Removing Slots

Adding slots can be done through ICuriosItemHandler#addTransientSlotModifiers(Multimap<String, AttributeModifier>) and ICuriosItemHandler#addPermanentSlotModifiers(Multimap<String, AttributeModifier>).

A transient slot modifier is a slot modifier that is not serialized to the player data, while a permanent slot modifier is serialized. The former will disappear upon players relogging into a world and the latter will always remain until manually removed. Transient slot modifiers are often used for effects that may not always be present and need to be verified at certain times while permanent slot modifiers are often used as rewards or other effects that are not meant to be removed often, if ever.

tip

For slot types that should not appear until given by a relevant slot modifier, be sure to set the default amount of slots to 0 so that it does not give any slots by default.

An example of adding a transient slot modifier:

CuriosApi.getCuriosInventory(livingEntity).ifPresent(inventory -> {
inventory.addTransientSlotModifier("ring", uuid, "name", 2, AttributeModifier.Operation.ADDITION));
});

This will add 2 slots to the ring slot type, with the specified name and uuid (UUID is not provided so developers will need to generate or substitute one). Note that each key for the map must be a valid SlotType identifier, such as "ring" or "necklace".

In the case of adding multiple slot modifiers at once:

CuriosApi.getCuriosInventory(livingEntity).ifPresent(inventory -> {
Map<String, AttributeModifier> map = LinkedHashMultimap.create();
map.put("ring", new AttributeModifier(uuid, "name", 2, AttributeModifier.Operation.ADDITION));
map.put("necklace", new AttributeModifier(uuid, "name", 1, AttributeModifier.Operation.ADDITION));
inventory.addTransientSlotModifiers(map);
});

If slots need to be removed, this is as simple as stating a negative amount for an AttributeModifier.Operation.ADDITION operation in the AttributeModifier:

inventory.addTransientSlotModifier("ring", uuid, "name", -2, AttributeModifier.Operation.ADDITION));

Instead of adding 2 slots, this will remove 2 slots.

If the total slot amount results in a number less than 0, the slots will remain at 0 but the slot modifiers will remain and existing slot modifiers will stack with each other. If a slot modifier removes 2 slots and the base amount is already 0, there will seemingly be no effect. However, if another slot modifier adds 3 slots on top of that, it will add to the existing -2 and result in a total of 1 slot.

caution

Slot modifiers can only add slots for slot types that are already assigned to entities. If a slot type exists but is not assigned to the specified entity, then the slot modifier will not be able to add any slots of that slot type. Be sure to go over how to assign slots to entities if slot modifiers do not appear to be adding any slots.

Removing Slot Modifiers

Removing slot modifiers can be done through ICuriosItemHandler#removeSlotModifiers(Multimap<String, AttributeModifier>).

This follows very similar logic as the preceding section on adding slot modifiers:

CuriosApi.getCuriosInventory(livingEntity).ifPresent(inventory -> {
inventory.removeSlotModifier("ring", uuid);
})

This will remove the slot modifier with UUID uuid from the ring slot type.

In the case of removing multiple slot modifiers at once:

CuriosApi.getCuriosInventory(livingEntity).ifPresent(inventory -> {
Map<String, AttributeModifier> map = LinkedHashMultimap.create();
map.put("ring", new AttributeModifier(uuid, "name", 2, AttributeModifier.Operation.ADDITION));
inventory.removeSlotModifiers(map);
})

The AttributeModifier used is mostly filler, the amount and operation do not matter. The key and the uuid, however, must match the ones used for the slot modifier being removed.

Items

The methods above are helpful for universal applications, but there are more streamlined methods for developers that want to attach slot modifiers to specific items so that they are only applied when those items are equipped and then removed when unequipped.

Interfaces

Both the ICurio and ICurioItem interfaces expose a method called getAttributeModifiers that returns a Multimap<Attribute, AttributeModifier> denoting attributes and their modifiers, in the same way that items themselves have a similar method when equipped in vanilla slots. For more information on attaching these interfaces to items, see the curio creation page.

@Override
public Multimap<Attribute, AttributeModifier> getAttributeModifiers(SlotContext slotContext, UUID uuid) {
Multimap<Attribute, AttributeModifier> map = LinkedHashMultimap.create();
// Add attribute modifiers
return map;
}

In order to add slot modifiers specifically, developers can leverage the CuriosApi#addSlotModifier(Multimap, String, UUID, double, AttributeModifier.Operation) method:

@Override
public Multimap<Attribute, AttributeModifier> getAttributeModifiers(SlotContext slotContext, UUID uuid) {
Multimap<Attribute, AttributeModifier> map = LinkedHashMultimap.create();
CuriosApi.addSlotModifier(map, "ring", uuid, 2, AttributeModifier.Operation.ADDITION);
return map;
}

This will add 2 slots of the ring slot type using the passed in uuid from the second parameter of the method. The slots will only be added when this item is equipped and those slots will be removed when this item is unequipped.

caution

Although the uuid in the preceding section can be decided on a case-by-case basis, the uuid in this section related to items is strongly encouraged to be fed from the second parameter of the getAttributeModifiers method. This is because the UUID in the parameter is guaranteed to be slot-specific, which avoids any collision issues in case multiple instances of the same item are equipped.

NBT Tag

The previous method works for items that developers can directly register or implement interfaces or capabilities for, but this can fall short if developers want to add these modifiers dynamically or even override previously registered behavior.

As an alternative, developers can directly add slot modifiers to item NBT tags as well using CuriosApi#addSlotModifier(ItemStack, String, String, UUID, double, AttributeModifier.Operation, String):

CuriosApi.addSlotModifier(stack, "ring", "name", uuid, 2, AttributeModifier.Operation.ADDITION, "necklace");

There are two slot identifiers in this method. The first one, "ring" above, denotes the slot type that the slot modifier gives or removes slots from. The second one, "necklace" above, denotes the slot type that the slot modifier becomes active in. In other words, the above example will give 2 ring slots when the item is equipped in a necklace slot.

caution

It's usually best to use null in place of the uuid, to avoid collisions as described in the preceding caution note, unless there is justification for providing a static UUID. Providing a null UUID will allow Curios to provide a slot-specific UUID in its place.