From McJty Modding
Revision as of 07:21, 31 July 2022 by McJty (talk | contribs) (Various bits of information to help with porting)
Jump to: navigation, search


Everything you need to know about 1.19 modding with Forge.


Useful links


18px-OOjs_UI_icon_notice-destructive.svg.png Warning: The tutorial for 1.19 is not ready yet! On the GitHub you can currently find the work in progress port to 1.19. Most of the things are working

Porting from 1.18.2

Various bits of information to help with porting

18px-OOjs_UI_icon_notice-destructive.svg.png Warning: This is not a complete list. The information in the list below contains everything that was discovered during the porting of the RFTools mods

Various Renames

Before starting to actually port you should follow this guide to do a lot of renames for you.

  • In many places World has been replaced with Level. For example it's now LevelTickEvent
  • Similarly many 'world' instance members have been replaced with 'level'. Especially in Forge events
  • Containers are now called MenuTypes. For example ForgeRegistries.CONTAINERS is now ForgeRegistries.MENU_TYPES
  • ForgeRegistries.BLOCK_ENTITIES is now called ForgeRegistries.BLOCK_ENTITY_TYPES
  • ForgeRegistries.ENTITIES is now called ForgeRegistries.ENTITY_TYPES
  • RenderGameOverlayEvent has become RenderGuiOverlayEvent and the getType() is replaced by getOverlay(). You can find the vanilla overlays in VanillaGuiOverlay
  • getMatrixStack() -> getPoseStack()
  • InputEvent.KeyInputEvent -> InputEvent.Key
  • NetworkHooks.openGui() -> NetworkHooks.openScreen()
  • Block Properties: noDrops() -> noLootTable()

Various Removals

  • net.minecraftforge.registries.ForgeRegistryEntry is gone. You can simply remove it. It is no longer needed


ClientRegistry.registerKeyBinding() has gone and is replaced by the RegisterKeyMappingsEvent event that you have to subscribe to the mod bus.


The getRegistryName() function is gone now. To get the ResourceLocation from an object you can do these:

ResourceLocation rl = ForgeRegistries.ITEMS.getKey(item);
ResourceLocation rl = ForgeRegistries.BLOCKS.getKey(block);
ResourceLocation rl = ForgeRegistries.FLUIDS.getKey(fluid);
ResourceLocation rl = level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY).getKey(biome);

Note how it is different for biomes. The reason for that is that biomes can be specified fully in Json. And when that happens there will be no entry for this biome in the forge registry. The method using registryAccess() is the safest way to get the key for a biome. The same is true for other objects that can be added dynamically to the game using json only (structures, dimensions, ...)

Text Component changes

You can no longer do things like new TranslatableComponent(), new TextComponent(), or new KeybindComponent(). Instead you have to do things like:

  • Component.translatable(key)
  • Component.literal(text)
  • Component.keybind(keybind)

Fluid API changes

There have been extensive changes to fluids. Here is a guide

  • Fluid.getAttributes() is gone and replaced with IClientFluidTypeExtensions.of(fluid) for render attributes and fluid.getFluidType() for other settings
  • When making a custom fluid the createAttributes() method is gone. Instead you have to create (and register) a new FluidType and also make a IClientFluidTypeExtensions anonymous subclass for client side attributes. See the fluid guide.

Data Generators

Data generation has changed. addProvider() has an extra boolean parameter. For a server-side datagenerator you pass event.includeServer() and for a client-side datagenerator you pass event.includeClient(). The 'if' can be removed:

    public static void gatherData(GatherDataEvent event) {
        DataGenerator generator = event.getGenerator();
        generator.addProvider(event.includeServer(), new Recipes(generator));
        generator.addProvider(event.includeServer(), new LootTables(generator));
        BlockTags blockTags = new BlockTags(generator, event.getExistingFileHelper());
        generator.addProvider(event.includeServer(), blockTags);
        generator.addProvider(event.includeServer(), new ItemTags(generator, blockTags, event.getExistingFileHelper()));
        generator.addProvider(event.includeClient(), new BlockStates(generator, event.getExistingFileHelper()));
        generator.addProvider(event.includeClient(), new Items(generator, event.getExistingFileHelper()));

Random vs RandomSource

In various places (like worldgen but also in block ticking) Mojang is now using RandomSource instead of Random. In addition tickable sounds now have an extra RandomSource parameter in their constructor.

Chat messages

Player.sendMessage() has now become player.sendSystemMessage() and the UUID parameter has been removed.

Biome Loading Event vs BiomeDecorators

See this guide for more information on Biome Decorators.

BiomeLoadingEvent is gone. You can now do (most/all) stuff with json Biome Modifiers. Example of a biome decorator (place in data/<modid>/forge/biome_modifier):

  "type": "forge:add_features",
  "biomes": "#minecraft:is_overworld",
  "features": "deepresonance:resonating_overworld",
  "step": "underground_ores"

Render Types

Although the old way still works it is deprecated and you should move your render type setting to the block model. This can also be done with datagen. Basically ItemBlockRenderTypes.setRenderLayer() is now deprecated. Instead make a model like this:

  "parent": "deepresonance:block/crystal",
  "render_type": "minecraft:translucent",
  "textures": {
    "crystal_texture": "deepresonance:block/empty_crystal",
    "particle": "deepresonance:block/empty_crystal"


When making CraftingContainer instances (if you want to craft a recipe in code) you also need to implement quickMoveStack() now. Just return ItemStack.EMPTY

Baked Models

There have been a lot of render related changes. To get some idea of this you can look at this notion site. Here is a summary:

BakedQuadBuilder has been replaced with QuadBakingVertexConsumer. You use it as follows:

        BakedQuad[] quad = new BakedQuad[1];
        QuadBakingVertexConsumer builder = new QuadBakingVertexConsumer(q -> quad[0] = q);
        builder.setDirection(Direction.getNearest(normal.x, normal.y, normal.z));
        RenderHelper.putVertex(builder, normal, v1.x, v1.y, v1.z, 0, 0, sprite, r, g, b, a);
        RenderHelper.putVertex(builder, normal, v2.x, v2.y, v2.z, 0, 16, sprite, r, g, b, a);
        RenderHelper.putVertex(builder, normal, v3.x, v3.y, v3.z, 16, 16, sprite, r, g, b, a);
        RenderHelper.putVertex(builder, normal, v4.x, v4.y, v4.z, 16, 0, sprite, r, g, b, a);
        return quad[0];

And building a vertex has also changed. Here is an example:

    public static void putVertex(VertexConsumer builder, Position normal,
                                 double x, double y, double z, float u, float v, TextureAtlasSprite sprite, float r, float g, float b, float a) {
        float iu = sprite.getU(u);
        float iv = sprite.getV(v);
        builder.vertex(x, y, z)
                .uv(iu, iv)
                .uv2(0, 0)
                .color(r, g, b, a)
                .normal((float)normal.x(), (float)normal.y(), (float)normal.z())

The Porting Tutorial

In this chapter we explain step by step how to port the tutorial from 1.18.2 to 1.19