diff --git a/docs/datastorage/nbt.md b/docs/datastorage/nbt.md new file mode 100644 index 000000000..c2f583180 --- /dev/null +++ b/docs/datastorage/nbt.md @@ -0,0 +1,98 @@ +# Named Binary Tag (NBT) + +NBT is a format introduced in the earliest days of Minecraft, written by Notch himself. It is widely used throughout the Minecraft codebase for data storage. + +## Specification + +The NBT spec is similar to the JSON spec, with a few differences: + +- Distinct types for bytes, shorts, longs and floats exist, suffixed by `b`, `s`, `l` and `f`, respectively, similar to how they would be represented in Java code. + - Doubles may also be suffixed with `d`, but this is not required, similar to Java code. The optional `i` suffix available in Java for integers is not permitted. + - The suffixes are not case-sensitive. So for example, `64b` is the same as `64B`, and `0.5F` is the same as `0.5f`. +- Booleans do not exist, they are instead represented by bytes. `true` becomes `1b`, `false` becomes `0b`. + - The current implementation treats all non-zero values as `true`, so `2b` would be treated as `true` as well. +- There is no `null` equivalent in NBT. +- Quotes around keys are optional. So a JSON property `"duration": 20` can become both `duration: 20` and `"duration": 20` in NBT. +- What is known in JSON as a sub-object is known in NBT as a **compound tag** (or just compound). +- NBT lists cannot mix and match types, unlike in JSON. The list type is determined by the first element, or defined in code. + - However, lists of lists can mix and match different list types. So a list of two lists, where the first one is a list of strings and the second one is a list of bytes, is allowed. +- There are special **array** types that are different from lists, but follow their scheme of containing elements in square brackets. There are three array types: + - Byte arrays, denoted by a `B;` at the beginning of the array. Example: `[B;0b,30b]` + - Integer arrays, denoted by a `I;` at the beginning of the array. Example: `[I;0,-300]` + - Long arrays, denoted by an `L;` at the beginning of the array. Example: `[L;0l,240l]` +- Trailing commas in lists, arrays and compound tags are allowed. + +## NBT Files + +Minecraft uses `.nbt` files extensively, for example for structure files in [datapacks][datapack]. Region files (`.mca`) that contain the contents of a region (i.e. a collection of chunks), as well as the various `.dat` files used in different places by the game, are NBT files as well. + +NBT files are typically compressed with GZip. As such, they are binary files and cannot be edited directly. + +## NBT in Code + +Like in JSON, all NBT objects are children of an enclosing object. So let's create one: + +```java +CompoundTag tag = new CompoundTag(); +``` + +We can now put our data into that tag: + +```java +tag.putInt("Color", 0xffffff); +tag.putString("Level", "minecraft:overworld"); +tag.putDouble("IAmRunningOutOfIdeasForNamesHere", 1d); +``` + +Several helpers exist here, for example, `putIntArray` also has a convenience method that takes a `List` in addition to the standard variant that takes an `int[]`. + +Of course, we can also get values from that tag: + +```java +int color = tag.getInt("Color"); +String level = tag.getString("Level"); +double d = tag.getDouble("IAmRunningOutOfIdeasForNamesHere"); +``` + +Number types will return 0 if absent. Strings will return `""` if absent. More complex types (lists, arrays, compounds) will throw an exception if absent. + +As such, we want to safeguard by checking if a tag element exists: + +```java +boolean hasColor = tag.contains("Color"); +boolean hasColorMoreExplicitly = tag.contains("Color", Tag.TAG_INT); +``` + +The `TAG_INT` constant is defined in `Tag`, which is the super interface for all tag types. Most tag types besides `CompoundTag` are mostly internal, for example `ByteTag` or `StringTag`, though the direct `CompoundTag#get` and `#put` methods can work with them if you ever stumble across some. + +There is one obvious exception, though: `ListTag`s. Working with these is special because when getting a list tag through `CompoundTag#getList`, you must also specify the list type. So getting a list of strings, for example, would work like this: + +```java +ListTag list = tag.getList("SomeListHere", Tag.TAG_STRING); +``` + +Similarly, when creating a `ListTag`, you must also specify the list type during creation: + +```java +ListTag list = new ListTag(List.of("Value1", "Value2"), Tag.TAG_STRING); +``` + +Finally, working with `CompoundTag`s inside other `CompoundTag`s directly utilizes `CompoundTag#get` and `#put`: + +```java +tag.put("Tag", new CompoundTag()); +tag.get("Tag"); +``` + +## Usages of NBT + +NBT is used in a lot of places in Minecraft. Some of the most common examples include [`ItemStack`][itemstack]s, [`BlockEntity`][blockentity]s and `Entity`s. + +## See Also + +- [NBT Format on the Minecraft Wiki][nbtwiki] + +[blockentity]: ../blockentities/index.md +[datapack]: ../resources/server/index.md +[itemstack]: ../items/index.md#itemstacks +[nbtwiki]: https://minecraft.wiki/w/NBT_format diff --git a/docs/items/index.md b/docs/items/index.md index 2b592394d..12deb27ad 100644 --- a/docs/items/index.md +++ b/docs/items/index.md @@ -1,72 +1,153 @@ -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. +- 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`. + +`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`][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 (= 0.8) of applying the Hunger effect when eaten. This method comes in two variants; you should use the one that takes in a supplier (the other one directly takes a mob effect instance and is deprecated by NeoForge due to classloading issues). +- `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. + +The two most common use cases for items are left-clicking and right-clicking. For left-clicking, see [Breaking a Block][breaking] and Attacking an Entity (WIP). For right-clicking, see [The Interaction Pipeline][interactionpipeline]. + +### 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 + +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][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. + +`ItemStack`s are mutable objects (see below), however it is sometimes required to treat them as immutables. If you need to modify an `ItemStack` that is to be treated immutable, you can clone the stack using `itemstack.copy()`. + +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 and RegistryObject called ITEM and BLOCK +//MyItemsClass.MY_ITEM is a Supplier, MyBlocksClass.MY_BLOCK is a Supplier @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 called REGISTRAR -public static final RegistryObject 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 +public static final Supplier 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 -------------------- - -Items must be [registered][registering] to function. - +[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 +[mobeffectinstance]: mobeffects.md#mobeffectinstances [modbus]: ../concepts/events.md#mod-event-bus +[nbt]: ../datastorage/nbt.md [registering]: ../concepts/registries.md#methods-for-registering +[resources]: ../resources/client/index.md +[sides]: ../concepts/sides.md diff --git a/docs/items/mobeffects.md b/docs/items/mobeffects.md new file mode 100644 index 000000000..1af79dfe4 --- /dev/null +++ b/docs/items/mobeffects.md @@ -0,0 +1,201 @@ +# Mob Effects & Potions + +Status effects, sometimes known as potion effects and referred to in-code as `MobEffect`s, are effects that influence an entity every tick. This article explains how to use them, what the difference between an effect and a potion is, and how to add your own. + +## Terminology + +- A `MobEffect` affects an entity every tick. Like [blocks][block] or [items][item], `MobEffect`s are registry objects, meaning they must be [registered][registration] and are singletons. + - An **instant mob effect** is a special kind of mob effect that is designed to be applied for one tick. Vanilla has two instant effects, Instant Health and Instant Harming. +- A `MobEffectInstance` is an instance of a `MobEffect`, with a duration, amplifier and some other properties set (see below). `MobEffectInstance`s are to `MobEffect`s what [`ItemStack`s][itemstack] are to `Item`s. +- A `Potion` is a collection of `MobEffectInstance`s. Vanilla mainly uses potions for the four potion items (read on), however, they can be applied to any item at will. It is up to the item if and how the item then uses the potion set on it. +- A **potion item** is an item that is meant to have a potion set on it. This is an informal term, the vanilla `PotionItem` class has nothing to do with this (it refers to the "normal" potion item). Minecraft currently has four potion items: potions, splash potions, lingering potions, and tipped arrows; however more may be added by mods. + +## `MobEffect`s + +To create your own `MobEffect`, extend the `MobEffect` class: + +```java +public class MyMobEffect extends MobEffect { + public MyMobEffect(MobEffectCategory category, int color) { + super(category, color); + } + + @Override + public void applyEffectTick(LivingEntity entity, int amplifier) { + // Apply your effect logic here. + } + + // Whether the effect should apply this tick. Used e.g. by the Regeneration effect that only applies + // once every x ticks, depending on the tick count and amplifier. + @Override + public boolean shouldApplyEffectTickThisTick(int tickCount, int amplifier) { + return tickCount % 2 == 0; // replace this with whatever check you want + } + + // Utility method that is called when the effect is first added to the entity. + @Override + public void onEffectStarted(LivingEntity entity, int amplifier) { + } +} +``` + +Like all registry objects, `MobEffect`s must be registered, like so: + +```java +//MOB_EFFECTS is a DeferredRegister +public static final Supplier MY_MOB_EFFECT = MOB_EFFECTS.register("my_mob_effect", () -> new MyMobEffect( + //Can be either BENEFICIAL, NEUTRAL or HARMFUL. Used to determine the potion tooltip color of this effect. + MobEffectCategory.BENEFICIAL, + //The color of the effect particles. + 0xffffff +)); +``` + +If you want your effect to act solely as a marker, you can also directly use the `MobEffect` class, like you can with the `Block` or `Item` classes. + +The `MobEffect` class also provides default functionality for adding attribute modifiers to affected entities. For example, the speed effect adds an attribute modifier for movement speed. Effect attribute modifiers are added like so: + +```java +public static final String MY_MOB_EFFECT_UUID = "01234567-89ab-cdef-0123-456789abcdef"; +public static final Supplier MY_MOB_EFFECT = MOB_EFFECTS.register("my_mob_effect", () -> new MyMobEffect(...) + .addAttributeModifier(Attribute.ATTACK_DAMAGE, MY_MOB_EFFECT_UUID, 2.0, AttributeModifier.Operation.ADD) +); +``` + +:::note +The UUID used must be a valid and unique UUIDv4, as for some reason, Mojang decided to use UUIDs here instead of some text-based identifier. A UUID is best obtained through an online generator, for example [uuidgenerator.net][uuidgen]. +::: + +### `InstantenousMobEffect` + +If you want to create an instant effect, you can use the helper class `InstantenousMobEffect` instead of the regular `MobEffect` class, like so: + +```java +public class MyMobEffect extends InstantenousMobEffect { + public MyMobEffect(MobEffectCategory category, int color) { + super(category, color); + } + + @Override + public void applyEffectTick(LivingEntity entity, int amplifier) { + // Apply your effect logic here. + } +} +``` + +Then, register your effect like normal. + +### Events + +Many effects have their logic applied in other places. For example, the levitation effect is applied in the living entity movement handler. For modded `MobEffect`s, it often makes sense to apply them in an [event handler][events]. NeoForge also provides a few events related to effects: + +- `MobEffectEvent.Applicable` is fired when the game checks whether a `MobEffectInstance` can be applied to an entity. This event can be used to deny or force adding the effect instance to the target. +- `MobEffectEvent.Added` is fired when the `MobEffectInstance` is added to the target. This event contains information about a previous `MobEffectInstance` that may have been present on the target. +- `MobEffectEvent.Expired` is fired when the `MobEffectInstance` expires, i.e. the timer goes to zero. +- `MobEffectEvent.Remove` is fired when the effect is removed from the entity through means other than expiring, e.g. through drinking milk or via commands. + +## `MobEffectInstance`s + +A `MobEffectInstance` is, simply put, an effect applied to an entity. Creating a `MobEffectInstance` is done by calling the constructor: + +```java +MobEffectInstance instance = new MobEffectInstance( + // The mob effect to use. + MobEffects.REGENERATION, + // The duration to use, in ticks. Defaults to 0 if not specified. + 500, + // The amplifier to use. This is the "strength" of the effect, i.e. Strength I, Strength II, etc; + // starting at 0. Defaults to 0 if not specified. + 0, + // Whether the effect is an "ambient" effect, meaning it is being applied by an ambient source, + // of which Minecraft currently has the beacon and the conduit. Defaults to false if not specified. + false, + // Whether the effect is visible in the inventory. Defaults to true if not specified. + true, + // Whether an effect icon is visible in the top right corner. Defaults to true if not specified. + true +); +``` + +Several constructor overloads are available, omitting the last 1-5 parameters, respectively. + +:::info +`MobEffectInstance`s are mutable. If you need a copy, call `new MobEffectInstance(oldInstance)`. +::: + +### Using `MobEffectInstance`s + +A `MobEffectInstance` can be added to an entity like so: + +```java +MobEffectInstance instance = new MobEffectInstance(...); +entity.addEffect(instance); +``` + +Similarly, `MobEffectInstance` can also be removed from an entity. Since a `MobEffectInstance` overwrites pre-existing `MobEffectInstance`s of the same `MobEffect` on the entity, there can only ever be one `MobEffectInstance` per `MobEffect` and entity. As such, specifying the `MobEffect` suffices when removing: + +```java +entity.removeEffect(MobEffects.REGENERATION); +``` + +:::info +`MobEffect`s can only be applied to `LivingEntity` or its subclasses, i.e. players and mobs. Things like items or thrown snowballs cannot be affected by `MobEffect`s. +::: + +## `Potion`s + +`Potion`s are created by calling the constructor of `Potion` with the `MobEffectInstance`s you want the potion to have. For example: + +```java +//POTIONS is a DeferredRegister +public static final Supplier MY_POTION = POTIONS.register("my_potion", () -> new Potion(new MobEffectInstance(MY_MOB_EFFECT.get(), 3600))); +``` + +Note that the parameter of `new Potion` is a vararg. This means that you can add as many effects as you want to the potion. This also means that it is possible to create empty potions, i.e. potions that don't have any effects. Simply call `new Potion()` and you're done! (This is how vanilla adds the `awkward` potion, by the way.) + +The name of the potion can be passed as the first constructor argument. It is used for translating; for example, the long and strong potion variants in vanilla use this to have the same names as their base variant. The name is not required; if it is omitted, the name will be queried from the registry. + +The `PotionUtils` class offers various helper methods related to potions, such as `getPotion` and `setPotion` for item stacks (this can be any kind of item and is not limited to potion items), or `getColor` for getting a potion's display color. + +### Brewing + +Now that your potion is added, potion items are available for your potion. However, there is no way to obtain your potion in survival, so let's change that! + +Potions are traditionally made in the Brewing Stand. Unfortunately, Mojang does not provide [datapack][datapack] support for brewing recipes, so we have to be a little old-fashioned and add our recipes through code. This is done like so: + +```java +// The brewing ingredient. This is the item at the top of the brewing stand. +Ingredient brewingIngredient = Ingredient.of(Items.FEATHER); +BrewingRecipeRegistry.addRecipe( + // The input potion ingredient, often an awkward potion. This is the item at the bottom of the brewing stand. + // Does not need to be a potion, but typically is. + PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.AWKWARD), + // Our brewing ingredient. + brewingIngredient, + // The resulting item stack. Does not need to be a potion, but typically is. + PotionUtils.setPotion(new ItemStack(Items.POTION), MY_POTION) +); +// We also need to do this separately for splash potions and lingering potions. +// The tipped arrow recipe is taken care of by Minecraft's tipped arrow special crafting handler. +BrewingRecipeRegistry.addRecipe( + PotionUtils.setPotion(new ItemStack(Items.SPLASH_POTION), Potions.AWKWARD), + brewingIngredient, + PotionUtils.setPotion(new ItemStack(Items.SPLASH_POTION), MY_POTION) +); +BrewingRecipeRegistry.addRecipe( + PotionUtils.setPotion(new ItemStack(Items.LINGERING_POTION), Potions.AWKWARD), + brewingIngredient, + PotionUtils.setPotion(new ItemStack(Items.LINGERING_POTION), MY_POTION) +); +``` + +This should be called some time during setup, for example during [`FMLCommonSetupEvent`][commonsetup]. Make sure to wrap this into an `event.enqueueWork()` call, as the brewing recipe registry is not thread-safe. + +[block]: ../blocks/index.md +[commonsetup]: ../concepts/events.md#mod-event-bus +[datapack]: ../resources/server/index.md +[events]: ../concepts/events.md +[item]: index.md +[itemstack]: index.md#itemstacks +[registration]: ../concepts/registries.md +[uuidgen]: https://www.uuidgenerator.net/version4 diff --git a/docs/items/tools.md b/docs/items/tools.md new file mode 100644 index 000000000..d37fcfb70 --- /dev/null +++ b/docs/items/tools.md @@ -0,0 +1,282 @@ +# Tools & Armor + +Tools are [items][item] whose primary use is to break [blocks][block]. Many mods add new tool sets (for example copper tools) or new tool types (for example hammers). + +## Custom Tool Sets + +A tool set typically consists of five items: a pickaxe, an axe, a shovel, a hoe and a sword. (Swords aren't tools in the classical sense, but are included here for consistency as well.) All of those items have their corresponding class: `PickaxeItem`, `AxeItem`, `ShovelItem`, `HoeItem` and `SwordItem`, respectively. The class hierarchy of tools looks as follows: + +```text +Item +- TieredItem + - DiggerItem + - AxeItem + - HoeItem + - PickaxeItem + - ShovelItem + - SwordItem +``` + +`TieredItem` is a class that contains helpers for items with a certain `Tier` (read on). `DiggerItem` contains helpers for items that are designed to break blocks. Note that other items usually considered tools, such as shears, are not included in this hierarchy. Instead, they directly extend `Item` and hold the breaking logic themselves. + +To create a standard set of tools, you must first define a `Tier`. For reference values, see Minecraft's `Tiers` enum. This example uses copper tools, you can use your own material here and adjust the values as needed. + +```java +// We place copper somewhere between stone and iron. +public static final Tier COPPER_TIER = new SimpleTier( + // Determines the level of this tool. Since this is an int, there is no good way to place our tool between stone and iron. + // NeoForge introduces the TierSortingRegistry to solve this problem, see below for more information. Use a best-effort approximation here. + // Stone is 1, iron is 2. + 1, + // Determines the durability of the tier. + // Stone is 131, iron is 250. + 200, + // Determines the mining speed of the tier. Unused by swords. + // Stone uses 4, iron uses 6. + 5f, + // Determines the attack damage bonus. Different tools use this differently. For example, swords do (getAttackDamageBonus() + 4) damage. + // Stone uses 1, iron uses 2, corresponding to 5 and 6 attack damage for swords, respectively; our sword does 5.5 damage now. + 1.5f, + // Determines the enchantability of the tier. This represents how good the enchantments on this tool will be. + // Gold uses 22, we put copper slightly below that. + 20, + // The tag that determines what blocks this tool can break. See below for more information. + MyBlockTags.NEEDS_COPPER_TOOL, + // Determines the repair ingredient of the tier. Use a supplier for lazy initializing. + () -> Ingredient.of(Tags.Items.INGOTS_COPPER) +); +``` + +Now that we have our `Tier`, we can use it for registering tools. All tool constructors have the same four parameters. + +```java +//ITEMS is a DeferredRegister +public static final Supplier COPPER_SWORD = ITEMS.register("copper_sword", () -> new SwordItem( + // The tier to use. + COPPER_TIER, + // The type-specific attack damage bonus. 3 for swords, 1.5 for shovels, 1 for pickaxes, varying for axes and hoes. + 3, + // The type-specific attack speed modifier. The player has a default attack speed of 4, so to get to the desired + // value of 1.6f, we use -2.4f. -2.4f for swords, -3f for shovels, -2.8f for pickaxes, varying for axes and hoes. + -2.4f, + // The item properties. We don't need to set the durability here because TieredItem handles that for us. + new Item.Properties() +)); +public static final Supplier COPPER_AXE = ITEMS.register("copper_axe", () -> new AxeItem(...)); +public static final Supplier COPPER_PICKAXE = ITEMS.register("copper_pickaxe", () -> new PickaxeItem(...)); +public static final Supplier COPPER_SHOVEL = ITEMS.register("copper_shovel", () -> new ShovelItem(...)); +public static final Supplier COPPER_HOE = ITEMS.register("copper_hoe", () -> new HoeItem(...)); +``` + +### Tags + +When creating a `Tier`, it is assigned a block [tag][tags] containing blocks that need this tool (or a better one) to be broken. For example, the `minecraft:needs_iron_tool` tag contains Diamond Ores (among others), and the `minecraft:needs_diamond_tool` tag contains blocks like Obsidian and Ancient Debris. + +You can reuse one of these tags for your tool if you're fine with that. For example, if we wanted our copper tools to just be more durable stone tools, we'd pass in `BlockTags.NEEDS_STONE_TOOL`. + +Alternatively, we can create our own tag, like so: + +```java +public static final TagKey NEEDS_COPPER_TOOL = TagKey.create(BuiltInRegistries.BLOCK.key(), new ResourceLocation(MOD_ID, "needs_copper_tool")); +``` + +And then, we populate our tag. For example, let's make copper able to mine gold ores, gold blocks and redstone ore, but not diamonds or emeralds. (Redstone blocks are already mineable by stone tools.) The tag file is located at `src/main/resources/data/mod_id/tags/blocks/needs_copper_tool.json` (where `mod_id` is your mod id): + +```json +{ + "values": [ + "minecraft:gold_block", + "minecraft:raw_gold_block", + "minecraft:gold_ore", + "minecraft:deepslate_gold_ore", + "minecraft:redstone_ore", + "minecraft:deepslate_redstone_ore" + ] +} +``` + +Finally, we can pass our tag into our tier creation, as seen above. + +### `TierSortingRegistry` + +In order to make the game actually pick up your tier as between two others, you must register it to the `TierSortingRegistry`. This must happen before item registration, a `static` initializer in the same class as your tier definition is a good spot for that. If you do not add your tier to the registry, it will fall back to what vanilla would do. + +```java +public static final Tier COPPER_TIER = new SimpleTier(...); + +static { + TierSortingRegistry.registerTier( + COPPER_TIER, + //The name to use for internal resolution. May use the Minecraft namespace if appropriate. + new ResourceLocation("minecraft", "copper"), + //A list of tiers that are considered lower than the type being added. For example, stone is lower than copper. + //We don't need to add wood and gold here because those are already lower than stone. + List.of(Tiers.STONE), + //A list of tiers that are considered higher than the type being added. For example, iron is higher than copper. + //We don't need to add diamond and netherite here because those are already higher than iron. + List.of(Tiers.IRON) + ); +} +``` + +Instead of or in addition to a `Tier`, you can also pass in other tiers' ids into these lists. For example, say we want to make our material be considered weaker than both iron and the Osmium tools from [Mekanism Tools][mektools], we could do that like so: + +```java +public static final Tier COPPER_TIER = new SimpleTier(...); + +static { + TierSortingRegistry.registerTier( + COPPER_TIER, + new ResourceLocation("minecraft", "copper"), + List.of(Tiers.STONE), + //We can mix and match Tiers and ResourceLocations here. + List.of(Tiers.IRON, new ResourceLocation("mekanism", "osmium")) + ); +} +``` + +This works for both the lower and higher tiers. If multiple options are available, the system will choose the strictest bounds available. + +:::caution +Be aware that circular dependencies may occur if this is set up incorrectly, so make sure that your bounds actually make sense and don't all cross-reference one another. +::: + +If you want to check if a tier is applicable for a block state, call `TierSortingRegistry#isCorrectTierForDrops`. + +## Custom Tool Types + +Custom tool types can be created by extending `DiggerItem` (or `TieredItem` if you are making custom weapon types). They don't need too big of a setup, it is an item class like any other, with all implications that has. + +One thing worth noting is the parameters of `DiggerItem`. The first four parameters are the same as for its subclasses (see the explanation for `SwordItem` above), while the fifth parameter is the `mineable` tag for the tool type. Generally, the format here is `:mineable/`, though `forge` can be used as the namespace too if you expect other mods to add similar tools. For example, [Farmer's Delight][farmersdelight] uses a `forge:mineable/knives` tag. + +If you plan on making a multitool-like item (i.e. an item that combines two or more tools into one, e.g. an axe and a pickaxe as one item), it is best to extend `AxeItem` if applicable. This is because enchantment checks for things like Sharpness or Knockback are hardcoded to `instanceof AxeItem`. + +## `ToolAction`s + +`ToolAction`s are an abstraction over what a tool can and cannot do. This includes both left-click and right-click behavior. NeoForge provides default `ToolAction`s in the `ToolActions` class: + +- Digging actions. These exist for all four `DiggerItem` types as mentioned above, as well as sword and shears digging. +- Axe right-click actions for stripping (logs), scraping (oxidized copper) and unwaxing (waxed copper). +- Shear actions for harvesting (honeycombs), carving (pumpkins) and disarming (tripwires). +- Actions for shovel flattening (dirt paths), sword sweeping, hoe tilling, shield blocking, and fishing rod casting. + +To create your own `ToolAction`s, use `ToolAction#get` - it will create a new `ToolAction` if needed. Then, in a custom tool type, override `IItemExtension#canPerformAction` as needed. + +To query if an `ItemStack` can perform a certain `ToolAction`, call `IItemStackExtension#canPerformAction`. Note that this works on any `Item`, not just tools. + +## Armor + +Similar to tools, armor uses a tier system (although a different one). What is called `Tier` for tools is called `ArmorMaterial` for armors. Like above, this example shows how to add copper armor; this can be adapted as needed. For the vanilla values, see the `ArmorMaterials` enum. + +```java +// We place copper somewhere between chainmail and iron. +public static final ArmorMaterial COPPER_ARMOR_MATERIAL = new ArmorMaterial() { + // The name of the armor material. Mainly determines where the armor texture is. Should contain + // a leading mod id to guarantee uniqueness, otherwise there may be issues when two mods + // try to add the same armor material. (If the mod id is omitted, the "minecraft" namespace will be used.) + @Override + public String getName() { + return "modid:copper"; + } + + // Override for StringRepresentable. Should generally return the same as getName(). + @Override + public String getSerializedName() { + return getName(); + } + + // Determines the durability of this armor material, depending on what armor piece it is. + // ArmorItem.Type is an enum of four values: HELMET, CHESTPLATE, LEGGINGS and BOOTS. + // Vanilla armor materials determine this by using a base value and multiplying it with a type-specific constant. + // The constants are 13 for BOOTS, 15 for LEGGINGS, 16 for CHESTPLATE and 11 for HELMET. + // Both chainmail and iron use 15 as the base value, so we'll use it as well. + @Override + public int getDurabilityForType(ArmorItem.Type type) { + return switch (type) { + case HELMET -> 11 * 15; + case CHESTPLATE -> 16 * 15; + case LEGGINGS -> 15 * 15; + case BOOTS -> 13 * 15; + }; + } + + // Determines the defense value of this armor material, depending on what armor piece it is. + @Override + public int getDurabilityForType(ArmorItem.Type type) { + return switch (type) { + case HELMET -> 2; + case CHESTPLATE -> 4; + case LEGGINGS -> 6; + case BOOTS -> 2; + }; + } + + // Returns the toughness value of the armor. The toughness value is an additional value included in + // damage calculation, for more information, refer to the Minecraft Wiki's article on armor mechanics: + // https://minecraft.wiki/w/Armor#Armor_toughness + // Only diamond and netherite have values greater than 0 here, so we just return 0. + @Override + public float getToughness() { + return 0; + } + + // Returns the knockback resistance value of the armor. While wearing this armor, the player is + // immune to knockback to some degree. If the player has a total knockback resistance value of 1 or greater + // from all armor pieces combined, they will not take any knockback at all. + // Only netherite has values greater than 0 here, so we just return 0. + @Override + public float getKnockbackResistance() { + return 0; + } + + // Determines the enchantability of the tier. This represents how good the enchantments on this armor will be. + // Gold uses 25, we put copper slightly below that. + @Override + public int getEnchantmentValue(ArmorItem.Type type) { + return 20; + } + + // Determines the sound played when equipping this armor. + @Override + public SoundEvent getEquipSound() { + return SoundEvents.ARMOR_EQUIP_GENERIC; + } + + // Determines the repair item for this armor. + @Override + public Ingredient getRepairIngredient() { + return Ingredient.of(Tags.Items.INGOTS_COPPER); + } + + // Optionally, you can also override #getArmorTexture here. This method returns a ResourceLocation + // that determines where the armor location is stored, in case you want to store it in a non-default location. + // See the default implementation in Tier for an example. +} +``` + +And then, we use that armor material in item registration. + +```java +//ITEMS is a DeferredRegister +public static final Supplier COPPER_HELMET = ITEMS.register("copper_helmet", () -> new ArmorItem( + // The armor material to use. + COPPER_ARMOR_MATERIAL, + // The armor type to use. + ArmorItem.Type.HELMET, + // The item properties. We don't need to set the durability here because ArmorItem handles that for us. + new Item.Properties() +)); +public static final Supplier COPPER_CHESTPLATE = ITEMS.register("copper_chestplate", () -> new ArmorItem(...)); +public static final Supplier COPPER_LEGGINGS = ITEMS.register("copper_leggings", () -> new ArmorItem(...)); +public static final Supplier COPPER_BOOTS = ITEMS.register("copper_boots", () -> new ArmorItem(...)); +``` + +Besides the usual resources, armors also need a worn armor texture that will be rendered over the player model when the armor is equipped. This texture must be located at `src/main/resources/assets//textures/models/armor/_layer_1.png` for the helmet, chestplate and boots textures, and in the same directory at `_layer_2.png` for the leggings. + +When creating your armor texture, it is a good idea to work on top of the vanilla armor texture to see which part goes where. + +[block]: ../blocks/index.md +[farmersdelight]: https://www.curseforge.com/minecraft/mc-mods/farmers-delight +[item]: index.md +[mektools]: https://www.curseforge.com/minecraft/mc-mods/mekanism-tools +[tags]: ../resources/server/tags.md