A surprise update for 1.20.3 comes, with a big change to blocks! The changes are likely for the future expansion of data packs to allow custom blocks. All Block
classes must(tm) now define its codec. I recommend checking the article on Fabric Modding Wiki, that should be good for most users.
A new Fabric Loader, version 0.14.23, supporting 1.20.3 versions was released. This update also comes with several changes, including support for Java 22 and duplicate loader detection that is useful in dev environment. It also changes some error messages to be more user-friendly.
Loom 1.4 was also released; this version requires Gradle 8.3. The biggest feature is the support for Vineflower (formerly known as Quiltflower) decompiler. Vineflower produces better output in certain cases, including chained methods. CFR remains the default decompiler. Other changes include fabricApi.module
support for deprecated modules, disk usage improvement for multi-project mods, and additional manifest entry to check if a jar is a source file.
Fabric API 0.89.4 was released for the snapshot. The only breaking change was to the Object Builder API, whose two deprecated classes, BlockSetTypeRegistry
and WoodTypeRegistry
, were removed. A builder class, added in an earlier update, should be used instead.
Here is a refresher for those who have been living under rocks for 6 years: Mojang now uses DataFixerUpper "codecs" to serialize various data. This system allows the same data to be represented in NBT or JSON without writing two codes, and is designed to be fail-safe against invalid inputs.
A codec is a serialization format for a particular class: for example, a codec for TinyPotatoBlock
can (de)serialize a tiny potato block instance. Each field is also serialized using codecs; for example, the field int love
is serialized using Codec.INT
. The wiki article mentioned above provides good example of codecs.
Back to the changes: Mojang now uses codecs to serialize blocks - specifically, instances of a particular type of block. (You cannot make an entirely new block like a cog or a piano, but you can make, for example, a new type of wood blocks.) This does not make much sense today, because block instances are created inside your code and not read from disk. This indicates however, that Mojang may be willing to make blocks data-driven to some extent.
Here are the changes for your mods. First, all blocks must now implement getCodec
method. This method, however, is currently unused, so you can return null
, throw UnsupportedOperationException
, etc. If you do however want to future-proof the code, you need to write the codec, store it in a static final
field, and return when called. For a block with no fields in the class (one whose constructor takes AbstractBlock.Settings
only):
public static final MapCodec<TinyPotatoBlock> CODEC = createCodec(TinyPotatoBlock::new);
public MapCodec<TinyPotatoBlock> getCodec() {
return CODEC;
}
For a block with fields, just do it like other codecs, like this (for public ColoredBlock(DyeColor color, Settings settings)
):
public static final MapCodec<ColoredBlock> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
DyeColor.CODEC.fieldOf("color").forGetter(ColoredBlock::getColor),
createSettingsCodec()
).apply(instance, ColoredBlock::new));
Text
also got a codec, and now is serialized using it (including when interacting with Gson). Over the network the text is now sent as an NBT.
- Important change:
Text#translatable
now expects all arguments to be numbers, boolean, strings, or anotherText
s. To pass things likeBlockPos
orIdentifier
, which were previously implicitly converted to strings, usestringifiedTranslatable
. - For those who have previously used
Codecs.TEXT
orSTRINGIFIED_TEXT
, it's time to switch toTextCodecs.CODEC
orTextCodecs.STRINGIFIED_CODEC
. Text.Serializer
inner class was split intoSerializer
(to use as an Gson adapter) andSerialization
(contains static methods). The methods were also renamed;toJson
is nowtoJsonString
to clarify return value.Style.Serializer
is gone; it is nowCodecs
and holds the codec only.- Those who add a custom
TextContent
orNbtDataSource
will now need an invasive mixin. If you're one of the people who need this, contact at #api. - In a related news,
PacketByteBuf#readUnlimitedText
was added; this reads an infinite amount of text with no size limit. Most S2C packets now use this.
AbstractBlock#randomTick
no longer callsscheduledTick
.BlockSetType
receivedcanButtonBeActivatedByArrows
andpressurePlateSensitivity
fields.pressurePlateSensitivity
is specified usingActivationRule
enum.ColoredFallingBlock
was added, replacingGravelBlock
andSandBlock
.PowderSnowCauldronBlock
was removed;LeveledCauldronBlock
handles the logic now.SaplingGenerator
is now inblock
package, and individual generator classes were removed and replaced with fields.
PopupScreen
was added. This screen, unlike other screens, renders on top of an existing screen. The popup can include a message, an image, and buttons (such as "Open Link"). To create an instance, useBuilder
.ClientPlayNetworkHandler#clearWorld
was split intoclearWorld
(for disconnection) andunloadWorld
(for temporary disconnection like reconfiguration).clearWorld
callsunloadWorld
inside.
LivingEntity#getMaxRelativeHeadRotation
, which... returns the max head rotation relative to the body in degrees, which by default is 50. Fun fact: human necks' horizontal range of motion is up to 90 degrees.IdList
is now reference (identity)-keyed. Many otherRegistryKey
-keyed maps were converted to reference maps as well.StringIdentifiable
can now be used with non-enums, viacreateBasicCodec
. This does not supportbyId
method.Util#lastIdentityIndexGetter
was added; this is the identity comparison version oflastIndexGetter
.Uuids#STRICT_CODEC
was added. UnlikeCODEC
, undashed UUIDs are not supported with this codec.Codecs#BASIC_OBJECT
andRuntimeOps
were added. This allows serialization of basic objects - primitives, strings, lists, and maps - without writing a codec yourself. Since the returned result has raw types, however, this should not be used in most cases.- GameTest users can now use
expectItem(Item)
anddontExpectItem(Item)
methods inTestContext
. They detect item entities within the entire bounding box of the test structure. EntityType#HEROBRINE
was removed. (Wait, was this ever added in the first place?)MathHelper#rotateAround
, which is useful if you are a linear algebra nerd and know what you are doing.
Thank you for this gist! As someone starting out with 1.20.4, trying to scrounge up documentation on the required
getCodec()
was tough.