From ecdd3b2e6a100db75315f7051be3e2c08883bd90 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Fri, 19 Apr 2024 18:26:53 +0000 Subject: [PATCH] Fabric for Minecraft 1.20.5 --- _posts/2024-04-19-1205.md | 501 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 501 insertions(+) create mode 100644 _posts/2024-04-19-1205.md diff --git a/_posts/2024-04-19-1205.md b/_posts/2024-04-19-1205.md new file mode 100644 index 00000000..d7148539 --- /dev/null +++ b/_posts/2024-04-19-1205.md @@ -0,0 +1,501 @@ +--- +layout: post +title: Fabric for Minecraft 1.20.5 +ref: 1205 +--- +Minecraft 1.20.5 is to be released in the near future with significant changes affecting mod makers. + +But first, we need to make this clear: **1.20.5 is a record-breaking update.** This development cycle spans from December 18, 2023 to April of 2024, the longest for any "dot release". We saw 15 snapshots, the first time it became two digits for a dot release (previous record was 1.20.3 for 8 snapshots). And no surprise: the amount of changes is also unprecedented. + +For this reason, **we ask all players to be patient, and give mod developers time to update to this new version.** We ask everyone kindly not to pester them. 1.20.5 is expected to be the last update of the 1.20 series. + +**We recommend all players to make a backup of the world.** For content mod users, creating a new world is recommended, as most mods do not handle world data upgrades of this magnitude. + +Here is a list of all major modder-facing changes in this version. Note that all code references are using Yarn mappings; modders using alternative mappings may need to use different names. + +## Java 21 +Minecraft 1.20.5 now requires Java 21 to run. This means mods can be compiled for Java 21 and use the latest features. This also marks the end of 32-bit support. + +To set up a development environment you will need to use Java 21, Loom 1.6, and Gradle 8.6 or higher. + +## Fabric changes +Developers should use Loom 1.6 (at the time of writing) to develop mods for Minecraft 1.20.5. Players should install the latest stable version of Fabric Loader (currently 0.15.10). + +### Loom 1.5 & 1.6 +There has been two major updates to Loom since the last blogpost: 1.5 and 1.6. + +Loom 1.5 includes several performance boosts and small bug fixes. Notably, the mixins can now be remapped using the Tiny Remapper instead of Mixin annotation processor. When enabled, the mixins are remapped in-place and the output jar no longer contains a refmap. This is currently experimental and opt-in. + +Loom 1.6 also brought more performance improvements. Decompiler caches were added, meaning that changes to access wideners no longer cause the entire game to be decompiled. There is also an update to how Loom handles existing locks (such as when two Gradle runs occur simultaneously) - it will no longer clear the cache, instead waiting for one process to exit. The error message for locked files is now more detailed, as well. + +Please see the [Loom 1.5](https://github.com/FabricMC/fabric-loom/releases/tag/1.5) and [Loom 1.6](https://github.com/FabricMC/fabric-loom/releases/tag/1.6) release notes for all of the changes. + +### Localization +Fabric has recently moved to using Crowdin to help manage translations for our projects. This makes it much easier to contribute translations across all Fabric projects. + +Current projects include Fabric API and installer. If you are able to help translate Fabric into your language, please visit [the Crowdin website](https://crowdin.com/project/fabricmc). + +### New Fabric API changes +With the help of many contributors, Fabric API has received some new features since the last update blog post: + +- New API: Data Attachments. This allows attaching custom data to block entities, chunks, entites, and worlds. Attached data can be saved or persisted between mob conversions. (Syst3ms) +- Interaction Events: add client after block break event (kevinthegreat1) +- GameTest API: add a system property for a custom output directory for gametest structures (ErrorCraft) +- Entity Events: add mob conversion event (Syst3ms) +- Fabric Rendering: add `AtlasSourceTypeRegistry` (PepperCode1) +- Data Generation: add `FabricCodecDataProvider` (ErrorCraft) +- Resource Loader: significant refactors to support `pack.mcmeta` metadata like filters and overlays. (apple502j) +- Fabric Rendering: add support for custom `ColorResolver`s (PepperCode1) +- Fluids Rendering: expose a function for querying the non-default fluid renderer (jellysquid3) +- Lifecycle Events: add save events to `ServerLifecycleEvents` (MrNavaStar) +- Item API: add enchantments API (Syst3ms) + +There is one more addition for advanced developers: you can now declare Fabric API as a dependency using BOM or version catalogs. Check [the pull request](https://github.com/FabricMC/fabric/pull/3487) for more details. + +### Breaking changes and deprecations +*Note: breaking changes related to vanilla changes are discussed below.* + +The following APIs were removed: + +- `fabric-containers-v0` (previously deprecated) +- `fabric-events-lifecycle-v0` (previously deprecated) +- `fabric-mining-level-api-v1` +- `ScreenRegistry` and `ScreenHandlerRegistry` + +`ModifyItemAttributeModifiersCallback` from the Item API was removed without replacement due to code changes making it infeasible to port. + +In Object Builder API, `FabricItemSettings` was removed. Use vanilla `Item.Settings` instead; interface injection provides settings added by Fabric API. Similarly, `FabricBlockSettings` was deprecated and replaced with vanilla `AbstractBlock.Settings`. `FabricEntityTypeBuilder` and `FabricBlockEntityTypeBuilder` were also deprecated; use vanilla builders instead. + +### Codec-based Resource Conditions +Unrelated to the 1.20.5 update, a significant change was made to Resource Conditions' internal workings. This update was developed by Apollo and apple502j. The only breaking change to the JSON syntax is the removal of `(block/item/fluid)_tags_populated` conditions, but data generation is heavily affected. + +The `ConditionJsonProvider` interface has been removed and been replaced by `ResourceCondition`. `ResourceCondition` has a `test` method, for determining whether the condition should pass, and `getType`, which returns a `ResourceConditionType`. `withConditions` methods in data providers now take `ResourceCondition` instances. Methods in `DefaultResourceConditions` that created conditions have been moved to `ResourceConditions`. A custom `ResourceConditionType` should be registered with `ResourceConditions#register`. + +In addition, `fabric:true` condition was added. This condition always passes. + +### Convention Tag unification +Another significant change was made in the Convention Tags. As part of collaborative efforts with NeoForge, TelepathicGrunt has prepared (and we released) the version 2 of the tags. Version 1 is now deprecated. + +As the changes are too long to list here, developers are encouraged to check the [pull request](https://github.com/FabricMC/fabric/pull/3310). + +## Minecraft changes +In short, these are the veeery major changes: + +- Item Components. Item stacks no longer use NBT as runtime data storage, instead using predefined "components" to keep values like custom name, enchantments, or damage. +- Networking. Instead of manually processing `PacketByteBuf`, packets are now serialized using `PacketCodec`s. In Fabric Networking API, the previous `PacketByteBuf`-based APIs were removed; the newer, `FabricPacket`-based API was rewritten to make use of the vanilla `CustomPayload` interface. +- Registries. Likely as a preparation for data-driven blocks and items, serialization/deserialization of most objects now require `RegistryWrapper.WrapperLookup` instance. This is most noticeable in texts and data generation. In addition, loot tables are now managed by a new type of registry called "reloadable registries". + +### Item Components +We skip the general description of the item components system, which you can check in the slicedlime's video: [News in Data Pack Version 33 (24w09a): Item Components!](https://www.youtube.com/watch?v=iY9OHAd4Aco). + +Now, we begin the journey into the implementation of item components: + +There are five main objects in the item components: + +- `DataComponentType`, a type of components, serving as keys; +- Component classes (can be any object), serving as values; +- `ComponentMap`, a read-only view of components; +- `ComponentMapImpl`, which is a `ComponentMap` that can be modified, and internally a pair of unmodifiable base `ComponentMap` and the "overrides" that are modified; and +- `ComponentChanges`, a map of component type to the changes for the value (either setting it to a specific value or removing it). This can be used as a diff applied to `ItemStack`; you apply an instance of `ComponentChanges` to `ItemStack`/`ComponentMapImpl`, so that the overrides part of the map reflects the changes. In other parts of the code, `ComponentChanges` is just used as `ComponentMapImpl` minus the base. + +So, how does this work? + +Each item has the base components. In addition to the base components common to all items, like having empty `EnchantmentsComponent`, some items provide additional base components. A notable example is `DataComponentTypes#DAMAGE` for armors, tools, and weapons. A component type that exists in the base has a corresponding default value; here the default damage is `0`. + +An `ItemStack` can either 1) add an additional component not present in the base; 2) change the components from the one in the base; or 3) remove a component that exists in the base. The final components of `ItemStack`, obtainable as `ComponentMap` from `ItemStack#getComponents`, reflects all three. + +#### Using Item Components + +Item components on item stacks have a similar API surface to a map. Here are some common operations that can be done, using the example of an item's custom name (note that `Text` is directly used as the component value): + +```java +// Similar to Map#get +@Nullable Text name = stack.get(DataComponentTypes.CUSTOM_NAME); + +// Similar to Map#put +// Returns the previous value, if any +@Nullable Text oldName = stack.set(DataComponentTypes.CUSTOM_NAME, Text.literal("Lorem ipsum")); + +// Similar to Map#getOrDefault +name = stack.getOrDefault(DataComponentTypes.CUSTOM_NAME, Text.empty()); + +// Similar to Map#remove +@Nullable Text removedName = stack.remove(DataComponentTypes.CUSTOM_NAME); + +// Similar to Map#compute +// In this example, we change the color of the item name +// (Note: stack#getName already checks for custom name, so in reality this does not need apply() call.) +stack.apply(DataComponentTypes.CUSTOM_NAME, stack.getName(), current -> current.copy().formatted(Formatting.RED)) +``` + +Getting/setting the custom data (NBT). This is useful for datapack makers and server-side modders, because custom item components (see below) need to be synced to the clients, while custom data remains an unparsed NBT. + +Unlike the previous example, this uses a component record `NbtComponent`. + +Note: **component values are supposed to be immutable** - even if you can modify it, don't. Always copy and `set()`. + +```java +NbtCompound nbt = ...; +NbtComponent component = NbtComponent.of(nbt); +// Setting +stack.set(DataComponentTypes.CUSTOM_DATA, component); + +// Getting a copy +@Nullable var data = stack.get(DataComponentTypes.CUSTOM_DATA); + +if (data != null) { + NbtCompound value = data.copyNbt(); +} + +// Using NbtComponent#apply, which copies automatically, to modify the NBT +// Note: you might want to use the static method NbtComponent#set instead, +// which makes this a bit shorter +stack.apply(DataComponentTypes.CUSTOM_DATA, NbtComponent.DEFAULT, comp -> comp.apply(currentNbt -> { + currentNbt.putInt("key", 0); +})); + +// Checking if a certain NBT is a subset of the stack NBT +// (also known as: "non-strict matching") +NbtCompound requiredNbt = ...; +boolean match = stack.getOrDefault(DataComponentTypes.CUSTOM_DATA, NbtComponent.DEFAULT).matches(requiredNbt); +// use createPredicate to make Predicate +``` + +Using `ComponentChanges` to mass-modify the components of `ItemStack`: + +```java +// stack is a damageable item. +// Repair the item and remove custom name. +// Note that the resulting stack has no components because 0 damage is the default from the base components. +var changes = ComponentChanges.builder().add(DataComponentTypes.DAMAGE, 0).remove(DataComponentTypes.CUSTOM_NAME).build(); +stack.applyChanges(changes); +``` + +Making an item with base components: + +```java +Item item = new Item(new Item.Settings().component(DataComponentTypes.CUSTOM_NAME, Text.literal("Hello"))); +// Call #component multiple times for multiple base components. +// Note: calling maxDamage automatically adds DAMAGE component. +``` + +Making a custom component. Note that like many registered entries, these must be present in both the client and the server. + +```java +public static final DataComponentType WEIRDNESS = DataComponentType.builder().codec(Codec.INT).packetCodec(PacketCodecs.VAR_INT).build(); +// in the initializer +Registry.register(Registries.DATA_COMPONENT_TYPE, new Identifier("example", "weirdness"), WEIRDNESS); +``` + +#### Some caveats +- Component values should not be modified directly. Using `Record` or other immutable object is highly recommended. Always copy, modify, then set. +- Setting an invalid value for a component does not cause an error immediately, but will lead to a crash during save, and possible data corruption. A common example is `NONNEGATIVE_INT` being used for an incrementing value; when it overflows and the value is set to negatives, saving it would crash. + +### BlockEntity interaction with components +`BlockEntity` stores the components when placing a block item stack with components and when pick-blocking. Components are not currently used to serialize block entities themselves. A block entity that uses components, like custom containers, should override `addComponents`, `readComponents`, and `removeFromCopiedStackNbt` methods: + +- `addComponents` adds the block entity's stored data to a component builder. +- `readComponents` reads the block entity data from components. +- `removeFromCopiedStackNbt` removes NBT keys which are now serialized using components when in item stacks. For example, a chest's held stacks are stored under `Items` key when the block entity itself is serialized, and stored under a component when an item stack for the block entity is serialized. To prevent double serialization, this method removes `Items` from the item stack NBT. + +Note that `LootableContainerBlockEntity` handles component changes themselves, so you do not have to reinvent the wheel if you use them. + +### Item Component-related Fabric API changes +`allowNbtUpdateAnimations` method of `FabricItem` was renamed to `allowComponentsUpdateAnimations`. +`FabricItem.getAttributeModifiers` changes? +`isSuitableFor` and `getFoodComponents` of `FabricItemStack` removed/replaced with vanilla components. + +#### Recipe API +`DefaultCustomIngredients#nbt` and support for NBT ingredients were removed, as the game no longer uses NBT to store item stack-specific data. + +To check for custom name, enchantments, etc that were previously kept inside the NBT but are now recorded in the components (see below for details), use the new `components` ingredient. To check for custom data component (a NBT data not used by the game but can be used by data packs or commands), use the `customData` ingredient. + +#### Transfer API +`TransferVariant` (such as `FluidVariant` or `ItemVariant`) is now a pair of the object and the components, instead of the object and NBT. `getNbt`, `hasNbt`, and `nbtMatches` methods were replaced with `getComponents`, `hasComponents`, and `componentsMatch` methods. The following methods were removed: `copyNbt`, `copyOrCreateNbt`, `toNbt`, and `toPacket`. + +`FluidVariant#of` and `ItemVariant#of` now takes `ComponentChanges` instead of `@Nullable NbtCompound`. + +`TransferVariant` is now serialized using codecs and packet codecs. Therefore, `fromNbt` and `fromPacket` static methods were removed. + +`SingleVariantStorage#writeNbt` instance method was removed; subclasses now provide separate methods named `writeNbt`. Both `readNbt` and `writeNbt` now require passing a `RegistryWrapper.WrapperLookup` instance; they should be available in the methods from which they are called (or you can use the world's `DynamicRegistryManager` instance). + + +### Other Item changes +- As noted in the video, an empty item stack is now serialized as omitting the field or an empty object. `ItemStack#fromNbt` now returns `Optional` while `fromNbtOrEmpty` supports empty NBT object. Both now require passing the registries. These methods log an error when an item with ID `minecraft:air` is encountered. +- `writeNbt` method was renamed to `encode`. The one with `NbtCompound` argument allows adding to the existing compound, like `writeNbt`. +- The methods in `ItemStack` that reference `Nbt` are generally renamed to reference `Components` instead. +- `Item#isNbtSynced` was removed, specify custom packet codecs instead. +- `Item#getBreakSound` was added. +- Attack damage and mining speed of `MiningToolItem` and `SwordItem` are now specified in item settings via `attributeModifiers` setting. +- Item tooltips are now given a "tooltip type", and `TooltipContext` is now under `Item`. `ItemTooltipCallback` Fabric API event now passes the type as well. Note that `hide_tooltip` item component prevents the event from being invoked. + +#### Item damages +When damaging an item stack held in the hands or in the armor slots, you now pass the `EquipmentSlot` instead of a callback: + +```diff +- stack.damage(1, entity, p -> p.sendToolBreakStatus(Hand.MAIN_HAND)); ++ stack.damage(1, entity, EquipmentSlot.MAINHAND); +``` + +When damaging an item stack held by non-entities (like shears in dispensers), the stack must be broken by the newly passed callback, not by checking the return value. + +```diff +- if (stack.damage(1, random, null)) stack.setCount(0); ++ stack.damage(1, random, null, () -> stack.setCount(0)); +``` + +In Fabric API, `CustomDamageHandler` callback's signature was changed from `ItemStack stack, int amount, LivingEntity entity, Consumer breakCallback` to `ItemStack stack, int amount, LivingEntity entity, EquipmentSlot slot, Runnable breakCallback`. Additionally, calling `breakCallback` now ignores the return value and vanilla damage handler (as the item is already broken). + +### Networking +Previously, networking code was simple: reading from, and writing to, `PacketByteBuf`. Although this method still works, Mojang has added an abstraction layor: `PacketCodec`. + +`PacketCodec` works like the DataFixerUpper codecs used in JSON/NBT serialization - although they are not compatible with each other. To keep it simple, **`PacketCodec` is a pair of deserializers and serializers** - or, decoders and encoders. This change reduces bugs related to wrong read/write order - which is one of the most difficult bugs to identify. + +#### How to create a PacketCodec +Note: A new subclass of `PacketByteBuf`, **`RegistryByteBuf`, is used for PLAY-phase networking** (the one you're probably using). For `ConfigurationNetworking`, use `PacketByteBuf` instead of `RegistryByteBuf`. `PacketCodec`s are usually stored in a `public static final` field. + +Suppose we are serializing this record: + +```java +public record VirtualHugs(int count) { + // Note: replaced PacketByteBuf with RegistryByteBuf + public VirtualHugs(RegistryByteBuf buf) { + this(buf.readVarInt()); + } + + // Instance method + public void write(RegistryByteBuf buf) { + buf.writeVarInt(count); + } + + // Static method, buffer-first + public static void write2(RegistryByteBuf buf, VirtualHugs hugs) { + buf.writeVarInt(hugs.count()) + } +} +``` + +1. The easy method - adopting existing code + +```java +PacketCodec PACKET_CODEC = PacketCodec.of(VirtualHugs::write, VirtualHugs::new); + +// Or, using static method: +PACKET_CODEC = PacketCodec.ofStatic(VirtualHugs::write2, VirtualHugs::new); +``` + +2. The new method - building codecs from other codecs, like in DataFixerUpper + +```java +// "tuple" is an ordered, un-keyed set of stuff. +// Up to 3 fields can be serialized with vanilla method. +// The constructor always comes last. +CODEC = PacketCodec.tuple(PacketCodecs.VAR_INT, VirtualHugs::count, VirtualHugs::new); + +// Or, since there is only one field in VirtualHugs, this works too. +CODEC = PacketCodecs.VAR_INT.xmap(VirtualHugs::new, VirtualHugs::count); +``` + +**You might see some nasty casting errors in some cases. Call `.cast()` on the codec to make it go away;** it's generally safe to do so. + +#### Advanced PacketCodecs examples +Here are some more examples: + +```java +// For a singleton (like an empty packet). Encoding something other than INSTANCE will error. +// It does not actually touch the buffer. +var singleton = PacketCodec.unit(INSTANCE); + +// Using PacketCodec from classic API +Text text = TextCodecs.PACKET_CODEC.decode(buf); +TextCodecs.PACKET_CODEC.encode(buf, text); + +// Codec for Optional +// Compatible with PacketByteBuf#readOptional +var optText = TextCodecs.PACKET_CODEC.collect(PacketCodecs::optional); + +// Codec for List +var strings = PacketCodecs.STRING.collect(PacketCodecs.toList()); + +// or Set, each max 16 chars +// both work fine, compatible with PacketByteBuf#readCollection +var stringSet = PacketCodecs.string(16).collect(PacketCodecs.toCollection(HashSet::new)); +stringSet = PacketCodecs.collection(HashSet::new, PacketCodecs.string(16)); + +// Map +var positions = PacketCodecs.map(HashMap::new, PacketCodecs.STRING, BlockPos.PACKET_CODEC); + +// What? DataFixerUpper codecs? +// Nah, these are just serialized as NBTs. +var advancement = PacketCodecs.codec(Advancement.CODEC); + +// Serializing NbtCompound +var nbt = PacketCodecs.NBT_COMPOUND; + +// Serializing a registry value (by raw ID) +// Note: these require RegistryByteBuf! +PacketCodecs item = PacketCodecs.registryValue(RegistryKeys.ITEM); +// Or, RegistryEntry +PacketCodecs biome = PacketCodecs.registryEntry(RegistryKeys.BIOME); + +// Serializing an Enum +var axis = PacketCodecs.indexed(i -> Direction.Axis.VALUES[i], Direction.Axis::ordinal); +``` + +#### Fabric Networking API +Networking API no longer directly uses `PacketByteBuf`, except in `LoginNetworking`. Instead, you need to subclass `CustomPayload` and register it. Note that `CustomPayload` is a vanilla interface. While this is similar to the packet object-based networking introduced recently, it is different in some ways. (`PacketType` and `FabricPacket` were, therefore, removed.) + +Compare the following, pre-snapshot packet: + +```java +public record SlapPacket(UUID slapped) implements FabricPacket { + public static final Identifier ID = new Identifier(...); + public static final PacketType TYPE = PacketType.create(ID, SlapPacket::new); + + public SlapPacket(PacketByteBuf buf) { + this(buf.readUuid()); + } + + @Override + public void write(PacketByteBuf buf) { + buf.writeUuid(slapped); + } +} +``` + +And a new one: + +```java +public record SlapPacket(UUID slapped) implements CustomPayload { + public static final CustomPayload.Id PACKET_ID = new CustomPayload.Id<>(new Identifier(...)); + public static final PacketCodec PACKET_CODEC = Uuids.PACKET_CODEC.xmap(SlapPacket::new, SlapPacket::slapped).cast(); +} +``` + +There are three differences you will notice: + +- Instead of now-removed `FabricPacket`, we implement `CustomPayload`. +- Each `CustomPayload` implementation has its own `CustomPayload.Id`. Unlike `PacketType`, it lacks reference to the decoder. +- The latter does not have a `write` method or `PacketByteBuf`-taking constructor. Instead, `PACKET_CODEC` field was added. (Note, you can make your `PacketCodec` from the constructor and the `write` method, so don't just remove those!) + +But, you may ask, how do you get the decoder if it's not in `Id`? Good question. The answer: **you need to register it in `ModInitializer` on both ends (sender and receiver)**. In fact, Fabric API will happily crash if you don't before calling `registerGlobalReceiver`. + +```java +// SlapPacket is sent during gameplay +// from the client to the server (serverbound; C2S) +PayloadTypeRegistry.playC2S().register(SlapPacket.PACKET_ID, SlapPacket.PACKET_CODEC); +// Replace with configurationS2C, playS2C, etc. +``` + +Then, you can change the receiver. Instead of long parameters, the event callback now gets only 2 parameters: the payload that was sent, and a context object. (Don't worry, it won't eat the RAM.) + +```diff +- ServerPlayNetworking.registerGlobalReceiver(SlapPacket.TYPE, (packet, player, sender) -> { +- var world = player.getServerWorld(); ++ServerPlayNetworking.registerGlobalReceiver(SlapPacket.PACKET_ID, (payload, context) -> { ++ var world = context.player().getServerWorld(); + var entity = world.getEntity(packet.slapped()); +}); +``` + +Here are the available fields in the context object: + +| `PayloadTypeRegistry` | Class | Fields | +| --------------------- | ---------------------- | ------------------------------------ | +| `playC2S` | `ServerPlayNetworking` | `player`, `responseSender` | +| `playS2C` | `ClientPlayNetworking` | `client`, `player`, `responseSender` | +| `configurationC2S` | `ServerConfigurationNetworking` | `networkHandler`, `responseSender` | +| `configurationS2C` | `ClientConfigurationNetworking` | `responseSender` | + +Note that the field shortcuts might be added later. + +Finally, sending the packet also uses `CustomPayload`. **Remember to register the codec first**! + +```java +ClientPlayNetworking.send(SlapPacket.PACKET_ID, new SlapPacket(...)); + +// for PacketSender: +sender.sendPacket(new SlapPacket(...)); +``` + +Note: **`PacketSender` no longer provides APIs that use `PacketByteBuf`.** For login networking where custom payloads are not used yet, use the subinterface `LoginPacketSender`. + +Some other Networking API related changes: +- `FutureListeners` was removed. +- `GenericFutureListener`-taking methods in `PacketSender` were removed. Use the one taking `PacketCallbacks`. +- `ServerPlayNetworking#getServer` was removed. `handler.player.server` should work. + +### Networking-adjacent changes in Fabric API +#### Particles API +`FabricParticleTypes#complex` now requires you to pass both `Codec` and `PacketCodec` for serializing the particle type. The string-based parser, `ParticleType.Factory`, was removed. + +#### Recipe API +`CustomIngredientSerializer` must now override `getPacketCodec`. The `read` and `write` methods were removed. Use `Ingredient#PACKET_CODEC` for representing another ingredient (which Fabric API patches up to also support ours). + +#### Screen Handler API +`ExtendedScreenHandlerType` now uses a payload object instead of `PacketByteBuf`. In the type constructor, you now need to pass `PacketCodec`: + +```java +public static final ExtendedScreenHandlerType OVEN = new ExtendedScreenHandlerType((syncId, inventory, data) -> ..., OvenData.PACKET_CODEC); +``` + +Notice that the callback got `data` instead of `buf`, as well. Note that the payload object can be of any type, whether it be `Identifier` or your custom record. (These don't have to be registered in `PayloadTypeRegistry`.) + +`ExtendedScreenHandlerFactory#writeScreenOpeningData` was replaced with `getScreenOpeningData`. It takes the player as the sole argument and returns the data class, in this case, `OvenData`. + +### Registries +#### RegistryWrapper & datagen +Many methods for serialization now require `RegistryWrapper.WrapperLookup` instance. This is used to query registries, and `DynamicRegistryManager` instance can be used for this purpose. This change is most prominent in text and data generation-related code. This registry is used to query data-driven values during serialization. + +Data provider constructors in Fabric API now take `RegistryWrapper.WrapperLookup` as a parameter; modders should change their constructors to take the instance and pass to the `super` constructor. In addition, `FabricAdvancementProvider#generateAdvancement` now also passes the instance. + +```diff +public class TestBlockLootTableProvider extends FabricBlockLootTableProvider { +- private TestBlockLootTableProvider(FabricDataOutput output) { +- super(output); ++ private TestBlockLootTableProvider(FabricDataOutput output, CompletableFuture registryLookup) { ++ super(output, registryLookup); + } +``` + +#### Loot Registries +Loot tables (including loot-adjacent stuff, namely predicates and item modifiers) are now managed by a special type of registry, called "reloadable registries". Unlike ordinary registries, they are reloaded during `/reload`. + +`LootDataLookup` was removed; `ReloadableRegistries.Lookup` can be obtained from `server.getReloadableRegistries()`. From there, item modifiers and predicates can be looked up via `getRegistryManager`; a shortcut exists for loot tables via `getLootTable`. + +Registry-ification of loot table also means that they are now identified with `RegistryKey`. Use `RegistryKey.of(RegistryKeys.LOOT_TABLE, id)` to get the registry key. In Fabric API, `VillagerInteractionRegistries#registerGiftLootTable` now takes the registry key, while the ID-taking method is deprecated. + +Fabric API's Loot API received breaking changes. For the arguments passed to events, `ResourceMaanger` and `LootManager` is gone. In the `LOAD_ALL` event, the loot manager was replaced with `Registry`. In all places, `Identifier` is replaced with `RegistryKey` as described above. In addition, because mutating registry is impossible now, the loot tables are modified before addition; this means that per-table events don't get the table registry anymore. + +#### Other changes +A new syncing protocol is in place for `DynamicRegistryManager` entries. Vanilla data packs provide `knownPackInfo` fields, which are sent by the server on joined clients. Clients then reply with the subset of the info they understand (i.e. loaded on their side). When a registry entry is loaded from a pack with `knownPackInfo`, and the client has acknowledged the info for the pack, the server tells the client to refer to its own copy of the data, skipping sending the serialized entry over the network. Most importantly, **this is currently not used by mod-provided packs**, so the registry entries from mods will be sent even if the client has the same mod. + +`SimpleRegistry` no longer supports changing the registered value post-registration (such as by the `set` method). For this reason, the `RegistryEntryRemovedCallback` event and the `registeyEntryRemoved` shortcut in `DynamicRegistryView` were removed. + +Finally, `SculkSensorFrequencyRegistry.register` now takes `RegistryKey` instead of `GameEvent`. + +### Blocks +All `AbstractBlock` public methods to be overridden were made `protected` and no longer marked as `@Deprecated`. + +```diff +- public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity entity, BlockHitResult hit) { ++ protected ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity entity, BlockHitResult hit) { +} +``` + +### Enchantments +`Enchantment` constructor now takes `Enchantment.Properties`, a record of enchantment properties. `EnchantmentTarget` enum was replaced with tags that specifies enchantment-supporting items. + +### Brewing +`FabricBrewingRecipeRegistry` was replaced with `FabricBrewingRecipeRegistryBuilder`. The new `FabricBrewingRecipeRegistryBuilder.BUILD` event can be used to add new recipes to the brewing stand. + +### Entities +`SpawnRestriction.Location` enum was replaced with an interface, `SpawnLocation`. `SpawnLocationTypes` provides predefined `SpawnLocation`s. + +### Client +In GUI, setting the initial focus of a screen is now done by overriding `setInitialFocus`, rather than calling it in `init`. `MatrixStack` was replaced with the actual matrix in several rendering code. + +### Other +DataFixerUpper was updated. This includes several breaking changes, such as `MapCodec` being used in places defining extra fields. Use `RecordCodecBuilder#mapCodec` instead of `create` in this case. Another significant change: `optionalFieldOf` is now strict by default. This means that a decoding error in the field value is now treated as an error, instead of being silently skipped. The `lenientOptionalFieldOf` method restores old behavior. + +On the Minecraft game code side, `Util#getResult` was replaced with `decode(...).getOrThrow()` method. Several methods and fields in `Codecs` were moved to the DFU itself, such as `either`, `xor`, and `withAlternative` (formerly `Codecs#alternatively`).