Skip to content

Instantly share code, notes, and snippets.

@apple502j
Last active December 25, 2023 18:20
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save apple502j/b6564eed41f7e3bd07001c23dfc371c4 to your computer and use it in GitHub Desktop.
Save apple502j/b6564eed41f7e3bd07001c23dfc371c4 to your computer and use it in GitHub Desktop.

23w40a: Block Codecs Update

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.

Fabric updates

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.

Minecraft updates

Block codecs

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

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 another Texts. To pass things like BlockPos or Identifier, which were previously implicitly converted to strings, use stringifiedTranslatable.
  • For those who have previously used Codecs.TEXT or STRINGIFIED_TEXT, it's time to switch to TextCodecs.CODEC or TextCodecs.STRINGIFIED_CODEC.
  • Text.Serializer inner class was split into Serializer (to use as an Gson adapter) and Serialization (contains static methods). The methods were also renamed; toJson is now toJsonString to clarify return value.
  • Style.Serializer is gone; it is now Codecs and holds the codec only.
  • Those who add a custom TextContent or NbtDataSource 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.

Other changes

Blocks

  • AbstractBlock#randomTick no longer calls scheduledTick.
  • BlockSetType received canButtonBeActivatedByArrows and pressurePlateSensitivity fields. pressurePlateSensitivity is specified using ActivationRule enum.
  • ColoredFallingBlock was added, replacing GravelBlock and SandBlock.
  • PowderSnowCauldronBlock was removed; LeveledCauldronBlock handles the logic now.
  • SaplingGenerator is now in block package, and individual generator classes were removed and replaced with fields.

Client

  • 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, use Builder.
  • ClientPlayNetworkHandler#clearWorld was split into clearWorld (for disconnection) and unloadWorld (for temporary disconnection like reconfiguration). clearWorld calls unloadWorld inside.

Misc

  • 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 other RegistryKey-keyed maps were converted to reference maps as well.
  • StringIdentifiable can now be used with non-enums, via createBasicCodec. This does not support byId method.
  • Util#lastIdentityIndexGetter was added; this is the identity comparison version of lastIndexGetter.
  • Uuids#STRICT_CODEC was added. Unlike CODEC, undashed UUIDs are not supported with this codec.
  • Codecs#BASIC_OBJECT and RuntimeOps 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) and dontExpectItem(Item) methods in TestContext. 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.
@Brickgard
Copy link

If you don't mind me asking:
Are the notes about Other Changes > Client > PopupScreen and such referencing Fabric client changes, or changes to vanilla's client within 23w40a?

@jacobbridges
Copy link

Thank you for this gist! As someone starting out with 1.20.4, trying to scrounge up documentation on the required getCodec() was tough.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment