NeoForge 21.0 for Minecraft 1.21

It’s that time of the year again! Mojang has just released a new Minecraft major version: 1.21, followed by the first beta release of NeoForge 21.0: 21.0.0-beta.

Previous changes

Before diving into the changes brought by 1.21, we would like to quickly go through the changes made to NeoForge since 1.20.1, for those that haven’t updated all the way to 1.20.6. You will also find the respective blog posts for each version, outlining important Vanilla changes:

The Vanilla 1.21 changes

Now, let’s get into the most important changes in Vanilla.

First of all, the ResourceLocation constructors were made private, and replaced with static factory methods:

  • ResourceLocation#fromNamespaceAndPath: takes in the namespace and the path of the resource location. This is functionally equivalent to the ResourceLocation(String, String) constructor in 1.20.6 and below. Accompanied by #tryBuild which returns null instead of throwing if the parameters aren’t valid.
  • ResourceLocation#parse: takes in a resource location string composed of a namespace and path, separated by :. This method is functionally equivalent to the ResourceLocation(String) constructor in 1.20.6 and below. Accompanied by #tryParse which returns null instead of throwing if the parameters aren’t valid.
  • ResourceLocation#withDefaultNamespace: takes in the path of the resource location, and always uses minecraft as its namespace.

Depluralisation

Several data folder names that were plural have been renamed:

  • tag folders:
    • tags/blocks -> tags/block
    • tags/entity_types -> tags/entity_type
    • tags/fluids -> tags/fluid
    • tags/items -> tags/item
    • tags/game_events -> tags/game_event
  • recipes -> recipe
  • advancements -> advancement

Data-driven enchantments

Enchantments are no longer a static, built-in registry, and are instead a datapack registry.
With this change, methods that previously took an Enchantment will now take a Holder<Enchantment> (which can be grabbed from a registry obtained through a level’s RegistryAccess), and all fields in the Enchantments class are ResourceKey<Enchantment>s.
Additionally, your code should now use EnchantmentEffectComponents to determine whether an enchantment should affect something, instead of relying on direct level checks.

For more information, we encourage you to consult ChampionAsh’s 1.21 primer.

The NeoForge changes

The first NeoForge beta release for 1.21 comes with some changes too.

Deprecations

Members deprecated for removal have been mostly removed:

  • IItemExtension#onArmorTick: use Item#inventory tick instead, with the armor slot indices being 36, 37, 38 and 39.
  • ItemHandlerHelper#copyStackWithSize -> ItemStack#copyWithCount
  • ItemHandlerHelper#canItemStacksStack -> ItemStack#isSameItemSameComponents
  • the ComposterBlock#COMPOSTABLES map is now ignored. Use the data map instead.
  • the VibrationSystem#VIBRATION_FREQUENCY_FOR_EVENT map is now ignored. Use the data map instead.
  • the Parrot#MOB_SOUND_MAP map is now ignored. Use the data map instead.

FML also had its deprecated members removed:

  • the ModLoadingContext#registerConfig methods are replaced by ModContainer#registerConfig
  • FMLJavaModLoadingContext#get was removed. The direct replacement is ModLoadingContext#get, however use of it is discouraged. You should use direct references to your container where possible, and consider that the mod’s event bus is provided as a mod class constructor argument.
  • DistExecutor was removed without replacement. You should either use if (FMLLoader.dist == <dist>) checks, or separate entrypoints for client and common code.

Enum extensions rework (introduced in NeoForge 21.0.10-beta)

Enum extensions were reworked to solve several shortcomings of the previous approach. Instead of adding new entries at an arbitrary time by calling a static method on the target enum, the values are now added by specifying them in an enum extensions JSON file which is used to add the new values when the enum is class-loaded. The JSON file is specified through the enumExtensions key in a [[mods]] block of the neoforge.mods.toml.
The entries specified in the file consist of the target enum, the field name, the constructor to be used and the parameters (specified as an array of constants, as a reference to a field of type EnumProxy or as a reference to a method):

{
  "entries": [
    {
      "enum": "net/minecraft/world/item/ItemDisplayContext",
      "name": "EXAMPLEMOD_STANDING",
      "constructor": "(ILjava/lang/String;Ljava/lang/String;)V",
      "parameters": [ -1, "examplemod:standing", null ]
    }
  ]
}

See the documentation for further information on how to use the new system and the FML PR for further details on the motivations of this change.

Experimental Gradle Plugin

We’re currently developing a new experimental Gradle Plugin, focused on simpler buildscripts and improved caching. You can find information on its usage here, and support is provided in the thread on our Discord server.

NeoGradle will continue to be supported.

A note on stability

As was the case with the 1.20 lifecycle, we expect 1.21 (or 1.21.1) to be the stable version packs will focus on during the 1.21 lifecycle.
This means that 1.21 may have a longer beta period so that we can make sure that the version packs will use for the year to come is as good as it gets.
However, we will, as always, refrain from making useless breaking changes, and will make sure to announce them 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!

As always, we want to thank everyone for their contributions during the 1.20 lifecycle, and we hope to see more mods be developed for NeoForge in the coming months.