Minecraft 1.19.3 is almost here, with big changes to game internals. Beginning with this update, Mojang have changed their versioning scheme such that ‘minor’ releases like this one may contain larger changes under the hood. As such, the changes in this version affect almost all mods (not even comparable to the changes in 1.18.2, and significantly bigger than 1.19). Here are the list of all major modder-facing changes in this version.

As usual, we ask players to be patient, and give mod developers time to update to this new version.

Fabric changes

Developers should use Loom 1.0 (at the time of writing) to develop for Minecraft 1.19.3.

Minecraft 1.19.3 introduces numerous breaking changes to major developer-facing APIs.

Fabric API Mod ID change

The mod ID of Fabric API is now fabric-api. The old ID fabric still works in fabric.mod.json, such as depends; however, the new ID is recommended for better user experience when Fabric API is missing.

New Fabric API features

Fabric API added many features since the last update blog post:

  • Item API: support stack-aware recipe remainders. (AlphaMode)
  • Content Registries: register villager interactions, sculk sensor frequencies, and path node types (aws404, Shnupbups, devpelux)
  • Client Tags: allow client-side mods to rely on tags not present on the server. (dexman545)
  • Entity Events: add AFTER_DEATH, AFTER_DAMAGE, and ALLOW_DEATH events. (Technici4n)
  • Resource Conditions: support all tags. (apple502j)
  • Sound API: play custom sounds. (SquidDev)
  • Resource Loader: support Text as pack display name. (apple502j)
  • Block Appearance API: groundwork for cross-mod connected textures. (Technici4n)
  • FabricLanguageProvider: easily generate language JSON files with data generation. (mineblock11)
  • Overwriting Screen Handler Factory: open new screen handlers without re-centering the mouse pointer. (apple502j)
  • Transfer API: add several helper APIs for fluid interactions and storage. (Technici4n)

Minecraft changes

Registries

There are several changes to registries.

The most impactful change is that the Registry class is now split into 3 different classes:

  • RegistryKeys holds the RegistryKey instances used for registries, previously held in Registry’s static final fields.
  • Registries holds all static registry instances.
  • Registry is now an interface and holds everything else.

Together with this change, the KEY suffixes for registry key fields have been removed.

- Registry.register(Registry.BLOCK_KEY, new Identifier("test", "dirt"), DIRT_BLOCK);
+ Registry.register(Registries.BLOCK, new Identifier("test", "dirt"), DIRT_BLOCK);

In many parts of the code, Registry is now replaced with RegistryEntryLookup or Registerable. RegistryEntryLookup is a read-only view of a registry, while Registerable is a write-only view. The BuiltinRegistries class no longer holds the built-in registry; it instead holds the builder to create a RegistryEntryLookup.RegistryLookup (a lookup of registry lookups, similar to DynamicRegistryManager). See below for migrating old worldgen code.

Since virtually all registry-related code needs a rewrite, Yarn used this opportunity to repackage the registry and tag packages under net.minecraft.registry and net.minecraft.registry.tag respectively. Note, if you are using Mojang Mappings or other third-party mappings, this does not affect you. A simple find-and-replace should be enough:

- import net.minecraft.tag.TagKey;
- import net.minecraft.util.registry.Registry;
- import net.minecraft.util.registry.RegistryEntry;
+ import net.minecraft.registry.tag.TagKey;
+ import net.minecraft.registry.Registry;
+ import net.minecraft.registry.entry.RegistryEntry;

Fabric API’s DynamicRegistrySetupCallback was changed to take a new context object DynamicRegistryView instead of a DynamicRegistryManager. This API allows easy registration of events, while preventing crashes caused by the misuse of previous API.

Item Groups

One of the major changes in this version involve the Creative inventory screen. Items can now appear in multiple tabs and the display order no longer relies on the item registration order. Item groups got a significant refactor during this process.

The fabric-item-groups-v0 module is replaced with fabric-item-group-api-v1. This is now required for adding items to vanilla item groups; you can no longer specify the item group using Item.Settings.

To add an item to a vanilla or other existing item group, use ItemGroupEvents.

// 1.19.2
Item MY_ITEM = new Item(new Item.Settings().group(ItemGroup.MISC));

// 1.19.3
ItemGroupEvents.modifyEntriesEvent(ItemGroups.INGREDIENTS).register(entries -> entries.add(MY_ITEM));
// Instead of ItemGroup, you can also specify an Identifier for modded item groups.

To create a new item group, use FabricItemGroup.builder(). This allows adding items directly, without using ItemGroupEvents:

ItemGroup ITEM_GROUP = FabricItemGroup.builder(new Identifier("example", "test_group"))
    .displayName(Text.literal("Example Item Group"))
    .icon(() -> new ItemStack(Items.DIAMOND))
    .entries((enabledFeatures, entries, operatorEnabled) -> {
        entries.add(Items.DIAMOND);
    })
    .build();

The changes also made it possible to add items at a specific position in the Creative inventory. Check the FabricItemGroupEntries javadoc for details.

Data generation

A number of breaking changes have been made to the Data Generation API.

Data generators now have to create a “pack” and add providers to the pack. (It’s like a resource pack - the provider generates a resource for a specific pack.) This can be done with FabricDataGenerator#createPack, or createBuiltinResourcePack for packs loadable by ResouceManagerHelper#registerBuiltinResourcePack.

FabricDataGenerator.Pack pack = dataGenerator.createPack();
pack.addProvider(YourProvider::new);

Data generator constructors now take FabricDataOutput as an argument instead of DataGenerator. generateStuff methods (e.g. generateBlockLootTables) are now provided from the vanilla game and renamed to generate. They are also now public, not protected.

public class TestBlockLootTableProvider extends FabricBlockLootTableProvider {
    public TestBlockLootTableProvider(FabricDataGenerator dataGenerator) {
        super(dataGenerator);
    }

    @Override
    // Renamed from generateBlockLootTables and now public
    public void generate() {
        addDrop(SIMPLE_BLOCK);
    }
}

For tag generators, the constructor must also take CompletableFuture<RegistryWrapper.WrapperLookup>. FabricTagProvider.DynamicRegistryTagProvider is now replaced with just FabricTagProvider. The configure method is used to add tags.

public class TestBiomeTagProvider extends FabricTagProvider<Biome> {
    public TestBiomeTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
        super(output, RegistryKeys.BIOME, registriesFuture);
    }

    @Override
    protected void configure(RegistryWrapper.WrapperLookup registries) {
        getOrCreateTagBuilder(TagKey.of(RegistryKeys.BIOME, new Identifier(MOD_ID, "example")))
        .add(BiomeKeys.BADLANDS);
    }
}

Custom world generation

In the registry section we briefly mentioned that BuiltinRegistries no longer holds the actual registries; more specifically, BuiltinRegistries is no longer used during actual world generation. If your biome mod, structure mod, 1.19 message type mod etc. registers stuff into BuiltinRegistries, you now need to generate its JSON and include it in the mod as a data pack.

You can override the new DataGeneratorEntrypoint.buildRegistry(RegistryBuilder registryBuilder) in your data gen entrypoint to add your modded entries the registry used for datageneration. buildRegistry is invoked asynchronously and the resulting RegistryWrapper.WrapperLookup can be passed to your data providers using a CompletableFuture.

public class DataGeneratorEntrypoint implements net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint {
	// onInitializeDataGenerator goes here

	@Override
	public void buildRegistry(RegistryBuilder registryBuilder) {
            registryBuilder.addRegistry(RegistryKeys.BIOME, ExampleBiomes::bootstrap);
	}
}

// Minecraft's BuiltinBiomes class is another good example.
public final class ExampleBiomes {
    public static final RegistryKey<Biome> MODDED_BIOME_KEY = RegistryKey.of(RegistryKeys.BIOME, new Identifier("modid", "biome_name"));

    public static void bootstrap(Registerable<Biome> biomeRegisterable) {
        biomeRegisterable.register(MODDED_BIOME_KEY, createBiome());
    }
}

A new data generator, FabricDynamicRegistryGenerator, allows generating the JSON files from the previously-registered objects.

public class WorldgenProvider extends FabricDynamicRegistryProvider {
    public WorldgenProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
        super(output, registriesFuture);
    }

    @Override
    protected void configure(RegistryWrapper.WrapperLookup registries, Entries entries) {
        final RegistryWrapper.Impl<Biome> biomeRegistry = registries.getWrapperOrThrow(RegistryKeys.BIOME);

        entries.add(ExampleBiomes.MODDED_BIOME_KEY, biomeRegistry.getOrThrow(ExampleBiomes.MODDED_BIOME_KEY).value());
    }
}

Textures

The performance optimizations in 1.19.3 include texture loading changes. By default, textures used in a certain atlas (such as block texture atlas) must now be in the folder for the type of the atlas (such as textures/block). This affects some resource packs, which might be bundled in a mod.

To use custom textures located elsewhere, an atlas configuration file should be added to the resource pack. See the 22w46a update blogpost for more details.

Fabric Textures API is removed entirely; ClientSpriteRegistryCallback is replaced with atlas configuration files, and DependentSprite was practically unused.

Resource loading

There are many refactors to resource loading, such as using a custom filesystem to improve performance. However they should not affect most mods.

One change made in the refactor is that resource packs now allow Text to be used as the display name. With this change,ResourceManagerHelper#registerBuiltinResourcePack method can now take Text. The old String based method is now deprecated; use Text#literal for a hard-coded name.

Mods that support additional resource types should now use ResourceFinder. This, when given a resource manager, returns the map of IDs to Resources.

public static final ResourceFinder JSON_FINDER = ResourceFinder.json("tiny_potatoes");
public static final ResourceFinder PNG_FINDER = new ResourceFinder("tiny_potatoes", ".png");

// to use:
JSON_FINDER.findResources(resourceManager).forEach((id, resource) -> {});

Command changes

Several command argument types are removed and consolidated. They include: EnchantmentArgumentType, EntitySummonArgumentType, and StatusEffectArgumentType. There are 2 new argument types that replace those.

  • RegistryEntryArgumentType, which is an argument type of RegistryEntry<T>
  • RegistryEntryPredicateArgumentType, which works like RegistryPredicateArgumentType but the entry is either named RegistryEntryList (tags) or RegistryEntry (one entry)

Move to JOML

Mojang has started using the JOML library for rendering-related math. Vec3f is now replaced with JOML Vector3f. Many of the functions have slightly different names. For example:

- import net.minecraft.util.math.Vec3f;
+ import org.joml.Vector3f;

- Vector3f vec;
- float x = vec.getX();
+ Vec3f vec;
+ float x = vec.x();

Vec3d and Vec3i are unaffected.

Sounds

During the pre-release phase of 1.19.3, there were changes to how sounds are referenced and played.

  • Introduction: there are two ways a sound is referred to - “sound asset” defined by the client and identified by sound ID, and “sound event” used by the server and registered in a registry.
  • Previously, to play a registered sound event, PlaySoundS2CPacket was used, and to play a custom (resource pack-defined) sound, PlaySoundIdS2CPacket was used.
  • References to SoundEvent are mostly replaced with Registry<SoundEvent>.
  • SoundEvent should now be constructed using SoundEvent.of, which is transitively access-widened by Fabric API.
  • PlaySoundIdS2CPacket was removed. To play a custom sound, use direct registry entry (RegistryEntry.of(SoundEvent)).
  • Biome Modification API received a breaking change to accept RegistryEntry<SoundEvent> instead of SoundEvent.

Other changes

Here are other miscellaneous changes in 1.19.3:

  • Feature flags were introduced. Currently, blocks, items, and entity types can be hidden behind a flag. “Experimental” features that aren’t enabled by a feature flag are still registered in a registry, but are ignored in most methods. Resource Condition API can now check feature flags.
  • For those who use the vanilla system for GUIs (instead of third-party APIs): a new grid-based GUI system is added. This can be used in place of the old way of positioning widgets, and reduces the need for hard-coded display positions.
  • ButtonWidget is now constructed using a builder.
  • Tooltips got a refactor to support item group related changes. Screen#setTooltip methods are added; there are three overloads. They all have to be called at every render call. setTooltip method is also available for ClickableWidget and ButtonWidget.Builder.
  • Networking changes: chat preview was removed, and the game no longer requires a header packet to be sent when blocking messages. The client-side sendChatMessage and sendCommand methods have been moved from ClientPlayerEntity to ClientPlayNetworkHandler.
  • Mobs using Brain for control can now take advantage of functional Task creation. This resembles React Hooks and is replacing the previous subclass-based approach in vanilla. See javadoc for examples.
  • ItemStack#isItemEqualIgnoreDamage and ItemStack#areItemsEqualIgnoreDamage were removed. Either use standard isItemEqual/areItemsEqual or compare yourself.
  • JsonHelper#deserialize no longer permits null. Use deserializeNullable instead.

Yarn renames

If you are using Mojang Mappings or other third-party mappings, you can skip this section.

There are dozens of renames to fix wrong names and improve code readability. Here are some of the major renames:

  • createAndScheduleBlockTick/createAndScheduleFluidTick is now simplyscheduleBlockTick/scheduleFluidTick.
  • OreBlock is renamed to ExperienceDroppingBlock as it is used by a Sculk block.
  • WallStandingBlockItem is renamed to VerticallyAttachableBlockItem because it can now be used for hanging blocks as well.
  • AbstractButtonBlock is renamed to ButtonBlock as it is no longer abstract
  • ScreenHandler#transferSlot is renamed to quickMove to be more descriptive.
  • Shaders and programs were renamed. A program is composed of vertex and fragment shaders; this was previously swapped. See the pull request for details.