Fabric for Minecraft 1.19.3
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
, andALLOW_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 theRegistryKey
instances used for registries, previously held inRegistry
’sstatic 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 Resource
s.
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 ofRegistryEntry<T>
RegistryEntryPredicateArgumentType
, which works likeRegistryPredicateArgumentType
but the entry is either namedRegistryEntryList
(tags) orRegistryEntry
(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 withRegistry<SoundEvent>
. SoundEvent
should now be constructed usingSoundEvent.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 ofSoundEvent
.
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 forClickableWidget
andButtonWidget.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
andsendCommand
methods have been moved fromClientPlayerEntity
toClientPlayNetworkHandler
. - Mobs using
Brain
for control can now take advantage of functionalTask
creation. This resembles React Hooks and is replacing the previous subclass-based approach in vanilla. See javadoc for examples. ItemStack#isItemEqualIgnoreDamage
andItemStack#areItemsEqualIgnoreDamage
were removed. Either use standardisItemEqual
/areItemsEqual
or compare yourself.JsonHelper#deserialize
no longer permitsnull
. UsedeserializeNullable
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 toExperienceDroppingBlock
as it is used by a Sculk block.WallStandingBlockItem
is renamed toVerticallyAttachableBlockItem
because it can now be used for hanging blocks as well.AbstractButtonBlock
is renamed to ButtonBlock as it is no longerabstract
ScreenHandler#transferSlot
is renamed toquickMove
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.