Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework and expand the Items section #39

Merged
merged 10 commits into from
Jan 14, 2024
174 changes: 131 additions & 43 deletions docs/items/index.md
Original file line number Diff line number Diff line change
@@ -1,72 +1,160 @@
Items
=====
# Items

Along with blocks, items are a key component of most mods. While blocks make up the level around you, items exist within inventories.
Along with blocks, items are a key component of Minecraft. While blocks make up the world around you, items exist within inventories.

Creating an Item
----------------
## What Even Is an Item?

### Basic Items
Before we get further into creating items, it is important to understand what an item actually is, and what distinguishes it from, say, a [block][block]. Let's illustrate this using an example:

Basic items that need no special functionality (think sticks or sugar) do not need custom classes. You can create an item by instantiating the `Item` class with an `Item$Properties` object. This `Item$Properties` object can be made via the constructor and customized by calling its methods. For instance:
- In the world, you encounter a dirt block and want to mine it. This is a **block**, because it is placed in the world. (Actually, it is not a block, but a blockstate. See the [Blockstates article][blockstates] for more detailed information.)
- Not all blocks drop themselves when breaking (e.g. leaves), see the article on [loot tables][loottables] for more information.
- Once you have [mined the block][breaking], it is removed (= replaced with an air block) and the dirt drops. The dropped dirt is an item **entity**. This means that like other entities (pigs, zombies, arrows, etc.), it can inherently be moved by things like water pushing on it, or burned by fire and lava.
- Once you pick up the dirt item entity, it becomes an **item stack** in your inventory. An item stack is, simply put, an instance of an item with some extra information, such as the stack size.
IchHabeHunger54 marked this conversation as resolved.
Show resolved Hide resolved
- Item stacks are backed by their corresponding **item** (which is what we're creating). Items hold information that is the same across all items (for example, every iron sword has a max durability of 250), while item stacks hold information that can be different between two similar items (for example, one iron sword has 100 uses left, while another iron sword has 200 uses left). For more information on what is done through items and what is done through item stacks, read on.
- The relationship between items and item stacks is roughly the same as between [blocks][block] and [blockstates][blockstates], in that a blockstate is always backed by a block. It's not a really accurate comparison (item stacks aren't singletons, for example), but it gives a good basic idea about what the concept is here.

| Method | Description |
|:------------------:|:----------------------------------------------|
| `requiredFeatures` | Sets the required `FeatureFlag`s needed to see this item in the `CreativeModeTab` it is added to. |
| `durability` | Sets the maximum damage value for this item. If it is over `0`, two item properties "damaged" and "damage" are added. |
| `stacksTo` | Sets the maximum stack size. You cannot have an item that is both damageable and stackable. |
| `setNoRepair` | Makes this item impossible to repair, even if it is damageable. |
| `craftRemainder` | Sets this item's container item, the way that lava buckets give you back an empty bucket when they are used. |
## Creating an Item

The above methods are chainable, meaning they `return this` to facilitate calling them in series.
Now that we understand what an item is, let's create one!

### Advanced Items
Like with basic blocks, for basic items that need no special functionality (think sticks, sugar, etc.), the `Item` class can be used directly. To do so, during registration, instantiate `Item` with a `Item.Properties` parameter. This `Item.Properties` parameter can be created using `Item.Properties#of`, and it can be customized by calling its methods:

Setting the properties of an item as above only works for simple items. If you want more complicated items, you should subclass `Item` and override its methods.
- `stacksTo` - Sets the max stack size of this item. Defaults to 64. Used e.g. by ender pearls or other items that only stack to 16.
- `durability` - Sets the durability of this item. Defaults to 0, which means "no durability". For example, iron tools use 250 here. Note that setting the durability automatically locks the stack size to 1.
- `craftRemainder` - Sets the crafting remainder of this item. Vanilla uses this for filled buckets that leave behind empty buckets after crafting.
- `fireResistant` - Makes item entities that use this item immune to fire and lava. Used by various netherite items.
- `setNoRepair` - Disables anvil and crafting grid repairing for this item. Unused in vanilla.
- `rarity` - Sets the rarity of this item. Currently, this simply changes the item's color. `Rarity` is an enum consisting of the four values `COMMON` (white, default), `UNCOMMON` (yellow), `RARE` (aqua) and `EPIC` (light purple). Be aware that mods may add more rarity types.
- `requiredFeatures` - Sets the required feature flags for this item. This is mainly used for vanilla's feature locking system in minor versions. It is discouraged to use this, unless you're integrating with a system locked behind feature flags by vanilla.
- `food` - Sets the [`FoodProperties`][food] of this item.

For examples, or to look at the various values used by Minecraft, have a look at the `Items` class.

### Food

The `Item` class provides default functionality for food items, meaning you don't need a separate class for that. To make your item edible, all you need to do is set the `FoodProperties` on it through the `food` method in `Item.Properties`.
IchHabeHunger54 marked this conversation as resolved.
Show resolved Hide resolved

`FoodProperties` are created using a `FoodProperties.Builder`. You can then set various properties on it:

- `nutrition` - Probably the most obvious part. Sets how many hunger points are restored. Counts in half hunger points, so for example, Minecraft's steak restores 8 hunger points.
- `saturationMod` - The saturation modifier used in calculating the [saturation value][hunger] restored when eating this food. The calculation is `min(2 * nutrition * saturationMod, playerNutrition)`, meaning that using `0.5` will make the effective saturation value the same as the nutrition value.
- `meat` - Whether this item should be considered meat or not. Used e.g. for determining if healing dogs with this food is possible.
- `alwaysEat` - Whether this item can always be eaten, even if the hunger bar is full. `false` by default, `true` for golden apples and other items that provide bonuses beyond just filling the hunger bar.
- `fast` - Whether fast eating should be enabled for this food. `false` by default, `true` for dried kelp in vanilla.
- `effect` - Adds a `MobEffectInstance` to apply when eating this item. The second parameter denotes the probability of the effect being applied; for example, Rotten Flesh has an 80% chance of applying the Hunger effect when eaten. This method comes in two variants, one that takes in a supplier (for your own effects) and one that directly takes a `MobEffectInstance` (for vanilla effects).
IchHabeHunger54 marked this conversation as resolved.
Show resolved Hide resolved
- `build` - Once you've set everything you want to set, call `build` to get a `FoodProperties` object for further use.

For examples, or to look at the various values used by Minecraft, have a look at the `Foods` class.

To get the `FoodProperties` for an item, call `Item#getFoodProperties(ItemStack, LivingEntity)`. This may return null, since not every item is edible. To determine whether an item is edible, call `Item#isEdible()` or null-check the result of the `getFoodProperties` call.

### More Functionality

Directly using `Item` only allows for very basic items. If you want to add functionality, for example right-click interactions, a custom class that extends `Item` is required. The `Item` class has many methods that can be overridden to do different things; see the classes `Item` and `IItemExtension` for more information. See also [below][using] for the most common use cases.

### Resources

If you register your item and get your item (via `/give` or through a [creative tab][creativetabs]), you will find it to be missing a proper model and texture. This is because textures and models are handled by Minecraft's resource system.

To apply a simple texture to an item, you must add an item model JSON and a texture PNG. See the section on [resources][resources] for more information.

## `ItemStack`s
IchHabeHunger54 marked this conversation as resolved.
Show resolved Hide resolved

Like with blocks and blockstates, most places where you'd expect an `Item` actually use an `ItemStack` instead. `ItemStack`s represent a stack of one or multiple items in a container, e.g. an inventory. Again like with blocks and blockstates, methods should be overridden by the `Item` and called on the `ItemStack`, and many methods in `Item` get an `ItemStack` instance passed in.

An `ItemStack` consists of three major parts:

- The `Item` it represents, obtainable through `itemstack.getItem()`.
- The stack size, typically between 1 and 64, obtainable through `itemstack.getCount()` and changeable through `itemstack.setCount(int)` or `itemstack.shrink(int)`.
- The extra NBT data, where stack-specific data is stored. Obtainable through `itemstack.getTag()`, or alternatively through `itemstack.getOrCreateTag()` which accounts for no tag existing yet. A variety of other NBT-related methods exist as well, the most important being `hasTag()` and `setTag()`.
- It is worth nothing that `ItemStack`s with empty NBT are not the same as `ItemStack`s with no NBT at all. This means that they will not stack, despite being functionally equivalent to one another.

To create a new `ItemStack`, call `new ItemStack(Item)`, passing in the backing item. By default, this uses a count of 1 and no NBT data; there are constructor overloads that accept a count and NBT data as well if needed.

To clone an existing `ItemStack`, call `itemstack.copy()`.
IchHabeHunger54 marked this conversation as resolved.
Show resolved Hide resolved

If you want to represent that a stack has no item, use `ItemStack.EMPTY`. If you want to check whether an `ItemStack` is empty, call `itemstack.isEmpty()`.

### Mutability of `ItemStack`s

`ItemStack`s are mutable objects. This means that if you call for example `setCount`, `setTag` or `getOrCreateTag`, the `ItemStack` itself will be modified. Vanilla uses the mutability of `ItemStack`s extensively, and several methods rely on it. For example, `itemstack.split(int)` splits the given amount off the stack it is called on, both modifying the caller and returning a new `ItemStack` in the process.

However, this can sometimes lead to issues when dealing with multiple `ItemStack`s at once. The most common instance where this arises is when handling inventory slots, since you have to consider both the `ItemStack` currently selected by the cursor, as well as the `ItemStack` you are trying to insert to/extract from.

:::tip
When in doubt, better be safe than sorry and `#copy()` the stack.
:::

## Creative Tabs

An item can be added to a `CreativeModeTab` via `BuildCreativeModeTabContentsEvent` on the [mod event bus][modbus]. An item(s) can be added without any additional configurations via `#accept`.
By default, your item will only be available through `/give` and not appear in the creative inventory. Let's change that!

The way you get your item into the creative menu depends on what tab you want to add it to.

### Existing Creative Tabs

:::note
This method is for adding your items to Minecraft's tabs, or to other mods' tabs. To add items to your own tabs, see below.
:::

An item can be added to an existing `CreativeModeTab` via the `BuildCreativeModeTabContentsEvent`, which is fired on the [mod event bus][modbus], only on the [logical client][sides]. Add items by calling `event#accept`.

```java
// Registered on the MOD event bus
// Assume we have RegistryObject<Item> and RegistryObject<Block> called ITEM and BLOCK
//MyItemsClass.MY_ITEM is a Supplier<? extends Item>, MyBlocksClass.MY_BLOCK is a Supplier<? extends Block>
@SubscribeEvent
public void buildContents(BuildCreativeModeTabContentsEvent event) {
// Add to ingredients tab
if (event.getTabKey() == CreativeModeTabs.INGREDIENTS) {
event.accept(ITEM);
event.accept(BLOCK); // Takes in an ItemLike, assumes block has registered item
}
public static void buildContents(BuildCreativeModeTabContentsEvent event) {
// Is this the tab we want to add to?
if (event.getTabKey() == CreativeModeTabs.INGREDIENTS) {
event.accept(MyItemsClass.MY_ITEM);
// Accepts an ItemLike. This assumes that MY_BLOCK has a corresponding item.
event.accept(MyBlocksClass.MY_BLOCK);
}
}
```

You can also enable or disable items being added through a `FeatureFlag` in the `FeatureFlagSet` or a boolean determining whether the player has permissions to see operator creative tabs.
The event also provides some extra information, such as `getFlags()` to get the list of enabled feature flags, or `hasPermissions()` to check if the player has permissions to view the operator items tab.

### Custom Creative Tabs

A custom `CreativeModeTab` must be [registered][registering]. The builder can be created via `CreativeModeTab#builder`. The tab can set the title, icon, default items, and a number of other properties. In addition, Forge provides additional methods to customize the tab's image, label and slot colors, where the tab should be ordered, etc.
`CreativeModeTab`s are a registry, meaning custom `CreativeModeTab`s must be [registered][registering]. Creating a creative tab uses a builder system, the builder is obtainable through `CreativeModeTab#builder`. The builder provides options to set the title, icon, default items, and a number of other properties. In addition, NeoForge provides additional methods to customize the tab's image, label and slot colors, where the tab should be ordered, etc.

```java
// Assume we have a DeferredRegister<CreativeModeTab> called REGISTRAR
public static final RegistryObject<CreativeModeTab> EXAMPLE_TAB = REGISTRAR.register("example", () -> CreativeModeTab.builder()
// Set name of tab to display
.title(Component.translatable("item_group." + MOD_ID + ".example"))
// Set icon of creative tab
.icon(() -> new ItemStack(ITEM.get()))
// Add default items to tab
.displayItems((params, output) -> {
output.accept(ITEM.get());
output.accept(BLOCK.get());
})
.build()
//CREATIVE_MODE_TABS is a DeferredRegister<CreativeModeTab>
public static final Supplier<CreativeModeTab> EXAMPLE_TAB = CREATIVE_MODE_TABS.register("example", () -> CreativeModeTab.builder()
//Set the title of the tab. Don't forget to add a translation!
.title(Component.translatable("itemGroup." + MOD_ID + ".example"))
//Set the icon of the tab.
.icon(() -> new ItemStack(MyItemsClass.EXAMPLE_ITEM.get()))
//Add your items to the tab.
.displayItems((params, output) -> {
output.accept(MyItemsClass.MY_ITEM);
// Accepts an ItemLike. This assumes that MY_BLOCK has a corresponding item.
output.accept(MyBlocksClass.MY_BLOCK);
})
.build()
);
```

Registering an Item
-------------------
## Using Items

### Left-Click

See [Breaking a Block][breaking] and Attacking an Entity (WIP).

### Right-Click

Items must be [registered][registering] to function.
See [The Interaction Pipeline][interactionpipeline].
IchHabeHunger54 marked this conversation as resolved.
Show resolved Hide resolved

[block]: ../blocks/index.md
[blockstates]: ../blocks/states.md
[breaking]: ../blocks/index.md#breaking-a-block
[creativetabs]: #creative-tabs
[food]: #food
[hunger]: https://minecraft.wiki/w/Hunger#Mechanics
[interactionpipeline]: interactionpipeline.md
[loottables]: ../resources/server/loottables.md
[modbus]: ../concepts/events.md#mod-event-bus
[registering]: ../concepts/registries.md#methods-for-registering
[resources]: ../resources/client/index.md
[sides]: ../concepts/sides.md
[using]: #using-items
Loading