Creating Items
Creating an Item Registry
To create a custom item, you'll first need to create an ItemRegistry
:
@Init(stage = InitStage.PRE_PACK) // (1)!
object Items ItemRegistry by ExampleAddon.registry {
// (2)!
}
- Nova will load this class during addon initialization, causing your items to be registered.
- Register your items here
Creating Items
You can register a really simple item like this:
@Init(stage = InitStage.PRE_PACK)
object Items ItemRegistry by ExampleAddon.registry {
val EXAMPLE_ITEM = registerItem("example_item", /* Item Behaviors */)
}
This item will default to the model under models/item/example_item.json
or alternatively create a basic item model
with the texture textures/item/example_item.png
.
Item Model Definitions
Item Model Definitions - Minecraft Wiki
Item Model Defintions are a 1.21.4 feature. You may interested in the Minecraft wiki page on this topic.
Nova offers a DSL builder for creating item model definitions:
@Init(stage = InitStage.PRE_PACK)
object Items ItemRegistry by ExampleAddon.registry {
val EXAMPLE_ITEM = item("example_item") {
modelDefinition {
model = /* ... */
}
}
}
In this scope, you'll need to set the "root" model of the item. Your options here are:
model
: A normal model, allows defining tints. You may want to use the shortcut functionbuildModel
instead.composite
: A composite model, which allows rendering multiple models in the same space.condition
: A model is selected based on a condition that is eithertrue
orfalse
.select
: A model is selected based on a value, such as an enum or a string.rangeDispatch
: A model is selected based on a number. If there is no exact match, the closest lower value is used.empty
: An empty model- Various "special" models, that use hardcoded rendering logic.
There are also some shortcut functions available for generating rangeDispatch
models: numberedModels
, rangedModels
Models are nested, so you can have, for example, a select
model that chooses another select
model.
Refer to the KDocs for a full list of available functions and properties.
Model
This is the most basic model type. You will need this type as a leaf of all your models, as it is the only type that directly links to a model file. Additionally, this type also allows you to define tints.
model = model {
tintSource[0] = TintSource.CustomModelData(Color.WHITE, 0) // (1)!
model = { getModel("item/my_item") } // (2)!
}
- This sets
tintindex
0 to read the color value 0 from theminecraft:custom_model_data
component. - This sets the model to
item/my_item
. In the model selector scope, you have additional functionality available that can be used to generate models at runtime.
Composite
This model type allows you to render multiple models in the same space.
- Adds a model to the composite. You can either create a model like for the root model, or define a model selector lambda directly.
Condition
This model type allows you to choose a model based on a condition.
model = condition(ConditionItemModelProperty.KeybindDown(Keybind.LEFT)) { // (1)!
onTrue = buildModel { getModel("item/left") } // (2)!
onFalse = buildModel { getModel("item/not_left") }
}
- This condition checks if the keybind
LEFT
is pressed. If it is, the modelitem/left
is used, otherwiseitem/not_left
. buildModel { /* ... */ }
is a shortcut formodel { model = { /* ... */ } }
.
Select
This model type allows you to choose a model based on a value.
model = select(SelectItemModelProperty.ChargedType) { // (1)!
case[ChargedType.NONE] = { getModel("item/crossbow")}
case[ChargedType.ARROW] = { getModel("item/crossbow_arrow")}
case[ChargedType.ROCKET] = composite { /* ... */ }
}
- Selects over the value of the
minecraft:charged_projectile
.
Range Dispatch
model = rangeDispatch(RangeDispatchItemModelProperty.Cooldown) { // (1)!
entry[0] = { getModel("item/my_item_ready") }
entry[0.5] = { getModel("item/my_item_half_ready") }
entry[1] = { getModel("item/my_item_not_ready") }
}
- Selects a model based on the value of the
minecraft:cooldown
component. You can add as many intermediate models as you want. The client will always render the one with the closest lower value.
Special
There are various special model types available. These use hardcoded rendering logic and are not achievable through regular model files.
The following special models exist:
bedSpecialModel
, bannerSpecialModel
, conduitSpecialModel
, chestSpecialModel
, decoratedPotSpecialModel
headSpecialModel
, shulkerBoxSpecialModel
, shieldSpecialModel
, standingSignSpecialModel
, tridentSpecialModel
,
hangingSignSpecialModel
model = chestSpecialModel {
texture = ResourcePath.of(ResourceType.ChestTexture, "my_addon:iron_chest")
openness = 0.5
}
NovaItem
Getting an ItemStack
To get an ItemStack from a NovaItem
, use NovaItem.createItemStack(amount)
.
Getting ItemBehaviors
Using the function hasItemBehavior<T>()
and getItemBehavior<T>()
you can check for and get an ItemBehavior of
a certain type.
Client-side items
Using NovaItem.clientsideProvider
and NovaItem.createClientsideItemBuilder()
you can obtain client-side items.
To understand the difference between a normal (server-side) and a client-side item, you first need to understand how custom
items are handled in Nova.
In order to be extremely flexible when it comes to changing custom model data, the underlying vanilla item type, the lore
format of the item or its display name, Nova's ItemStacks do not store this information at all.
All of these values are actually only applied on packet level, which can be observed by running the command
/data get entity @p SelectedItem
while holding an item from Nova: its item type will always be shulker_shell
and it
won't have any custom model data, display name or lore, even though it has one for your game.
Coming back to client-side item builders and providers: These are wrappers for the ItemStacks that the client actually sees.
They should only be used in cases where the ItemStack isn't actually stored anywhere, for example as a button in a GUI
or for FakeEntities
.
Generally, you should use NovaItem.clientsideProvider
and NovaItem.createClientsideItemBuilder()
when working with GUIs and NovaItem.createItemStack(amount)
if you need an item to give to a player.