NeoForge 21.2 for Minecraft 1.21.2
Update time, once again! Mojang has just released Minecraft version 1.21.2.
The first beta release of NeoForge 21.2 is already available: 21.2.0-beta
.
This version brings many large technical changes under the hood, so let’s talk about version support for a second.
Version Support
With Minecraft’s new development policy, minor updates often come with large internal technical changes. These changes are great, and usually benefit modders in the long run. However, they also fragment the community because not all mods are ported or can be ported immediately.
To avoid that fragmentation, we recommend that modders continue to actively maintain the 1.21.1 version of their mods until the release of Minecraft 1.22. Of course, we encourage modders who have the time to also try out and release their mods for 1.21.2 too, and we need their feedback to continue improving NeoForge!
Per our usual policy, all Pull Requests now need to be accepted into our 1.21.x
branch which currently targets Minecraft 1.21.2, before a backport can be accepted in the 1.21.1
branch.
As usual, we will have a few weeks of beta where breaking changes are allowed in the 21.2 series.
Remember that we announce breaking changes in the Dev Announcements channel of our Discord server. Make sure to select the Dev Announcement Pings
role if you want to be kept up to date with the most important changes!
Minecraft Changes
Here is a selection of the changes in vanilla 1.21.2 that will affect many modders.
ID in Block Properties
The Block properties (of type BlockBehaviour.Properties
) now require the ID of the block to be set:
- new MyBlock(BlockBehaviour.Properties.of().xxx())
+ new MyBlock(BlockBehaviour.Properties.of().xxx().setId(ResourceKey.create(Registries.BLOCK, resourceLocation)))
This is done automatically when using DeferredRegister.Blocks
with the registerBlock
method:
BLOCKS.registerBlock("block_name", MyBlock::new, properties -> properties.xxx())
ID in Item Properties
The same is true for Item properties (of type Item.Properties
).
We suggest using DeferredRegister.Items
with the registerItem
method that will take care of this.
By default, items use the item.namespace.path
translation key.
For block items, remember to call useBlockDescriptionPrefix()
on the properties to use the block.namespace.path
translation key:
// On block items only:
+ properties.useBlockDescriptionPrefix()
Block Entity Type Creation
There is no builder for block entity types anymore. Now, they are constructed directly:
- BlockEntityType.Builder.of(MyBlockEntity::new, BLOCK1.get(), BLOCK2.get()).build(null)
+ new BlockEntityType<>(MyBlockEntity::new, BLOCK1.get(), BLOCK2.get())
Registry Method Renames
RegistryAccess.registry
was renamed to RegistryAccess.lookup
, and similarly for the throwing methods:
- registryAccess.registryOrThrow(Registries.DAMAGE_TYPE)
+ registryAccess.lookupOrThrow(Registries.DAMAGE_TYPE)
Registry.getHolder
was renamed to get
, and similarly for the throwing methods:
- registry.getHolderOrThrow(resourceKey)
+ registry.getOrThrow(resourceKey)
Note that it returns a Holder
.
To retrieve the object directly, use getValue
:
- registry.get(resourceLocation)
+ registry.getValue(resourceLocation)
ServerLevel
Methods
Many methods were moved from Level
down to ServerLevel
.
Beware of casts, some of these methods might still be called with client levels too!
In that case, the recommended pattern is to use an instanceof
check:
if (level instanceof ServerLevel serverLevel) {
serverLevel.serverSpecificMethod(...);
}
// Continue with more common code
GuiGraphics.blit
The blit
method now takes a Function<ResourceLocation, RenderType>
as its first parameter.
In most cases, you’ll want to pass RenderType::guiTextured
. For example:
- guiGraphics.blit(TEXTURE, ...);
+ guiGraphics.blit(RenderType::guiTextured, TEXTURE, ...);
Recipe Changes
The recipe system was largely changed. Notably:
Recipe
s are no longer synced with clients.- Instead, only
RecipeDisplay
s are. - Custom subclasses of
RecipeDisplay
can be created by modders, as long as theRecipeDisplay.Type
is registered. - The
Recipe
interface has a newList<RecipeDisplay> display()
method to obtain recipe displays.
- Instead, only
- The recipe book system was refactored, and is now more accessible to modders.
Ingredient
s were changed too:- They are generally not synced anymore. Instead,
SlotDisplay
s are, similarly to theRecipeDisplay
s. - The format changed, and now follows the holder set format. For example:
- They are generally not synced anymore. Instead,
- { "item": "minecraft:diamond" }
+ "minecraft:diamond"
- { "tag": "c:ingots/copper" }
+ "#c:ingots/copper"
Custom holder sets are supported too. For example, here is an ingredient that accepts any item:
{ "type": "neoforge:any" }
Custom ingredients are still supported too, using the neoforge:ingredient_type
key:
{
- "type": "neoforge:compound",
+ "neoforge:ingredient_type": "neoforge:compound",
"children": [
- /* old ingredient syntax */
+ /* new ingredient syntax */
]
}
Porting Primer
Finally, here is a more extensive list of changes, courtesy of @ChampionAsh5357
: https://github.com/ChampionAsh5357/neoforged-github/blob/port/1212-or-122/primers/1.21.2/index.md.
Happy porting!