diff --git a/_posts/2024-05-31-121.md b/_posts/2024-05-31-121.md new file mode 100644 index 00000000..add23235 --- /dev/null +++ b/_posts/2024-05-31-121.md @@ -0,0 +1,192 @@ +--- +layout: post +title: Fabric for Minecraft 1.21 +ref: 121 +--- +Minecraft 1.21 is expected to be released on June 13, with some significant changes affecting mod makers. + +It's been only a month and a half since we last released a blogpost. Yet, this update is nothing small - some changes are likely to affect most, if not all, mods. + +As always, **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. **We also recommend all players to make a backup of their worlds.** + +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. + +## Fabric changes +Developers should use Loom 1.6 (at the time of writing) to develop mods for Minecraft 1.21. Players should install the latest stable version of Fabric Loader (currently 0.15.11). +### New Fabric API changes +With the help of many contributors, Fabric API has received some new features since the last update blog post: + +- Conventional Tags: Default English Translations for `c` namespaced tags (TelepathicGrunt) +- Data Generation: Support extending dynamic registries in datagen (SquidDev) +- Item API: Add API to modify default item components (modmuss50) +- Resource Conditions: Support loading a single resource condition instead of array (Apollo) +- Resource Conditions: Registry resource conditions (SquidDev) +- Removed Herobrine (Tiny Potato) + +#### Tag translation +Mods are now strongly encouraged to provide an English translation for item tags it provides. For example, the translation for `test:potatoes` should be declared like this: + +```json +{ + "tag.item.test.potatoes": "Potatoes" +} +``` + +Although these are not used by the API itself, other mods (such as recipe viewers) rely on them for proper display. + +### Breaking Changes +*Note: breaking changes related to vanilla changes are addressed separately below.* + +One deprecated module was removed: `fabric-models-v0`. + +In Item API, `EquipmentSlotProvider#getPreferredEquipmentSlot` is now passed a `LivingEntity`. Implementations are expected to check themselves whether the slot is available, using `entity.canUseSlot(EquipmentSlot)`. `FabricItem#getAttributeModifiers` was removed; use Default Components API instead. + +Registry Sync now freezes the registry at an earlier point. This does not affect mods that register things in their `ModInitializer`s, but might affect more complex mods. Make sure to register everything during `ModInitializer`. + +## Minecraft changes +This version brought many breaking changes, including data-driven Enchantments. Data pack structures also changed, using singular nouns (instead of plurals) in many places. + +### Identifier +`Identifier` constructor is now `protected`. Use the static method `of` or `ofVanilla` to construct `Identifier`. Replacing `new Identifier` with `Identifier.of` using text editors or IDEs should be sufficient. + +```diff +- var id = new Identifier("example", "foo_bar"); +- var id2 = new Identifier("test:single_argument"); +- var creeper = new Identifier("minecraft", "creeper"); +- @Nullable var customId = Identifier.of("namespace", unsanitizedInput); ++ var id = Identifier.of("example", "foo_bar"); ++ var id2 = Identifier.of("test:single_argument"); ++ var creeper = Identifier.ofVanilla("creeper"); // very slightly improved performance ++ @Nullable var customId = Identifier.tryParse("namespace", unsanitizedInput); +``` + +Pro tip: make a method to construct `Identifier` for your mod's namespace; this can be imported later using `import static` to shorten your code. + +```java +public static Identifier id(String path) { + return Identifier.of("mod_namespace", path); +} +``` + +### Enchantments +Enchantments are now data-driven. This means that they are no longer hardcoded - instead, they're part of data packs. Consequentially, there are several important changes in how mods handle enchantments. + +- Generally, enchantments either "do something" (like causing an explosion), or "modify a value" (like attack damage). +Example: Instead of checking if the player has Thorns and applying damage to the attacker, a mod should now call `EnchantmentHelper#onTargetDamaged` which should automatically handle this. +Example 2: Instead of checking the level of Knockback, a mod should now call `EnchantmentHelper#modifyKnockback` with the original knockback. +- Sometimes, a code needs to check if an item has certain enchantments. Because enchantments are no longer hard-coded, this is done using enchantment tags. +Example 3: Breaking a beehive with Silk Touch prevents bees from getting released. Previously, this was done by checking for the Silk Touch enchantment. Now, this is done by calling `EnchantmentHelper#hasAnyEnchantmentsIn(stack, EnchantmentTags#PREVENTS_BEE_SPAWNS_WHEN_MINING)`. + +### Enchantment Code Structures +An `Enchantment` is, well, an enchantment. Because it is now defined by a dynamic registry, it is often handled as `RegistryEntry`. These can be obtained from the dynamic registry, i.e. `world.getRegistryManager()` or the `registryLookup` passed to various methods. + +An enchantment has effect components, which is a map of effect types to list of effects. Effect types are pre-defined keys that enchantments can define behaviors for. For example, an enchantment may want to add "multiply by 2" behavior for `DAMAGE` effect type, or "explode" behavior for `POST_ATTACK` effect type. These are defined in `EnchantmentEffectComponentTypes`. + +The values of effect components are `EnchantmentEffectEntry`. This is a pair of the effect and an optional condition. `LootCondition` is reused for this purpose. + +Enchantment effects can be categorized into three categories: + +- `EnchantmentValueEffect`. When given a value, the effect calculates the modified value. Examples include Protection (which modifies `DAMAGE_PROTECTION`), Lure (`FISHING_LUCK_BONUS`), Unbreaking (`ITEM_DAMAGE`), and Multishot (`PROJECTILE_COUNT`). +- `EnchantmentEntityEffect`. This effect does something when triggered. Examples include Thorns and Channeling (`POST_ATTACK`) and Flame (`PROJECTILE_SPAWNED`). +- `AttributeEnchantmentEffect`, which adds an attribute to the entity. Unlike entity effects, attributes persist until the enchantment becomes inapplicable. + +`EnchantmentLocationBasedEffect` is an interface implemented by `EnchantmentEntityEffect` and `AttributeEnchantmentEffect`. In addition, some enchantment effect types simply require effective values to be specified directly - like `CROSSBOW_CHARGING_SOUNDS`, which is a list of sounds. Some effects, like `PREVENT_ARMOR_CHANGE`, cannot be configured further. + +### Using Vanilla Enchantments +`EnchantmentHelper` methods can be used to handle vanilla enchantments. + +```java +// Example of modifying a value +float newDamage = EnchantmentHelper.getDamage( + world, + stack, + attackTarget, + damageSource, + baseDamage +); + +// For values with no base value (such as Protection) +float protection = EnchantmentHelper.getProtectionAmount( + world, + user, + damageSource +); + +// Entity-based effect +EnchantmentHelper.onTargetDamaged( + world, + attackTarget, + damageSource, + weapon +); + +// Checking if an ItemStack is enchanted with certain enchantments +if (EnchantmentHelper.hasAnyEnchantmentsIn( + stack, + EnchantmentTags.PREVENTS_BEE_SPAWNS_WHEN_MINING +)) { + return; +} + +// Checking for nonconfigurable effects +// e.g. checking for Curse of Binding +if (EnchantmentHelper.hasAnyEnchantmentsWith( + stack, + EnchantmentEffectComponentTypes.PREVENT_ARMOR_CHANGE +)) { + return; +} +``` + +### Adding a new Enchantment +Adding a new enchantment is now done by writing JSON files. You can use Data Generation to generate enchantments easily. + +An enchantment can perform many tasks, like applying attributes, replacing blocks or summoning an entity. However, not all things are possible. To add a custom **effect type**, a new effect class must be created and its codec registered. **An effect type must exist in both the client and the server.** + +Enchantment tags are used to specify exclusive enchantments (e.g. Fortune and Silk Touch) and where the enchantments can be obtained. Make sure to add your enchantments to those tags. + +### Enchantment-related Fabric API changes +The following event callbacks now pass `RegistryEntry` instead of `Enchantment`: + +- `EnchantmentEvents.AllowEnchanting#allowEnchanting` +- `FabricItem#canBeEnchantedWith` +- `FabricItemStack#canBeEnchantedWith` + +`EnchantmentContext` was reworked. Previously, a context was one of `RANDOM_ENCHANTMENT`, `ANVIL`, `ENCHANT_COMMAND`, or `LOOT_RANDOM_ENCHANTMENT`. To clarify its purpose, they are now one of `ACCEPTABLE` (e.g. anvils) or `PRIMARY` (e.g. enchanting tables). For example, a helmet can be enchanted with Thorns using anvils but not in enchanting tables, because only chestplates are `PRIMARY` in case of Thorns. + +### Teleportation +Both intra-dimensional and cross-dimensional teleportation can now be performed using `Entity#teleportTo` (previously known as `moveToWorld`). `TeleportTarget` now contains the destination world and position. + +`FabricDimensions` was removed, because its only API, `teleport`, is effectively superseded with `Entity#teleportTo`. + +### Data Pack Paths +Data packs now use singular nouns in the following paths: + +- Tag subdirectories such as `tags/blocks`, `tags/entity_types`, `tags/functions`. They are now `tags/block`, `tags/entity_type`, and `tags/function`, respectively. **The `tags` directory itself remains plural.** +- Advancements (previously `advancements`, now `advancement`). +- Functions (`functions` to `function`). +- Item modifiers/loot functions (`item_modifiers` to `item_modifier`). +- Loot tables (`loot_tables` to `loot_table`). +- Predicates/loot conditions (`predicates` to `predicate`). +- Recipes (`recipes` to `recipe`). +- Structures (`structures` to `structure`). + +In Fabric API news, GameTest structure directories are now singular as well; instead of `gametest/structures`, they are now placed in `gametest/structure`. + +### Rendering Changes +In the Fabric Rendering API, `HudRenderCallback` now passes `RenderTickCounter` instead of `tickDelta`. `tickDelta` can be obtained from the counter. `WorldRenderContext`'s `tickDelta` and `limitTime` methods are also replaced with `tickCounter`. + +There are some other, significant internal refactors to rendering. For example, `BufferBuilder#next()` was removed, and the methods for beginning or ending the building process has changed: + +```diff +- BufferBuilder builder = tessellator.getBuffer(); +- builder.begin(...); ++ BufferBuilder builder = tessellator.begin(...); +- builder.vertex(...).texture(...).color(...).next(); ++ builder.vertex(...).texture(...).color(...) +- tessellator.draw(); ++ BufferRenderer.drawWithGlobalProgram(builder.end()); +``` + +### Miscellaneous +- `FabricCodecProvider` now has a new constructor that takes `RegistryKey` instead of directory name. This can be used with, for example, item modifier providers. The old constructor can still be used for non-registered codecs.