Skip to content

Commit 58d565b

Browse files
committed
Fabric for Minecraft 1.21.6
1 parent bfe3aa4 commit 58d565b

File tree

1 file changed

+205
-0
lines changed

1 file changed

+205
-0
lines changed

_posts/2025-06-15-1216.md

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
---
2+
layout: post
3+
title: Fabric for Minecraft 1.21.6
4+
ref: 1216
5+
---
6+
A new version of Minecraft is coming soon with some changes that affect most mod makers. As always, **we ask all players to be patient, and give mod developers time to update to this new version.** We kindly ask everyone not to pester them. **We also recommend all players make backups of their worlds.**
7+
8+
Here is a list of several 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.
9+
10+
## Fabric changes
11+
Developers should use Loom 1.10 (at the time of writing) to develop mods for Minecraft 1.21.6.
12+
Players should install the latest stable version of Fabric Loader (currently 0.16.14).
13+
14+
### Deprecations and removals
15+
The following previously deprecated modules have been removed ([#4651](https://github.com/FabricMC/fabric/pull/4651)):
16+
* `fabric-command-api-v1`
17+
* `fabric-commands-v0` (Deprecated almost 5 years ago!)
18+
* `fabric-keybindings-v0`
19+
* `fabric-rendering-data-attachment-v1`
20+
21+
The following modules have been merged into other modules for simplicity:
22+
* `fabric-client-tags-api-v1` was merged into `fabric-tag-api-v1` ([#4647](https://github.com/FabricMC/fabric/pull/4647))
23+
* `fabric-blockrenderlayer-v1` was merged into `fabric-rendering-v1` ([#4675](https://github.com/FabricMC/fabric/pull/4675))
24+
25+
The tag api changes are technically breaking for some developers who explicitly depend on these modules. The removal and merging of these modules has been done to help improve peformance when setting up a new development environment.
26+
27+
The Fabric Rendering API previously provided a Material API, to allow modders more control of the way their models rendered. This has been removed.
28+
> Materials were removed ... because they were deemed to be an unnecessary part of the API design, and the breaking change induced by changes in 1.21.6 was related to materials, which made this the perfect time to remove them - PepperCode1
29+
30+
See [#4675](https://github.com/FabricMC/fabric/pull/4675) for more info.
31+
32+
In addition to being relocated, the `BlockRenderLayerMap` API was also updated to be more consistent out current api style:
33+
```diff
34+
- import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
35+
+ import net.fabricmc.fabric.api.client.rendering.v1.BlockRenderLayerMap;
36+
//...
37+
- BlockRenderLayerMap.INSTANCE.putBlock(ModBlocks.MY_EPIC_BLOCK, BlockRenderLayer.CUTOUT)
38+
+ BlockRenderLayerMap.putBlock(ModBlocks.MY_EPIC_BLOCK, BlockRenderLayer.CUTOUT)
39+
```
40+
See ([#4664](https://github.com/FabricMC/fabric/pull/4664)) for more info.
41+
### Breaking changes
42+
43+
Fabric's brand new HUD api had to be tottaly rewritten in 1.21.6. The new `HudElementRegistry` provides all of the functionality provided by the old API. The following basic example shows how you can draw text after all of the vanilla HUD layers.
44+
45+
```java
46+
HudElementRegistry.addLast(Identifier.of("example", "hud"), (context, tickCounter) -> {
47+
context.drawTextWithShadow(MinecraftClient.getInstance().textRenderer, "This is an example", 10, 10, Colors.WHITE);
48+
});
49+
```
50+
51+
If you wish to render your custom hud element before the vanilla chat you can do the following:
52+
```java
53+
HudElementRegistry.attachElementBefore(VanillaHudElements.CHAT, Identifier.of("example", "ud"), (context, tickCounter) -> {
54+
/* Render here */
55+
});
56+
```
57+
58+
59+
### New Fabric API features
60+
61+
Since `Item#appendTooltip` has become deprecated, Fabric API now provides the `ComponentTooltipAppenderRegistry`. This registry provides `addAfter`, `addBefore`, `addFirst`, and `addLast` to allow you to position your tooltips relative to vanilla and other mods.
62+
```java
63+
record MyAmazingComponent() implements TooltipAppender {
64+
@Override
65+
public void appendTooltip(Item.TooltipContext context, Consumer<Text> textConsumer, TooltipType type, ComponentsAccess components) {
66+
textConsumer.accept(Text.literal("Amazingness Awaits!"));
67+
}
68+
}
69+
ComponentType<MyAmazingComponent> myAmazingComponentComponentType = /*omitted for brevity*/;
70+
ComponentTooltipAppenderRegistry.addAfter(
71+
DataComponentTypes.DAMAGE,
72+
myAmazingComponentComponentType
73+
);
74+
```
75+
Any `ItemStack` that has your component applied will call your components appendTooltip method, allowing you to append as you wish. ([#4587](https://github.com/FabricMC/fabric/pull/4587))
76+
77+
The LootTable API has been expanded to make certain extreme usages more convenient. The `LootTableEvents.MODIFY_DROPS` event allows modders to customize the collective output of `LootTable`s. The `LootTableEvents.MODIFY` event should still be preferred when possible, for mod compatibility reasons. This event may also recurse if you generate loot from within a listener. ([#4643](https://github.com/FabricMC/fabric/pull/4643))
78+
```java
79+
var matchGetter = ServerRecipeManager.createCachedMatchGetter(RecipeType.SMELTING);
80+
81+
// smelt any smeltable drops from blocks broken with a diamond pickaxe
82+
LootTableEvents.MODIFY_DROPS.register((entry, context, drops) -> {
83+
if (!context.hasParameter(LootContextParameters.TOOL)) return;
84+
if (!context.hasParameter(LootContextParameters.BLOCK_STATE)) return;
85+
ItemStack tool = context.get(LootContextParameters.TOOL);
86+
if (!tool.isOf(Items.DIAMOND_PICKAXE)) return;
87+
var world = context.getWorld();
88+
var lookup = world.getRegistryManager();
89+
drops.replaceAll(drop -> {
90+
return matchGetter
91+
.getFirstMatch(new SingleStackRecipeInput(drop), world)
92+
.map(RecipeEntry::value)
93+
.map(recipe -> recipe.craft(input, lookup))
94+
.orElse(drop);
95+
});
96+
});
97+
```
98+
Continuing with our conventional tag api, We added new biome tags, allowing modders to differentiate biomes based on their primary wood type.
99+
The `ServerChunkEvents.CHUNK_LEVEL_TYPE_CHANGE` was added to allow more control over the timing of chunk events. This event fires for changes in chunk loading level, to react to changes not previously possible without mixins. ([#4541](https://github.com/FabricMC/fabric/pull/4541))
100+
101+
An event was added for attachment changes, allowing reaction to an attachment value changing. This event can be recursive in nature, as if you set an attachment value from within a listener, the event will be invoked again. Modders should use proper recursion techniques to prevent infinite recursion. ([#4606](https://github.com/FabricMC/fabric/pull/4606))
102+
103+
104+
Still more events were added for Players leaving and joining the game:
105+
```java
106+
AttachmentType<Instant> JOINED_TIME = /**/;
107+
ServerPlayerEvents.JOIN.register(player -> {
108+
// runs on the main thread, no need to use player.getServer().execute(() -> ...);
109+
player.setAttached(JOINED_TIME, Instant.now());
110+
});
111+
```
112+
```java
113+
List<ServerPlayerEntity> activePlayers = /**/;
114+
ServerPlayerEvents.LEAVE.register(activePlayers::remove);
115+
```
116+
These events are designed for initializing and de-initializing state related to players, and run along vanilla code with the same purpose on the main thread, unlike the current events. ([#4642](https://github.com/FabricMC/fabric/pull/4642))
117+
118+
The `FabricSoundsProvider` class was added to allow convenient creation of `sounds.json` from within datagen. ([#4560](https://github.com/FabricMC/fabric/pull/4560))
119+
120+
The Client Game Test API has been tweaked to support filtering tests run by model, allowing more precise and efficient testing. ([#4597](https://github.com/FabricMC/fabric/pull/4597))
121+
122+
The Model Loading API now supports registering extra unbound models ([#4565](https://github.com/FabricMC/fabric/pull/4565))
123+
```java
124+
// A ModelKey is a unique identifier for a model you want to bake.
125+
public static final ModelKey<BlockStateModel> HALF_RED_SAND_MODEL_KEY = ModelKey.create();
126+
public static final Identifier HALF_RED_SAND_MODEL_ID = id("half_red_sand");
127+
128+
public static void init() {
129+
ModelLoadingPlugin.register(pluginContext -> {
130+
pluginContext.addModel(HALF_RED_SAND_MODEL_KEY, HALF_RED_SAND_MODEL_ID, (model, baker) -> {
131+
ModelTextures textures = model.getTextures();
132+
return new SimpleBlockStateModel(new GeometryBakedModel(
133+
model.bakeGeometry(textures, baker, ModelRotation.X0_Y0),
134+
model.getAmbientOcclusion(),
135+
model.getParticleTexture(textures, baker)
136+
));
137+
});
138+
}
139+
140+
public static BlockStateModel getModel() {
141+
return MinecraftClient.getInstance().getBakedModelManager().getModel(HALF_RED_SAND_MODEL_KEY);
142+
}
143+
```
144+
145+
`FabricTrackedDataRegistry` has been added to allow registering of tracked data handlers for entities. This removes conflicts between mods registering tracked data handlers and ensures that the order is consistent between the client and server. If you previouly used the vanilla API the following 1 line change is all you need to take advantage of this new API:
146+
147+
```diff
148+
- TrackedDataHandlerRegistry.register(TRACKED_DATA_HANDLER);
149+
+ FabricTrackedDataRegistry.registerHandler(TRACKED_DATA_HANDLER_ID, TRACKED_DATA_HANDLER);
150+
```
151+
152+
### Bug Fixes
153+
Due to diligent developers and players, Many bugs in Fabric API were reported and patched during this update cycle. See [The Fabric Github](https://github.com/FabricMC/fabric/pulls?q=is%3Apr+is%3Aclosed+label%3Abug) for more info.
154+
## Minecraft changes
155+
### Rendering
156+
Mojang is currently working on separating Minecraft's rendering pipeline into two stages:
157+
1. The extraction stage, where all renderable data is seperated from the game
158+
2. The render phase, where the previously extracted data is rendered.
159+
160+
This process began in 1.21.2, and is still incomplete as of this update. Chunk rendering, GUI rendering and HUD rendering have all been converted to use the new separate rendering style. The ultimate goal of this separation is to enable the game to render one frame while the next is being extracted.
161+
162+
In order to facilitate this, the blaze3d rendering api is being reworked. (Almost everything changed... fill in more)
163+
164+
Many methods in `RenderSystem` have been removed without direct replacement. In most cases, there isn't a one-to-one translation from the old code to the new, but the same capabilities exist by combining the new `RenderPipline`s with `RenderLayer`s
165+
166+
### NBT
167+
168+
`BlockEntity`s now abstract saving to NBT through `(Read|Write)View`s. These views are responsible for storing errors from encoding / decoding, and keeping track of registries throughout the serialization process. You can read from a `ReadView` using the `read` method, passing in a `Codec` for the desired type. Likewise, you can write to a `WriteView` by using the `put` method, passing in a `Codec` for the type, and the value in question. there are also methods for primitives, under `get(Int, Short, Boolean, ...)` and `put(Int, Short, Boolean, ...)`. The View also provides methods for working with lists, nullable types, and nested objects.
169+
```java
170+
class BE extends BlockEntity {
171+
private int anInt;
172+
private String aString;
173+
private Extra extra;
174+
// ctor excluded for brevity
175+
@Override
176+
public NbtCompound toInitialChunkDataNbt(RegistryWrapper.WrapperLookup registries) {
177+
return createNbt(registries); // createNbt takes care of adapting to / from WriteView
178+
}
179+
180+
@Override
181+
protected void writeData(WriteView view) {
182+
super.writeData(view);
183+
view.putNullable("extra", Extra.CODEC, this.extra);
184+
if (aString != null) // putString will eventually throw if we pass null
185+
view.putString("aString", aString);
186+
view.putInt("anInt", anInt);
187+
}
188+
189+
@Override
190+
protected void readData(ReadView view) {
191+
super.readData(view);
192+
view.read("extra", Extra.CODEC).ifPresent(extra -> this.extra = extra);
193+
view.getOptionalString("aString").ifPresent(aString -> this.aString = aString);
194+
view.getOptionalInt("anInt").ifPresent(anInt -> this.anInt = anInt);
195+
}
196+
197+
record Extra(int i, int j) {
198+
public static final Codec<Extra> CODEC = RecordCodecBuilder.create(instance -> instance.group(Codec.INT.fieldOf("i").forGetter(extra -> extra.i), Codec.INT.fieldOf("j").forGetter(extra -> extra.j)).apply(instance, Extra::new));
199+
}
200+
}
201+
```
202+
203+
### Data Generation
204+
205+
* `getOrCreateTagBuilder` should be replaced with the new `valueLookupBuilder`

0 commit comments

Comments
 (0)