Skip to content

Item Behaviors

Item behaviors are used to add functionality to items. There are some default implementations, but you can also create your own.

Default Item Behaviors

Default Item Behaviors

These are the default item behaviors that Nova provides:

Allows you to make an item that stores energy. This should mostly be used with other custom item behaviors, since there is no default implementation for consuming energy.

val EXAMPLE_ITEM = registerDefaultItem(ExampleAddon, "example_item", Chargeable)

The above example uses the durability bar to display the item's charge. If you don't want this, you can disable this behavior:

val EXAMPLE_ITEM = registerDefaultItem(ExampleAddon, "example_item", Chargeable(false))

The energy capacity can then be configured in the material config file:

configs/example_item.yml
max_energy: 100000

Allows you to make a custom consumable item. Example:

val EXAMPLE_ITEM = registerDefaultItem(ExampleAddon, "example_item", Consumable)
configs/example_item.yml
# The type of food (normal, fast, always_eatable).
food_type: normal
# The time it takes for the food to be consumed, in ticks.
consume_time: 40
# The nutrition value this food provides.
nutrition: 4
# The saturation modifier this food provides.
saturation_modifier: 0.3
# The amount of health to be restored immediately.
instant_health: 5
# A list of effects to apply to the player when this food is consumed.
effects: []
Saturation & Nutrition

This is how the saturation_modifier and nutrition value affects your player's food level and saturation:

foodLevel
min(player.foodLevel + options.nutrition, 20)
saturation
min(saturation + nutrition * saturationModifier * 2.0f, foodLevel)

You can find the nutrition and saturationModifier for vanilla items by decompiling the mojang-mapped class net.minecraft.world.food.Foods.

Example Effect
effects:
# A level 1 speed effect that lasts 10 seconds.
- type: speed # (1)!
  duration: 200 # (2)!
  amplifier: 0 # (3)!
  ambient: true # (4)!
  particles: true # (5)!
  icon: true # (6)!
  1. The type of the effect.
    A list of all effect types can be found here.
  2. The duration of the effect in ticks.
  3. The amplifier of the effect. An amplifier of 0 is a level 1 effect.
  4. Whether the effect is ambient or not.
    Default value: true
  5. Whether the effect has particles or not.
    Default value: true
  6. Whether the effect has an icon or not.
    Default value: true

Allows you to make an item that can be equipped in a players armor slots.

val EXAMPLE_ITEM = registerDefaultItem(ExampleAddon, "example_item", Wearable(ArmorType.CHESTPLATE, Sound.ITEM_ARMOR_EQUIP_DIAMOND))
configs/example_item.yml
armor: 8.0
armor_toughness: 3.0
knockback_resistance: 2.0

If you need some examples for the armor, armorToughness and knockback_resistance values, you can check out the Minecraft wiki.

Allows you to create a custom tool.

val EXAMPLE_ITEM = registerDefaultItem(ExampleAddon, "example_item", Tool)
configs/example_item.yml
# The tool level
tool_level: minecraft:iron
# The tool category
tool_category: minecraft:sword
# The block breaking speed
break_speed: 1.5
# The attack damage
attack_damage: 6
# The attack speed
attack_speed: 2.0
# The knockback bonus
knockback_bonus: 1
# If sweep attacks can be performed with this tool
can_sweep_attack: true
# If this tool can break blocks in creative
can_break_blocks_in_creative: false

Makes an item damageable.

val EXAMPLE_ITEM = registerDefaultItem(ExampleAddon, "example_item", Damageable)
configs/example_item.yml
# The maximum durability of the item.
max_durability: 200
# The damage the item takes when it is used to attack an entity.
item_damage_on_attack_entity: 1
# The damage the item takes when it is used to break a block.
item_damage_on_break_block: 2
# The repair ingredient that can be used in anvils.
repair_ingredient: "minecraft:paper"

Makes your item enchantable.

val EXAMPLE_ITEM = registerDefaultItem(ExampleAddon, "example_item", Enchantable)
configs/example_item.yml
# The enchantment value
enchantment_value: 10 # (1)!
# The enchantment categories
enchantment_categories: ["weapon", "breakable"] # (2)!
  1. The enchantment value of the item. This value defines how enchantable an item is. A higher enchantment value means more secondary and higher-level enchantments.
    Vanilla enchantment values: wood: 15, stone: 5, iron: 14, diamond: 10, gold: 22, netherite: 15
  2. The enchantment categories of the item. This defines which enchantments can be applied to this item.
    Available enchantment categories: armor, armor_feet, armor_legs, armor_chest, armor_head, weapon, digger, fishing_rod, trident, breakable, bow, wearable, crossbow, vanishable

Gives your item the ability to strip wood, logs, oxidization layers and wax.

val EXAMPLE_ITEM = registerDefaultItem(ExampleAddon, "example_item", Stripping)

Gives your item the ability to create dirt paths.

val EXAMPLE_ITEM = registerDefaultItem(ExampleAddon, "example_item", Flattening)

Gives your item the ability to extinguish campfires.

val EXAMPLE_ITEM = registerDefaultItem(ExampleAddon, "example_item", Extinguishing)

Gives your item the ability to till dirt.

val EXAMPLE_ITEM = registerDefaultItem(ExampleAddon, "example_item", Tilling)
Using hardcoded material options (not recommended)

If you don't want your material options to be configurable or your specific use-case does not work well with configurable values, you can using the factory functions named after the material options interfaces.
For example, this is how you would create hardcoded ToolOptions:

Hardcoded ToolOptions
@OptIn(HardcodedMaterialOptions::class)
val toolOptions = ToolOptions(
    ToolLevel.STONE,
    ToolCategory.PICKAXE,
    breakSpeed = 12.0,
    attackDamage = 4.0,
    attackSpeed = 1.0,
    canSweepAttack = false,
    canBreakBlocksInCreative = false
)

Since hardcoding those values is strongly discouraged, you need to opt-in via the @OptIn(HardcodedMaterialOptions::class) annotation.

Custom Item Behaviors

There are of course a lot of cases that don't fit into any of the default item behaviors which is why you can easily make your own. Just create a new class and extend ItemBehavior. Instead of registering event handlers, you can override the handle...() functions, which are called when something is done with an ItemStack of a material with that behavior.

val vanillaMaterialProperties

A Provider for a list of VanillaMaterialPropertys.
Vanilla material properties define what properties the item should have client-side. Based on the given properties, a corresponding vanilla material will be used. Nova will always try to find a vanilla material with the exact same properties as requested. If there is no such material, Nova might also choose a vanilla material with more vanilla material properties. If there is no material that has all requested properties, properties of low importance will be ignored.

These are the available vanilla material properties:

Property Name Effect
DAMAGEABLE The item has a durability bar.
CREATIVE_NON_BLOCK_BREAKING The item cannot break blocks in creative mode.
CONSUMABLE_NORMAL The item can be consumed normally.
CONSUMABLE_ALWAYS The item can always be consumed.
CONSUMABLE_FAST The item can be consumed fast, the eating process start without a delay.
HELMET The item can render a custom helmet texture.
CHESTPLATE The item can render a custom chestplate texture.
LEGGINGS The item can render a custom leggings texture.
BOOTS The item can render a custom boots texture.
FIRE_RESISTANT The item will not catch on fire.

val attributeModifiers

A Provider for a list of AttributeModifiers.

Example Attribute Modifiers
override val attributeModifiers = provider(listOf(
    AttributeModifier(
        name = "Example Attribute Modifier (${novaMaterial.id}})", // (1)!
        attribute = Attributes.MOVEMENT_SPEED, // (2)!
        operation = Operation.MULTIPLY_TOTAL, // (3)!
        value = 0.1, // (4)!
        showInLore = true, // (5)!
        EquipmentSlot.MAINHAND // (6)!
    )
))
  1. The name of the attribute modifier. This is also used to create a UUID for your AttributeModifier to distinguish it from other AttributeModifiers. It is important that different AttributeModifiers have different UUIDs.
  2. The attribute that should be modified.
  3. The operation that should be done.
  4. The value that should be used for the operation. In this case, the movement speed will be increased by 10%.
  5. Whether the attribute modifier should be shown in the ItemStack's lore.
  6. The equipment slot(s) that this attribute modifier should be applied to.

fun modifyItemBuilder

This function is called when an ItemBuilder is created for an ItemStack of a material with this behavior.
Here, you can add additional NBT data to the ItemStack by calling ItemBuilder.addModifer.

Modifying display name, lore and other attributes

Do not use this method to modify the item's display name, lore, or other properties that are not required for the item to work server-side.
For that, use the updatePacketItemData function instead.

fun updatePacketItemData

This method is called every time a packet that includes an ItemStack of a material with this ItemBehavior is sent to a player.
Here, you can customize how the item is displayed for the player. Using the given PacketItemData, you can modify things like the display name, lore (normal and advanced tooltips), the durability bar and more.

Confused? Take a look at Understanding Packet Items.

ItemBehaviorFactory & MaterialOptions / ConfigAccess

If you want to create item behaviors that can be added with a similar syntax as the default item behaviors, you'll need to inherit from ItemBehaviorFactory in the companion object of your ItemBehavior. Then, implement the create(ItemNovaMaterial) function. Here, you can create an instance of your ItemBehavior based on the ItemNovaMaterial that is passed to the function.

With ConfigAccess, you easily create a class that houses config-reloadable properties for your item behavior.
Here is an example of how we implement ItemBehaviorFactory and ConfigAccess for food items.

Item Data

If you need to store or retrieve data from an ItemStack, call ItemStack.novaCompound to retrieve the CBF Compound. There, you can store any data you want.

Tip

Make sure to check out the CBF documentation for more information.
CBF Documentation