NeoForge 21.5 for Minecraft 1.21.5
Hello everyone,
The first beta release of NeoForge 21.5 for Minecraft 1.21.5 is now available: 21.5.0-beta
.
And with that the Team wants to hand out a large thanks for all the porting efforts this time around to the entire team, you all did amazing work!
Now let’s get into the changes, shall we?
Changes
This section will draw heavily from the Porting Primer, as well as from changes noticed by the porting team.
Weapons, Tools, and Armor: Removing the Redundancies
There have been a lot of updates to weapons, tools, and armor that removes the reliance on the hardcoded base classes of SwordItem
, DiggerItem
, and ArmorItem
, respectively. These have been replaced with their associated data components WEAPON
for damage, TOOL
for mining, ARMOR
for protection, and BLOCKS_ATTACKS
for shields. Additionally, the missing attributes are usually specified by setting the ATTRIBUTE_MODIFIERS
, MAX_DAMAGE
, MAX_STACK_SIZE
, DAMAGE
, REPAIRABLE
, and ENCHANTABLE
.
Given that pretty much all the non-specific logic has moved to a data component, these classes have now been completely removed. Use one of the available item property methods or call Item$Properties#component
directly to set up each item as a weapon, tool, armor, or some combination of the three.
We have also removed the _DIG
ItemAbilities
these tools previously had in favour of the new components.
Extrapolating the Saddles: Equipment Changes
A new EquipmentSlot
has been added for saddles, which brings with it new changes for generalizing slot logic.
First, rendering an equipment slot for an entity can now be handled as an additional RenderLayer
called SimpleEquipmentLayer
.
This takes in the entity renderer, the EquipmentLayerRenderer
, the layer type to render, a function to get the ItemStack
from the entity state, and the adult and baby models.
The renderer will attempt to look up the client info from the associated equippable data component and use that to render the laters as necessary.
Next, instead of having individual lists for each equipment slot on the entity, there is now a general EntityEquipment
object that holds a delegate to a map of slots to ItemStack
s.
This simplifies the storage logic greatly.
Finally, equippables can now specify whether wearing one will contribute to the bonus XP earned when killing a mob by setting equipOnInteract
.
Data Component Getters
The data component system can now be represented on arbitrary objects through the use of the DataComponentGetter
.
As the name implies, the getter is responsible for getting the component from the associated type key.
Both block entities and entities use the DataComponentGetter
to allow querying internal data, such as variant information or custom names.
They both also have methods for collecting the data components from another holder (via applyImplicitComponents
or applyImplicitComponent
).
Block entities also contain a method for collection to another holder via collectImplicitComponents
.
NBT Tags and Parsing
NBT tags have received a rewrite, removing any direct references to types while also sealing and finalizing related classes.
Getting a value from the tag now returns an Optional
-wrapped entry, unless you use one of the get*Or
methods, which have a parameter for a fallback default value.
Objects, on the other hand, do not take in a default, instead returning an empty variant of the desired tag.
Writing with Codecs
CompoundTag
s now have methods to write and read using a Codec
or MapCodec
. For a Codec
, it will store the serialized data inside the key specified. For a MapCodec
, it will merge the fields into the top level tag.
// For some Codec<ExampleObject> CODEC and MapCodec<ExampleObject> MAP_CODEC
// We will also have ExampleObject example
CompoundTag tag = new CompoundTag();
// For a codec
tag.store("example_key", CODEC, example);
Optional<ExampleObject> fromCodec = tag.read("example_key", CODEC);
// For a map codec
tag.store(MAP_CODEC, example);
Optional<ExampleObject> fromMapCodec = tag.read(MAP_CODEC);
Render Pipeline Rework
Rendering an object to the screen, whether through a shader or a RenderType, has been fully or partially reworked, depending on what systems you were using previously. As such, a lot of things need to be reexplained, the primer mentioned below will provide a very in-depth look. However, for the people who don’t care, here’s the TL;DR.
First, core-shader JSONs no longer exist. They are replaced by a RenderPipeline
, which is effectively an in-code substitute.
Second, the RenderPipeline
s turns most flag values into enum constants.
For example, instead of storing the blend function mode id, you store a BlendFunction
.
Similarly, you no longer store or set up the direct texture objects, but instead manage it through a GpuTexture
.
Finally, the VertexBuffer
can either draw to the framebuffer by directly passing in the RenderPipeline
, updating any necessary uniforms in the consumer, or by passing in the RenderType
.
Abstracting OpenGL
As many are aware, Minecraft has been abstracting away their OpenGL calls and constants, and this release is no different. All the calls to GL codes, except BufferUsage, have been moved out of object references, to be obtained typically by calling GlConst$toGl. However, with all the other rendering reworks, there are numerous changes and complexities that require learning an entirely new system, assuming you’re not using RenderTypes
.
Warning
Please be aware that while these changes are wide sweeping, OpenGL is still the underlying platform, so they will probably not cause compile errors. Mods are however advised switch to the new platform.
Model rework
Besides the abstracting of OpenGL, there are also significant changes to how models are loaded into the game, and how they are processed.
Examples of this include rewrites to model discovery, parsing and instantiation.
Additionally, NeoForge has aligned its BakedModel
framework closer to what vanilla wants to use in the new model part system.
Note
The changes in this area are significant, and would blow up the size of this announcement. We will post additional information and documentation in the next few days that describe the changes and how to use them.
Fabric is also going in this direction, causing less headaches for cross-platform modders.
Client Mod Initialization
Previously, in the case of the client, mods were instantiated during client initialization.
This meant that Minecraft.getInstance()
returned a valid object and was usable to a certain degree.
To better align with vanilla changes to game option registration (such as keybinds), your @Mod
entrypoints will now be constructed before Minecraft
. As a consequence, accessing the Minecraft
instance during mod loading is not possible, and mods that require access to it will have to adjust their code (for example, to use the FMLClientSetupEvent
).
NeoForge internal changes
Besides the myriad of user and modder facing changes, there are also some internal changes to NeoForge’s build system, which modders will not experience.
Split SourceSets
To prepare for supporting split sourcesets in mod development environments, we needed to split the NeoForge code base first, based on whether the code in question was common, or client only. This split has now been performed and PRs written for older versions will need to be adapted, especially if they touch client side code. Players will not experience any changes, however some classes had to be moved from a common package to a client one or vice versa so some mods will have to be updated to account for this.
Porting Primer
A porting primer covering Minecraft’s changes is available here (courtesy of @ChampionAsh5357
).
We might update this blog post later with more NeoForge-specific changes.
Stay tuned, and happy porting!