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:
- 1.20.2:
- The package renames
- The EventBus changes
- The Registry Rework
- 1.20.3:
- 1.20.4:
- The introduction of Data Maps
- The Networking Refactor
- The switch to Fabric Mixin
- 1.20.5:
- The
mods.toml
file was renamed toneoforge.mods.toml
- The Second Networking Rework
- The Tick Event Refactor
- The
- 1.20.6:
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 theResourceLocation(String, String)
constructor in 1.20.6 and below. Accompanied by#tryBuild
which returnsnull
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 theResourceLocation(String)
constructor in 1.20.6 and below. Accompanied by#tryParse
which returnsnull
instead of throwing if the parameters aren’t valid.ResourceLocation#withDefaultNamespace
: takes in the path of the resource location, and always usesminecraft
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
: useItem#inventoryTick
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 byModContainer#registerConfig
FMLJavaModLoadingContext#get
was removed. The direct replacement isModLoadingContext#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 useif (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.
Damage Pipeline rework (introduced in NeoForge 21.0.31-beta)
In NeoForge 21.0.31-beta
, damage events have been reworked.
The motivation behind this change was that the previous poorly named and documented events were causing constant confusion, especially among beginners.
DamageContainer
DamageContainer
is a new class exposed via the damage events. This object allows modifications to all aspects of the damage pipeline, including absorption and invulnerability ticks.
You can modify the different types of reduction (ARMOR
, ENCHANTMENTS
, MOB_EFFECTS
and ABSORPTION
) through addModifier
:
// Reduce armor reduction by 1 hear
container.addModifier(DamageContainer.Reduction.ARMOR, (container, currentReduction) -> Math.max(0, currentReduction - 1));
EntityInvulnerabilityCheckEvent
This new event represents the earliest point modders can use to cancel damage, and can be used to override entities that would otherwise be invulnerable in vanilla.
This event will always be fired when an entity is attacked, even if the attack would not actually damage the entity.
LivingIncomingDamageEvent
(formerly LivingAttackEvent
)
This is the first event of the damage pipeline. Most modifications to the incoming damage should happen during this event.
LivingShieldBlockEvent
(formerly ShieldBlockEvent
)
This event can be used to decide whether the entity is actually blocking the damage through the shield, and if so, how much of the damage is blocked.
LivingDamageEvent.Pre
(formerly LivingDamageEvent
)
This event is the lastest point at which the final damage may be modified, or reduced to 0. However, the event is not cancellable as by when it is fired, armor and shield durability loses have already occurred.
LivingDamageEvent.Post
(formerly LivingHurtEvent
)
This is the last event of the damage pipeline. It indicates that all damage has been applied to the entity, and can only be used for reacting to the damage being applied (i.e. to reduce custom hunger or thirst values).
ILivingEntityExtension#onDamageTaken
This method has been added to living entities in order to allow them to react to already applied damage, without needing to override actuallyHurt
and call super.
We would like to thank Caltinor for their work on the Pull Request, which you can consult for more information.
PlantType system is now replaced (introduced in NeoForge 21.0.39-beta)
The original PlantType system was buggy and quite confusing to deal with. Instead, we deleted that system and added SpecialPlantable
item interface, patched in a canSustainPlant
block method, and added a neoforge:villager_farmlands
block tag.
The SpecialPlantable
interface allows mods to more easily tell if a modded item can spawn a plant and exposes methods for easy checking if a spot is valid for the item and to spawn the plant itself.
The patched-in canSustainPlant
method allows blocks to forcibly sustain many plants and now works with all vanilla plants. Modded plants would need to call this method if the plant block override canSurvive without calling super.
And the SpecialPlantable
block tag now lets Farmer Villagers detect and plant on modded blocks more easier. This can also be used by mods to know if a modded block is farmland-like.
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.