Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

1.21.1 to 26.1 NeoForge Porting Guide

This site indexes the upstream NeoForge porting primers so you can jump straight to the section that matters.

The upstream chain covered here is:

1.21.1 -> 1.21.2/3 -> 1.21.4 -> 1.21.5 -> 1.21.6 -> 1.21.7 -> 1.21.8 -> 1.21.9 -> 1.21.10 -> 1.21.11 -> 26.1

There is no separate 1.21.3 primer upstream. The 1.21.2 primer covers the 1.21.1 -> 1.21.2/3 step.

How to use this site

If you know what subsystem changed, use the Topic Map below. Every link goes directly to the relevant section.

If the same subsystem changed across multiple versions, see Repeatedly Changing Systems for the reading order.

If you want the raw primers, see Detailed Primers for a full table of contents with anchor links to every section.

If you have a compile error, use the Class and Method Index to find where it changed.


Topic Map

Build, mappings, names, imports, and package moves

Datagen, packs, registries, tags, codecs, loot, validation, and recipe serialization

Items, components, equipment, armor, tools, combat, dyes, and consumables

Rendering, models, shaders, particles, block models, item models, materials, atlases, and visual pipelines

Entities, mobs, mob AI, conversions, spawning, and entity data

GUI, input, keybinds, debug screens, debug tooling, RPC tooling, and test infrastructure

World state, saved data, game rules, timelines, clocks, players, permissions, waypoints, and other server-side systems

Remaining minor migrations

Every primer also contains New Tags, Tag Changes, List of Additions, List of Changes, and List of Removals subsections within their Minor Migrations. For those, go to the full primer pages in Detailed Primers.


Class and Method Index

If you have a compile error or need to find where a specific class/method changed, search this table.

Class / MethodVersionSection
AbstractFurnaceBlockEntity fuel1.21.2Fuel Values
AbstractMinecart1.21.2Minecart Behavior
Activities / Brain26.1Activities and Brains
AnimationDefinition#bake1.21.6Animation Baking
ArmorItem / ArmorMaterial1.21.2Armor Materials, Equipment, and Model (Textures)
BakedModel / BakedQuad1.21.5Model Rework
BlockBehaviour#neighborChanged1.21.2Orientations
BlockEntityType constructors1.21.2BlockEntityTypes Privatized!
CauldronInteraction26.1Cauldron Interaction Dispatchers
ChunkPos (now record)26.1ChunkPos, now a record
ChunkSectionLayer1.21.6ChunkSectionLayers
Client item JSONs1.21.4Client Items
Consumable / ConsumableListener1.21.2Consumables
DataComponents getters1.21.5Data Component Getters
DataComponents new types1.21.11New Data Components
DataComponents initializers26.1Data Component Initializers
DiggerItem / SwordItem removal1.21.5Weapons, Tools, and Armor: Removing the Redundancies
DyeRecipe / DyeItem26.1Dye Component
Entity#interactAt removal26.1The Removal of interactAt
EntityReference (replaces UUID)1.21.5Entity References
EntityRenderState1.21.2Entity Render States
Explosion (now interface)1.21.2EXPLOOOOSSSION!
GameRules1.21.11The Game Rule Shuffle
GameTest framework1.21.5The Game Test Overhaul
GenerationStep$Carving removal1.21.2The Removal of the Carving Generation Step
GpuTexture / RenderPipeline1.21.5Render Pipeline Rework
GuiGraphics / GUI rendering1.21.6GUI Changes
Holder / HolderSet / HolderGetter1.21.2The Holder Set Transition
Identifier (was ResourceLocation)1.21.11ResourceLocation to Identifier
Ingredient1.21.2The Ingredient Shift
InteractionResult1.21.2Interaction Results
ItemInstance / StackTemplate26.1Item Instances and Stack Templates
KeyMapping / input events1.21.9Input Handling Consolidation
Leashable1.21.6Leashes
Level#isClientSide1.21.9Level#isClientSide now private
Level#random26.1Level#random field now protected
LootContextParam / LootContextParamSet1.21.2Context Keys
LootPoolEntry / loot codecs26.1Loot Type Unrolling
Mob#convertTo1.21.2Mob Conversions
OptionEnum removal1.21.11OptionEnum Removal
Permission / PermissionSet1.21.11Permission Overhaul
Profiler#get (replaces getProfiler)1.21.2Profilers and the Tracy Client
Recipe registry format1.21.2Recipes, now in Registry format
RecipeDisplay / SlotDisplay1.21.2Recipes, now in Registry format
RenderType shuffle1.21.11Oh Hey, Another Rendering Rewrite
SavedData / SavedDataType1.21.5Saved Data, now with Types
ServerExplosion1.21.2EXPLOOOOSSSION!
Shader JSON / .vsh / .fsh1.21.2Shader Rewrites
SimpleJsonResourceReloadListener1.21.4SimpleJsonResourceReloadListener
TagProvider appender1.21.6Tag Providers: Appender Rewrite
Validatable / ValidationContext26.1Validation Overhaul
Villager trades (datapack)26.1Datapack Villager Trades
VoxelShape helpers1.21.5Voxel Shape Helpers
Waypoint system1.21.6Waypoints
World clocks / time markers26.1World Clocks and Time Markers
World data split26.1Splitting the Primary Level Data into Saved Data

Source and attribution

The split primer pages are copied from ChampionAsh5357/neoforged-github, branch update/26.1. See Source And Attribution.

Repeatedly Changing Systems

This page is the guard rail for the direct port.

When the same subsystem changed in multiple intermediate versions, do not treat the earliest migration note as final. Use the latest applicable version as the source of truth, but still apply the older chapter first so the intermediate API transitions make sense.

Rendering and graphics

Relevant sections:

How to read them:

  • 1.21.2/3 changes GUI blits, shader JSON structure, and render-state assumptions.
  • 1.21.5 is the first large rendering infrastructure rewrite around RenderPipeline, GpuTexture, and render passes.
  • 1.21.6 changes GUI rendering flow again through prepare/render state separation.
  • 1.21.9 changes how features are submitted for rendering.
  • 1.21.11 changes samplers, render types, terrain split, and atlases.
  • 26.1 is the final authority for block/item rendering, materials, tint sources, fluid models, particle layers, and backend-facing rendering APIs.

Practical rule:

  • Treat 26.1 as the final rendering target.
  • Keep 1.21.4 client items and 1.21.6 GUI flow as still-active requirements, not obsolete history.

Item models and item metadata

Relevant sections:

What sticks:

  • 1.21.4 client items are the baseline for item rendering data.
  • 1.21.5 removes more hardcoded item-class assumptions in favor of components and equipment data.
  • 1.21.9, 1.21.11, and 26.1 further change how items participate in rendering and metadata pipelines.

Practical rule:

  • First convert item assets to client items.
  • Then port behavior and metadata around components.
  • Finally validate them against the 26.1 rendering and item-instance model.

Tags, registries, codecs, and validation

Relevant sections:

What sticks:

  • 1.21.2/3 is where Holder and HolderSet start affecting large parts of the codebase.
  • 1.21.5 changes tag access, parser behavior, codec-based reads and writes, and saved-data construction.
  • 1.21.6 changes tag provider building and nudges more code toward generic encoding and decoding.
  • 1.21.11 contributes rename churn that affects registry and identifier-facing code.
  • 26.1 finalizes more codec-driven infrastructure with loot type unrolling and validation overhaul.

Practical rule:

  • The earlier chapters tell you how to get onto holder- and codec-based APIs.
  • 26.1 is the final target for validation and loot registration shape.

Data components

Relevant sections:

What sticks:

  • 1.21.2/3 introduces important component-facing migrations such as consumables and recipe-related data moves.
  • 1.21.5 expands component-centered behavior for tools, armor, weapons, and general data access.
  • 1.21.11 adds more component types.
  • 26.1 continues with initializers, dye components, and more component additions.

Practical rule:

  • Expect items and recipes to get less class-driven and more component-driven as you move forward.

Saved data and world state

Relevant sections:

What sticks:

  • 1.21.5 moves saved data to SavedDataType.
  • 26.1 splits primary level data further into dedicated saved-data objects.

Practical rule:

  • Do the 1.21.5 migration first, then revisit every level/world persistence assumption again in 26.1.

Developer tooling, tests, debugging, and permissions

Relevant sections:

What sticks:

  • 1.21.5 overhauls game tests.
  • 1.21.9 overhauls debugging and management-server shape.
  • 1.21.11 adds a permission overhaul and gizmo-focused visualization work.
  • 26.1 adds Java 25 and more minor tooling-facing changes.

Practical rule:

  • Port gameplay code first.
  • Then re-enable your debug, test, and operator-only tooling against the later chapters.

Detailed Primers

These chapters preserve the upstream primer content step by step. Each section heading links directly to that section within the primer page.

1.21.1 -> 1.21.2/3

Full primer

1.21.2/3 -> 1.21.4

Full primer

1.21.4 -> 1.21.5

Full primer

1.21.5 -> 1.21.6

Full primer

1.21.6 -> 1.21.7

Full primer

1.21.7 -> 1.21.8

Full primer

1.21.8 -> 1.21.9

Full primer

1.21.9 -> 1.21.10

Full primer

1.21.10 -> 1.21.11

Full primer

1.21.11 -> 26.1

Full primer

Minecraft 1.21.1 -> 1.21.2 Mod Migration Primer

This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.1 to 1.21.2. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.

This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.

If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.

Pack Changes

There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.

The Holder Set Transition

Many of the methods that used TagKeys or raw registry objects have been replaced with the direct HolderSet object. A HolderSet is essentially a list of registry object references that can be dynamically updated and managed as needed by the game. There are effectively two kinds of HolderSets: direct and named. Named HolderSets are the object representation of tags in game. It’s called a named set as the HolderSet is referenced by the tag’s name. Direct HolderSets, on the other hand, are created by HolderSet#direct, which functions as an inlined list of values. These are useful when a separate object doesn’t need to be defined to construct some value.

For a JSON example:

// HolderSet#direct with one element
{
    "holder_set": "minecraft:apple"
}

// HolderSet#direct with multiple elements
{
    "holder_set": [
        "minecraft:apple",
        "minecraft:stick"
    ]
}

// HolderSet reference (tags)
{
    "holder_set": "#minecraft:planks"
}

Generally, you should never be constructing holder sets incode except during provider generation. Each set type has a different method of construction.

First, to even deal with Holders or HolderSets, you will need access to the static registry instance via Registry or the datapack registry via HolderGetter. The HolderGetter is either obtained from a BootstrapContext#lookup during datapack registry generation or HolderLookup$Provider#lookupOrThrow either as part of generation or MinecraftServer#registryAccess during gameplay.

Once that is available, for direct HolderSets, you will need to get the Holder form of a registry object. For static registries, this is done through Registry#wrapAsHolder. For datapack registries, this is done through HolderGetter#getOrThrow.

// Direct holder set for Items
HolderSet<Item> items = HolderSet.direct(BuiltInRegistries.ITEM.wrapAsHolder(Items.APPLE));

// Direct holder set for configured features
// Assume we have access to the HolderGetter<ConfiguredFeature<?, ?>> registry
Holderset<ConfiguredFeature<?, ?>> features = HolderSet.direct(registry.getOrThrow(OreFeatures.ORE_IRON));

For named HolderSets, the process is similar. For both static and dynamic registries, you call HolderGetter#getOrThrow.

// Named holder set for Items
HolderSet<Item> items = BuiltInRegistries.ITEM.getOrThrow(ItemTags.PLANKS);

// Named holder set for biomes
// Assume we have access to the HolderGetter<Biome> registry
Holderset<Biome> biomes = registry.getOrThrow(BiomeTags.IS_OCEAN);

As these changes are permeated throughout the entire codebase, they will be listed in more relevant subsections.

Gui Render Types

Gui rendering methods within GuiGraphics now take in a Function<ResourceLocation, RenderType> to determine how to render the image. Also, blit methods now require the size of the PNG to be specified.

// For some GuiGraphics graphics
graphics.blit(
    // How to render the texture
    RenderType::guiTextured,
    // The previous texture parameters
    ...,
    // The size of the PNG to use
    256, 256);

This means methods that provided helpers towards setting the texture or other properties that could be specified within a shader have been removed.

  • com.mojang.blaze3d.pipeline.RenderTarget#blitToScreen(int, int, boolean) -> blitAndBlendToScreen
  • net.minecraft.client.gui.GuiGraphics
    • drawManaged is removed
    • setColor is removed - Now a parameter within the blit and blitSprite methods
    • blit(int, int, int, int, int, TextureAtlasSprite, *) is removed
    • bufferSource -> drawSpecial, not one-to-one as this takes in a consumer of the MultiBufferSource and ends the current batch instead of just returning the MultiBufferSource
  • net.minecraft.client.gui.components.PlayerFaceRenderer
    • All draw methods except draw(GuiGraphics, PlayerSkin, int, int, int) takes in an additional int that defines the color
  • net.minecraft.client.renderer.RenderType - guiTexturedOverlay - Gets the render type for an image overlayed onto the game screen. - guiOpaqueTexturedBackground - Gets the render type for a GUI texture applied to the background of a menu. - guiNauseaOverlay - Gets the render type for the nausea overlay. - guiTextured - Gets the render type for an image within a GUI menu.
  • net.minecraft.client.resources.metadata.gui.GuiSpriteScaling$NineSlice now takes in a boolean representing whether the center portion of the texture should be streched to fit the size

Shader Rewrites

The internals of shaders have been rewritten quite a bit.

Shaders Files

The main changes are the defined samplers and post shaders.

The DiffuseSampler and DiffuseDepthSampler have been given new names depending on the target to apply: InSampler, MainSampler, and MainDepthSampler. InSampler is used in everything but the transparency program shader.

// In some shader JSON
{
    "samplers": [
        { "name": "MainSampler" },
        // ...
    ]
}

Within post effect shaders, they have been changed completely. For a full breakdown of the changes, see PostChainConfig, but in general, all targets are now keys to objects, all pass inputs and filters are now lists of sampler inputs. As for how this looks:

// Old post effect shader JSON
// In assets/<namespace>/shaders/post
{
    "targets": [
        "swap"
    ],
    "passes": [
        {
            "name": "invert",
            "intarget": "minecraft:main",
            "outtarget": "swap",
            "use_linear_filter": true,
            "uniforms": [
                {
                    "name": "InverseAmount",
                    "values": [ 0.8 ]
                }
            ]
        },
        {
            "name": "blit",
            "intarget": "swap",
            "outtarget": "minecraft:main"
        }
    ]
}

// New post effect JSON
// In assets/<namespace>/post_effect
{
    "targets": {
        "swap": {} // Swap is now a target object (fullscreen unless otherwise specified)
    },
    "passes": [
        {
            // Name of the program to apply (previously 'name')
            // assets/minecraft/shaders/post/invert.json
            "program": "minecraft:post/invert",
            // Inputs is now a list
            "inputs": [
                {
                    // Targets the InSampler
                    // Sampler must be available in the program shader JSON
                    "sampler_name": "In",
                    // Reading from the main screen (previously 'intarget')
                    "target": "minecraft:main",
                    // Use GL_LINEAR (previously 'use_linear_filter')
                    "bilinear": true
                }
            ],
            // Writes to the swap target (previously 'outtarget')
            "output": "swap",
            "uniforms": [
                {
                    "name": "InverseAmount",
                    "values": [ 0.8 ]
                }
            ]
        },
        {
            "program": "minecraft:post/blit",
            "inputs": [
                {
                    "sampler_name": "In",
                    "target": "swap"
                }
            ],
            "output": "minecraft:main"
        }
    ]
}

Shader Programs

All shaders, regardless of where they are used (as part of a program or post effect), have a JSON within assets/<namespace>/shaders. This JSON defines everything the shader will use, as defined by ShaderProgramConfig. The main addition is the change to ResourceLocation relative references, and adding the defines header dynamically during load time.

// For some assets/my_mod/shaders/my_shader.json
{
    // Points to assets/my_mod/shaders/my_shader.vsh (previously 'my_shader', without id specification)
    "vertex": "my_mod:my_shader",
    // Points to assets/my_mod/shaders/my_shader.fsh (previously 'my_shader', without id specification)
    "fragment": "my_mod:my_shader",
    // Adds '#define' headers to the shaders
    "defines": {
        // #define <key> <value>
        "values": {
            "ALPHA_CUTOUT": "0.1"
        },
        // #define flag
        "flags": [
            "NO_OVERLAY"
        ]
    },
    // A list of sampler uniforms to use in the shader
    // There are 12 texture sampler uniforms Sampler0-Sampler11, though usually only Sampler0 is supplied
    // Additionally, there are dynamic '*Sampler' for post effect shaders which are bound to read the specified targets or 'minecraft:main'
    "samplers": [
        { "name": "Sampler0" }
    ],
    // A list of uniforms that can be accessed within the shader
    // A list of available uniforms can be found in CompiledShaderProgram#setUniforms
    "uniforms": [
        { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
        { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
        { "name": "ModelOffset", "type": "float", "count": 3, "values": [ 0.0, 0.0, 0.0 ] },
        { "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] }
    ]
}
// For some assets/my_mod/shaders/my_shader.vsh (Vertex Shader)

// GLSL Version
#version 150

// Imports Mojang GLSL files
// Located in assets/<namespace>/shaders/include/<path>
#moj_import <minecraft:light.glsl>

// Defines are injected (can use 'ALPHA_CUTOUT' and 'NO_OVERLAY')

// Defined by the VertexFormat passed into the ShaderProgram below
in vec3 Position; // vec3 float
in vec4 Color; // vec4 unsigned byte (0-255)

// Samplers defined by the JSON
uniform sampler2D Sampler0;

// Uniforms provided by the JSON
uniform mat4 ModelViewMat;
uniform mat4 ProjMat;
uniform vec3 ModelOffset;

// Values to output to the fragment shader
out float vertexDistance;
out vec4 vertexColor;
out vec2 texCoord0;

void main() {
    // Out values should be set here
}
// For some assets/my_mod/shaders/my_shader.fsh (Fragment Shader)

// GLSL Version
#version 150

// Imports Mojang GLSL files
// Located in assets/<namespace>/shaders/include/<path>
#moj_import <minecraft:fog.glsl>

// Defines are injected (can use 'ALPHA_CUTOUT' and 'NO_OVERLAY')

// Defined by the output of the vertex shader above 
in float vertexDistance;
in vec4 vertexColor;
in vec2 texCoord0;

// Samplers defined by the JSON
uniform sampler2D Sampler0;

// Uniforms provided by the JSON
uniform vec4 ColorModulator;

// Values to output to the framebuffer (the color of the pixel)
out vec4 fragColor;

void main() {
    // Out values should be set here
}

On the code side, shaders are stored internally as either a ShaderProgram or a CompiledShaderProgram. ShaderProgram represents the identifier, while the CompiledShaderProgram represents the shader itself to run. Both are linked together through the ShaderManager.

Shader programs are compiled dynamically unless specified as a core shader. This is done by registering the ShaderProgram to CoreShaders#PROGRAMS.

// List<ShaderProgram> PROGRAMS access
ShaderProgram MY_SHADER = new ShaderProgram(
    // Points to assets/my_mod/shaders/my_shader.json
    ResourceLocation.fromNamespaceAndPath('my_mod', 'my_shader'),
    // Passed in vertex format used by the shader
    DefaultVertexFormat.POSITION_COLOR,
    // Lists the '#define' values and flags
    // Value: '#define <key> <value>'
    // Flag: '#define <flag>'
    ShaderDefines.EMPTY
)

The shader programs are then set by calling RenderSystem#setShader with the ShaderProgram in question. In fact, all references to GameRenderer#get*Shader should be replaced with a ShaderProgram reference.

// In some rendering method
RenderSystem.setShader(MY_SHADER);

// Creating a new ShaderStateShard for a RenderType
ShaderStateShard MY_SHARD = new ShaderStateShard(MY_SHADER);
  • com.mojang.blaze3d.ProjectionType - An enum which holds the logic for how a projection matrix should be rendered.
  • com.mojang.blaze3d.buffers
    • BufferType - An enum that specifies the GL target buffer type.
    • GpuBuffer - A wrapper around the GL buffer calls for handling the rendering of the screen.
    • GpuFence - A handle for managing the sync status of the GPU fence.
  • com.mojang.blaze3d.platform.GlStateManager
    • glShaderSource now takes in a String rather than a List<String>
    • _glMapBufferRange - Delegates to GL30#glMapBufferRange.
    • _glFenceSync - Delegates to GL32#glFenceSync.
    • _glClientWaitSync - Delegates to GL32#glClientWaitSync.
    • _glDeleteSync - Delegates to GL32#glDeleteSync.
    • _glBuffserSubData - Delegates to GL15#glBufferSubData.
  • com.mojang.blaze3d.preprocessor.GlslPreprocessor#injectDefines - Injects any defined sources to the top of a loaded .*sh file.
  • com.mojang.blaze3d.shaders
    • BlendMode, Effect, EffectProgram, Program, ProgramManager, Shader has been bundled into CompiledShader
    • Unform no longer takes in a Shader
      • glGetAttribLocation is removed
      • glBindAttribLocation -> VertexFormat#bindAttributes
      • setFromConfig - Sets the uniform parameters given the values and count of another uniform configuration.
  • com.mojang.blaze3d.systems.RenderSystem
    • setShader now takes in the CompiledShaderProgram, or ShaderProgram
    • clearShader - Clears the current system shader.
    • runAsFancy is removed, handled internally by LevelRenderer#getTransparencyChain
    • setProjectionMatrix now takes in a ProjectionType than just the VertexSorting
    • getVertexSorting -> getProjectionType; not one-to-one, but the VertexSorting is accessible on the ProjectionType
  • com.mojang.blaze3d.vertex.VertexBuffer
    • drawWithShader will now noop when passing in a null CompiledShaderProgram
    • $Usage -> com.mojang.blaze3d.buffers.BufferUsage
  • net.minecraft.client.Minecraft#getShaderManager - Returns the manager that loads all the shaders and post effects.
  • net.minecract.client.renderer
    • EffectInstance class is removed, replaced by CompiledShaderProgram in most cases
    • GameRenderer
      • get*Shader -> CoreShaders#*
      • shutdownEffect -> clearPostEffect
      • createReloadListener -> ShaderManager
      • currentEffect -> currentPostEffect
    • ItemBlockRenderTypes#getRenderType no longer takes in a boolean indicating whether to use the translucent render type
    • ShaderInstance -> CompiledShaderProgram
      • CHUNK_OFFSET -> MODEL_OFFSET
        • JSON shaders: ChunkOffset -> ModelOffset
      • getUniformConfig - Returns the configuration of a uniform given its name.
    • LevelRenderer#graphicsChanged is removed, handled internally by LevelRenderer#getTransparencyChain
    • PostChainConfig - A configuration that represents how a post effect shader JSON is constructed.
    • PostPass now takes in the ResourceLocation representing the output target instead of the in and out RenderTargets or the boolean filter mode, the CompiledShaderProgram to use instead of the ResourceProvider, and a list of uniforms for the shader to consume
      • No longer AutoCloseable
      • addToFrame no longer takes in the float time
      • getEffect -> getShader
      • addAuxAsset -> addInput
      • process -> addToFrame
      • $Input - Represents an input of the post effect shader.
      • $TargetInput - An input from a RenderTarget.
      • $TextureInput - An input from a texture.
    • PostChain constructor is now created via load
      • No longer AutoCloseable
      • MAIN_RENDER_TARGET is now public
      • getName is removed, replaced with ShaderProgram#configId
      • process no longer takes in the DeltaTracker
      • $TargetBundle - Handles the getting and replacement of resource handles within the chain.
    • RenderType
      • entityTranslucentCull, entityGlintDirect is removed
      • armorTranslucent - A render type which renders armor that can have a translucent texture.
    • ShaderDefines - The defined values and flags used by the shader as constants.
    • ShaderManager - The resource listener that loads the shaders.
    • ShaderProgram - An identifier for a shader.
    • ShaderProgramConfig - The definition of the program shader JSON.
    • Sheets#translucentCullBlockSheet is removed
    • SkyRenderer now implements AutoCloseable
  • net.minecraft.client.renderer.entity.ItemRenderer
    • getFoilBufferDirect is removed, replaced by getFoilBuffer
    • ITEM_COUNT_BLIT_OFFSET -> ITEM_DECORATION_BLIT_OFFSET

Entity Render States

Entity models and renderers have been more or less completely reworked due to the addition of EntityRenderStates. EntityRenderStates are essentially data object classes that only expose the computed information necessary to render the Entity. For example, a Llama does not need to know what is has in its inventory, just that it has a chest to render in the layer.

To start, you need to choose an EntityRenderState to use, or create one using a subclass if you need additional information passed to the renderer. The most common states to subclass is either EntityRenderState or LivingEntityRenderState for living entities. These fields should be mutable, as the state class is created only once for a renderer.

// Assuming MyEntity extends LivingEntity
public class MyEntityRenderState extends LivingEntityRenderState {
    // An example of a field
    boolean hasExampleData;
}

From there, you create the EntityModel that will render your Entity. The EntityModel has a generic that takes in the EntityRenderState along with taking in the ModelPart root, and optionally the RenderType factory as part of its super. The are no methods to implement by default; however, if you need to setup any kind of model movement, you will need to overrride setupAnim which modifies the ModelPart’s mutable fields using the render state. If your model does not have any animation, then a Model$Simple implementation can be used instead. This does not need anything implemented.

public class MyEntityModel extends EntityModel<MyEntityRenderState> {

    public MyEntityModel(ModelPart root) {
        super(root);
        // ...
    }

    @Override
    public void setupAnim(MyEntityRenderState state) {
        // Calls resetPose and whatever other transformations done by superclasses
        super.setupAnim(state); 

        // Perform transformations to model parts here
    }
}

EntityModel also has three final methods from the Model subclass: root, which grabs the root ModelPart; allParts, which returns a list of all ModelParts flattened; and resetPose, which returns the ModelPart to their default state.

LayerDefinitions, MeshDefinitions, PartDefinitions, and CubeDeformations remain unchanged in their implementation and construction for the ModelLayerLocation -> LayerDefinition map in LayerDefinitions.

What about model transformations? For example, having a baby version of the entity, or where the model switches out altogether? In those cases, a separate layer definition is registered for each. For example, a Llama would have a model layer for the main Llama model, the baby model, the decor for both the adult and baby, and finally one for the spit. Since models are generally similar to one another with only a slight transformation, a new method was added to LayerDefinition to take in a MeshTransformer. MeshTransformers are basically unary operators on the MeshDefinition. For baby models, a BabyModelTransform mesh transformer is provided, which can be applied via LayerDefinition#apply.

public class MyEntityModel extends EntityModel<MyEntityRenderState> {
    public static final MeshTransformer BABY_TRANSFORMS = ...;

    public static LayerDefinition create() {
        // ...
    }
}

// Wherever the model layers are registered
ModelLayerLocation MY_ENTITY = layers.register("examplemod:my_entity");
ModelLayerLocation MY_ENTITY_BABY = layers.register("examplemod:my_entity_baby");

// Wherever the layer definitions are registered
defns.register(MY_ENTITY, MyEntityModel.create());
defns.register(MY_ENTITY_BABY, MyEntityModel.create().apply(MyEntityModel.BABY_TRANSFORMS));

But how does the model know what render state to use? That’s where the EntityRenderer comes in. The EntityRenderer has two generics: the type of the Entity, and the type of the EntityRenderState. The EntityRenderer takes in a Context object, similar to before. Additionally, getTextureLocation needs to be implemented, though this time it takes in the render state instead of the entity. The new methods to implement/override are createRenderState and extractRenderState. createRenderState constructs the default render state object. extractRenderState, meanwhile, populates the render state for the current entity being rendered. extractRenderState will need to be overridden if you are not using an existing render state class.

Of course, there are also subclasses of the EntityRenderer. First, there is LivingEntityRenderer. This has an additional generic of the EntityModel being rendered, and takes that value in the constructor along with the shadow radius. This renderer also accepts RenderLayers, which largely remain unchanged if you access the previous arguments through the render state. Then, there is the MobRenderer, which is what all entities extend. Finally, there is AgeableMobRenderer, which takes in two models - the adult and the baby - and decides which to render dependent on LivingEntityRenderState#isBaby. AgeableMobRenderer should be used with BabyModelTransform if the entity has a baby form. Otherwise, you will most likely use MobRenderer or EntityRenderer.

public class MyEntityRenderer extends AgeableMobRenderer<MyEntity, MyEntityRenderState, MyEntityModel> {

    public MyEntityRenderer(EntityRendererProvider.Context ctx) {
        super(
            ctx,
            new MyEntityModel(ctx.bakeLayer(MY_ENTITY)), // Adult model
            new MyEntityModel(ctx.bakeLayer(MY_ENTITY_BABY)), // Baby model
            0.7f // Shadow radius
        );

        // ...
    }

    @Override
    public ResourceLocation getTextureLocation(MyEntityRenderState state) {
        // Return entity texture here
    }

    @Override
    public MyEntityRenderState createRenderState() {
        // Constructs the reusable state
        return new MyEntityRenderState();
    }

    @Override
    public void extractRenderState(MyEntity entity, MyEntityRenderState state, float partialTick) {
        // Sets the living entity and entity render state info
        super.extractRenderState(entity, state, partialTick);
        // Set our own variables
        state.hasExampleData = entity.hasExampleData();
    }
}

// Wherever the entity renderers are registered
renderers.register(MyEntityTypes.MY_ENTITY, MyEntityRenderer::new);
  • net.minecraft.client.model
    • AbstractBoatModel - A model that assumes there is a left_paddle and right_paddle that is animated according to the boat’s rowing time.
    • AgeableHierarchicalModel, ColorableAgeableListModel, AgeableListModel -> BabyModelTransform
    • AnimationUtils
      • animateCrossbowCharge now takes in a float representing the charge duration and int representing the use ticks instead of a LivingEntity
      • swingWeaponDown now takes in a HumanoidArm instead of a Mob
    • BabyModelTransform - A mesh transformer that applies a baby scaled form of the model.
    • BoatModel
      • createPartsBuilder is removed
      • createChildren -> addCommonParts, now private
      • createBodyModel -> createBoatModel, createChestBoatModel
      • waterPatch -> createWaterPatch
      • parts is removed
    • ChestBoatModel -> BoatModel#createChestBoatModel
    • ChestedHorseModel class is removed and now purely lives in LlamaModel and DonkeyModel
    • ChestRaftModel -> RaftModel#createChestRaftModel
    • ColorableHierarchicalModel is now stored in the individual EntityRenderState
    • EntityModel
      • The generic now takes in a EntityRenderState
      • setupAnim only takes in the EntityRenderState generic
      • prepareMobModel is removed
      • copyPropertiesTo is removed, still exists in HumanoidModel
    • HierarchicalModel class is removed
    • HumanoidModel#rotLerpRad -> Mth#rotLerpRad
    • ListModel class is removed
    • Model
      • renderToBuffer is now final
      • root - Returns the root ModelPart.
      • getAnyDescendantWithName - Returns the first descendant of the root that has the specified name.
      • animate - Give the current state and definition of the aninmation, transforms the model between the current time and the maximum time to play the animation for.
      • animateWalk - Animates the walking cycle of the model.
      • applyStatic - Applies an immediate animation to the specified state.
      • $Simple - Constructs a simple model that has no additional animation.
    • ModelUtils class is removed
    • ParrotModel#getState -> getPose, now public
    • PlayerModel no longer has a generic
      • renderEars -> PlayerEarsModel
      • renderCape -> PlayerCapeModel
      • getRandomModelPart -> getRandomBodyPart
      • getArmPose - Returns the arm pose of the player given its render state.
    • RaftModel#createBodyModel -> createRaftModel
    • WardenModel#getTendrilsLayerModelParts, getHeartLayerModelParts, getBioluminescentLayerModelParts, getPulsatingSpotsLayerModelParts now take in the WardenRenderState
    • WaterPatchModel -> BoatModel#createWaterPatch and Model$Simple
  • net.minecraft.client.model.geom
    • ModelLayerLocation is now a record
    • ModelLayers
      • createRaftModelName, createChestRaftModelName is removed
      • createSignModelName -> createStandingSignModelName, createWallSignModelName
      • createBoatModelName, createChestBoatModelName is removed
    • ModelPart
      • rotateBy - Rotates the part using the given Quaternionf.
      • $Cube#polygons, $Polygon, $Vertex is now public
    • PartPose is now a record
      • translated - Translates a pose.
      • withScale, scaled - Scales a pose.
  • net.minecraft.client.model.geom.builders
    • LayerDefinition#apply - Applies a mesh transformer to the definition and returns a new one.
    • MeshDefinition#transformed - Applies a transformation to the root pose and returns a new one.
    • MeshTransformer - Transforms an existing MeshDefinition into a given form.
    • PartDefinition
      • addOrReplaceChild now has an overload that takes in a PartDefinition
      • clearChild - Removes the child from the part definition.
      • getChildren - Gets all the children of the current part.
      • transformed - Applies a transformation to the current pose and returns a new one.
  • net.minecraft.client.renderer.entity
    • AbstractBoatRenderer - A boat renderer that contains methods for the boat model and any additions to the boat itself.
    • AgeableMobRenderer - A mob renderer that takes in the baby and adult model.
    • BoatRenderer now takes in a ModelLayerLocation instead of a boolean
    • EntityRenderDispatcher now takes in a MapRenderer
      • render no longer takes in the entity Y rotation
    • EntityRenderer now takes in a generic for the EntityRenderState
      • getRenderOffset only takes in the EntityRenderState
      • getBoundingBoxForCulling - Returns the bounding box of the entity to determine whether to cull or not.
      • affectedByCulling - Returns whether the entity can be culled.
      • render only takes in the render state, along with the stack, buffer source, and packet light
      • shouldShowName now takes in a double for the camera squared distance from the entity
      • getTextureLocation is removed, being moved to the classes where it is used, like LivingEntityRenderer
        • Subsequent implementations of getTextureLocation may be protected or private
      • renderNameTag now takes in the render state instead of the entity and removes the partial tick float
      • getNameTag - Gets the name tag from the entity.
      • getShadowRadius now takes in the render state instead of the entity
      • createRenderState - Creates the render state object.
      • extractRenderState - Reads any data from the entity to the render state.
    • EntityRendererProvider$Context takes in the MapRenderer instead of the ItemInHandRenderer
    • LivingRenderer
      • isShaking now takes in the render state instead of the entity
      • setupRotations now takes in the render state instead of the entity
      • getAttackAnim, getBob are now within the render state
      • getFlipDegrees no longer takes in the entity
      • getWhiteOverlayProgress now takes in the render state instead of the entity and no longer takes in the entity Y rotation
      • scale now takes in the render state instead of the entity and no longer takes in the entity Y rotation
      • shouldShowName now takes in a double representing the squared distance to the camera
      • getShadowRadius now takes in the render state instead of the entity
    • RaftRenderer - A raft renderer that implements the AbstractBoatRenderer.
    • RenderLayerParent#getTextureLocation is removed
  • net.minecraft.client.renderer.entity.layers
    • EnergySwirlLayer#isPowered - Returns whether the energy is powered.
    • CustomHeadLayer and #translateToHead takes in a CustomHeadLayer$Transforms instead of a scaling information hardcoding the transform
    • PlayerItemInHandRenderer takes in an ItemRenderer instead of a ItemInHandRenderer
    • RenderLayer takes in an EntityRenderState generic instead of an Entity generic
      • coloredCutoutModelCopyLayerRender takes in a single EntityModel with the state info bundled into the render state
      • renderColoredCutoutModel takes in non-generic forms of the rendering information, assuming a LivingEntityRenderState
      • getTextureLocation is removed, instead being passed directly into the appropriate location
      • render now takes in the render state instead of the entity and parameter information
    • SaddleLayer has a constructor to take in a baby model.
    • SheepFurLayer -> SheepWoolLayer
    • StuckInBodyLayer now takes in the model to apply the stuck objects to, the texture of the stuck objects, and the placement style of the objects
      • numStuck now takes in the render state instead of the entity
      • renderStuckItem is now private
    • WardenEmissiveLayer -> LivingEntityEmissiveLayer, a more generalized implementation
  • net.minecraft.client.renderer.entity.player.PlayerRenderer
    • renderRightHand, renderLeftHand now take in a ResourceLocation instead of the AbstractClientPlayer and a boolean whether to render the left and/or right sleeve
    • setupRotations now takes in the render state instead of the entity and parameter information
  • net.minecraft.world.entity
    • AnimationState#copyFrom - Copies the animation state from another state.
    • Entity
      • noCulling -> EntityRenderer#affectedByCulling
      • getBoundingBoxForCulling -> EntityRenderer#getBoundingBoxForCulling
    • LerpingModel class is removed
    • PowerableMob class is removed

Model Baking

UnbakedModels now have a different method to resolve any dependencies. Instead of getting the dependencies and resolving the parents, this is now done through a single method called resolveDependencies. This method takes in the Resolver. The Resolver is responsible for getting the UnbakedModel for the ResourceLocation.

// For some UnbakedModel instance
public class MyUnbakedModel implements UnbakedModel {

    @Nullable
    protected ResourceLocation parentLocation;
    @Nullable
    protected UnbakedModel parent;
    private final List<ItemOverride> overrides;

    // ...

    @Override
    public void resolveDependencies(UnbakedModel.Resolver resolver) {
        // Get parent model for delegate resolution
        if (this.parentLocation != null) {
            this.parent = resolver.resolve(this.parentLocation);
        }
    }
}
  • net.minecraft.client.renderer.block
    • BlockModel#getDependencies, resolveParents -> resolveDependencies
    • BlockModelDefintion now takes in a MultiPart$Definition, no List<BlockModelDefinition> constructor exists
      • fromStream, fromJsonElement no longer take in a $Context
      • getVariants is removed
      • isMultiPart is removed
      • instantiate -> MultiPart$Definition#instantiate
    • MultiVariant is now a record
    • UnbakedBlockStateModel - An interface that represents a block state model, contains a single method to group states together with the same model.
    • VariantSelector - A utility for constructing the state definitions from the model descriptor.
  • net.minecraft.client.renderer.block.model
    • BlockModel
      • MISSING_MATERIAL - The material of the missing block texture.
      • bake no longer takes in the ModelBaker and BlockModel
      • $LoopException class is removed
  • net.minecraft.client.renderer.block.model.multipart.MultiPart now implements UnbakedBlockStateModel
    • getSelectors -> $Definition#selectors
    • getMultiVariants -> $Definition#getMultiVariants
  • net.minecraft.client.resources.model
    • BakedModel#getOverrides -> overrides, method is defaulted to an empty override
    • BlockStateModelLoader only takes in the missing unbaked model
      • loadAllBlockStates is removed
      • definitionLocationToBlockMapper - Gets the state definition from a given resource location
      • loadBlockStateDefinitions -> loadBlockStateDefinitionStack
      • getModelGroups -> ModelGroupCollector
      • $LoadedJson -> $LoadedBlockModelDefinition
      • $LoadedModel is now public
      • $LoadedModels - A record which maps a model location to a loaded model.
    • BuiltInModel no longer takes in the ItemOverrides
    • DelegateBakedModel - A utility implementation that delegates all logic to the supplied BakedModel
    • Material#buffer takes in another boolean that handles whether to apply the glint
    • MissingBlockModel - The missing model for a block.
    • ModelBaker#getModel is removed, implementation in ModelBakery$ModelBakerImpl is private
    • ModelBakery only takes in the top models, all unbacked models, and the missing model
      • BUILTIN_SLASH -> SpecialModels#builtinModelId
      • BUILTIN_SLASH_GENERATED -> SpecialModels#BUILTIN_GENERATED
      • BUILTIN_BLOCK_ENTITY -> SpecialModels#BUILTIN_BLOCK_ENTITY
      • MISSING_MODEL_LOCATION -> MissingBlockModel#LOCATION
      • MISSING_MODEL_VARIANT -> MissingBlockModel#VARIANT
      • GENERATION_MARKER -> SpecialModels#GENERATED_MARKER
      • BLOCK_ENTITY_MARKER -> SpecialModels#BLOCK_ENTITY_MARKER
      • getModelGroups -> ModelGroupCollector
    • ModelDiscovery - A loader for block and item models, such as how to resolve them when reading.
    • ModelGroupCollector - A blockstate collector meant to map states to their associated block models.
    • ModelResourceLocation#vanilla is removed
    • MultiPartBakedModel fields are now obtained from the first model in the selector and are private
      • $Builder class is removed, replaced with $Selector
    • SimpleBakedModel, SimpleBakedModel$Builder no longer takes in the ItemOverrides
    • SpecialModels - A utility for builtin models.
    • UnbakedModel
      • getDependencies, resolveParents -> resolveDependencies
      • bake is no longer nullable
      • $Resolver - Determines how the unbaked model should be loaded when on top or on override.
    • WeightedBakedModel now takes in a SimpleWeightedRandomList rather than a list of WeightedEntrys

Equipments and Items, Models and All

Equipments and Items have had a major overhaul, most of which is spread throughout this documentation. This is some of the core change which, while they are important, do not deserve more than a cursory explanation due to their ease of change.

Item Names and Models

The item name and model is now set directly within the properties using the ITEM_NAME and ITEM_MODEL data components, respectively. By default, this will use the same name and model location as previously, but these can be set via Item$Properties#overrideDescription and #overrideModel. overrideDescription takes in the translation key to use. There is also useBlockDescriptionPrefix and useItemDescriptionPrefix to change it to the default block and item translation keys, respectively. overrideModel takes in the relative ResourceLocation of the model JSON. For example, a value of examplemod:example_item will map to a ModelResourceLocation of examplemod:example_item#inventory. This is intended to link to the model JSON at assets/examplemod/models/item/example_item.json.

There is a slight quirk to item models. The same key can also point to assets/examplemod/models/example_item.json if the modder decides to for a special model to load at that location under the inventory variant. So, it is recommended to avoid having model names with the same name in the root models and models/item subdirectory.

Enchantable, Repairable Items

The enchantment value and repair item checks are being replaced with data components: DataComponents#ENCHANTABLE and DataComponents#REPAIRABLE, respectively. These can be set via the Item$Properties#enchantable and #repairable. As a result, Item#getEnchantmentValue and isValidRepairItem are removed.

Elytras -> Gliders

Any item can act similarly to an elytra if they have the DataComponents#GLIDER value equipped. This essentially functions as a flag to indicate that the item can be used to glide. This works only if the item also has a DataComponents#EQUIPPABLE entry.

new Item(
    new Item.Properties()
        .component(DataComponents.GLIDER, Unit.INSTANCE) // Sets as a glider
        .component(DataComponents.EQUIPPABLE, /*...*/) // Determines the slot to check whether it can be used
);

Tools, via Tool Materials

Tiers within items have been replaced with ToolMaterial, which better handles the creation of tools and swords without having to implement each method manually. ToolMaterial takes in the same arguments as Tier, just as parameters to a single constructor rather than as implementable methods. From there, the ToolMaterial is passed to the DiggerItem subtypes, along with two floats representing the attack damage and attack speed. Interally, ToolMaterial#apply*Properties is called, which applies the ToolMaterial info to the DataComponents#TOOL and the attributes from the given floats.

// Some tool material
public static final ToolMaterial WOOD = new ToolMaterial(
    BlockTags.INCORRECT_FOR_WOODEN_TOOL, // Tier#getIncorrectBlocksForDrops
    59, // Tier#getUses
    2.0F, // Tier#getSpeed
    0.0F, // Tier#getAttackDamageBonus
    15, // Tier#getEnchantmentValue
    ItemTags.WOODEN_TOOL_MATERIALS // Tier#getRepairIngredient
);

// When constructing the digger item subtype
new PickaxeItem(
    WOOD, // Tool material
    1.0f, // Attack damage
    -2.8f, // Attack speed
    new Item.Properties()
)

Armor Materials, Equipment, and Model (Textures)

This is, by far, the largest change outside of consumables to items. ArmorMaterials have effectively been made obsolete, as almost all of the logic is handled within data components, and attached to some resource pack JSON to load the associated textures. It is annoyingly complicated to understand at first glance, but is rather intuitive once you are familiar with the process.

ArmorMaterial

ArmorMaterial is essentially a record that converts a list of properties to their proper location on the data components, NOT a registry object. This is done by passing in the item properties and an additional setting to either #humanoidProperties or #animalProperties. These settings should be familiar, as they remained unchanged from the previous version, the only difference is that they now specify a ‘model id’, which we will go into below. The armor material is used in conjunction with the ArmorType: an enum which defines the equipment slot the armor is placed into, the unit durability of each armor type, and the name (which is only used to construcct the attribute modifier id).

ArmorMaterial exampleArmorMaterial = new ArmorMaterial(
    15, // The scalar durability to multiply the armor type against
    // A map of ArmorType -> half armor bars to apply to the entity ARMOR attribute
    // Should be set for all ArmorTypes
    Util.make(new EnumMap<>(ArmorType.class), map -> {
        map.put(ArmorType.BOOTS, 2);
        map.put(ArmorType.LEGGINGS, 5);
        map.put(ArmorType.CHESTPLATE, 6);
        map.put(ArmorType.HELMET, 2);
        map.put(ArmorType.BODY, 5);
    },
    25, // The enchantment value of the armor
    SoundEvents.ARMOR_EQUIP_IRON, // The holder wrapped sound event on what sound to make when the item is equipped
    0f, // The ARMOR_TOUGHNESS attribute value
    2f, // The KNOCKBACK_RESISTANCE attribute value,
    ItemTags.REPAIRS_DIAMOND_ARMOR, // An item tag representing the items that can repair this armor
    // The relative location of the EquipmentModel JSON
    // Points to assets/examplemod/models/equipment/example_armor_material.json
    ResourceLocation.fromNamespaceAndPath("examplemod", "example_armor_material")
)

With the ArmorMaterial, this is either applied to the item properties by calling humanoidProperties, to apply the armor to a specific ArmorType; or animalProperties to apply the armor to the BODY and only allow specific entities to wear them.

Does this mean that ArmorItem and AnimalArmorItem are effectively pointless? For AnimalArmorItem, this can be argued. The only thing that AnimalArmorItem does is have a $BodyType parameter, which means that the armor can only be applied to a horse or a wolf, and specifies the item breaking sound. ArmorItem, on the other hand, only has one specific usecase: determining whether the item can be taken off or swapped. This implicity checks the currently wearing armor item to see whether it can’t be taken off (via PREVENT_ARMOR_CHANGE enchantment) and calculating the properties on the replacing armor material so that any hotswaps will only improve their wearer’s armor attribute values.

Let’s go one level deeper.

The Data Components

ArmorMaterial specifies eight data components to apply to item:

  • MAX_DAMAGE - Set to the maximum durability of the item multiplied by the ArmorType unit durability
  • MAX_STACK_SIZE - Set to 1
  • DAMAGE - Set to 0
  • ATTRIBUTE_MODIFIERS - Sets ARMOR and ARMOR_TOUGHNESS attributes, and KNOCKBACK_RESISTANCE when greater than 0
  • ENCHANTABLE - Set to the enchantment value (not set when calling animalProperties)
  • REPAIRABLE - Set to the HolderSet of the tag key representing the repairing ingredients
  • EQUIPPABLE - Sets the slot, equip sound, model id, what entities can wear the item, and whether it is dispensible

Everything but EQUIPPABLE has already been explained above or has been around from a prior version, so this primer will only focus on EQUIPPABLE from now on.

Equippable

Equippable, which used to be an interface, is now a data component that contains how an entity can equip this item and if the equipment should be rendered. Because of this, an item can only be equipped to a single slot. This can be done using the Equippable constructor or through the builder via Equippable#builder.

new Item(
    new Item.Properties()
    .component(DataComponents.EQUIPPABLE, new Equippable(
        EquipmentSlot.HEAD, // The slot the item can be equipped to
        SoundEvents.ARMOR_EQUIP_IRON, // The sound to play when equipping the item
        // The relative location of the EquipmentModel JSON
        // Points to assets/examplemod/models/equipment/example_armor_material.json
        // When set to an empty optional, the item does not attempt to render as equipment
        Optional.of(ResourceLocation.fromNamespaceAndPath("examplemod", "example_armor_material")),
        // The relative location over the texture to overlay on the player screen when wearing
        // Points to assets/examplemod/textures/example_overlay.png
        // When set to an empty optional, does not render on the player screen
        Optional.of(ResourceLocation.withDefaultNamespace("examplemod", "example_overlay")),
        // A HolderSet of entities (direct or tag) that can equip this item
        // When set to an empty optional, any entity can equip this item
        Optional.of(HolderSet.direct(EntityType::builtInRegistryHolder, EntityType.ZOMBIE)),
        // Whether the item can be equipped when dispensed from a dispenser 
        true,
        // Whether the item can be swapped off the player during a quick equip
        false,
        // Whether the item should be damaged when attacked (for equipment typically)
        // Must also be a damageable item
        false
    ))
);

Equipment Models?

So, as mentioned previously, Equippable items, and by extension the ArmorMaterial delegate, can specify a model id to determine how the equipment should render. However, what does this id link to? Well, it points to an EquipmentModel serialized as a JSON within models/equipment of the resource pack. This JSON defines the layers and textures of the equippable item to render. This does NOT specify the model, making the record a misnomer. It is better to think of this as the equipment textures applied to the passed in model.

EquipmentModel functions as a more feature generic version of the previous ArmorMaterial$Layer, which has been removed. Each EquipmentModel is functionally a map of $LayerTypes to a list of $Layer to render.

A $LayerType is an enum representing the layer to render the equipment model as. While these are non-specific, they are implemented and read by specific entity renderer through the layer renderers. For example, HUMANOID is used by the HumanoidArmorLayer to render the head, chest, and feet; so any usage of HUMANOID will be rendered using that system. Another example is WOLF_BODY is used by WolfArmorLayer to render the body armor. As such, if using existing layer types (which is the only scenario unless your mod loader supports enum extensions), make sure that they are compatible with the existing renderers in place.

The $Layer list specifies the texture and dyeable options to use when rendering over the passed in model. The first parameter specifes the texture location, relative to textures/entity/equipment. The second parameter specifies an optional indicating whether the texture can be tinted (stored via the ItemTags#DYEABLE in conjunction with the DYED_COLOR data component). When specified, an optional color can be specified for when the item is not dyed. If empty, the armor will be invisible when not dyed. The final parameter indicates whether it should use the texture provided to the renderer instead, such as when rendering a custom elytra texture for the player.

// In assets/examplemod/models/equipment/example_armor_material.json
{
    // The layer map
    "layers": {
        // The serialized name of the EquipmentModel$LayerType to apply to
        "humanoid": [
            // A list of layers to render in the order provided in the list
            {
                // The relative texture of the layer
                // Points to assets/examplemod/textures/entity/equipment/example.png
                "texture": "examplemod:example",
                // When specified, allows the texture to be tinted the color in DYED_COLOR data component
                // Otherwise, cannot be tinted
                "dyeable": {
                    // An RGB value (always opaque color)
                    // 0x7683DE as decimal
                    // When not specified, set to 0 (meaning transparent or invisible)
                    "color_when_undyed": 7767006
                },
                // When true, uses the texture passed into the layer renderer instead
                "use_player_texture": true
            }
            // ...
        ]
        // ...
    }
}
EquipmentModel.builder()
    .addLayers(EquipmentModel.LayerType.HUMANOID, new EquipmentModel.Layer(
        // The relative texture of the layer
        // Points to assets/examplemod/textures/entity/equipment/example.png
        ResourceLocation.fromNamespaceAndPath("examplemod", "example"),
        // When specified, allows the texture to be tinted the color in DYED_COLOR data component
        // Otherwise, cannot be tinted
        Optional.of(new EquipmentModel.Dyeable(
            // An RGB value (always opaque color)
            // When not specified, set to 0 (meaning transparent or invisible)
            Optional.of(0x7683DE)
        )),
        // When true, uses the texture passed into the layer renderer instead
        true
    )/*, ... */)
    .build();

The equipment model is then rendered by calling EquipmentLayerRenderer#renderLayers in the render function of an EntityRenderer or RenderLayer. EquipementLayerRenderer is passed in as part of the render context via EntityRendererProvider$Context#getEquipmentRenderer.

// In some render method where EquipmentLayerRenderer equipmentLayerRenderer is a field
this.equipmentLayerRenderer.renderLayers(
    // The layer type to render
    EquipmentModel.LayerType.HUMANOID,
    // The model id representing the EquipmentModel JSON
    // This would be set in the `EQUIPPABLE` data component via `model`
    ResourceLocation.fromNamespaceAndPath("examplemod", "example_armor_material"),
    // The model to apply the textures to
    // These are usually separate models from the entity model
    // and are separate ModelLayers linking to a LayerDefinition
    model,
    // The item stack representing the item being rendered as a model
    // This is only used to get the dyeable, foil, and armor trim information
    stack,
    // The stack used to render the model in the correct location
    poseStack,
    // The source of the buffers to get the vertex consumer of the render type
    bufferSource,
    // The packed light texture
    lighting,
    // An absolute path of the texture to render when use_player_texture is true for one of the layer if not null
    ResourceLocation.fromNamespaceAndPath("examplemod", "textures/other_texture.png");
)

Technical Changes to Items

  • net.minecraft.client.Minecraft#getEquipmentModels - Gets the EquipmentModelSet that contains the current equipment model textures.
  • net.minecraft.client.gui.GuiGraphics#renderTooltip, renderComponentTooltip now has a parameter to take in the relative directory of the background and frame textures of the tooltip, or the default if null
  • net.minecraft.client.gui.screens.inventory.tooltip.TooltipRenderUtil#renderTooltipBackground now has a parameter to take in the relative directory of the background and frame textures of the tooltip, or the default if null
  • net.minecraft.client.renderer.block.model
    • ItemOverrides -> BakedOverrides
      • The construct no longer takes in the parent BlockModel
      • resolve -> findOverride, does not take in the fallback model
    • ItemOverride, ItemOverride$Predicate is now a record
      • getPredicates is removed, use predicates
      • getModel -> model
  • net.minecraft.client.renderer.entity
    • EntityRenderDispatcher now takes in the EquipmentModelSet
    • EntityRendererProvider$Context
      • getEquipmentModels - Gets the current equipment textures.
      • getEquipmentRenderer - Gets the renderer for the equipment.
    • ItemRenderer no longer takes in the Minecraft instance and TextureManager
      • TRIDENT_MODEL, SPYGLASS_MODEL is now public
      • TRIDENT_IN_HAND_MODEL, SPYGLASS_IN_HAND_MODEL is removed
      • getItemModelShaper is removed
      • renderBundleWithSelectedItem -> renderBundleItem, not one-to-one
  • net.minecraft.client.renderer.entity.layers
    • CapeLayer now takes in the EquipmentModelSet
    • ElytraLayer -> WingsLayer
      • The constructor now takes in the EquipmentLayerRenderer
    • EquipmentLayerRenderer - A renderer for equipment layers on the provided model.
    • HorseArmorLayer now takes in the EquipmentLayerRenderer
    • HumanoidArmorLayer now teaks in the EquipmentLayerRenderer instead of the ModelManager
      • shouldRender - Returns whether the equippable item should be rendered in the given slot.
    • LlamaDecorLayer now takes in the EquipmentLayerRenderer
    • WolfArmorLayer now takes in the EquipmentLayerRenderer
  • net.minecraft.client.renderer.entity.player.PlayerRenderer#getArmPose is now private, replaced publically with a method that only takes in the HumanoidArm and PlayerRenderState
  • net.minecraft.client.resources.model
    • EquipmentModelSet - A resource listener that loads the EquipmentModels from models/equipment.
    • ItemModel - A model for an item.
  • net.minecraft.core.component.DataComponents
    • ITEM_MODEL - Returns the model of the item. The item/ is stripped, meaning that minecraft:apple points to minecraft/textures/models/item/apple.json.
    • EQUIPPABLE - Indicates that an item is equippable in the given slot. Also contains the model to render for the equipment.
    • GLIDER - Indicates that an item can be used to glide across the air. Must also be used in conjunction with EQUIPPABLE.
    • TOOLTIP_STYLE - Determines the relative location representing how the tooltip should render
  • net.minecraft.core.dispenser.EquipmentDispenseItemBehavior - Handles how equipment is dispensed from a dispenser.
  • net.minecraft.core.registries.BuiltInRegistries#, Registries#ARMOR_MATERIAL is no longer a registry, handled purely through data components
  • net.minecraft.world.entity
    • EquipmentSlot#getFilterFlag -> getId
      • Also a method getFilterBit for converting the ID to a bit mask
    • LivingEntity
      • canContinueToGlide -> canGlide, no longer takes in the ItemStack
      • canTakeItem replaced by DataComponents#EQUIPPABLE
      • canEquipWithDispenser - Returns whether the stack can be equipped when spat from a dispenser.
      • canDispenserEquipIntoSlot - An entity override that specifies whether a dispenser can put eequipment into a given slot.
      • isEquippableInSlot - Returns whether the stack can be equipped in the given slot.
      • canGlideUsing - Whether the entity can glide with the stack in the provided slot.
    • Mob
      • canReplaceCurrentItem now takes in the EquipmentSlot
      • isBodyArmorItem replaced by DataComponents#EQUIPPABLE
  • net.minecraft.world.entity.animal.horse
    • Horse#isBodyArmorItem replaced by DataComponents#EQUIPPABLE
    • Llama#isBodyArmorItem, getSwag replaced by DataComponents#EQUIPPABLE
  • net.minecraft.world.item
    • AnimalArmorItem no longer extends ArmorItem
      • The constructor no longer takes in a boolean indicating the overlay texture, as that is now part of the EquipmentModel
      • The constructor can take in an optional Holder<SoundEvent> of the equip sound
      • The constructor can take in a boolean representing whether the armor should be damaged if the entity is hurt
      • $BodyType no takes in the allowed entities to wear the armor rather than the path factory to the texture
    • ArmorItem is no longer equipable
      • Basically functions as an item class where its only remaining usage is to prevent armor change when enchanted and get the associated attributes
      • $Type -> ArmorType
    • ArmorMaterial -> .equipment.ArmorMaterial
      • Bascially a dummy record to easily handle applying the associated data components (MAX_DAMAGE, ATTRIBUTE_MODIFIERS, ENCHANTABLE, EQUIPPABLE, REPAIRABLE)
    • ArmorMaterials -> .equipment.ArmorMaterials
    • BookItem, EnchantedBookItem -> DataComponents#WRITTEN_BOOK_CONTENT
    • BundleItem now takes in a ResourceLocation for the model rather than just strings
      • $Mutable#setSelectedItem -> toggleSelectedItem
    • ComplexItem class is removed
    • ElytraItem class is removed, now just and item with DataComponents#GLIDER
    • Equippable -> .equipment.Equippable, now a record which defines how an item can be equipped
    • FoodOnAStackItem parameter order has been switched
    • InstrumentItem parameter order has been switched
    • Item
      • descriptionId is now protected
      • getDescription -> getName
      • getOrCreateDescriptionId is removed
      • getDescriptionId(ItemStack) -> DataComponents#ITEM_NAME
      • isEnchantable, getEnchantmentValue is removed
      • isValidRepairItem is removed
      • getDefaultAttributeModifiers is removed
      • getDamageSource - Returns the damage source this item makes against the LivingEntity
      • isComplex is removed
      • $Properties
        • equippable - Sets an equippable component, defining how an item can be equipped
        • equippableUnswappable - Sets an equippable commponent that cannot be swapped via a key shortcut.
        • overrideDescription - Sets the translation key of the item.
        • overrideModel - Sets the model resource location.
      • getCraftingRemainingItem, hasCraftingRemainingItem -> getCraftingRemainder
    • ItemNameBlockItem class is removed, just a normal Item useItemDescriptionPrefix as a property
    • ItemStack
      • ITEM_NON_AIR_CODEC -> Item#CODEC
      • isValidRepairItem - Returns whether the stack can be repaired by this stack.
      • nextDamageWillBreak - Checks if the next damage taken with break the item.
      • getDescriptionId -> getItemName, not one-to-one, as now it returns the full component
    • ShieldItem no longer implements Equippable, passed in through DataComponents#EQUIPPABLE
    • SignItem parameter order has been switched
    • SmithingTemplateItem parameter order has been swtiched, removes FeatureFlags
    • StandingAndWallBlockItem paramter order has been switched
    • AxeItem now takes in two floats representing the attack damage and attack speed
    • DiggerItem now takes in two floats representing the attack damage and attack speed
      • createAttributes -> ToolMaterial#applyToolProperties
    • HoeItem now takes in two floats representing the attack damage and attack speed
    • PickaxeItem now takes in two floats representing the attack damage and attack speed
    • ShovelItem now takes in two floats representing the attack damage and attack speed
    • SwordItem now takes in two floats representing the attack damage and attack speed
      • createAttributes -> ToolMaterial#applySwordProperties
    • Tier -> ToolMaterial
    • TieredItem class is removed
    • Tiers constants are stored on ToolMaterial
  • net.minecraft.world.item.alchemy.Potion name is now required - getName -> name, not one-to-one as this is stored directly on the potion without any other processing
  • net.minecraft.world.item.armortrim.* -> .equipment.trim.*
  • net.minecraft.world.item.component
    • Tool methods that return Tool$Rule now only take the HolderSet of blocks and not a list or tag key
    • DamageResistant - A component that holds a tag of damage types the item is resistant to as an entity or being worn
  • net.minecraft.world.item.enchantment
    • Enchantable - The data component object for the item’s enchantment value.
    • Repairable - The data component object for the items that can repair this item.
  • net.minecraft.world.level.block
    • AbstractSkullBlock no longer implements Equippable
    • EquipableCarvedPumpkinBlock class is removed, as replaced by DataComponents#EQUIPPABLE
    • WoolCarpetBlock no longer implements Equippable

Interaction Results

InteracitonResults have been completely modified to encompass everything to one series of sealed implementations. The new implementation of InteractionResult combines both InteractionResultHolder and ItemInteractionResult, meaning that all uses have also been replcaed.

InteractionResult is now an interface with four implementations depending on the result type. First there is $Pass, which indicates that the interaction check should be passed to the next object in the call stack. $Fail, when used for items and blocks, prevents anything further in the call stack for executing. For entities, this is ignored. Finally, $TryEmptyHandInteraction tells the call stack to try to apply the click with no item in the hand, specifically for item-block interactions.

There is also $Success, which indicates that the interaction was successful and can be consumed. A success specifies two pieces of information: the $SwingSource, which indicates where the source of the swing originated from (CLIENT or SERVER) or NONE if not specified, and $ItemContext that handles whether there was an iteraction with the item in the hand, and what the item was transformed to.

None of the objects should be directly initialized. The implementations are handled through six constants on the InteractionResult interface:

  • SUCCESS - A $Success object that swings the hand on the client.
  • SUCCESS_SERVER - A $Success object that swings the hand on the server.
  • CONSUME - A $Success object that does not swing the hand.
  • FAIL - A $Fail object.
  • PASS - A $Pass object.
  • TRY_WITH_EMPTY_HAND - A $TryEmptyHandInteraction object.
// For some method that returns an InteractionResult
return InteractionResult.PASS;

For success objects, if the item interaction should transform the held stack, then you call $Success#heldItemTransformedTo, or $Success#withoutItem if no item was used for the interaction.

// For some method that returns an InteractionResult
return InteractionResult.SUCCESS.heldItemTransformedTo(new ItemStack(Items.APPLE));

// Or
return InteractionResult.SUCCESS.withoutItem();
  • net.minecraft.core.cauldron.CauldronInteraction
    • interact now returns an InteractionResult
    • fillBucket, emptyBucket now returns an InteractionResult
  • net.minecraft.world
    • InteractionResultHolder, ItemInteractionResult -> InteractionResult
  • net.minecraft.world.item
    • Equipable#swapWithEquipmentSlot now returns an InteractionResult
    • Item#use, ItemStack#use now returns an InteractionResult
    • ItemUtils#startUsingInstantly now returns an InteractionResult
    • JukeboxPlayable#tryInsertIntoJukebox now returns an InteractionResult
  • net.minecraft.world.level.block.state.BlockBehaviour#useItemOn, $BlockStateBase#useItemOn now returns an InteractionResult

Instruments, the Datapack Edition

Instruments (not NoteBlockInstruments) are now a datapack registry, meaning they must be defined in JSON or datagenned.

// In data/examplemod/instrument/example_instrument.json
{
    // The registry name of the sound event
    "sound_event": "minecraft:entity.arrow.hit",
    // How many seconds the instrument is used for
    "use_duration": 7.0,
    // The block range, where each block is 16 units
    "range": 256.0,
    // The description of the instrument
    "description": {
        "translate": "instrument.examplemod.example_instrument"
    },
}
// For some RegistrySetBuilder builder
builder.add(Registries.INSTRUMENT, bootstrap -> {
    bootstrap.register(
        ResourceKey.create(Registries.INSTRUMENT, ResourceLocation.fromNamespaceAndPath("examplemod", "example_instrument")),
        new Instrument(
            BuiltInRegistries.SOUND_EVENT.wrapAsHolder(SoundEvents.ARROW_HIT),
            7f,
            256f,
            Component.translatable(Util.makeDescriptionId("instrument", ResourceLocation.fromNamespaceAndPath("examplemod", "example_instrument")))
        )
    )
});
  • net.minecraft.world.item
    • Instrument takes in a float for the use duration and a Component description.
    • InstrumentItem#setRandom is removed

Trial Spawner Configurations, now in Datapack Form

TrialSpawnConfig are now a datapack registry, meaning they must be defined in JSON or datagenned.

// In data/examplemod/trial_spawner/example_config.json
{
    // The range the entities can spawn from the trial spawner block
    "spawn_range": 2,
    // The total number of mobs that can be spawned
    "total_mobs": 10.0,
    // The number of mobs that can be spawned at one time
    "simultaneous_mobs": 4.0,
    // The number of mobs that are added for each player in the trial
    "total_mobs_added_per_player": 3.0,
    // The number of mobs that can be spawned at one time that are added for each player in the trial
    "simultaneous_mobs_added_per_player": 2.0,
    // The ticks between each spawn
    "ticks_between_spawn": 100,
    // A weighted list of entities to select from when spawning
    "spawn_potentials": [
        {
            // The SpawnData
            "data": {
                // Entity to spawn
                "entity": {
                    "id": "minecraft:zombie"
                }
            },
            // Weighted value
            "weight": 1
        }
    ],
    // A weight list of loot tables to select from when the reward is given
    "loot_tables_to_eject": [
        {
            // The loot key
            "data": "minecraft:spawners/ominous/trial_chamber/key",
            // Weight value
            "weight": 1
        }
    ],
    // Returns the loot table to use when the the trial spawner is ominous
    "items_to_drop_when_ominous": "minecraft:shearing/bogged"
}
// For some RegistrySetBuilder builder
builder.add(Registries.TRIAL_SPAWNER_CONFIG, bootstrap -> {
    var entityTag = new CompoundTag();
    entityTag.putString("id", BuiltInRegistries.ENTITY_TYPE.getKey(EntityType.ZOMBIE).toString());

    bootstrap.register(
        ResourceKey.create(Registries.INSTRUMENT, ResourceLocation.fromNamespaceAndPath("examplemod", "example_config")),
        TrialSpawnerConfig.builder()
            .spawnRange(2)
            .totalMobs(10.0)
            .simultaneousMobs(4.0)
            .totalMobsAddedPerPlayer(3.0)
            .simultaneousMobsAddedPerPlayer(2.0)
            .ticksBetweenSpawn(100)
            .spawnPotentialsDefinition(
                SimpleWeightedRandomList.single(new SpawnData(entityTag, Optional.empty(), Optional.empty()))
            )
            .lootTablesToEject(
                SimpleWeightedRandomList.single(BuiltInLootTables.SPAWNER_OMINOUS_TRIAL_CHAMBER_KEY)
            )
            .itemsToDropWhenOminous(
                BuiltInLootTables.BOGGED_SHEAR
            )
            .build()
    )
});
  • net.minecraft.world.level.block.entity.trialspawner
    • TrialSpawner now takes in a Holder of the TrialSpawnerConfig
      • canSpawnInLevel now takes in a ServerLevel
    • TrialSpawnerConfig
      • CODEC -> DIRECT_CODEC
      • $Builder, builder - A builder for a trial spawner configuration

Recipe Providers, the ‘not actually’ of Data Providers

RecipeProvider is no longer a DataProvider. Instead, a RecipeProvider is constructed via a RecipeProvider$Runner by implementing createRecipeProvider. The name of the provider must also be specified.

public class MyRecipeProvider extends RecipeProvider {

    // The parameters are stored in protected fields
    public MyRecipeProvider(HolderLookup.Provider registries, RecipeOutput output) {
        super(registries, output);
    }

    @Override
    protected void buildRecipes() {
        // Register recipes here
    }

    // The runner class, this should be added to the DataGenerator as a DataProvider
    public static class Runner extends RecipeProvider.Runner {

        public Runner(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
            super(output, registries)
        }

        @Override
        protected RecipeProvider createRecipeProvider(HolderLookup.Provider registries, RecipeOutput output) {
            return new VanillaRecipeProvider(registries, output);
        }

        @Override
        public String getName() {
            return "My Recipes";
        }
    }
}
  • net.minecraft.data.recipes
    • RecipeOutput#includeRootAdvancement - Generates the root advancement for recipes.
    • RecipeProvider no longer extends DataProvider
      • The constructor takes in the lookup provider and a RecipeOutput, which are protected fields
      • buildRecipes does not take in any parameters
      • All generation methods do not take in a RecipeOutput and are instance methods
      • $FamilyRecipeProvider - Creates a recipe for a BlockFamily by passing in the Block the resulting block and the base block.
      • $Runner - A DataProvider that constructs the RecipeProvider via createRecipeProvider
    • ShapedRecipeBuilder, ShapelessRecipeBuilder now have private constructors and take in a holder getter for the items

The Ingredient Shift

Ingredients have be reimplemented to use a HolderSet as its base rather that it own internal Ingredient$Value. This most changes the call to Ingredient#of as you either need to supply it with Item objects or the HolderSet representing the tag. For more information on how to do this, see the holder set section.

  • net.minecraft.world.item.crafting.Ingredient
    • EMPTY -> Ingredient#of, though the default usecases do not allow empty ingredients
    • CODEC is removed
    • CODEC_NONEMPTY -> CODEC
    • testOptionalIngredient - Tests whether the stack is within the ingredient if present, or default to an empty check if not.
    • getItems -> items
    • getStackingIds is removed
    • of(ItemStack...), of(Stream<ItemStack>) is removed
    • of(TagKey) -> of(HolderSet), need to resolve tag key

BlockEntityTypes Privatized!

BlockEntityTypes have been completely privatized and the builder being removed! This means that if a mod loader or mod does not provide some access widening to the constructor, you will not be able to create new block entities. The only other change is that the Type for data fixers was removed, meaning that all that needs to be supplied is the client constructor and the set of valid blocks the block entity can be on.

// If the BlockEntityType constructor is made public
// MyBlockEntity(BlockPos, BlockState) constructor
BlockEntityType<MyBlockEntity> type = new BlockEntityType(MyBlockEntity::new, MyBlocks.EXAMPLE_BLOCK);

Consumables

Consuming an item has been further expanded upon, with most being transitioned into separate data component entries.

The Consumable Data Component

The Consumable data component defines how an item is used when an item is finished being used. This effectively functions as FoodProperties used to previously, except all consumable logic is consolidated in this one component. A consumable has five properties: the number of seconds it takes to consume or use the item, the animation to play while consuming, the sound to play while consuming, whether particles should appear during consumption, and the effects to apply once the consumption is complete.

A Consumable can be applied using the food item property. If only the Consumable should be added, then component should be called. A list of vanilla consumables and builders can be found in Consumables.

// For some item
Item exampleItem = new Item(new Item.Properties().component(DataComponents.CONSUMABLE,
    Consumable.builder()
    .consumeSeconds(1.6f) // Will use the item in 1.6 seconds, or 32 ticks
    .animation(ItemUseAnimation.EAT) // The animation to play while using
    .sound(SoundEvents.GENERIC_EAT) // The sound to play while using the consumable
    .soundAfterConsume(SoundEvents.GENERIC_DRINK) // The sound to play after consumption (delegates to 'onConsume')
    .hasConsumeParticles(true) // Sets whether to display particles
    .onConsume(
        // When finished consuming, applies the effects with a 30% chance
        new ApplyStatusEffectsConsumeEffect(new MobEffectInstance(MobEffects.HUNGER, 600, 0), 0.3F)
    )
    // Can have multiple
    .onConsume(
        // Teleports the entity randomly in a 50 block radius
        new TeleportRandomlyConsumeEffect(100f)
    )
    .build()
));

OnOverrideSound

Sometimes, an entity may want to play a different sound when consuming an item. In that case, the entity can implement Consumable$OverrideConsumeSound and return the sound event that should be played.

// On your own entity
public class MyEntity extends Mob implements Consumable.OverrideCustomSound {
    // ...

    @Override
    public SoundEvent getConsumeSound(ItemStack stack) {
        // Return the sound event to play
    }
}

ConsumableListener

ConsumableListeners are data components that indicate an action to apply once the stack has been ‘consumed’. This means whenever Consumable#consumeTicks has passed since the player started using the consumable. An example of this would be FoodProperties. ConsumableListener only has one method #onConsume that takes in the level, entity, stack doing the consumption, and the Consumable that has finished being consumed.

// On your own data component
public record MyDataComponent() implements ConsumableListener {

    // ...

    @Override
    public void onConsume(Level level, LivingEntity entity, ItemStack stack, Consumable consumable) {
        // Perform stuff once the item has been consumed.
    }
}

ConsumeEffect

There is now a data component that handles what happens when an item is consumed by an entity, aptly called a ConsumeEffect. The current effects range from adding/removing mob effects, teleporting the player randomly, or simply playing a sound. These are applied by passing in the effect to the Consumable or onConsume in the builder.

// When constructing a consumable
Consumable exampleConsumable = Consumable.builder()
    .onConsume(
        // When finished consuming, applies the effects with a 30% chance
        new ApplyStatusEffectsConsumeEffect(new MobEffectInstance(MobEffects.HUNGER, 600, 0), 0.3F)
    )
    // Can have multiple
    .onConsume(
        // Teleports the entity randomly in a 50 block radius
        // NOTE: CURRENTLY BUGGED, only allows for 8 block raidus
        new TeleportRandomlyConsumeEffect(100f)
    )
    .build();

On Use Conversion

Converting an item into another stack on consumption is now handled through DataComponents#USE_REMAINDER. The remainder will only be converted if the stack is empty after this use. Otherwise, it will return the current stack, just with one item used.

// For some item
Item exampleItem = new Item(new Item.Properties().usingConvertsTo(
    Items.APPLE // Coverts this into an apple on consumption
)); 
Item exampleItem2 = new Item(new Item.Properties().component(DataComponents.USE_REMAINDER,
    new UseCooldown(
        new ItemStack(Items.APPLE, 3) // Converts into three apples on consumption
    )
));

Cooldowns

Item cooldowns are now handled through DataComponents#USE_COOLDOWN; however, they have been expanded to apply cooldowns to stacks based on their defined group. A cooldown group either refers to the Item registry name if not specified, or a custom resource location. When applying the cooldown, it will store the cooldown instance on anything that matches the defined group. This means that, if a stack has some defined cooldown group, it will not be affected when a normal item is used.

// For some item
Item exampleItem = new Item(new Item.Properties().useCooldown(
    60 // Wait 60 seconds
    // Will apply cooldown to items in the 'my_mod:example_item' group (assuming that's the registry name)
)); 
Item exampleItem2 = new Item(new Item.Properties().component(DataComponents.USE_COOLDOWN,
    new UseCooldown(
        60, // Wait 60 seconds
        // Will apply cooldown to items in the 'my_mod:custom_group' group
        Optional.of(ResourceLocation.fromNamespaceAndPath("my_mod", "custom_group"))
    )
));
  • net.minecraft.core.component.DataComponents#FOOD -> CONSUMABLE
  • net.minecraft.world.entity.LivingEntity
    • getDrinkingSound, getEatingSound is removed, handled via ConsumeEffect
    • triggerItemUseEffects is removed
    • eat is removed
  • net.minecraft.world.entity.npc.WanderingTrader now implements Consumable$OverrideConsumeSound
  • net.minecraft.world.food
    • net.minecraft.world.food.FoodData
      • tick now takes in a ServerPlayer
      • getLastFoodLevel, getExhaustionLevel, setExhaustion is removed
    • FoodProperties is now a ConsumableListener
      • eatDurationTicks, eatSeconds -> Consumable#consumeSeconds
      • usingConvertsTo -> DataComponents#USE_REMAINDER,
      • effects -> ConsumeEffect
  • net.minecraft.world.item
    • ChorusFruitItem class is removed
    • HoneyBottleItem class is removed
    • Item
      • getDrinkingSound, #getEatingSound is removed, handled via ConsumeEffect
      • releaseUsing now returns a boolean whether it was successfully released
      • $Properties#food can now take in a Consumable for custom logic
      • $Properties#usingConvertsTo - The item to convert to after use.
      • $Properties#useCooldown - The amount of seconds to wait before the item can be used again.
    • ItemCooldowns now take in ItemStacks or ResourceLocations to their methods rather than just an Item
      • getCooldownGroup - Returns the key representing the group the cooldown is applied to
    • ItemStack#getDrinkingSound, getEatingSound is removed
    • MilkBucketItem class is removed
    • OminousBottleItem class is removed
    • SuspiciousStewItem class is removed
  • net.minecraft.world.item.alchemy.PotionContents now implements ConsumableListener
    • The constructor takes in an optional string representing the translation key suffix of the custom name
    • applyToLivingEntity - Applies all effects to the provided entity.
    • getName - Gets the name component by appending the custom name to the end of the provided contents string.
  • net.minecraft.world.item.component
    • Consumable - A data component that defines when an item can be consumed.
    • ConsumableListener - An interface applied to data components that can be consumed, executes once consumption is finished.
    • SuspiciousStewEffects now implements ConsumableListener
    • UseCooldown - A data component that defines how the cooldown for a stack should be applied.
    • UseRemainder - A data component that defines how the item should be replaced once used up.
    • DeathProtection - A data component that contains a list of ConsumeEffects on what to do when using the item to survive death.
  • net.minecraft.world.item.consume_effects.ConsumeEffect - An effect to apply after the item has finished being consumed.

Registry Objcet Id, in the Properties?

When providing the BlockBehaviour$Properties to the Block or the Item$Properties to the Item, it must set the ResourceKey in the block directly by calling #setId. An error will be thrown if this is not set before passing in.

new Block(BlockBehaviour.Properties.of()
    .setId(ResourceKey.create(Registries.BLOCK, ResourceLocation.fromNamespaceAndPath("examplemod", "example_block"))));

new BlockItem(exampleBlock, new Item.Properties()
    .useBlockDescriptionPrefix() // Makes the description id for a block item
    .setId(ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath("examplemod", "example_item"))));

new Item(new Item.Properties()
    .setId(ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath("examplemod", "example_item"))));
  • net.minecraft.world.item.Item$Properties
    • setId - Sets the resource key of the item to get the default description and model from. This property must be set.
    • useBlockDescriptionPrefix - Creates the description id using the block. prefix.
    • useItemDescriptionPrefix - Creates the description id using the item. prefix.
  • net.minecraft.world.level.block.state.BlockBehaviour$Properties#setId - Sets the resource key of the block to get the default drops and description from. This property must be set.

Properties Changes

DirectionProperty has been removed, and must now be called and referenced via EnumProperty#create with a Direction generic. Additionally, all property classes have been made final and must be constructed through one of the exposed create methods.

  • net.minecraft.world.level.block.state.properties
    • BooleanProperty is now final
    • DirectionProperty class is removed
    • EnumProperty is now final
      • create now takes in a List instead of a Collection
    • IntegerProperty is now final
    • Property#getPossibleValues now returns a List instead of a Collection

Recipes, now in Registry format

Recipes have been upgraded to a data pack registry, similar to how loot tables are handled. They are still queried in the same fashion, it just simply using a pseudo-registry-backed instance. Some of the more common changes is that RecipeHolder may be replaced by RecipeDisplayId, RecipeDisplay, or RecipeDisplayEntry if the holder itself is not needed. With this, there are a few changes to how recipe books are handled.

Recipe Books

RecipeBookComponents have been modified somewhat to hold a generic instance of the menu to render. As such, the component no longer implements PlacedRecipe and instead takes in a generic representing the RecipeBookMenu. The menu is passed into the component via its constructor instead of through the init method. This also menas that RecipeBookMenu does not have any associated generics. To create a component, the class needs to be extended.

// Assume some MyRecipeMenu extends AbstractContainerMenu
public class MyRecipeBookComponent extends RecipeBookComponent<MyRecipeMenu> {

    public MyRecipeBookComponent(MyRecipeMenu menu, List<RecipeBookComponent.TabInfo> tabInfos) {
        super(menu, tabInfos);
        // ...
    }

    @Override
    protected void initFilterButtonTextures() {
        // ...
    }

    @Override
    protected boolean isCraftingSlot(Slot slot) {
        // ...
    }

    @Override
    protected void selectMatchingRecipes(RecipeCollection collection, StackedItemContents contents) {
        // ...
    }

    @Override
    protected Component getRecipeFilterName() {
        // ...
    }

    @Override
    protected void fillGhostRecipe(GhostSlots slots, RecipeDisplay display, ContextMap ctx) {

    }
}

public class MyContainerScreen extends AbstractContainerScreen<MyRecipeMenu> implements RecipeUpdateListener {

    public MyContainerScreen(MyRecipeMenu menu, List<RecipeBookComponent.TabInfo> tabInfos, ...) {
        super(menu, ...);
        this.recipeBookComponent = new MyRecipeBookComponent(menu, tabInfos);
    }
    

    // See AbstractFurnaceScreen for a full implementation
}

Recipe Displays

However, how does a recipe understand what should be displayed in a recipe book? This falls under two new static registries: the RecipeDisplay and the SlotDisplay.

The SlotDisplay represents what displays in a single slot within a recipe. The display only has one method (ignoring types): resolve. resolve takes in the ContextMap holding the data and the DisplayContentsFactory which accepts the stacks and remainders that will be displayed in this slot. SlotDisplay also has a lot of helper implementations, such as $Composite that takes in a list of displays or $ItemStackSlotDisplay that takes in the stack to display. The display is registered by its $Type, which takes in the map codec and stream codec.

The slot also has methods to get for the associated stacks that can be displayed via resolveForStacks and resolveForFirstStack.

public static record MySlotDisplay() implements SlotDisplay {

    @Override
    public <T> Stream<T> resolve(ContextMap ctx, DisplayContentsFactory<T> output) {
        // Call output.forStack(...) or addRemainder(..., ...) using instanceof to display items
        if (output instanceof ForStacks<T> stacks) {
            stacks.forStack(...);
        } else if (output instanceof ForRemainders<T> remainders) {
            remainders.addRemainder(..., ...);
        }
    }

    @Override
    public SlotDisplay.Type<? extends SlotDisplay> type() {
        // Return the registered object here registered to Registries#SLOT_DISPLAY
    }
}

RecipeDisplay represents how a recipe is displayed. As an implementation detail, the RecipeDisplay only needs to be aware of the result (via result slot display) and the place the recipe is being used (via craftingStation slot display) as those are the only two details the recipe book cares about. However, it is recommended to also have slot displays for the ingredients and then have those consumed by your RecipeBookComponent. The display is registered by its $Type, which takes in the map codec and stream codec.

public record MyRecipeDisplay(SlotDisplay result, SlotDisplay craftingStation, ...) implements RecipeDisplay {

    @Override
    public RecipeDisplay.Type<? extends RecipeDisplay> type() {
        // Return the registered object here registered to Registries#RECIPE_DISPLAY
    }
}

Recipe Placements

Recipe ingredients and placements within the recipe book are now handled through Recipe#placementInfo. A PlacementInfo is basically a definition of items the recipe contains and where they should be placed within the menu if supported. If the recipe cannot be placed, such as if it is not an Item or uses stack information, then it should return PlacementInfo#NOT_PLACEABLE.

A PlacementInfo can be created either from an Ingredient, a List<Ingredient>, or a List<Optional<Ingredient>> using create or createFromOptionals, respectively.

public class MyRecipe implements Recipe<RecipeInput> {

    private PlacementInfo info;

    public MyRecipe(Ingredient input) {
        // ...
    }

    // ...

    @Override
    public PlacementInfo placementInfo() {
        // This delegate is done as the HolderSet backing the ingredient may not be fully populated in the constructor
        if (this.info == null) {
            this.info = PlacementInfo.create(input);
        }

        return this.info;
    }
}

If an Optional<Ingredient> is used, they can be tested via Ingredient#testOptionalIngredient.

  • net.minecraft.world.item.crafting
    • Ingredient#display - Returns the SlotDisplay that shows this ingredient.
    • PlacementInfo - Defines all ingredients necessary to construct the result of a recipe.
    • Recipe
      • getToastSymbol -> getCategoryIconItem
      • getIngredients, isIncomplete -> placementInfo
        • getIngredients -> PlacementInfo#stackedRecipeContents,
        • isIncomplete -> PlacementInfo#isImpossibleToPlace
    • RecipeManager#getSynchronizedRecipes - Returns all recipes that can be placed and sends them to the client. No other recipes are synced.
    • ShapedRecipePattern now takes in a List<Optional<Ingredient>> instead of a NonNullList<Ingredient>
    • ShapelessRecipe now takes in a List<Ingredient> instead of a NonNullList<Ingredient>
    • SmithingTransformRecipe, SmithingTrimRecipe now takes in Optional<Ingredient>s instead of Ingredients
    • SuspiciousStewRecipe class is removed

Recipe Changes

There have been a few changes within the recipe class itself, which mirror all of the above changes. First, canCraftInDimensions is removed and now hardcoded into the match function. getResultItem and getCategoryIconItem has been replaced by RecipeDisplay via display. getRemainingItems has moved to CraftingRecipe. Finally, all recipes now return their RecipeBookCategory via recipeBookCategory.

public class MyRecipe implements Recipe<RecipeInput> {

    @Override
    public String group() {
        // Return here what `getGroup` was
    }

    @Override
    public List<RecipeDisplay> display() {
        return List.of(
            // Some recipe display instance
            // RecipeDisplay#result should return `getResultItem`
            // RecipeDisplay#craftingStation should return `getCategoryIconItem`
        )
    }

    @Override
    public RecipeBookCategory recipeBookCategory() {
        // Functions similar to the book category passed into the recipe builders during data generation
        return RecipeBookCategories.CRAFTING_MISC;
    }
}

Creating Recipe Book Categories

Recipe book categories are unified by ExtendedRecipeBookCategory and split into two sections: RecipeBookCategory for actual categories, and SearchRecipeBookCategory for aggregate categories. While SearchRecipeBookCategorys are enums, RecipeBookCategory is like any other static registry object. This is done by creating a new RecipeBookCategory.

// Using the standard vanilla registry method
public static final RecipeBookCategory EXAMPLE_CATEGORY = Registry.register(
    BuiltInRegistries.RECIPE_BOOK_CATEGORY,
    // The registry object name
    ResourceLocation.fromNamespaceAndPath("examplemod", "example_category"),
    // This creates a new recipe book category. It functions as a marker object.
    new RecipeBookCategory()
);

Technical Changes

  • net.minecraft.advancements.AdvancementRewards now takes in a list of ResourceKeys instead of ResourceLocations for the recipe
    • $Builder#recipe, addRecipe now takes in a ResourceKey
  • net.minecraft.advancements.critereon
    • PlayerPredicate now takes in a ResourceKey for the recipe map
      • $Builder#addRecipe now takes in a ResourceKey
    • RecipeCraftedTrigger
      • trigger now takes in a ResourceKey
      • $TriggerInstance now takes in a ResourceKey
      • $TriggerInstance#craftedItem, crafterCraftedItem now takes in a ResourceKey
    • RecipeUnlockedTrigger
      • unlocked now takes in a ResourceKey
      • $TriggerInstance now takes in a ResourceKey
  • net.minecraft.client
    • ClientRecipeBook
      • setupCollections -> rebuildCollections, not one-to-one
      • getCollection(RecipeBookCategories) -> getCollection(ExtendedRecipeBookCategory)
      • add, remove - Handles adding/removing a recipe entry to display within the recipe book.
      • addHighLight, removeHighlight, hasHighlight - Handles if the entry is highlighted when filtered or selected by the player.
      • clear - Clears the known and highlighted recipes.
    • RecipeBookCategories#*_MISC -> SearchRecipeBookCategory#*
      • This can also be replaced within methods by RecipeBookComponent$TabInfo, ExtendedRecipeBookCategory, or RecipeBookCategory
  • net.minecraft.client.gui.components.toasts
    • RecipeToast(RecipeHolder) -> RecipeToast(), now private
    • addOrUpdate now takes in a RecipeDisplay instead of a RecipeHolder
  • net.minecraft.client.gui.screens.inventory.AbstractFurnaceScreen
    • recipeBookComponent is now private
    • AbstractFurnaceScreen(T, AbstractFurnaceRecipeBookComponent, Inventory, Component, ResourceLocation, ResourceLocation, ResourceLocation) - AbstractFurnaceRecipeBookComponent has been replaced with a Component as the recipe book is not constructed internally and now takes in a list of RecipeBookComponent$TabInfo
  • net.minecraft.client.gui.screens.recipebook
    • AbstractFurnaceReipceBookComponent, BlastingFurnaceReipceBookComponent, SmeltingFurnaceReipceBookComponent, SmokingFurnaceReipceBookComponent -> FurnaceReipceBookComponent
    • GhostRecipe -> GhostSlots not one-to-one, as the recipe itself is stored as a private field in RecipeBookComponent as a RecipeHolder
      • addResult -> setResult, not one-to-one
      • addIngredient -> setIngredient, not one-to-one
      • setSlot, setInput, setResult now take in a ContextMap
    • OverlayRecipeComponent() -> OverlayRecipeComponent(SlotSelectTime, boolean)
      • init takes in a ContextMap containing registry data to display within the components and a boolean representing whether the recipe book is filtering instead of computing it from the Minecraft instance
      • getLastRecipeClicked now returns a RecipeDisplayId
      • $OverlayRecipeButton is now an abstract package-private class, taking in the ContextMap
      • $Pos is now a record
    • RecipeBookComponent no longer implements RecipeShownListener
      • The constructor takes in a list of $TabInfos containing the tabs shown in the book
      • init no longer takes in a RecipeBookMenu
      • initVisuals is now private
      • initFilterButtonTextures is now abstract
      • updateCollections now takes in another boolean representing if the book is filtering
      • renderTooltip now takes in a nullable Slot instead of an int representing the slot index
      • renderGhostRecipe no longer takes in a float representing the delay time
      • setupGhostRecipe -> fillGhostRecipe, no longer takes in the List<Slot> to place, that is stored within the component itself
      • selectMatchingRecipes no longer takes in the RecipeBook
      • recipesShown now takes in a RecipeDisplayId
      • setupGhostRecipeSlots -> fillGhostRecipe, taking in the ContextMap
      • $TabInfo - A record that denotes the icons and categories of recipe to display within a recipe book page.
    • RecipeBookPage() -> RecipeBookPage(RecipeBookComponent, SlotSelectTime, boolean)
      • updateCollections now takes in a boolean representing if the book is filtering
      • getMinecraft is removed
      • addListener is removed
      • getLastRecipeClicked now returns a RecipeDisplayId
      • recipesShown now takes in a RecipeDisplayId
      • getRecipeBook now returns a ClientRecipeBook
    • RecipeBookTabButton now takes in a RecipeBookComponent$TabInfo
      • startAnimation(Minecraft) -> startAnimation(ClientRecipeBook, boolean)
      • getCategory now returns a ExtendedRecipeBookCategory
    • RecipeButton() -> RecipeButton(SlotSelectTime)
      • init now takes in a boolean representing if the book is filtering and a ContextMap holding the registry data
      • getRecipe -> getCurrentRecipe, not one-to-one
      • getDisplayStack - Returns the result stack of the recipe.
      • getTooltipText now takes in the ItemStack
    • RecipeCollection(RegistryAccess, List<RecipeHolder>) -> RecipeCollection(List<RecipeDisplayEntry>)
      • canCraft -> selectRecipes
      • getRecipes, getDisplayRecipes -> getSelectedRecipes
      • registryAccess, hasKnownRecipes, updateKnownRecipes is removed
      • isCraftable now takes in a RecipeDisplayId
      • hasFitting -> hasAnySelected
      • getRecipes now returns a list of RecipeDisplayEntrys
    • RecipeShownListener class is removed
    • RecipeUpdateListener
      • getRecipeBookComponent is removed
      • fillGhostRecipe -> Fills the ghost recipe given the RecipeDisplay
    • SearchRecipeBookCategory - An enum which holds the recipe book categories for aggregate types.
    • SlotSelectTime - Represents the current index of the slot selected by the player.
  • net.minecraft.client.multiplayer
    • ClientPacketListener#getRecipeManager -> recipes, returns RecipeAccess
    • ClientRecipeContainer - A client side implementation of the RecipeAccess when synced from the server.
    • MultiPlayerGameMode#handlePlaceRecipe now takes in a RecipeDisplayId
    • SessionSearchTrees#updateRecipes now takes in a Level instead of the RegistryAccess$Frozen
  • net.minecraft.client.player.LocalPlayer#removeRecipeHightlight now takes in a RecipeDisplayId
  • net.minecraft.commands.SharedSuggestionProvider#getRecipeNames is removed as it can be queried from the registry access
  • net.minecraft.commands.arguments.ResourceLocationArgument
    • getRecipe -> ResourceKeyArgument#getRecipe
    • getAdvancement -> ResourceKeyArgument#getAdvancement
  • net.minecraft.commands.synchronization.SuggestionProviders#ALL_RECIPES is removed
  • net.minecraft.core.component.DataComponents#RECIPES now takes in a list of ResourceKeys
  • net.minecraft.data.recipes
    • RecipeBuilder#save now takes in a ResourceKey instead of a ResourceLocation
    • RecipeOutput#accept now takes in a ResourceKey instead of a ResourceLocation
    • RecipeProvider#trimSmithing now takes in a ResourceKey instead of a ResourceLocation
  • net.minecraft.network.protocol.game
    • ClientboundPlaceGhostRecipePacket - A packet that contains the container id and the RecipeDisplay
    • ClientboundRecipeBookAddPacket - A packet that adds entries to the recipe book
    • ClientboundRecipeBookRemovePacket - A packet that removes entries to the recipe book
    • ClientboundRecipeBookSettingsPacket - A packet that specifies the settings of the recipe book
    • ClientboundRecipePacket class is removed
    • ClientboundUpdateRecipesPacket is now a record, taking in the property sets of the recipes and the stonecutter recipes
      • getRecipes is removed
    • ServerboundPlaceRecipePacket is now a record
    • ServerboundRecipeBookSeenRecipePacket is now a record
  • net.minecraft.recipebook
    • PlaceRecipe -> PlaceRecipeHelper
      • addItemToSlot -> $Output#addItemToSlot
      • placeRecipe now takes in a Recipe instead of the RecipeHolder
        • There is an overload that takes in two more ints that represent the pattern height and width for a ShapedRecipe, or just the first two integers repeated
    • RecipeBook
      • add, contains, remove -> ServerRecipeBook#add, contains, remove
      • addHighlight, removeHighlight, willHighlight -> ServerRecipeBook#addHighlight, removeHighlight, ClientRecipeBook#hasHighlight
      • bookSettings is now protected
    • RecipeBookSettings#read, write is now private
    • ServerPlaceRecipe is not directly accessible anymore, instead it is accessed and returned as a RecipeBookMenu$PostPlaceAction via #placeRecipe
      • $CraftingMenuAccess - Defines how the placable recipe menu can be interacted with.
    • ServerRecipeBook
      • fromNbt now takes in a predicate of a ResourceKey instead of the RecipeManager
      • copyOverData - Reads the data from another recipe book.
      • $DisplayResolver - Resoluves the recipes to display by passing in a RecipeDisplayEntry
  • net.minecraft.stats.RecipeBook#isFiltering(RecipeBookMenu) is removed
  • net.minecraft.world.entity.player
    • Player#awardRecipesByKey now takes in a list of ResourceKeys
    • StackedItemContents#canCraft overloads that take in a list of ingredient infos
  • net.minecraft.world.inventory
    • AbstractCraftingMenu - A menu for a crafting interface.
    • AbstractFurnaceMenu now takes in the RecipePropertySet key
    • CraftingMenu#slotChangedCraftingGrid now takes in a ServerLevel instead of a Level
    • ItemCombinerMenu now takes in an ItemCombinerMenuSlotDefinition
      • mayPickup now defaults to true
    • ItemCombinerMenuSlotDefinition#hasSlot, getInputSlotIndexes is removed
    • RecipeBookMenu no longer takes in any generics
      • handlePlacement is now abstract and returns a $PostPlaceAction, taking in an additional ServerLevel
        • This remove all basic placement recipes calls, as that would be handled internally by the ServerPlaceRecipe
    • RecipeCraftingHolder#setRecipeUser no longer takes in a Level
    • SmithingMenu#hasRecipeError - Returns whether the recipe had an error when placing items in the inventory.
  • net.minecraft.world.item.crafting
    • AbstractCookingRecipe now implements SingleItemRecipe
      • The constructor no longer takes in the RecipeType, making the user override the getType method
      • getExperience -> experience
      • getCookingTime -> cookingTime
      • furnaceIcon - Returns the icon of the furnace.
      • $Serializer - A convenience implementation for the cooking recipe serializer instance.
    • CookingBookCategory now has an integer id
    • CraftingRecipe#defaultCrafingRemainder - Gets the stacks that should remain behind in the crafting recipe.
    • CustomRecipe$Serializer - A convenience implementation for the custom recipe serializer instance.
    • ExtendedRecipeBookCategory - A unifying interface that denotes a category within the recipe book.
    • Ingredient#optionalIngredientToDisplay - Converts an optional ingredient to a SlotDisplay.
    • Recipe#getRemainingItems -> CraftingRecipe#getRemainingItems
    • RecipeAccess - An accessor that returns the property sets that contain the inputs of available recipes.
    • RecipeBookCategory - An object that represents a single category within the recipe book.
    • RecipeCache#get now takes in a ServerLevel instead of a Level
    • RecipeHolder now takes in a ResourceKey
    • RecipeManager now extends SimplePreparableReloadLsitener<RecipeMap> and implements RecipeAccess
      • prepare - Creates the recipe map from the recipe registry
      • logImpossibleRecipes, hasErrorsLoading is removed
      • getRecipeFor now takes in a ResourceKey where there was a ResourceLocation repviously
      • getRecipesFor, getAllRecipesFor -> RecipeMap#getRecipesFor
      • byType is removed
      • getRemainingItemsFor is Removed
      • byKey.byKeyTyped now takes in a ResourceKey
      • getOrderedRecipes is revmoed
      • getSynchronizedRecipes -> getSynchronizedItemProperties, getSynchronizedStonecutterRecipes; not one-to-one
      • getRecipeIds is removed
      • getRecipeFromDisplay - Gets the recipe display info given its id.
      • listDisplaysForRecipe - Accepts a list of display entries of the recipes to display.
      • replaceRecipes is removed
      • $CachedCheck#getRecipeFor now takes in a ServerLevel instead of a Level
      • $IngredientCollector - A recipe consumer that extracts the ingredient from a recipe and adds it to a RecipePropertySet
      • $IngredientExtractor - A method that gets the ingredients of a recipe when present.
      • $ServerDisplayInfo - A record that links a display entry to its recipe holder.
    • RecipeMap - A class which maps recipe holders by their recipe type and resource key.
    • RecipePropertySet - A set of ingredients that can be used as input to a given recipe slot. Used to only allow specific inputs to slots on screens.
    • SelectableRecipe - A record that holds the slot display and its associated recipe. Currently only used for the stonecutting menu.
    • SimpleCookingSerializer -> AbstractCookingRecipe$Serializer
    • SingleItemRecipe no longer takes in the RecipeType or RecipeSerializer
      • ingredient, result, group is now private
      • input, result - The slots of the recipe.
  • net.minecraft.world.item.crafting.display
    • DisplayContentsFactory - A factory for accepting contents of a recipe. Its subtypes accepts the stacks of the recipe and the remainder.
    • RecipeDisplay - A display handler to show the contents of a recipe.
    • RecipeDisplayEntry - A record that links the recipe display to its identifier, category, and crafting requirements.
    • RecipeDisplayId - An identifier for the recipe display.
    • SlotDisplay - A display handler to show the contents of a slot within a recipe.
    • SlotDisplayContext - Context keys used by slot displays.
  • net.minecraft.world.level.Level#getRecipeManager -> recipeAccess, returns RecipeAccess on level but RecipeManager on ServerLevel
  • net.minecraft.world.level.block.CrafterBlock#getPotentialResults now takes in a ServerLevel instead of a Level
  • net.minecraft.world.level.block.entity.CampfireBlockEntity
    • getCookableRecipe is removed
    • placeFood now takes in a ServerLevel instead of a Level

Minor Migrations

The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.

Language File Removals and Renames

All removals and renames to translations keys within assets/minecraft/lang are now shown in a deprecated.json.

Critereons, Supplied with HolderGetters

All critereon builders during construction now take in a HolderGetter. While this may not be used, this is used instead of a direct call to the static registry to grab associated Holders and HolderSets.

  • net.minecraft.advancement.critereon
    • BlockPredicate$Builder#of
    • ConsumeItemTrigger$TriggerInstance#usedItem
    • EntityEquipmentPredicate#captainPredicate
    • EntityPredicate$Builder#of
    • EntityTypePredicate#of
    • ItemPredicate$Builder#of
    • PlayerTrigger$TriggerInstance#walkOnBlockWithEquipment
    • ShotCrossbowTrigger$TriggerInstance#shotCrossbow
    • UsedTotemTrigger$TriggerInstance#usedToItem

MacosUtil#IS_MACOS

com.mojang.blaze3d.platform.MacosUtil#IS_MACOS has been added to replace specifying a boolean during the render process.

  • com.mojang.blaze3d.pipeline
    • RenderTarget#clear(boolean) -> clear()
    • TextureTarget(int, int, boolean, boolean) -> TextureTarget(int, int, boolean)
  • com.mojang.blaze3d.platform.GlStateManager#_clear(boolean) -> _clear()
  • com.mojang.blaze3d.systems.RenderSystem#clear(int, boolean) -> clear(int)

Fog Parameters

Fog methods for individual values have been replaced with a FogParameters data object.

  • com.mojang.blaze3d.systems.RenderSystem
    • setShaderFogStart, setShaderFogEnd, setShaderFogColor, setShaderFogShape -> setShaderFog
    • getShaderFogStart, getShaderFogEnd, getShaderFogColor, getShaderFogShape -> getShaderFog
  • net.minecraft.client.renderer.FogRenderer
    • setupColor -> computeFogColor, returns a Vector4f
    • setupNoFog -> FogParameters#NO_FOG
    • setupFog now takes in a Vector4f for the color and returns the FogParameters
    • levelFogColor is removed

New Tags

  • minecraft:banner_pattern
    • bordure_indented
    • field_masoned
  • minecraft:block
    • bats_spawnable_on
    • pale_oak_logs
  • minecraft:damage_type
    • mace_smash
  • minecraft:item
    • diamond_tool_materials
    • furnace_minecart_fuel
    • gold_tool_materials
    • iron_tool_materials
    • netherite_tool_materials
    • villager_picks_up
    • wooden_tool_materials
    • piglin_safe_armor
    • repairs_leather_armor
    • repairs_chain_armor
    • repairs_iron_armor
    • repairs_gold_armor
    • repairs_diamond_armor
    • repairs_netherite_armor
    • repairs_turtle_helmet
    • repairs_wolf_armor
    • duplicates_allays
    • brewing_fuel
    • panda_eats_from_ground
    • shulker_boxes
    • bundles
    • map_invisibility_equipment
    • pale_oak_logs
    • gaze_disguise_equipment
  • minecraft:entity_type
    • boat

Smarter Framerate Limiting

Instead of simply limiting the framerate when the player is not in a level or when in a screen or overlay, there is different behavior depending on different actions. This is done using the InactivityFpsLimit via the FramerateLimitTracker. This adds two additional checks. If the window is minimized, the game runs at 10 fps. If the user provides no input for a minute, then the game runs at 30 fps. 10 fps after ten minutes of no input.

  • com.mojang.blaze3d.platform.FramerateLimitTracker - A tracker that limits the framerate based on the set value.
  • com.mojang.blaze3d.platform#Window#setFramerateLimit, getFramerateLimit is removed
  • net.minecraft.client
    • InactivityFpsLimit - An enum that defines how the FPS should be limited when the window is minimzed or the player is away from keyboard.
    • Minecraft#getFramerateLimitTracker - Returns the framerate limiter.

Fuel Values

FuelValues has replaced the static map within AbstractFurnaceBlockEntity. This functions the same as that map, except the fuel values are stored on the MinecraftServer itself and made available to individual Level instances. The map can be obtained with access to the MinecraftServer or Level and calling the fuelValues method.

  • net.minecraft.client.multiplayer.ClientPacketListener#fuelValues - Returns the burn times for fuel.
  • net.minecraft.server.MinecraftServer#fuelValues - Returns the burn times for fuel.
  • net.minecraft.server.level.Level#fuelValues - Returns the burn times for fuel.
  • net.minecraft.world.level.block.entity
    • AbstractFurnaceBlockEntity
      • invalidateCache, getFuel -> Level#fuelValues
      • getBurnDuration now takes in the FuelValues
      • isFuel -> FuelValues#isFuel
    • FuelValues - A class which holds the list of fuel items and their associated burn times

Light Emissions

Light emission data is now baked into the quad and can be added to a face using the light_emission tag.

  • net.minecraft.client.renderer.block.model
    • BakedQuad now takes in an int representing the light emission
      • getLightEmission - Returns the light emission of a quad.
    • BlockElement now takes in an int representing the light emission
    • FaceBakery#bakeQuad now takes in an int representing the light emission

Map Textures

Map textures are now handled through the MapTextureManager, which handles the dynamic texture, and the MapRenderer, which handles the map rendering. Map decorations are still loaded through the map_decorations sprite folder.

  • net.minecraft.client
    • Minecraft
      • getMapRenderer - Gets the renderer for maps.
      • getMapTextureManager - Gets the texture manager for maps.
  • net.minecraft.client.resources#MapTextureManager - Handles creating the dynamic texture for the map.
  • net.minecraft.client.gui.MapRenderer -> net.minecraft.client.renderer.MapRenderer
  • net.minecraft.client.renderer#GameRenderer#getMapRenderer -> Minecraft#getMapRenderer

Orientations

With the edition of the redstone wire experiments comes a new class provided by the neighbor changes: Orientation. Orientation is effectively a combination of two directions and a side bias. Orientation is used as a way to propogate updates relative to the connected directions and biases of the context. Currently, this means nothing for people not using the new redstone wire system as all other calls to neighbor methods set this to null. However, it does provide a simple way to propogate behavior in a stepwise manner.

  • net.minecraft.client.renderer.debug.RedstoneWireOrientationsRenderer - A debug renderer for redstone wires being oriented.
  • net.minecraft.world.level.Level
    • updateNeighborsAt - Updates the neighbor at the given position with the specified Orientation.
    • updateNeighborsAtExceptFromFacing, neighborChanged now takes in an Orientation
  • net.minecraft.world.level.block.RedStoneWireBlock
    • getBlockSignal - Returns the strength of the block signal.
  • net.minecraft.world.level.block.state.BlockBehaviour
    • neighborChanged, $BlockStateBase#handleNeighborChanged now takes in an Orientation instead of the neighbor BlockPos
    • updateShape now takes in the LevelReader, ScheduledTickAccess, and a RandomSource instead of the LevelAccessor; the Direction and BlockState parameters are reordered
    • $BlockStateBase#updateShape now takes in the LevelReader, ScheduledTickAccess, and a RandomSource instead of the LevelAccessor; the Direction and BlockState parameters are reordered
  • net.minecraft.world.level.redstone
    • CollectingNeighborUpdater$ShapeUpdate#state -> neighborState
    • NeighborUpdater
      • neighborChanged, updateNeighborsAtExceptFromFacing, executeUpdate now takes in an Orientation instead of the neighbor BlockPos
      • executeShapeUpdate switches the order of the BlockState and neighbor BlockPos
    • Orientation - A group of connected Directions on a block along with a bias towards either the front or the up side.
    • RedstoneWireEvaluator - A strength evaluator for incoming and outgoing signals.

Minecart Behavior

Minecarts now have a MinecartBehavior class that handles how the entity should be moved and rendered.

  • net.minecraft.core.dispenser.MinecartDispenseItemBehavior - Defines how a minecart should behave when dispensed from a dispenser.
  • net.minecraft.world.entity.vehicle
    • AbstractMinecart
      • getMinecartBehavior - Returns the behavior of the minecart.
      • exits is now public
      • isFirstTick - Returns whether this is the first tick the entity is alive.
      • getCurrentBlockPosOrRailBelow - Gets the current position of the minecart or the rail beneath.
      • moveAlongTrack -> makeStepAlongTrack
      • setOnRails - Sets whether the minecart is on rails.
      • isFlipped, setFlipped - Returns whetherh the minecart is upside down.
      • getRedstoneDirection - Returns the direction the redstone is powering to.
      • isRedstoneConductor is now public
      • applyNaturalSlowdown now returns the vector to slowdown by.
      • getPosOffs -> MinecartBehavior#getPos
      • setInitialPos - Sets the initial position of the minecart.
      • createMinecart is now abstract in its creation, meaning it can be used to create any minecart given the provided parameters
      • getMinecartType is removed
      • getPickResult is now abstract
      • $Type and getMinecartType is replaced by isRideable and isFurnace, which is not one-to-one.
    • AbstractMinecartContainer(EntityType, double, double, double, Level) is removed
    • MinecartBehavior - holds how the entity should be rendered and positions during movement.
    • MinecartFurnace#xPush, zPush -> push
  • net.minecraft.world.level.block.state.properties.RailShape#isAscending -> isSlope
  • net.minecraft.world.phys.shapes.MinecartCollisionContext - An entity collision context that handles the collision of a minecart with some other collision object.

EXPLOOOOSSSION!

Explosion is now an interface that defines the metadata of the explosion. It does not contain any method to actually explode itself. However, ServerExplosion is still used internally to handle level explosions and the like.

  • net.minecraft.world.level
    • Explosion -> ServerExplosion
    • Explosion - An interface that defines how an explosion should occur.
      • getDefaultDamageSource - Returns the default damage source of the explosion instance.
      • shouldAffectBlocklikeEntities - Returns whether block entites should be affected by the explosion.
      • level - Gets the ServerLevel
    • ExplosionDamageCalculator#getEntityDamageAmount now takes in an additional float representing the seen percent
    • Level#explode no longer returns anything
  • net.minecraft.world.level.block.Block#wasExploded now takes in a ServerLevel instead of a Level
  • net.minecraft.world.level.block.state.BlockBehaviour#onExplosionHit, $BlockStateBase#onExplosionHit now takes in a ServerLevel instead of a Level

The Removal of the Carving Generation Step

GenerationStep$Carving has been removed, meaning that all ConfiguredWorldCarvers are provided as part of a single HolderSet.

// In some BiomeGenerationSettings JSON
{
    "carvers": [
        // Carvers here
    ]
}
  • net.minecraft.world.level.biome.BiomeGenerationSettings
    • getCarvers no longer takes in a GenerationStep$Carving
    • $Builder#addCarver no longer takes in a GenerationStep$Carving
    • $PlainBuilder#addCarver no longer takes in a GenerationStep$Carving
  • net.minecraft.world.level.chunk
    • ChunkGenerator#applyCarvers no longer takes in a GenerationStep$Carving
    • ProtoChunk#getCarvingMask, getOrCreateCarvingMask, setCarvingMask no longer takes in a GenerationStep$Carving
  • net.minecraft.world.level.levelgen.placement
    • CarvingMaskPlacement class is removed
    • PlacementContext#getCarvingMask no longer takes in a GenerationStep$Carving

Codecable Json Reload Listener

The SimpleJsonResourceReloadListener has been rewritten to use codecs instead of pure Gson.

public class MyJsonListener extends SimpleJsonResourceReloadListener<MyJsonObject> {

    // If you do not need registry access, the HolderLookup$Provider parameter can be removed
    public MyJsonListener(HolderLookup.Provider registries, Codec<T> codec, String directory) {
        super(registries, codec, directory);
    }
}
  • net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener now takes in a generic representing the data object of the JSON
    • The constructor is now protected, taking in the codec of the data object, the string of the directory, and an optional HolderLookup$Provider to construct the RegistryOps serialization context as necessary
    • prepare now returns a map of names to objects
    • scanDirectory now takes in the DynamicOps and Codec

Consecutive Executors

ProcessorMailbox and ProcessorHandle have been replaced with AbstractConsecutiveExecutor and TaskScheduler, respectively. These are effectively the same in their usage, just with potentially different method names.

  • net.minecraft.util.thread
    • ProcessorMailbox -> AbstractConsecutiveExecutor, not one-to-one
      • ConsecutiveExecutor would be the equivalent implementation
    • PriorityConsecutiveExecutor - An executor that specifies the priority of the task to run when scheduling.
    • BlockableEventLoop#wrapRunnable -> AbstractConsecutiveExecutor#wrapRunnable
    • ProcessorHandle -> TaskScheduler, where the generic is a subtype of Runnable
      • tell -> schedule
      • ask, askEither -> scheduleWithResult, not one-to-one
      • of -> wrapExecutor
    • StrictQueue no longer takes in an F generic and makes T a subtype of Runnable
      • pop now returns a Runnable
      • $IntRunnable -> $RunnableWithPriority

Mob Conversions

Mobs, converted via #convertTo, have their logic handled by ConversionType, ConversionParams. ConversionType is an enum that dictates the logic to apply when copying the information from one mob to another via #convert. The common properties are handled via #convertCommon, which is called within the #convert method. There are currently two types: SINGLE, where the entity is converted one-to-one to another entity; and SPLIT_ON_DEATH, where the Mob#convertTo method is called mutiple times such as when a slime dies. ConversionParams contains the metadata about the conversion process: the type, whether the entity can keep its equipment or pick up loot, and what team the entity is on. Mob#convertTo also takes in a mob consumer to apply any finalization settings to the entity itself.

// For some Mob exampleMob
exampleMob.convertTo(
    EntityType.SHEEP, // The entity to convert to
    new ConversionParams(
        ConversionType.SINGLE, // One-to-one
        true, // Keep equipment
        false // Do not preserve pick up loot
    ),
    EntitySpawnReason.CONVERSION, // Reason entity spawned
    sheep -> {
        // Perform any other settings to set on the newly converted entity
    },
)
  • net.minecraft.world.entity
    • ConversionParams - A record containing the settings of what happens when a mob is converted to another entity
    • ConversionType - An enum that defines how one mob is transformed to another. Currently either SINGLE for one-to-one, or SPLIT_ON_DEATH for one-to-many (only used for slimes)
    • Mob#convertTo now takes in the ConversionParams, an optional EntitySpawnReason of the entity (default CONVERSION), and a mob consumer to set any other information after conversion

Ender Pearl Chunk Loading

Ender pearls now load the chunks they cross through by adding a ticket to the chunk source and storing the entity on the player.

  • net.minecraft.server.level.ServerPlayer
    • registerEnderPearl, deregisterEnderPearl, getEnderPearls - Handles the ender pearls thrown by the player.
    • registerAndUpdateEnderPearlTicket, placeEnderPearlTicket - Handles the region tickets for the thrown ender pearls.

Profilers and the Tracy Client

Profilers have been separated from the minecraft instance, now obtained through Profiler#get. A new profiler instance can be added via a try-resource block on Profiler#use. In addition, the profiler addds a new library called Tracy, made to track the current stack frame along with capturing images on the screen, if the associated --tracy argument is passed in. These sections can be split into ‘zones’ to more granularly distinguish what is happening.

Profiler.get().push("section");
// Do code here
Profiler.get().pop();
  • com.mojang.blaze3d.systems.RenderSystem#flipFrame now takes in a TracyFrameCapture, or null
  • net.minecraft.client.Minecraft#getProfiler -> Profiler#get
  • net.minecraft.client.main.GameConfig$GameData now takes in a boolean on whether to capture the screen via the tracy client.
  • net.minecraft.client.multiplayer.ClientLevel no longer takes in the ProfilerFiller
  • net.minecraft.server.MinecraftServer#getProfiler -> Profiler#get
  • net.minecraft.server.packs.resources.PreparableReloadListener#reload no longer takes in the ProfilerFillers
  • net.minecraft.util.profiling
    • Profiler - A static handler for managing the currently active ProfilerFiller.
    • ProfilerFiller
      • addZoneText - Adds text to label when profiling the current frame.
      • addZoneValue - Adds the value of the zone when profiling the current frame.
      • setZoneColor - Sets the color of the zone when profiling the current frame.
      • zone - Adds a profiler section while creating a new zone to call the above methods for.
      • tee -> combine
      • $CombinedProfileFiller - A profiler that writes to multiple profilers.
    • TracyZoneFiller - A profiler used by the tracy client to keep track of the currently profiling zones.
    • Zone - A section that is current being profiled and interpreted by Tracy.
  • net.minecraft.world.entity.ai.goal.GoalSelector no longer takes in the supplied ProfilerFiller
  • net.minecraft.world.level
    • Level no longer takes in the ProfilerFiller
      • getProfiler, getProfilerSupplier -> Profiler#get
    • PathNavigationRegion#getProfiler -> Profiler#get
  • net.minecraft.world.ticks.LevelTicks no longer takes in the ProfilerFiller

Tick Throttler

To prevent the player from spamming certain actions, TickThrottler was added. The throttler takes in the threshold and the increment to add to the count. If the count is less than the threshold, the action can occur. The count is reduced every tick.

  • net.minecraft.util.TickThrottler - A utility for throttling certain actions from happening too often.

Context Keys

Loot context parameters have been replaced with Context keys, which is simply a more general naming scheme for the previous classes. This also caused the context keys to be used in other contexts that may have arbitrary data.

For a brief description, the context key system is effectively a general typed dictionary, where each ContextKey holds the value type, which is then stored in a backed-map within a ContextMap. To enforce required and optional parameters, a ContextMap is built with a ContextKeySet, which defines the keys of the dictionary map.

  • net.minecraft.advancements.critereon.CriterionValidator#validate now takes in a ContextKeySet instead of a LootContextParamSet
  • net.minecraft.data.loot.LootTableProvider$SubProviderEntry#paramSet now takes in a ContextKeySet instead of a LootContextParamSet
  • net.minecraft.util.context
    • ContextKey - A key that represents an object. It can be thought of a dictionary key that specifies the value type.
    • ContextKeySet - A key set which indicates what keys the backing dictionary must have, along with optional keys that can be specified.
    • ContextMap - A map of context keys to their typed objects.
  • net.minecraft.world.item.enchantment
    • ConditionalEffect#codec now takes in a ContextKeySet instead of aLootContextParamSet
    • TargetedConditionalEffect#codec now takes in a ContextKeySet instead of aLootContextParamSet
  • net.minecraft.world.level.storage.loot
    • LootContext
      • hasParam -> hasParameter
      • getParam -> getParameter
      • getParamOrNull - getOptionalParameter
      • $EntityTraget#getParam now returns a ContextKey instead of a LootContextParam
    • LootContextUser#getReferencedContextParams now takes in a set of ContextKeys rather than a set of LootContextParams
    • LootParams now takes in a ContextMap instead of a map of params to objects
      • hasParam, getParameter, getOptionalParameter, getParamOrNull are accessible through the ContextMap under different names
      • $Builder#withParameter, withOptionalParameter, getParameter, getOptionalParameter now takes in a ContextKey instead of a LootContextParam
      • $Builder#create now takes in a ContextKeySet instead of a LootContextParamSet
    • LootTable
      • getParameSet now returns a ContextKeySet instead of a LootContextParamSet
      • $Builder#setParamSet now takes in a ContextKeySet instead of a LootContextParamSet
    • ValidationContext now takes in a ContextKeySet instead of a LootContextParamSet
      • validateUser -> validateContextUsage
      • setParams - setContextKeySet
  • net.minecraft.world.level.storage.loot.functions
    • CopyComponentsFunction$Source#getReferencedContextParams now takes in a set of ContextKeys rather than a set of LootContextParams
  • net.minecraft.world.level.storage.loot.parameters
    • LootContextParam -> net.minecraft.util.context.ContextKey
    • LootContextParamSet -> net.minecraft.util.context.ContextKeySet
  • net.minecraft.world.level.storage.loot.providers.nbt
    • ContextNbtProvider$Getter#getReferencedContextParams now takes in a set of ContextKeys rather than a set of LootContextParams
    • NbtProvider#getReferencedContextParams now takes in a set of ContextKeys rather than a set of LootContextParams
  • net.minecraft.world.level.storage.loot.providers.score.ScoreboardNameProvider#getReferencedContextParams now takes in a set of ContextKeys rather than a set of LootContextParams

List of Additions

  • com.mojang.blaze3d.framegraph
    • FrameGraphBuilder - A builder that constructs the frame graph that define the resources used and the frame passes to render.
    • FramePass - An interface that defines how to read/write resources and execute them for rendering within the frame graph.
  • com.mojang.blaze3d.platform
    • ClientShutdownWatchdog - A watchdog created for what happens when the client is shutdown.
    • NativeImage#getPixelsABGR - Gets the pixels of the image in ABGR format.
    • Window
      • isIconified - Returns whether the window is currently iconified (usually minimized onto the taskbar).
      • setWindowCloseCallback - Sets the callback to run when the window is closed.
  • com.mojang.blaze3d.resource
    • CrossFrameResourcePool - Handles resources that should be rendered across multiple frames
    • GraphicsResourceAllocator - Handles resources to be rendered and removed.
    • RenderTargetDescriptor - Defines a render target to be allocated and freed.
    • ResourceDescriptor - Defines a resource and how it is allocated and freed.
    • ResourceHandle - Defines a pointer to an individual resource.
  • com.mojang.blaze3d.systems.RenderSystem#overlayBlendFunc - Sets the default overlay blend function between layers with transparency.
  • com.mojang.blaze3d.vertex
    • PoseStack#translate(Vec3) - Translates the top pose using a vector
    • VertexConsumer#setNormal(PoseStack$Pose, Vec3) - Sets the normal of a vertex using a vector
  • net.minecraft
    • Optionull#orElse - If the first object is null, return the second object.
    • TracingExecutor - An executor that traces the stack frames of the class references executing.
    • Util
      • allOf - ANDs all predicates or a list of predicates provided. If there are no supplied predicates, the method will default to true.
      • anyOf - ORs all predicates or a list of predicates provided. If there are no supplied predicates, the method will default to false.
      • makeEnumMap - Creates an enum map given the enum class and a function to convert the enum to a value.
  • net.minecraft.advancements.critereon
    • InputPredicate - A predicate that matches the input the player is making.
    • SheepPredicate - A predicate for when the entity is a sheep.
  • net.minecraft.client
    • Minecraft
      • saveReport - Saves a crash report to the given file.
      • triggerResourcePackRecovery - A function that attempts to save the game when a compilation exception occurs, currently used by shaders when loading.
    • Options#highContrastBlockOutline - When enabled, provides a greater contrast when hovering over a block in range.
    • ScrollWheelHandler - A handler for storing information when a mouse wheel is scrolled.
  • ItemSlotMouseAction - An interface that defines how the mouse interacts with a slot when hovering over.
  • net.minecraft.client.gui.components
    • AbstractSelectionList#setSelectedIndex - Sets the selected entry based on its index.
    • AbstractWidget#playButtonClickSound - Plays the button click sound.
    • DebugScreenOverlay#getProfilerPieChart - Gets the pie chart profiler renderer.
  • net.minecraft.client.gui.components.debugchart.AbstractDebugChart#getFullHeight - Returns the height of the rendered chart.
  • net.minecraft.client.gui.components.toasts
    • Toast
      • getWantedVisbility - Returns the visbility of the toast to render.
      • update - Updates the data within the toast.
    • TutorialToast has a constructor that takes in an int to represent the time to display in milliseconds.
  • net.minecraft.client.gui.font.glyphs.BakedGlyph
    • renderChar - Renders a character in the specified color.
    • $GlyphInstance - An instance of a glyph with the metadata of its screen location.
  • net.minecraft.client.gui.screens
    • BackupConfirmScreen has a constructor that takes in another Component that represents the prompt for erasing the cache.
    • Screen
      • getFont - Returns the current font used for rendering the screen.
      • showsActiveEffects - When true, shows the mob effects currently applied to the player, assuming that such functionality is added to the screen in question.
  • net.minecraft.client.gui.screens.inventory
    • AbstractContainerScreen
      • BACKGROUND_TEXTURE_WIDTH, BACKGROUND_TEXTURE_HEIGHT - Both set to 256.
      • addItemSlotMouseAction - Adds a mouse action when hovering over a slot.
      • renderSlots - Renders all active slots within the menu.
    • AbstractRecipeBookScreen - A screen that has a renderable and interactable RecipeBookComponent supplied from the constructor.
  • net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent#showTooltipWithItemInHand- Returns whether the tooltip should be rendered when the item is in the player’s hand.
  • net.minecraft.client.gui.screens.worldselection
    • CreateWorldCallback - An interface that creates the world given the current screen, registries, level data, and path directory.
    • CreateWorldScreen#testWorld - Tries to open the world create screen with the provided generation settings context.
    • InitialWorldCreationOptions - Contains the options set when creating the world to generate.
    • WorldCreationContextMapper - An interface that creates the world context from the available resource reloaders and registries.
  • net.minecraft.client.multiplayer
    • ClientChunkCache
      • getLoadedEmptySections - Returns the sections that have been loaded by the game, but has no data.
    • ClientLevel
      • isTickingEntity - Returns whether the entity is ticking in the level.
      • setSectionRangeDirty- Marks an area as dirty to update during persistence and network calls.
      • onSectionBecomingNonEmpty - Updates the section when it has data.
    • PlayerInfo#setTabListOrder, getTabListOrder - Handles the order of players to cycle through in the player tab.
  • net.minecraft.client.multiplayer.chat.report.ReportReason#getIncompatibleCategories - Gets all reasons that cannot be reported for the given type.
  • net.minecraft.client.particle.TrailParticle - A particle to trail from its current position to the target position.
  • net.minecraft.client.player.LocalPlayer#getDropSpamThrottler - Returns a throttler that determines when the player can drop the next item.
  • net.minecract.client.renderer
    • CloudRenderer - Handles the rendering and loading of the cloud texture data.
    • DimensionSpecialEffects#isSunriseOrSunset - Returns whether the dimension time represents sunrise or sunset in game.
    • LevelEventHandler - Handles the events sent by the Level#levelEvent method.
    • LevelRenderer
      • getCapturedFrustrum - Returns the frustrum box of the renderer.
      • getCloudRenderer - Returns the renderer for the clouds in the skybox.
      • onSectionBecomingNonEmpty - Updates the section when it has data.
    • LevelTargetBundle - Holds the resource handles and render targets for the rendering stages.
    • LightTexture
      • getBrightness - Returns the brightness of the given ambient and sky light.
      • lightCoordsWithEmission - Returns the packed light coordinates.
    • RenderType
      • entitySolidZOffsetForward - Gets a solid entity render type where the z is offset from the individual render objects.
      • flatClouds - Gets the render type for flat clouds.
      • debugTriangleFan - Gets the render type for debugging triangles.
      • vignette - Gets the vignette type.
      • crosshair - Gets the render type for the player crosshair.
      • mojangLogo - Gets the render type for the mojang logo
    • Octree - A traversal implementation for defining the order sections should render in the frustum.
    • ShapeRenderer - Utility for rendering basic shapes in the Minecraft level.
    • SkyRenderer - Renders the sky.
    • WeatherEffectRenderer - Renders weather effects.
    • WorldBorderRenderer - Renders the world border.
  • net.minecraft.client.renderer
    • SectionOcclusionGraph#getOctree - Returns the octree to handle traversal of the render sections.
    • ViewArea#getCameraSectionPos - Gets the section position of the camera.
  • net.minecraft.client.renderer.culling.Frustum
    • getFrustumPoints - Returns the frustum matrix as an array of Vector4fs.
    • getCamX, getCamY, getCamZ - Returns the frustum camera coordinates.
  • net.minecraft.client.renderer.chunk.CompileTaskDynamicQueue - A syncrhonized queue dealing with the compile task of a chunk render section.
  • net.minecraft.client.renderer.debug
    • ChunkCullingDebugRenderer - A debug renderer for when a chunk is culled.
    • DebugRenderer
      • renderAfterTranslucents - Renders the chunk culling renderer after translucents have been rendered.
      • renderVoxelShape - Renders the outline of a voxel shape.
      • toggleRenderOctree - Toggles whether OctreeDebugRenderer is rendered.
    • OctreeDebugRenderer - Renders the order of the section nodes.
  • net.minecraft.client.renderer.texture.AbstractTexture#defaultBlur, getDefaultBlur - Returns whether the blur being applied is the default blur.
  • net.minecraft.client.resources.DefaultPlayerSkin#getDefaultSkin - Returns the default PlayerSkin.
  • net.minecraft.commands.CommandBuildContext#enabledFeatures - Returns the feature flags
  • net.minecraft.commands.arguments.selector.SelectorPattern - A record that defines an EntitySelector resolved from some pattern.
  • net.minecraft.core
    • BlockPos#betweenClosed - Returns an iterable of all positions within the bounding box.
    • Direction
      • getYRot - Returns the Y rotation of a given direction.
      • getNearest - Returns the nearest direction given some XYZ coordinate, or the fallback direction if no direction is nearer.
      • getUnitVec3 - Returns the normal unit vector.
      • $Axis#getPositive, getNegative, getDirections - Gets the directions along the axis.
    • GlobalPos#isCloseEnough - Returns whether the distance from this position to another block position in a dimension is within the given radius.
    • HolderLookup$Provider
      • listRegistries - Returns the registry lookups for every registry.
      • allRegistriesLifecycle - Returns the lifecycle of all registries combined.
    • HolderSet#isBound - Returns whether the set is bound to some value.
    • Registry$PendingTags#size - Gets the number of tags to load.
    • Vec3i#distChessboard - Gets the maximum absolute distance between the vector components.
  • net.minecraft.core.component
    • DataComponentHolder#getAllOfType - Returns all data components that are of the specific class type.
    • DataComponentPredicate
      • someOf - Constructs a data component predicate where the provided map contains the provided component types.
      • $Builder#expect - Adds that we should expect the data component has some value.
    • PatchedDataComponentMap#clearPatch - Clears all patches to the data components on the object.
  • net.minecraft.core.particles.TargetColorParticleOption - A particle option that specifies a target location and a color of the particle.
  • net.minecraft.data.DataProvider
    • saveAll - Writes all values in a resource location to value map to the PathProvider using the provided codec.
    • saveStable - Writes a value to the provided path given the codec.
  • net.minecraft.data.loot#BlockLootSubProvider
    • createMossyCarpetBlockDrops - Creates a loot table for a mossy carpet block.
    • createShearsOrSlikTouchOnlyDrop - Creates a loot table that can only drop its item when mined with shears or an item with the silk touch enchantment.
  • net.minecraft.data.worldgen.Pools#createKey - Creates a ResourceKey for a template pool.
  • net.minecraft.data.models.EquipmentModelProvider - A model provider for equipment models, only includes vanilla bootstrap.
  • net.minecraft.data.info.DatapackStructureReport - A provider that returns the structure of the datapack.
  • net.minecraft.gametest.framework
    • GameTestHelper
      • absoluteAABB, relativeAABB - Moves the bounding box between absolute coordinates and relative coordinates to the test location
      • assertEntityData - Asserts that the entity at the provided block position matches the predicate.
      • hurt - Hurts the entity the specified amount from a source.
      • kill - Kills the entity.
    • GameTestInfo#getTestOrigin - Gets the origin of the spawn structure for the test.
    • StructureUtils#getStartCorner - Gets the starting position of the test to run.
  • net.minecraft.network
    • FriendlyByteBuf
      • readVec3, writeVec3 - Static methods to read and write vectors.
      • readContainerId, writeContainerId - Methods to read and write menu identifiers.
      • readChunkPos, writeChunkPos - Methods to read and write the chunk position.
    • StreamCodec#composite - A composite method that takes in seven/eight parameters.
  • net.minecraft.network.codec.ByteBufCodecs
    • CONTAINER_ID - A stream codec to handle menu identifiers.
    • ROTATION_BYTE - A packed rotation into a byte.
    • LONG - A stream codec for a long, or 64 bytes.
    • OPTIONAL_VAR_INT - A stream codec for an optional integer, serializing 0 when not present, or one above the stored value.
      • -1 cannot be sent properly using this stream codec.
  • net.minecraft.network.protocol.game
    • ClientboundEntityPositionSyncPacket - A packet that syncs the entity’s position.
    • ClientboundPlayerRotationPacket - A packet that contains the player’s rotation.
  • net.minecraft.server
    • MinecraftServer
      • tickConnection - Ticks the connection for handling packets.
      • reportPacketHandlingException - Reports a thrown exception when attempting to handle a packet
      • pauseWhileEmptySeconds - Determines how many ticks the server should be paused for when no players are on.
    • SuppressedExceptionCollector - A handler for exceptions that were supressed by the server.
  • net.minecraft.server.commands.LookAt - An interface that defines what should happen to an entity when the command is run, typically moving it to look at another.
  • net.minecraft.server.level
    • ChunkHolder#hasChangesToBroadcast - Returns whether there is any updates within the chunk to send to the clients.
    • ChunkTaskDispatcher - A task scheduler for chunks.
    • DistanceManager
      • getSpawnCandidateChunks - Returns all chunks that the player can spawn within.
      • getTickingChunks - Returns all chunks that are currently ticking.
    • ServerChunkCache#onChunkReadyToSend - Adds a chunk holder to broadcast to a queue.
    • ServerEntityGetter - An entity getter interface implementation that operates upon the ServerLevel.
      • Replcaes the missing methods from EntityGetter
    • ServerPlayer
      • getTabListOrder - Handles the order of players to cycle through in the player tab.
      • getLastClientInput, setLastClientInput, getLastClientMoveIntent - Handles how the server player interprets the client impulse.
      • commandSource - Returns the player’s source of commands.
      • createCommandSourceStack - Creates the source stack of the player issuing the command.
    • ThrottlingChunkTaskDispatcher - A chunk task dispatcher that sets a maximum number of chunks that can be executing at once.
    • TickingTracker#getTickingChunks - Returns all chunks that are currently ticking.
  • net.minecraft.server.packs.repository.PackRepository#isAbleToClearAnyPack - Rebuilds the selected packs and returns whether it is different from the currently selected packs.
  • net.minecraft.resources.DependantName - A reference object that maps some registry object ResourceKey to a value. Acts similarly to Holder except as a functional interface.
  • net.minecraft.tags.TagKey#streamCodec - Constructs a stream codec for the tag key.
  • net.minecraft.util
    • ARGB#vector3fFromRGB24 - Creates a Vector3f containing the RGB components using the low 24 bits of an integer.
    • BinaryAnimator - A basic animator that animates between two states using an easing function.
    • ExtraCodecs
      • NON_NEGATIVE_FLOAT - A float codec that validates the value cannot be negative.
      • RGB_COLOR_CODEC - An integer, float, or three vector float codec representing the RGB color.
      • nonEmptyMap - A map codec that validates the map is not empty.
    • Mth
      • wrapDegrees - Sets the degrees to a value within (-180, 180].
      • lerp - Linear interpolation between two vectors using their components.
      • length - Gets the length of a 2D point in space.
      • easeInOutSine - A cosine function that starts at (0,0) and alternates between 1 and 0 every pi.
      • packDegrees, unpackDegrees - Stores and reads a degree in float form to a byte.
    • RandomSource#triangle - Returns a random float between the two floats (inclusive, exclusive) using a trangle distribution.
    • StringRepresentable$EnumCodec#byName - Gets the enum by its string name or the provided supplier value if null.
    • TriState - An enum that represents three possible states: true, false, or default.
  • net.minecraft.util.datafix.ExtraDataFixUtils
    • patchSubType - Rewrites the second type to the third type within the first type.
    • blockState - Returns a dynamic instance of the block state
    • fixStringField - Modifies the string field within a dynamic.
  • net.minecraft.util.thread.BlockableEventLookup
    • BLOCK_TIME_NANOS - Returns the amount of time in nanoseconds that an event will block the thread.
    • isNonRecoverable - Returns whether the exception can be recovered from.
  • net.minecraft.world.damagesource.DamageSources
    • enderPearl - Returns a damage source from when an ender pearl is hit.
    • mace - Returns a damage source where a direct entity hits another with a mace.
  • net.minecraft.world.entity
    • Entity
      • applyEffectsFromBlocks - Applies any effects from blocks via Block#entityInside or hardcoded checks like snow or rain.
      • isAffectedByBlocks - Returns whether the entity is affect by the blocks when inside.
      • checkInsideBlocks - Gets all blocks that teh player has traversed and checks whether the entity is inside one and adds them to a set when present.
      • oldPosition, setOldPosAndrot, setOldPos, setOldRot - Helpers for updating the last position and rotation of the entity.
      • getXRot, getYRot - Returns the linearly interpolated rotation of the entity given the partial tick.
      • isAlliedTo(Entity) - Returns whether the entity is allied to this entity.
      • teleportSetPosition - Sets the position and rotation data of the entity being teleported via a DimensionTransition
      • getLootTable - Returns the ResourceKey of the loot table the entity should use, if present.
      • isControlledByOrIsLocalPlayer - Return whether the entity is the local player or is controlled by a local player.
      • shouldPlayLavaHurtSound - When true, plays the lava hurt sound when the entity is hurt by lava.
      • onRemoval - A method that gets called when the entity is removed.
      • cancelLerp - Stops any lerped movement.
      • forceSetRotation - Sets the rotation of the entity.
      • isControlledByClient - Returns whether the entity is controlled by client inputs.
    • EntityType
      • getDefaultLootTable now returns an Optional in case the loot table is not present
      • $Builder#noLootTable - Sets the entity type to have no loot spawn on death.
      • $Builder#build now takes in the resouce key of the entity type
    • EntitySelector#CAN_BE_PICKED - Returns a selector that gets all pickable entities not in spectator.
    • LivingEntity
      • dropFromShearingLootTable - Resolves a loot table with a shearing context.
      • getItemHeldByArm - Returns the stack held by the specific arm.
      • getEffectiveGravity - Returns the gravity applied to the entity.
      • canContinueToGlide - Returns whether the entity can stil glide in the sky.
      • getItemBlockingWith - Returns the stack the player is currently blocking with.
      • canPickUpLoot - Returns whether the entity can pick up items.
      • dropFromGiftLootTable - Resolves a loot table with a gift context.
      • handleExtraItemsCreatedOnUse - Handles when a living entity gets a new item as a result of using another item.
      • isLookingAtMe - Checks whether the provided entity is looking at this entity.
    • PositionMoveRotation - A helper for handling the position and rotation of the entity in context.
    • WalkAnimationState#stop - Stops the walking animation of the entity.
  • net.minecraft.world.entity.ai.attributes
    • AttributeInstance
      • getPermanentModifiers - Returns all permanent modifiers applied to the entity.
      • addPermanentModifiers - Adds a collection of permanent modifiers to apply.
    • AttributeMap#assignPermanentModifiers - Copies the permanent modifiers from another map.
  • net.minecraft.world.entity.ai.control.Control#rotateTowards - Returns a float that rotates to some final rotation by the provided difference within a clamped value.
  • net.minecraft.world.entity.ai.goal.Goal#getServerLevel - Gets the server level given the entity or a level.
  • net.minecraft.world.entity.ai.navigation.PathNavigation
    • updatePathfinderMaxVisitedNodes - Updates the maximum number of nodes the entity can visit.
    • setRequiredPathLength - Sets the minimum length of the path the entity must take.
    • getMaxPathLength - Returns the maximum length of the path the entity can take.
  • net.minecraft.world.entity.ai.sensing
    • PlayerSensor#getFollowDistance - Returns the following distance of this entity.
    • Sensor#wasEntityAttackableLastNTicks - Returns a predicate that checks whether the entity is attackable within the specified number of ticks.
  • net.minecraft.world.entity.ai.village.poi.PoiRecord#pack, PoiSection#pack - Packs the necessary point of interest information. This only removes the dirty runnable.
  • net.minecraft.world.entity.animal
    • AgeableWaterCreature - A water creature that has an age state.
    • Animal
      • createAnimalAttributes - Creates the attribute supplier for animals.
      • playEatingSound - Plays the sound an animal makes while eating.
    • Bee#isNightOrRaining - Returns whether the current level has sky light and is either at night or raining.
    • Cat#isLyingOnTopOfSleepingPlayer - Returns whether the cat is on top of a sleeping player.
    • Salmon#getSalmonScale - Returns the scale factor to apply to the entity’s bounding box.
    • Wolf#DEFAULT_TAIL_ANGLE - Returns the default tail angle of the wolf.
  • net.minecraft.world.entity.boss.enderdragon.DragonFlightHistory - Holds the y and rotation of the dragon when flying through the sky. Used for animating better motion of the dragon’s parts.
  • net.minecraft.world.entity.monster.Zombie#canSpawnInLiquids - When true, the zombie can spawn in a liquid.
  • net.minecraft.world.entity.player
    • Inventory
      • isUsableForCrafting - Returns whether the state can be used in a crafting recipe.
      • createInventoryUpdatePacket - Creates the packet to update an item in the inventory.
    • Player
      • handleCreativeModeItemDrop - Handles what to do when a player drops an item from creative mode.
      • shouldRotateWithMinecart - Returns whether the player should also rotate with the minecart.
      • canDropItems - When true, the player can drop items from the menu.
      • getPermissionLevel, hasPermissions - Returns the permissions of the player.
    • StackedContents - Holds a list of contents along with their associated size.
      • $Output - An interface that defines how the contents are accepted when picked.
  • net.minecraft.world.entity.projectile.Projectile
    • spawnProjectileFromRotation - Spawns a projectile and shoots from the given rotation.
    • spawnProjectileUsingShoot - Spawns a projectile and sets the initial impulse via #shoot.
    • spawnProjectile - Spawns a projectile.
    • applyOnProjectileSpawned - Applies any additional configurations from the given level and ItemStack.
    • onItemBreak - Handles what happens when the item that shot the projectile breaks.
    • shouldBounceOnWorldBorder - Returns whether the projectile should bounce off the world border.
    • setOwnerThroughUUID - Set the owner of the projectile by querying it through its UUID.
    • $ProjectileFactory - Defines how a projectile is spawned from some ItemStack by an entity.
  • net.minecraft.world.entity.vehicle
    • AbstractBoat - An entity that represents a boat.
    • AbstractChestBoat - An entity that represent a boat with some sort of inventory.
    • ChestRaft - An entity that represents a raft with some sort of inventory.
    • Raft - An entity that represents a raft.
  • net.minecraft.world.inventory.AbstractContainerMenu
    • addInventoryHotbarSlots - Adds the hotbar slots for the given container at the x and y positions.
    • addInventoryExtendedSlots - Adds the player inventory slots for the given container at the x and y positions.
    • addStandardInventorySlots - Adds the hotbar and player inventory slots at their normal location for the given container at the x and y positions.
    • setSelectedBundleItemIndex - Toggles the selected bundle in a slot.
  • net.minecraft.world.item
    • BundleItem
      • getOpenBundleModelFrontLocation, getOpenBundleModelBackLocation - Returns the model locations of the bundle.
      • toggleSelectedItem, hasSelectedItem, getSelectedItem, getSelectedItemStack - Handles item selection within a bundle.
      • getNumberOfItemsToShow - Determines the number of items in the bundle to show at once.
      • getByColor - Handles the available links from bundle to dyed bundles.
      • getAllBundleItemColors - Returns a stream of all dyed bundles.
    • ItemStack
      • clearComponents - Clears the patches made to the stack, not the item components.
      • isBroken - Returns wheter the stack has been broken.
      • hurtWithoutBreaking - Damages the stack without breaking the stack.
      • getStyledHoverName - Gets the stylized name component of the stack.
  • net.minecraft.world.item.component.BundleContents
    • canItemBeInBundle - Whether the item can be put into the bundle.
    • getNumberOfItemsToShow - Determines the number of items in the bundle to show at once.
    • hasSelectedItem, getSelectedItem - Handles item selection within a bundle.
  • net.minecraft.world.item.enchantment.EnchantmentHelper
    • createBook - Creates an enchanted book stack.
    • doPostAttackEffectsWithItemSourceOnBreak - Applies the enchantments after attack when the item breaks.
  • net.minecraft.world.level
    • BlockCollisions has a constructor to take in a CollisionContext
    • BlockGetter#boxTraverseBlocks - Returns an iterable of the positions traversed along the vector in a given bounding box.
    • CollisionGetter
      • noCollision - Returns whether there is no collision between the entity and blocks, entities, and liquids if the boolean provided is true.
      • getBlockAndLiquidCollisions - Returns the block and liquid collisions of the entity within the bounding box.
      • clipIncludingBorder - Gets the block hit result for the specified clip context, clamped by the world border if necessary.
    • EmptyBlockAndTintGetter - A dummy BlockAndTintGetter instance.
    • GameType#isValidId - Checks whether the id matches an existing game type.
    • LevelHeightAccessor#isInsideBuildHeight - Returns whether the specified Y coordinate is within the bounds of the level.
  • net.minecraft.world.level.block
    • Block#UPDATE_SKIP_SHAPE_UPDATE_ON_WIRE - A block flag that, when enabled, does not update the shape of a redstone wire.
    • BonemealableFeaturePlacerBlock - A block that places a configured feature and can be bonemealed.
  • net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerData#resetStatistics - Resets the data of the spawn to an empty setting, but does not clear the current mobs or the next spawning entity.
  • net.minecraft.world.level.block.piston.PistonMovingBlockEntity#getPushDirection - Returns the push direction of the moving piston.
  • net.minecraft.world.level.block.state
    • BlockBehaviour
      • getEntityInsideCollisionShape, $BlockStateBase#getEntityInsideCollisionShape - Determines the voxel shape of the block when the entity is within it.
      • $Properties#overrideDescription - Sets the translation key of the block name.
    • StateHolder
      • getValueOrElse - Returns the value of the property, else the provided default.
      • getNullableValue - Returns the value of the property, or null if it does not exist.
  • net.minecraft.world.level.block.state.properties.Property#getInternalIndex - Converts the provided boolean to a 0 when true, or 1 otherwise.
  • net.minecraft.world.level.border.WorldBorder#clampVec3ToBound - Clamps the vector to within the world border.
  • net.minecraft.world.level.chunk
    • ChunkAccess#canBeSerialized - Returns true, allows the chunk to be written to disk.
    • ChunkSource#onSectionEmptinessChanged - Updates the section when it has data.
    • LevelChunkSection
      • copy - Makes a shallow copy of the chunk section.
      • setUnsavedListener - Adds a listener which takes in the chunk position whenever the chunk is marked dirty.
      • $UnsavedListener - A consumer of a chunk position called when the chunk is marked dirty.
    • PalettedContainerRO#copy - Creates a shallow copy of the PalettedContainer.
    • UpgradeData#copy - Creates a deep copy of UpgradeData.
  • net.minecraft.world.level.chunk.storage.IOWorker#store - Stores the writes of the chunk to the worker.
  • net.minecraft.world.level.levelgen
    • SurfaceRules$Context#getSeaLevel, SurfaceSystem#getSeaLevel - Gets the sea level of the generator settings.
    • WorldOptions#testWorldWithRandomSeed - Creates a test world with a randomly generated seed.
  • net.minecraft.world.level.levelgen.feature.treedecorators.TreeDecorator$Context#checkBlock - Checks if the block at the given position matches the predicate.
  • net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate
    • getJigsaws - Returns the jigsaw blocks that are at the provided position with the given rotation.
    • getJointType - Returns the joint type of the jigsaw block.
    • $JigsawBlockInfo - A record which contains the block info for a jigsaw block.
      • Most methods that involve jigsaws have replaced the $StructureBlockInfo with a $JigsawBlockInfo.
  • net.minecraft.world.level.lighting.LayerLightSectionStorage#lightOnInColumn - Returns whether there is light in the zero node section position.
  • net.minecraft.world.level.pathfinder.PathFinder#setMaxVisitedNodes - Sets the maximum number of nodes that can be visited.
  • net.minecraft.world.level.portal
    • DimensionTransition#withRotation - Updates the entity’s spawn rotation.
    • PortalShape#findAnyShape - Finds a PortalShape that can be located at the given block position facing the specific direction.
  • net.minecraft.world.phys
    • AABB
      • clip - Clips the vector inside the given bounding box, or returns an empty optional if there is no intersection.
      • collidedAlongVector - Returns whether this box collided with one of the bounding boxes provided in the list along the provided movement vector.
      • getBottomCenter - Gets the bottom center of the bounding box as a vector.
    • Vec3
      • add, subtract - Translates the vector and returns a new object.
      • horizontal - Returns the horizontal components of the vector.
      • projectedOn - Gets the unit vector representing this vector projected onto another vector.
  • net.minecraft.world.phys.shapes
    • CollisionContext
      • of(Entity, boolean) - Creates a new entity collision context, where the boolean determines whether the entity can always stand on the provided fluid state.
      • getCollisionShape - Returns the collision shape collided with.
    • VoxelShape#move(Vec3) - Offsets the voxel shape by the provided vector.
  • net.minecraft.world.ticks.ScheduledTick#toSavedTick - Converts a scheduled tick to a saved tick.

List of Changes

  • F3 + F now toggles fog rendering
  • com.mojang.blaze3d.platform
    • NativeImage
      • getPixelRGBA, setPixelRGBA are now private. These are replaced by getPixel and setPixel, respectively
      • getPixelsRGBA -> getPixels
    • Window#updateDisplay now takes in a TraceyFrrameCapture, or null
  • net.minecraft.Util
    • backgroundExecutor, ioPool, and nonCriticalIoPool now return a TracingExecutor instead of an ExecutorService
    • wrapThreadWithTaskName -> runNamed with its parameters flipped and no return value
  • net.minecraft.advancements.critereon
    • KilledByCrossbowTrigger -> KilledByArrowTrigger, not one-to-one, takes in the stack in question
    • PlayerPredicate can now match the player’s input
  • net.minecraft.client
    • Minecraft
      • debugFpsMeterKeyPress -> ProfilerPieChart#profilerPieChartKeyPress obtained via Minecraft#getDebugOverlay and then DebugScreenOverlay#getProfilerPieChart
      • getTimer -> getDeltaTracker
      • getToasts -> getToastManager
    • Options#setModelPart is now public, replaces toggleModelPart but without broadcasting the change
    • ParticleStatus -> net.minecraft.server.level.ParticleStatus
  • net.minecraft.client.animation.KeyframeAnimations#animate now takes in a Model instead of a HierarchicalModel
  • net.minecraft.client.gui.Font
    • drawInBatch(String, float, float, int, boolean, Matrix4f, MultiBufferSource, Font.DisplayMode, int, int, boolean) is removed and should use the Component replacement
      • There is also a delegate that sets the inverse depth boolean to true by default for the Component drawInBatch method
    • $StringRenderOutput now takes in the Font, an optional background color, and a boolean representing if inverse depth should be use when drawing the text
    • $StringRenderOutput#finish is now package private
  • net.minecraft.client.gui.components
    • AbstractSelectionList
      • replaceEntries is now public
      • getRowTop, getRowBottom is now public
    • PlayerFaceRenderer#draw(GuiGraphics, ResourceLocation, int, int, int, int) takes in a PlayerSkin instead of a ResourceLocation
  • net.minecraft.client.gui.components.toasts
    • Toast
      • Toast$Visibility render(GuiGraphics, ToastComponent, long) -> void render(GuiGraphics, Font, long)
      • slotCount - occupiedSlotCount
    • ToastComponent -> ToastManager
  • net.minecraft.client.gui.font.glyphs.BakedGlyph
    • render now takes in a single integer representing the color instead of four floats and is private
      • renderChar is the public replacement, taking in the $GlyphInstance, the Matrix4f, VertexConsumer, and color integer
    • $Effect is a record, now taking in a single integer representing the color instead of four floats
  • net.minecraft.client.gui.screens
    • LoadingOverlay#MOJANG_STUDIOS_LOGO_LOCATION is now public
    • Screen
      • renderBlurredBackground(float) -> renderBlurredBackground()
      • wrapScreenError -> fillCrashDetails, not one to one as it only adds the relevant crash information and not actually throw the error
  • net.minecraft.client.gui.screens.inventory
    • AbstractContainerScreen#renderSlotHighlight -> renderSlotHighlightBack, renderSlotHighlightFront, now private
    • BookEditScreen now takes in the WritableBookContent
    • AbstractSignEditScreen
      • sign is now protected
      • renderSignBackground no longer takes in the BlockState
    • EffectRenderingInventoryScreen -> Screen#hasActiveEffects, EffectsInInventory. Not one-to-one as EffectsInInventory now acts as a helper class to a screen to render its effects at the specified location.
  • net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent
    • getHeight() -> getHeight(Font)
    • renderImage now takes in the int width and height of the rendering tooltip
  • net.minecraft.client.gui.screens.recipebook
    • GhostSlots#render no longer takes in an x and y offset.
    • RecipeBookComponent no longer takes in an x and y offset.
  • net.minecraft.client.gui.screens.reporting.ReportReasonSelectionScreen now takes in a ReportType
  • net.minecraft.client.gui.screens.worldselection
    • CreateWorldScreen
      • $DataPackReloadCookie -> DataPackReloadCookie
      • openFresh now has an overload that takes in the CreateWorldCallback
    • WorldCreationContext now takes in the InitialWorldCreationOptions
    • WorldOpenFlows#createFreshLevel takes in a Function<HolderLookup.Provider, WorldDimensions> instead of Function<RegistryAccess, WorldDimensions>
  • net.minecraft.client.gui.spectator.SpectatorMenuItem#renderIcon now takes in a float instead of an int to represent the alpha value
  • net.minecraft.client.multiplayer
    • ClientLevel now takes in an int representing the sea level
      • getSkyColor now returns a single int instead of a Vec3
      • getCloudColor now returns a single int instead of a Vec3
      • setGameTime, setDayTime -> setTimeFromServer
    • TagCollector -> RegistryDataCollector$TagCollector, now package-private
  • net.minecraft.client.player
    • AbstractClientPlayer#getFieldOfViewModifier now takes in a boolean representing whether the camera is in first person and a float representing the partial tick
    • Input -> ClientInput and net.minecraft.world.entity.player.Input
    • KeyboardInput now extends ClientInput
    • LocalPlayer#input is now ClientInput
  • net.minecraft.client.renderer
    • DimensionSpecialEffects#getSunriseColor -> getSunriseOrSunsetColor
    • GameRenderer
      • processBlurEffect no longer takes in the partial tick float
      • getFov returns a float instead of a double
      • getProjectionMatrix now takes in a float instead of a double
    • ItemModelShaper
      • shapes is now private
      • getItemModel(Item) is removed
      • getItemModel(ResourceLocation) - Gets the baked model associated with the provided ResourceLocation.
      • register is removed
      • getModelManager is removed
      • invalidateCache - Clears the model map.
    • LevelRenderer
      • renderSnowAndRain -> WeatherEffectRenderer
      • tickRain -> tickParticles
      • renderLevel now takes in a GraphicsResourceAllocator
      • renderClouds -> CloudRenderer
      • addParticle is now public
      • globalLevelEvent -> LevelEventHandler
      • entityTarget -> entityOutlineTarget
      • $TransparencyShaderException no longer takes in the throwable cause
    • SectionOcclusionGraph
      • onSectionCompiled -> schedulePropagationFrom
      • update now takes in a LongOpenHashSet that holds the currently loaded section nodes
      • $GraphState is now package-private
      • addSectionsInFrustum now takes in a list to add the render sections to
    • ShapeRenderer#renderShape now takes in a single integer for the color instead of four floats
    • ViewArea
      • repositionCamera now takes in the SectionPos instead of two doubles
      • getRenderSectionAt -> getRenderSection
  • net.minecraft.client.renderer.blockentity
    • BannerRenderer#renderPatterns now takes in a boolean determining the glint render type to use
    • *Renderer classes that constructed LayerDefinitions have now been moved to their associated *Model class
    • SignRenderer$SignModel -> SignModel
  • net.minecraft.client.renderer.chunk.SectionRenderDispatcher now takes in a TracingExecutor rather than just a Executor
    • $CompiledSection#hasNoRenderableLayers -> hasRenderableLayers
    • $RenderSection now takes in a compiled long of the section node
      • setOrigin -> setSectionNode
      • getRelativeOrigin -> getNeighborSectionNode
      • cancelTasks now returns nothing
      • pointOfView - A reference to the location of where the translucent render type is rendered from.
      • resortTransparency no longer takes in the RenderType and returns nothing
      • hasTranslucentGeometry - Returns whether the compiled blocks have a translucent render type.
      • transparencyResortingScheduled - Returns whether the last task was scheduled but not completed.
      • isAxisAlignedWith -> $TranslucencyPointOfView#isAxisAligned
    • $CompileTask is now public
      • No longer Comparable
      • The constructor no longer takes in the distance at creation
      • isHighPriority -> isRecompile
    • $TranslucencyPointOfView - Returns the coordinate representing the view point of the tranlucent render type in this section.
  • net.minecraft.client.renderer.culling.Frustum#cubeInFrustum now returns an int representing the index of the first plane that culled the box
  • net.minecraft.client.renderer.DebugRenderer#render now takes in the Frustum
  • net.minecraft.client.renderer.texture.atlas.sources.PalettedPermutations#loadPaletteEntryFromImage is now private
  • net.minecraft.client.tutorial
    • Tutorial
      • addTimedToast, #removeTimedToast, $TimedToast -> TutorialToast parameter
      • onInput takes in a ClientInput instead of an Input
    • TutorialStepInstance
      • onInput takes in a ClientInput instead of an Input
  • net.minecraft.core
    • Direction
      • getNearest -> getApproximateNearest
      • getNormal -> getUnitVec3i
    • HolderGetter$Provider#get no longer takes in the registry key, instead reading it from the ResourceKey
    • HolderLookup$Provider now implements HolderGetter$Provider
      • asGetterLookup is removed as the interface is a HolderGetter$Provider
      • listRegistries -> listRegistryKeys
    • Registry now implements HolderLookup$RegistryLookup
      • getTags only returns a stream of named holder sets
      • asTagAddingLookup -> prepareTagReload
      • bindTags -> WritabelRegistry#bindTag
      • get -> getValue
      • getOrThrow -> getValueOrThrow
      • getHolder -> get
      • getHolderOrThrow -> getOrThrow
      • holders -> listElements
      • getTag -> get
      • holderOwner, asLookup is removed as Registry is an instance of them
    • RegistryAccess
      • registry -> lookup
      • registryOrThrow -> lookupOrThrow
    • RegistrySynchronization#NETWORKABLE_REGISTRIES -> isNetworkable
  • net.minecraft.core.cauldron.CauldronInteraction
    • FILL_WATER -> fillWaterInteraction, now private
    • FILL_LAVA -> fillLavaInteraction, now private
    • FILL_POWDER_SNOW -> fillPowderSnowInteraction, now private
    • SHULKER_BOX -> shulkerBoxInteraction, now private
    • BANNER -> bannerInteraction, now private
    • DYED_ITEM -> dyedItemIteration, now private
  • net.minecraft.core.dispenser.BoatDispenseItemBehavior now takes in the EntityType to spawn rather that the variant and chest boat boolean
  • net.minecraft.core.particles.DustColorTransitionOptions, DustParticleOptions now takes in integers representing an RGB value instead of Vector3fs.
  • net.minecraft.data.loot
    • BlockLootSubProvider
      • HAS_SHEARS -> hasShears
      • createShearsOnlyDrop is now an instance method
    • EntityLootSubProvider
      • killedByFrog, killedByFrogVariant now take in the getter for the EntityType registry
      • createSheepTable -> createSheepDispatchPool, not one-to-one as the table was replaced with a pool builder given a map of dye colors to loot tables
  • net.minecraft.gametest.framework
    • GameTestHelper#assertEntityPresent, assertEntityNotPresent takes in a bounding box instead of two vectors
    • GameTestInfo#getOrCalculateNorthwestCorner is now public
  • net.minecraft.network.chat.Component#score now takes in a SelectorPattern
  • net.minecraft.network.chat.contents.ScoreContents, SelectorContents is now a record
  • net.minecraft.network.protocol.login.ClientboundGameProfilePacket -> ClientboundLoginFinishedPacket
  • net.minecraft.network.protocol.game
    • ClientboundMoveEntityPacket#getyRot, getxRot now returns a float of the degrees
    • ClientboundPlayerPositionPacket is now a record, taking in a PositionMoverotation representing the change
      • relativeArguments -> relatives
      • yRot, xRot -> ClientboundPalyerRotationPacket
    • ClientboundSetTimePacket is now a record
    • ClientboundRotateHeadPacket#getYHeadRot now returns a float of the degrees
    • ClientboundTeleportEntityPacket is now a record, where the necessary parameters are passed into the packet instead of the entity
    • ServerboundPlayerInputPacket is now a record, taking in an Input
  • net.minecraft.resources.RegistryDataLoader$Loader#loadFromNetwork now takes in a $NetworkedRegistryData, which contains the packed registry entries
  • net.minecraft.server
    • MinecraftServer no longer implements AutoCloseable
      • tickChildren is now protected
      • wrapRunnable is now public
    • ReloadableServerRegistries#reload now takes in a list of pending tags and returns a $LoadResult instead of a layered registry access
    • ReloadableServerResources
      • loadResources now takes in a list of pending tags and the server Executor
      • updateRegistryTags -> updateStaticRegistryTags
    • ServerFunctionLibrary#getTag, ServerFunctionManager#getTag returns a list of command functions
  • net.minecraft.server.level
    • ChunkHolder
      • blockChanged, sectionLightChanged now returns boolean if the information has changed
      • addSaveDependency is now protected, a method within GenerationChunkHolder
    • ChunkTaskPriorityQueue no longer takes in a generic
      • The constructor no longer takes in the maximum number of tasks to do
      • submit now takes in a Runnable rather than an Optional
      • pop returns a $TasksForChunk instead of a raw Stream
    • ChunkTaskPriorityQueueSorter -> ChunkTaskDispatcher
    • ServerPlayer
      • teleportTo takes in a boolean that determines whether the camera should be set
      • INTERACTION_DISTANCE_VERIFICATION_BUFFER -> BLOCK_INTERACTION_DISTANCE_VERIFICATION_BUFFER
        • Also splits into ENTITY_INTERACTION_DISTANCE_VERIFICATION_BUFFER set to 3.0
      • findRespawnPositionAndUseSpawnBlock now deals with TeleportTransition
    • TextFilterClient -> ServerTextFilter
    • ThreadedLevelLightEngine now takes in a ConsecutiveExecutor and ChunkTaskDispatcher instead of a ProcessorMailbox and a ProcessorHandle, respectively
  • net.minecraft.server.packs.resources.ProfiledReloadInstance$State is now a record
  • net.minecraft.sounds.SoundEvent is now a record
  • net.minecraft.tags
    • TagEntry$Lookup#element now takes in a boolean representing if the element is required
    • TagLoader now takes in an $ElementLookup, which functions the same as its previous function parameter
      • build now returns a value of lists
      • loadAndBuild -> loadTagsFromNetwork, loadTagsForExistingRegistries, loadTagsForRegistry, buildUpdatedLookups
    • TagNetworkSerialization$NetworkPayload
      • size -> isEmpty
      • applyToRegistry -> resolve
  • net.minecraft.util
    • FastColor -> ARGB
      • scaleRGB overload with an alpha integer and three floats.
    • Mth#color -> ARGB#color
  • net.minecraft.util.profiling.metrics.MetricCategory#MAIL_BOXES -> CONSECUTIVE_EXECUTORS
  • net.minecraft.util.thread
    • BlockableEventLoop#waitForTasks is now protected
    • ProcessorMailbox no longer implements AutoCloseable
  • net.minecraft.util.worldupdate.WorldUpgrader implements AutoCloseable
  • net.minecraft.world.LockCode now takes in an ItemPredicate instead of a String representing the item name
    • addToTag, fromTag now takes in a HolderLookup$Provider
  • net.minecraft.world.effect
    • MobEffect#applyEffectTick, applyInstantenousEffect, onMobRemoved, onMobHurt now takes in the ServerLevel
    • MobEffectInstance#onMobRemoved, onMobHurt now takes in the ServerLevel
  • net.minecraft.world.entity
    • AgeableMob$AgeableMobGroupData now has a public constructor
    • AnimationState#getAccumulatedTime -> getTimeInMillis
    • Entity no longer implements CommandSource
      • setOnGroundWithMovement now takes in an additional boolean representing whether there is any horizontal collision.
      • getInputVector is now protected
      • isAlliedTo(Entity) -> considersEntityAsAlly
      • teleportTo now takes in an additional boolean that determines whether the camera should be set
      • checkInsideBlocks() -> recordMovementThroughBlocks, not one-to-one as it takes in the movement vectors
      • checkInsideBlocks(Set<BlockState>) -> collectBlockCollidedWith, now private
      • kill now takes in the ServerLevel
      • hurt has been marked as deprecated, to be replaced by hurtServer and hurtClient
        • hurtOrSimulate acts as a helper to determine which to call, also marked as deprecated
      • spawnAtLocation now takes in a ServerLevel
      • isInvulnerableTo -> isInvulnerableToBase, now protected and final
        • isInvulnerableTo is moved to LivingEntity#isInvulnerableTo
      • teleportSetPosition now public and takes in a PositionMoveRotation and Relative set instead of the DimensionTransition
      • createCommandSourceStack -> createCommandSourceStackForNameResolution, not one to one as it takes in the ServerLevel
      • mayInteract now takes in the ServerLevel instead of just the Level
      • setOldRot is now public
      • changeDimension -> teleport, returns ServerPlayer given TeleportTransition
      • canChangeDimensions -> canTeleport
    • EntitySpawnReason#SPAWN_EGG -> SPAWN_ITEM_USE, not one-to-one as this indicates the entity can be spawned from any item
    • EntityType
      • create, loadEntityRecursive, loadEntitiesRecursive, loadStaticEntity now takes in an EntitySpawnReason
      • *StackConfig now takes in a Level instead of a ServerLevel
    • EquipmentTable now has a constructor that takes in a single float representing the slot drop chance for all equipment slots
    • MobSpawnType -> EntitySpawnReason
    • Leashable#tickLeash now takes in the ServerLevel
    • LivingEntity
      • getScale is now final
      • onAttributeUpdated is now protected
      • activeLocationDependentEnchantments now takes in an EquipmentSlot
      • handleRelativeFrictionAndCalculateMovement is now private
      • updateFallFlying is now protected
      • onEffectRemoved -> onEffectsRemoved
      • spawnItemParticles is now public
      • getLootTable -> Entity#getLootTable, wrapped in optional
      • getBaseExperienceReward now takes in the ServerLevel
      • triggerOnDeathMobEffects now takes in the ServerLevel
      • canAttack is removed
      • dropEquipment now takes in the ServerLevel
      • dropExperience now takes in the ServerLevel
      • dropFromLootTable now takes in the ServerLevel
      • actuallyHurt, doHurtTarget now takes in the ServerLevel
      • hasLineOfSight overload with clip contexts and a eye y supplier
      • makePoofParticles is now public
    • Mob
      • pickUpItem, wantsToPickUp now takes in the ServerLevel
      • equipItemIfPossible now takes in the ServerLevel
      • customServerAiStep now takes in the ServerLevel
      • dropPreservedEquipment now takes in the ServerLevel
    • NeutralMob
      • isAngryAt, isAngryAtAllPlayers now takes in the ServerLevel
      • playerDied now takes in the ServerLevel
    • PortalProcessor#getPortalDestination now returns a TeleportTransition
    • PositionMoveRotation
      • of(ClientboundPlayerPositionPacket) -> ofEntityUsingLerpTarget(Entity)
      • of(DimensionTransition) -> of(TeleportTransition)
    • Shearable#shear now takes in the ServerLevel and ItemStack that is shearing the entity
    • RelativeMovement -> Relative, expanded to contain delta movement
    • WalkAnimationState#update now takes in an additional float representing the position scale when moving.
  • net.minecraft.world.entity.ai.behavior
    • StartAttacking now takes in a $TargetFinder and additionally a $StartAttackingCondition
      • Both are functional interfaces that replace the previous functions/predicates, though with an extra ServerLevel parameter
    • StopAttackingIfTargetInvalid now takes in a $TargetErasedCallback and/or a $StopAttackCondition
      • Both are functional interfaces that replace the previous consumers/predicates, though with an extra ServerLevel parameter
    • MeleeAttack#create can now take in a predicate to test the mob for
    • Swim now takes in a generic representing the mob
  • net.minecraft.world.entity.ai.control.LookControl#rotateTowards -> Control#rotateTowards
  • net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal now takes in a $Selector
    • It is a functional interface that replaces the previous predicate, though with an extra ServerLevel parameter
  • net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities now takes in a ServerLevel
  • net.minecraft.world.entity.ai.sensing
    • NearestLivingEntitySensor
      • radiusXZ, radiusY -> Attributes#FOLLOW_RANGE
      • isMatchingEntity now takes in a ServerLevel
    • Sensor
      • TARGETING_RANGE is now private
      • isEntityTargetable, isEntityAttackable, isEntityAttackableIgnoringLineOfSight now take in a ServerLevel
      • wasEntityAttackableLastNTicks, rememberPositives now delas with BiPredicates instead of Predicates
  • net.minecraft.world.entity.ai.targeting.TargetingConditions
    • selector now takes in a $Selector
      • It is a functional interface that replaces the previous predicate, though with an extra ServerLevel parameter
    • test now takes in a ServerLevel
  • net.minecraft.world.entity.ai.village.poi.PoiRecord#codec, PoiSection#codec -> $Packed#CODEC
  • net.minecraft.world.entity.animal
    • Fox$Type -> $Variant
    • MushroomCow$MushroomType -> $Variant
      • $Variant no longer takes in the loot table
    • Salmon now has a variant for its size
    • Wolf
      • getBodyRollAngle -> #getShakeAnim, not one-to-one as the angle is calculated within the render state
      • hasArmor is removed
  • net.minecraft.world.entity.animal.horse.AbstractHorse#followMommy now takes in a ServerLevel
  • net.minecraft.world.entity.boss.enderdragon.EnderDragon#onCrystalDestroyed now takes in a ServerLevel
  • net.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance#doServerTick now takes in a ServerLevel
  • net.minecraft.world.entity.boss.wither.WitherBoss#getHead*Rot -> getHead*Rots, returns all rotations rather than just the provided index
  • net.minecraft.world.entity.decoration
    • ArmorStand default rotations are now public
      • isShowArms -> showArms
      • isNoBasePlate -> showBasePlate
    • PaintingVariant now takes in a title and author Component
  • net.minecraft.world.entity.item.ItemEntity#getSpin is now static
  • net.minecraft.world.entity.monster.Monster#isPreventingPlayerRest now takes in a ServerLevel
  • net.minecraft.world.entity.monster.breeze.Breeze#getSnoutYPosition -> getFiringYPosition
  • net.minecraft.world.entity.monster.hoglin.HoglinBase#hurtAndThrowTarget now takes in a ServerLevel
  • net.minecraft.world.entity.monster.piglin.PiglinAi#isWearingGold -> #isWearingSafeArmor
  • net.minecraft.world.entity.npc.InventoryCarrier#pickUpItem now takes in a ServerLevel
  • net.minecraft.world.entity.player
    • Player#disableShield now takes in the stack to apply the cooldown to
    • Inventory
      • findSlotMatchingUnusedItem -> findSlotMatchingCraftingIngredient
      • swapPaint -> setSelectedHotbarSlot
      • StackedContents -> StackedItemContents
  • net.minecraft.world.entity.projectile
    • AbstractArrow#inGround -> IN_GROUND, now an EntityDataAccessor
      • Protected accessible via isInGround and setInGround
    • ThrowableItemProjectile can now take in an ItemStack of the item thrown
  • net.minecraft.world.entity.raid.Raid#getLeaderBannerInstance -> getOminousBannerInstance
  • net.minecraft.world.entity.vehicle
    • Boat$Type now takes in the supplied boat item and the translation key for the item, but no longer take in the planks they are made from
    • ContainerEntity
      • *LootTable* -> ContainerLootTable
      • chestVehicleDestroyed now takes in a ServerLevel
    • VehicleEntity
      • destroy now takes in a seerverLevel
      • getDropItem is now protected
  • net.minecraft.world.item
    • BoatItem now takes in an EntityType instead of the variant and chest boolean
    • ItemStack#hurtEnemy, postHurtEnemy now take in a LivingEntity instead of a Player
    • SmithingTemplateItem now takes in the Item.Properties instead of hardcoding it, also true for static initializers
    • UseAnim -> ItemUseAnimation
  • net.minecraft.world.item.crafting.ShulkerBoxColoring -> TransmuteRecipe, expanded to copy any data stored on the item to the result item
  • net.minecraft.world.item.enchantment.EnchantmentHelper
    • onProjectileSpawned now takes in a Projectile instead of an AbstractArrow
  • net.minecraft.world.item.enchantment.effects.DamageItem -> ChangeItemDamage
  • net.minecraft.world.level
    • GameRules takes in a FeatureFlagSet during any kind of construction
      • $IntegerValue#create takes in a FeatureFlagSet
      • $Type takes in a FeatureFlagSet
    • Level
      • setSpawnSettings no longer takes in a boolean to determine whether to spawn friendlies
      • getGameRules -> ServerLevel#getGameRules
    • LevelAccessor now implements ScheduledTickAccess, an interface that now contains the tick scheduling methods that were originally on LevelAccessor
      • neighborShapeChanged switches the order of the BlockState and neighbor BlockPos parameters
    • LevelHeightAccessor
      • getMinBuildHeight -> getMinY
      • getMaxBuildHeight -> getMaxY, this value is one less than the previous version
      • getMinSection -> getMinSectionY
      • getMaxSection -> getMaxSectionY, this value is one less than the previous version
    • NaturalSpawner#spawnForChunk has been split into two methods: getFilteredSpawningCategories, and spawnForChunk
  • net.minecraft.world.level.biome#Biome#getPrecipitationAt, coldEnoughToSnow, warmEnoughToRain, shouldMeltFrozenOceanIcebergSlightly now takes in an int representing the the base height of the biome
  • net.minecraft.world.level.block
    • Block
      • shouldRenderFace takes in the relative state for the face being checked, no longer passing in the BlockGetter or BlockPoss.
      • updateEntityAfterFallOn -> updateEntityMovementAfterFallOn
      • $BlockStatePairKey -> FlowingFluid$BlockStatePairKey, now package private
      • getDescriptionId -> BlockBehaviour#getDescriptionId, also a protected field descriptionId
    • ChestBlock constructor switched its parameter order
    • Portal#getPortalDestination now returns TeleportTransition
  • net.minecraft.world.level.block.entity
    • AbstractFurnaceBlockEntity#serverTick now takes in a ServerLevel instead of a Level
    • BrushableBlockEntity
      • brush now takes in the level and stack performing the brushing behavior
      • unpackLootTable is now private
      • checkReset now takes in the server level
  • net.minecraft.world.level.block.state
    • BlockBehaviour
      • getOcclusionShape, getLightBlock, propagatesSkylightDown only takes in the BlockState, not the BlockGetter or BlockPos
      • getLootTable now returns an Optional, also a protected field drops
      • $BlockStateBase#getOcclusionShape, getLightBlock, getFaceOcclusionShape, propagatesSkylightDown, isSolidRender no longer takes in the BlockGetter or BlockPos
      • $BlockStateBase#getOffset no longer takes in the BlockGetter
      • $OffsetFunction#evaluate no longer takes in the BlockGetter
      • $Properties#dropsLike -> overrideLootTable
    • StateHolder#findNextInCollection now takes in a List instead of a Collection
  • net.minecraft.world.level.chunk
    • ChunkAccess
      • addPackedPostProcess now takes in a ShortList instead of a single short
      • getTicksForSerialization now takes in a long of the game time
      • unsaved is now private
      • setUnsaved -> markUnsaved, tryMarkSaved
      • $TicksToSave -> $PackedTicks
    • ChunkSource#setSpawnSettings no longer takes in a boolean to determine whether to spawn friendlies
    • LevelChunk#postProcessGeneration now takes in a ServerLevel
    • Palette#copy now takes in a PaletteResize
  • net.minecraft.world.level.chunk.status.WorldGenContext now takes in an Executor or the main thread rather than a processor handle mail box
    • The construtor also takes in a LevelChunk$UnsavedListener for when a chunk is marked as dirty
  • net.minecraft.world.level.chunk.storage
    • ChunkSerializer -> SerializableChunkData
    • ChunkStorage#write now takes in a supplied CompoundTag instead of the instance itself
    • SectionStorage now takes in a second generic representing the packed form of the storage data
      • The constructor now takes in the packed codec, a function to convert the storage to a packed format, and a function to convert the packed and dirty runnable back into the storage.
  • net.minecraft.world.level.levelgen
    • Aquifer$FluidStatus is now a record
    • WorldDimensions#withOverworld now takes in a HolderLookup instead of the Registry itself
    • BlendingData now has a packed and unpacked state for serializing the interal data as a simple object
  • net.minecraft.world.level.levelgen.material.MaterialRuleList now takes in an array instead of a list
  • net.minecraft.world.level.levelgen.placement.PlacementContext#getMinBuildHeight -> getMinY
  • net.minecraft.world.level.levelgen.structure.pools.StructurePoolElement#getShuffledJigsawBlocks now returns a StructureTemplate$JigsawBlockInfo
  • net.minecraft.world.level.lighting
    • LevelLightEngine#lightOnInSection -> lightOnInColumn
    • LightEngine
      • hasDifferentLightProperties, getOcclusionShape no longer takes in the BlockGetter or BlockPos
      • getOpacity no longer takes in the BlockPos
      • shapeOccludes no longer takes in the two longs representing the packed positions
  • net.minecraft.world.level.material
    • FlowingFluid
      • spread now takes in the BlockState at the current position
      • getSlopeDistance previous parameters have been merged into a $SpreadContext object
      • spread, getNewLiquid, canConvertToSource, getSpread now takes in a ServerLevel
    • Fluid
      • tick now takes in the BlockState at the current position
      • tick and randomTick now take in the ServerLevel
    • FluidState
      • tick now takes in the BlockState at the current position
      • tick and randomTick now take in the ServerLevel
    • MapColor#calculateRGBColor -> calculateARGBColor
  • net.minecraft.world.level.portal
    • DimensionTransition -> TeleportTransition
      • pos -> position
      • speed -> deltaMovement
      • The constructor can now take in a set of Relatives to indicate in what motions should the positions be moved relative to another
    • PortalShape#createPortalBlocks now takes in a LevelAccessor
  • net.minecraft.world.level.saveddata.SavedData#save(File, HolderLookup$Provider) now returns CompoundTag, not writing the data to file in the method
  • net.minecraft.world.level.storage
    • DimensionDataStorage now implements AutoCloseable
      • The constructor takes in a Path instead of a File
      • save -> scheduleSave and saveAndJoin
    • LevelData#getGameRules -> ServerLevelData#getGameRules
  • net.minecraft.world.phys.BlockHitResult now takes in a boolean representing if the world border was hit
    • Adds in two helpers hitBorder, isWorldBorderHit
  • net.minecraft.world.ticks
    • ProtoChunkTicks#load now takes in a list of saved ticks
    • SavedTick#loadTickList now returns a list of saved ticks, rather than consuming them
    • SerializableTickContainer#save -> pack

List of Removals

  • com.mojang.blaze3d.Blaze3D
    • process
    • render
  • com.mojang.blaze3d.pipeline.RenderPipeline
    • Replaced by com.mojang.blaze3d.framegraph.* and com.mojang.blaze3d.resources.*
  • com.mojang.blaze3d.platform.NativeImage
    • setPixelLuminance
    • getRedOrLuminance, getGreenOrLuminance, getBlueOrLuminance
    • blendPixel
    • asByteArray
  • com.mojang.blaze3d.systems.RenderSystem
    • glGenBuffers
    • glGenVertexArrays
    • _setShaderTexture
    • applyModelViewMatrix
  • net.minecraft.Util#wrapThreadWithTaskName(String, Supplier)
  • net.minecraft.advancements.critereon.EntitySubPredicates#BOAT
  • net.minecraft.client.Options#setKey
  • net.minecraft.client.gui.screens.inventory.EnchantmentScreen#time
  • net.minecraft.client.multiplayer
    • ClientCommonPacketListenerImpl#strictErrorHandling
    • ClientLevel#isLightUpdateQueueEmpty
    • CommonListenerCookie#strictErrorHandling
  • net.minecraft.client.particle.ParticleRenderType#PARTICLE_SHEET_LIT
  • net.minecraft.client.renderer
    • GameRenderer#resetProjectionMatrix
    • LevelRenderer
      • playJukeboxSong
      • clear
    • PostChain
      • getTempTarget, addTempTarget
    • PostPass
      • setOrthoMatrix
      • getFilterMode
  • net.minecraft.client.renderer.block.model.BlockModel#fromString
  • net.minecraft.client.renderer.texture
    • AbstractTexture#blur, mipmap
    • TextureManager#bindForSetup
  • net.minecraft.commands.arguments.coordinates.WorldCoordinates#current
  • net.minecraft.core
    • Direction#fromDelta
    • Registry#getOrCreateTag, getTagNames, resetTags
  • net.minecraft.server.MinecraftServer
    • isSpawningAnimals
    • areNpcsEnabled
  • net.minecraft.server.level
    • GenerationChunkHolder#getGenerationRefCount
    • ServerPlayer
      • setPlayerInput
      • teleportTo(ServerLevel, double, double, double, float, float, boolean)
  • net.minecraft.tags
    • TagManager
    • TagManagerSerialization$TagOutput
  • net.minecraft.world.entity
    • AnimationState#updateTime
    • Entity
      • walkDist0, walkDist
      • wasOnFire
      • tryCheckInsideBlocks
    • EntitySelector$MobCanWearArmorEntitySelector
  • net.minecraft.world.entity.ai.sensing
    • BreezeAttackEntitySensor#BREEZE_SENSOR_RADIUS
    • TemptingSensor#TEMPTATION_RANGE
  • net.minecraft.world.entity.animal
    • Cat#getTextureId
    • Squid#setMovementVector
    • Wolf#isWet
  • net.minecraft.world.entity.boss.dragon.EnderDragon
    • getLatencyPos
    • getHeadPartYOffset
  • net.minecraft.world.entity.monster.Zombie#supportsBreakDoorGoal
  • net.minecraft.world.entity.npc.Villager#setChasing, isChasing
  • net.minecraft.world.entity.projectile
    • AbstractArrow#shotFromCrossbow
    • ThrowableProjectile(EntityType, LivingEntity, Level)
  • net.minecraft.world.item
    • BannerPatternItem#getDisplayName
    • ItemStack#LIST_STREAM_CODEC
  • net.minecraft.world.level.BlockGetter#getMaxLightLevel
  • net.minecraft.world.level.block.entity.JigsawBlockEntity$JointType#byName
  • net.minecraft.world.level.block.state.BlockBehaviour#isOcclusionShapeFullBlock
  • net.minecraft.world.level.chunk.ChunkAccess#setBlendingData
  • net.minecraft.world.level.storage.loot.LootDataType#deserialize
  • net.minecraft.world.phys.AABB#getBottomCenter
  • net.minecraft.world.phys.shapes.Shapes#getFaceShape
  • net.minecraft.world.ticks.SavedTick#saveTick

Minecraft 1.21.2/3 -> 1.21.4 Mod Migration Primer

This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.2/3 to 1.21.4. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.

This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.

If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.

Pack Changes

There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.

Client Items

Minecraft has moved the lookup and definition of how an item should be rendered to its own data generated system, which will be referred to as Client Items, located at assets/<namespace>/items/<path>.json. Client Items is similar to the block state model definition, but has the potential to have more information enscribed in the future. Currently, it functions as simply a linker to the models used for rendering.

All client items contain some ItemModel$Unbaked using the model field. Each unbaked model has an associated type, which defines how the item should be set up for rendering, or rendered in one specific case. These types can be found within ItemModels. This primer will review all but one type, as that unbaked model type is specifically for bundles when selecting an item.

The item also contains a properties field which holds some metadata-related parameters. Currently, it only specifies a boolean that, when false, make the hand swap the currently held item instantly rather than animate the hand coming up.

// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
    "model": {
        "type": "" // Set type here
        // Add additional parameters
    },
    "properties": {
        // When false, disables animation when swapping this item into the hand
        "hand_animation_on_swap": false
    }
}

A Basic Model

The basic model definition is handled by the minecraft:model type. This contains two fields: model, to define the relative location of the model JSON, and an optional list of tints, to define how to tint each index.

model points to the model JSON, relative to assets/<namespace>/models/<path>.json. In most instances, a client item defintion will look something like this:

// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
    "model": {
        "type": "minecraft:model",
        // Points to 'assets/examplemod/models/item/example_item.json'
        "model": "examplemod:item/example_item"
    }
}

Tint Sources

In model JSONs, some element faces will have a tintindex field which references some index into the tints list in the minecraft:model unbaked model type. The list of tints are ItemTintSources, which are all defined in net.minecraft.client.color.item.*. All defined tint sources can be found within ItemTintSources, like minecraft:constant for a constant color, or minecraft:dye, to use the color of the DataComponents#DYED_COLOR or default if not present. All tint sources must return an opaque color, though all sources typically apply this by calling ARGB#opaque.

// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
    "model": {
        "type": "minecraft:model",
        // Points to 'assets/examplemod/models/item/example_item.json'
        "model": "examplemod:item/example_item",
        // A list of tints to apply
        "tints": [
            {
                // For when tintindex: 0
                "type": "minecraft:constant",
                // 0x00FF00 (or pure green)
                "value": 65280
            },
            {
                // For when tintindex: 1
                "type": "minecraft:dye",
                // 0x0000FF (or pure blue)
                // Only is called if `DataComponents#DYED_COLOR` is not set
                "default": 255
            }
        ]
    }
}

To create your own ItemTintSource, you need to implement the calculate method register the MapCodec associated for the type field. calculate takes in the current ItemStack, level, and holding entity and returns an RGB integer with an opaque alpha, defining how the layer should be tinted.

Then, the MapCodec needs to be registered to ItemTintSources#ID_MAPPER, though this field is private by default, so some access changes or reflection needs to be applied.

// The item source class
public record FromDamage(int defaultColor) implements ItemTintSource {

    public static final MapCodec<FromDamage> MAP_CODEC = RecordCodecBuilder.mapCodec(instance ->
        instance.group(
            ExtraCodecs.RGB_COLOR_CODEC.fieldOf("default").forGetter(FromDamage::defaultColor)
        ).apply(instance, FromDamage::new)
    );

    public FromDamage(int defaultColor) {
        this.defaultColor = ARGB.opaque(defaultColor);
    }

    @Override
    public int calculate(ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity) {
        return stack.isDamaged() ? ARGB.opaque(stack.getBarColor()) : defaultColor;
    }

    @Override
    public MapCodec<FromDamage> type() {
        return MAP_CODEC;
    }
}

// Then, in some initialization location where ItemTintSources#ID_MAPPER is exposed
ItemTintSources.ID_MAPPER.put(
    // The registry name
    ResourceLocation.fromNamespaceAndPath("examplemod", "from_damage"),
    // The map codec
    FromDamage.MAP_CODEC
);
// For some object in the 'tints' array
{
    "type": "examplemod:from_damage",
    // 0x0000FF (or pure blue)
    // Only is called if the item has not been damaged yet
    "default": 255
}

Ranged Property Model

Ranged property models, as defined by the minecraft:range_dispatch unbaked model type, are the most similar to the previous item override system. Essentially, the type defines some item property that can be scaled along with a list of thresholds and associated models. The model chosen is the one with the closest threshold value that is not over the property (e.g. if the property value is 4 and we have thresholds 3 and 5, 3 would be chosen as it is the cloest without going over). The item property is defined via a RangeSelectItemModelProperty, which takes in the stack, level, entity, and some seeded value to get a float, usually scaled betwen 0 and 1 depending on the implementation. All properties can be found within net.minecraft.client.renderer.item.properties.numeric.* and are registered in RangeSelectItemModelProperties, such as minecraft:cooldown, for the cooldown percentage, or minecraft:count, for the current number of items in the stack or percentage of the max stack size when normalized.

// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
    "model": {
        "type": "minecraft:range_dispatch",

        // The `RangeSelectItemModelProperty` to use
        "property": "minecraft:count",
        // A scalar to multiply to the computed property value
        // If count was 0.3 and scale was 0.2, then the threshold checked would be 0.3*0.2=0.06
        "scale": 1,
        "fallback": {
            // The fallback model to use if no threshold matches
            // Can be any unbaked model type
            "type": "minecraft:model",
            "model": "examplemod:item/example_item"
        },

        // ~~ Properties defined by `Count` ~~
        // When true, normalizes the count using its max stack size
        "normalize": true,

        // ~~ Entries with threshold information ~~
        "entries": [
            {
                // When the count is a third of its current max stack size
                "threshold": 0.33,
                "model": {
                    // Can be any unbaked model type
                }
            },
            {
                // When the count is two thirds of its current max stack size
                "threshold": 0.66,
                "model": {
                    // Can be any unbaked model type
                }
            }
        ]
    }
}

To create your own RangeSelectItemModelProperty, you need to implement the get method register the MapCodec associated for the type field. get takes in the stack, level, entity, and seeded value and returns an arbitrary float to be interpreted by the ranged dispatch model.

Then, the MapCodec needs to be registered to RangeSelectItemModelProperties#ID_MAPPER, though this field is private by default, so some access changes or reflection needs to be applied.

// The ranged property class
public record AppliedEnchantments() implements RangeSelectItemModelProperty {

    public static final MapCodec<AppliedEnchantments> MAP_CODEC = MapCodec.unit(new AppliedEnchantments());

    @Override
    public float get(ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed) {
        return (float) stack.getEnchantments().size();
    }

    @Override
    public MapCodec<AppliedEnchantments> type() {
        return MAP_CODEC;
    }
}

// Then, in some initialization location where RangeSelectItemModelProperties#ID_MAPPER is exposed
RangeSelectItemModelProperties.ID_MAPPER.put(
    // The registry name
    ResourceLocation.fromNamespaceAndPath("examplemod", "applied_enchantments"),
    // The map codec
    AppliedEnchantments.MAP_CODEC
);
// For some client item in 'model'
{
    "type": "minecraft:range_dispatch",

    // The `RangeSelectItemModelProperty` to use
    "property": "examplemod:applied_enchantments",
    // A scalar to multiply to the computed property value
    "scale": 0.5,
    "fallback": {
        // The fallback model to use if no threshold matches
        // Can be any unbaked model type
        "type": "minecraft:model",
        "model": "examplemod:item/example_item"
    },

    // ~~ Properties defined by `AppliedEnchantments` ~~
    // N/A (no arguments to constructor)

    // ~~ Entries with threshold information ~~
    "entries": [
        {
            // When there is one enchantment present
            // Since 1 * the scale 0.5 = 0.5
            "threshold": 0.5,
            "model": {
                // Can be any unbaked model type
            }
        },
        {
            // When there are two enchantments present
            "threshold": 1,
            "model": {
                // Can be any unbaked model type
            }
        }
    ]
}

Select Property Model

Select property models, as defined by the minecraft:select unbaked model type, are functionally similar to ranged property models, except now it switches on some property, typically an enum. The item property is defined via a SelectItemModelProperty, which takes in the stack, level, entity, some seeded value, and the current display context to get one of the property values. All properties can be found within net.minecraft.client.renderer.item.properties.select.* and are registered in SelectItemModelProperties, such as minecraft:block_state, for the stringified value of a specified block state property, or minecraft:display_context, for the current ItemDisplayContext.

// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
    "model": {
        "type": "minecraft:select",

        // The `SelectItemModelProperty` to use
        "property": "minecraft:display_context",
        "fallback": {
            // The fallback model to use if no threshold matches
            // Can be any unbaked model type
            "type": "minecraft:model",
            "model": "examplemod:item/example_item"
        },

        // ~~ Properties defined by `DisplayContext` ~~
        // N/A (no arguments to constructor)

        // ~~ Switch cases based on Selectable Property ~~
        "cases": [
            {
                // When the display context is `ItemDisplayContext#GUI`
                "when": "gui",
                "model": {
                    // Can be any unbaked model type
                }
            },
            {
                // When the display context is `ItemDisplayContext#FIRST_PERSON_RIGHT_HAND`
                "when": "firstperson_righthand",
                "model": {
                    // Can be any unbaked model type
                }
            }
        ]
    }
}

To create your own SelectItemModelProperty, you need to implement the get method register the SelectItemModelProperty$Type associated for the type field. get takes in the stack, level, entity, seeded value, and display context and returns an encodable object to be interpreted by the select model.

Then, the MapCodec needs to be registered to SelectItemModelProperties#ID_MAPPER, though this field is private by default, so some access changes or reflection needs to be applied.

// The select property class
public record StackRarity() implements SelectItemModelProperty<Rarity> {

    public static final SelectItemModelProperty.Type<StackRarity, Rarity> TYPE = SelectItemModelProperty.Type.create(
        // The map codec for this property
        MapCodec.unit(new StackRarity()),
        // The codec for the object being selected
        Rarity.CODEC
    );

    @Nullable
    @Override
    public Rarity get(ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed, ItemDisplayContext displayContext) {
        // When null, uses the fallback model
        return stack.get(DataComponents.RARITY);
    }

    @Override
    public SelectItemModelProperty.Type<StackRarity, Rarity> type() {
        return TYPE;
    }
}

// Then, in some initialization location where SelectItemModelProperties#ID_MAPPER is exposed
SelectItemModelProperties.ID_MAPPER.put(
    // The registry name
    ResourceLocation.fromNamespaceAndPath("examplemod", "rarity"),
    // The property type
    StackRarity.TYPE
);
// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
    "model": {
        "type": "minecraft:select",

        // The `SelectItemModelProperty` to use
        "property": "examplemod:rarity",
        "fallback": {
            // The fallback model to use if no threshold matches
            // Can be any unbaked model type
            "type": "minecraft:model",
            "model": "examplemod:item/example_item"
        },

        // ~~ Properties defined by `StackRarity` ~~
        // N/A (no arguments to constructor)

        // ~~ Switch cases based on Selectable Property ~~
        "cases": [
            {
                // When rarity is `Rarity#UNCOMMON`
                "when": "uncommon",
                "model": {
                    // Can be any unbaked model type
                }
            },
            {
                // When rarity is `Rarity#RARE`
                "when": "rare",
                "model": {
                    // Can be any unbaked model type
                }
            }
        ]
    }
}

Conditional Property Model

Conditional property models, as defined by the minecraft:condition unbaked model type, are functionally similar to ranged property models, except now it switches on boolean. These are usually combined with range dispatch, such as when pulling the bow. The item property is defined via a ConditionalItemModelProperty, which takes in the stack, level, entity, some seeded value, and the current display context to get a true of false statement. All properties can be found within net.minecraft.client.renderer.item.properties.conditional.* and are registered in ConditionalItemModelProperties, such as minecraft:damaged, for if the item is damaged, or minecraft:has_component, if it has a given data component.

// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
    "model": {
        "type": "minecraft:condition",

        // The `SelectItemModelProperty` to use
        "property": "minecraft:damaged",

        // ~~ Properties defined by `Damaged` ~~
        // N/A (no arguments to constructor)

        // ~~ What the boolean outcome is ~~
        "on_true": {
            // Can be any unbaked model type
        },
        "on_false": {
            // Can be any unbaked model type
        }
    }
}

To create your own ConditionalItemModelProperty, you need to implement the get method register the MapCodec associated for the type field. get takes in the stack, level, entity, seeded value, and display context and returns a boolean to be interpreted by on_true and on_false, respectively.

Then, the MapCodec needs to be registered to ConditionalItemModelProperties#ID_MAPPER, though this field is private by default, so some access changes or reflection needs to be applied.

// The predicate property class
public record TimePeriod(int month, MinMaxBounds.Ints dates, boolean enabled) implements ConditionalItemModelProperty {

    public static final MapCodec<TimePeriod> MAP_CODEC = RecordCodecBuilder.mapCodec(instance ->
        instance.group(
            Codec.intRange(1, 12).fieldOf("month").forGetter(TimePeriod::month),
            MinMaxBounds.Ints.CODEC.fieldOf("dates").forGetter(TimePeriod::dates)
        ).apply(instance, TimePeriod::new)
    );

    public TimePeriod(int month, MinMaxBounds.Ints dates) {
        this.month = month;
        this.dates = dates;

        Calendar cal = Calendar.getInstance();
        this.enabled = cal.get(Calendar.MONTH) + 1 == this.month
            && this.dates.matches(cal.get(Calendar.DATE));
    }

    @Override
    public boolean get(ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed, ItemDisplayContext context) {
        return this.enabled;
    }

    @Override
    public MapCodec<TimePeriod> type() {
        return MAP_CODEC;
    }
}

// Then, in some initialization location where ConditionalItemModelProperties#ID_MAPPER is exposed
ConditionalItemModelProperties.ID_MAPPER.put(
    // The registry name
    ResourceLocation.fromNamespaceAndPath("examplemod", "time_period"),
    // The map codec
    TimePeriod.MAP_CODEC
);
// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
    "model": {
        "type": "minecraft:condition",

        // The `SelectItemModelProperty` to use
        "property": "examplemod:time_period",

        // ~~ Properties defined by `TimePeriod` ~~
        // Month of July
        "month": 7,
        "dates": {
            // Between July 1st - 14th
            "min": 1,
            "max": 14
        },

        // ~~ What the boolean outcome is ~~
        "on_true": {
            // Can be any unbaked model type
        },
        "on_false": {
            // Can be any unbaked model type
        }
    }
}

Composite Model

Composite models, defined by minecraft:composite, are essentially a combination of other model types to render. Specifically, this sets up multiple players to overlay models on top of one another when rendering.

// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
    "model": {
        "type": "minecraft:composite",

        // Will render in the order they appear in the list
        "models": [
            {
                // Can be any unbaked model type
            },
            {
                // Can be any unbaked model type
            }
        ]
    }
}

Special Dynamic Models

Special dynamic models, as defined by the minecraft:special unbaked model type, are the new system for block entity without level renderers (e.g., chests, banners, and the like). Instead of storing a baked model, these provide a render method to call. The special model wrapper takes in a base model used for grabbing the basic model settings (not the elements) and a SpecialModelRenderer. All special model renderers can be found within net.minecraft.client.renderer.special.* and are registered in SpecialModelRenderers.

// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
    "model": {
        "type": "minecraft:special",

        // The model to read the particle texture and display transformation from
        "base": "minecraft:item/template_skull",
        "model": {
            // The special model renderer to use
            "type": "minecraft:head",

            // ~~ Properties defined by `SkullSpecialRenderer.Unbaked` ~~
            // The type of the skull block
            "kind": "wither_skeleton"
        }
    }
}

To create your own SpecialModelRenderer, you need to implement both the renderer and the $Unbaked model to read the data from the JSON. The $Unbaked model creates the SpecialModelRenderer via bake and is registered using a MapCodec for its type. The SpecialModelRenderer then extracts the necessary data from the stack needed to render via extractArgument and passes that to the render method. If you do not need any information from the stack, you can implement NoDataSpecialModelRenderer instead.

Then, the MapCodec needs to be registered to SpecialModelRenderers#ID_MAPPER, though this field is private by default, so some access changes or reflection needs to be applied.

If your item is a held block, it also needs to be added to the SpecialModelRenderers#STATIC_BLOCK_MAPPING for specific rendering scenarios via BlockRenderDispatcher#renderSingleBLock (e.g. in minecart, or picked up by endermen). Both the default model renderer and the special model renderer are called in this method; allowing for both the static block model and the dynamic special model to be rendered at the same time. As this map is immutable, you will either need to replace it or hook into SpecialBlockModelRenderer and somehow add to the stored map there.

// The special renderer
public record SignSpecialRenderer(WoodType defaultType, Model model) implements SpecialModelRenderer<WoodType> {

    // Render the model
    @Override
    public void render(@Nullable WoodType type, ItemDisplayContext displayContext, PoseStack pose, MultiBufferSource bufferSource, int light, int overlay, boolean hasFoil) {
        VertexConsumer consumer = Sheets.getSignMaterial(type).buffer(bufferSource, this.model::renderType);
        this.model.renderToBuffer(pose, consumer, light, overlay);
    }

    // Get the wood type from the stack
    @Nullable
    @Override
    public WoodType extractArgument(ItemStack stack) {
        return (stack.getItem() instanceof BlockItem item && item.getBlock() instanceof SignBlock sign)
            ? sign.type() : this.defaultType;
    }

    // The model to read the json from
    public static record Unbaked(WoodType defaultType) implements SpecialModelRenderer.Unbaked {

        public static final MapCodec<SignSpecialRenderer.Unbaked> MAP_CODEC = RecordCodecBuilder.mapCodec(instance ->
            instance.group(
                WoodType.CODEC.fieldOf("default").forGetter(SignSpecialRenderer.Unbaked::defaultType)
            ).apply(instance, SignSpecialRenderer.Unbaked::new)
        );

        // Create the special model renderer, or null if it fails
        @Nullable
        @Override
        public SpecialModelRenderer<?> bake(EntityModelSet modelSet) {
            return new SignSpecialRenderer(
                this.defaultType,
                SignRenderer.createSignModel(modelSet, defaultType, true)
            )
        }

        @Overrides
        public MapCodec<SignSpecialRenderer.Unbaked> type() {
            return MAP_CODEC;
        }
    }
}

// Then, in some initialization location where SpecialModelRenderers#ID_MAPPER is exposed
SpecialModelRenderers.ID_MAPPER.put(
    // The registry name
    ResourceLocation.fromNamespaceAndPath("examplemod", "sign"),
    // The map codec
    SignSpecialRenderer.Unbaked.MAP_CODEC
);
// Let assume we can add directly to SpecialModelRenderers#STATIC_BLOCK_MAPPING as well
// We'll have a Block EXAMPLE_SIGN
SpecialModelRenderers.STATIC_BLOCK_MAPPING.put(
    // The block with a special rendering as an item
    EXAMPLE_SIGN,
    // The unbaked renderer to use
    new SignSpecialRenderer.Unbaked(WoodType.BAMBOO)
);
// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
    "model": {
        "type": "minecraft:special",

        // The model to read the particle texture and display transformation from
        "base": "minecraft:item/bamboo_sign",
        "model": {
            // The special model renderer to use
            "type": "examplemod:sign",

            // ~~ Properties defined by `SignSpecialRenderer.Unbaked` ~~
            // The default wood type if none can be found
            "default": "bamboo"
        }
    }
}

Rendering an Item

Rendering an item is now done through the ItemModelResolver and ItemStackRenderState. This is similar to how the EntityRenderState works: first, the ItemModelResolver sets up the ItemStackRenderState, then the state is rendered via ItemStackRenderState#render.

Let’s start with the ItemStackRenderState. For rendering, the only one we care about the following methods: isEmpty, isGui3d, usesBlockLight, transform, and render. isEmpty is used to determine whether the stack should render at all. Then isGui3d, usesBlockLight, and transform are used in their associated contexts to properly position the stack to render. Finally, render takes in the pose stack, buffer source, packed light, and overlay texture to render the item in its appropriate location.

ItemModelResolver is responsible for setting the information on the ItemStackRenderState needed to render. This is done through updateForLiving for items held by living entities, updateForNonLiving for items held by other kinds of entities, and updateforTopItem, for all other scenarios. updateForItem, which the previous two methods delegate to, take in the render state, the stack, the display context, if the stack is in the left hand, the level, the entity, and some seeded value. This will effectively clear the previous state via ItemStackRenderState#clear and then set up the new state via a delegate to ItemModel#update. The ItemModelResolver can always be obtained via Minecraft#getItemModelResolver, if you are not within a renderer context (e.g., block entity, entity).

// In its most simple form, assuming you are not doing any transformations (which you should as necessary)
public class ExampleRenderer {
    private final ItemStackRenderState state = new ItemStackRenderState();

    public void render(ItemStack stack, Level level, PoseStack pose, MultiBufferSource bufferSource) {
        // First update the render state
        Minecraft.getInstance().getItemModelResolver().updateForTopItem(
            // The render state
            this.state,
            // The stack to update the state with
            stack,
            // The display context to render within
            ItemDisplayContext.NONE,
            // Whether it is in the left hand of the entity (use false when unknown)
            false,
            // The current level (can be null)
            level,
            // The holding entity (can be null)
            null,
            // An arbitrary seed value
            0
        );

        // Perform any desired transformations here

        // Then render the state
        this.state.render(
            // The pose stack with the required transformations
            pose,
            // The buffer sources
            bufferSource,
            // The packed light value
            LightTexture.FULL_BRIGHT,
            // The overlay texture value
            OverlayTexture.NO_OVERLAY
        );
    }
}

Custom Item Model Defintions

To make a custom item model definition, we need to look at a few more methods in ItemStackRenderState which, although you won’t typically use, is useful to understand: ensureCapacity and newLayer. Both of these are responsible for ensuring there are enough ItemStackRenderState$LayerRenderStates if you happen to be overlaying multiple models at once. Effectively, every time you are planning to render something in an unbaked model, newLayer should be called. If you plan on rendering multiple things on top of one another, then ensureCapacity should be set with the number of layers that you plan to render before calling newLayer.

An item model definition is made up of the ItemModel, which functionally defines a ‘baked model’ and its ItemModel$Unbaked, used for serialization.

The unbaked variant has two methods: bake, which is used to create the ItemModel, and type, which references the MapCodec to be registered to ItemModels#ID_MAPPER, though this field is private by default, so some access changes or reflection needs to be applied. bake takes in the $BakingContext, which contains the ModelBaker to get BakedModels, the EntityModelSet for entity models, and the missing ItemModel.

The baked variant only has one method update, which is responsible for setting up everything necessary on the ItemStackRenderState. The model does no rendering itself.

public record RenderTypeModelWrapper(BakedModel model, RenderType type) implements ItemModel {

    // Update the render state
    @Override
    public void update(ItemStackRenderState state, ItemStack stack, ItemModelResolver resolver, ItemDisplayContext displayContext, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed) {
        ItemStackRenderState.LayerRenderState layerState = state.newLayer();
        if (stack.hasFoil()) {
            layerState.setFoilType(ItemStackRenderState.FoilType.STANDARD);
        }
        layerState.setupBlockModel(this.model, this.type);
    }

    public static record Unbaked(ResourceLocation model, RenderType type) implements ItemModel.Unbaked {
        // Create a render type map for the codec
        private static final BiMap<String, RenderType> RENDER_TYPES = Util.make(HashBiMap.create(), map -> {
            map.put("translucent_item", Sheets.translucentItemSheet());
            map.put("cutout_block", Sheets.cutoutBlockSheet());
        });
        private static final Codec<RenderType> RENDER_TYPE_CODEC = ExtraCodecs.idResolverCodec(Codec.STRING, RENDER_TYPES::get, RENDER_TYPES.inverse()::get);

        // The map codec to register
        public static final MapCodec<RenderTypeModelWrapper.Unbaked> MAP_CODEC = RecordCodecBuilder.mapCodec(instance ->
            instance.group(
                ResourceLocation.CODEC.fieldOf("model").forGetter(RenderTypeModelWrapper.Unbaked::model),
                RENDER_TYPE_CODEC.fieldOf("render_type").forGetter(RenderTypeModelWrapper.Unbaked::type)
            )
            .apply(instance, RenderTypeModelWrapper.Unbaked::new)
        );

        @Override
        public void resolveDependencies(ResolvableModel.Resolver resolver) {
            // Resolve model dependencies, so pass in all known resource locations
            resolver.resolve(this.model);
        }

        @Override
        public ItemModel bake(ItemModel.BakingContext context) {
            // Get the baked model and return
            BakedModel baked = context.bake(this.model);
            return new RenderTypeModelWrapper(baked, this.type);
        }

        @Override
        public MapCodec<RenderTypeModelWrapper.Unbaked> type() {
            return MAP_CODEC;
        }
    }
}

// Then, in some initialization location where ItemModels#ID_MAPPER is exposed
ItemModels.ID_MAPPER.put(
    // The registry name
    ResourceLocation.fromNamespaceAndPath("examplemod", "render_type"),
    // The map codec
    RenderTypeModelWrapper.Unbaked.MAP_CODEC
);
// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
    "model": {
        "type": "examplemod:render_type",
        // Points to 'assets/examplemod/models/item/example_item.json'
        "model": "examplemod:item/example_item",
        // Set the render type to use when rendering
        "render_type": "cutout_block"
    }
}
  • net.minecraft.client
    • ClientBootstrap - Registers the maps backing the client; currently used for item model definitions.
    • Minecraft
      • getEquipmentModels is removed, only directly accessible in the EntityRendererProvider$Context#getEquipmentAssets
      • getItemModelResolver - Returns the updater for resolving the current model to be rendered in the ItemStackRenderState$LayerRenderState.
    • KeyMapping#get - Gets a key mapping based on its translation key.
  • net.minecraft.client.color.item
    • Constant - A constant to tint the item texture.
    • CustomModelDataSource - Gets the color to tint based on an index in the DataComponent#CUSTOM_MODEL_DATA data component. If no index is found or is out of bounds, then the default color is used.
    • Dye - Gets the color to tint using the DataComponent#DYED_COLOR data component.
    • Firework - Gets the color to tint using the DataComponent#FIRE_EXPLOSION data component.
    • GrassColorSource - Gets the color to tint based on the provided temperature and downfall values.
    • ItemColor -> ItemTintSource, not one-to-one as indexing is setup by providing multiple ItemTintSources in the model list.
    • ItemColors class is removed, now data generated as ItemTintSources
    • ItemTintSources - A registry of sources for tinting an item texture in a model.
    • MapColor - Gets the color to tint using the DataComponent#MAP_COLOR data component.
    • Potion - Gets the color to tint using the DataComponent#POTION_CONTENTS data component.
    • TeamColor - Gets the color based on the holding entity’s team color.
  • net.minecraft.client.data.Main - The entrypoint for client data generation.
  • net.minecraft.client.particle.BreakingItemParticle now takes in an ItemStackRenderState instead of an ItemStack
    • $ItemParticleProvider - An abstract particle provide that provides a simple method to calculate the ItemStackRenderState.
  • net.minecraft.client.renderer
    • BlockEntityWithoutLevelRenderer class is removed, replaced by the NoDataSpecialModelRenderer datagen system
    • ItemInHandRenderer now takes in an ItemModelResolver
    • ItemModelShaper is removed, as the methods are available within the ModelManager
    • Sheets
      • getBedMaterial - Gets the bed material from the dye color.
      • colorToResourceMaterial - Gets the resource location of the dye color.
      • createBedMaterial - Creates the bed material from the dye color or resource location.
      • getShulkerBoxMaterial - Gets the shulker box material from the dye color.
      • colorToShulkerMaterial - Gets the resource location of the dye color for the shulker box.
      • createShulkerMaterial - Creates the shulker box material from the dye color or resource location.
      • chestMaterial - Creates a new material for a chest with the given resource location.
    • SpecialBlockModelRenderer - A map of blocks to special renderers for item variants.
  • net.minecraft.client.renderer.block.BlockRenderDispatcher now takes in a supplied SpecialBlockModelRenderer instead of a BlockEntityWithoutLevelRenderer
  • net.minecraft.client.renderer.block.model
    • BakedOverrides class is removed, replaced by the RangeSelectItemModelProperty datagen system
    • BlockModel now takes in a TextureSlots$Data instead of just a material map, and no longer takes in a list of ItemOverrides
      • MISSING_MATERIAL is removed, replaced by minecraft:missingno
      • textureMap -> textureSlots, now private, not one-to-one
      • parent is now private, not one-to-one
      • parentLocation is now private
      • hasAmbientOcclusion -> getAmbientOcclusion
      • isResolved is removed
      • getOverrides is removed
      • getParent - Returns the unbaked parent model.
      • getTextureSlots - Returns the texture data for the model.
      • getElements is now package-private
      • $GuiLight -> UnbakedModel$GuiLight
    • FaceBakery
      • bakeQuad is now static
      • calculateFacing is now private
    • ItemModelGenerator now implements UnbakedModel
    • ItemOverride class is removed, replaced by the RangeSelectItemModelProperty datagen system
    • ItemTransforms is now a record
      • hasTransform is removed
    • TextureSlots - A class which handles the texture mapping within a model. The data is read from $Data and stored as $SlotContents until it is resolved during the baking process into Materials.
    • UnbakedBlockStateModel now extends ResolvableModel instead of UnbakedModel
      • bake - Bakes the block state into its selectable models.
    • Variant is now a record
  • net.minecraft.client.renderer.blockentity
    • BannerRenderer now has an overload constructor which takes in the EntityModelSet
      • renderInHand - Renders the item model of the banner.
    • BedRenderer now has an overload constructor which takes in the EntityModelSet
      • renderInHand - Renders the item model of the bed.
    • BlockEntityRenderDispatcher(Font, EntityModelSet, Supplier<BlockRenderDispatcher>, Supplier<ItemRenderer>, Supplier<EntityRenderDispatcher>) -> BlockEntityRenderDispatcher(Font, Supplier<EntityModelSet>, BlockRenderDispatcher, ItemModelResolver, ItemRenderer, EntityRenderDispatcher)
      • renderItem is removed, implemented in their specific classes
    • BlockEntityRendererProvider now takes in an ItemModelResolver
      • getItemModelResolver - Gets the resolver which returns the item models.
    • ChestRenderer#xmasTextures - Returns whether christmas textures should render on a chest.
    • DecoratedPotRenderer now has an overload constructor which takes in the EntityModelSet
      • renderInHand - Renders the item model of the pot.
    • ShulkerBoxRenderer now has an overload constructor which takes in the EntityModelSet
      • render - Renders the shulker box.
      • $ShulkerBoxModel#animate no longer takes in the ShulkerBoxBlockEntity
    • SkullblockRenderer#createSkullRenderers -> createModel, not one-to-one
  • net.minecraft.client.renderer.entity
    • EntityRenderDispatcher now takes in an IteModelResolver, a supplied EntityModelSet instead of the instance, and an EquipmentAssetManager instead of a EquipmentModelSet
    • EntityRendererProvider$Context now takes in an ItemModelResolver instead of an ItemRenderer, and an EquipmentAssetManager instead of a EquipmentModelSet
      • getItemRenderer -> getItemModelResolver, not one-to-one
      • getEquipmentModels -> getEquipmentAssets
    • FishingHookRenderer - Returns the holding arm of the fishing hook.
    • HumanoidMobRenderer
      • getArmPose - Returns the arm pose of the entity.
      • extractHumanoidRenderState now takes in an ItemModelResolver
    • ItemEntityRenderer
      • getSeedForItemStack is removed
      • renderMultipleFromCount now takes in the ItemClusterRenderState, and removes the ItemRenderer, ItemStack, BakedModel, and 3d boolean
    • ItemRenderer no longer implements ResourceManagerReloadListener
      • The constructor now only takes in the ItemModelResolver
      • render -> renderItem, not one-to-one
      • renderBundleItem is removed
      • getModel, resolveItemModel is removed
    • LivingEntityRenderer#itemRenderer -> itemModelResolver, not one-to-one
    • OminousItemSpawnerRenderer now uses the ItemClusterRenderState
    • SkeletonRenderer#getArmPose -> AbstractSkeletonRenderer#getArmPose
    • SnowGolemRenderer now uses the SnowGolemRenderState
  • net.minecraft.client.renderer.entity.layers
    • CrossArmsItemLayer now uses the HoldingEntityRenderState
    • CustomHeadLayer no longer takes in the ItemRenderer
    • DolphinCarryingItemLayer no longer takes in the ItemRenderer
    • EquipmentLayerRenderer$TrimSpriteKey now takes in a ResourceKey<EquipmentAsset>
      • textureId - Gets the texture id for the trim.
    • FoxHeldItemLayer no longer takes in the ItemRenderer
    • ItemInHandLayer now uses the ArmedEntityRenderState
      • The constructor no longer takes in the ItemRenderer
      • renderArmWithItem no longer takes in the BakedModel, ItemStack, or ItemDisplayContext and instead the ItemStackRenderState
    • LivingEntityEmissiveLayer now takes in a boolean which determines whether the layer is always visible
    • PandaHoldsItemLayer no longer takes in the ItemRenderer
    • PlayerItemInHandLayer no longer takes in the ItemRenderer
      • renderArmWithItem no longer takes in the BakedModel, ItemStack, or ItemDisplayContext and instead the ItemStackRenderState
    • SnowGolemHeadLayer now uses the SnowGolemRenderState
    • WitchItemLayer no longer takes in the ItemRenderer
  • net.minecraft.client.renderer.entity.player.PlayerRenderer#getArmPose is now private
  • net.minecraft.client.renderer.entity.state
    • ArmedEntityRenderState - A render state for an entity that holds items in their right and left hands.
    • HoldingEntityRenderState - A render state for an entity that holds a single item.
    • ItemClusterRenderState - A render state for an item that should be rendered multiple times.
    • ItemDisplayEntityRenderState#itemRenderState, itemModel -> item, not one-to-one
    • ItemEntityRenderState#itemModel, item -> ItemClusterRenderState#item, not one-to-one
    • ItemFrameRenderState#itemStack, itemModel -> item, not one-to-one
    • LivingEntityRenderState
      • headItemModel, headItem -> headItem, not one-to-one
      • Arm and Hand methods moved to ArmedEntityRenderState
    • OminousItemSpawnerRenderState -> ItemClusterRenderState
    • PlayerRenderState
      • mainHandState, offHandState -> ArmedEntityRenderState methods
      • heldOnHead - Represents the item stack on the head of the player.
    • SkeletonRenderState#isHoldingBow - Represents if the skeleton is holding a bow.
    • SnowGolemRenderState - The render state for the snow golem.
    • ThrownItemRenderState#item, itemModel -> item, not one-to-one
    • WitchRenderState#isHoldingPotion - Whether the witch is holding a potion or not.
  • net.minecraft.client.renderer.item
    • BlockModelWrapper - The basic model definition that contains the model and its associated tints.
    • BundleSelectedItemSpecialRenderer- A special renderer for a stack selected by a bundle.
    • ClampedItemPropertyFunction, ItemPropertyFunction -> .properties.numeric.* classes depending on the situation and property
    • ClientItem - The base item that represents the model definition in assets/<modid>/items.
    • CompositeModel - Overlays multiple models together.
    • ConditionalItemModel - A model that shows a different model based on a boolean.
    • EmptyModel - A model that renders nothing.
    • ItemModel - The base item model that updates the stack render state as necessary.
    • ItemModelResolver - The resolver that updates the stack render state.
    • ItemModels - Contains all potential item models for a ClientItem.
    • ItemProperties class is removed
    • ItemStackRenderState - The render state representing the stack to render.
    • MissingItemModel - A model that represents the missing model.
    • RangeSelectItemModel - A model that contains some range of values that applies the associated model that meets the threshold.
    • SelectItemModel - An item model that switches based on the provided property.
    • SpecialModelWrapper - An item model for models that are rendered dynamically, such as chests.
  • net.minecraft.client.renderer.item.properties.conditional
    • Broken - If the item only has one durability left.
    • BundleHasSelectedItem - If the bundle is holding the selected item.
    • ConditionalItemModelProperties - Contains all potential conditional property types.
    • ConditionalItemModelProperty - Represents a property that returns some boolean.
    • CustomModelDataProperty - If the current index is set to true within DataComponents#CUSTOM_MODEL_DATA.
    • Damaged - If the item is damaged.
    • ExtendedView - If the display context is a gui and the shift key is down.
    • FishingRodCast - If the fishing rod is being used.
    • HasComponent - Whether it has the associated data component.
    • IsCarried - If the item is being carried in the current menu.
    • IsKeybindDown - If the key mapping is being pressed.
    • IsSelected - If the item is selected in the hotbar.
    • IsUsingItem - If the item is being used.
    • IsViewEntity - Whether the holding entity is the current camera entity.
  • net.minecraft.client.renderer.item.properties.numeric
    • BundleFullness - A threshold based on the bundle contents.
    • CompassAngle - A threshold on the currrent angle state.
    • CompassAngleState - A threshold based on the current compass angle towards its target.
    • Cooldown - A threshold based on the current cooldown percentage.
    • Count - A threshold based on the stack count.
    • CrossbowPull - A threshold based on the crossbow being pulled.
    • CustomModelDataProperty - If the current index has set theshold value within DataComponents#CUSTOM_MODEL_DATA.
    • Damage - A threshold based on the durability percentage remaining.
    • NeedleDirectionHelper - An abstract class which help point the position needle in the correct direction.
    • RangeSelectItemModelProperties - Contains all potential ranged property types.
    • RangeSelectItemModelProperty - Represents a property that returns some threshold of a float.
    • Time - A threshold based on the current time of day.
    • UseCycle - A threshold based on the remaining time left normalized to some period modulo in the stack being used.
    • UseDuration - A threshold based on the remaining time left in the stack being used.
  • net.minecraft.client.renderer.item.properties.select
    • Charge - A case based on the charge type of a crowssbow.
    • ContextDimension - A case based on the dimension the item is currently within.
    • ContextEntityType - A case based on the holding entity’s type.
    • CustomModelDataProperty - If the current index is set to the string within DataComponents#CUSTOM_MODEL_DATA.
    • DisplayContext - A case based on the display context.
    • ItemBlockState - A case based on getting a property value from an item holding the block state properties.
    • LocalTime - A case based on a simple date format pattern.
    • MainHand - A case based on the arm holding the item.
    • SelectItemModelProperties - Contains all potential select-cased property types.
    • SelectItemModelProperty - Represents a property that returns some cased selection.
    • TrimMaterialProperty - A case based on the trim material on the item.
  • net.minecraft.client.renderer.special
    • BannerSpecialRenderer - An item renderer for a banner.
    • BedSpecialRenderer - An item renderer for a bed.
    • ChestSpecialRenderer - An item renderer for a chest.
    • ConduitSpecialRenderer - An item renderer for a conduit.
    • DecoratedPotSpecialRenderer - An item renderer for a decorated pot.
    • HangingSignSpecialRenderer - An item renderer for a hanging sign.
    • NoDataSpecialModelRenderer - An item renderer that does not need to read any data from the stack.
    • ShieldSpecialRenderer - An item renderer for a shield.
    • ShulkerBoxSpecialRenderer - An item renderer for a shulker box.
    • SkullSpecialRenderer - An item renderer for a skull.
    • SpecialModelRenderer - Represents a model that reads data from the stack and renders the object without needing the render state.
    • SpecialModelRenderers - Contains all potential special renderers.
    • StandingSignSpecialRenderer - An item renderer for a standing sign.
    • TridentSpecialRenderer - An item renderer for a trident.
  • net.minecraft.client.resources.model
    • BakedModel
      • isCustomRenderer is removed, replaced by the special renderer system
      • overrides is removed, replaced by the properties renderer system
    • BlockStateModelLoader no longer takes in the missing model
      • definitionLocationToBlockMapper is now private
      • loadBlockStateDefinitionStack is now private
      • loadBlockStates - Gets the loaded models for the block state.
      • $LoadedBlockModelDefinition is now package-private
      • $LoadedModel now takes in an UnbakedBlockStateModel instead of a UnbakedModel
      • $LoadedModels
        • forResolving - Returns all models hat need to be resolved.
        • plainModels - Returns a map from the model location to the unbaked model.
    • BuiltInModel class is removed
    • ClientItemInfoLoader - Loads all models for all item stacks.
    • EquipmentModelSet -> EquipmentAssetManager
    • ItemModel -> net.minecraft.client.renderer.item.ItemModel
    • MissingBlockModel#MISSING is now private
    • ModelBaker
      • sprites - Returns the getter to get sprites.
      • rootName - Gets the name of the model for debugging.
    • ModelBakery(Map<ModelResourceLocation, UnbakedModel>, Map<ResourceLocation, UnbakedModel>, UnbakedModel) -> ModelBakery(EntityModelSet, Map<ModelResourceLocation, UnbakedBlockStateModel>, Map<ResourceLocation, ClientItem>, Map<ResourceLocation, UnbakedModel>, UnbakedModel)
      • bakeModels now returns a $BakingResult
      • getBakedTopLevelModels is removed
      • $BakingResult - Holds all models that have been lodaded.
      • $TextureGetter
        • get now takes in the ModelDebugName instead of the ModelResourceLocation
        • reportingMissingReference - Handles how a texture is reported when not set.
        • bind - Creates a spriate getter bound to the current model.
    • ModelDebugName - Returns the name of the model for debugging.
    • ModelDiscovery
      • registerStandardModels is removed
      • registerSpecialModels - Adds the internal models loaded by the system.
      • addRoot - Adds a new model that can be resolved.
      • getUnreferencedModels - Returns the difference between the models loaded vs the models used.
      • getTopModels is removed
    • ModelGroupCollector$GroupKey#create now takes in an UnbakedBlockStateModel instead of a UnbakedModel
    • ModelManager
      • specialBlockModelRenderer - Returns the renderer for special block models.
      • entityModels - Returns the model set for the entities.
      • getItemProeprties - Returns the properties for the client item based on its resource location.
    • ModelResourceLocation#inventory is removed
    • ResolvableModel - The base model, usually unbaked, that have references to resolve.
    • SimpleBakedModel fields are now all private
      • bakeElements - Bakes a model given the block elements.
      • $Builder no longer has an overload that takes in the BlockModel
    • SpecialModels class is removed
    • SpriteGetter - A getter for atlas sprites for the associated materials.
    • UnbakedModel is now a ResolvableModel
      • bake(ModelBaker, Function<Material, TextureAtlasSprite>, ModelState) -> bake(TextureSlots, ModelBaker, ModelState, boolean, boolean, ItemTransforms)
      • getAmbientOcclusion, getTopAmbientOcclusion - Returns whether ambient occlusion should be enabled on the item.
      • getGuiLight, getTopGuiLight - Returns the lighting side within a gui.
      • getTransforms, getTopTransform, getTopTransforms - Returns the transformations to apply based on the display context.
      • getTextureSlots, getTopTextureSlots - Returns the texture data for the model.
      • getParent - Returns the parent of this model.
      • bakeWithTopModelValues - Bakes the model.
  • net.minecraft.data.models.* -> net.minecraft.client.data.models.*
  • net.minecraft.world.item
    • BundleItem no longer takes in any ResourceLocations
      • openFrontModel, openBackModel is removed
    • CrossbowItem$ChargeType - The item being charged by the crossbow.
    • DyeColor#getMixedColor - Returns the dye most closely representing the mixed color.
    • Item$Properties#overrideModel is removed
    • SpawnEggItem no longer takes in its tint colors
      • getColor is removed
  • net.minecraft.world.item.alchemy.PotionContents
    • getColor(*) is removed
    • getColorOr - Gets a custom color fro the potion or the default if not present.
  • net.minecraft.world.item.component.CustomModelData now takes in a list of floats, flags, strings, and colors to use in the custom model properties based on the provided index
  • net.minecraft.world.item.equipment
    • ArmorMaterial now takes in a ResourceKey<EquipmentAsset> instead of just the model id
    • EquipmentAsset - A marker to represent the equipment client info key
    • EquipmentAssets - All vanilla equipment assets.
    • EquipmentModel -> net.minecraft.client.resources.model.EquipmentClientInfo
    • EquipmentModels -> net.minecraft.client.data.models.EquipmentAssetProvider, not one-to-one
    • Equippable now takes in a ResourceKey<EquipmentAsset> instead of just the model id
      • $Builder#setModel -> setAsset
  • net.minecraft.world.item.equipment.trim
    • ArmorTrim#getTexture is removed
    • TrimMaterial no longer takes in an item model index, and the key over the override armor materials points to ResourceKey<EquipmentAsset>
  • net.minecraft.world.level.FoliageColor
    • getEvergreenColor -> FOLIAGE_EVERGREEN
    • getBirchColor -> FOLIAGE_BIRCH
    • getDefaultColor -> FOLIAGE_DEFAULT
    • getMangroveColor -> FOLIAGE_MANGROVE
  • net.minecraft.world.level.block.RenderShape#ENTITYBLOCK_ANIMATED is removed
  • net.minecraft.world.level.block.entity
    • BannerBlockEntity#fromItem is removed
    • BedBlockEntitty#setColor is removed
    • BlockEntity#saveToItem is removed
    • DecoratedPotBlockEntity#setFromItem, getPotAsItem is removed
  • net.minecraft.world.level.storage.loot.functions.SetCustomModelDataFunction now takes in a list of floats, flags, strings, and colors to use in the custom model properties based on the provided index

Mob Replacing Current Items

One of the last hardcoded instances relating to tools and armor being subtypes of DiggerItem and ArmorItem, respectively, have been reworked: Mob#canReplaceCurrentItem. Now, it reads the EquipmentSlot of the stack from the DataComponents#EQUIPPABLE data component. Then, using that, different logic occurs depending on the situation.

For armor slots, it cannot be changed if the armor is enchanted with a EnchantmentEffectComponents#PREVENT_ARMOR_CHANGE effect component. Otherwise, it will attempt to compare the armor attributes first, then armor toughness if equal.

For weapons (via hand slots), it will first check if the mob has a preferred weapon type tag. If so, it will switch the item to the weapon in the tag, provided one item is in the tag and the other is not. Otherwise, it will attempt to compare attack damage attributes.

If all attributes are equal, then they will both default to the following logic. First, it will try to pick the item with the most enchantments. Then, it will attempt to pick the item with the most durability remaining (the raw value, not the percentage). Finally, it will check whether one of the items hsa a custom name via the DataComponents#CUSTOM_NAME.

As a small caveat, BambooSaplingBlock and BambooStalkBLock still hardcode a check for check if the mainhand item is a SwordItem, though this could probably be replaced with a change to ToolMaterial#applySwordProperties in the future.

Particles, rendered through Render Types

Particles are now rendered using a RenderType, rather than setting a buffer builder themselves. The only special cases are ParticleRenderType#CUSTOM, which allows the modder to implement their own rendering via Particle#renderCustom; and ParticleRenderType#NO_RENDER, which renders nothing.

To create a new ParticleRenderType, it can be created by passing in its name for logging and the RenderType to use. Then, the type is returned in Particle#getRenderType.

public static final ParticleRenderType TERRAIN_SHEET_OPAQUE = new ParticleRenderType(
    "TERRAIN_SHEET_OPAQUE", // Typically something recognizable, like the name of the field
    RenderType.opaqueParticle(TextureAtlas.LOCATION_BLOCKS) // The Render Type to use
);
  • net.minecraft.client.particle
    • CherryParticle -> FallingLeavesParticle, not one-to-one as the new class has greater configuration for its generalization
    • ItemPickupParticle no longer takes in the RenderBuffers
    • Particle#renderCustom - Renders particles with the ParticleRenderType#CUSTOM render type.
    • ParticleEngine#render(LightTexture, Camera, float) -> render(Camera, float, MutliBufferSource$BufferSource)
    • ParticleRenderType is now a record which takes in the name and the RenderType it uses.

Minor Migrations

The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.

SimpleJsonResourceReloadListener

SimpleJsonResourceReloadListeners now take in a converter to map some key to a resource location. An abstract has been provided for registry keys. This is done through a FileToIdConverter, which essentially holds a prefix and extension to apply to some ResourceLocation.

// We will assume this is a server reload listener (meaning in the 'data' folder)
public class MyLoader extends SimpleJsonResourceReloadListener<ExampleObject> {

    public MyLoader() {
        super(
            // The codec to encode/decode the object
            ExampleObject.CODEC,
            // The file converter
            // Will place files in data/<namespace>/example/object/<path>.json
            FileToIdConverter.json(
                // The prefix
                "example/object"
            )
        );
    }

    // Below is the same
}
  • net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener now takes in a resource key for a registry, or a file to id converter instead of just a string
    • scanDirectory now takes in a resource key for a registry, or a file to id converter instead of just a string

MetadataSectionSerializer, replaced by Codecs

MetadataSectionSerializer has been removed in favor of using Codecs to serialize the metadata sections. As such all MetadataSectionSerializers have been replaced by its MetadataSectionType instead, which holds the name of the section and the codec for the metadata section.

  • net.minecraft.client.renderer.texture
    • HttpTexture -> SkinTextureDownloader, not one-to-one as the new class is just a utility that returns the content to store
    • MissingTextureAtlasSprite
      • getTexture -> generateMissingImage, not one-to-one
      • getMissingImage(int, int) is now public
    • SpriteLoader#loadAndStitch now takes in a collection of MetadataSectionTypes rather than MetadataSectionSerializers
  • net.minecraft.client.resources.SkinManager no longer takes in the TextureManager
    • getOrLoad now returns an Optional<PlayerSkin> future instead of just the PlayerSkin
  • net.minecraft.client.resources.metadata.animation
    • AnimationFrame is now a record
    • AnimationMetadataSection is now a record
    • AnimationMetadataSectionSerializer class is removed
    • VillagerMetaDataSection -> VillagerMetadataSection
    • VillagerMetadataSectionSerializer class is removed
  • net.minecraft.client.resources.metadata.texture
    • TextureMetadataSection is now a record
    • TextureMetadataSectionSerializer class is removed
  • net.minecraft.server.packs.PackResources#getMetadataSection now takes in a MetadataSectionType instead of a MetadataSectionSerializer
  • net.minecraft.server.packs.metadata
    • MetadataSectionSerializer is removed in favor of section codecs
    • MetadataSectionType is a now a record instead of a MetadataSectionSerializer extension
  • net.minecraft.server.packs.resources.ResourceMetadata
    • getSection now takes in a MetadataSectionType instead of a MetadataSectionSerializer
    • copySections now takes in a collection of MetadataSectionTypes instead of a MetadataSectionSerializers

Music, now with Volume Controls

The background music is now handled through a MusicInfo class, which also stores the volume along with the associated Music.

  • net.minecraft.client.Minecraft#getSituationalMusic now returns a MusicInfo instead of a Music
  • net.minecraft.client.sounds
    • MusicInfo - A record that holds the currently playing Music and the volume its at.
    • MusicManager#startPlaying now takes in a MusicInfo instead of a Music
    • SoundEngine#setVolume, SoundManager#setVolume - Sets the volume of the associated sound instance.
  • net.minecraft.world.level.biome
    • Biome
      • getBackgroundMusic now returns a optional SimpleWeightedRandomList of music.
      • getBackgroundMusicVolume - Gets the volume of the background music.
    • BiomeSpecialEffects$Builder#silenceAllBackgroundMusic, backgroundMusic(SimpleWeightedRandomList<Music>) - Handles setting the background music for the biome.

Tag Changes

  • minecraft:block
    • tall_flowers -> bee_attractive
  • minecraft:item
    • tall_flowers, flowers is removed
    • trim_templates is removed
    • skeleton_preferred_weapons
    • drowned_preferred_weapons
    • piglin_preferred_weapons
    • pillager_preferred_weapons
    • wither_skeleton_disliked_weapons

List of Additions

  • com.mojang.blaze3d.platform.Window#isMinimized - Returns whether the application window is minimized.
  • com.mojang.blaze3d.vertex.VertexBuffer
    • uploadStatic - Immediately uploads the provided vertex data via the Consumer<VertexConsumer> using the Tesselator with a STATIC_WRITE VertexBuffer.
    • drawWithRenderType - Draws the current buffer to the screen with the given RenderType.
  • com.mojang.math.MatrixUtil#isIdentity - Checks whether the current Matrix4f is an identity matrix.
  • net.minecraft
    • SuppressForbidden - An annotation that holds some reason, usually related to needing the sysout stream.
    • Util#maxAllowedExecutorThreads - Returns the number of available processors clamped between one and the maximum number of threads.
  • net.minecraft.client.gui.components.events.GuiEventListener#getBorderForArrowNavigation - Returns the ScreenRectangle bound to the current direction.
  • net.minecraft.client.gui.navigation.ScreenRectangle#transformAxisAligned - Creates a new ScreenRectangle by transforming the position using the provided Matrix4f.
  • net.minecraft.client.gui.narration.NarratableEntry#getNarratables - Returns the list of narratable objects within the current object.
  • net.minecraft.client.gui.screens.recipebook.RecipeCollection#EMPTY - An empty collection of recipes.
  • net.minecraft.client.gui.screens.worldselection
    • ExperimentsScreen$ScrollArea - Represents a narratable scroll area of the currently available experiments.
    • SwitchGrid#layout - Returns the layout of the grid to visit.
  • net.minecraft.client.model
    • BannerFlagModel, BannerModel - Models for the banner and hanging banner.
    • VillagerLikeModel#translateToArms - Translates the pose stack such that the current relative position is at the entity’s arms.
  • net.minecraft.client.model.geom.EntityModelSet#vanilla - Creates a new model set with all vanilla models.
  • net.minecraft.client.multiplayer.PlayerInfo#setShowHat, showHat - Handles showing the hat layer of the player in the tab overlay.
  • net.minecraft.client.renderer.blockentity
    • AbstractSignRenderer - How a sign should render as a block entity.
    • HangingSignRenderer
      • createSignModel - Creates a sign model given the wood and the attachment location.
      • renderInHand - Renders the model in the entity’s hand.
      • $AttachmentType - An enum which represents where the model is attached to, given its properies.
      • $ModelKey - A key for the model that combines the WoodType with its $AttachmentType.
    • SignRenderer
      • renderInHand - Renders the model in the entity’s hand.
  • net.minecraft.client.renderer.entity.EntityRenderer#getShadowStrength - Returns the raw opacity of the display’s shadow.
  • net.minecraft.client.renderer.entity.layers.CrossedArmsItemLayer#applyTranslation - Applies the translation to render the item in the model’s arms.
  • net.minecraft.client.renderer.texture
    • ReloadableTexture - A texture that can be reloaded from its associated contents.
    • TextureContents - Holds the image and metadata associated with a given texture.
    • TextureManager
      • registerAndLoad - Registers a reloadable texture with the given name.
      • registerForNextReload - Registers a texture by its resource location to be loaded on next reload.
  • net.minecraft.commands.SharedSuggestionProvider#MATCH_SPLITTER - Defines a matcher that matches a period, underscore, or forward slash.
  • net.minecraft.core.BlockPos$TraversalNodeStatus - A marker indicating whether the BlockPos should be used, skipped, or stopped from any further traversal.
  • net.minecraft.core.component.PatchedDataComponentMap
    • toImmutableMap - Returns either the immutable patch or a copy of the current map.
    • hasNonDefault - Returns whether there is a custom value for the data component instead of just the default.
  • net.minecraft.data.PackOutput$PathProvider#json - Gets the JSON path from a resource key.
  • net.minecraft.data.loot.BlockLootSubProvider#createMultifaceBlockDrops - Drops a block depending on the block face mined.
  • net.minecraft.data.worldgen.placement.PlacementUtils#HEIGHTMAP_NO_LEAVES - Creates a y placement using the Heightmap$Types#MOTION_BLOCKING_NO_LEAVES heightmap.
  • net.minecraft.network.chat.Style#getShadowColor, withShadowColor - Methods for handling the shadow color of a component.
  • net.minecraft.network.protocol.game.ServerboundPlayerLoadedPacket - A packet for when the client player loads into a client world.
  • net.minecraft.resources.FileToIdConverter#registry - Gets the file converter from a registry key.
  • net.minecraft.util.ExtraCodecs
    • idResolverCodec - Creates a codec that maps some key to some value.
    • compactListCodec - Creates a codec that can either be an element of a list of elements.
    • floatRange - Creates a codec that must be between two float values.
    • $LateBoundIdMapper - A mapper that functionally acts like a registry with an associated codec.
  • net.minecraft.util.profiling.jfr.JvmProfiler#onStructureGenerate - Returns the profiled duration on when a structure attempts to generate in the world.
  • net.minecraft.util.profiling.jfr.event.StructureGenerationEvent - A profiler event when a structure is being generated.
  • net.minecraft.util.profiling.jfr.stats.StructureGenStat - A result of a profiled structure generation.
  • net.minecraft.world.entity
    • LivingEntity
      • resolvePlayerResponsibleForDamage - Gets the player responsible for hurting the current entity.
      • canBeNameTagged - When true, the entity’s can be set with a name tag.
    • Mob#getPreferredWeaponType - Gets the tag that represents the weapons the entity wants to pick up.
  • net.minecraft.world.entity.ai.attributes.AttributeMap#resetBaseValue - Resets the attribute instance to its default value.
  • net.minecraft.world.entity.monster.creaking
    • Creaking
      • activate, deactivate - Handles the activateion of the brain logic for the creaking.
      • setTransient, isHeartBound, setHomePos, getHomePos - Handles the home position.
      • blameSourceForDamage - Finds the player responsible for the damage.
      • tearDown - Handles when the creaking is destroyed.
      • creakingDeathEffects - Handles the death of a creaking.
      • playerIsStuckInYou - Checks whether there are at least four players stuck in a creaking.
      • setTearingDown, isTearingDown - Handles the tearing down state.
      • hasGlowingEyes, checkEyeBlink - Handles the eye state.
  • net.minecraft.world.entity.player.Player
    • hasClientLoaded, setClientLoaded - Whether the client player has been loaded.
    • tickClientLoadTimeout - Ticks the timer on how long to wait before kicking out the client player if not loaded.
  • net.minecraft.world.item
    • Item#shouldPrintOpWarning - Whether a warning should be printed to the player based on stored block entity data and adminstrator permissions.
    • ItemStack
      • getCustomName - Returns the custom name of the item, or null if no component exists.
      • immutableComponents - Returns either the immutable patch or a copy of the stack component map.
      • hasNonDefault - Returns whether there is a custom value for the data component instead of just the default.
  • net.minecraft.world.item.component.CustomData
    • parseEntityId - Reads the entity id off of the component.
    • parseEntityType - Reads the entity type from the id and maps it to its registry object.
  • net.minecraft.world.item.crafting.Ingredient#isEmpty - Returns whether the ingredient has no values.
  • net.minecraft.world.item.trading.Merchant#stillValid - Checks whether the merchant can still be accessed by the player.
  • net.minecraft.world.level
    • Level#dragonParts - Returns the list of entities that are the parts of the ender dragon.
    • ServerExplosion#getDamageSource - Returns the damage source of the explosion.
  • net.minecraft.world.level.block
    • EyeblossomBlock$Type
      • block - Gets the block for the current type.
      • state - Gets the block state for the current type.
      • transform - Returns the opposiate state of this type.
    • FlowerBlock#getBeeInteractionEffect - Returns the effect that bees obtain when interacting with the flower.
    • FlowerPotBlock#opposite - Returns the opposite state of the block, only for potted eyeblossoms.
    • MultifaceBlock#canAttachTo - Returns whether this block can attach to another block.
    • MultifaceSpreadeableBlock - A multiface block that can naturally spread.
  • net.minecraft.world.level.block.entity.trialspawner
    • TrialSpawner#overrideEntityToSpawn - Changes the entity to spawn in the trial.
    • TrialSpawnerConfig#withSpawning - Sets the entity to spawn within the trial.

List of Changes

  • com.mojang.blaze3d.platform.NativeImage#upload no longer takes in three booleans that set the filter mode or texture wrap clamping for TEXTURE_2D
    • This has been moved to AbstractTexture#setClamp and #setFilter
  • net.minecraft.client.gui
    • Gui#clear -> clearTitles
    • GuiGraphics#drawWordWrap has a new overload that takes in whether a drop shadow should be applied to the text
      • The default version enables drop shadows instead of disabling it
  • net.minecraft.client.gui.components
    • AbstractContainerWidget now implements AbstractScrollArea
    • AbstractScrollWidget -> AbstractScrollArea or AbstractTextAreaWidget depending on use-case, not one-to-one
    • AbstractSelectionList
      • setRenderHeader is now bundled into a new constructor with an extra integer
      • getMaxScroll -> AbstractScrollArea#maxScrollAmount
      • getScrollAmount -> AbstractScrollArea#scrollAmount
      • scrollbarVisible -> AbstractScrollArea#scrollbarVisible
      • setClampedScrollAmount, setScrollAmount -> AbstractScrollArea#setScrollAmount
      • clampScrollAmount -> refreshScrollAmount
      • updateScrollingState -> AbstractScrollArea#updateScrolling
      • getScrollbarPosition, getDefaultScrollbarPosition -> scrollBarY, not one-to-one
    • AbstractWidget#clicked -> isMouseOver, already exists
  • net.minecraft.client.gui.components.toasts.TutorialToast now requires a Font as the first argument in its constructor
  • net.minecraft.client.gui.font.glyphs.BakedGlyph$Effect and $GlyphInstance now take in the color and offset of the text shadow
  • net.minecraft.client.gui.screens
    • LoadingOverlay#registerTextures now takes in a TextureManager instead of the Minecraft instance
    • TitleScreen#preloadResources -> registerTextures, not one-to-one
  • net.minecraft.client.gui.screens.debug.GameModeSwitcherScreen$GameModeSlot is now a static inner class
  • net.minecraft.client.gui.screens.reporting.ChatSelectionScreen$Entry, $PaddingEntry are now static inner classes
  • net.minecraft.client.gui.screens.worldselection.SwitchGrid$Builder#build no longer takes in a Consumer<LayoutElement>
  • net.minecraft.client.model
    • DonkeyModel#createBodyLayer, createBabyLayer now take in a scaling factor
    • VillagerHeadModel -> VillagerLikeModel
  • net.minecraft.client.model.geom.EntityModelSet is no longer a ResourceManagerReloadListener
  • net.minecraft.client.multiplayer.MultiPlayerGameMode#handlePickItem -> handlePickItemFromBlock or handlePickItemFromEntity, providing both the actual object data to sync and a boolean about whether to include the data of the object being picked
  • net.minecraft.client.particle.CherryParticle -> FallingLeavesParticle, not one-to-one as the new class has greater configuration for its generalization
  • net.minecraft.client.player.ClientInput#tick no longer takes in any parameters
  • net.minecraft.client.renderer
    • CubeMap#preload -> registerTextures, not one-to-one
    • LevelRenderer
      • renderLevel no longer takes in the LightTexture
      • onChunkLoaded -> onChunkReadyToRender
    • PostChainConfig$Pass#program -> programId
      • program now returns the ShaderProgram with the given programId
    • ScreenEffectRenderer#renderScreenEffect now takes in a MultiBufferSource
    • SectionOcclusionGraph#onChunkLoaded -> onChunkReadyToRender
    • Sheets#createSignMaterial, createHangingSignMaterial now has an overload that takes in a ResourceLocation
    • SkyRenderer
      • renderSunMoonAndStars, renderSunriseAndSunset now takes in a MultiBufferSource$BufferSource instead of a Tesselator
      • renderEndSky no longer takes in the PoseStack
    • WeatherEffectRenderer#render now takes in a MultiBufferSource$BufferSource instead of a LightTexture
  • net.minecraft.client.renderer.blockentity
    • BannerRenderer#createBodyLayer -> BannerModel#createBodyLayer, not one-to-one
    • HangingSignRenderer
      • createHangingSignLayer now takes in a HangingSignRenderer$AttachmentType
      • $HangingSignModel is now replaced with a Model$Simple, though its fields can be obtained from the root
    • SkullBlockRenderer#getRenderType now has an overload that takes in a ResourceLocation to override representing the player’s texture
  • net.minecraft.client.renderer.entity.AbstractHorseRenderer, DonkeyRenderer no longer takes in a float scale
  • net.minecraft.client.renderer.entity.layers.CrossedArmsItemLayer now requires the generic M to be a VillagerLikeModel
  • net.minecraft.client.renderer.entity.state.CreakingRenderState#isActive -> eyesGlowing
    • The original parameter still exists on the Creaking, but is not necessary for rendering
  • net.minecraft.core.BlockPos#breadthFirstTraversal now takes in a function that returns a $TraversalNodeStatus instead of a simple predicate to allow certain positions to be skipped
  • net.minecraft.core.particles.TargetColorParticleOption -> TrailParticleOption, not one-to-one
  • net.minecraft.data.DataProvider#savelAll now has overloads for maps with a key function to get the associated path
  • net.minecraft.network
    • NoOpFrameEncoder replaced by LocalFrameEncoder, not one-to-one
    • NoOpFrameDecoder replaced by LocalFrameDecoder, not one-to-one
    • MonitorFrameDecoder replaced by MonitoredLocalFrameDecoder, not one-to-one
  • net.minecraft.network.protocol.game
    • ClientboundLevelParticlesPacket now takes in a boolean that determines whether the particle should always render
    • ClientboundMoveVehiclePacket is now a record
    • ClientboundPlayerInfoUpdatePacket$Entry now takes in a boolean representing whether the hat should be shown
    • ClientboundSetHeldSlotPacket is now a record
    • ServerboundMoveVehiclePacket is now a record
    • ServerboundPickItemPacket -> ServerboundPickItemFromBlockPacket, ServerboundPickItemFromEntityPacket; not one-to-one
  • `net.minecraft.server.level
    • ServerLevel#sendParticles now has an overload that takes in the override limiter distance and whether the particle should always be shown
      • Other overloads that take in the override limiter now also take in the boolean for if the particle should always be shown
    • ServerPlayer#doCheckFallDamage -> Entity#doCheckFallDamage, now final
  • net.minecraft.util
    • ARGB#from8BitChannel is now private, with individual float components obtained from alphaFloat, redFloat, greenFloat, and blueFloat
    • SpawnUtil#trySpawnMob now takes in a boolean that, when false, allows the entity to spawn regardless of collision status with the surrounding area
  • net.minecraft.util.profiling.jfr.callback.ProfiledDuration#finish now takes in a boolean that indicates whether the profiled event was successful
  • net.minecraft.util.profiling.jfr.parse.JfrStatsResults now takes in a list of structure generation statistics
  • net.minecraft.world.effect.PoisonMobEffect, WitherMobEffect is now public
  • net.minecraft.world.entity
    • Entity
      • setOnGroundWithMovement has an overload that sets the horizontal collision to whatever the entity’s current state is.
      • awardKillScore no longer takes in an integer
      • makeBoundingBox() is now final
        • makeBoundingBox(Vec3) is now
      • onlyOpCanSetNbt -> EntityType#onlyOpCanSetNbt
    • Leashable
      • readLeashData is now private, replaced by a method that returns nothing
      • dropLeash(boolean, boolean) -> dropLeash(), removeLeash, onLeashRemoved; not one-to-one, as they all internally call the private dropLeash
    • LivingEntity
      • isLookingAtMe no longer takes in a Predicate<LivingEntity>, and array of DoubleSuppliers is now an array of doubles
      • hasLineOfSight takes in a double instead of a DoubleSupplier
  • net.minecraft.world.entity.ai.behavior.AcquirePoi#create now has overloads which take in a BiPredicate<ServerLevel, BlockPos> for filtering POI locations
  • net.minecraft.world.entity.animal.Bee#attractsBees is now public
  • net.minecraft.world.entity.monster.Shulker#getProgressAabb, getProgressDeltaAabb now take in a movement Vec3
  • net.minecraft.world.entity.player
    • Inventory
      • setPickedItem -> addAndPickItem
      • findSlotMatchingCraftingIngredient now takes in an ItemStack to compare against
    • Player#getPermissionLevel is now public
    • StackedContents$IngredientInfo is now an interface that acts like a predicate for accepting some item
  • net.minecraft.world.entity.projectile.FishingHook no longer takes in the ItemStack
  • net.minecraft.world.inventory.Slot#getNoItemIcon now returns a single ResourceLocation rather than a pair of them
  • net.minecraft.world.item
    • Item$TooltipContext#of now takes in the Player viewing the item
    • MobBucketItem now requires a Mob entity type - SpawnEggItem#spawnsEntity, getType now takes in a HolderLookup$Provider
  • net.minecraft.world.item.crafting
    • Ingredient now implements StackedContents$IngredientInfo<Holder<Item>>
      • items now returns a stream instead of a list
    • PlacementInfo#slotInfo -> slotsToIngredientIndex, not one-to-one
  • net.minecraft.world.level.Level#addParticle now takes in a boolean representing if the particle should always be shown
  • net.minecraft.world.level.block
    • Block#getCloneItemStack -> state.BlockBehaviour#getCloneItemStack, now protected
    • CherryLeavesBlock -> ParticleLeavesBlock
    • CreakingHeartBlock#canSummonCreaking -> isNaturalNight
    • MultifaceBlock is no longer abstract and implements SimpleWaterloggedBlock
      • getSpreader -> MultifaceSpreadeableBlock#getSpreader
    • SculkVeinBlock is now an instance of MultifaceSpreadeableBlock
    • SnowyDirtBlock#isSnowySetting is now protected
  • net.minecraft.world.level.block.entity
    • AbstractFurnaceBlockEntity
      • litTime -> litTimeRemaining
      • litDuration -> litTotalTime
      • cookingProgress -> cookingTimer
    • BeehiveBlockEntity#addOccupant now takes in a Bee rather than an Entity
    • CreakingHeartBlockEntity#setCreakingInfo - Sets the creaking the block entity is attached to.
  • net.minecraft.world.level.block.state.BlockBehaviour#getCloneItemStack, $BlockStateBase#getCloneItemStack now takes in a boolean representing if there is infinite materials and whether the current block data should be saved.
  • net.minecraft.world.level.chunk.ChunkGenerator#createStructures now takes in the Level resource key, only used for profiling
  • net.minecraft.world.level.levelgen.feature.configurations
    • MultifaceGrowthConfiguration now takes in a MultifaceSpreadableBlock instead of a MultifaceBlock
    • SimpleBlockConfiguration now takes in a boolean on whether to schedule a tick update
  • net.minecraft.world.level.levelgen.structure.Structure#generate now takes in the Structure holder and a Level resource key, only used for profiling

List of Removals

  • com.mojang.blaze3d.systems.RenderSystem#overlayBlendFunc
  • net.minecraft.client.gui.components.AbstractSelectionList
    • clickedHeader
    • isValidMouseClick
  • net.minecraft.client.gui.screens.recipebook.RecipeCollection#hasSingleResultItem
  • net.minecraft.client.model
    • DrownedModel#getArmPose, now part of the ArmedEntityRenderState
    • FelineModel#CAT_TRANSFORMER
    • HumanoidModel#getArmPose, now part of the ArmedEntityRenderState
    • PlayerModel#getArmPose, now part of the ArmedEntityRenderState
    • SkeletonModel#getArmPose, now part of the ArmedEntityRenderState
    • VillagerModel#BABY_TRANSFORMER
  • net.minecraft.client.renderer.texture
    • AbstractTexture
      • load
      • reset
      • getDefaultBlur
    • PreloadedTexture
    • TextureManager
      • getTexture(ResourceLocation, AbstractTexture)
      • register(String, DynamicTexture)
      • preload
  • net.minecraft.server.level.TicketType#POST_TELEPORT
  • net.minecraft.world.entity.LivingEntity#deathScore
  • net.minecraft.world.entity.ai.navigation.FlyingPathNavigation, GroundPathNavigation
    • canPassDoors, setCanPassDoors
    • canOpenDoors
  • net.minecraft.world.entity.monster.creaking.CreakingTransient
  • net.minecraft.world.entity.player.StackedItemContents#convertIngredientContents
  • net.minecraft.world.item
    • CompassItem#getSpawnPosition
    • ItemStack#clearComponents
  • net.minecraft.world.item.crafting.PlacementInfo
    • ingredientToContents
    • unpackedIngredients
    • $SlotInfo
  • net.minecraft.world.level.block.CreakingHeartBlock$CreakingHeartState
  • net.minecraft.world.level.block.entity.BlockEntity#onlyOpCanSetNbt
  • net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerData#setEntityId

Minecraft 1.21.4 -> 1.21.5 Mod Migration Primer

This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.4 to 1.21.5. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.

This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.

If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.

Thank you to:

  • @TelepathicGrunt for the information within the ‘Very Technical Changes’ section
  • @RogueLogix for their review and comments on the ‘Render Pipeline Rework’ section
  • @Tslat for catching an error about equipOnInteract

Pack Changes

There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.

Handling the Removal of Block Entities Properly

Previously, BlockEntity would handle all of their removal logic within BlockBehaviour#onRemove, including both dropping any stored items and removing the block entity itself. However, depending on how the method is used, it can cause some strange behaviors due to the mutable state of the block entity. For this reason, the logic that makes up the removal process has been split between two methods: BlockEntity#preRemoveSideEffects and BlockBehaviour#affectNeighborsAfterRemoval.

BlockEntity#preRemoveSideEffects is now responsible for removing anything from the block entity before it is removed from the level. By default, if the BlockEntity is a Container instance, it will drop the contents of the container into the level. Other logic can be handled within here, but it should generally avoid removing the BlockEntity itself, unless the position of the block entity tends to change dynamically, like for a piston.

From there, the LevelChunk logic will call removeBlockEntity before calling BlockBehaviour#affectNeighborsAfterRemoval. This should only send the updates to other blocks indicating that this block has been removed from the level. For BlockEntity holders, this can be done easily by calling Containers#updateNeighboursAfterDestroy. Otherwise may want to call Level#updateNeighborsAt themselves, depending on the situation.

  • net.minecraft.world.Containers
    • updateNeighboursAfterDestroy - Updates the neighbor state aftering destroying the block at the specified position.
    • dropContentsOnDestroy is removed, handled within BlockEntity#preRemoveSideEffects for Container instances
  • net.minecraft.world.level.block.entity.BlockEntity#preRemoveSideEffects - Handles logic on the block entity that should happen before being removed from the level.
  • net.minecraft.world.level.block.state.BlockBehaviour#onRemove, $BlockStateBase#onRemove -> affectNeighborsAfterRemoval, should only handle logic to update the surrounding neighbors rather than dropping container data

Voxel Shape Helpers

VoxelShapes have received numerous helpers for more common transformations of its base state. There are the Block methods for creating a centered (if desired) box and the Shapes methods for rotating a VoxelShape to its appropriate axis or direction. There is also a Shapes#rotateAttachFace method for rotating some VoxelShape that is attached to a face of a different block. The results are either stored in a Map of some key to a VoxelShape, or when using Block#getShapeForEachState, a Function<BlockState, VoxelShape>.

Most of the Block subclasses that had previous public or protected VoxelShapes are now private, renamed to a field typically called SHAPE or SHAPES. Stored VoxelShapes may also be in a Function instead of directly storing the map itself.

  • com.mojang.math.OctahedralGroup
    • permute - Returns the axis that the given axis is permuted to within the specified group.
    • fromAngles - Creates a group with the provided X and Y rotations.
  • net.minecraft.core.Direction$Axis#choose now has an overload that takes in three booleans
  • net.minecraft.world.level.block.Block
    • boxes - Creates one more than the specified number of boxes, using the index as part of the function to create the VoxelShapes.
    • cube - Creates a centered cube of the specified size.
    • column - Creates a horizontally centered column of the specified size.
    • boxZ - Creates a vertically centered (around the X axis) cube/column of the specified size.
    • getShapeForEachState now returns a Function which wraps the ImmutableMap, there is also a method that only considers the specified properties instead of all possible states.
  • net.minecraft.world.phys.shapes
    • DiscreteVoxelShape#rotate - Rotates a voxel shape according to the permutation of the OctahedralGroup.
    • Shapes
      • blockOccudes -> blockOccludes
      • rotate - Rotates a given voxel shape according to the permutation of the OctahedralGroup around the provided vector, or block center if not specified.
      • equal - Checks if two voxel shapes are equivalent.
      • rotateHorizontalAxis - Creates a map of axes to VoxelShapes of a block being rotated around the y axis.
      • rotateAllAxis - Creates a map of axes to VoxelShapes of a block being rotated around any axis.
      • rotateHorizontal - Creates a map of directions to VoxelShapes of a block being rotated around the y axis.
      • rotateAll - Creates a map of directions to VoxelShapes of a block being rotated around the any axis.
      • rotateAttachFace - Creates a map of faces to a map of directions to VoxelShapes of a block being rotated around the y axis when attaching to the faces of other blocks.
    • VoxelShape#move now has an overload to take in a Vec3i

Weapons, Tools, and Armor: Removing the Redundancies

There have been a lot of updates to weapons, tools, and armor that removes the reliance on the hardcoded base classes of SwordItem, DiggerItem, and ArmorItem, respectively. These have been replaced with their associated data components WEAPON for damage, TOOL for mining, ARMOR for protection, and BLOCKS_ATTACKS for shields. Additionally, the missing attributes are usually specified by setting the ATTRIBUTE_MODIFIERS, MAX_DAMAGE, MAX_STACK_SIZE, DAMAGE, REPAIRABLE, and ENCHANTABLE. Given that pretty much all of the non-specific logic has moved to a data component, these classes have now been completely removed. Use one of the available item property methods or call Item$Properties#component directly to set up each item as a weapon, tool, armor, or some combination of the three.

Constructing a BlockAttacks component for a shield-like item:

var blocker = new BlocksAttacks(
    // The number of seconds to wait when the item is being used
    // before the blocking effect is applied.
    1.2f,
    // A scalar to change how many ticks the blocker is disabled
    // for. If negative, the blocker cannot normally be disabled.
    0.5f,
    // A list of reductions for what type and how much of a damage type
    // is blocked by this blocker.
    List.of(
        new DamageReduction(
            // The horizontal blocking angle of the shield required to apply
            // the reduction
            90f,
            // A set of damage types this reduction should apply for.
            // When empty, it applies for all damage types.
            Optional.empty(),
            // The base damage to reduce the attack by.
            1f,
            // A scalar representing the fraction of the damage blocked.
            0.5f
        )
    ),
    // A function that determines how much durability to remove to the blocker.
    new ItemDamageFunction(
        // A threshold that specifies the minimum amount of damage required
        // to remove durability from the blocker.
        4f,
        // The base durability to remove from the blocker.
        1f,
        // A scalar representing the fraction of the damage to convert into
        // removed durability.
        0.5f
    ),
    // A tag key containing the items that can bypass the blocker and deal
    // damage directly to the wielding entity. If empty, no item can bypass
    // the blocker.
    Optional.of(DamageTypeTags.BYPASSES_SHIELD),
    // The sound to play when the blocker successfully mitigates some damage.
    Optional.of(SoundEvents.SHIELD_BLOCK),
    // The sound to play when the blocker is disabled by a weapon.
    Optional.of(SoundEvents.SHIELD_BREAK)
);

Constructing a Weapon component for a sword-like item:

var weapon = new Weapon(
    // The amount of durability to remove from the item.
    3,
    // The number of seconds a `BlocksAttack`s component item should
    // be disabled for when hit with this weapon.
    5f
);
  • net.minecraft.core.component.DataComponents
    • UNBREAKABLE is now a Unit instance
    • HIDE_ADDITIONAL_TOOLTIP, HIDE_TOOLTIP have been bundled in TOOLTIP_DISPLAY, taking in a TooltipDisplay
    • BLOCKS_ATTACKS - A component that determines whether a held item can block an attack from some damage source
    • INSTRUMENT now takes in an InstrumentComponent
    • PROVIDES_TRIM_MATERIAL, PROVIDES_BANNER_PATTERNS handles a provider for their associated types.
    • BEES now takes in a Bees component
    • BREAK_SOUND - The sound to play when the item breaks.
  • net.minecraft.data.recipes
    • RecipeProvider#trimSmithing now takes in the key for the TrimPattern
    • SmithingTrimRecipeBuilder now takes in a holder for the TrimPattern
  • net.minecraft.world.entity.LivingEntity
    • blockUsingShield -> blockUsingItem
    • blockedByShield -> blockedByItem
    • hurtCurrentlyUsedShield is removed
    • canDisableBlocking -> getSecondsToDisableBlocking, not one-to-one
    • applyItemBlocking - Applies the damage reduction done when blocking an attack with an item.
    • isDamageSourceBlocked is removed
  • net.minecraft.world.entity.player.Player#disableShield -> net.minecraft.world.item.component.BlocksAttacks#disable
  • net.minecraft.world.item
    • AnimalArmorItem class is removed
    • ArmorItem class is removed
    • AxeItem now extends Item
    • BannerPatternItem class is removed
    • DiggerItem class is removed
    • FireworkStarItem class is removed
    • HoeItem now extends Item
    • InstrumentItem no longer takes in the tag key
    • Item
      • getBreakingSound is removed
      • $Properties
        • tool - Sets the item as a tool.
        • pickaxe - Sets the item as a pickaxe.
        • sword - Sets the item as a sword.
        • axe - Sets the item as an axe.
        • hoe - Sets the item as a hoe.
        • shovel - Sets the item as a shovel.
        • trimMaterial - Sets the item as providing a trim material.
    • ItemStack#getBreakingSound is removed
    • PickaxeItem class is removed
    • ShovelItem now extends Item
    • SwordItem class is removed
    • ToolMaterial#applyToolProperties now takes in a boolean of whether the weapon can disable a blocker (e.g., shield)
  • net.minecraft.world.item.component
    • Bees - A component that holds the occupants of a beehive.
    • BlocksAttacks - A component for blocking an attack with a held item.
    • InstrumentComponent - A component that holds the sound an instrument plays.
    • ProvidesTrimMaterial - A component that provides a trim material to use on some armor.
    • Tool now takes in a boolean representing if the tool can destroy blocks in creative
    • Unbreakable class is removed
    • Weapon - A data component that holds how much damage the item can do and for how long it disables blockers (e.g., shield).
  • net.minecraft.world.item.equipment
    • AllowedEntitiesProvider - A functional interface for getting the entities that are allowed to handle the associated logic.
    • ArmorMaterial
      • humanoidProperties -> Item$Properties#humanoidArmor
      • animalProperties -> Item$Properties#wolfArmor, horseArmor
      • createAttributes is now public
    • Equippable
      • equipOnInteract - When true, the item can be equipped to another entity when interacting with them.
      • saddle - Creates an equippable for a saddle.
      • equipOnTarget - Equips the item onto the target entity.

Extrapolating the Saddles: Equipment Changes

A new EquipmentSlot has been added for saddles, which brings with it new changes for genercizing slot logic.

First, rendering an equipment slot for an entity can now be handled as an additional RenderLayer called SimpleEquipmentLayer. This takes in the entity renderer, the EquipmentLayerRenderer, the layer type to render, a function to get the ItemStack from the entity state, and the adult and baby models. The renderer will attempt to look up the client info from the associated equippable data component and use that to render the laters as necessary.

Next, instead of having individual lists for each equipment slot on the entity, there is now a general EntityEquipment object that holds a delegate to a map of slots to ItemStacks. This simplifies the storage logic greatly.

Finally, equippables can now specify whether an item should be equipped to a mob on interact (usually right-click) by setting equipOnInteract.

  • net.minecraft.client.model
    • CamelModel
      • head is now public
      • createBodyMesh - Creates the mesh definition for a camel.
    • CamelSaddleModel - A model for a camel with a saddle.
    • DonkeyModel#createSaddleLayer - Creates the layer definition for a donkey with a saddle.
    • EquineSaddleModel - A model for an equine animal with a saddle.
    • PolarBearModel#createBodyLayer now takes in a boolean for if the entity is a baby
  • net.minecraft.client.renderer.entity.layers.HorseArmorLayer, SaddleLayer -> SimpleEquipmentLayer
  • net.minecraft.client.renderer.entity.state
    • CamelRenderState#isSaddled -> saddle, not one-to-one
    • EquineRenderState#isSaddled -> saddle, not one-to-one
    • PigRenderState#isSaddled -> saddle, not one-to-one
    • SaddleableRenderState class is removed
    • StriderRenderState#isSaddled -> saddle, not one-to-one
    • CamelRenderState#isSaddled -> saddle, not one-to-one
  • net.minecraft.client.resources.model.EquipmentClientInfo$LayerType now has:
    • PIG_SADDLE
    • STRIDER_SADDLE
    • CAMEL_SADDLE
    • HORSE_SADDLE
    • DONKEY_SADDLE
    • MULE_SADDLE
    • ZOMBIE_HORSE_SADDLE
    • SKELETON_HORSE_SADDLE
    • trimAssetPrefix - Returns the prefix applied to the texture containing the armor trims for the associated type.
  • net.minecraft.world.entity
    • EntityEquipment - A map of slots to item stacks representing the equipment of the entity.
    • EquipmentSlot
      • SADDLE, $Type#SADDLE
      • canIncreaseExperience - Whether the slot can increase the amount of experience earned when killing a mob.
    • EquipmentSlotGroup is now an iterable
      • SADDLE
      • slots - Returns the slots within the group.
    • LivingEntity
      • getEquipSound - Gets the sound to play when equipping an item into a slot.
      • getArmorSlots, getHandSlots, getArmorAndBodyArmorSlots, getAllSlots are removed
      • equipment - The equipment worn by the entity.
      • createEquipment - Sets the default equipment worn by the entity.
      • drop - Drops the specified stack.
      • getItemBySlot, setItemBySlot are no longer abstract.
      • verfiyEquippedItem is removed
    • Mob
      • isSaddled - Checks if an item is in the saddle slot.
      • createEquipmentSlotContainer - Creates a single item container for the equipment slot.
    • OwnableEntity#getRootOwner - Gets the highest level owner of the entity.
    • Saddleable interface is removed
  • net.minecraft.world.entity.animal.horse.AbstractHorse
    • syncSaddletoClients is removed
    • getBodyArmorAccess is removed
  • net.minecraft.world.entity.player
    • Inventory
      • armor, offhand -> EQUIPMENT_SLOT_MAPPING, not one-to-one
      • selected is now private
      • setSelectedHotbarSlot -> setSelectedSlot
        • Getter also exists getSelectedSlot
      • getSelected -> getSelectedItem
        • Setter also exists setSelectedItem
      • getNonEquipmentItems - Returns the list of non-equipment items in the inventory.
      • getDestroySpeed is removed
      • getArmor is removed
    • PlayerEquipment - Equipment that is worn by the player.
  • net.minecraft.world.item
    • Item#inventoryTick(ItemStack, Level, Entity, int, boolean) -> inventoryTick(ItemStack, ServerLevel, Entity, EquipmentSlot)
    • SaddleItem class is removed

Weighted List Rework

The weighted random lists have been redesigned into a basic class that hold weighted entries, and a helper class that can obtain weights from the objects themselves.

First there is WeightedList. It is effectively the replacement for SimpleWeightedRandomList, working the exact same way by storing Weighted (replacement for WeightedEntry) entries in the list itself. Internally, the list is either stored as a flat array of object entries, or the compact weighted list if the total weight is greater than 64. Then, to get a random element, either getRandom or getRandomOrThrow can be called to obtain an entry. Both of these methods will either return some form of an empty object or exception if there are no elements in the list.

Then there are the static helpers within WeightedRandom. These take in raw lists and some ToIntFunction that gets the weight from the list’s object. Some methods also take in an integer either representing the largest index to choose from or the entry associated with the weighted index.

  • net.minecraft.client.resources.model.WeightedBakedModel now takes in a WeightedList instead of a SimpleWeightedRandomList
  • net.minecraft.util.random
    • SimpleWeightedRandomList, WeightedRandomList -> WeightedList, now final and not one-to-one
      • contains - Checks if the list contains this element.
    • Weight class is removed
    • WeightedEntry -> Weighted
    • All WeightedRandom static methods now take in a ToIntFunction to get the weight of some entry within the provided list
  • net.minecraft.util.valueproviders.WeightedListInt now takes in a WeightedList
  • net.minecraft.world.level.SpawnData#LIST_CODEC is now a WeightedList of SpawnData
  • net.minecraft.world.level.biome
    • Biome#getBackgroundMusic is now a WeightedList of Music
    • BiomeSpecialEffects#getBackgroundMusic, $Builder#backgroundMusic is now a WeightedList of Music
    • MobSpawnSettings#EMPTY_MOB_LIST, getMobs is now a WeightedList
  • net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerConfig#spawnPotentialsDefinition, lootTablesToEject now takes in a WeightedList
  • net.minecraft.world.level.chunk.ChunkGenerator#getMobsAt now returns a WeightedList
  • net.minecraft.world.level.levelgen.feature.stateproviders.WeightedStateProvider now works with WeightedLists
  • net.minecraft.world.level.levelgen.heightproviders.WeightedListHeight now works with WeightedLists
  • net.minecraft.world.level.levelgen.structure.StructureSpawnOverride now takes in a WeightedList
  • net.minecraft.world.level.levelgen.structure.pools.alias
    • PoolAliasBinding#random, randomGroup now takes in a WeightedList
    • Random now takes in a WeightedList
    • RandomGroup now takes in a WeightedList
  • net.minecraft.world.level.levelgen.structure.structures.NetherFortressStructure#FORTRESS_ENEMIES is now a WeightedList

Tickets

Tickets have been reimplemented into a half type registry-like, half hardcoded system. The underlying logic of keeping a chunk loaded or simulated for a certain period of time still exists; however, the logic associated with each ticket is hardcoded into their appropriate locations, such as the forced or player loading tickets.

Tickets begin with their registered TicketType, which contains information about how many ticks should the ticket should last for (or 0 when permanent), whether the ticket should be saved to disk, and what the ticket is used for. A ticket has two potential uses: one for loading the chunk and keeping it loaded, and one for simulating the chunk based on the expected movement of the ticket creator. Most ticks specify that they are for both loading and simulation.

There are two special types that have additional behavior associated with them. TicketType#FORCED has some logic for immediately loading the chunk and keeping it loaded. TicketType#UNKNOWN cannot be automatically timed out, meaning they are never removed unless explicitly specified.

// You need to register the ticket type to `BuiltInRegistries#TICKET_TYPE`
public static final TicketType EXAMPLE = new TicketType(
    // The amount of ticks before the ticket is removed
    // Set to 0 if it should not be removed
    0L,
    // Whether the ticket should be saved to disk
    true,
    // What the ticket will be used for
    TicketType.TicketUse.LOADING_AND_SIMULATION
);

Then there is the Ticket class, which are actually stored and handled within the TicketStorage. The Ticket class takes in the type of the ticket and uses it to automatically populate how long until it expires. It also takes in the ticket level, which is a generally a value of 31 (for entity ticking and block ticking), 32 (for block ticking), or 33 (only can access static or modify, not naturally update) minus the radius of chunks that can be loaded. A ticket is then added to the process by calling TicketStorage#addTicketWithRadius or its delegate ServerChunkCache#addTicketWithRadius. There is also addTicket if you wish to specify the ticket manually rather than having it computed based on its radius.

  • net.minecraft.server.level
    • ChunkMap now takes in a TicketStorage
      • $TrackedEntity#broadcastIgnorePlayers - Broadcasts the packet to all player but those within the UUID list.
    • DistanceManager
      • chunksToUpdateFutures is now protected and takes in a TicketStorage
      • purgeStaleTickets -> net.minecraft.world.level.TicketStorage#purgeStaleTickets
      • getTicketDebugString -> net.minecraft.world.level.TicketStorage#getTicketDebugString
      • getChunkLevel - Returns the current chunk level or the simulated level when the provided boolean is true.
      • getTickingChunks is removed
      • removeTicketsOnClosing is removed
      • $ChunkTicketTracker -> LoadingChunkTracker, or SimulationChunkTracker
    • ServerChunkCache
      • addRegionTicket -> addTicketWithRadius, or addTicket
      • removeRegionTicket -> removeTicketWithRadius
      • removeTicketsOnClosing -> deactivateTicketsOnClosing
    • Ticket is no longer final or implements Comparable
      • The constructor no longer takes in a key
      • CODEC
      • setCreatedTick, timedOut -> resetTicksLeft, decreaseTicksLeft, isTimedOut; not one-to-one
    • TicketType is now a record and no longer has a generic
      • getComparator is removed
      • doesLoad, doesSimulate - Checks whether the ticket use is for their particular instance.
      • $TicketUse - What a ticket can be used for.
    • TickingTracker -> SimulationChunkTracker
  • net.minecraft.world.level.ForcedChunksSavedData -> TicketStorage
  • net.minecraft.world.level.chunk.ChunkSource
    • updateChunkForced now returns a boolean indicating if the chunk has been forcefully loaded
    • getForceLoadedChunks - Returns all chunks that have been forcefully loaded.

The Game Test Overhaul

Game tests have been completely overhauled into a registry based system, completely revamped from the previous automatic annotation-driven system. However, most implementations required to use the system must be implemented yourself rather than provided by vanilla. As such, this explanation will go over the entire system, including which parts need substantial work to use it similarly to the annotation-driven system of the previous version.

The Environment

All game tests happen within some environment. Most of the time, a test can occur independent of the area, but sometimes, the environment needs to be curated in some fashion, such as checking whether an entity or block does something at a given time or whether. To facilitate the setup and teardown of the environment for a given test instance, a TestEnvironmentDefinition is created.

A TestEnvironmentDefinition works similarly to the BeforeBatch and AfterBatch annotations. The environment contains two methods setup and teardown that manage the ServerLevel for the test. The environments are structured in a type-based registry system, meaning that every environment registers a MapCodec to built-in registry minecraft:test_environment_definition_type that is then consumed via the TestEnvironmentDefinition in a datapack registry minecraft:test_environment.

Vanilla, by default, provides the minecraft:default test environment which does not do anything. However, additional test environments can be created using the available test definition types.

Game Rules

This environment type sets the game rules to use for the test. During teardown, the game rules are set back to their default value.

// examplemod:example_environment
// In 'data/examplemod/test_environment/example_environment.json'
{
    "type": "minecraft:game_rules",

    // A list of game rules with boolean values to set
    "bool_rules": [
        {
            // The name of the rule
            "rule": "doFireTick",
            "value": false
        }
        // ...
    ],

    // A list of game rules with integer values to set
    "int_rules": [
        {
            "rule": "playersSleepingPercentage",
            "value": 50
        }
        // ...
    ]
}

Time of Day

This environment type sets the time to some non-negative integer, similar to how the /time set <number> command is used.

// examplemod:example_environment
// In 'data/examplemod/test_environment/example_environment.json'
{
    "type": "minecraft:time_of_day",

    // Sets the time of day in the world
    // Common values:
    // - Day      -> 1000
    // - Noon     -> 6000
    // - Night    -> 13000
    // - Midnight -> 18000
    "time": 13000
}

Weather

This environment type sets the weather, similar to how the /weather command is used.

// examplemod:example_environment
// In 'data/examplemod/test_environment/example_environment.json'
{
    "type": "minecraft:weather",

    // Can be one of three values:
    // - clear   (No weather)
    // - rain    (Rain)
    // - thunder (Rain and thunder)
    "weather": "thunder"
}

Function

This environment type provides two ResourceLocations to mcfunctions to setup and teardown the level, respectively.

// examplemod:example_environment
// In 'data/examplemod/test_environment/example_environment.json'
{
    "type": "minecraft:function",

    // The setup mcfunction to use
    // If not specified, nothing will be ran
    // Points to 'data/examplemod/function/example/setup.mcfunction'
    "setup": "examplemod:example/setup",

    // The teardown mcfunction to use
    // If not specified, nothing will be ran
    // Points to 'data/examplemod/function/example/teardown.mcfunction'
    "teardown": "examplemod:example/teardown"
}

Composite

If multiple combinations are required, then the composite environment type (aptly named all_of) can be used to string multiple of the above environment types together.

// examplemod:example_environment
// In 'data/examplemod/test_environment/example_environment.json'
{
    "type": "minecraft:all_of",

    // A list of test environments to use
    // Can either specified the registry name or the environment itself
    "definitions": [
        // Points to 'data/minecraft/test_environment/default.json'
        "minecraft:default",
        {
            // A raw environment definition
            "type": "..."
        }
        // ...
    ]
}

Custom Types

If none of the types above work, then a custom definition can be created by implementing TestEnvironmentDefinition and creating an associated MapCodec:

public record ExampleEnvironmentType(int value1, boolean value2) implements TestEnvironmentDefinition {

    // Construct the map codec to register
    public static final MapCodec<ExampleEnvironmentType> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
            Codec.INT.fieldOf("value1").forGetter(ExampleEnvironmentType::value1),
            Codec.BOOL.fieldOf("value2").forGetter(ExampleEnvironmentType::value2)
        ).apply(instance, ExampleEnvironmentType::new)
    );

    @Override
    public void setup(ServerLevel level) {
        // Setup whatever is necessary here
    }

    @Override
    public void teardown(ServerLevel level) {
        // Undo whatever was changed within the setup method
        // This should either return to default or the previous value
    }

    @Override
    public MapCodec<ExampleEnvironmentType> codec() {
        return CODEC;
    }
}

Then register the MapCodec using whatever registry method is required by your mod loader:

Registry.register(
    BuiltInRegistries.TEST_ENVIRONMENT_DEFINITION_TYPE,
    ResourceLocation.fromNamespaceAndPath("examplemod", "example_environment_type"),
    ExampleEnvironmentType.CODEC
);

Finally, you can use it in your environment definition:

// examplemod:example_environment
// In 'data/examplemod/test_environment/example_environment.json'
{
    "type": "examplemod:example_environment_type",

    "value1": 0,
    "value2": true
}

Test Functions

The initial concept of game tests were structured around running functions from GameTestHelper determining whether the test succeeds or fails. Test functions are the registry-driven representation of those. Essentially, every test function is a method that takes in a GameTestHelper.

At the moment, vanilla only provides minecraft:always_pass, which just calls GameTestHelper#succeed. Test functions are also not generated, meaning it simply runs the value with whatever is provided. As such, a test function should generally represent a single old game test:

Registry.register(
    BuiltInRegistries.TEST_FUNCTION,
    ResourceLocation.fromNamespaceAndPath("examplemod", "example_function"),
    (GameTestHelper helper) -> {
        // Run whatever game test commands you want
        helper.assertBlockPresent(...);

        // Make sure you have some way to succeed
        helper.succeedIf(() -> ...);
    }
);

Test Data

Now that we have environments and test functions, we can get into defining our game test. This is done through TestData, which is the equivalent of the GameTest annotation. The only things changed are that structures are now referenced by their ResourceLocation via structure, GameTest#timeoutTicks is now renamed to TestData#maxTicks, and instead of specifying GameTest#rotationSteps, you simply provide the Rotation via TestData#rotation. Everything else remains the same, just represented in a different format.

The Game Test Instance

With the TestData in hand, we can now link everything together through the GameTestInstance. This instance is what actually represents a single test. Once again, vanilla only provides the default minecraft:always_pass, so we will need to construct the instance ourselves.

The Original Instance

The previous game tests are implemented using minecraft:function, which links a test function to the test data.

// examplemod:example_test
// In 'data/examplemod/test_instance/example_test.json'
{
    "type": "minecraft:function",

    // Points to a 'Consumer<GameTestHelper>' in the test function registry
    "function": "examplemod:example_function",

    // The 'TestData' information

    // The environment to run the test in
    // Points to 'data/examplemod/test_environment/example_environment.json'
    "environment": "examplemod:example_environment",
    // The structure used for the game test
    // Points to 'data/examplemod/structure/example_structure.nbt'
    "structure": "examplemod:example_structure",
    // The number of ticks that the game test will run until it automatically fails
    "max_ticks": 400,
    // The number of ticks that are used to setup everying required for the game test
    // This is not counted towards the maximum number of ticks the test can take
    // If not specified, defaults to 0
    "setup_ticks": 50,
    // Whether the test is required to succeed to mark the batch run as successful
    // If not specified, defaults to true
    "required": true,
    // Specifies how the structure and all subsequent helper methods should be rotated for the test
    // If not specified, nothing is rotated
    "rotation": "clockwise_90",
    // When true, the test can only be ran through the `/test` command
    // If not specified, defaults to false
    "manual_only": true,
    // Specifies the maximum number of times that the test can be reran
    // If not specified, defaults to 1
    "max_attempts": 3,
    // Specifies the minimum number of successes that must occur for a test to be marked as successful
    // This must be less than or equal to the maximum number of attempts allowed
    // If not specified, defaults to 1
    "required_successes": 1,
    // Returns whether the structure boundary should keep the top empty
    // This is currently only used in block-based test instances
    // If not specified, defaults to false 
    "sky_access": false
}

Block-Based Instances

Vanilla also provides a block-based test instance via minecraft:block_based. This is handled through via structures with test blocks receiving signals via Level#hasNeighborSignal. To start, a structure must have one test block which is set to its start mode. This block is then triggered, sending a fifteen signal pulse for one tick. Structures may then have as many test blocks with either a log, accept, or fail mode set. Log test blocks also send a fifteen signal pulse when activated. Accept and fail test blocks either succeed or fail the game test if any of them are activated (success takes precedent over failure).

As this test relies on test blocks in the structure, no additional information is required other than the test data:

// examplemod:example_test
// In 'data/examplemod/test_instance/example_test.json'
{
    "type": "minecraft:block_based",

    // The 'TestData' information

    // Points to 'data/examplemod/test_environment/example_environment.json'
    "environment": "examplemod:example_environment",
    // Points to 'data/examplemod/structure/example_structure.nbt'
    "structure": "examplemod:example_structure",
    "max_ticks": 400,
    "setup_ticks": 50,
    "required": true,
    "rotation": "clockwise_90",
    "manual_only": true,
    "max_attempts": 3,
    "required_successes": 1,
    "sky_access": false
}

Custom Tests

If you need to implement your own test-based logic, whether using a more dynamic feature or because you can’t be bothered to migrated all of your data logic to the new systems, you can create your own custom test instance by extending GameTestInstance and creating an associated MapCodec:

public class ExampleTestInstance extends GameTestInstance {

    // Construct the map codec to register
    public static final MapCodec<ExampleTestInstance> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
            Codec.INT.fieldOf("value1").forGetter(test -> test.value1),
            Codec.BOOL.fieldOf("value2").forGetter(test -> test.value2),
            TestData.CODEC.forGetter(ExampleTestInstance::info)
        ).apply(instance, ExampleTestInstance::new)
    );

    public ExampleTestInstance(int value1, boolean value2, TestData<Holder<TestEnvironmentDefinition>> info) {
        super(info);
    }

    @Override
    public void run(GameTestHelper helper) {
        // Run whatever game test commands you want
        helper.assertBlockPresent(...);

        // Make sure you have some way to succeed
        helper.succeedIf(() -> ...);
    }

    @Override
    public MapCodec<ExampleTestInstance> codec() {
        return CODEC;
    }

    @Override
    protected MutableComponent typeDescription() {
        // Provides a description about what this test is supposed to be
        // Should use a translatable component
        return Component.literal("Example Test Instance");
    }
}

Then register the MapCodec using whatever registry method is required by your mod loader:

Registry.register(
    BuiltInRegistries.TEST_INSTANCE_TYPE,
    ResourceLocation.fromNamespaceAndPath("examplemod", "example_test_instance"),
    ExampleTestInstance.CODEC
);

Finally, you can use it in your test instance:

// examplemod:example_test
// In 'data/examplemod/test_instance/example_test.json'
{
    "type": "examplemod:example_test_instance",

    "value1": 0,
    "value2": true,

    // The 'TestData' information

    // Points to 'data/examplemod/test_environment/example_environment.json'
    "environment": "examplemod:example_environment",
    // Points to 'data/examplemod/structure/example_structure.nbt'
    "structure": "examplemod:example_structure",
    "max_ticks": 400,
    "setup_ticks": 50,
    "required": true,
    "rotation": "clockwise_90",
    "manual_only": true,
    "max_attempts": 3,
    "required_successes": 1,
    "sky_access": false
}
  • net.minecraft.client.renderer.blockentity
    • BeaconRenderer now has a generic that takes in a subtype of BlockEntity and BeaconBeamOwner
    • StructureBlockRenderer -> BlockEntityWithBoundingBoxRenderer, not one-to-one
  • net.minecraft.core.registries.Registries#TEST_FUNCTION, TEST_ENVIRONMENT_DEFINITION_TYPE, TEST_INSTANCE_TYPE
  • net.minecraft.gametest.Main - The entrypoint for the game test server.
  • net.minecraft.gametest.framework
    • AfterBatch, BeforeBatch annotations are removed
    • BlockBasedTestInstance - A test instance for testing the test block.
    • BuiltinTestFunctions - Contains all registered test functions.
    • FailedTestTracker - An object for holding all game tests that failed.
    • FunctionGameTestInstance - A test instance for running a test function.
    • GameTest annotation is removed
    • GameTestAssertException now extends GameTestException
    • GameTestException - An exception thrown during the execution of a game test.
    • GameTestBatch now takes in an index and environment definition instead of a name and batch setups
    • GameTestBatchFactory
      • fromTestFunction -> divideIntoBatches, not one-to-one
      • toGameTestInfo is removed
      • toGameTestBatch now takes in an environment definition and an index
      • $TestDecorator - Creates a list of test infos from a test instance and level.
    • GameTestEnvironments - Contains all environments used for batching game test instances.
    • GameTestGenerator annotation is removed
    • GameTestHelper
      • tickBlock - Ticks the block at the specific position.
      • assertionException - Returns a new exception to throw on error.
      • getBlockEntity now takes in a Class to cast the block entity to
      • assertBlockTag - Checks whether the block at the position is within the provided tag.
      • assertBlock now takes in a block -> component function for the error message.
      • assertBlockProperty now takes in a Component instead of a string
      • assertBlockState now takes in either nothing, a blockstate -> component function, or a supplied component
      • assertRedstoneSignal now takes in a supplied component
      • assertContainerSingle - Asserts that a container contains exactly one of the item specified.
      • assertEntityPosition, assertEntityProperty now takes in a component
      • fail now takes in a Component for the error message
      • assertTrue, assertValueEqual, assertFalse now takes in a component
    • GameTestInfo now takes in a holder-wrapped GameTestInstance instead of a TestFunction
      • setStructureBlockPos -> setTestBlockPos
      • placeStructure now returns nothing
      • getTestName - id, not one-to-one
      • getStructureBlockPos -> getTestBlockPos
      • getStructureBlockEntity -> getTestInstanceBlockEntity
      • getStructureName -> getStructure
      • getTestFunction -> getTest, getTestHolder, not one-to-one
      • getOrCalculateNorthwestCorner, setNorthwestCorner are removed
      • fail now takes in a Component or GameTestException instead of a Throwable
      • getError now returns a GameTestException instead of a Throwable
    • GameTestInstance - Defines a test to run.
    • GameTestInstances - Contains all registered tests.
    • GameTestMainUtil - A utility for running the game test server.
    • GameTestRegistry class is removed
    • GameTestSequence
      • tickAndContinue, tickAndFailIfNotComplete now take in an integer for the tick instead of a long
      • thenFail now takes in a supplied GameTestException instead of a Throwable
    • GameTestServer#create now takes in an optional string and boolean instead of the collection of test functions and the starting position
    • GeneratedTest - A object holding the test to run for the given environment and the function to apply
    • GameTestTicker$State - An enum containing what state the game test ticker is currently executing.
    • GameTestTimeoutException now extends GameTestException
    • ReportGameListener#spawnBeacon is removed
    • StructureBlockPosFinder -> TestPosFinder
    • StructureUtils
      • testStructuresDir is now a path
      • getStructureBounds, getStructureBoundingBox, getStructureOrigin, addCommandBlockAndButtonToStartTest are removed
      • createNewEmptyStructureBlock -> createNewEmptyTest, not one-to-one
      • getStartCorner, prepareTestStructure, encaseStructure, removeBarriers are removed
      • findStructureBlockContainingPos -> findTestContainingPos
      • findNearestStructureBlock -> findNearestTest
      • findStructureByTestFunction, createStructureBlock are removed
      • findStructureBlocks -> findTestBlocks
      • lookedAtStructureBlockPos -> lookedAtTestPos
    • TestClassNameArgument is removed
    • TestEnvironmentDefinition - Defines the environment that the test is run on by setting the data on the level appropriately.
    • TestFinder no longer contains a generic for the context
      • $Builder#allTests, allTestsInClass, locateByName are removed
      • $Builder#byArgument -> byResourceSelection
    • TestFunction -> TestData, not one-to-one
    • TestFunctionArgument -> net.minecraft.commands.arguments.ResourceSelectorArgument
    • TestFunctionFinder -> TestInstanceFinder
    • TestFunctionLoader - Holds the list of test functions to load and run.
    • UnknownGameTestException - An exception that is thrown when the error of the game test is unknown.
  • net.minecraft.network.protocol.game
    • ClientboundTestInstanceBlockState - A packet sent to the client containing the status of a test along with its size.
    • ServerboundSetTestBlockPacket - A packet sent to the server to set the information within the test block to run.
    • ServerboundTestInstanceBlockActionPacket - A packet sent to the server to set up the test instance within the test block.
  • net.minecraft.world.entity.player.Player
    • openTestBlock - Opens a test block.
    • openTestInstanceBlock - Opens a test block for a game test instance.
  • net.minecraft.world.level.block
    • TestBlock - A block used for running game tests.
    • TestInstanceBlock - A block used for managing a single game test.
  • net.minecraft.world.level.block.entity
    • BeaconBeamOwner - An interface that represents a block entity with a beacon beam.
    • BeaconBlockEntity now implements BeaconBeamOwner
      • BeaconBeamSection -> BeaconBeamOwner$Section
    • BoundingBoxRenderable - An interface that represents a block entity that can render an arbitrarily-sized bounding box.
    • StructureBlockEntity now implements BoundingBoxRenderable
    • TestBlockEntity - A block entity used for running game tests.
    • TestInstanceBlockEntity - A block entity used for managing a single game test.
  • net.minecraft.world.level.block.state.properties.TestBlockMode - A property for representing the current state of the game tests associated with a test block.

Data Component Getters

The data component system can now be represented on arbitrary objects through the use of the DataComponentGetter. As the name implies, the getter is responsible for getting the component from the associated type key. Both block entities and entities use the DataComponentGetter to allow querying the internal data, such as variant information or custom names. They both also have methods for collecting the data components from another holder (via applyImplicitComponents or applyImplicitComponent). Block entities also contain a method for collection to another holder via collectImplicitComponents.

Items

ItemSubPredicates have been completely replaced with DataComponentPredicates. Each sub predicate has its appropriate analog within the system.

  • net.minecraft.advancements.critereon.* -> net.minecraft.core.component.predicates.*
    • ItemAttributeModifiersPredicate -> AttributeModifiersPredicate
    • ItemBundlePredicate -> BundlePredicate
    • ItemContainerPredicate -> ContainerPredicate
    • ItemCustomDataPredicate -> CustomDataPredicate
    • ItemDamagePredicate -> DamagePredicate
    • ItemEnchantmentsPredicate -> EnchantmentsPredicate
    • ItemFireworkExplosionPredicate -> FireworkExplosionPredicate
    • ItemFireworksPredicate -> FireworksPredicate
    • ItemJukeboxPlayablePredicate -> JukeboxPlayablePredicate
    • ItemPotionsPredicate -> PotionsPredicate
    • ItemSubPredicate -> DataComponentPredicate, not one-to-one
      • SINGLE_STREAM_CODEC
    • ItemSubPredicates -> DataComponentPredicates, not one-to-one
    • ItemTrimPredicate -> TrimPredicate
    • ItemWritableBookPredicate -> WritableBookPredicate
    • ItemWrittenBookPredicate -> WrittenBookPredicate
  • net.minecraft.advancements.critereon
    • BlockPredicate now takes in a DataComponentMatchers for matching any delegated component data
    • DataComponentMatchers - A predicate that operates on a DataComponentGetter, matching any exact and partial component data on the provider.
    • EntityPredicate now takes in a DataComponentMatchers instead of a Optional<DataComponentExactPredicate>
    • ItemPredicate now takes in a DataComponentMatchers for matching any delegated component data
    • NbtPredicate#matches now takes in a DataComponentGetter instead of an ItemStack
    • SingleComponentItemPredicate now implements DataComponentPredicate instead of ItemSubPredicate
      • matches(ItemStack, T) -> matches(T)
  • net.minecraft.core.component
    • DataComponentPatch
      • DELIMITED_STREAM_CODEC
      • $CodecGetter - Gets the codec for a given component type.
    • DataComponentPredicate -> DataComponentExactPredicate
      • isEmpty - Checks if the expected components list within the predicate is empty.
  • net.minecraft.core.registries.Registries#ITEM_SUB_PREDICATE_TYPE -> DATA_COMPONENT_PREDICATE_TYPE, not one-to-one
  • net.minecraft.world.item.AdventureModePredicate no longer takes in a boolean to show in tooltip
  • net.minecraft.world.item
    • BannerItem#appendHoverTextFromBannerBlockEntityTag is removed
    • Item#appendHoverText(ItemStack, Item.TooltipContext, List<Component>, TooltipFlag) -> appendHoverText(ItemStack, Item.TooltipContext, TooltipDisplay, Consumer<Component>, TooltipFlag), now deprecated
    • ItemStack
      • addToTooltip is now public
      • addDetailsToTooltip - Appends the component details of an item to the tooltip.
    • JukeboxPlayable#showInTooltip is removed
  • net.minecraft.world.item.component
    • BlockItemStateProperties now implements TooltipProvider
    • ChargedProjectiles now implements TooltipProvider
    • CustomData#itemMatcher is removed
    • DyedItemColor#showInTooltip is removed
    • FireworkExplosion#addShapeNameTooltip is removed
    • ItemAttributeModifiers#showInTooltip is removed
    • ItemContainerContents now implements TooltipProvider
    • SeededContainerLoot now implements TooltipProvider
    • TooltipDisplay - A component that handles what should be hidden within an item’s tooltip.
    • TooltipProvider#addToTooltip now takes in a DataComponentGetter
  • net.minecraft.world.item.enchantment.ItemEnchantments#showInTooltip is removed
  • net.minecraft.world.item.equipment.trim.ArmorTrim#showInTooltip is removed
  • net.minecraft.world.item.trading.ItemCost now takes in a DataComponentExactPredicate instead of a DataComponentPredicate
  • net.minecraft.world.level.block.Block#appendHoverText is removed
  • net.minecraft.world.level.block.entity
    • BannerPatternLayers now implements TooltipProvider
    • PotDecorations now implements TooltipProvider
  • net.minecraft.world.level.saveddata.maps.MapId now implements TooltipProvider

Entities

Some EntitySubPredicates for entity variants have been transformed into data components stored on the held item due to a recent change on EntityPredicate now taking in a DataComponentExactPredicate for matching the slots on an entity.

  • net.minecraft.advancements.critereon
    • EntityPredicate now takes in a DataComponentExactPredicate to match the equipment slots checked
    • EntitySubPredicate
      • AXOLTOL -> DataComponents#AXOLOTL_VARIANT
      • FOX -> DataComponents#FOX_VARIANT
      • MOOSHROOM -> DataComponents#MOOSHROOM_VARIANT
      • RABBIT -> DataComponents#RABBIT_VARIANT
      • HORSE -> DataComponents#HORSE_VARIANT
      • LLAMA -> DataComponents#LLAMA_VARIANT
      • VILLAGER -> DataComponents#VILLAGER_VARIANT
      • PARROT -> DataComponents#PARROT_VARIANT
      • SALMON -> DataComponents#SALMON_SIZE
      • TROPICAL_FISH -> DataComponents#TROPICAL_FISH_PATTERN, TROPICAL_FISH_BASE_COLOR, TROPICAL_FISH_PATTERN_COLOR
      • PAINTING -> DataComponents#PAINTING_VARIANT
      • CAT -> DataComponents#CAT_VARIANT, CAT_COLLAR
      • FROG -> DataComponents#FROG_VARIANT
      • WOLF -> DataComponents#WOLF_VARIANT, WOLF_COLLAR
      • PIG -> DataComponents#PIG_VARIANT
      • register with variant subpredicates have been removed
      • catVariant, frogVariant, wolfVariant are removed
      • $EntityHolderVariantPredicateType, $EntityVariantPredicateType are removed
    • SheepPredicate no longer takes in the DyeColor
  • net.minecraft.client.renderer.entity.state.TropicalFishRenderState#variant -> pattern
  • net.minecraft.core.component
    • DataComponentGetter - A getter that obtains data components from some object.
    • DataComponentHolder, DataComponentMap now extends DataComponentGetter
    • DataComponentExactPredicate is now a predicate of a DataComponentGetter
      • expect - A predicate that expects a certain value for a data component.
      • test(DataComponentHolder) is removed
    • DataComponents
      • SHEEP_COLOR - The dye color of a sheep.
      • SHULKER_COLOR - The dye color of a shulker (box).
      • COW_VARIANT - The variant of a cow.
      • CHICKEN_VARIANT - The variant of a chicken.
      • WOLF_SOUND_VARIANT - The sounds played by a wolf.
  • net.minecraft.world.entity
    • Entity now implements DataComponentGetter
      • applyImplicitComponents - Applies the components from the getter onto the entity. This should be overriden by the modder.
      • applyComponentsFromItemStack - Applies the components from the stack onto the entity.
      • castComponentValue - Casts the type of the object to the component type.
      • setComponent - Sets the component data onto the entity.
      • applyImplicitComponent - Applies the component data to the entity. This should be overriden by the modder.
      • applyImplicitComponentIfPresent - Applies the component if it is present on the getter.
    • EntityType#appendCustomNameConfig -> appendComponentsConfig
    • VariantHolder interface is removed
      • As such, all setVariant methods on relevant entities are private while the associated data can also be obtained from the DataComponentGetter
  • net.minecraft.world.entity.animal
    • CatVariant#CODEC
    • Fox$Variant#STREAM_CODEC
    • FrogVariant#CODEC
    • MushroomCow$Variant#STREAM_CODEC
    • Parrot$Variant#STREAM_CODEC
    • Rabbit$Variant#STREAM_CODEC
    • Salmon$Variant#STREAM_CODEC
    • TropicalFish
      • getVariant -> getPattern
      • $Pattern now implements TooltipProvider
    • Wolf -> .wolf.Wolf
    • WolfVariant -> .wolf.WolfVariant, now a record, taking in an $AssetInfo and a SpawnPrioritySelectors
    • WolfVariants -> .wolf.WolfVariants
  • net.minecraft.world.entity.animal.axolotl.Axolotl$Variant#STREAM_CODEC
  • net.minecraft.world.entity.animal.horse
    • Llama$Variant#STREAM_CODEC
    • Variant#STREAM_CODEC
  • net.minecraft.world.entity.animal.wolf
    • WolfSoundVariant - The sounds played by a wolf.
    • WolfSoundVariants - All vanilla wolf sound variants.
  • net.minecraft.world.entity.decoration.Painting
    • VARIANT_MAP_CODEC is removed
    • VARIANT_CODEC is now private
  • net.minecraft.world.entity.npc.VillagerDataHolder#getVariant, setVariant are removed
  • net.minecraft.world.entity.variant.VariantUtils- A utility for getting the variant info of an entity.
  • net.minecraft.world.item
    • ItemStack#copyFrom - Copies the component from the getter.
    • MobBucketItem#VARIANT_FIELD_CODEC -> TropicalFish$Pattern#STREAM_CODEC
  • net.minecraft.world.level.block.entity.BlockEntity#applyImplicitComponents now takes in a DataComponentGetter
    • $DataComponentInput -> DataComponentGetter
  • net.minecraft.world.level.Spawner methods now takes in a CustomData instead of the ItemStack itself

Spawn Conditions

To allow entities to spawn variants randomly but within given conditions, a new registry called SPAWN_CONDITION_TYPE was added. These take in SpawnConditions: a selector that acts like a predicate to take in the context to see whether the given variant can spawn there. All of the variants are thrown into a list and then ordered based on the selected priorty stored in the SpawnProritySelectors. Those with a higher priority will be checked first, with multiple of the same priority selected in the order they are provided. Then, all variants on the same priority level where a condition has been met is selected at random.

// For some object where there are spawn conditions
[
    {
        // The spawn condition being checked
        "condition": {
            "type": "minecraft:biome",
            // Will check that the biome the variant is attempting to spawn in is in the forest
            "biomes": "#minecraft:is_forest"
        },
        // Will check this condition first
        "priority": 1
    },
    {
        // States that the condition will always be true
        "priority": 0
    }
]
  • net.minecraft.core.registries.Registries#SPAWN_CONDITION_TYPE
  • net.minecraft.world.entity.variant
    • BiomeCheck - A spawn condition that checks whether the entity is in one of the given biomes.
    • MoonBrightnessCheck - A spawn condition that checks the brightness of the moon.
    • PriorityProvider - An interface which orders the condition selectors based on some priority integer.
    • SpawnCondition - Checks whether an entity can spawn at this location.
    • SpawnConditions - The available spawn conditions to choose from.
    • SpawnContext - An object holding the current position, level, and biome the entity is being spawned within.
    • SpawnPrioritySelectors - A list of spawn conditions to check against the entity. Used to select a random variant to spawn in a given location.
    • StructureCheck - A spawn condition that checks whether the entity is within a structure.

Variant Datapack Registries

Frog, cat, cow, chicken, pig, and wolf, and wolf sound variants are datapack registry objects, meaning that most references now need to be referred to through the RegistryAccess or HolderLookup$Provider instance.

For a frog, cat, or wolf:

// A file located at:
// - `data/examplemod/frog_variant/example_frog.json`
// - `data/examplemod/cat_variant/example_cat.json`
// - `data/examplemod/wolf_variant/example_wolf.json`
{
    // Points to a texture at `assets/examplemod/textures/entity/cat/example_cat.png`
    "asset_id": "examplemod:entity/cat/example_cat",
    "spawn_conditions": [
        // The conditions for this variant to spawn
        {
            "priority": 0
        }
    ]
}

For a pig, cow, or chicken:

// A file located at:
// - `data/examplemod/pig_variant/example_pig.json`
// - `data/examplemod/cow_variant/example_cow.json`
// - `data/examplemod/chicken_variant/example_chicken.json`
{
    // Points to a texture at `assets/examplemod/textures/entity/pig/example_pig.png`
    "asset_id": "examplemod:entity/pig/example_pig",
    // Defines the `PigVariant$ModelType` that's used to select what entity model to render the pig variant with
    "model": "cold",
    "spawn_conditions": [
        // The conditions for this variant to spawn
        {
            "priority": 0
        }
    ]
}

For a wolf sound variant:

// A file located at:
// - `data/examplemod/wolf_sound_variant/example_wolf_sound.json``
{
    // The registry name of the sound event to play randomly on idle
    "ambient_sound": "minecraft:entity.wolf.ambient",
    // The registry name of the sound event to play when killed
    "death_sound": "minecraft:entity.wolf.death",
    // The registry name of the sound event to play randomly when angry on idle
    "growl_sound": "minecraft:entity.wolf.growl",
    // The registry name of the sound event to play when hurt
    "hurt_sound": "minecraft:entity.wolf.hurt",
    // The registry name of the sound event to play randomly
    // 1/3 of the time on idle when health is max
    "pant_sound": "minecraft:entity.wolf.pant",
    // The registry name of the sound event to play randomly
    // 1/3 of the time on idle when health is below max
    "whine_sound": "minecraft:entity.wolf.whine"
}

Client Assets

Raw ResourceLocations within client-facing files for identifiers or textures are being replaced with objects defining an idenfitier along with a potential texture path. There are three main objects to be aware of: ClientAsset, ModelAndTexture, and MaterialAssetGroup.

ClientAsset is an id/texture pair used to point to a texture location. By default, the texture path is contructed from the id, with the path prefixed with textures and suffixed with the PNG extension.

ModelAndTexture is a object/client asset pair used when a renderer should select between multiple models. Usually, the renderer creates a map of the object type to the model, and the object provided to the ModelAndTexture is used as a lookup into the map.

MaterialAssetGroup is a handler for rendering an equipment asset with some trim material. It takes in the base texture used to overlay onto the armor along with any overrides for a given equipment asset.

  • net.minecraft.advancements.DisplayInfo now takes in a ClientAsset instead of only a ResourceLocation for the background texture
  • net.minecraft.client.model
    • AdultAndBabyModelPair - Holds two Model instances that represents the adult and baby of some entity.
    • ChickenModel#createBaseChickenModel - Creates the default chicken model.
    • ColdChickenModel - A variant model for a chicken in cold temperatures.
    • ColdCowModel - A variant model for a cow in cold temperatures.
    • ColdPigModel - A variant model for a big in cold temperatures.
    • CowModel#createBaseCowModel - Creates the base model for a cow.
    • PigModel#createBasePigModel - Creates the default pig model.
    • WarmCowModel - A variant model for a cow in warm temperatures.
  • net.minecraft.client.renderer.entity
    • ChickenRenderer now extends MobRenderer instead of AgeableMobRenderer
    • CowRenderer now extends MobRenderer instead of AgeableMobRenderer
    • PigRenderer now extends MobRenderer instead of AgeableMobRenderer
  • net.minecraft.client.renderer.entity.layers.SheepWoolUndercoatLayer - A layer that renders the wool undercoat of a sheep.
  • net.minecraft.client.renderer.entity.state
    • CowRenderState - A render state for a cow entity.
    • SheepRenderState
      • getWoolColor - Returns the integer color of the sheep wool.
      • isJebSheep - Returns whether the sheep’s name contains the jeb_ prefix.
  • net.minecraft.core.ClientAsset - An object that holds an identifier and a path to some texture.
  • net.minecraft.data.loot.EntityLootSubProvider#killedByFrogVariant now takes in a HolderGetter for the FrogVariant
  • net.minecraft.data.tags.CatVariantTagsProvider class is removed
  • net.minecraft.tags.CatVariantTags class is removed
  • net.minecraft.world.entity.animal
    • AbstractCow - An abstract animal that represents a cow.
    • Chicken#setVariant, getVariant - Handles the variant information of the chicken.
    • ChickenVariant - A class which defines the common-sideable rendering information and biome spawns of a given chicken.
    • ChickenVariants - Holds the keys for all vanilla chicken variants.
    • Cow now extends AbstractCow.
    • CowVariant - A class which defines the common-sideable rendering information and biome spawns of a given cow.
    • CowVariants - Holds the keys for all vanilla cow variants.
    • CatVariant(ResourceLocation) -> CatVariant(ClientAsset, SpawnPrioritySelectors)
    • CatVariants - Holds the keys for all vanilla cat variants.
    • FrogVariant -> .frog.FrogVariant
      • FrogVariant(ResourceLocation) -> FrogVariant(ClientAsset, SpawnPrioritySelectors)
    • MushroomCow now extends AbstractCow
    • PigVariant - A class which defines the common-sideable rendering information and biome spawns of a given pig.
    • TemperatureVariants - An interface which holds the ResourceLocations that indicate an entity within a different temperature.
  • net.minecraft.world.entity.variant.ModelAndTexture - Defines a model with its associated texture.
  • net.minecraft.world.item.equipment.trim
    • MaterialAssetGroup - An asset defines some base and the permutations based on the equipment worn.
    • TrimMaterial now takes in a MaterialAssetGroup instead of the raw base and overrides

Tags and Parsing

Tags have received a rewrite, removing any direct references to types while also sealing and finalizing related classes. Getting a value from the tag now returns an Optional-wrapped entry, unless you call one of the get*Or, where you specify the default value. Objects, on the other hand, do not take in a default, instead returning an empty variant of the desired tag.

// For some `CompoundTag` tag

// Read a value
Optional<Integer> value1 = tag.getInt("value1");
int value1Raw = tag.getIntOr("value1", 0);

// Reading another object
Optional<CompoundTag> childTag = tag.getCompound("childTag");
CompoundTag childTagRaw = tag.getCopmoundOrEmpty("childTag");

Writing with Codecs

CompoundTags now have methods to write and read using a Codec or MapCodec. For a Codec, it will store the serialized data inside the key specified. For a MapCodec, it will merge the fields onto the top level tag.

// For some Codec<ExampleObject> CODEC and MapCodec<ExampleObject> MAP_CODEC
// We will also have ExampleObject example
CompoundTag tag = new CompoundTag();

// For a codec
tag.store("example_key", CODEC, example);
Optional<ExampleObject> fromCodec = tag.read("example_key", CODEC);

// For a map codec
tag.store(MAP_CODEC, example);
Optional<ExampleObject> fromMapCodec = tag.read(MAP_CODEC);

Command Parsers

The packrat parser has been updated with new rules and systems, allowing commands to have parser-based arguments. This comes from the CommandArgumentParser, which parses some grammar to return the desired object. The parser is then consumed by the ParserBasedArgument, where it attempts to parse a string and build any suggestions based on what you’re currently typing. These are both handled through the Grammar class, which implements CommandArgumentParser, constructed using a combination of atoms, dictionaries, rules, and terms.

  • net.minecraft.commands.ParserUtils#parseJson
  • net.minecraft.commands.arguments
    • ComponentArgument now extends ParserBasedArgument
    • NbtTagArgument now extends ParserBasedArgument
    • StyleArgument now extends ParserBasedArgument
  • net.minecraft.commands.arguments.item.ItemPredicateArgument now extends ParserBasedArgument
  • net.minecraft.nbt
    • ByteArrayTag, now final, no longer takes in a list object
    • ByteTag is now a record
    • CollectionTag is now a sealed interface, no longer extending AbstractList or has a generic
      • set, add is removed
      • remove now returns a Tag
      • get - Returns the tag at the specified index.
      • getElementType is removed
      • size - Returns the size of the collection.
      • isEmpty - Returns whether the collection has no elements.
      • stream - Streams the elements of the collection.
    • CompoundTag is now final
      • store - Writes a codec or map codec to the tag.
      • read - Reads the codec or map codec-encoded value from the tag.
      • getFloatOrDefault, getIntOrDefault, getLongOrDefault - Gets the value with the associated key, or the default if not present or an exception is thrown.
      • storeNullable - When not null, uses the codec to write the value to the tag.
      • putUUID, getUUID, hasUUID is removed
      • getAllKeys -> keySet
      • values, forEach - Implements the standard map operations.
      • putByteArray, putIntArray with list objects are removed
      • getTagType is removed
      • contains is removed
      • get*, get*Or - Returns an optional wrapped object for the key, or the default value specified is using the Or methods.
    • DoubleTag is now a record
    • EndTag is now a record
    • FloatTag is now a record
    • IntArrayTag, now final, no longer takes in a list object
    • IntTag is now a record
    • ListTag, now final, extends AbstractList
      • addAndUnwrap - Adds the tag to the list where, if a compound with one element, adds the inner tag instead.
      • get*, get*Or - Returns an optional wrapped object for the key, or the default value specified is using the Or methods.
      • compoundStream - Returns a flat map of all CompoundTags within the list.
    • LongArrayTag, now final, no longer takes in a list object
    • LongTag is now a record
    • NbtIo#readUnnamedTag is now public, visible for testing
    • NbtOps now has a private constructor
    • NbtUtils
      • getDataVersion now has an overload that takes in a Dynamic
      • createUUID, loadUUID is removed
      • readBlockPos, writeBlockPos is removed
    • NumericTag is now a sealed interface that implements PrimitiveTag
      • getAsLong -> longValue
      • getAsInt -> intValue
      • getAsShort -> shortValue
      • getAsByte -> byteValue
      • getAsDouble -> doubleValue
      • getAsFloat -> floatValue
      • getAsNumber -> box
      • as* - Returns an optional wrapped of the numeric value.
    • PrimitiveTag - A sealed interface that represents the tag data as being a primitive object.
    • ShortTag is now a record
    • SnbtGrammar - A parser creater for stringified NBTs.
    • SnbtOperations - A helper that contains the built in operations for parsing some value.
    • StringTag is now a record
    • StringTagVisitor
      • visit -> build, not one-to-one
      • handleEscape -> handleKeyEscape, now private
    • Tag is now a sealed interface
      • as* -> Attempts to cast the tag as one of its subtypes, returning an empty optional on failure.
      • getAsString -> asString, not one-to-one
    • TagParser now holds a generic referncing the type of the intermediate object to parse to
      • The constructor now takes in a grammar, or create constructs the grammar from a DynamicOps
      • AS_CODEC -> FLATTENED_CODEC
      • parseTag -> parseCompoundFully or parseCompoundAsArgument
        • Additional methods such as parseFully, parseAsArgument parse to some intermediary object
        • These are all instance methods
      • readKey, readTypedValue is removed
    • TagType#isValue is removed
  • net.minecraft.util.parsing.packrat
    • CachedParseState - A parse state that caches the parsed positions and controls when reading.
    • Control#hasCut - Returns whether the control flow for the grammar has a cut for the reading object.
    • DelayedException - An interface that creates an exception to throw.
    • Dictionary
      • put now returns a NamedRule
      • put(Atom<T>, Term<S>, Rule.RuleAction<S, T>) -> putComplex
      • get -> getOtThrow, not one-to-one
      • forward - Gets or writes the term to the dictionary.
      • namedWithAlias - Creates a new reference to the named atom or its alias.
    • ErrorCollector$Nop - A error collector that does nothing.
    • NamedRule - A rule that has an associated name.
    • ParseState is now an interface
      • Caching logic has moved to CachedParseState
      • scope - Returns the current scope being analyzed within the parsing object.
      • parse now takes in a NamedRule instead of an Atom
      • acquireControl, releaseControl - Handles obtaining the Control used during parsing.
      • silent - Returns a ParseState that does not collect any errors.
    • Rule
      • parse, $RuleAction#run now returns a nullable value rather than an optional
      • SimpleRuleAction now implements $RuleAction
    • Scope#pushFrame, popFrame, splitFrame, clearFrameValues, mergeFrame - Handles the management of parsing terms into sections called frames.
    • Term
      • named -> Dictionary#named, not one-to-one
      • repeated, repeatedWithTrailingSeparator, repeatedWithoutTrailingSeparator - Handles terms similar to varargs that are repeated and sticks them into a list.
      • positiveLookahead, negativeLookahead - Handles a term that matches information based on what is following.
      • fail - Mark a term as having failed during parsing.
  • net.minecraft.util.parsing.packrat.commands
    • CommandArgumentParser - Parses a string into an argument for use with a command.
    • Grammar now takes in a NamedRule for the top rather than an Atom
    • GreedyPatternParseRule - A rule that attempts to match the provided pattern greedily, assuming that if a region matches, that the matched group can be obtained.
    • GreedyPredicateParseRule - A rule that attempts to match the accepted characters greedily, making sure that the string reaches a minimum size.
    • NumberRunParseRule - A rule that attempts to parse a number from the string.
    • ParserBasedArgument - A command argument that uses a parser to extract the value.
    • ResourceLookupRule now takes in a NamedRule for the id parser rather than an Atom
    • StringReaderParserState now extends CachedParsedState
      • The Dictoionary is no longer taken in
    • StringReaderTerms#characters - Matches multiple characters in a string, usually for catching both the lowercase and uppercase variant.
    • UnquotedStringParseRule - A rule that reads part of the sequence as an unquoted string, making sure it reaches a minimum size.

Saved Data, now with Types

SavedData has been reworked to abstract most of its save and loading logic into a separate SavedDataType. This means that the save override and additional load and factory methods are now handled within the SavedDataType itself.

To construct a SavedDataType, you need to pass in four paramters. First is the string identifier, used to resolve the .dat file holding your information. This must be a vaild path. Then there is the constructor, which takes in the SavedData$Context to return an instance of your data object when no information is present. Following that is the codec, which takes in the SavedData$Context and returns a Codec to read and write your saved data. Finally, there is the DataFixTypes used for data fixers. As this is a static enum, you will either need to inject into the enum itself, if you plan on using vanilla data fixers, or patch out the update call within DimensionDataStorage#readTagFromDisk to pass in a null value.

// Our saved data instance
public class ExampleSavedData extends SavedData {

    // The saved data type
    public static final SavedDataType<ExampleSavedData> TYPE = new SavedDataType<>(
        // Best to preface the identifier with your mod id followed by an underscore
        // Slashes will throw an error as the folders are not present
        // Will resolve to `saves/<world_name>/data/examplemod_example.dat`
        "examplemod_example",
        // Constructor for the new instance
        ExampleSavedData::new,
        // Codec factory to encode and decode the data
        ctx -> RecordCodecBuilder.create(instance -> instance.group(
            RecordCodecBuilder.point(ctx.levelOrThrow()),
            Codec.INT.fieldOf("value1").forGetter(data -> data.value1),
            Codec.BOOL.fieldOf("value2").forGetter(data -> data.value2)
        ).apply(instance, ExampleSavedData::new));
    );

    private final ServerLevel level;
    private final int value1;
    private final boolean value2;


    // For the new instance
    private ExampleSavedData(ServerLevel.Context ctx) {
        this(ctx.levelOrThrow(), 0, false);
    }

    // For the codec
    // The constructors don't need to be public if not using `DimensionDataStorage#set`
    private ExampleSavedData(ServerLevel level, int value1, boolean value2) {
        this.level = level;
        this.value1 = value1;
        this.value2 = value2;
    }

    // Other methods here
}

// With access to the DimensionDataStorage storage
ExampleSavedData data = storage.computeIfAbsent(ExampleSavedData.TYPE);
  • net.minecraft.server.ServerScoreboard
    • dataFactory is removed
    • createData now takes in a $Packed instance
  • net.minecraft.world.RandomSequences
    • factory, load is removed
    • codec - Constructs a codec for the random sequence given the current world seed.
  • net.minecraft.world.entity.raid.Raids no longer takes in anything
    • getType - Returns the saved data type based on the current dimension.
    • factory is removed
    • tick now takes in the ServerLevel
    • getId - Gets the identifier for the raid instance.
    • canJoinRaid no longer takes in the raid instance
    • load no longer takes in the ServerLevel
  • net.minecraft.world.level.levelgen.structure.structures.StructureFeatureIndexSavedData
    • factory, load is removed
    • type - Returns the feature saved data type with its specified id.
  • net.minecraft.world.level.saveddata
    • SavedData
      • save is removed
      • $Factory record is removed
      • $Context - Holds the current context that the saved data is being written to.
    • SavedDataType - A record that represents the type of the saved data, including information on how to construct, save, and load the data.
  • net.minecraft.world.level.saveddata.maps
    • MapIndex now has a constructor to take in the last map id
      • factory, load is removed
      • getFreeAuxValueForMap -> getNextMapId
    • MapItemSavedData
      • factory, load is removed
      • type - Returns the saved data type using the map id’s key.
  • net.minecraft.world.level.storage.DimensionDataStorage now takes in a SavedData$Context
    • computeIfAbsent, get now take in only the SavedDataType
    • set now takes in the SavedDataType along with the data instance
  • net.minecraft.world.scores.ScoreboardSaveData
    • load -> loadFrom
    • pack - Packs the data into its saved data format.
    • $Packed - Represents the serializable packed data.

Render Pipeline Rework

Rendering an object to the screen, whether through a shader or a RenderType, has been fully or partially reworked, depending on what systems you were using previously. As such, a lot of things need to be reexplained, which a more in-depth look will be below. However, for the people who don’t care, here’s the TL;DR.

First, shader JSONs no longer exist. This is replaced by a RenderPipeline, which is effectively an in-code substitute. Second, the RenderPipelines forcibly make most abtrarily values into objects. For example, instead of storing the blend function mode id, you store a BlendFunction object. Similarly, you no longer store or setup the direct texture objects, but instead manage it through a GpuTexture. Finally, the VertexBuffer can either draw to the framebuffer by directly passing in the RenderPipeline, updating any necessary uniforms in the consumer, or by passing in the RenderType.

Now, for those who need the details, let’s jump into them.

Abstracting Open GL

As many are aware, Minecraft has been abstracting away their OpenGL calls and constants, and this release is no different. All of the calls to GL codes, except BufferUsage, have been moved out of object references, to be obtained typically by calling GlConst$toGl. However, with all of the other rendering reworks, there are numerous changes and complexities that require learning an entirely new system, assuming you’re not using RenderTypes.

Starting from the top, all calls to the underlying render system goes through GpuDevice, an interface that acts like a general implementation of a render library like OpenGL or Vulkan. The device is responsible for creating buffers and textures, executing whatever commands are desired. Getting the current GpuDevice can be accessed through the RenderSystem via getDevice like so:

GpuDevice device = RenderSystem.getDevice();

The GpuDevice can the create either buffers with the desired data or a texture containing information on what to render using createBuffer and createTexture, respectively. Just for redundancy, buffers hold the vertex data while textures hold the texture (color and depth) data. You should generally cache the buffer or texture object for later use with any additional data updated as needed. For reference, buffers are typically created by using a BufferBuilder with a ByteBufferBuilder to build the MeshData first, before passing that into createBuffer.

With the desired buffers and textures set up, how do we actually modify render them to the screen? Well, this is handled through the CommandEncoder, which can also be optained from the device via GpuDevice#createCommandEncoder. The encoder contain the familiar read and write methods along with a few extra to clear texture to a given color or simply blit the the texture immediately to the screen (presentTexture). However, the most important method here is createRenderPass. This takes in the GpuTexture to draw to the screen along with a default ARGB color for the background. Additionally, it can take in a depth texture as well. This should be created using a try with resources block like so:

// We will assume you have constructed a `GpuTexture` texture for the color data
try (RenderPass pass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(this.texture, OptionalInt.of(0xFFFFFFFF))) {
    // Setup things here

}

Within the RenderPass, you can set the RenderPipeline to use, which defines the associated shaders, bind any samplers from other targets or set uniforms, scissor a part of a screen to render, and set the vertex and index buffers used to define the vertices to render. Finally, everything can be drawn to the screen using one of the draw methods, providing the starting index and the vertex count.

// If the buffers/textures are not created or cached, create them here
// Any methods ran from `CommandEncoder` cannot be run while a render pass is open
RenderSystem.AutoStorageIndexBuffer indices = RenderSystem.getSequentialBuffer(VertexFormat.Mode.QUADS);
GpuBuffer vertexBuffer = RenderSystem.getQuadVertexBuffer();
GpuBuffer indexBuffer = indices.getBuffer(6);

// We will assume you have constructed a `GpuTexture` texture for the color data
try (RenderPass pass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(this.texture, OptionalInt.of(0xFFFFFFFF))) {

    // Set pipeline information along with any samplers and uniforms
    pass.setPipeline(EXAMPLE_PIPELINE);
    pass.setVertexBuffer(0, vertexBuffer);
    pass.setIndexBuffer(indexBuffer, indices.type());
    pass.bindSampler("Sampler0", RenderSystem.getShaderTexture(0));

    // Then, draw everything to the screen
    // In this example, the buffer just contains a single quad
    // For those unaware, the vertex count is 6 as a quad is made up of 2 triangles, so 2 vertices overlap
    pass.drawIndexed(0, 6);
}

However, unless you need such fine control, it is recommended to use a RenderType with the MultiBufferSource when necessary as that sets up most things for you.

Object References

Most raw references to GL codes used for determining the mode and handling the texture have been replaced with objects. As the TL;DR previously mentioned, these are stored typically as some sort of enum or object that can then be resolved to their GL counterparts. Some objects contain their reference identifier directly, like BlendFunction. Others are simply placeholders that are resolved in their appropriate location, like DepthTestFunction whose enum values are converted via RenderPipeline#toGl.

However, the biggest change is the addition of the GpuTexture. This is responsible for managing anything to do with creating, writing, and releasing a texture written to some buffer. At initialization, the texture is created and bound, with any necessary parameters set for mipmaps and texture formats. These GpuTextures are stored and referenced everywhere, from the depth and color targets for a RenderTarget to the texture backing a TextureAtlas. Then, once no longer need, the texture is released by calling #close. Note that although technically #bind can be called again, the texture is already considered deleted and should not be used.

If, for some reason, you need to use a GpuTexture, it’s actually quite simple to use. First, you just construct the GpuTexture via GpuDevice#createTexture. Then, if you need to change any of the addressing or texture mipmap filters, you can apply them whenever before writing.

public class MyTextureManager {
    
    private final GpuTexture texture;

    public MyTextureManager() {
        this.texture = RenderSystem.getDevice().createTexture(
            // The texture name, used for logging and debugging
            "Example Texture",
            // The format of the texture pixels, can be one of three values that
            // Values:   (texture internal format, texel data format,  texel data type,  pixel size)
            // - RGBA8   (GL_RGBA8,                GL_RGBA,            GL_UNSIGNED_BYTE, 4)
            // - RED8    (GL_R8,                   GL_RED,             GL_UNSIGNED_BYTE, 1)
            // - DEPTH32 (GL_DEPTH_COMPONENT32,    GL_DEPTH_COMPONENT, GL_FLOAT,         4)
            TextureFormat.RGBA8,
            // Width of the texture
            16,
            // Height of the texture
            16,
            // The mipmap level and maximum level-of-detail (minimum of 1)
            1
        );

        // Set the texture mode for the UV component
        // Values:
        // - REPEAT        (GL_REPEAT)
        // - CLAMP_TO_EDGE (GL_CLAMP_TO_EDGE)
        this.texture.setAddressMode(
            // The mode to use for the U component (GL_TEXTURE_WRAP_S)
            AddressMode.CLAMP_TO_EDGE,
            // The mode to use for the V component (GL_TEXTURE_WRAP_R)
            AddressMode.REPEAT
        );

        // Sets the filter functions used for scaling the texture on the screen
        // Values    (default,    for mipmaps):
        // - NEAREST (GL_NEAREST, GL_NEAREST_MIPMAP_LINEAR)
        // - LINEAR  (GL_LINEAR,  GL_LINEAR_MIPMAP_LINEAR)
        this.texture.setTextureFilter(
            // The mode to use for the texture minifying function (GL_TEXTURE_MIN_FILTER)
            FilterMode.LINEAR,
            // The mode to use for the texture magnifying function (GL_TEXTURE_MAG_FILTER)
            FilterMode.NEAREST,
            // Whether mipmaps should be used for the minifying function (should have a higher mipmap level than 1 when true)
            false
        );
    }
}

Then, whenever you want to upload something to the texture, you call CommandEncoder#writeToTexture or CommandEncoder#copyTextureToTexture. This either takes in the NativeImage to write from or an IntBuffer with the texture data and a NativeImage$Format to use.

// Like other buffer/texture modification methods, this must be done outside of a render pass
// We will assume you have some `NativeImage` image to load into the texture
RenderSystem.getDevice().createCommandEncoder().writeToTexture(
    // The texture (destination) being written to
    this.texture,
    // The image (source) being read from
    image,
    // The mipmap level
    0,
    // The starting destination x offset
    0,
    // The starting destination y offset
    0,
    // The destination width (x size)
    16,
    // The desintation height (y size)
    16,
    // The starting source x offset
    0,
    // The starting source y offset
    0
)

Finally, once you’re done with the texture, don’t forget to release it via #close if it’s not already handled for you.

Render Pipelines

Previously, a pipeline was constructed using a JSON that contained all metadata from the vertex and fragement shader to their defined values, samplers, and uniforms. However, this has all been replaced with an in-code solution that more localizes some parts of the JSON and some parts that were relegated to the RenderType. This is known as a RenderPipeline.

A RenderPipeline can be constructed using its builder via RenderPipeline#builder. A pipeline can then be built by calling build. If you want the shader to be pre-compiled without any additional work, the final pipeline can be passed to RenderPipeline#register. However, you can also handle the compilation yourself if more graceful fail states are desired. If you have snippets that are used across multiple pipelines, then a partial pipeline can be built via $Builder#buildSnippet and then passed to the constructing pipelines in the builder method.

The following enums described in the examples have their GL codes provided with them as they have been abstracted away.

// This assumes that RenderPipeline#register has been made public through some form
public static final RenderPipeline EXAMPLE_PIPELINE = RenderPipelines.register(
    RenderPipeline.builder()
    // The name of the pipeline (required)
    .withLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "pipeline/example"))
    // The location of the vertex shader, relative to 'shaders' (required)
    // Points to 'assets/examplemod/shaders/example.vsh'
    .withVertexShader(ResourceLocation.fromNamespaceAndPath("examplemod", "example"))
    // The location of the fragment shader, relative to 'shaders' (required)
    // Points to 'assets/examplemod/shaders/example.fsh'
    .withFragmentShader(ResourceLocation.fromNamespaceAndPath("examplemod", "example"))
    // The format of the vertices within the shader (required)
    .withVertexFormat(
        // The vertex format
        DefaultVertexFormat.POSITION_TEX_COLOR,
        // The mode of the format
        VertexFormat.Mode.QUADS
    )
    // Adds constants that can be referenced within the shaders
    // Can specify a name in addition to an int / float to represent its value
    // If no value is specified, then it should be gated with a #ifdef / #endif block
    .withShaderDefines("ALPHA_CUTOUT", 0.5)
    // Adds the texture sampler2Ds that can be referenced within the shaders
    // Typically, the shader textures stored in the `RenderSystem` is referenced via `Sampler0` - `Sampler11`
    // - `Sampler0` is usually always present, but these should be set up beforehand
    // Additionally, for render targets, `InSampler` is typically present, along with any defined in a postpass
    .withSampler("Sampler0")
    // Adds uniforms that can be referenced within the shaders
    // These are just definitions which are then populated by default or by the caller depending on the scenario
    // Defaults can be found in `CompiledShaderProgram#setupUniforms`
    .withUniform("ModelOffset", UniformType.VEC3)
    // Custom uniforms must be set manually as the vanilla batching system does not support such an operation
    .withUniform("CustomUniform", UniformType.INT)
    // Sets the depth test functions used rendering objects at varying distances from the camera
    // Values:
    // - NO_DEPTH_TEST      (GL_ALWAYS)
    // - EQUAL_DEPTH_TEST   (GL_EQUAL)
    // - LEQUAL_DEPTH_TEST  (GL_LEQUAL)
    // - LESS_DEPTH_TEST    (GL_LESS)
    // - GREATER_DEPTH_TEST (GL_GREATER)
    .withDepthTestFunction(DepthTestFunction.LEQUAL_DEPTH_TEST)
    // Sets how the polygons should render
    // Values:
    // - FILL      (GL_FILL)
    // - WIREFRAME (GL_LINE)
    .withPolygonMode(PolygonMode.FILL)
    // When true, can cull front or back-facing polygons
    .withCull(false)
    // Specifies the functions to use when blending two colors with alphas together
    // Made up of the `GlStateManager$SourceFactor` and `GlStateManager$DestFactor`
    // First two are for RGB, the last two are for alphas
    // If nothing is specified, then blending is disabled
    .withBlend(BlendFunction.TRANSLUCENT)
    // Determines whether to mask writing colors and alpha to the draw buffer
    .withColorWrite(
        // Mask RGB
        false,
        // Mask alpha
        false
    )
    // Determines whether to mask writing values to the depth buffer
    .withDepthWrite(false)
    // Determines the logical operation to apply when applying an RGBA color to the framebuffer
    .withColorLogic(LogicOp.NONE)
    // Sets the scale and units used to calculate the depth values for the polygon.
    // This takes the place of the polygon offset.
    .withDepthBias(0f, 0f)
    .build()
);

From there, the pipeline can either be used directly or through some RenderType:

// This will assume that RenderType#create is made public
public static final RenderType EXAMPLE_RENDER_TYPE = RenderType.create(
    // The name of the render type
    "examplemod:example",
    // The size of the buffer
    // Or 4MB
    4194304,
    // Whether it effects crumbling that is applied to block entities
    false,
    // Whether the vertices should be sorted before upload
    true,
    // The pipeline to use
    EXAMPLE_PIPIELINE,
    // Any additional composite state settings to apply
    RenderType.CompositeState.builder().createCompositeState(RenderType.OutlineProperty.NONE)
);

The pipeline can then be drawn by creating the RenderPass and setting the RenderPipeline to use your pipeline. As for the RenderType, the associated buffer can be obtained using MultiBufferSource#getBuffer. Note that custom uniforms should not be used within RenderTypes as they cannot be set easily.

// Since we are using a custom uniform, we must handle it ourselves
// We will assume we have some `GpuTexture` texture to write to

// Create the render pass to use
try (RenderPass pass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(
        // The GPU color texture to write to
        this.texture,
        // The clear color in ARGB format
        OptionalInt.of(0xFFFFFFFF),
        // The depth texture and the clear depth value can also be constructed here
    )
) {
    // Add the pipeline and our uniform
    pass.setPipeline(EXAMPLE_PIPELINE);
    pass.setUniform("CustomUniform", 1);
    
    // Set any additional sampler and the vertex/index buffers to use

    // Finally, call one of the draw functions
    // Takes in the first index and the index count to draw for the vertices
    pass.draw(...);
}

Post Effects

Given that the pipeline JSONs have been stripped, this also effects the post effects. The program is replaced with directly specifying the vertex_shader and the fragment_shader. Additionally, uniforms must specify their type.

// Before 1.21.5 (for some pass in 'passes')
{
    // Same as before
    "inputs": [ /*...*/ ],
    "output": "swap",

    // Replaced by 'vertex_shader', 'fragement_shader'
    "program": "minecraft:post/box_blur",

    "uniforms": [
        {
            "name": "BlurDir",
            // Required
            "values": [ 1.0, 0.0 ]
        },
        {
            "name": "Radius",
            // Required
            "values": [ 0.0 ]
        }
    ]
}

// 1.21.1 (for some pass in 'passes')
{
    // Same as before
    "inputs": [ /*...*/ ],
    "output": "swap",

    // Relative to 'shaders'
    // Points to 'assets/minecraft/shaders/post/blur.vsh'
    "vertex_shader": "minecraft:post/blur",
    // Points to 'assets/minecraft/shaders/post/box_blur.fsh'
    "fragment_shader": "minecraft:post/box_blur",


    "uniforms": [
        {
            "name": "BlurDir",
            // Specifies the type to use for this uniform
            // One of `Uniform$Type`:
            // - int
            // - ivec3
            // - float
            // - vec2
            // - vec3
            // - vec4
            // - matrix4x4
            "type": "vec2",
            "values": [ 1.0, 0.0 ]
        },
        {
            "name": "Radius",
            "type": "float"
            // Values are no longer required
        }
    ]
}

Note that if you do not define a value for a uniform, they still must be specified before processing the PostChain by calling #setUniform within the RenderPass consumer of PostChain#process.

// Assume we already got the `PostChain` post
post.process(Minecraft.getInstance().getMainRenderTarget(), GraphicsResourceAllocator.UNPOOLED, pass -> {
    pass.setUniform("Radius", 0.4f);
});
  • com.mojang.blaze3d.GpuOutOfMemoryException - An exception thrown when a texture could not be allocated on the GPU.
  • com.mojang.blaze3d.buffers
    • BufferType no longer stores the GL codes, now in GlConst#toGl
    • BufferUsage no longer stores the GL codes, now in GlConst#toGl
      • isReadable, isWritable - Returns whether the buffer can be read from or written to.
    • GpuBuffer is now abstract
      • Constructor with ByteBuffer is removed
      • size - Returns the size of the buffer.
      • type - Returns the type of the buffer.
      • resize, write, read, bind is removed
      • usage - Returns the usage of the buffer.
      • close is now abstract
      • isClosed - Returns whether the buffer has been closed.
      • $ReadView is now an interface that defines the buffer data and how to close the view
  • com.mojang.blaze3d.font.SheetGlyphInfo#upload now takes in a GpuTexture
  • com.mojang.blaze3d.opengl
    • DirectStateAccess - An interface that creates and binds data to some framebuffer.
      • $Core - An implementation of DSA that modifies the framebuffer without binding them to the context.
      • $Emulated - An abstraction over DSA that still binds the context.
    • GlBuffer - An implementation of the GpuBuffer for OpenGL.
    • GlCommandEncoder - An implementation of the CommandEncoder for OpenGL.
    • GlDebugLabel - A labeler for handling debug references to GL-specified data structures.
    • GlDevice - An implementation of GpuDevice for OpenGL.
    • GlRenderPass - An implementation of RenderPass for OpenGL.
    • GlRenderPipeline - An implementation of CompiledRenderPipeline for OpenGL.
    • GlTexture - An implementation of GpuTexture for OpenGL.
    • VertexArrayCache - A cache for binding and uploading a vertex array to the OpenGL pipeline.
  • com.mojang.blaze3d.pipeline
    • BlendFunction - A class that holds the source and destination colors and alphas to apply when overlaying pixels in a target. This also holds all vanilla blend functions.
    • CompiledRenderPipeline - An interface that holds the pipeline with all necessary information to render to the screen.
    • RenderPipeline - A class that contains everything required to render some object to the screen. It acts similarly to a render state before being applied.
    • RenderTarget now takes in a string representing the name of the target
      • colorTextureId -> colorTexture, now a GpuTexture
        • Same with getColorTextureId -> getColorTexture
      • depthBufferId -> depthTexture, now a GpuTexture
        • Same with getDepthTextureId -> getDepthTexture
      • filterMode is now a FilterMode
        • Same with setFilterMode for the int parameter
      • blitAndBlendToScreen no longer takes in the viewport size parameters
      • framebufferId is removed
      • checkStatus is removed
      • bindWrite, unbindWrite, setClearColor is removed
      • blitToScreen no longer takes in any parameters
      • blitAndBlendToScreen -> blitAndBlendToTexture, not one-to-one
      • clear is removed
      • unbindRead is removed
  • com.mojang.blaze3d.platform
    • DepthTestFunction - An enum representing the supported depth tests to apply when rendering a sample to the framebuffer.
    • DisplayData is now a record
      • withSize - Creates a new instance with the specified width/height.
      • withFullscreen - Creates a new instance with the specified fullscreen flag.
    • FramerateLimitTracker
      • getThrottleReason - Returns the reason that the framerate of the game was throttled.
      • isHeavilyThrottled - Returns whether the current throttle significantly impacts the game speed.
      • $FramerateThrottleReason - The reason the framerate is throttled.
    • GlConst -> com.mojang.blaze3d.opengl.GlConst
      • #toGl - Maps some reference object to its associated OpenGL code.
    • GlDebug -> com.mojang.blaze3d.opengl.GlDebug
      • enableDebugCallback now takes in a set of the enabled extensions.
    • GlStateManager -> com.mojang.blaze3d.opengl.GlStateManager
      • _blendFunc, _blendEquation is removed
      • _glUniform2(int, IntBuffer), _glUniform4(int, IntBuffer) is removed
      • _glUniformMatrix2(int, boolean, FloatBuffer), _glUniformMatrix3(int, boolean, FloatBuffer) is removed
      • _glUniformMatrix4(int, boolean, FloatBuffer) -> _glUniformMatrix4(int, FloatBuffer), transpose is now always false
      • _glGetAttribLocation is removed
      • _glMapBuffer is removed
      • _glCopyTexSubImage2D is removed
      • _glBindRenderbuffer, _glDeleteRenderbuffers is removed
      • glGenRenderbuffers, _glRenderbufferStorage, _glFramebufferRenderbuffer is removed
      • _texParameter(int, int, float) is removed
      • _genTextures, _deleteTextures is removed
      • _texSubImage2D now has an overload that takes in an IntBuffer instead of a long for the pixel data
      • upload is removed
      • _stencilFunc, _stencilMask, _stencilOp, _clearStencil is removed
      • _getTexImage is removed
      • _glDrawPixels, _readPixels is removed
      • $CullState#mode is removed
      • $DestFactor -> DestFactor, codes are removed to be called through GlConst#toGl
      • $FramebufferState enum is removed
      • $LogicOp -> LogicOp, codes are removed to be called through GlConst#toGl
        • All but OR_REVERSE is removed
        • NONE - Performs no logic operation.
      • $PolygonOffsetState#line is removed
      • $SourceFactor -> SourceFactor, codes are removed to be called through GlConst#toGl
      • $StencilFunc, $StencilState class is removed
      • $Viewport enum is removed
    • GlUtil class is removed
      • getVendor, getRenderer, getOpenGlVersion (now getVersion) have been moved to instance abstract methods on GpuDevice
      • getCpuInfo -> GLX#_getCpuInfo
    • GLX
      • getOpenGLVersionString is removed
      • _init -> _getCpuInfo, not one-to-one
      • _renderCrosshair, com.mojang.blaze3d.systems.RenderSystem#renderCrosshair -> net.minecraft.client.gui.components.DebugScreenOverlay#render3dCrosshair, not one-to-one
    • PolygonMode - A enum that defines how the polygons will render in the buffer.
    • NativeImage constructor is now public
      • upload is removed
      • getPointer - Returns the pointer to the image data.
      • setPixelABGR is now public
      • applyToAllPixels is removed
      • downloadTexture, downloadDepthBuffer is removed
      • flipY is removed
      • setPackPixelStoreState, setUnpackPixelStoreState is removed
      • $InternalGlFormat enum is removed
      • $Format no longer contains the GL codes, now in GlConst#toGl
    • TextureUtil
      • generateTextureId, releaseTextureId is removed
      • prepareImage is removed
      • writeAsPNG now takes in a GpuTexture instead of the direct three integers
        • The overload without the IntUnaryOperator is removed
  • com.mojang.blaze3d.resource
    • RenderTargetDescriptor now takes in an integer representing the color to clear to
    • ResourceDescriptor
      • prepare - Prepares the resource for use after allocation.
      • canUsePhysicalResource - Typically returns whether a descriptor is already allocated with the same information.
  • com.mojang.blaze3d.shaders
    • AbstractUniform -> com.mojang.blaze3d.opengl.AbstractUniform
      • setSafe methods are removed
      • setMat* methods are removed
      • set(Matrix3f) is removed
    • CompiledShader -> com.mojang.blaze3d.opengl.GlShaderModule
      • $Type -> com.mojang.blaze3d.shaders.ShaderType
    • Uniform -> com.mojang.blaze3d.opengl.Uniform
      • Constructor now takes in a $Type instead of the count and an integer representing the type
      • UT_* fields are removed
      • setFromConfig(ShaderProgramConfig.Uniform) is removed
      • getTypeFromString is removed
      • getType now returns a $Type
      • set(int, float) is removed
      • setSafe is now private
      • $Type - Holds the type name as well as how many values it holds.
      • getLocation is removed
      • getCount -> $Type#count
      • getIntBuffer, getFloatBuffer is removed
      • $Type -> com.mojang.blaze3d.shaders.UniformType
  • com.mojang.blaze3d.systems
    • CommandEncoder - An interface that defines how to encode various commands to the underlying render system, such as creating a pass, clearing and writing textures, or reading from the buffer.
    • GpuDevice - An interface that defines the device or underlying render system used to draw to the screen. This is responsible for creating the buffers and textures while compiling any pipelines.
    • RenderPass - An interface that defines how a given pass is rendered to some buffer using the underlying render system. This allows binding any samplers and setting the required uniforms.
    • RenderSystem
      • isOnRenderThreadOrInit, assertOnRenderThreadOrInit is removed
      • recordRenderCall, replayQueue is removed
      • blendFunc, blendFuncSeparate, blendEquation is removed
      • texParameter, deleteTexture, bindTextureForSetup is removed
      • stencilFunc, stencilMask, stencilOp is removed
      • clearDepth is removed
      • glBindBuffer, glBindVertexArray, glBufferData, glDeleteBuffers is removed
      • glUniform1i is removed
      • glUniform1, glUniform2, glUniform3, glUniform4 is removed
      • glUniformMatrix2, glUniformMatrix3, glUniformMatrix4 is removed
      • setupOverlayColor now takes in a GpuTexture instead of two ints
      • beginInitialization, finishInitialization is removed
      • renderThreadTesselator is removed
      • setShader, clearShader, getShader is removed
      • setShaderTexture now takes in a GpuTexture instead of a bind address
      • getShaderTexture now returns a GpuTexture or null if not present
      • pixelStore, readPixels is removed
      • queueFencedTask, executePendingTasks - Handles sending tasks that run on the GPU asyncronously.
      • SCISSOR_STATE - Holds the main scissor state.
      • disableDepthTest, enableDepthTest is removed
      • depthFunc, depthMask is removed
      • enableBlend, disableBlend is removed
      • neableCull, disableCull is removed
      • polygonMode, enablePolygonOffset, disablePolygonOffset, polygonOffset is removed
      • enableColorLogicOp, disableColorLogicOp, logicOp is removed
      • bindTexture, viewport is removed
      • colorMask, clearColor, clear is removed
      • setupShaderLights(CompiledShaderProgram) is removed
      • getShaderLights - Returns the vectors representing the block and sky lights.
      • drawElements, getString is removed
      • initRenderer now takes in the window pointer, the default shader source, and a boolean of whether to use debug labels
      • setupDefaultState no longer takes in any parameters
      • maxSupportTextureSize is removed
      • glDeleteVertexArrays is removed
      • defaultBlendFunc is removed
      • setShaderTexture is removed
      • getQuadVertexBuffer - Returns a vertex buffer with a quad bound to it.
      • getDevice, tryGetDevice - Returns the GpuDevice representing the underlying render system to use.
      • getCapsString is removed
      • activeTexture is removed
      • setModelOffset, resetModelOffset, getModelOffset - Handles the offset to apply to a model when rendering for the uniform ModelOffset. Typically for clouds and world borders.
      • $AutoStorageIndexBuffer#bind -> getBuffer, not one-to-one
      • $GpuAsyncTask - A record that holds the callback and fence object used to sync information to the GPU.
    • ScissorState - A class which holds the part of the screen to render.
  • com.mojang.blaze3d.textures
    • AddressMode - The mode set for how to render a texture to a specific location.
    • FilterMode - The mode set for how to render a texture whenever the level-of-detail function determines how the texture should be maximized or minimized.
    • GpuTexture - A texture that is bound and written to the GPU as required.
    • TextureFormat - Specifies the format that the texture should be allocated with.
  • com.mojang.blaze3d.vertex
    • PoseStack
      • mulPose(Quaternionf), rotateAround now takes in a Quaternionfc instead of a Quaternionf
      • clear -> isEmpty
      • mulPose(Matrix4f) -> mulPose(Matrix4fc)
      • $Pose
        • computeNormalMatrix is now private
        • transformNormal now takes in a Vector3fc as its first parameter
        • translate, scale, rotate, rotateAround, setIdentity, mulPose are now available on the pose itself in addition to the stack
    • VertexBuffer -> com.mojang.blaze3d.buffers.GpuBuffer, not one-to-one
      • Some logic is also moved to VertexFormat
    • VertexFormat
      • bindAttributes is removed
      • setupBufferState, clearBufferState, getImmediateDrawVertexBuffer -> uploadImmediateVertexBuffer, uploadImmediateIndexBuffer; not one-to-one
      • $IndexType no longer stores the GL codes, now in GlConst#toGl
      • $Mode no longer stores the GL codes, now in GlConst#toGl
    • VertexFormatElement
      • setupBufferState is removed
      • $Type no longer stores the GL codes, now in GlConst#toGl
      • $Usage no longer stores the GL function calls, now in VertexArrayCache#setupCombinedAttributes
  • com.mojang.math
    • MatrixUtil
      • isIdentity, isPureTranslation, isOrthonormal now take in a Matrix4fc
      • checkProperty - Checks if the provided property is represented within the matrix.
    • OctahedralGroup
      • transformation now returns a Matrix3fc
      • fromAnges -> fromXYAngles, not one-to-one
    • Quadrant - An enum that contains rotations in 90 degree increments.
    • SymmetricGroup3#transformation now returns a Matrix3fc
    • Transformation now takes in a Matrix4fc
      • getMatrix now returns a Matrix4fc
      • getMatrixCopy - Returns a deep copy of the current matrix.
  • net.minecraft.client.gui.font.FontTexture now takes in a supplied label string
  • net.minecraft.client.main.GameConfig now takes in a boolean representing whether to render debug labels
  • net.minecraft.client.renderer
    • CloudRenderer#render no longer takes in the Matrix4fs used for projection or posing
    • CompiledShaderProgram -> com.mojang.blaze3d.opengl.GlProgram
      • link now takes in a string for the shader name
      • setupUniforms now take in the list of $UniformDescriptions along with a list of names used by the samplers
      • getUniformConfig is removed
      • bindSampler now takes in a GpuTexture instead of the integer bind identifier
      • parseUniformNode is removed
    • CoreShaders -> RenderPipelines, not one-to-one
    • LightTexture#getTarget - Returns the GpuTexture that contains the light texture for the current level based on the player.
    • PostChain
      • load no longer takes in the ShaderManager, now taking in a ResourceLocation representing the name of the chain
      • addToFrame, process now takes in a RenderPass consumer to apply any additional settings to the pass to render
      • setUniform is removed
      • setOnRenderPass - Sets the uniform within the post chain on the RenderPass for use in the shaders.
    • PostChainConfig
      • $Pass now takes in the ids of the vertex and fragment shader instead of the program id
        • referencedTargets - Returns the targets referenced in the pass to apply.
        • program is removed
      • $Uniform now takes in the type of the uniform along with an optional list of floats if the value does not need to be overridden
    • PostPass no longer takes in the CompiledShaderProgram, now taking in the RenderPipeline instead of a string representing the name of the pass
      • addToFrame now takes in a RenderPass consumer to apply any additional settings to the pass to render
      • getShader is removed
      • $Input#bindTo now takes in a RenderPass instead of the CompiledShaderProgram
    • RenderStateShard
      • $LayerStateShards using polygon offsets have been removed
      • getName - Returns the name of the shard.
      • $TransparencyStateShard class is removed
        • Now handled through BlendFunction
      • $ShaderStateShard class is removed
        • Directly referred to by the VertexBuffer
      • $CullStateShard class is removed
        • Now handled as a setting on the RenderPipeline
      • $DepthTestStateShard class is removed
        • Now handled through DepthTestFunction
      • $WriteMaskStateShard class is removed
        • Now handled as a setting on the RenderPipeline
      • $ColorLogicStateShard class is removed
        • Now handled as a setting on the RenderPipeline
      • $OutputStateShard now takes in a supplied RenderTarget instead of the runnables for the startup and teardown states
    • RenderType no longer takes in the VertexFormat or VertexFormat$Mode
      • SKY, END_SKY, sky, endSky, stars is removed
      • ENTITY_OUTLINE_BLIT, entityOutlineBlit is removed
      • PANORAMA, panorama is removed
      • CREATE_LIGHTMAP, createLightmap is removed
      • createClouds, flatClouds, clouds, cloudsDepthOnly is removed
      • worldBorder is removed
      • debugLine - Returns the RenderType associated with the debug line.
      • entityOutlineBlit - Returns the RenderType used for rendering an entity outline.
      • panorama - Returns the RenderType used for rendering panorama mode.
      • createLightmap - Returns the RenderType used for rendering the lightmap texture.
      • create no longer takes in the VertexFormat or VertexFormat$Mode, instead the RenderPipeline
      • getRenderTarget, getRenderPipeline - Returns the target and pipeline used for rendering.
      • format, mode, draw are now abstract
      • $CompositeStateBuilder methods are now protected
      • $OutlineProperty is now protected
    • ShaderDefines$Builder#define now has an overload that takes in an integer
    • ShaderManager
      • SHADER_INCLUDE_PATH is now private
      • MAX_LOG_LENGTH is removed
      • preloadForStartup is removed, replaced by GpuDevice#precompilePipeline
      • getProgram, getProgramForLoading -> getShader, not one-to-one
      • linkProgram now takes in a RenderPipeline instead of a ShaderProgram and ShaderProgramConfig
      • $CompilationCache#getOrCompileProgram, getOrCompileShader -> getShaderSource, not one-to-one
      • $Configs no longer takes in the map of programs
      • $ShaderCompilationKey record is removed
    • ShaderProgram, ShaderProgramConfig -> RenderPipeline, not one-to-one
    • SkyRenderer#renderDarkDisc no longer takes in the PoseStack
  • net.minecraft.client.renderer.chunk.SectionRenderDispatcher
    • uploadSectionLayer, uploadSectionIndexBuffer -> $RenderSection#uploadSectionLayer, uploadSectionIndexBuffer
    • $SectionBuffers - A class that holds the buffers used to render the sections.
  • net.minecraft.client.renderer.texture
    • AbstractTexture
      • NOT_ASSIGNED is removed
      • texture, getTexture - Holds the reference to the texture to render.
      • getId, releaseId is removed
      • bind is removed
    • DynamicTexture now takes in the label of the texture
    • SpriteContents#uploadFirstFrame, $AnimatedTexture#uploadFirstFrame now takes in a GpuTexture
    • SpriteTicker#tickAndUpload now takes in the GpuTexture
    • TextureAtlasSprite#uploadFirstFrame, $Ticker#tickAndUpload now takes in the GpuTexture

Model Rework

The model system has been further separated into models for block states, blocks, and items. As such, the unifying BakedModel has been completely removed and separated into their own sections, loaded in three steps: from JSON, resolving dependencies, and then baking for use with the associated block state model or item model. For reference, everything discussed below is what’s happenening within ModelManager#reload in parallel.

First, let’s start from the base model JSON used between blocks and items. These are loaded into an UnbakedModel (specifically BlockModel) which contains the familiar properties such as gui light and texture slots. However, one change is the splitting of the elements from their render settings. These elements that hold the render quads are stored in an UnbakedGeometry. The UnbakedGeometry is responsible for baking the model into a QuadCollection, which effectively holds the list of BakedQuads to render. Currently, vanilla only has the SimpleUnbakedGeometry, which holds the familiar list of BlockElements. These UnbakedModel, once loaded, are then passed to the ModelDiscovery for resolving the block state and item models.

Next we have the ResolvableModels, which is the base of both block state and item models. These models essentially function as markers requesting the UnbakedModels that they will be using. From there, we have their subtypes BlockStateModel$UnbakedRoot for the block state JSON and ItemModel$Unbaked for the model referenced in the client item JSON. Each of these implement resolveDependencies in some way to call ResolvableModel$Resolver#markDependency with the model location they would like to use.

Technically, BlockStateModels are a bit more complex as variants use BlockStateModel$Unbaked during loading which are then transformed into an $UnbakedRoot during initialization.

Now that we know what models that should be loaded, they now have to be put into a usable state for baking. This is the job of the ModelDiscovery, which takes in a ResolvableModel and loads the UnbakedModels into a ResolvedModel on first reference. ResolvedModels are functionally wrappers around UnbakedModels used to resolve all dependency chains, as the name implies.

From there, model groups are built for BlockStates and the textures are loaded, leading to the final step of actually baking the BlockStateModel and the ItemModel. This is handled through the bake methods provided on the $UnbakedRoot (or $Unbaked) and the ModelBakery. In a nutshell, bake constructs the list of BakedQuads stored with whatever additional information is desired by the block state or item model itself. The ResolvedModels are obtained from the baker, from which the instance methods are called. For BlockStateModels, this is resolved via SimpleModelWrapper#bake, from which the ModelState is obtained from the Variant data. They stored the baked quads in a BlockModelPart. For ItemModels, it just consumes the BakedQuads list directly along with information provided by ModelRenderProperties#fromResolvedModel. This does mean that each BlockStateModel and ItemModel may contain duplicated (but unique) BakedQuads if the same model is referenced in multiple locations.

Block Generators: The Variant Mutator

Given all the changes that separated out the block state JSON loading, there have also been a number of changes to the BlockModelGenerators. While most of them are simply renames (e.g., BlockStateGenerator -> BlockModelDefinitionGenerator), the major change is the addition of the VariantMutator. The VariantMutator is functionally a UnaryOperator on a Variant used to set some setting. This addition has simplified (or more like codec construction) the use of the PropertyDispatch for more quickly dispatching blocks with variants based on their properties.

// Creates a property dispatch on the horizontal facing property
// Applies the associated variants, though if desired, a functional interface can be provided instead
public static final PropertyDispatch<VariantMutator> ROTATION_HORIZONTAL_FACING = PropertyDispatch.modify(BlockStateProperties.HORIZONTAL_FACING)
    .select(Direction.EAST, BlockModelGenerators.Y_ROT_90)
    .select(Direction.SOUTH, BlockModelGenerators.Y_ROT_180)
    .select(Direction.WEST, BlockModelGenerators.Y_ROT_270)
    .select(Direction.NORTH, BlockModelGenerators.NOP);

// Then, with access to the `Consumer<BlockModelDefinitionGenerator>` blockStateOutput
this.blockStateOutput.accept(
    MultiVariantGenerator.dispatch(EXAMPLE_BLOCK).with(ROTATION_HORIZONTAL_FACING)
);
  • net.minecraft.client.data.models
    • BlockModelGenerators
      • nonOrientableTrapdoor -> NON_ORIENTABLE_TRAPDOOR, now static
      • Constants are now available for common VariantMutators, like rotating the block model some number of degrees
      • texturedModels -> TEXTURED_MODELS, now static
      • MULTIFACE_GENERATOR is now private
      • plainModel - Creates a variant from the model location.
      • variant, variants - Creates a regular MultiVariant from some number of Variants
      • plainVariant - Creates a MultiVariant with only one model from its location.
      • condition - Creates a new condition builder for multipart models
      • or - ORs multiple conditions together.
      • Most generator methods now return the BlockModelDefinitionGenerator, Variant, or MultiVariant and take in a Variant or MultiVariant instead of a ResourceLocation pointing to the desired model
        • VariantProperties have been replaced with VariantMutators
        • Condition$TerminalCondition is replaced with Condition
      • createHorizontalFacingDispatch, createHorizontalFacingDispatchAlt, createTorchHorizontalDispatch is removed
      • createFacingDispatch is removed
      • createRotatedVariant(Block, ResourceLocation) is removed
      • selectMultifaceProperties - Creates a map of properties to VariantMutators based on the provided BlockState and direction to property function.
      • applyRotation no longer takes in the Variant and returns a VariantMutator
    • ItemModelGenerators#generateSpawnEgg is removed
    • ModelProvider#saveAll is removed
  • net.minecraft.client.data.models.blockstates
    • BlockStateGenerator -> BlockModelDefinitionGenerator, not one-to-one
    • Condition -> net.minecraft.client.renderer.block.model.multipart.Condition, not one-to-one
      • validate -> instantiate, not one-to-one
    • ConditionBuilder - Builds a condition using property values
    • MultiPartGenerator now implements BlockModelDefinitionGenerator
      • with(List<Variant>) -> with(MultiVariant)
      • with(Variant) is removed
      • with(Condition, ...) -> with(Condition, MultiVariant)
        • Overload taking in ConditionBuilder
      • $ConditionalEntry, $Entry is removed
    • MultiVariantGenerator now implements BlockModelDefinitionGenerator
      • multiVariant -> dispatch
      • multiVariant(Block, ...) -> dispatch(Block, MultiVariant)
      • $Empty - A multi variant entry that matches every block state.
    • PropertyDispatch has a generic containing the value of the dispatch
      • The generic V replaces all values of List<Variant>
      • property, properties -> initial or modify
      • $C*#generateList methods are removed
      • $*Function are removed
    • Selector -> PropertyValueList, not one-to-one
    • Variant -> net.minecraft.client.renderer.block.model.Variant, not one-to-one
    • VariantProperties -> net.minecraft.client.renderer.block.model.VariantMutator, not one-to-one
    • VariantProperty -> net.minecraft.client.renderer.block.model.VariantMutator$VariantProperty, not one-to-one
  • net.minecraft.client.renderer.ItemInHandRenderer#renderItem no longer takes in the boolean representing if the item is held in the left hand
  • net.minecraft.client.renderer.block
    • BlockModelShaper#stateToModelLocation, statePropertiesToString is removed
    • BlockRenderDispatcher#renderBatched now takes in a list of BlockModelParts instead of a RandomSource
    • ModelBlockRenderer
      • tesselateBlock, tesselateWithAO, tesselateWithoutAO no longer takes in a RandomSource and replaces BlockStateModel with a list of BlockModelParts
      • renderModel is now static and no longer takes in the BlockState
      • $AmbientOcclusionFace -> $AmbientOcclusionRenderStorage
      • $CommonRenderStorage - A class that holds some metadata used to render a block at its given position.
      • $SizeInfo now takes in the direct index rather than computing the info from its direction and a flipped boolean
  • net.minecraft.client.renderer.block.model
    • BakedQuad is now a record
    • BlockElement is now a record
      • from, to are now Vector3fc
    • BlockElementFace now takes in a Quadrant for the face rotation
      • getU, getV - Returns the texture coordinate after rotation.
      • $Deserializer#getTintIndex is now private and static
    • BlockFaceUV -> BlockElementFace$UVs, not one-to-one
    • BlockModel is now a record, taking in an UnbakedGeometry instead of the direct list of BlockElements
      • $Deserializer#getElements now returns an UnbakedGeometry
    • BlockModelDefinition is now a record, taking in $SimpleModelSelectors and $MultiPartDefinitions
      • GSON, fromStream, fromJsonElement -> CODEC, not one-to-one
      • instantiate now takes in a supplied string instead of the string directly
      • $Deserializer is removed
      • $MultiPartDefinition - A record that holds a list of selectors to get for the multi part model.
      • $SimpleModelSelectors - A record that holds a map of variants to their unbaked model instances.
    • BlockModelPart - A baked model representation of a block.
    • BlockStateModel - A baked representation of a block state.
      • collectParts - Obtains the list of baked models used to render this state.
      • $SimpleCachedUnbakedRoot - A class that represents a delegate of some $Unbaked model.
      • $Unbaked - An extension over $UnbakedRoot that can create a $SimpleCachedUnbakedRoot
    • FaceBakery
      • bakeQuad now takes in Vector3fcs instead of Vector3fs
      • recomputeUVs is removed
      • extractPositions - Extracts the face positions and passes them to a consumer for use.
    • ItemTransform is now a record, vectors are Vector3fcs
    • MultiVariant -> net.minecraft.client.data.models.MultiVariant
      • CODEC
      • with - Creates a MultiVariant with the specified mutators.
      • $Deserializer class is removed
    • SimpleModelWrapper now implements BlockModelPart
    • SimpleUnbakedGeometry - An unbaked geometry that holds a list of BlockElements to bake.
    • SingleVariant - A BlockStateModel implementation with only one model for its state.
    • UnbakedBlockStateModel -> BlockStateModel$UnbakedRoot
    • Variant no longer implements ModelState, now taking in a $SimpleModelState instead of the direct rotation and uv lock
      • The constructor now has an overload for only providing the ResourceLocation and no longer takes in the weight, leaving that to the MultiVariant
      • CODEC
      • withXRot, withYRot, withUvLock, withModel, withState, with - Mutates the variant into a new object with the given setting applied.
      • $Deserializer class is removed
      • $SimpleModelState - A record that holds the x/y rotations and uv lock.
    • VariantMutator - A unary operator on a variant that applies the specified setting to the variant. Used during state generation.
  • net.minecraft.client.renderer.block.model.multipart
    • AndCondition, OrCondition -> CombinedCondition, not one-to-one
    • KeyValueCondition is now a record that takes in a map of keys to terms to test
    • MultiPart -> MultiPartModel$Unbaked
      • $Definition
        • CODEC
        • getMultiVariants is removed
      • $Deserializer class is removed
    • Selector is now a record, taking in a BlockStateModel$Unbaked instead of a MultiVariant
      • $Deserializer class is removed
  • net.minecraft.client.renderer.entity.ItemRenderer
    • renderItem now takes in a List<BakedQuad> instead of a BakedModel
    • renderStatic no longer takes in a boolean indicating what hand the item was held in
  • net.minecraft.client.renderer.item
    • BlockModelWrapper now has a public constructor that takes in the list of tint sources, the list of quads, and the ModelRenderProperties
      • The list of quads and ModelRenderProperties replaces the direct BakedModel, or now BlockStateModel
      • computeExtents - Extracts the vertices of the baked quads into an array.
    • ItemModel$BakingContext#bake is removed
    • ItemModelResolver#updateForLiving, updateForTopItem no longer takes in a boolean representing if the item is in the left hand
    • ItemStackReenderState
      • isGui3d is removed
      • transform is removed
      • visitExtents - Visits all vertices of the model to render and passes them into the provided consumer.
      • $LayerRenderState
        • NO_EXTENTS_SUPPLIER - An empty list of vertices.
        • setupBlockModel has been broken into prepareQuadList, setRenderType, setUsesBlockLight, setExtents, setParticleIcon, setTransform
        • setupSpecialModel no longer takes in the base BakedModel
    • MissingItemModel now takes in a list of BakedQuads and ModelRenderProperties instead of the direct BakedModel
    • ModelRenderProperties - The properties used to render a model, typically retrieved from the ResolvedModel.
    • SpecialModelRenderer now takes in the ModelRenderProperties insetad of the base BakedModel
  • net.minecraft.client.resources.model
    • BakedModel -> net.minecraft.client.resources.model.QuadCollection, not one-to-one
    • BlockModelRotation
      • by now takes in Quadrants instead of integers
      • withUvLock - Returns the model state with the rotation and a mention that it locks the UV for the rotation.
    • BlockStateDefinitions - A manager for creating the mapper of block names to their state defintions.
    • BlockStateModelLoader
      • ModelResourceLocation fields are removed
      • loadBlockState no longer takes in the missing model
      • $LoadedModel class is removed
      • $LoadedModels now takes in a BlockStateModel$UnbakedRoot instead of an $Unbaked
        • forResolving, plainModels is removed
    • DelegateBakedModel -> net.minecraft.client.renderer.block.model.SimpleModelWrapper, not one-to-one
    • MissingBlockModel#VARIANT is removed
    • ModelBaker
      • bake -> getModel, not one-to-one
        • The baker is simply retrieving the ResolvedModel
      • rootName is removed
      • compute - Computes the provided key that contains the ModelBaker. Typically used for baking BlockStateModels
      • $SharedOperationKey - An interface which typically computes some baking process for an unbaked model.
    • ModelBakery now takes in a Map<BlockState, BlockStateModel$UnbakedRoot> for the unbaked block state models, a Map<ResourceLocation, ResolvedModel> for the loaded models, and a ResolvedModel for the missing model
      • bakeModels now takes in a SpriteGetter and an Executor while returning a CompletableFuture for parallel loading and baking
      • $BakingResult now takes in a $MissingModels for the missing block state and item model and a Map<BlockState, BlockStateModel> for the baked block state models; the missing item model is stored within $MissingModels
      • $MissingModels - Holds the missing models for a block state and item.
      • $TextureGetter interface is removed
    • ModelDebugName no longer extends Supplier<String>, instead using debugName
    • ModelDiscovery
      • registerSpecialModels is removed
      • discoverDependencies is now private
      • getReferencedModels, getUnreferencedModels is removed
      • addSpecialModel - Adds a root model to the list of arbitrarily loaded models.
      • missingModel - Returns the missing model
      • resolve - Resolves all model dependencies, returning a map of model names to their models.
    • ModelGroupCollector$GroupKey#create now takes in a BlockStateModel$UnbakedRoot instead of an $Unbaked
    • ModelManager
      • getModel is removed
      • getMissingModel -> getMissingBlockStateModel
      • $ResolvedModels - A map of models with their dependencies resolved.
    • ModelResourceLocation record is removed
    • ModelState
      • getRotation -> transformation
      • isUvLocked is removed
      • faceTransfomration, inverseFaceTransformation - Handles returning the transformed Matrix4fc for baking the face vertices.
    • MultiPartBakedModel -> net.minecraft.client.renderer.block.model.multipart.MultiPartModel
      • Now implements BlockStateModel instead of extending DelegateBakedModel
      • $SharedBlockState - A holder that contains the BlockStateModels mapped to their $Selectors.
    • QuadCollection - A data object containing the list of quads to render based on the associated direction and culling.
    • ResolvableModel$Resolver#resolve -> markDependency, not one-to-one
      • Instead of directly resolving, the dependency is marked for a later post processing step
    • ResolvedModel - An UnbakedModel whose model and texture dependencies have been completely resolved.
    • SimpleBakedModel -> net.minecraft.client.renderer.block.model.SimpleModelWrapper or net.minecraft.client.renderer.block.model.SimpleUnbakedGeometry, not one-to-one
    • SpriteGetter
      • get, reportMissingReference now take in the ModelDebugName
      • resolveSlot - Resolves the key from the TextureSlots into its TextureAtlasSprite.
    • UnbakedGeometry - An interface that constructs a collection of quads the render when baked.
    • UnbakedModel no longer implements ResolvableModel
      • DEFAULT_AMBIENT_OCCLUSION, DEFAULT_GUI_LIGHT is removed
      • PARTICLE_TEXTURE_REFERENCE - Holds the key representing the particle texture.
      • bake is removed
      • getAmbientOcclusion -> ambientOcclusion
      • getGuiLight -> guiLight
      • getTransforms - transforms
      • getTextureSlots - textureSlots
      • geometry - Holds the unbaked geometry representing the model elements.
      • getParent -> parent, not one-to-one
      • bakeWithTopModelValues is removed
      • getTopTextureSlots, getTopAmbientOcclusion, getTopGuiLight, getTopTransform, getTopTransforms is removed
    • WeightedBakedModel -> WeightedVariants
      • Now implements BlockStateModel instead of extending DelegateBakedModel
  • net.minecraft.world.item.ItemDisplayContext#leftHand - Returns whether the display context is rendering with the entity’s left hand.

Minor Migrations

The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.

Entity References

Generally, the point of storing the UUID of another entity was to later grab that entity to perform some logic. However, storing the raw entity could lead to issues if the entity was removed at some point in time. As such, the EntityReference was added to handle resolving the entity from its UUID while also making sure it still existed at the time of query.

An EntityReference is simply a wrapped Either which either holds the entity instance or the UUID. When resolving via getEntity, it will attempt to verify that the stored entity, when present, isn’t removed. If it is, it grabs the UUID to perform another lookup for the entity itself. If that entity does exist, it will be return, or otherwise null.

Most references to a UUID within an entity have been replaced with an EntityReference to facilitate this change.

  • net.minecraft.network.syncher.EntityDataSerializers#OPTIONAL_UUID -> OPTIONAL_LIVING_ENTITY_REFERENCE, not one to one as it can hold the entity reference
  • net.minecraft.server.level.ServerLevel#getEntity(UUID) -> Level#getEntity(UUID)
  • net.minecraft.world.entity
    • EntityReference - A reference to an entity either by its entity instance when present in the world, or a UUID.
    • LivingEntity#lastHurtByPlayer, lastHurtByMob are now EntityReferences
    • OwnableEntity
      • getOwnerUUID -> getOwnerReference, not one-to-one
      • level now returns a Level instead of an EntityGetter
    • TamableAnimal#setOwnerUUID -> setOwner, or setOwnerReference; not one-to-one
  • net.minecraft.world.entity.animal.horse.AbstractHorse#setOwnerUUID -> setOwner, not one-to-one
  • net.minecraft.world.level.Level now implements UUIDLookup<Entity>
  • net.minecraft.world.level.entity
    • EntityAccess now implements UniquelyIdentifyable
    • UniquelyIdentifyable - An interface that claims the object as a UUID and keeps tracks of whether the object is removed or not.
    • UUIDLookup - An interface that looks up a type by its UUID.

Descoping Player Arguments

Many methods that take in the Player has been descoped to take in a LivingEntity or Entity depending on the usecase. The following methods below are a non-exhaustive list of this.

  • net.minecraft.world.entity.EntityType
    • spawn
    • createDefaultStackConfig, appendDefaultStackConfig
    • appendCustomEntityStackConfig, updateCustomEntityTag
  • net.minecraft.world.item
    • BucketItem#playEmptySound
    • DispensibleContainerItem#checkExtraContent, emptyContents
  • net.minecraft.world.level
    • Level
      • playSeededSound
      • mayInteract
    • LevelAccessor
      • playSound
      • levelEvent
  • net.minecraft.world.level.block
    • BucketPickup#pickupBlock
    • LiquidBlockContainer#canPlaceLiquid
  • net.minecraft.world.level.block.entity.BrushableBlockEntity#brush

Component Interaction Events

Click and hover events on a MutableComponent have been reworked into MapCodec registry-like system. They are both now interfaces that register their codecs to an $Action enum. The implementation then creates a codec that references the $Action type and stores any necessary information that is needed for the logic to apply. However, there is no direct ‘action’ logic associated with the component interactions. Instead, they are hardcoded into their use locations. For click events, this is within Screen#handleComponentClicked. For hover events, this is in GuiGraphics#renderComponentHoverEffect. As such, any additional events added will need to inject into both the enum and one or both of these locations.

  • net.minecraft.network.chat
    • ClickEvent is now an interface
      • getAction -> action
      • getValue is now on the subclasses as necessary for their individual types
    • HoverEvent is now an interface
      • getAction -> action
      • $EntityTooltipInfo
        • CODEC is now a MapCodec
        • legacyCreate is removed
      • $ItemStackInfo is removed, replaced by $ShowItem
      • $LegacyConverter interface is removed

Texture Atlas Reworks

The texture atlas logic has been finalized into a registry codec system; however, the querying of the atlas data has changed. First, all atlas identifiers are stored within AtlasIds while the corresponding texture location is stored within Sheets. To get a material from an atlas, a MaterialMapper is used as a wrapper around the texture location and the associated prefix to append to the material. The Material can then be obtained using apply by passing in the id of the material you would like to use.

For example:

// Found in sheets
public static final MaterialMapper ITEMS_MAPPER = new MaterialMapper(TextureAtlas.LOCATION_BLOCKS, "item");
public static final MaterialMapper BLOCKS_MAPPER = new MaterialMapper(TextureAtlas.LOCATION_BLOCKS, "block");

// Finds the texture for the material at `assets/examplemod/textures/item/example_item.png`
public static final Material EXAMPLE_ITEM = ITEMS_MAPPER.apply(ResourceLocation.fromNamespaceAndPath("examplemod", "example_item"));

// Finds the texture for the material at `assets/examplemod/textures/block/example/block.png`
public static final Material EXAMPLE_BLOCK = ITEMS_MAPPER.apply(ResourceLocation.fromNamespaceAndPath("examplemod", "example/block"));
  • net.minecraft.client.data.AtlasProvider - A data provider for generating the providers of a texture atlas.
  • net.minecraft.client.data.models.ItemModelGenerators
    • SLOT_* -> TRIM_PREFIX_*, now public and ResourceLocations
    • TRIM_MATERIAL_MODELS is now public
    • generateTrimmableItem now takes in a ResourceLocation instead of a String
    • $TrimMaterialData is now public, taking in a MaterialAssetGroup instead of the name and override materials
  • net.minecraft.client.renderer
    • MaterialMapper - An object that stores the location of the atlas texture and the prefix applied to the ids within the texture.
    • Sheets
      • *_MAPPER - MaterialMappers for each texture atlas texture.
      • createBedMaterial(ResourceLocation) is removed
      • createShulkerMaterial(ResourceLocation) is removed
      • createSignMaterial(ResourceLocation) is removed
      • chestMaterial(String), chestMaterial(ResourceLocation) are removed
      • createDecoratedPotMaterial(ResourceLocation) is removed
  • net.minecraft.client.renderer.blockentity.ConduitRenderer#MAPPER - A mapper to get the conduit textures from the block atlas.
  • net.minecraft.client.renderer.texture.atlas
    • SpriteSource#type -> codec, not one-to-one
    • SpriteSources now contains logic similar to client registries via their id mapper
    • SpriteSourceType record is removed
  • net.minecraft.client.renderer.texture.atlas.sources
    • DirectoryLister is now a record
    • PalettedPermutations is now a record
    • SingleFile is now a record
    • SourceFilter is now a record
    • Unstitcher is now a record
      • $Region is now public
  • net.minecraft.client.resources.model.AtlasIds - A class which holds the ResourceLocations of all vanilla texture atlases.

Registry Context Swapper

Client items now store a RegistryContextSwapper, which is used to properly check client item information that accesses registry objects. Before level load, this is provided a placeholder to avoid crashing and populated with the correct value during rendering.

  • net.minecraft.client.multiplayer
    • CacheSlot - An object that contains a value computed from some context. When updated, the previous value is overwritten and the context registers the slot to be cleaned.
    • ClientLevel now implements CacheSlot$Cleaner
  • net.minecraft.client.renderer.item
    • ClientItem can now take in a nullable RegistryContextSwapper
      • withRegistrySwapper - Sets the RegistryContextSwapper within a ClientItem
    • ItemModel$BakingContext now takes in a RegistryContextSwapper
  • net.minecraft.util
    • PlaceholderLookupProvider - A provider that contains placeholders for referenced objects. Used within client items as they will be loaded before the RegistyAccess is populated.
    • RegistryContextSwapper - An interface used to swap out some object for a different one. Used by client items to swap the placeholders for the loaded RegistryAccess.

Reload Instance Creation

Reload instances have been slightly rearranged. The SimpleReloadInstance base now only takes in the List<PreparableReloadListener>, where the other fields are passed into the of function such that #startTasks can be called immediately.

  • net.minecraft.server.packs.resources
    • ProfiledReloadInstance construct is now private, accessed through of
    • SimpleReloadInstance only takes in the List<PreparableReloadListener>
      • of now returns a ReloadInstance, not one-to-one
      • allPreparations is now package private
      • allDone is now private
      • startTasks - Begins the reload of the listener.
      • prepareTasks - Runs the executor and sets up the futures needed to read and load all desired data.
      • StateFactory$SIMPLE - A factory that calls PreparableReloadListener#reload

Block Effect Appliers

Effects that are applied to entities when inside a block are now handled through the InsideBlockEffectApplier and InsideBlockEffectType. The InsideBlockEffectType is an enum that contains a consumer on what to apply to an entity when called. InsideBlockEffectApplier, on the other hand, is stored on the entity has a way to apply an effect in a ordered manner based on the enum ordinals.

To call one of the effect types, you must override BlockBehaviour#entityInside or Fluid#entityInside and call InsideBlockEffectApplier#apply. If something should apply before the effect type, like entinguishing fire before freezing in powder snow, then InsideBlockEffectApplier#runBefore should be called before apply. Similarly, if something should run afterward, like hurting an enemy after being placed in lava, then runAfter should be called.

// In some block or fluid subclass
@Override
protected void entityInside(Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier applier) {
    applier.runBefore(InsideBlockEffectType.EXTINGUISH, entity -> {
        // Modify entity here.
    });

    // Do the base application logic stored on the type
    applier.apply(InsideBlockEffectType.FIRE_IGNITE);

    applier.runAfter(InsideBlockEffectType.FIRE_IGNITE, entity -> {
        // Perform any final checks that are as a result of the effect being applied
        entity.hurt(...);
    });
}
  • net.minecraft.world.entity
    • InsideBlockEffectApplier - An interface that defines how an entity should interact when within a given block.
    • InsideBlockEffectType - An enum that defines what behavior to perform when side the specific block that references the type.
  • net.minecraft.world.level.block.state.BlockBehaviour#entityInside, $BlockStateBase#entityInside now takes in an InsideBlockEffectApplier
  • net.minecraft.world.level.material.Fluid#entityInside, FluidState#entityInside - A method called whenever the entity is considered inside the bounding box of the fluid.

Timer Callbacks, joining the codec club!

TimerCallbacks, used in the server schedule for executing events, typically mcfunctions in datapacks, have now been reworked into a codec form. This means that a callback can be registered to the list of available callbacks by passing in the MapCodec to TimerCallbacks#register (via TimerCallbacks#SERVER_CALLBACKS) instead of the serializer.

  • net.minecraft.world.level.timers
    • FunctionCallback is now a record
    • FunctionTagCallback is now a record
    • TimerCallback
      • codec - Returns the codec used for serialization.
      • $Serializer class is removed
    • TimerCallbacks
      • serialize, deserialize -> codec, not one-to-one

The JOML Backing Interfaces

Mojang has opted to lessen the restriction on JOML objects by passing around the implementing interface of their logic objects (usually implemented with a tacked on c). For example, Vector3f becomes Vector3fc or Matrix4f becomes Matrix4fc. This does not change any logic itself as the c interfaces are implemented by the class components.

Tag Changes

  • minecraft:worldgen/biome
    • spawns_cold_variant_farm_animals
    • spawns_warm_variant_farm_animals
  • minecraft:block
    • sword_instantly_mines
    • replaceable_by_mushrooms
    • plays_ambient_desert_block_sounds
    • edible_for_sheep
    • dead_bush_may_place_on -> dry_vegetation_may_place_on
    • camels_spawnable_on
  • minecraft:cat_variant are removed
  • minecraft:entity_type
    • can_equip_saddle
    • can_wear_horse_armor
  • minecraft:item
    • book_cloning_target
    • eggs
    • flowers

Mob Effects Field Renames

Some mob effects have been renamed to their in-game name, rather than some internal descriptor.

  • MOVEMENT_SPEED -> SPEED
  • MOVEMENT_SLOWDOWN -> SLOWNESS
  • DIG_SPEED -> HASTE
  • DIG_SLOWDOWN -> MINING_FATIGUE
  • DAMAGE_BOOST -> STRENGTH
  • HEAL -> INSTANT_HEALTH
  • HARM -> INSTANT_DAMAGE
  • JUMP -> JUMP_BOOST
  • CONFUSION -> NAUSEA
  • DAMAGE_RESISTANCE -> RESISTANCE

Very Technical Changes

This is a list of technical changes that could cause highly specific errors depending on your specific setup.

  • The order of the minecraft:patch_sugar_cane feature and minecraft:patch_pumpkin feature have swapped orders (first pumpkin, then sugar cane), meaning modded biomes that generate both of these features will need to update their JSONs to the new ordering.

  • Serveral vanilla oak tree and tree selector features now have _leaf_litter appended at the end.

    • For example: trees_birch_and_oak -> trees_birch_and_oak_leaf_litter

List of Additions

  • net.minecraft
    • ChatFormatting#COLOR_CODEC
    • CrashReportCategory#populateBlockLocationDetails - Adds the block location details to a crash report.
  • net.minecraft.advancements.critereon.MinMaxBounds#createStreamCodec - Constructs a stream codec for a MinMaxBounds implementation.
  • net.minecraft.client.Options#startedCleanly - Sets whether the game started cleanly on last startup.
  • net.minecraft.client.data.models
    • BlockModelGenerators#createSegmentedBlock - Generates a multipart blockstate definition with horizontal rotation that displays up to four models based on some integer property.
    • ItemModelGenerators#prefixForSlotTrim - Generates a vanilla ResourceLocation for a trim in some slot.
  • net.minecraft.client.MouseHandler
    • fillMousePositionDetails - Adds details about the current mouse location and screen size to a crash report.
    • getScaledXPos - Gets the current x position scaled by the gui scaling option.
    • getScaledYPos - Gets the current y position scaled by the gui scaling option.
    • drawDebugMouseInfo - Draws information about the scaled position of the mouse to the screen.
  • net.minecraft.client.gui.components.toasts.Toast#getSoundEvent - Returns the sound to play when the toast is displayed.
  • net.minecraft.client.gui.screens.options.VideoSettingsScreen#updateFullscreenButton - Sets the fullscreen option to the specified boolean.
  • net.minecraft.client.model.geom.builders
    • MeshDefinition#apply - Applies the given transformer to the mesh before returning a new instance.
    • MeshTransformer#IDENTITY- Performs the identity transformation.
  • net.minecraft.client.multiplayer.ClientPacketListener#decoratedHashOpsGenenerator - Returns the generator used to create a hash of a data component and its value.
  • net.minecraft.client.particle
    • FallingLeavesParticle$TintedLeavesProvider - A provider for a FallingLeavesParticle that uses the color specified by the block above the particle the spawn location.
    • FireflyParticle - A particle that spawns fireflies around a given non-air block position.
  • net.minecraft.client.renderer
    • BiomeColors#getAverageDryFoliageColor - Returns the average foliage color for dry biomes.
    • LevelRenderer$BrightnessGetter - An interfaces which obtains the packed brightness at a given block position.
    • WorldBorderRenderer#invalidate - Invalidates the current render of the world border to be rerendered.
  • net.minecraft.client.renderer.entity
    • EntityRenderDispatcher#getRenderer - Gets the renderer to use from the data stored on the render state.
    • EntityRenderer#extractAdditionalHitboxes - Gets any additional hitboxes to render when the ‘show hitboxes’ debug state is enabled.
  • net.minecraft.client.renderer.entity.state
    • EntityRenderState
      • entityType - The type of the entity.
      • hitboxesRenderState - The hitbox information of the entity relative to the entity’s position.
      • serverHitboxesRenderState - The hitbox information of the entity synced from the server.
      • fillCrashReportCategory - Sets the details for any crashes related to the render state.
    • HitboxesRenderState - The render state of the hitboxes for the entity relative to the entity’s position.
    • HitboxRenderState - The render state of a single hitbox to render along with its color, such as the eye height of an entity.
    • ServerHitboxesRenderState - The render state containing the last synced information from the related server entity.
    • PigRenderState#variant - The variant of the pig.
  • net.minecraft.client.renderer.item.SelectItemModel$ModelSelector - A functional interface that selects the item model based on the switch case and level.
  • net.minecraft.client.renderer.item.properties.conditional.ComponentMatches - A conditional property that checks whether the given predicate matches the component data.
  • net.minecraft.client.renderer.item.properties.select
    • ComponentContents - A switch case property that operates on the contents within a data component.
    • SelectItemModelProperty#valueCodec - Returns the Codec for the property type.
  • net.minecraft.client.resources.DryFoliageColorReloadListener - A reload listener that loads the colormap for dry foliage.
  • net.minecraft.commands.arguments.ComponentArgument#getResolvedComponent - Constructs a component with the resolved information of its contents.
  • net.minecraft.core
    • Direction#getUnitVec3f - Returns the float unit vector of the direction.
    • HolderGetter$Provider#getOrThrow - Gets a holder reference from a resource key.
    • SectionPos#sectionToChunk - Converts a compressed section position to a compressed chunk position.
    • Vec3i#STREAM_CODEC
  • net.minecraft.network
    • HashedPatchMap - A record containing a map of components to their hashed type/value along with a set of removed components.
    • HashedStack - An ItemStack representation that hashes the stored components.
    • ProtocolInfo$DetailsProvider - Provides the details for a given protocol.
    • SkipPacketDecoderException - An exception thrown when an error occurs during decoding before having its data ignored.
    • SkipPacketEncoderException - An exception thrown when an error occurs during encoding before having its data ignored.
  • net.minecraft.network.chat
    • LastSeenMessages
      • computeChecksum - Computes a byte representing the merged checksums of all message signatures.
      • $Update#verifyChecksum - Verifies that the update checksum matches those within the last seen messages.
    • LastSeenMessagesValidator$ValidationException - An exception thrown if the messages can not be validated.
    • MessageSignature
      • describe - Returns a stringified version of the message signature.
      • checksum - Hashes the bytes within the signature into a single integer.
    • PlayerChatMessage#describeSigned - Returns a stringified version of the chat message.
  • net.minecraft.network.codec
    • ByteBufCodecs
      • LONG_ARRAY
      • lengthPrefixed - Returns an operation that limits the size of the buffer to the given size.
    • IdDispatchCodec$DontDecorateException - An interface that tells the exception handler to rethrow the raw exception rather than wrap it within an EncoderException.
  • net.minecraft.network.protocol
    • CodecModifier - A function that modifies some codec using a given object.
    • ProtocolInfoBuilder#context*Protocol - Builds an UnboundProtocol with the given context used to modify the codecs to send.
  • net.minecraft.network.protocol.game.GameProtocols
    • HAS_INFINITE_MATERIALS - A modifier that checks the ServerboundSetCreativeModeSlotPacket for if the player has the necessary settings. If not, the packet is discarded.
    • $Context - Returns the context used by the packet to modify the incoming codec.
  • net.minecraft.resources.DelegatingOps
    • $DelegateListBuilder - A list builder that can be subclassed if needed.
    • $DelegateRecordBuilder - A record builder that can be subclassed if needed.
  • net.minecraft.server.bossevents.CustomBossEvent$Packed - A record that backs the event information for serialization.
  • net.minecraft.server.commands.InCommandFunction - A command function that takes in some input and returns a result.
  • net.minecraft.server.level
    • DistanceManager#forEachBlockTickingChucnks - Applies the provided consumer for each chunk with block ticking enabled.
    • ServerLevel
      • areEntitiesActuallyLoadedAndTicking - Returns whether the entity manager is actually ticking and loading entities in the given chunk.
      • tickThunder - Ticks the thunger logic within a given level.
      • anyPlayerCloseEnoughForSpawning - Returns if a player is close enough to spawn the entity at the given location.
    • ServerPlayer$RespawnConfig - A record containing the respawn information for the player.
  • net.minecraft.util
    • AbstractListBuilder - A ops list builder which boils the implementation down to three methods which initializes, appends, and builds the final list.
    • Brightness
      • block - Returns the block light from a packed value.
      • sky - Returns the sky light from a packed value.
    • HashOps - A dynamic ops that generates a hashcode for the data.
    • ExtraCodecs
      • UNTRUSTED_URI - A codec for a URI that is not trusted by the game.
      • CHAT_STRING - A codec for a string in a chat message.
      • legacyEnum - A codec that maps an enum to its output in Enum#toString.
    • FileSystemUtil - A utility for interacting with the file system.
    • GsonHelper#encodesLongerThan - Returns whether the provided element can be written in the specified number of characters.
    • Unit#STREAM_CODEC - A stream codec for a unit instance.
    • Util
      • mapValues - Updates the values of a map with the given function.
      • mapValuesLazy - Updates the values of a map with the given function, but each value is resolved when first accessed.
      • growByHalf - Returns an integer multiplied by 1.5, rounding down, clamping the value to some minimum and the max integer size.
  • net.minecraft.util.random.Weighted#map, WeightedList#map - Transforms the stored object(s) to a new type.
  • net.minecraft.util.thread.ParallelMapTransform - A helper that handles scheduling and batching tasks in parallel.
  • net.minecraft.world.effect.MobEffectInstance#withScaledDuration - Constructs a new instance with the duration scaled by some float value.
  • net.minecraft.world.entity
    • AreaEffectCloud#setPotionDurationScale - Sets the scale of how long the potion should apply for.
    • DropChances - A map of slots to probabilities indicating how likely it is for an entity to drop that piece of equipment.
    • Entity
      • isInterpolating - Returns whether the entity is interpolating between two steps.
      • sendBubbleColumnParticles - Spawns bubble column particles from the server.
      • canSimulateMovement - Whether the entity’s movement can be simulated, usually from being the player.
      • propagateFallToPassengers - Propogates the fall damage of a vehicle to its passengers.
      • lavaIgnite - Ignites the entity for 15 seconds if not immune.
      • clearFreeze - Sets the number of ticks the entity is frozen for to 0.
      • removeLatestMovementRecordingBatch - Removes the last element from all movements performed this tick.
    • InterpolationHandler - A class meant to easily handle the interpolation of the position and rotation of the given entity as necessary.
    • LivingEntity
      • getLuck - Returns the luck of the entity for random events.
      • getLastHurtByPlayer, setLastHurtByPlayer - Handles the last player to hurt this entity.
      • getEffectBlendFactor - Gets the blend factor of an applied mob effect.
      • applyInput - Applies the entity’s input as its AI, typically for local players.
      • INPUT_FRICTION - The scalar to apply to the movements of the entity.
  • net.minecraft.world.entity.animal.camel.Camel#checkCamelSpawnRules - Checks if a camel can spawn at a particular position.
  • net.minecraft.world.entity.animal.sheep.SheepColorSpawnRules - A class that contains the color spawn configurations for a sheep’s wool when spawning within a given climate.
  • net.minecraft.world.entity.npc.Villager#createDefaultVillagerData - Returns the default type and profession of the villager to use when no data is set.
  • net.minecraft.world.entity.player.Player
    • preventsBlockDrops - Whether the player cannot drop any blocks on destruction.
    • gameMode - Returns the current game mode of the player.
    • debugInfo - Returns the common information about the player as a single string.
  • net.minecraft.world.inventory
    • ContainerSynchronizer#createSlot - Creates a RemoteSlot that represents a slot on the opposite side.
    • RemoteSlot - A slot that represents the data on the opposing side, syncing when the data is not consistent.
  • net.minecraft.world.item
    • EitherHolder#key - Returns the resource key of the held registry object.
    • Item#STREAM_CODEC
    • ItemStack
      • OPTIONAL_UNTRUSTED_STREAM_CODEC
      • MAP_CODEC
      • canDestroyBlock - Returns whether this item can destroy the provided block state.
  • net.minecraft.world.item.alchemy.PotionContents#getPotionDescription - Returns the description of the mob effect with some amplifier.
  • net.minecraft.world.item.crafting
    • Recipe#KEY_CODEC
    • TransmuteResult - A recipe result object that represents an item, count, and the applied components.
  • net.minecraft.world.item.equipment.trim.ArmorTrim#layerAssetId - Returns the location of the the trim asset.
  • net.minecraft.world.level
    • BlockGetter$BlockStepVisitor - A consumer that takes in the current position and how many collisions within the desired path of travel.
    • ColorMapColorUtil - A helper for getting the color from a map given the biome’s temperature, downfall, colormap, and default color.
    • DryFoliageColor - A color resolver for biomes with dry foliage.
    • GameRules
      • getType - Gets the game rule type from its key.
      • keyCodec - Creates the codec for the key of a game rule type.
    • Level
      • isMoonVisible - Returns wehther the moon is currently visible in the sky.
      • getPushableEntities - Gets all entities except the specified target within the provided bounding box.
      • getClientLeafTintColor - Returns the color of the leaf tint at the specified location.
      • playPlayerSound - Plays a sound to the current player on the client.
    • LevelReader#getHeight - Returns the height of the map at the given position.
    • NaturalSpawner#INSCRIBED_SQUARE_SPAWN_DISTANCE_CHUNK - Provides the minimum distance that the player is close enough for spawning to occur.
  • net.minecraft.world.level.biome
    • Biome
      • getDryFoliageColor, getDryFoliageColorFromTexture - Gets the dry foliage color of the biome, either from the effects or from the climate settings.
    • BiomeSpecialEffects#getDryFoliageColorOverride, $Builder#dryFoliageColorOverride - Returns the default dry foliage color when not pulling from a colormap texture.
  • net.minecraft.world.level.block
    • BaseFireBlock#fireIgnite - Lights an entity on fire.
    • Block
      • UPDATE_SKIP_BLOCK_ENTITY_SIDEEFFECTS - A flag that skips all potential sideeffects when updating a block entity.
      • UPDATE_SKIP_ALL_SIDEEFFECTS - A flag that skips all sideeffects by skipping certain block entity logic, supressing drops, and updating the known shape.
      • UPDATE_SKIP_ON_PLACE - A flag that skips calling BlockState#onPlace when set.
    • BonemealableBlock#hasSpreadableNeighbourPos, findSpreadableNeighbourPos - Handles finding other positions that the vegetation can spread to on bonemeal.
    • CactusFlowerBlock - A flower that grows on a cactus.
    • FireflyBushBlock - A bush that spawns firefly particles around it.
    • SandBlock - A colored sand block that can play ambient sounds.
    • SegmentableBlock - A block that can typically be broken up into segments with unique sizes and placements.
    • ShortDryGrassBlock - A single grass block that has been dried out.
    • TallDryGrassBlock - A double grass block that has been dried out.
    • TerracottaBlock - A terracotta block that can play ambient sounds.
    • TintParticleLeavesBlock - A leaves block whose particles are tinted.
    • UntintedParticleLeavesBlock - A leaves block whose particles are not tinted.
    • VegetationBlock - A block that represents some sort of vegetation that can propogate light and need some sort of farmland or dirt to survive.
  • net.minecraft.world.level.block.entity.StructureBlockEntity#isStrict, setStrict - Sets strict mode when generating structures.
  • net.minecraft.world.level.block.sounds.AmbientDesertBlockSoundsPlayer - A helper to play sounds for a given block, typically during animateTick.
  • net.minecraft.world.level.block.state.BlockBehaviour#getEntityInsideCollisionShape - Gets the collision shape of the block when the entity is within it.
  • net.minecraft.world.level.border.WorldBorder
    • closestBorder - Returns a list of the closest borders to the player based on their horizontal direction.
    • $DistancePerDirection - A record containing the distance from the entity of the world border in a given direction.
  • net.minecraft.world.level.chunk.status.ChunkStatus#CODEC
  • net.minecraft.world.level.entity.PersistentEntitySectionManager#isTicking - Returns whether the specified chunk is currently ticking.
  • net.minecraft.world.level.levelgen.Heightmap$Types#STREAM_CODEC
  • net.minecraft.world.level.levelgen.feature
    • AbstractHugeMushroomFeature#placeMushroomBlock - Places a mushroom block that specified location, replacing a block if it can.
    • FallenTreeFeature - A feature that generates flane trees with a stump of given lengths.
    • TreeFeature#getLowestTrunkOrRootOfTree - Retruns the lowest block positions of the tree decorator.
  • net.minecraft.world.level.levelgen.feature.configurations.FallenTreeConfiguration - A configuration for fallen trees with stumps.
  • net.minecraft.world.level.levelgen.feature.treedecorators
    • AttachedToLogsDecorator - A decorator that attaches a random block to a given direction on a log with a set probability.
    • PlaceOnGroundDecorator - A decorator that places the tree on a valid block position.
  • net.minecraft.world.level.levelgen.structure.pools
    • ListPoolElement#getElements - Returns the elements of the structure pool.
    • SinglePoolElement#getTemplateLocation - Returns the location of the template used by the element.
    • StructureTemplatePool#getTemplates - Returns a list of elements with their weights.
  • net.minecraft.world.level.levelgen.structure.structures.JigsawStructure
    • getStartPool - Returns the starting pool of the jigsaw to generate.
    • getPoolAliases - Returns all pools used by the jigsaw.
  • net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate#getDefaultJointType - Returns the default join type between two jigsaw pieces if none is specified or an error occurs during loading.
  • net.minecraft.world.level.material.Fluid#getAABB, FluidState#getAABB - Returns the bounding box of the fluid.
  • net.minecraft.world.scores
    • Objective#pack, $Packed - Handles the serializable form of the objective data.
    • PlayerTeam#pack, $Packed - Handles the serializable form of the player team data.
    • Scoreboard
      • loadPlayerTeam, loadObjective - Loads the data from the packed object.
      • $PackedScore - Handles the serializable form of the scoreboard data.
  • net.minecraft.world.level.storage.loot.LootTable#KEY_CODEC
  • net.minecraft.world.phys
    • AABB$Builder - A builder for constructing a bounding box by providing the vectors within.
    • Vec2#CODEC
  • net.minecraft.world.phys.shapes.CollisionContext
    • placementContext - Constructs the context when placing a block from its item.
    • isPlacement - Returns whether the context is being used for placing a block.
  • net.minecraft.world.ticks.TickPriority#CODEC

List of Changes

  • net.minecraft.client.Screenshot is now a utility instead of an instance class, meaning all instance methods are removed
    • takeScreenshot(RenderTarget) -> takeScreenshot(RenderTarget, Consumer<NativeImage>), not returning anything
  • net.minecraft.client.multiplayer
    • ClientChunkCache#replaceWithPacketData now takes in a Map<Heightmap$Types, long[]> instead of a CompoundTag
    • MultiPlayerGameMode#hasInfiniteItems -> net.minecraft.world.entity.LivingEntity#hasInfiniteMaterials
    • ClientPacketListener#markMessageAsProcessed now takes in a MessageSignature instead of a PlayerChatMessage
  • net.minecraft.client.multiplayer.chat.ChatListener#handleChatMessageError now takes in a nullable MessageSignature
  • net.minecraft.client.player
    • ClientInput#leftImpulse, forwardImpulse -> moveVector, now protected
    • LocalPlayer#spinningEffectIntensity, oSpinningEffectIntensity -> portalEffectIntensity, oPortalEffectIntensity
  • net.minecraft.client.renderer.LevelRenderer#getLightColor(BlockAndTintGetter, BlockState, BlockPos) -> getLightColor(LevelRenderer$BrightnessGetter, BlockAndTintGetter, BlockState, BlockPos)
  • net.minecraft.client.renderer.blockentity.BlockEntityRenderer#render now takes in a Vec3 representing the camera’s position
  • net.minecraft.client.renderer.chunk.SectionRenderDispatcher
    • $RenderSection
      • getOrigin -> getRenderOrigin
      • reset is now public
      • releaseBuffers is removed
    • $CompileTask#getOrigin -> getRenderOrigin
  • net.minecraft.client.renderer.entity
    • DonkeyRenderer now takes in a DonekyRenderer$Type containing the textures, model layers, and equipment information
    • ItemEntityRenderer#renderMultipleFromCount now has an overload that takes in the model bounding box
    • UndeadHorseRenderer now takes in a UndeadHorseRenderer$Type containing the textures, model layers, and equipment information
  • net.minecraft.client.renderer.entity.layers
    • EquipmentLayerRenderer$TrimSpriteKey#textureId -> spriteId
    • VillagerProfessionLayer#getHatData now takes in a map of resource keys to metadata sections and swaps the registry and value for a holder instance
  • net.minecraft.client.renderer.item
    • ConditionalItemModel now takes in a ItemModelPropertyTest instead of a ConditionalItemModelProperty
    • SelectItemModel now takes in a $ModelSelector instead of an object map
  • net.minecraft.client.renderer.item.properties.conditional.ConditionalItemModelProperty now implements ItemModelPropertyTest
    • ItemModelPropertyTest holds the get method previously within ConditionalItemModelProperty
  • net.minecraft.commands.arguments
    • ComponentArgument
      • ERROR_INVALID_JSON -> ERROR_INVALID_COMPONENT
      • getComponent -> getRawComponent
    • ResourceKeyArgument#getRegistryKey is now public
    • StyleArgument#ERROR_INVALID_JSON -> ERROR_INVALID_STYLE
  • net.minecraft.commands.arguments.item
    • ComponentPredicateParser$Context#createComponentTest, createPredicateTest now takes in a Dynamic instead of a Tag
    • ItemPredicateArgument
      • $ComponentWrapper#decode now takes in a Dynamic instead of a RegistryOps, Tag pair
      • $PredicateWrapper#decode now takes in a Dynamic instead of a RegistryOps, Tag pair
  • net.minecraft.core
    • BlockMath
      • VANILLA_UV_TRANSFORM_LOCAL_TO_GLOBAL, VANILLA_UV_TRANSFORM_GLOBAL_TO_LOCAL is now private
      • getUVLockTransform -> getFaceTransformation
    • Direction#rotate now takes in a Matrix4fc instead of a Matrix4f
    • Rotations is now a record
  • net.minecraft.data.loot.BlockLootSubProvider#createPetalDrops -> createSegmentedBlockDrops
  • net.minecraft.network
    • FriendlyByteBuf
      • writeLongArray, readLongArray now have static delegates which take in the ByteBuf and *Fixed* versions for fixed size arrays
    • ProtocolInfo$Unbound -> $Details, net.minecraft.network.protocol.SimpleUnboundProtocol, net.minecraft.network.protocol.UnboundProtocol; not one-to-one
      • #bind -> net.minecraft.network.protocol.SimpleUnboundProtocol#bind, UnboundProtocol#bind; not one-to-one
    • SkipPacketException is now an interface instead of a subclass of EncoderException
  • net.minecraft.network.chat
    • ComponentSerialization#flatCodec -> flatRestrictedCodec
    • LastSeenMessages$Update now takes in a byte representing the checksum value
    • LastSeenMessagesValidator
      • applyOffset now returns nothing and can throw a $ValidationException
      • applyUpdate now returns the raw messages and can throw a $ValidationException
  • net.minecraft.network.codec.StreamCodec#composite now has an overload for nine parameters
  • net.minecraft.network.protocol.ProtocolInfoBuilder now takes in a third generic representing how to modify the provided codec.
    • addPacket now has an overload that takes in a CodecModifier
    • build -> buildUnbound, not one-to-one
    • protocol, serverboundProtocol, clientboundProtocol now returns a SimpleUnboundProtocol
  • net.minecraft.network.protocol.ConfigurationProtocols now contain SimpleUnboundProtocol constants
  • net.minecraft.network.protocol.game
    • ClientboundContainerSetContentPacket is now a record
    • ClientboundMoveEntityPacket#getyRot, getxRot -> getYRot, getXRot
    • ClientboundPlayerChatPacket now takes in a global index for the chat message
    • ClientboundLevelChunkPacketdata#getHeightmaps now returns a Map<Heightmap.Types, long[]>
    • ClientboundUpdateAdvancementsPacket now takes in a boolean representing whether to show the adavncements as a toast
    • GameProtocols constants are now either SimpleUnboundProtocols or UnboundProtocols
    • ServerboundContainerClickPacket is now a record
    • ServerboundMovePlayerPacket$Pos, $PosRot now has an overload that takes in a Vec3 for the position
    • ServerboundSetStructureBlockPacket now takes in an additional boolean representing whether the structure should be generated in strict mode
  • net.minecraft.network.protocol.handshake.HandshakeProtocols#SERVERBOUND_TEMPLATE is now a SimpleUnboundProtocol
  • net.minecraft.network.protocol.login.LoginProtocols#SERVERBOUND_TEMPLATE constants are now SimpleUnboundProtocols
  • net.minecraft.network.protocol.status.StatusProtocols#SERVERBOUND_TEMPLATE constants are now SimpleUnboundProtocols
  • net.minecraft.server.PlayerAdvancements#flushDirty now takes in a boolean that represents whether the advancements show display as a toast
  • net.minecraft.server.bossevents.CustomBossEvent
    • save -> pack, not one-to-one
    • load now takes in the id and the packed variant to unpack
  • net.minecraft.server.level
    • DistanceManager
      • hasPlayersNearby now returns a TriState
      • forEachBlockTickingChunks -> forEachEntityTickingChunk, not one-to-one
    • ServerEntity now takes in a consumer for broadcasting a packet to all players but those in the ignore list
    • ServerLevel
      • getForcedChunks -> getForceLoadedChunks
      • isPositionTickingWithEntitiesLoaded is now public
      • isNaturalSpawningAllowed -> canSpawnEntitiesInChunk, BlockPos variant is removed
    • ServerPlayer
      • getRespawnPosition, getRespawnAngle, getRespawnDimension, isRespawnForced -> getRespawnConfig, not one-to-one
      • setRespawnPosition now takes in a $RespawnConfig instead of the individual respawn information
      • loadAndSpawnParentVehicle, loadAndSpawnEnderpearls now takes in a CompoundTag without the optional wrapping\
  • net.minecraft.server.network.ServerGamePacketListenerImpl now implements GameProtocols$Context
  • net.minecraft.sounds.SoundEvents have the following sounds now Holder wrapped:
    • ITEM_BREAK
    • SHIELD_BLOCK, SHIELD_BREAK,
    • WOLF_ARMOR_BREAK
  • net.minecraft.util
    • Brightness
      • FULL_BRIGHT is now final
      • pack now has a static overload that takes in the block and sky light.
    • ExtraCodecs#MATRIX4f now is a Codec<Matrix4fc>
    • Util#makeEnumMap returns the Map superinstance rather than the specific EnumMap
  • net.minecraft.util.parsing.packrat.commands.TagParseRule now takes in a generic for the tag type
    • The construct is now public, taking in a DynamicOps
  • net.minecraft.util.profiling
    • ActiveProfiler now takes in a BooleanSupplier instead of a boolean
    • ContinuousProfiler now takes in a BooleanSupplier instead of a boolean
  • net.minecraft.util.worldupdate.WorldUpgrader now takes in the current WorldData
  • net.minecraft.world
    • BossEvent$BossBarColor, $BossBarOverlay now implements StringRepresentable
    • Container now implements Iterable<ItemStack>
  • net.minecraft.world.effect
    • MobEffect
      • getBlendDurationTicks -> getBlendInDurationTicks, getBlendOutDurationTicks, getBlendOutAdvanceTicks; not one-to-one
      • setBlendDuration now has an overload that takes in three integers to set the blend in, blend out, and blend out advance ticks
    • MobEffectInstance#tick -> tickServer, tickClient; not one-to-one
  • net.minecraft.world.entity
    • Entity
      • cancelLerp -> InterpolationHandler#cancel
      • lerpTo -> moveOrInterpolateTo
      • lerpTargetX, lerpTargetY, lerpTargetZ, lerpTargetXRot, lerpTargetYRot -> getInterpolation
      • onAboveBubbleCol -> onAboveBubbleColumn now takes in a BlockPos for the bubble column particles spawn location
        • Logic delegates to the protected static handleOnAboveBubbleColumn
      • isControlledByOrIsLocalPlayer -> isLocalInstanceAuthoritative, now final
      • isControlledByLocalInstance -> isLocalClientAuthoritative, now protected
      • isControlledByClient -> isClientAuthoritative
      • fallDistance, causeFallDamage is now a double
      • absMoveto -> absSnapTo
      • absRotateTo -> asbSnapRotationTo
      • moveTo -> snapTo
      • sendBubbleColumnParticles is now static, taking in the Level
      • onInsideBubbleColumn logic delegates to the protected static handleOnInsideBubbleColumn
    • EntityType
      • POTION -> SPLASH_POTION, LINGERING_POTION, not one-to-one
      • $EntityFactory#create can now return a null instance
    • ExperienceOrb#value -> DATA_VALUE
    • ItemBasedSteering no longer takes in the accessor for having a saddle
    • LivingEntity
      • lastHurtByPlayerTime -> lastHurtByPlayerMemoryTime
      • lerpSteps, lerpX, lerpY, lerpZ, lerpYRot, lerpXRot -> interpolation, not one-to-one
      • isAffectedByFluids is now public
      • removeEffectNoUpdate is now final
      • tickHeadTurn now returns nothing
      • canDisableShield -> canDisableBlocking, now set via the WEAPON data component
      • calculateFallDamage now takes in a double instead of a float
    • Mob
      • handDropChances, armorDropChances, bodyArmorDropChance -> dropChances, not one-to-one
      • getEquipmentDropChance -> getDropChances, not one-to-one
  • net.minecraft.world.entity.ai.Brain#addActivityWithConditions now has an overload that takes in an integer indiciating the starting priority
  • net.minecraft.world.entity.ai.behavior
    • LongJumpToRandomPos$PossibleJump is now a record
    • VillagerGoalPackages#get*Package now takes in a holder-wrapped profession
  • net.minecraft.world.entity.ai.gossip.GossipContainer#store, update -> clear, putAll, copy; not one-to-one
  • net.minecraft.world.entity.animal
    • Pig is now a VariantHolder
    • Sheep -> .sheep.Sheep
    • WaterAnimal#handleAirSupply now takes in a ServerLevel
  • net.minecraft.world.entity.animal.axolotl.Axolotl#handleAirSupply now takes in a ServerLevel
  • net.minecraft.world.entity.monster.ZombieVillager#setGossips now takes in a GossipContainer
  • net.minecraft.world.entity.monster.warden.WardenSpawnTracker now has an overload which sets the initial parameters to zero
  • net.minecraft.world.entity.npc
    • Villager now takes in either a key or a holder of the VillagerType
      • setGossips now takes in a GossipContainer
    • VillagerData is now a record
      • set* -> with*
    • VillagerProfession now takes in a Component for the name
    • VillagerTrades
      • TRADES now takes in a resource key as the key of the map
        • This is similar for all other type specific trades
      • $FailureItemListing is now private
  • net.minecraft.world.entity.player.Player
    • stopFallFlying -> LivingEntity#stopFallFlying
    • isSpectator, isCreative no longer abstract in the Player class
  • net.minecraft.world.entity.projectile.ThrownPotion -> AbstractThrownPotion, implemented in ThrownLingeringPotion and ThrownSplashPotion
  • net.minecraft.world.entity.raid.Raid(int, ServerLevel, BlockPos) -> Raid(BlockPos, Difficulty)
    • tick, addWaveMob now takes in the ServerLevel
  • net.minecraft.world.entity.vehicle
    • AbstractMinecart#setDisplayBlockState -> setCustomDisplayBlockState
    • MinecartBehavior
      • cancelLerp -> InterpolationHandler#cancel
      • lerpTargetX, lerpTargetY, lerpTargetZ, lerpTargetXRot, lerpTargetYRot -> getInterpolation
    • MinecartTNT#primeFuse now takes in the DamageSource cause
  • net.minecraft.world.inventory
    • AbstractContainerMenu
      • setRemoteSlotNoCopy -> setRemoteSlotUnsafe, not one-to-one
      • setRemoteCarried now takes in a HashedStack
    • ClickType now takes in an id for its representations
    • ContainerSynchronizer#sendInitialData now takes in a list of stacks rather than a NonNullList
  • net.minecraft.world.item
    • EitherHolder now takes in an Either instance rather than just an Optional holder and ResourceKey
    • Item
      • canAttackBlock -> canDestroyBlock
      • hurtEnemy no longer returns anything
      • onCraftedBy no longer takes in a separate Level instance, now relying on the one provided by the Player
    • ItemStack
      • validateStrict is now public
      • onCraftedBy no longer takes in a separate Level instance, now relying on the one provided by the Player
    • MapItem
      • create now takes in a ServerLevel instead of a Level
      • lockMap is now private
    • ThrowablePotionItem is now abstract, containing two methods to create the AbstractThrownPotion entity
    • WrittenBookItem#resolveBookComponents -> WrittenBookContent#resolveForItem
  • net.minecraft.world.item.alchemy.PotionContents now implements TooltipProvider
    • forEachEffect, applyToLivingEntity now takes in a float representing a scalar for the duration
  • net.minecraft.world.item.component.WrittenBookContent now implements TooltipProvider
  • net.minecraft.world.item.crafting
    • SmithingRecipe#baseIngredient now returns an Ingredient
    • SmithingTransformRecipe now takes in a TransmuteResult instead of an ItemStack and an Ingredient for the base
    • SmithingTrimRecipe now takes in Ingredients instead of Optional wrapped entries along with a TrimPattern holder
    • TransmuteRecipe now takes in a TransmuteResult instead of an Item holder
  • net.minecraft.world.item.crafting.display.SlotDisplay$SmithingTrimDemoSlotDisplay now takes in a TrimPattern holder
  • net.minecraft.world.item.enchantment.EnchantmentInstance is now a record
  • net.minecraft.world.level
    • BlockGetter#boxTraverseBlocks -> forEachBlockIntersectedBetween, not one-to-one
    • CustomSpawner#tick no longer returns anything
    • GameRules$Type now takes in a value class
    • Level
      • onBlockStateChange -> updatePOIOnBlockStateChange
      • isDay -> isBrightOutside
      • isNight -> isDarkOutside
      • setMapData -> net.minecraft.server.level.ServerLevel#setMapData
      • getFreeMapId -> net.minecraft.server.level.ServerLevel#getFreeMapId
    • LevelAccessor#blockUpdated -> updateNeighborsAt
  • net.minecraft.world.level.biome.MobSpawnSettings$SpawnerData is now a record
  • net.minecraft.world.level.block
    • AttachedStemBlock now extends VegetationBlock
    • AzaleaBlock now extends VegetationBlock
    • Block#fallOn now takes a double for the fall damage instead of a float
    • BushBlock now extends VegetationBlock and implements BonemealableBlock
    • ColoredFallingBlock#dustColor is now protected
    • CropBlock now extends VegetationBlock
    • DeadBushBlock -> DryVegetationBlock
    • DoublePlantBlock now extends VegetationBlock
    • FallingBlock#getDustColor is now abstract
    • FlowerBedBlock now extends VegetationBlock
    • FlowerBlock now extends VegetationBlock
    • FungusBlock now extends VegetationBlock
    • LeafLitterBlock now extends VegetationBlock
    • LeavesBlock is now abstract, taking in the chance for a particle to spawn
      • Particles are spawned via spawnFallingLeavesParticle
    • MangroveLeavesBlock now extends TintedParticleLeavesBlock
    • MushroomBlock now extends VegetationBlock
    • NetherSproutsBlock now extends VegetationBlock
    • NetherWartBlock now extends VegetationBlock
    • ParticleLeavesBlock -> LeafLitterBlock
    • PinkPetalsBlock -> FlowerBedBlock
    • RootsBlock now extends VegetationBlock
    • Rotation now has an index used for syncing across the network
    • SaplingBlock now extends VegetationBlock
    • SeagrassBlock now extends VegetationBlock
    • SeaPickleBlock now extends VegetationBlock
    • StemBlock now extends VegetationBlock
    • SweetBerryBushBlock now extends VegetationBlock
    • TallGrassBlock now extends VegetationBlock
    • TntBlock#prime now returns whether the primed tnt was spawned.
    • WaterlilyBlock now extends VegetationBlock
  • net.minecraft.world.level.block.entity
    • BlockEntity
      • parseCustomNameSafe now takes in a nullable Tag instead of a string
      • getPosFromTag now takes in the ChunkPos
      • $ComponentHolder#COMPONENTS_CODEC is now a MapCodec
    • BLockEntityType#create is no longer nullable
  • net.minecraft.world.level.block.entity.trialspawner.TrialSpawner#codec now returns a MapCodec
  • net.minecraft.world.level.block.state.StateHolder
    • getNullableValue is now private
    • hasProperty no longer contains a generic
  • net.minecraft.world.level.chunk
    • ChunkAccess#setBlockState now takes in the block flags instead of a boolean, and has an overload to update all set
    • LevelChunk#replaceWithPacketData now takes in a Map<Heightmap$Types, long[]> instead of a CompoundTag
  • net.minecraft.world.level.chunk.storage.SerializableChunkData#getChunkTypeFromTag -> getChunkStatusFromTag, not one-to-one
  • net.minecraft.world.level.gameevent.vibrations.VibrationSystem#DEFAULT_VIBRATION_FREQUENCY -> NO_VIBRATION_FREQUENCY
  • net.minecraft.world.level.levelgen.feature.TreeFeature#isVine is now public
  • net.minecraft.world.level.levelgen.structure.pools.alias
    • Direct -> DirectPoolAlias
    • Random -> RandomPoolAlias
    • RandomGroup -> RandomGroupPoolAlias
  • net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate$JigsawBlockInfo now takes in a ResourceKey to the StructureTemplatePool instead of a raw ResourceLocation
  • net.minecraft.world.level.saveddata.maps.MapFrame is now a record
    • save, load -> CODEC, not one-to-one
  • net.minecraft.world.level.storage.loot.functions.SetWrittenBookPagesFunction#PAGE_CODEC -> WrittenBookContent#PAGES_CODEC
  • net.minecraft.world.scores
    • Score#write -> CODEC, not one-to-one
    • Scoreboard
      • savePlayerScores -> packPlayerScores, not one-to-one
      • loadPlayerScores -> loadPlayerScore, not one-to-one
    • Team$CollisionRule, $Visibility are now StringRepresentable
  • net.minecraft.world.phys.shapes.EntityCollisionContext now takes in a boolean representing if it is used for placing a block
  • net.minecraft.world.ticks.SavedTick
    • loadTick, saveTick, save -> codec, not one-to-one
    • loadTickList -> filterTickListForChunk, not one-to-one

List of Removals

  • com.mojang.blaze3d.vertex.BufferUploader
  • net.minecraft.core.Rotations#getWrapped*
  • net.minecraft.network.chat.ComponentSerialization#FLAT_CODEC
  • net.minecraft.network.protocol.game
    • ClientboundAddExperimentOrbPacket
    • ClientGamePacketListener#handleAddExperienceOrb
  • net.minecraft.resources.ResourceLocation$Serializer
  • net.minecraft.server.network.ServerGamePacketListenerImpl#addPendingMessage
  • net.minecraft.world
    • BossEvent$BossBarColor#byName, $BossBarOverlay#byName
    • Clearable#tryClear
  • net.minecraft.world.effect.MobEffectInstance#save, load
  • net.minecraft.world.entity
    • Entity
      • isInBubbleColumn
      • isInWaterRainOrBubble, isInWaterOrBubble
      • newDoubleList, newFloatList
      • recordMovementThroughBlocks
    • EntityEvent#ATTACK_BLOCKED, SHIELD_DISABLED
    • ItemBasedSteering
      • addAdditionalSaveData, readAdditionalSaveData
      • setSaddle, hasSadddle
    • LivingEntity
      • timeOffs, rotOffs
      • rotA
      • oRun, run
      • animStep, animStep0
      • appliedScale
      • canBeNameTagged
    • Mob
      • DEFAULT_EQUIPMENT_DROP_CHANCE
      • PRESERVE_ITEM_DROP_CHANCE_THRESHOLD, PRESERVE_ITEM_DROP_CHANCE
    • NeutralMob#setLastHurtByPlayer
    • PositionMoveRotation#ofEntityUsingLerpTarget
  • net.minecraft.world.entity.ai.attributes.AttributeModifier#save, load
  • net.minecraft.world.entity.animal
    • Dolphin#setTreasurePos, getTreasurePos
    • Fox$Variant#byName
    • MushroomCow$Variant#byName
    • Panda$Gene#byName
    • Salmon$Variant#byName
    • Turtle
      • getHomePos
      • setTravelPos, getTravelPos
      • isGoingHome, setGoingHome
      • isTravelling, setTravelling
  • net.minecraft.world.entity.animal.armadillo.Armadillo$ArmadilloState#fromName
  • net.minecraft.world.entity.npc.VillagerTrades#EXPERIMENTAL_WANDERING_TRADER_TRADES
  • net.minecraft.world.entity.projectile.AbstractArrow#getBaseDamage
  • net.minecraft.world.entity.raid.Raid
    • getLevel, getId
    • save
  • net.minecraft.world.entity.vehicle.AbstractMinecart#hasCustomDisplay, setCustomDisplay
  • net.minecraft.world.item.ItemStack#parseOptional, saveOptional
  • net.minecraft.world.item.equipment.trim.TrimPattern#templateItem
  • net.minecraft.world.level.Level#updateNeighborsAt(BlockPos, Block)
  • net.minecraft.world.level.block.entity
    • CampfireBlockEntity#dowse
    • PotDecorations#save, load
  • net.minecraft.world.level.levelgen.BelowZeroRetrogen#read
  • net.minecraft.world.level.levelgen.structure.structures.RuinedPortalPiece$VerticalPlacement#byName
  • net.minecraft.world.level.saveddata.maps.MapBanner#LIST_CODEC
  • net.minecraft.world.scores.Team
    • $CollisionRule#byName
    • $Visibility#getAllNames, byName
  • net.minecraft.world.ticks.LevelChunkTicks#save, load

Minecraft 1.21.5 -> 1.21.6 Mod Migration Primer

This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.5 to 1.21.6. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.

This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.

If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.

Thank you to:

  • @Soaryn for some ItemStack best practices and typo fixes
  • @earthcomputer for color changes when drawing strings

Pack Changes

There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.

GUI Changes

The GUI rendering system has significantly changed from the previous version. While it may seem somewhat similar on the surface, the actual implementation details are much more complex and roundabout. This will explain a high-level overview of the new system with some basic examples.

Prepare and Render

Rendering a GUI has been broken into two phases: ‘prepare’ and ‘render’.

The prepare phase is what we typically consider the GUI render methods (e.g., Gui#render, AbstractContainerScreen#renderBg, etc.). These methods, instead of actually rendering the components, now submit them to the GuiRenderState to be stored for use during the ‘render’ phase. The GuiRenderState is stored on the GameRenderer and passed to the GuiGraphics which uses the previous methods to add the desired objects to the render state.

The render phase is what actually handles the rendering of all the objects. This is handled through the GuiRenderer, which reads the data from the GuiRenderState and, after a bit of delegated preparation and sorting, renders the objects to the screen. The GuiRenderer is also stored on the GameRenderer.

Element Ordering

Now, how are elements rendered onto screen? In the previous versions, this happened mainly based on the order of the render calls. However, the new system using two different methods of sorting. The first method handles the depth using strata and a linear tree. The second method uses a comparator based on three things (in order of priorty): the ScreenRectangle scissor, the RenderPipeline order, and the TextureSetup’s hash code. These are all stored on the GuiElementRenderState passed to the GuiRenderState via GuiRenderState#submitGuiElement.

Once the elements have been ordered, they are rendered starting at a Z of 0, with each element rendered 0.01 ahead of the previous.

As a warning, due to the element sort order, certain custom configurations may result in incorrect screen renders. As such, it is imperative that you understand how the methods and their assigned values work when sorting elements.

Strata and Trees

The first method of sorting handles the z-depth an object is rendered at.

First let’s start with the linear tree. As the name implies, it is basically a doubly-linked GuiRenderState$Node list. Each node contains its own list of elements to render. Navigating the node list is handled using GuiRenderState#up or down, where each either gets the next node, or creates a new one if it doesn’t exist. Nodes within a given tree are rendered from bottom to top, meaning that down will render any elements submitted before the current node, while up will render any elements submitted after the current node.

Determining what node an object is added to is computed automatically when submitting an element using its ScreenArea. The ScreenArea defines the bounds of your element to be rendered. Essentially, a node will be added in the up direction if the bounds of the element intersect with any other element on the current node.

Then there are strata. A stratum is essentially a linear tree. Strata are rendered in the order they are created, which means calling nextStratum will render all elements after the previous stratum. This can be used if you want to group elements into a specific layer. Note: you cannot navigate to a prior stratum.

The Comparator

The comparator handles sorting the elements within a given node in a linear tree in a strata.

Screen Rectangle Scissor

The ScreenRectangle is simply the area that the element is allowed to draw to, stored via GuiElementRenderState#scissorArea. Elements with no specified ScreenRectangle will be ordered first, followed by the minimum Y, the maximum Y, the minimum X, and the maximum X.

Render Pipeline

RenderPipelines define the pipeline used to render some object to the screen, including its shaders, format, uniforms, etc. This is stored via GuiElementRenderState#pipeline. Pipelines are sorted in the order they are built. This means that RenderPipelines#ENTITY_TRANSLUCENT will be rendered before RenderPipelines#GUI if on the same layer and scissor rectangle. As this is a system that relies on classloading constants, if you want to add new elements, make sure your mod loader supports some kind of dynamic pipeline ordering.

Texture Hash Code

TextureSetup defines Sampler0, Sampler1, and Sampler2 for use in the render pipelines, stored via GuiElementRenderState#textureSetup. Elements with no textures will be ordered first, followed by getSortKey of the record object. Note that, at the moment, this returns the hashCode of the TextureSetup, which may be non-deterministic as GpuTextureView does not implement hashCode, relying instead on the identity object hash.

GuiElementRenderState

Now that we understand ordering, what exactly is the GuiElementRenderState that we’ve been using? Well essentially, every object rendered to the screen is represented by a GuiElementRenderState, from the player seen in the inventory menu to each individual item. A GuiElementRenderState defines four methods. First, there are the common ones used for ordering and how to render to the screen (pipeline, scissorArea, textureSetup, bounds). Then there is buildVertices, which takes in the VertexConsumer to write the vertices to and the z-depth. For GUIs, this typically calls VertexConsumer#addVertexWith2DPose.

There are three types of GuiElementRenderStates provided by vanilla: BlitRenderState, ColoredRectangleRenderState, GlyphEffectRenderState, and GlyphRenderState. ColoredRectangleRenderState and GlyphRenderState/GlyphEffectRenderState are simple cases for handling a basic color rectangle and text character, respectively. BlitRenderState covers every other case as almost every method eventually writes to a GpuTexture which is then consumed by this.

GuiElementRenderStates are added to the GuiRenderState via GuiRenderState$Node#submitGuiElement. The GuiRenderState makes submitBlitToCurrentLayer and submitGlyphToCurrentLayer available to add textures and glyphs. For example, these are called by GuiGraphics#*line, fill, and blit* methods.

GuiItemRenderState

GuiItemRenderState is a special case used to render an item to the screen. It takes in the stringified name of the item, the current pose, its XY coordinates, and its scissor area. The ItemStackRenderState it holds is what defines how the item is rendered. The rendering bounds are computed based on the item model bounding box when ClientItem$Properties#oversizedInGui is true; otherwise, using a 16x16 square when false.

Just before the ‘render’ phase, the GuiRenderer effectively turns the GuiItemRenderState into a GuiElementRenderState, more specifically a BlitRenderState. This is done by constructing an item atlas GpuTexture which the item is drawn to, and then that texture is submitted as a BlitRenderState. All GuiItemRenderStates use RenderPipelines#GUI_TEXTURED_PREMULTIPLIED_ALPHA.

GuiElementRenderStates are added to the GuiRenderState via GuiRenderState#submitItem. This is called by GuiGraphics#render*Item* methods.

GuiTextRenderState

GuiTextRenderState is a special case used to render text to the screen. It takes in the Font, FormattedCharSequence, current pose, its XY coordinates, color, background color, whether it has a drop shadow, and its rendering bounds.

Just before the ‘render’ phase, the GuiRenderer turns the GuiTextRenderState into a GuiElementRenderState, more specifically a GlyphRenderState or GlyphEffectRenderState depending on what should be rendered via GuiTextRenderState#ensurePrepared. This performs a similar process as the item render state where the text is written to a GpuTexture to be consumed. Any backgrounds are rendered first, followed by the background effects, then the character, then finally the foreground effects.

GuiElementRenderStates are added to the GuiRenderState via GuiRenderState#submitText. This is called by GuiGraphics#draw*String and render*Tooltip methods.

Picture-in-Picture

Picture-in-Picture is a special case used to render arbitrary objects to a GpuTexture to be passed into a BlitRenderState. A Picture-in-Picture is made up of two components the PictureInPictureRenderState, and the PictureInPictureRenderer.

PictureInPictureRenderState is an interface which can store some data used to render the object to the texture. By default, it must supply the minimum and maximum XY coordinates, the texture scale, its scissor area, and its rendering bounds. You can also choose to specify the transformation matrix via pose. Any other data can be added by the implementor.

public record ExamplePIPRenderState(boolean data, int x0, int x1, int y0, int y1, float scale, @Nullable ScreenRectangle scissorArea, @Nullable ScreenRectangle bounds)
    implements PictureInPictureRenderState {}

PictureInPictureRenderer is the renderer which writes the data to the GpuTexture. It does this by taking advantage of the fact that the RenderSystem#output*Override textures are written to in a BufferSource if they are not null. A PictureInPictureRenderer method must implement three methods. getRenderStateClass returns the class of the PictureInPictureRenderState implementation. getTextureLabel returns the texture label for debugging purposes. renderToTexture is where the render logic is called to write the data to the texture.

public class ExamplePIPRenderer extends PictureInPictureRenderer<ExamplePIPRenderState> {

    // Takes in the buffer source from `RenderBuffers`
    public ExamplePIPRenderer(MultiBufferSource.BufferSource bufferSource) {
        super(bufferSource);
    }

    @Override
    public Class<ExamplePIPRenderState> getRenderStateClass() {
        // The class of the render state
        return ExamplePIPRenderState.class;
    }

    @Override
    protected void renderToTexture(ExamplePIPRenderState renderState, PoseStack pose) {
        // Render whatever you want here
        // You can make use of the buffer source via `this.bufferSource`
    }

    @Override
    protected void blitTexture(ExamplePIPRenderState renderState, GuiRenderState guiState) {
        // You can override this if you want to change how your layer is submitted to the render state
        // By default, this uses the `BlitRenderState`

        // Remove this if you want to handle submission yourself
        super.blitTexture(renderState, guiState);
    }

    @Override
    protected boolean textureIsReadyToBlit(ExamplePIPRenderState renderState) {
        // When true, this will skip setting up the textures and projection matrices and use whatever is currently available
        return false;
    }

    @Override
    protected String getTextureLabel() {
        // This can be anything, but it should be unique
        return "examplemod: example pip";
    }
}

To be able to use the renderer, is must be added to GuiRenderer#pictureInPictureRenderers. As the constructor takes in an immutable list while the renderer stores an immutable map, use whatever method is provided by your mod loader.

// We will assume:
// - `GuiRenderer#bufferSource` is accessible
// - The map is made mutable
// For some GuiRenderer renderer

var examplePIP = new ExamplePIPRenderer(renderer.bufferSource);

renderer.pictureInPictureRenderers.put(
    examplePIP.getRenderStateClass(),
    examplePIP
);

PictureInPictureRenderStates are added to the GuiRenderState via GuiRenderState#submitPicturesInPictureState. This is called by GuiGraphics#submit*RenderState methods.

Logic Changes

GuiGraphics#drawString now joins the rest of the GuiGraphics methods by allowing the int color argument to accept an alpha channel (upper eight bits). This means that any color string without an alpha specified will not be rendered. Previous behavior can be replicated by ORing your int color with 0xFF000000 or by passing your color into ARGB#opaque.

Contextual Bars

Many HUD elements on the screen take over where the experience bar is rendered. However, how these are rendered and which one is prioritized is handled through the contextual bar system. A contextual bar is made up of two parts, the ContextualBarRenderer, responsible for rendering the bar to the screen, and the Gui$ContextualInfo, which is used as the bar’s identifier.

A ContextualBarRenderer requires two methods to be implemented: renderBackground, which renders the bar itself, and render, which renders elements that appear on top of the bar.

public class ExampleContextualBarRenderer implements ContextualBarRenderer {

    @Override
    public void renderBackground(GuiGraphics graphics, DeltaTracker delta) {
        // Render background bar sprites here
    }

    @Override
    public void render(GuiGraphics graphics, DeltaTracker delta) {
        // Render anything that might sit on top of the bar
    }
}

Gui$ContextInfo is an enum, so your mod loader will need to either allow extensions or some other method of identifying a bar renderer. Then, the renderer needs to be added to map of renderers stored in Gui#contextualInfoBarRenderers. As this is an immutable map, use whatever method is provided by your mod loader.

// We will assume:
// - Created a new enum value `EXAMPLEMOD_EXAMPLE`
// - The map is made mutable
// For some Gui gui
gui.contextualInfoBarRenderers.put(
    EXAMPLEMOD_EXAMPLE,
    ExampleContextualBarRenderer::new
);

Finally, to get your bar to be called and prioritized, you need to modify Gui#nextContextualInfoState to return your enum value, or whatever method is provided by your mod loader.

Dialogs

To more generally handle screens which provide some basic functionalities – such as confirmation screens, button selection, or user input, Vanilla has provided a generic dialog system. These dialogs can be constructed in a datapack and delivered on the client by calling Player#openDialog. The basic JSON description is documented in Minecraft Snapshot 25w20a.

For a quick overview, a basic Dialog contains the following components: a title, an optional external title for navigation, whether the screen can be closed by pressing ‘esc’, and its DialogBody contents. Everything else is determined by the dialog itself, but it has functionality for user inputs via InputControls. Buttons are typically added through ClickActions which hold the common button data and an event to execute on click. If the dialog is canceled (e.g., closed), then onCancel is run.

DialogBody and InputControl are simply generic interfaces that have no defined structure. Implementing them, or any dialog for that matter, requires some registration to the available types on both the client and server.

Custom Bodies

A DialogBody is simply the contents of a dialog screen. This is generally immutable information that should be displayed at all times. Every dialog holds a list of these DialogBodys as every screen has some text to explain what it is for. It only contains one method mapCodec, which is used as the registry key and encoder for the body information.

// Obviously, a body would have actual contents, but this is simply an example implementation
public record ExampleDialogBody(boolean val1, int val2) implements DialogBody {
    public static final MapCodec<ExampleDialogBody> BODY_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
        Codec.BOOL.fieldOf("val1").forGetter(ExampleDialogBody::val1),
        Codec.INT.fieldOf("val2").forGetter(ExampleDialogBody::val2)
    ).apply(ExampleDialogBody::new));

    @Override
    public MapCodec<? extends DialogBody> mapCodec() {
        return BODY_CODEC;
    }
}

// Register the codec to the registry
Registry.register(BuiltInRegistries.DIALOG_BODY_TYPE, "examplemod:example_body", ExampleDialogBody.BODY_CODEC);
// For some dialog
{
    // ...
    "body": [
        {
            // Our body
            "type": "examplemod:example_body",
            "val1": true,
            "val2": 0
        },
        // ...
    ]
}

How does this body actually render then? Well, that is done via a DialogBodyHandler. This contains a single method createControls that generates the LayoutElement to render given the DialogScreen and the dialog data. This body handler can be linked to the MapCodec via DialogBodyHandlers#register.

public class ExampleDialogBodyHandler implements DialogBodyHandler<ExampleDialogBody> {

    @Override
    public LayoutElement createControls(DialogScreen<?> screen, ExampleDialogBody body) {
        // Create the element (widgets, layouts, etc.)
        return new StringWidget(...);
    }
}

// Note that `register` is not public, so this needs to be access widened
DialogBodyHandlers.register(BODY_CODEC, new ExampleDialogBodyHandler());

Custom Inputs

An InputControl represents some input a user can provide, whether that would be some text or a button submission click. This is generally made up of components that can accept or provide some string value or tag based on a state. All dialogs can provide these inputs; through the DialogControlSet. It only contains one method mapCodec, which is used as the registry key and encoder for the input control.

public record ExampleInputControl(int value) implements InputControl {
    public static final MapCodec<ExampleInputControl> INPUT_CODEC = Codec.INT.fieldOf("value").xmap(
        ExampleInputControl::new, ExampleInputControl::value
    );

    @Override
    public MapCodec<? extends InputControl> mapCodec() {
        return INPUT_CODEC;
    }
}

// Register the codec to the registry
Registry.register(BuiltInRegistries.INPUT_CONTROL_TYPE, "examplemod:example_input", ExampleInputControl.INPUT_CODEC);
// For some dialog (assume `minecraft:simple_input_form`)
{
    "inputs": [
        {
            // Our input
            "type": "examplemod:example_input",
            
            // The identifier for the data of this input
            "key": "example_input",

            "value": 0
        },
        // ...
    ]
}

Like above, the input is rendered via a InputControlHandler. This contains a single method addControl, which provides the Screen and input control and creates the LayoutElement and its associated Action$ValueGetter via $Output. This input handler can be linked to the MapCodec via InputControlHandlers#register.

public class ExampleInputControlHandler implements InputControlHandler<ExampleInputControl> {

    @Override
    public void addControl(ExampleInputControl control, Screen screen, InputControlHandler.Output output) {
        EditBox box = new EditBox(...);
        box.setValue(String.valueOf(control.value()));

        // Add the elements to the output
        output.accept(
            // The element to render
            box,
            // The value output of the input
            Action.ValueGetter.of(box::getValue)
        );
    }
}

// Note that `register` is not public, so this needs to be access widened
InputControlHandlers.register(INPUT_CODEC, new ExampleInputControlHandler());

Custom Actions

As shown above, an input can provide some value to pass to an Action. The former is known as a $ValueGetter, which essentially gets a stringified or tagged input to use. The latter, meanwhile, ends up creating the ClickEvent that is sent to the server. These are typically created through ActionButtons which defines some common button data along with the Action to perform.

A custom action contains two methods: one which returns the MapCodec (codec) to use during encoding, while the other creates the ClickEvent based on the map of input strings to their $ValueGetters.

public record ExampleAction() implements Action {
    public static final MapCodec<ExampleAction> ACTION_CODEC = MapCodec.unit(new ExampleAction());

    @Override
    public MapCodec<? extends Action> codec() {
        return ACTION_CODEC;
    }

    @Override
    public Optional<ClickEvent> createAction(Map<String, Action.ValueGetter> keysToGetters) {
        // Handle how you want to map the key input map to some click event
        return Optional.empty();
    }
}

// Register the codec to the registry
Registry.register(BuiltInRegistries.DIALOG_ACTION_TYPE, "examplemod:example_action", ExampleAction.ACTION_CODEC);
// For some dialog (assume `minecraft:notice`)
{
    "action": {
        // Button data
        "label": "Example!",
        "tooltip": "This is an example!",
        "width": 80,

        // The action to perform
        "action": {
            // Out action type
            "type": "examplemod:example_action"
        }
    }
}

Depending on how you implement your Dialog below, the action button will automatically be added to the screen, or you will need to add it in one of the methods via DialogControlSet#createActionButton:

// For some DialogScreen implementation, we will assume some `SimpleDialog`
@Override
protected void updateHeaderAndFooter(HeaderAndFooterLayout layout, DialogControlSet controls, SimpleDialog dialog, DialogConnectionAccess access) {
    dialog.mainActions().forEach(actionButton -> layout.addToFooter(controls.createActionButton(actionButton).build()));
}

Custom Dialogs

A Dialog is pretty much all of the above components put together as desired. It is up to the user to choose how to implement them. Every Dialog must provide its CommonDialogData, which defines the basic title, body contents, and functionality. In additional, a Dialog may choose to execute an Action on close via onCancel.

// `common` is already implemented by the record
public record ExampleDialog(CommonDialogData common, boolean val1, int val2) implements Dialog {
    public static final MapCodec<ExampleDialog> DIALOG_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
        CommonDialogData.MAP_CODEC.forGetter(ExampleDialog::common),
        Codec.BOOL.fieldOf("val1").forGetter(ExampleDialog::val1),
        Codec.INT.fieldOf("val2").forGetter(ExampleDialog::val2)
    ).apply(ExampleDialog::new));

    @Override
    public MapCodec<? extends Dialog> codec() {
        return DIALOG_CODEC;
    }

    @Override
    public Optional<Action> onCancel() {
        // You can choose to return something here, or empty if nothing should be done
        return Optional.empty();
    }
}

// Register the codec to the registry
Registry.register(BuiltInRegistries.DIALOG_TYPE, "examplemod:example_dialog", ExampleDialog.DIALOG_CODEC);
// For some dialog in `data/examplemod/dialog/example.json`
{
    // Our dialog type
    "type": "examplemod:example_dialog",
    
    // Common button data
    "title": "Example dialog!",
    "can_close_with_escape": true,
    "after_action": "wait_for_response",

    // Our custom params
    "val1": true,
    "val2": 0
}

Like the others, a dialog type can only be rendered through a DialogScreen$Factory. This interface constructs a DialogScreen given the parent Screen, Dialog instance, and DialogConnectionAccess used to communicate to the server. This dialog screen can then be linked to the MapCodec via DialogScreens#register.

public class ExampleDialogScreen extends DialogScreen<ExampleDialog> {

    public ExampleDialogScreen(@Nullable Screen previousScreen, ExampleDialog dialog, DialogConnectionAccess connectionAccess) {
        super(previousScreen, dialog, connectionAccess);
    }

    // You can choose to implement the other methods as you wish
    // See existing dialog screens for an example

    @Override
    protected void populateBodyElements(LinearLayout layout, DialogControlSet controls, ExampleDialog dialog, DialogConnectionAccess access) {
        // Add elements and actions to the body of the screen (usually the center)
    }

    @Override
    protected void updateHeaderAndFooter(HeaderAndFooterLayout layout, DialogControlSet controls, ExampleDialog dialog, DialogConnectionAccess access) {
        // Add elements and actions to the header and footer of the screen (top and bottom)
    }
}

// Note that `register` is not public, so this needs to be access widened
DialogScreens.register(DIALOG_CODEC, ExampleDialogScreen::new);
  • com.mojang.blaze3d.vertex.VertexConsumer#addVertexWith2DPose - Adds a vertex to be rendered in 2d space.
  • net.minecraft.client.gui
    • Font
      • drawInBatch no longer returns anything
      • prepareText - Prepares the text to be rendered to the screen.
      • splitIgnoringLanguage - Splits the text in the order provided without being processed by the language handler.
      • ALPHA_CUTOFF is removed
      • $GlyphVisitor - An interface that handles a glyph or effect to be rendered.
      • $PreparedText - An interface that defines how a piece of text should be rendered by visiting each glyph.
      • $StringRenderOutput -> $PreparedTextBuilder, no longer takes in the MultiBufferSource, Matrix4f, $DisplayMode, packed light coords, and the inverse depth boolean
    • Gui
      • shouldRenderDebugCrosshair - Returns true if the debug crosshair should be rendered.
      • $RenderFunction - An interface that defines how a certain section or element is rendered on the gui.
    • GuiGraphics now takes in a GuiRenderState instead of the MultiBufferSource$BufferSource
      • MAX_GUI_Z, MIN_GUI_Z are removed
      • pose now returns a Matrix3x2fStack
      • flush is removed
      • nextStratum - Adds another layer to traverse through that renders after all nodes in the previous tree.
      • All methods no longer take in a RenderType, VertexConsumer, or Function<ResourceLocation, RenderType>, instead specifying a RenderPipeline and a TextureSetup depending on the call
      • drawString, drawStringWithBackdrop no longer returns anything
      • draw*String methods must now pass in an ARGB value, where A cannot be 0.
      • renderItem(ItemStack, int, int, int, int) is removed
      • drawSpecial is removed, replaced by individual submit*RenderState depending on the special case
      • blurBeforeThisStratum - Notifies the render state that a blur effect should render between this strata and all previously rendered ones. This can only be applied between once per frame.
      • render*Tooltip -> set*TooltipForNextFrame, does not directly add to the render state, instead waiting for renderDeferredTooltip to be called when not present or overridden
      • renderDeferredTooltip - Adds the tooltip information to be rendered on a new stratum.
      • blitSprite now has an overload that takes in a float R tint color
      • $ScissorStack#peek - Gets the last rectangle on the stack.
    • LayeredDraw class is removed
  • net.minecraft.client.gui.components
    • AbstractTextAreaWidget now has an overload which takes in two additional booleans of whether to show the background or decorations
    • AbstractWidget#getTooltip is removed
    • CycleButton$Builder#displayOnlyValue now has an overload that takes in the boolean to set
    • EditBox
      • setCentered - Sets whether the text position should be centered.
      • setTextShadow - Sets whether the text should have a drop shadow effect.
    • FocusableTextWidget can now take in a boolean indicating whether to fill the background
      • DEFAULT_PADDING is now public
    • ImageWidget#updateResource - Updates the sprite of the image on the component.
    • ItemDisplayWidget - A widget that displays an ItemStack.
    • LogoRenderer#keepLogoThroughFade - When true, keeps the logo visible even when the title screen is fading.
    • MultiLineEditBox is now package private and should be constructed via builder, calling the $Builder#set* methods
      • setLineLimit - Sets the line limit of the text field.
      • setValue now has an overload that takes in the boolean to determine whether it should force pass the max line limit
    • MultiLineLabel
      • getStyleAtCentered - Computes the component style for centered text.
      • getStyleAtLeftAligned - Computes the component style for left aligned text.
    • MultilineTextField#NO_CHARACTER_LIMIT -> NO_LIMIT
      • setLineLimit - Sets the maximum number of lines that can be written on the text field.
      • hasLineLimit - Returns whether the text field has some line limit.
      • setValue now has an overload that takes in the boolean to determine whether it should force pass the max line limit
    • MultiLineTextWidget#configureStyleHandling - Sets whether something is displayed when hovering over components and what to do on click.
    • ScrollableLayout - A layout with some defined bounds that can be scrolled through.
    • SplashRenderer#render now takes in a float for the R color instead of an int
    • WidgetTooltipHolder#refreshTooltipForNextRenderPass now takes in the GuiGraphics and the XY position
  • net.minecraft.client.gui.components.spectator.SpectatorGui#renderTooltip -> renderAction
  • net.minecraft.client.gui.components.tabs
    • LoadingTab - A tab that indicates information is currently being loaded.
    • Tab#getTabExtraNarration - Returns the hint narration of the tab.
    • TabManager can now take in two Consumers on what to do when a tab is selected or deselected
    • TabNavigationBar
      • getTabs - Returns the list of tabs on the navigation bar.
      • setTabActiveState - Sets the active state of the given tab index.
      • setTabTooltip - Sets the tooltip information of the given tab index.
  • net.minecraft.client.gui.components.toasts
    • NowPlayingToast - A toast that displays the currently playing background music.
    • Toast
      • xPos, yPos - Gets the x and y position in relation to the current toast index.
      • onFinishedRendering - A method called once the toast has finished rendered on screen.
    • ToastManager now takes in the Options
      • showNowPlayingToast, hideNowPlayingToast, createNowPlayingToast, removeNowPlayingToast - Handles the ‘Now Playing’ music toast.
      • $ToastInstance#resetToast - Resets the toast.
  • net.minecraft.client.gui.contextualbar
    • ContextualBarRenderer - An interface which defines an object with some background to render.
    • ExperienceBarRenderer - Draws the experience bar.
    • JumpableVehicleBarRenderer - Draws the jump power bar (e.g. horse jumping).
    • LocatorBarRenderer - Draws the bar that points to given waypoints.
  • net.minecraft.client.gui.font.GlyphRenderTypes now takes in a RenderPipeline for the gui rendering
  • net.minecraft.client.gui.font.glyphs.BakedGlyph now takes in a GpuTextureView
    • extractEffect - Extracts a glyph effect (e.g. drop shadow) submits the element to be rendered.
    • extractBackground - Extracts a glyph effect and submits the element to be rendered on the background Z.
    • left, top, right, bottom - Computes the bounds of the glyph.
    • textureView - Returns the view of the texture making up the glyph.
    • guiPipeline - Returns the pipeline to render the glyph.
    • renderChar, renderEffect now takes in an additional boolean that sets the Z offset to 0 when true and 0.001 when false
    • $Effect#left, top, right, bottom - Computes the bounds of the glyph effect.
    • $GlyphInstance#left, top, right, bottom - Computes the bounds of the glyph instance.
  • net.minecraft.client.gui.navigation.ScreenRectangle
    • transformAxisAligned now takes in a Matrix3x2f instead of a Matrix4f
    • intersects - Returns whether this rectangle overlaps with another rectangle.
    • encompasses - Returns whether this rectangle contains the entirety of another rectangle.
    • transformMaxBounds - Returns a new rectangle that is moved into a given position by the provided matrix.
  • net.minecraft.client.gui.render
    • GuiRenderer - A class that renders all submitted elements to the screen.
    • TextureSetup - A record that specifies samplers 0-2 for use in a render pipeline. The first two textures views are arbitrary with the third being for the current lightmap texture.
  • net.minecraft.client.gui.render.pip
    • GuiBannerResultRenderer - A renderer for the banner result preview.
    • GuiBookModelRenderer - A renderer for the book model in the enchantment screen.
    • GuiEntityRenderer - A renderer for a given entity.
    • GuiProfilerChartRenderer - A renderer for the profiler chart.
    • GuiSignRenderer - A renderer for the sign background in the edit screen.
    • GuiSkinRenderer - A renderer for a player with a given skin.
    • OversizedItemRenderer - A rendered for when an item model should be rendered larger than its item slot.
    • PictureInPictureRenderer - An abstract class meant for rendering dynamic elements that are not standard 2d elements, items, or text.
  • net.minecraft.client.gui.render.state
    • BlitRenderState - An element state for a basic 2d texture blit.
    • ColoredRectangleRenderState - An element state for a simple rectangle with a tint.
    • GlyphEffectRenderState - An element state for a glyph effect (e.g., font text drop shadow).
    • GlyphRenderState - An element state for a glyph (font text).
    • GuiElementRenderState - An interface representing the state of a element to render.
    • GuiItemRenderState - A record representing the state of an item to render.
    • GuiRenderState - The state of the GUI to render to the screen.
    • GuiTextRenderState - A record representing the state of the text and its location to render.
    • ScreenArea - An interface which defines the render area of an element. This does not affect scissoring, instead layer orders.
  • net.minecraft.client.gui.render.state.pip
    • GuiBannerResultRenderState - The state of the banner result preview.
    • GuiBookModelRenderState - The state of the book model in the enchantment screen.
    • GuiEntityRenderState - The state of a given entity.
    • GuiProfilerChartRenderState - The state of the profiler chart.
    • GuiSignRenderState - The state of the sign background in the edit screen.
    • GuiSkinRenderState - The state of a player with a given skin.
    • OversizedItemRenderState - The state of an item model that can be rendered at an arbitrary size.
    • PictureInPictureRenderState - An interfaces that defines the basic state necessary to render the picture-in-picture to the screen.
  • net.minecraft.client.gui.screens
    • ConfirmScreen
      • layout - Defines a vertical list of elements spaced by eight units.
      • yesButton, noButton -> yesButtonComponent, noButtonComponent
        • yesButton, noButton now represent the actual buttons
      • addAdditionalText - Adds any additional text before the buttons in the layout.
      • addButtons - Adds the buttons in the layout.
    • PauseScreen
      • rendersNowPlayingToast - Returns whether the ‘Now Playing’ toast should be rendered.
      • onDisconnect -> disconnectFromWorld, now public and static; not one-to-one
    • Screen
      • CUBE_MAP -> net.minecraft.client.renderer.GameRenderer#cubeMap
      • PANORAMA -> net.minecraft.client.renderer.GameRenderer#panorama
      • renderBlurredBackground now takes in the GuiGraphics
      • *TooltipForNextRenderPass methods are either removed or moved to GuiGraphics
      • FADE_IN_TIME - Represents how much time in milliseconds does it take for some element to fade in.
      • fadeWidgets - Sets the alpha of the AbstractWidgets added as children to the screen.
      • handleClickEvent - Handles the event to play when the component is clicked.
      • defaultHandleClickEvent - The default logic to execute when the component is clicked.
      • clickUrlAction - The logic to perform when a URL is clicked (has the Open URL style).
      • clickCommandAction - The logic to perform when a command should be executed (has the * Command style).
  • net.minecraft.client.gui.screens.dialog
    • ButtonListDialogScreen - A dialog screen that contains some list of buttons.
    • DialogConnectionAccess - A client side interface that processes general interaction information from the dialog.
    • DialogControlSet - An input handler for a dialog screen.
    • DialogListDialogScreen - A button list of DialogListDialogs.
    • DialogScreen - A screen for some dialog modal.
    • DialogScreens - A factory registry of dialog modals to their associated screen.
    • MultiButtonDialogScreen - A button list of MultiActionDialogs.
    • ServerLinksDialogScreen - A button list of ServerLinksDialogs.
    • SimpleDialogScreen - A dialog screen for some simple dialog.
    • WaitingForResponseScreen - A screen that handles the downtime between client/server communication of dialog submissions.
  • net.minecraft.client.gui.screens.dialog.body
    • DialogBodyHandler - A list of body elements describing the contents between the title and actions/inputs.
    • DialogBodyHandlers - A registry of DialogBodys to their DialogBodyHandlers.
  • net.minecraft.client.gui.screens.dialog.input
    • InputControlHandler - A user input handler.
    • InputControlHandlers- A registry of InputControls to their InputControlHandlers.
  • net.minecraft.client.gui.screens.inventory
    • AbstractContainerScreen
      • SLOT_ITEM_BLIT_OFFSET is removed
      • renderContents - Renders the slot and labels of an inventory.
      • renderCarriedItem - Renders the held item.
      • renderSnapbackItem - Renders the swapped item with the held item.
      • $SnapbackData - Holds the information about the dragging or swapped item as it moves from the held location to its slot location.
    • AbstractSignEditScreen#offsetSign -> getSignYOffset, not one-to-one
    • BookEditScreen
      • TEXT_*, IMAGE_*, BACKGROUND_TEXTURE_* are now public
    • BookSignScreen - A screen for signing a book.
    • BookViewScreen
      • closeScreen -> closeContainerOnServer, not one-to-one
      • $BookAccess#getPage now returns a Component
    • EffectsInInventory
      • renderEffects is now public
      • renderTooltip has been overloaded to a public method
    • InventoryScreen#renderEntityInInventory no longer takes in the XY offset, instead taking in 4 ints to represent the region to render to
    • ItemCombinerScreen#renderFg is removed
  • net.minecraft.client.gui.screens.inventory.tooltip
    • ClientTooltipComponent#renderText no longer takes in the pose and buffer, instead the GuiGraphics to submit the text for rendering
    • TooltipRenderUtil#renderTooltipBackground no longer takes in a Z offset
  • net.minecraft.client.gui.screens.multiplayer.ServerLinksScreen class is removed, replaced by dialog modal
  • net.minecraft.client.gui.screens.social
    • PlayerEntry#refreshHasDraftReport - Sets whether the current context as a report for this player.
    • SocialInteractionsPlayerList#refreshHasDraftReport - Refreshes whether the current context as a report for all players.
  • net.minecraft.client.gui.screens.worldselection.ExperimentsScreen$ScrollArea class is removed, replaced by the ScrollableLayout
  • net.minecraft.client.model.geom.ModelPart#getExtentsForGui - Gets the set of vectors representing the part transformed into their appropriate space.
  • net.minecraft.client.multiplayer.ClientCommonPacketListenerImpl
    • showDialog - Shows the current dialog, creating the screen dynamically.
    • serverLinks - Returns the entries of server links the client can access.
    • createDialogAccess - Creates the dialog handler on the client used for communication.
    • clearDialog - Closes the current dialog screen.
  • net.minecraft.client.player.LocalPlayer#experienceDisplayStartTick - Represents the start tick of when the experience display should be prioritized.
  • net.minecraft.client.renderer
    • GameRenderer no longer takes in a ResourceManager
      • ITEM_ACTIVATION_ANIMATION_LENGTH is removed
      • setRenderHand is removed
      • renderZoomed is removed
      • getPanorama - Returns the panorama renderer.
    • LightTexture#getTexture -> getTextureView, not one-to-one
    • MapRenderer#WIDTH, HEIGHT are now public
    • PanoramaRenderer#registerTextures - Registers the texture for use by the cube map.
    • PostPass$Input#texture now returns a GpuTextureView instead of a GpuTexture
    • RenderPipelines
      • GUI_OVERLAY, GUI_GHOST_RECIPE_OVERLAY, GUI_TEXTURED_OVERLAY are removed
      • GUI_TEXTURED_PREMULTIPLIED_ALPHA - A pipeline that assumes the textures have already had their transparency premultiplied during the composite stage.
    • RenderStateShard
      • $Builder#add no longer takes in whether the shard should be blurred
      • $TextureStateShard no longer takes in a TriState to set the blur mode
    • RenderType
      • debugLine is removed
      • gui, guiOverlay, guiTexturedOverlay, guiOpaqueTexturedBackground, guiNauseaOverlay, guiTextHighlight, guiGhostRecipeOverlay, guiTextured are removed
      • vignette is removed
      • crosshair is removed
      • mojangLogo is removed
    • ScreenEffectRenderer is now an instance implementation instead of simply a static method
      • The constructor takes in the current Minecraft instance and a MultiBufferSource
      • renderScreenEffect is now an instance method, taking in whether the entity is sleeping and the partial tick
      • resetItemActivation, displayItemActivation - Handles when an item is automatically activated (e.g., totem).
  • net.minecraft.client.renderer.blockentity
    • *Renderer#getExtents - Adds the transformed vectors representing all models to a set.
    • HangingSignRenderer
      • MODEL_RENDER_SCALE is now public
      • translateBase is now public
    • SignRenderer
      • RENDER_SCALE is now public
      • applyInHandTransforms - Transforms the stack to properly represent the held sign’s position.
    • SkullBlockRenderer#getRenderType(SkullBlock$Type, ResolvableProfile, ResourceLocation) -> getSkullRenderType, getPlayerSkinRenderType; not one-to-one
  • net.minecraft.client.renderer.entity.ItemRenderer
    • GUI_SLOT_CENTER_X, GUI_SLOT_CENTER_Y, ITEM_DECORATION_BLIT_OFFSET are removed
    • COMPASS_* -> SPECIAL_*
  • net.minecraft.client.renderer.item
    • ClientItem$Properties#oversizedInGui - When true, allows an item to render outside the 16x16 box in a GUI; otherwise, clips the size to the box.
    • ItemStackRenderState
      • setAnimated, isAnimated - Returns whether the item is animated (e.g., foil).
      • appendModelIdentityElement, getModelIdentity, clearModelIdentity - Handles the identity component being rendered.
      • getModelBoundingBox - Computes the bounding box of the model.
      • setOversizedInGui, isOversizedInGui - Handles when the item can be oversized in the GUI based on its property.
  • net.minecraft.client.renderer.special
    • PlayerHeadSpecialRenderer - Renders an player head based on its render info.
    • SkullSpecialRenderer now implements NoDataSpecialModelRenderer, no longer taking in the model or texture override, instead just the RenderType to use
    • SpecialModelRenderer#getExtents - Adds the transformed vectors representing all models used by this renderer to a set.
  • net.minecraft.client.renderer.texture.TextureAtlasSprite#isAnimated - Returns whether the sprite has any animation.
  • net.minecraft.commands.arguments.ResourceOrIdArgument#dialog, getDialog, $DialogArgument - Handles command arguments for dialog screens.
  • net.minecraft.core.registries
    • BuiltInRegistries#DIALOG_TYPE, DIALOG_ACTION_TYPE, INPUT_CONTROL_TYPE, DIALOG_BODY_TYPE
    • Registries#DIALOG_TYPE, DIALOG_ACTION_TYPE, INPUT_CONTROL_TYPE, DIALOG_BODY_TYPE, DIALOG
  • net.minecraft.data.tags.DialogTagsProvider - A tags provider for dialogs.
  • net.minecraft.network.chat
    • ClientEvent
      • $Action#SHOW_DIALOG, CUSTOM
        • valueCodec - Returns the map codec used to encode this action.
      • $Custom - An event that contains some nbt payload to send to the server, currently does nothing.
      • $ShowDialog - An event that shows the specified dialog.
    • CommonComponents
      • GUI_RETURN_TO_MENU - The component that displays the ‘Return to Menu’ text.
      • disconnectButtonLabel - Returns the component based on whether the server is local.
  • net.minecraft.network.protocol.common
    • ClientboundClearDialogPacket - Closes the current dialog screen.
    • ClientboundShowDialogPacket - Opens a new dialog screen.
    • ServerboundCustomClickActionPacket - Sends a custom action to the server.
  • net.minecraft.server.dialog
    • ActionButton - A button that can perform some Action on click.
    • ButtonListDialog - A dialog modal that has some number of columns to click buttons of.
    • CommonButtonData - The data that is associated with every button within a dialog modal.
    • CommonDialogData - The data that is associated with every dialog modal.
    • ConfirmationDialog - A dialog modal whether you can either click yes or no.
    • Dialog - The base interface that defines some dialog modal.
    • DialogAction - The action to perform typically after some action button is clicked.
    • DialogListDialog - A scrollable list of buttons that lead to other dialogs.
    • Dialogs - A datapack bootstrap registering Dialogs.
    • DialogTypes - A registry of map codecs to encode some dialog model.
    • Input - A handler that maps some key to an InputControl.
    • MultiActionDialog - A scrollable list of actions arrange in columns.
    • NoticeDialog - A simple screen with one action in the footer.
    • ServerLinksDialog - A scrollable list of links received from the server, arrange in columns.
    • SimpleDialog - A dialog that defines the main actions that can be taken.
  • net.minecraft.server.dialog.action
    • Action - A general operation to perform on some input, usually a button click.
    • ActionTypes - A registry of map codecs to encode some action.
    • CustomTemplate - Builds a command and requests the server to run it.
    • CustomAll - Builds a custom server click action from all inputs and requests the server to run it.
    • ParsedTemplate - A template that encodes some string similar to how function macros work.
    • StaticAction - An action that fires a ClickEvent on activation.
  • net.minecraft.server.dialog.body
    • DialogBody - A body element describing the content between the title and actions/inputs.
    • DialogBodyTypes - A registry of map codecs to encode some body.
    • ItemBody - An item with an optional description.
    • PlainMessage - A multiline label.
  • net.minecraft.server.dialog.input
    • BooleanInput - A plain checkbox with a label.
    • InputControl - A control mechanism to accept user input.
    • InputControlTypes - A registry of map codecs to encode some input control.
    • NumberRangeInput - A slider for picking a numeric value from some range.
    • SingleOptionInput - A button that cycles between a set of options.
    • TextInput - Simple text input.
  • net.minecraft.world.entity.player.Player#openDialog - Opens the specified dialog screen.

Waypoints

Waypoints are simply a method to track the position of some object in the game. The underlying system is handled by the WaypointManager, responsible for holding the waypoints it is tracking while also allowing updates and removals as necessary. The server handles waypoints through the ServerWaypointManager (obtained via ServerLevel#getWaypointManager), which holds an active connect to the transmitter to receive live updates. The client receives these waypoints via the ClientWaypointManager (obtained via ClientPacketListener#getWaypointManager), which simply holds some identifier along with an exact position, a chunk if the position is not within the view distance, or an angle if the distance is further than the stored Waypoint$Fade#farDist, which is over 332 blocks away by default.

Entities track waypoints by default.

Styles and Icons

Every waypoint is represents by an icon of some kind, which is defined by its WaypointStyle and the color of the icon. A WaypointStyle is similar to a client item or a equipment model, where it has some key pointed to by a WaypointStyleAsset that’s located in assets/<modid>/waypoint_style/<path>.json. This contains a list of sprites located within assets/<modid>/textures/gui/sprites/hud/locator_bar_dot/<path>.png which is chosen based upon the distance from the tracker. The sprites change between the range specified by the near and far distance.

// For some style examplemod:example_style
// It will be found in `assets/examplemod/waypoint_style/example_style.json`
{
    // Represents that any value closer will use the first sprite when rendering the bar
    // Defaults to 128 when not specified
    "near_distance": 100,
    // Represents that any value further will use the last sprite when rendering the bar
    // Defaults to 332 when not specified
    // Must be greater than near distance
    "far_distance": 400,
    // A non-empty list of textures relative to `assets/<modid>/textures/gui/sprites/hud/locator_bar_dot/<path>.png`
    // This is what's used to lerp between the two distances
    "sprites": [
        // Points to `assets/examplemod/textures/gui/sprites/hud/locator_bar_dot/example_style_0.png`
        "examplemod:example_style_0",
        "examplemod:example_style_1",
        "examplemod:example_style_2"
    ]
}

The icon can then be constructed using its constructor and referenced via WaypointTransmitter#waypointIcon or TrackedWaypoint#icon on the server or client, respectively.

// We will assume that this constructor is made public for a more dynamic usage
// Currently, it can only be set on a `LivingEntity` through its `CompoundTag` via `locator_bar_icon`
public static Waypoint.Icon EXAMPLE_ICON = new Waypoint.Icon(
    // The registry key of the waypoint style
    // Points to `assets/examplemod/waypoint_style/example_style.json`
    ResourceKey.create(WaypointStyleAssets.ROOT_ID, ResourceLocation.fromNamespaceAndPath("examplemod", "example_style")),
    // The color of the waypoint
    // When not present, uses the hashcode of the waypoint identifier
    Optional.of(0xFFFFFF)
);

Connections

Waypoints, when tracked, are managed through their connections via WaypointTransmitter$Connection. A connection is responsible for syncing information to the client, whether connecting, disconnecting, or updating.

public class ExampleBlockConnection implements WaypointTransmitter.Connection {

    private final BlockState state;
    private final BlockPos pos;
    private final Waypoint.Icon icon;
    private final ServerPlayer receiver;

    public ExampleBlockConnection(BlockState state, BlockPos pos, Waypoint.Icon icon, ServerPlayer receiver) {
        this.state = state;
        this.pos = pos;
        this.icon = icon;
        this.recevier = receiver;
    }

    public static boolean doesSourceIgnoreReceiver(BlockPos pos, ServerPlayer player) {
        double receiveRange = player.getAttributeValue(Attributes.WAYPOINT_RECEIVE_RANGE);
        return pos.distSqr(player.blockPosition()) >= receiveRange * receiveRange;
    }

    @Override
    public boolean isBroken() {
        // When true, it will attempt to remake the connection to this transmitter
        // This is only called when updating the position
        return ExampleBlockConnection.doesSourceIgnoreReceiver(this.pos, this.receiver);
    }

    @Override
    public void connect() {
        // This sends the tracking packet to the client
        this.receiver.connection.send(ClientboundTrackedWaypointPacket.addWaypointPosition(this.state.toString() + ": " + this.pos.toString(), this.icon, this.pos));
    }

    @Override
    public void disconnect() {
        // This sends the removal packet to the client
        this.receiver.connection.send(ClientboundTrackedWaypointPacket.removeWaypoint(this.state.toString() + ": " + this.pos.toString()));
    }

    @Override
    public void update() {
        // This updates the tracked value on the client assuming that the connect has not broken
        // In our case, we can assume this never changes as the position of a block should remain consistent
    }
}

Transmitters

A WaypointTransmitter is responsible for constructing the connection between it and the server. For your object to transmit a location, it must implement WaypointTransmitter and its three methods. waypointIcon simply returns the icon to display. isTransmittingWaypoint will determine whether the waypoint can be transmitted from this object. makeWaypointConnectionWith actually handles constructing the connection used to track the position or angle of the connection.

public class ExampleWaypointBlock extends BlockEntity implements WaypointTransmitter {

    // ...

    @Override
    public boolean isTransmittingWaypoint() {
        // This should return false if no connection should be made
        return true;
    }

    @Override
    public Optional<WaypointTransmitter.Connection> makeWaypointConnectionWith(ServerPlayer player) {
        // Make a connection if nothing is ignored
        return ExampleBlockConnection.doesSourceIgnoreReceiver(this.getBlockPos(), player)
            ? Optional.empty()
            : Optional.of(new ExampleBlockConnection(this.getBlockState(), this.getBlockPos(), this.waypointIcon(), player));
    }

    @Override
    public Waypoint.Icon waypointIcon() {
        return EXAMPLE_ICON;
    }
}

Then, all you need to do is track, update, or untrack the transmitter as necessary. This can be done using the methods provided by ServerWaypointManager:

// We will assume we have access to:
// - ServerLevel serverLevel
// - ExampleWaypointBlock be

// Tracking the waypoint, such as on some initialization
serverLevel.getWaypointManager().trackWaypoint(be);

// Update the waypoint if the position changes
serverLevel.getWaypointManager().updateWaypoint(be);

// Remove the waypoint once it no longer exists
serverLevel.getWaypointManager().untrackWaypoint(be);
  • net.minecraft.client
    • Camera now implements TrackedWaypoint$Camera
    • Minecraft#getWaypointStyles - Returns a manager of keys to the style of a waypoint.
  • net.minecraft.client.data.models.WaypointStyleProvider - A data provider that generates waypoint styles.
  • net.minecraft.client.multiplayer.ClientPacketListener#getWaypointManager - Gets the client manager used for tracking waypoints.
  • net.minecraft.client.renderer.GameRenderer now implements TrackedWaypoint$Projector
  • net.minecraft.client.resources
    • WaypointStyle - Defines the style used to render a waypoint.
    • WaypointStyleManager - The manager that maps some key to the style of a waypoint.
  • net.minecraft.client.waypoints.ClientWaypointManager - A client-side manager for tracked waypoints.
  • net.minecraft.commands.arguments.WaypointArgument - A static method holder that gets some waypoint transmitter from an entity.
  • net.minecraft.network.protocol.game
    • ClientboundTrackedWaypointPacket - A packet that sends some operation for a waypoint to the client.
    • ClientGamePacketListener#handleWaypoint - Handles the waypoint packet on the client.
  • net.minecraft.server.ServerScoreboard$Method enum is removed
  • net.minecraft.server.level.ServerLevel#getWaypointManager - Gets the server manager used for tracking waypoints.
  • net.minecraft.server.level.ServerPlayer#isReceivingWaypoints - Whether the player is receiving waypoints from other locations or entities.
  • net.minecraft.server.waypoints.ServerWaypointManager - A server-side manager for tracked waypoints (e.g., players and transmitters).
  • net.minecraft.world.entity
    • Entity#getRequiresPrecisePosition, setRequiresPrecisePosition - Handles when a more precise position is needed for tracking.
    • LivingEntity now implements WaypointTransmitter
  • net.minecraft.world.waypoints
    • TrackedWaypoint - A waypoint that is identified by some UUID or string, displayed via a Waypoint$Icon, and specified via $Type.
    • TrackedWaypointManager - A waypoint manager for TrackedWaypoints.
    • Waypoint - An interface that represents some positional location. This holds no information, and is typically used in the context of TrackedWaypoint.
    • WaypointManager - An interface that tracks and updates waypoints.
    • WaypointStyleAsset - A class that indicates a style asset.
    • WaypointStyleAssets - A class that defines all vanilla style assets.
    • WaypointTransmitter - An object that transmits some position that can be connected to and tracked.

Blaze3d Changes

Just like the previous update Blaze3d has new redesigns that change how rendering is handled.

Buffer Slices

The most important change within the rendering system is the use of GpuBufferSlices. As the name implies, it simply takes some slice of a GpuBuffer, using an offset to indicate the starting index, and the length to indicate its size. When dealing with anything rendering related, even when passing to a shader, you will almost always be dealing with a GpuBufferSlice. A way to think about it is that the buffer is just some arbitrary list of object where a slice represents a specific object.

To create a slice, simply call GpuBuffer#slice, optionally providing the starting index and length. In most instances, you will not be calling this method directly, instead dealing with other methods that call it for you. Note that as you are generally writing data to these slices, they should be constructed before a try-with-resources RenderPass is created.

Uniform Rework

The uniform system has been completely overhauled such that, unless you are familiar with specific features, it might seem completely foreign. In a nutshell, uniforms are now stored as either interface objects, a texel buffer, or a sampler. These are populated either by GpuBuffers or GpuBufferSlices.

Uniform Types

A uniform is currently represented as one of two UniformTypes: either as an UNIFORM_BUFFER/interface block, or a TEXEL_BUFFER. When setting up a pipeline and calling withUniform, you must specify your uniform with one of the above types. If you choose to use a texel buffer, you must also specify the format of the texture data. Samplers have not changed.

public static final RenderPipeline EXAMPLE_PIPELINE = RenderPipeline.builder(...)
    // Uses a uniform interface block called 'ExampleUniform'
    .withUniform("ExampleUniform", UniformType.UNIFORM_BUFFER)
    // Uses a buffer called 'ExampleTexel' that stores texture data as a 8-bit R value
    .withUniform("ExampleTexel", UniformType.TEXEL_BUFFER, TextureFormat.RED8I)
    // Perform other setups
    .build();

Interface Blocks

A UNIFORM_BUFFER is stored as a std140 interface block. In GLSL, this is represented like so:

// In assets/examplemod/shaders/core/example_shader.json

// ExampleUniform is the name of the block
layout(std140) uniform ExampleUniform {
    // The data within the block
    // Post Effects can only use int, float, vec2, vec3, ivec3, vec4, or mat4
    vec4 Param1;
    float Param2;
};

The values can be used freely inside the main block like so:

// In assets/examplemod/shaders/core/example_shader.json

out vec4 fragColor;

void main() {
    fragColor = Param1;
}

The uniform block can either be inside the same file as the main function or, if it will be reused, as a moj_import, where the uniform file is within assets/<modid>/shaders/include/<path>. Note that any shaders used before resource packs are loaded cannot use moj_import.

Post Effects define their interface blocks in the uniform input:

// In assets/examplemod/post_effect/example_post_effect.json
// Inside a 'passes' object
{
    "vertex_shader": "...",
    // ...
    "uniforms": {
        // The name of the interface block
        "ExampleUniform": [
            // A parameter within the uniform block
            // See `UniformValue` for codec formats
            {
                // The name of the parameter
                "name": "Param1",
                // The parameter type, one of:
                // - int
                // - ivec3
                // - float
                // - vec2
                // - vec3
                // - vec4
                // - matrix4x4 (mat4)
                "type": "vec4",
                // The value stored in the uniform
                // Dynamic values from the codebase are no longer supported
                "value": [ 0.0, 0.0, 0.0, 0.0 ]
            },
            {
                "name": "Param2",
                "type": "float",
                "value": 0
            }
        ]
    }
}

Texel Buffers

Texel buffers are typically represented as a isamplerBuffer to be queried from, typically using texelFetch:

// In assets/examplemod/shaders/core/example_shader.json

uniform isamplerBuffer ExampleTexel;

void main() {
    // Read the documentation to understand how texel fetch works
    texelFetch(ExampleTexel, gl_InstanceID);
}

Writing Custom Uniforms

Writing custom uniforms can only happen when you are the one responsible for creating the RenderPass. Like before, you create and cache the object before opening the RenderPass, then you set the uniform by calling RenderPass#withUniform. The only difference is that, instead of providing arbitrary objects, you must now either provide a GpuBuffer or GpuBufferSlice with the uniform data written to it. For a texel buffer, this is usually some encoded data in the desired texture format (such as a mesh). For an interface block, the easiest method is to use the Std140Builder to populate the buffer with the correct values.

There are many different methods of writing to a GpuBuffer or GpuBufferSlice, such as using the newly created MappableRingBuffer. It is up to you to figure out what method works best in your scenario. The following is simply one solution out of many.

// Buffer for 'ExampleUniform'
// Takes in the name of the buffer, its usage, and the size
private final MappableRingBuffer ubo = new MappableRingBuffer(
    // Buffer name
    () -> "Example UBO",
    // Buffer Usage
    // We set 128 as its used for a uniform and 2 since we are writing to it
    // Other bits can be found as constants in `GpuBuffer`
    GpuBuffer.USAGE_UNIFORM | GpuBuffer.USAGE_MAP_WRITE,
    // The size of the buffer
    // Easiest method is to use Std140SizeCalculator to properly calculate this
    new Std140SizeCalculator()
        // Param1
        .putVec4()
        // Param2
        .putFloat()
        .get()
);

// Buffer for 'ExampleTexel'
private final MappableRingBuffer utb = new MappableRingBuffer(
    // Buffer name
    () -> "Example UTB",
    // We set 256 as its used for a texel buffer and 2 since we are writing to it
    GpuBuffer.USAGE_UNIFORM_TEXEL_BUFFER | GpuBuffer.USAGE_MAP_WRITE,
    // The size of the buffer
    // It will likely be larger than this for you
    3
);

// In some render method

// Populate the buffers as required

// As we are using a ring buffer, this simply uses the next available buffer in the list
this.ubo.rotate();
// Write the data to the buffer
try (GpuBuffer.MappedView view = RenderSystem.getDevice().createCommandEncoder().mapBuffer(this.ubo.currentBuffer(), false, true)) {
    Std140Builder.intoBuffer(view.data())
        .putVec4(0f, 0f, 0f, 0f)
        .putFloat(0f);
}

// Similar thing here
this.utb.rotate();
try (GpuBuffer.MappedView view = RenderSystem.getDevice().createCommandEncoder().mapBuffer(this.utb.currentBuffer(), false, true)) {
    view.data()
        .put((byte) 0)
        .put((byte) 0)
        .put((byte) 0);
}

// Create the render pass and pass in the buffers as part of the uniform
try (RenderPass pass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(...)) {
    // ..
    pass.setUniform("ExampleUniform", this.ubo.currentBuffer());
    pass.setUniform("ExampleTexel", this.utb.currentBuffer());
    // ...
}

Fog Environments

The fog system has been reworked into an environment/render state-like handler. Each environment mostly handles setting up the fog data and color. Some additional processing is provided for the individual FogTypes and special mob effects.

All environments are handled through the FogEnvironment. A environment is setup via the setupFog method, which is responsible for mutating the passed in FogData to the values associated with that environment. If the fog colors its surroundings, then providesColor should return true, with the base color tint applied in getBaseColor. Likewise, if the fog darkens its surroundings, then modifiesDarkness should return true, with the modified darkness returned via getModifiedDarkness. To determine whether an environment should apply, isApplicable is checked. If not applicable, then onNotApplicable is called.

All environments are registered to FogRenderer#FOG_ENVIRONMENTS; however, what environment to use is based on isApplicable and the list order. For the color and darkness, the fog environment chosen is the last one in the list where one of the provides* methods return true. For the actual fog setup, the fog environment chosen is the first one in the list.

Render Pass Scissoring now only OpenGL

The scissoring state has been removed from the generic pipeline code, now only accessible through the OpenGL implementation. Generic region handling has been delegated to CommandEncoder#clearColorAndDepthTextures. Note that this does not affect the existing ScreenRectangle system that handles the blit facing scissoring.

  • com.mojang.blaze3d.buffers
    • BufferType enum is removed
    • BufferUsage enum is removed
    • GpuBuffer now takes two ints represent the size and usage, the type is no longer specified
      • type is removed
      • usage now returns an int
      • slice - Returns a record representing a slice of some buffer. The actual buffer is not modified in any way.
      • $ReadView -> $MappedView
    • GpuBufferSlice - A record that represents a slice of some buffer by holding a reference to the entire buffer, an offset index of the starting point, and the length of the slice.
    • GpuFence is now an interface, with its OpenGL implementation moved to blaze3d.opengl.GlFence
    • Std140Builder - A buffer inserter for an interface block laid out in the std140 format. This is used for the uniform blocks within shaders.
    • Std140SizeCalculator - An object used for keeping track of the size of some interface block.
  • com.mojang.blaze3d.opengl
    • AbstractUniform is removed, replaced by the Std140* classes
    • BufferStorage - A class that create buffers given its types. Its implementations define its general usage.
    • DirectStateAccess
      • createBuffer - Creates a buffer.
      • bufferData - Initializes a buffer’s data store.
      • bufferSubData - Updates a subset of a buffer’s data store.
      • bufferStorage - Creates the data store of a buffer.
      • mapBufferRange - Maps a section of a buffer’s data store.
      • unmapBuffer - Relinguishes the mapping of a buffer and invalidates the pointer to its data store.
    • GlBuffer now takes in a DirectStateAccess, two ints, and a ByteBuffer instead of a GlDebugLabel and its Buffer* enums
      • initialized is removed
      • persistentBuffer - Holds a reference to an immutable section of some buffer.
      • $ReadView -> $GlMappedView
    • GlCommandEncoder
      • executeDrawMultiple now takes in a collection of strings that defines the list of required uniforms and a generic indicating the object of the draw call
      • executeDraw now takes in two int, the number of instances of the specified range of indices to be rendered and the base vertex
    • GlConst#toGl for BufferType and BufferUsage -> bufferUsageToGlFlag, bufferUsageToGlEnum
    • GlDebugLabel#pushDebugGroup, popDebugGroup - Profiler commands for grouping similar calls.
    • GlDevice
      • USE_GL_ARB_buffer_storage - Sets the extension flag for GL_ARB_buffer_storage.
      • getBufferStorage - Returns the storage responsible for creating buffers.
    • GlProgram
      • Uniform fields have been removed
      • safeGetUniform, setDefaultUniforms are removed
      • bindSampler is removed
      • getSamplerLocations, getSamplers, getUniforms -> getUniforms which returns a map of names to their Uniform objects
    • GlRenderPass
      • uniforms now is a HashMap<String, GpuBufferSlice>
      • dirtSamplers is removed
      • samplers map now holds a GpuTextureView value
      • pushedDebugGroups - Returns the number of groups pushed onto the stack. No debug groups must be open for the render pass to be closed.
      • isScissorEnabled - Returns whether the scissoring state is enabled which crops the area that is rendered to the screen.
      • getScissorX, getScissorY, getScissorWidth, getScissorHeight - Returns the values representing the scissored rectangle.
    • GlTexture now takes in an additional integer for the usage and depth/layers
      • flushModeChanges now takes in an int which represents the texture target
      • addViews, removeViews - Manages the views looking at a texture for some mip levels.
    • GlTextureView - A view implementation of a texture for some mip levels.
    • Uniform is now a sealed interface which is implemented as either a buffer object, texel buffer, or a sampler
  • com.mojang.blaze3d.pipeline
    • BlendFunction#PANORAMA is removed
    • CompiledRenderPipeline#containsUniform is removed
    • RenderPipeline
      • $Builder#withUniform now has an overload that can take in a TextureFormat
      • $UniformDescription now takes in a nullable TextureFormat
    • RenderTarget
      • colorTextureView, depthTextureView, getColorTextureView, getDepthTextureView - A view of the current color and depth textures.
      • blitAndBlendToTexture now takes in a GpuTextureView instead of a GpuTexture
  • com.mojang.blaze3d.platform.Lightning is now AutoCloseable
    • setup* -> setupFor, an instance method that takes in an $Entry
    • updateLevel - Updates the lighting buffer, taking in whether to use the nether diffused lighting.
  • com.mojang.blaze3d.shaders
    • FogShape -> net.minecraft.client.renderer.fog.FogData, not one-to-one
    • UniformType now only holds two types: UNIFORM_BUFFER, or TEXEL_BUFFER, and no longer takes in a count
  • com.mojang.blaze3d.systems
    • CommandEncoder
      • clearColorAndDepthTextures now has an overload that takes in four ints representing the region to clear the texture information within
      • writeToBuffer, mapBuffer(GpuBuffer, int, int) now take in a GpuBufferSlice instead of a GpuBuffer
      • createFence - Creates a new sync fence.
      • createRenderPass now takes in a Supplier<String>, used for determining the name of the pass to use as a debug group, and GpuTextureViews instead of GpuTextures
      • writeToTexture now takes in an additional int representing the depth or layer to write to
      • presentTexture now takes in a GpuTextureView instead of a GpuTexture
    • GpuDevice
      • createBuffer no longer takes in a BufferUsage, with BufferType replaced by an int
      • getUniformOffsetAlignment - Returns the uniform buffer offset alignment.
      • createTexture now takes in additionals int for the usage and the number of depth/layers, see GpuTexture constants
      • createTextureView - Creates a view of a texture for a certain range of mip levels.
    • RenderPass
      • enableScissor is removed
      • bindSampler can now take in a nullable GpuTextureView
      • setUniform can either take in a GpuBuffer or GpuBufferSlice instead of the raw inputs
      • drawIndexed now takes the following ints: the base vertex, the start index, the number of elements, and the prim count
      • drawMultipleIndexed now takes in a collection of strings that defines the list of required uniforms and a generic indicating the object of the draw call
      • pushDebugGroup, popDebugGroup - Profiler commands for grouping similar calls.
      • $UniformUploader#upload now takes in a GpuBufferSlice instead of an array of floats
      • $Draw now has a generic that passed in to upload any uniforms to the buffer
    • RenderSystem
      • SCISSOR_STATE -> scissorStateForRenderTypeDraws, now private
        • Accessible through getScissorStateForRenderTypeDraws
      • enableScissor, disableScissor -> enableScissorForRenderTypeDraws, disableScissorForRenderTypeDraws, not one to one
      • PROJECTION_MATRIX_UBO_SIZE - Returns the size of the projection matrix uniform
      • setShaderFog, getShaderFog now deals with a GpuBufferSlice
      • setShaderGlintAlpha, getShaderGlintAlpha is removed
      • setShaderLights, getShaderLights now deals with a GpuBufferSlice
      • setShaderColor, getShaderColor
      • setup*Lighting methods are removed
      • setProjectionMatrix, getProjectionMatrix (now getProjectionMatrixBuffer) now deals with a GpuBufferSlice
      • setShaderGameTime, getShaderGameTime -> setGlobalSettingsUniform, getGlobalSettingsUniform; not one-to-one
      • getDynamicUniforms - Returns a list of uniforms to write for the shader.
      • bindDefaultUniforms - Binds the default uniforms to be used within a RenderPass
      • outputColorTextureOverride, outputDepthTextureOverride are now GpuTextureViews
      • setupOverlayColor, setShaderTexture, getShaderTexture now operate on GpuTextureViews instead of GpuTextures
  • com.mojang.blaze3d.textures
    • GpuTexture now takes in an int representing the usage flags and number of depth/layers
      • usage - The flags that define how the texture can be used.
      • depthOrLayers, getDepthOrLayers - Defines how many layers or depths are available for a given texture. This is meant as a generic count for available texture encodings. Only cubemap support is currently available (meaning the layer count must be a multiple of 6).
    • GpuTextureView - A view of some texture for a range of mip levels.
    • TextureFormat#RED8I - An 8-bit signed integer handling the red color channel.
  • com.mojang.blaze3d.vertex
    • ByteBufferBuilder now takes in a long for the maximum capacity
      • exactlySized - Returns a buffer that is its maximum capacity. This should be called over the public constructor.
    • DefaultVertexFormat#EMPTY - A vertex format with no elements.
  • net.minecraft.client.renderer
    • CachedOrthoProjectionMatrixBuffer - An object that caches the orthographic projection matrix, rebuilding if the width or height of the screen changes.
    • CachedPerspectiveProjectionMatrixBuffer - An object that caches the perspective projection matrix, rebuilding if the width, height, or field of view changes.
    • CloudRenderer
      • FLAG_INSIDE_FACE, FLAG_USE_TOP_COLOR are now private
      • RADIUS_BLOCKS is removed
      • endFrame - Ends the current frame being rendered to by constructing a fence.
    • CubeMap is now AutoCloseable
      • render no longer takes in the float for the partial tick.
    • DynamicUniforms - A class that writes the uniform interface blocks to the buffer for use in shaders.
    • DynamicUniformStorage - A class that holds the uniforms within a slice of a mappable ring buffer.
    • FogParameters record is removed, now stored in a general GpuBufferSlice
    • FogRenderer now implements AutoCloseable -> .fog.FogRenderer
      • endFrame - Ends the current frame being rendered to by constructing a fence.
      • getBuffer - Gets the buffer slice that holds the uniform for the current fog mode.
      • setupFog no longer takes in the FogMode, returning nothing
      • $FogData#mode is removed, replaced by skyEnd, cloudEnd
      • $FogMode enums have been replaced with NONE and WORLD, not one-to-one
    • GameRenderer
      • getGlobalSettingsUniform - Returns the uniform for the game settings.
      • getLighting - Gets the lighting renderer.
      • setLevel - Sets the current level the renderer is rendering.
    • GlobalSettingsUniform - An object fod handling the uniform holding the current game settings.
    • LevelRenderer
      • endFrame - Ends the current frame being rendered to by constructing a fence.
      • renderLevel now takes in a GpuBufferSlice, the fog vector, and whether the current position is foggy instead of the GameRenderer
    • MappableRingBuffer - An object that contains three buffers that are written to as required, then rotates to the next buffer to use on end. These are synced using fences.
    • PanoramaRenderer#render now takes in a boolean for whether to change the spin up the spin rather than two floats.
    • PerspectiveProjectionMatrixBuffer - An object that holds the projection matrix uniform.
    • PostChain
      • load now takes in the CachedOrthoProjectionMatrixBuffer
      • addToFrame no longer takes in the Consumer<RenderPass>
      • process no longer takes in the Consumer<RenderPass>
    • PostChainConfig
      • $FixedSizedTarget record is removed
      • $FullScreenTarget record is removed
      • $InternalTarget is now a record which can take in an optional width, height, whether the target is persistent, and the clear color to use
      • $Pass#uniforms is now a Map<String, List<UniformValue>>
      • $Uniform record is removed
    • PostPass is now AutoCloseable, taking in a Map<String, List<UniformValue>> for the uniforms along with a list of PostPass$Inputs
      • addToFrame no longer takes in the Consumer<RenderPass>, with the Matrix4f passed in as a GpuBufferSlice
      • $Input
        • bindTo is removed
        • texture - Constructs a GpuTexture for the input given the map of resources.
        • samplerName - Returns the name of the sampler.
    • SkyRenderer#renderSunMoonAndStars no longer takes in the FogParameters
    • UniformValue - An interface that represents a uniform stored within an interface block.
  • net.minecraft.client.renderer.chunk.SectionRendererDispatcher$RenderSection#setDynamicTransformIndex, getDynamicTransformIndex - Handles the index used to query the correct dynamic transforms for a given section.
  • net.minecraft.client.renderer.fog.environment
    • AirBasedFogEnvironment - An environment whose color is derived from the air of the biome
    • AtmosphericFogEnvironment - The default fog environment if no other special cases match.
    • BlindessFogEnvironment - An environment that activates if the entity has the blindness effect.
    • DarknessFogEnvironment - An environment that activates if the entity has the darkness effect.
    • DimensionOrBossFogEnvrionment - An environment that activates based on if there are any bosses or the dimension special effects.
    • FogEnvironment - An abstract class that determines how the fog should render at a given location for an entity.
    • LavaFogEnvironment - An environment that activates if the entity is within lava.
    • MobEffectFogEnvironment - An environment that activates based on if the entity has a given mob effect.
    • PowderedSnowFogEnvironment - An environment that activates if the entity is within powdered snow.
    • WaterFogEnvironment - An environment that activates if the entity is within water.
  • net.minecraft.client.renderer.texture
    • AbstractTexture
      • setUseMipmaps - Sets whether the texture should use mipmapping.
      • textureView, getTextureView - Represents the current texture view.
    • CubeMapTexture - A cubemap compatible texture, textures are expected to have suffixes _0 to _5.
    • ReloadableTexture#doLoad is now protected
  • net.minecraft.world.level.material.FogType
    • DIMENSION_OR_BOSS - Fog for dimension special effects or bosses.
    • ATMOSPHERIC - Default fog type.

Tag Providers: Appender Rewrite

The TagAppender has been rewritten to a degree, changing the basic implementations of TagsProviders.

By default, the TagsProvider no longer provides any useful methods for adding content to a TagBuilder. The most you can do is construct the builder using TagsProvider#getOrCreateRawBuilder and add elements or tags via their ResourceLocation using one of the available add* methods.

// We will assume there is some TagKey<Item> EXAMPLE_TAG
public class ExampleTagsProvider extends TagsProvider<Item> {

    public ExampleTagsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries, CompletableFuture<TagsProvider.TagLookup<Item>> parentProvider) {
        super(
            // The output location of the pack
            output,
            // The registry key to generate tags for
            Registries.ITEM,
            // The registry of registries
            registries,
            // Optional: A parent provider to use the generate tags of
            // Typically obtained from TagsProvider#contentsGetter
            parentProvider
        );
    }

    @Override
    protected void addTags(HolderLookup.Provider registries) {
        // Add tags here
        TagBuilder builder = this.getOrCreateRawBuilder(EXAMPLE_TAG);
        builder
            // Add single element
            .addElement(ResourceLocation.fromNamespaceAndPath("minecraft", "apple"))
            // Add tag to builder
            .addTag(ItemTags.WOOL.location());
    }
}

But what if we want to reference tags by their ResourceKey? Or registry object? This is where the rewritten TagAppender comes in. TagAppender is an interface with two generics, E which represents the type of the entry to add, and T which represents the type of the objects within the tag. A TagAppender has five common methods: three that add entries (add, addAll, addOptional), and two that add tags (addTag, addOptionalTag). A TagAppender can be created via forBuilder, which accepts ResourceKeys for entries.

KeyTagProvider provides this for you by adding a tag method, creating the appender from a TagKey. Generally, datapack registry objects have their tags generated using this provider:

// We will assume there is some TagKey<Item> EXAMPLE_TAG
public class ExampleTagsProvider extends KeyTagProvider<Item> {

    public ExampleTagsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
        super(
            // The output location of the pack
            output,
            // The registry key to generate tags for
            Registries.ITEM,
            // The registry of registries
            registries
        );
    }

    @Override
    protected void addTags(HolderLookup.Provider registries) {
        // Add tags here
        TagAppender<ResourceKey<Item>, Item> builder = this.tag(EXAMPLE_TAG);
        builder
            // Add single element
            .add(ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath("minecraft", "apple")))
            // Add tag to builder
            .addTag(ItemTags.WOOL);
    }
}

TagAppenders can also be mapped to change their entry type using the map method. This takes in a function which maps the new entry type to the original entry type. IntrinsicHolderTagsProvider provides this for you via a tag method, creating the appender from a TagKey and mapping it using a key extractor. Generally, built-in registry objects have their tags generated using this provider:

// We will assume there is some TagKey<Item> EXAMPLE_TAG
public class ExampleTagsProvider extends IntrinsicHolderTagsProvider<Item> {

    public ExampleTagsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
        super(
            // The output location of the pack
            output,
            // The registry key to generate tags for
            Registries.ITEM,
            // The registry of registries
            registries,
            // Maps the registry object to its resource key
            item -> item.builtInRegistryHolder().key()
        );
    }

    @Override
    protected void addTags(HolderLookup.Provider registries) {
        // Add tags here
        TagAppender<Item, Item> builder = this.tag(EXAMPLE_TAG);
        builder
            // Add single element
            .add(Items.APPLE)
            // Add tag to builder
            .addTag(ItemTags.WOOL);
    }
}

Copying Tags: Block and Item

Copying tags no longer exists in the traditional sense, where it loops through the elements of an existing tag. Instead, the implementation has been narrowed down to a general BlockItemTagsProvider. This method provides a TagAppender<Block, Block> by taking in both a block and an item tag, and then converting them appropriately within the Vanilla*TagsProvider. As such, it is less copying and more mapping blocks to their associated items.

The one drawback is that tags that are used within other tags (calling addTag) must have the same name. For example, adding BlockTags#LOGS only works because there is a minecraft:logs for both block and item tags. Meanwhile, adding BlockTags#CEILING_HANGING_SIGNS would fail as the associated item tag is minecraft:hanging_signs instead of minecraft:ceiling_hanging_signs.

// We will assume there is some TagKey<Block> BLOCK_EXAMPLE_TAG
// We will assume there is some TagKey<Item> ITEM_EXAMPLE_TAG
public class ExampleBlockItemTagsProvider extends BlockItemTagsProvider {

    @Override
    public void run() {
        // Add block item tags here
        // Will add entries to block or item tag depending on the provider
        TagAppender<Block, Block> builder = this.tag(BLOCK_EXAMPLE_TAG, ITEM_EXAMPLE_TAG);
        builder
            // Add single element
            .add(Blocks.TERRACOTTA)
            // Add tag to builder
            // There exists both `minecraft:logs` in block and item tags
            .addTag(BlockTags.LOGS);
    }
}

// For some IntrinsicHolderTagsProvider<Item> or IntrinsicHolderTagsProvider<Block>
@Override
protected void addTags(HolderLookup.Provider registries) {
    // Add tags here
    new ExampleBlockItemTagsProvider() {
        // Or <Item, Item> depending on the situation
        protected TagAppender<Block, Block> tag(TagKey<Block> blockTag, TagKey<Item> itemTag) {
            // Return a TagAppender
            // See VanillaItemTagsProvider$BlockToItemConverter for an item example
            // See VanillaBlockTagsProvider for a block example
        }
    }.run();
}
  • net.minecraft.data.tags
    • BlockItemTagsProvider - A provider that generates tags for block items, using the block and item tag equivalents as a starting point.
    • IntrinsicHolderTagsProvider
      • tag now returns the raw TagAppender
      • $IntrinsicTagAppender class is removed
    • ItemTagsProvider class is removed
    • KeyTagProvider - A provider which appends elements via their ResourceKey.
    • TagsProvider
      • tag is removed
      • $TagAppender -> TagAppender, not one-to-one
    • VanillaItemTagsProvider now implements IntrinsicHolderTagsProvider
      • BlockToItemConverter - A tag appender that adds a block to an item tag.

Generic Encoding and Decoding: Replacing Direct NBT Access

Direct access to get data out of some NBT has been removed completely from higher level objects like entities and block entities. This means that, generally, you cannot directly touch the CompoundTag during the serialization process. Instead, indirect access is provided to nbt tags via ValueInput and ValueOutput. As their name implies, these read values from and write values to the data object, respectively. The methods available are similar to those on CompoundTags. For ValueInput, there’s the get* methods by providing the associated key, and get*Or for a get-or-default if not present. There is also read for handling Codecs. For ValueOutput, there’s the put* methods by providing the associated key and value, and also a store for Codecs. List variants exists separately on the input/output access.

As such, most methods that take in a CompoundTag now instead take in a ValueInput for read/load or ValueOutput for write/save.

// For some Entity with an ItemStack stack
@Override
protected void readAdditionalSaveData(ValueInput in) {
    super.readAdditionalSaveData(in);
    // By default, the input uses a registry ops
    this.stack = in.read("example_stack", ItemStack.CODEC).orElse(ItemStack.EMPTY);
}

@Override
protected void addAdditionalSaveData(ValueOutput out) {
    super.addAdditionalSaveData(out);
    // By default, the output uses a registry ops
    in.storeNullable("example_stack", ItemStack.CODEC, this.stack);
}

// For some BlockEntity with an int value
@Override
    protected void loadAdditional(ValueInput in) {
        super.loadAdditional(in);
        this.value = in.getIntOr("value", 0);
    }

    @Override
    protected void saveAdditional(ValueOutput out) {
        super.saveAdditional(out);
        out.putInt("value", this.value);
    }

NBT Implementations

To provide indirect access to CompoundTags, there are implementations of ValueInput and ValueOutput called TagValueInput and TagValueOutput respectively.

A TagValueOutput can be created using either createWithContext or createWithoutContext. ‘With context’ means that the output has access to the HolderLookup$Provider for registry objects while ‘without context’ does not. Currently, no location uses createWithoutContext. Internally, this creates a new CompoundTag. Then, this output is passed around to be populated before finally returning the NBT for writing via buildResult.

A TagValueInput, on the other hand, can be created via create, taking in the HolderLookup$Provider and the CompoundTag to read from. If the data is stored as a list of objects rather than a single object, you can pass in a List<CompoundTag> and get back a ValueInputList. Note this does not handle indicies, only providing an iterable or stream associated implementation.

Problem Reporter

In addition to what’s mentioned above, the create* methods also take in a ProblemReporter, used for collecting all problems encountered when attempting to serialize/deserialize the data. It is up to the implementation to determine whether this report causes a crash or gives a warning. A ProblemReporter contains two methods: report, which reports a $Problem; and forChild, which further groups $Problems using a $PathElement. Both problems and path elements are simply interface objects that return a string indicating what the problem is or the grouping, respectively.

There are two common ProblemReporters that are used: $Collector, which is typically used with data providers, and $ScopedCollector, which is used with disk objects (e.g., entities, block entities, chunks, etc.). A $Collector typiccally uses either forEach to report each problem one by one, getReport/getTreeReport to return a stringified problems, or isEmpty to list if there are any problems. A $ScopedCollector does the same, except this is AutoCloseable, in case nothing is done with the output. In these scenarios, the reports are written to a logger.

Each collector takes in an initial $PathElement. This typically comes from the object itself containing some method called problemPath, which implements the interface. The HolderLookup$Provider is provided in the same fashion.

// For some object with HolderLookup.Provider registries
// There is also a Logger LOGGER

// Let's assume our root path element is implemented like so
public record ExamplePathElement(String name) implements ProblemReporter.PathElement {

    @Override
    public String get() {
        return "Example: " + this.name();
    }
}

// For a data provider
ProblemReporter.Collector problems = new ProblemReporter.Collector(
    // Can be empty for a non-specified root
    new ExamplePathElement("data_provider")
);
// Pass around the provider

// For a disk-based object
try (ProblemReporter.ScopedCollector problems = new ProblemReporter.ScopedCollector(new ExamplePathElement("EXAMPLE TEST"), LOGGER)) {
    TagValueOutput out = TagValueOutput.createWithContext(problems, this.registries);
    // Pass around the output to write data

    // For the input
    // The last parameter can be whatever CompoundTag, using the output as an example
    TagValueInput in = TagValueInput.create(problems, this.registries, out.buildResult());
    // Pass around the input to read data
}
  • net.minecraft.nbt.StringTag#escapeWithoutQuotes - Creates a string that escapes control characters, quotations, apostrophes, and backslashes.
  • net.minecraft.server.level.ServerPlayer
    • loadAndSpawnParentVehicle now takes in a ValueInput
    • loadAndSpawnEnderPearls now takes in a ValueInput
    • loadGameTypes now takes in a ValueInput
  • net.minecraft.server.players.PlayerList#load takes in a ProblemReporter, returning an optional ValueInput
  • net.minecraft.util.ProblemReporter
    • DISCARDING - A reporter which discards all reporters.
    • forChild now takes in a $PathElement
    • report now takes in a $Problem
    • $Collector now has a constructor that takes in the root $PathElement
      • isEmpty - Returns whether there are no reports.
      • forEach - Loops through all available problems.
      • getReport now returns a regular String
      • getTreeReport - Gets the report and all its children using DFS.
    • $ElementReferencePathElement - A path element that references some ResourceKey.
    • $FieldPathElement - A path element that references some string.
    • $IndexedFieldPathElement - A path element that references some string at an index.
    • $IndexedPathElement - A path element that references some index.
    • $PathElement - An interface that defines the grouping or element.
    • $Problem - An interface that defines a problem with an element.
    • $RootElementPathElement - A path element that references some ResourceKey as the root.
    • $RootFieldPathElement - A path element that references some string as the root.
    • $ScopedCollector - A collector that logs warnings when problems arise.
  • net.minecraft.world
    • ContainerHelper
      • saveAllItems now takes in a ValueOutput instead of a CompoundTag, and no longer takes in a HolderLookup$Provider while returning nothing
      • loadAllItems now takes in a ValueInput instead of a CompoundTag, and no longer takes in a HolderLookup$Provider
    • LockCode#addToTag, fromTag now takes in a ValueOutput/ValueInput instead of a CompoundTag, and no longer takes in a HolderLookup$Provider
    • RandomziableContainer#tryLoadLootTable, trySaveLootTable now takes in a ValueOutput/ValueInput instead of a CompoundTag
    • SimpleContainer
      • fromTag -> fromItemList, not one-to-one
      • createTag -> storeAsItemList, not one-to-one
  • net.minecraft.world.entity
    • Entity
      • saveAsPassenger now takes in a ValueOutput instead of a CompoundTag
      • save now takes in a ValueOutput instead of a CompoundTag
      • saveWithoutId now takes in a ValueOutput instead of a CompoundTag, returning nothing
      • load now takes in a ValueInput instead of a CompoundTag
      • readAdditionalSaveData now takes in a ValueInput instead of a CompoundTag
      • addAdditionalSaveData now takes in a ValueOutput instead of a CompoundTag
      • problemPath - Returns the path element to report problems from.
    • EntityRenference
      • store now takes in a ValueOutput instead of a CompoundTag
      • read, readWithOldOwnerConversion now take in a ValueInput instead of a CompoundTag
    • Entity
      • UUID_TAG -> TAG_UUID
      • create, by now take in a ValueInput instead of a CompoundTag
      • loadEntityRecursive now takes in a ValueInput instead of a CompoundTag
      • loadEntitiesRecursive now takes in a ValueInput$ValueInputList instead of a list of nbt tags
      • loadStaticEntity now takes in a ValueInput instead of a CompoundTag
    • EntityReference#store - Writes the reference data to the ValueOutput.
    • Leashable#readLeashData, writeLeashData now take in a ValueInput/ValueOutput instead of a CompoundTag
    • LivingEntity#ATTRIBUTES_FIELD -> TAG_ATTRIBUTES
    • NeutralMob#addPersistentAngerSaveData, readPersistentAngerSaveData now take in a ValueOutput/ValueInput instead of a CompoundTag
  • net.minecraft.world.entity.npc.InventoryCarrier#readInventoryFromTag, writeInventoryToTag now take in a ValueInput/ValueOutput instead of a CompoundTag
  • net.minecraft.world.entity.player.Inventory
    • save now takes in a ValueOutput$TypedOutputList, returning nothing
    • load now takes in a ValueOutput$TypedInputList
  • net.minecraft.world.entity.variant.VariantUtils
    • writeVariant now takes in a ValueOutput instead of a CompoundTag
    • readVariant now takes in a ValueInput instead of a CompoundTag, and no longer takes in a RegistryAccess
  • net.minecraft.world.entity.vehicle.ContainerEntity#addChestVehicleSaveData, readChestVehicleSaveData now take in a ValueOutput/ValueInput instead of a CompoundTag, and no longer takes in a HolderLookup$Provider
  • net.minecraft.world.inventory.PlayerEnderChestContainer
    • fromTag -> fromSlots, not one-to-one
    • createTag -> storeAsSlots, not one-to-one
  • net.minecraft.world.item
    • BlockItem#setBlockEntityData now takes in a TagValueOutput instead of a CompoundTag
    • ItemStack#parse, save are removed
  • net.minecraft.world.level
    • BaseCommandBlock#save, load now take in a ValueOutput/ValueInput instead of a CompoundTag, and no longer takes in a HolderLookup$Provider, returning nothing
    • BaseSpawner#save, load now take in a ValueOutput/ValueInput instead of a CompoundTag, returning nothing
  • net.minecraft.world.level.block.SculkSpreader#save, load now take in a ValueOutput/ValueInput instead of a CompoundTag
  • net.minecraft.world.level.block.entity.BlockEntity
    • load* methods now take in a ValueInput instead of a CompoundTag, and no longer takes in a HolderLookup$Provider
    • save* methods now take in a ValueOutput instead of a CompoundTag, and no longer takes in a HolderLookup$Provider
    • removeComponentsFromTag now takes in a ValueOutput instead of a CompoundTag
    • parseCustomNameSafe now takes in a ValueInput and key instead of a tag and HolderLookup$Provider
    • problemPath - Returns the path element to report problems from.
  • net.minecraft.world.level.block.entity.trialspawner.TrialSpawner#load, store - Handles writing the spawner data.
  • net.minecraft.world.level.chunk.ChunkAccess#problemPath - Returns the path element to report problems from.
  • net.minecraft.world.level.storage
    • PlayerDataStorage#load now returns a ValueInput instead of a CompoundTag, taking in a ProblemReporter
    • TagValueInput - A compound tag input.
    • TagValueOutput - A compound tag output.
    • ValueInput - An interface that defines how to read data from some object.
    • ValueInputContextHelper - A class that contains the context used to read object data.
    • ValueOutput - An interface that defines how to write data to some object.
  • net.minecraft.world.level.storage.loot.ValidationContext
    • forChild, enterElement now takes in a ProblemReporter$PathElement instead of a String
    • reportProblem now takes in a ProblemReporter$Problem instead of a String
    • $MissingReferenceProblem - A problem where the referenced object is missing.
    • $ParametersNotProvidedProblem - A problem where the loot context params are missing.
    • $RecursiveReferenceProblem - A problem where the referenced object is referencing itself.
    • $ReferenceNotAllowedProblem - A problem where the referenced object is not allowed to be referenced.
  • net.minecraft.world.level.storage.loot.entries
    • AlternativesEntry#UNREACHABLE_PROBLEM - A problem where the altnerative entry can never be executed.
    • CompositeEntryBase#NO_CHILDREN_PROBLEM - A problem where the composite has no entries.
    • NestedLootTable#INLINE_LOOT_TABLE_PATH_ELEMENT - An element which indicates that a table is inlined.

Server Player Changes

MinecraftServer is no longer publicly exposed on the ServerPlayer. Additionally, serverLevel has been removed, now replaced with overloading level to return the ServerLevel.

  • net.minecraft.server.level.ServerPlayer
    • server field is now private
    • serverLevel -> level, still returns ServerLevel

Minor Migrations

The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.

Leashes

The leash system has been updated to support up to four on enabled entities. Additionally, the physics have been updated to more properly handle real-world elasicity of some stretchable object.

  • net.minecraft.client.renderer.entity.state.EntityRenderState
    • leashState now returns a list of $LeashStates
    • $LeashState#slack - Whether the leash has any slack.
  • net.minecraft.world.entity
    • Entity
      • shearOffAllLeashConnections - Handles when shears are used to removed a leash.
      • dropAllLeashConnections - Handles when all leashes should be removed from an entity.
      • getQuadLeashHolderOffsets - Gets the offsets when four leashes attached to an entity.
      • supportQuadLeashAsHolder - Returns whether the entity can be leashed up to four times.
      • notifyLeashHolder, notifyLeasheeRemoved - Handles when the leash is ticked on an entity and when its removed.
      • setLeashOffset is removed
      • getLeashOffset -> Leashable#getLeashOffset
    • Leashable
      • MAXIMUM_ALLOWED_LEASHED_DIST - The maximum distance a leash can be attached to an entity.
      • AXIS_SPECIFIC_ELASTICITY - The resistance of the leash along each axis.
      • SPRING_DAMPENING - The loss of energy when the leash is oscillating on stretch.
      • TORSIONAL_ELASTICITY - The resistance of the leash under torque.
      • STIFFNESS - The stiffness of the leash.
      • ENTITY_ATTACHMENT_POINT - Specifies the attachment point of the leash on the entity.
      • LEASHER_ATTACHMENT_POINT - Specifies the attachment point of the leash on the holder.
      • SHARED_QUAD_ATTACHMENT_POINTS - Specifies the attachment points of the leashes on an entity.
      • canHaveALeashAttachedToIt -> canHaveALeashAttachedTo, not one-to-one
      • leashDistanceTo - Returns the distance of the leash traveled between the holder and leashee.
      • onElasticLeashPull - Handles when the leash is being pulled upon.
      • leashSnapDistance - Returns when the leash will attempt to remove itself from the entity.
      • leashElasticDistance - Returns the max distance before the elasticity of the leash becomes a physics factor.
      • handleLeashAtDistance is removed
      • angularFriction - Returns the angular friction of the entity on a block or within a liquid.
      • whenLeashedTo - Notifies the entity that the leash is attached.
      • elasticRangeLeashBehaviour, legacyElasticRangeLeashBehaviour -> checkElasticInteractions, not one-to-one
      • supportQuadLeash - Whether the entity can be leashed up to four times.
      • getQuadLeashOffsets - Returns the offsets of each leash attached to the entity.
      • createQuadLeashOffsets - Creates the offsets for each of the four possible leash positions.
      • leashableLeashedTo - Gets all entities within a 32-block radius that are leashed to this holder.
      • $LeashData#angularMomentum - Returns the angular momentum of the entity when leashed.
      • $Wrench - A record which handles the force and torque applied to the leash.
  • net.minecraft.world.item.LeadItem#leashableInArea -> Leashable#leashableInArea

Removal of Mob Effects Atlas

The mob effect atlas has been removed and merged with the gui altas.

  • net.minecraft.client.Minecraft#getMobEffectTextures is removed
  • net.minecraft.client.gui.Gui#getMobEffectSprite - Gets the location of the mob effect sprite.
  • net.minecraft.client.resources.MobEffectTextureManage class is removed
  • AtlasIds#MOB_EFFECTS is removed

Permission Sources

The permission checks for commands have been abstracted into its own PermissionSource interface. This provides the previously provided hasPermission method, in addition to a new method allowsSelectors, which returns whether the source has the necessary permission to select other entities (defaults to level 2 perms). You can incoporate the permission check into your commands by calling Commands#hasPermission with the desired level in ArgumentBuilder#requires.

  • net.minecraft.client.multiplayer
    • ClientPacketListener
      • getCommands now returns a ClientSuggestionProvider generic
      • sendUnattendedCommand now takes in a Screen instead of a boolean
    • ClientSuggestionListener now implements PermissionSource, taking in a boolean of whether it allows restricted commands
      • allowRestrictedCommands - Returns whether restricted commands can be suggested.
  • net.minecraft.commands
    • Commands#hasPermission - Returns a permission check for the given level.
    • CommandSourceStack now implements PermissionSource
    • ExecutionCommandSource now implements PermissionSource
    • PermissionSource - Returns the source of the permission to run a command.
    • SharedSuggestionProvider
      • suggestResgitryElements now takes in a HolderLookup instead of a Registry
      • listSuggestions - Lists the suggestion for some registry elements.
      • hasPermission is removed
  • net.minecraft.commands.synchronization.SuggestionProviders
    • AVAILABLE_SOUNDS, SUMMONABLE_ENTITIES now take in a SharedSuggestionProvider for their generic
    • cast - Casts the suggestion provider to the correct type.
    • safelySwap is removed
    • $Wrapper -> $RegisteredSuggestion
  • net.minecraft.world.entity.Entity#getCommandSenderWorld is removed

Animation Baking

Animations are now baked into KeyframeAnimation. Each KeyframeAnimation is made up of entries that apply the keyframes to a given ModelPart. To create an animation, the definition should be baked via AnimationDefinition#bake in the model constructor, then calling #apply or #applyWalk as required during EntityModel#setupAnim.

// For some entity model
// Assume some AnimationDefinition EXAMPLE_DEFN
// Assume our ExampleEntityState has some AnimationState exampleAnimState
public class ExampleModel extends EntityModel<ExampleEntityState> {

    private final KeyframeAnimation exampleAnim;

    public ExampleModel(ModelPart root) {
        // We pass in whatever 'root' that can apply all animations
        this.exampleAnim = EXAMPLE_DEFN.bake(root);
    }

    @Override
    public void setupAnim(ExampleEntityState state) {
        super.setupAnim(state);
        this.exampleAnim.apply(state.exampleAnimState, state.ageInTicks);
    }
}
  • net.minecraft.client.animation
    • AnimationDefinition#bake - Bakes a defined animation to be used on a Model.
    • KeyframeAnimation - A baked animation used to move ModelParts on a given Model.
    • KeyframeAnimations#animate -> KeyframeAnimation$Entry#apply
  • net.minecraft.client.model.Model
    • getAnyDescendantWithName is removed
    • animate -> KeyframeAnimation#apply
    • animateWalk - KeyframeAnimation#applyWalk
    • applyStatic -> KeyframeAnimation#applyStatic
  • net.minecraft.client.model.geom.ModelPart
    • getAllParts now returns a List
    • createPartLookup - Creates a lookup of part names to their ModelPart, any duplicate names are ignored.

ChunkSectionLayers

RenderTypes used for defining how a block or fluid should render are now replaced with ChunkSectionLayers. These functionally do the same thing as the RenderType; however, they only specify the RenderPipeline to use along with the buffer information. This also means that certain RenderTypes are removed, like TRANSLUCENT, as they were only used for the block chunk rendering.

This also means that adding to ItemBlockRenderTypes#TYPE_BY_BLOCK must specify the ChunkSectionLayer instead of the associated RenderType.

  • net.minecraft.client.renderer
    • ItemBlockRenderTypes
      • getChunkRenderType now returns a ChunkSectionLayer
      • getRenderLayer(FluidState) now returns a ChunkSectionLayer
    • RenderType
      • translucent is removed
      • getRenderTarget, getRenderPipeline is removed
      • chunkBufferLayers is removed
  • net.minecraft.client.renderer.chunk
    • ChunkSectionLayer - An enum that defines how an individual chunk layer (e.g., solid blocks, translucent blocks) is rendered.
    • ChunkSectionLayerGroup - An enum that groups the layers for rendering.
    • ChunkSectionsToRender - A record that contains the draws of a given chunk, allowing them to be rendered per layer group.
    • RenderChunk -> SectionCopy
    • RenderChunkRegion -> RenderSectionRegion
    • RenderRegionCache#createRegion now takes in a long instead of a SectionPos
    • SectionCompiler$Results
      • globalBlockEntities -> - net.minecraft.client.multiplayer.ClientLevel#getGloballyRenderedBlockEntities
      • renderedLayers now takes in a ChunkSectionLayer for the key
    • SectionMesh - An interface that defines the mesh of a given section within a chunk
    • SectionRenderDispatcher
      • getBatchToCount -> getCompileQueueSize
      • setCamera, getCameraPosition are removed
      • blockUntilClear is removed
      • clearBatchQueue -> clearCompileQueue, now public
      • $CompiledSection -> CompiledSectionMesh
      • $RenderSection
        • getBuffers is removed
        • uploadSectionLayer(RenderType, MeshData) -> upload(Map, CompiledSectionMesh), not one-to-one
        • uploadSectionIndexBuffer now takes in a CompiledSectionMesh and a ChunkSectionLayer instead of a RenderType
        • getDistToPlayerSqr is removed
        • getCompiled -> getSectionMesh, not one-to-one
        • rebuildSectionAsync no longer takes in the SectionRenderDispatcher
        • setDynamicTransformIndex, getDynamicTransformIndex are removed
      • $SectionBuffers -> SectionBuffers
      • $TranslucencyPointOfView -> TranslucencyPointOfView
  • net.minecraft.server.level.ChunkMap#getUpdatingChunkIfPresent is now public
  • net.minecraft.world.level.TicketStorage
    • purgeStaleTickets now takes in the ChunkMap
    • removeTicketIf now takes in a BiPredicate instead of a Predicate, taking in the chunk position and the ticket
  • net.minecraft.world.level.chunk.ChunkAccess#isSectionEmpty is removed

Tag Changes

  • minecraft:block
    • plays_ambient_desert_block_sounds is split into triggers_ambient_desert_sand_block_sounds, triggers_ambient_desert_dry_vegetation_block_sounds
    • happy_ghast_avoids
    • triggers_ambient_dried_ghast_block_sounds
  • minecraft:dialog
    • pause_screen_additions
    • quick_actions
  • minecraft:entity_type
    • can_equip_harness
    • followable_friendly_mobs
  • minecraft:item
    • harnesses
    • happy_ghast_food
    • happy_ghast_tempt_items

List of Additions

  • com.mojang.blaze3d.pipeline
    • BlendFunction#TRANSLUCENT_PREMULTIPLIED_ALPHA - A blend function that assumes the target has a premultiplied alpha from the composite step.
    • RenderPipeline
      • getSortKey - Returns a value representing how the element should be sorted for rendering. Used for layer sorting.
      • updateSortKeySeed - Updates the seed of the sort key, currently unused.
  • com.mojang.blaze3d.systems.RenderSystem
    • outputColorTextureOverride - Holds a texture containing the override color used instead of whatever is specified in the RenderType target.
    • outputDepthTextureOverride - Holds a texture containing the override depth used instead of whatever is specified in the RenderType target.
  • com.mojang.blaze3d.textures.GpuTexture#setUseMipmaps - Sets whether the texture should use mipmaps at different distances.
  • net.minecraft
    • FileUtil#isPathPartPortable - Returns whether the provided string does not match any of the windows reserved filenames.
    • WorldVersion$Simple - A simple implementation of the current world version.
  • net.minecraft.advancements.critereon
    • ItemUsedOnLocationTrigger$TriggerInstance#placedBlockWithProperties - Creates a trigger where a block was placed with the specified property.
    • PlayerInteractTrigger$TriggerInstance#equipmentSheared - Creates a criterion trigger that actus upon a player taking off an item on some entity.
  • net.minecraft.client
    • GameNarrator#saySystemChatQueued - Narrates a component if either system or chat message narration is enabled.
    • Minecraft#disconnectWithSavingScreen - Disconnects the current client instance and shows the ‘Saving Level’ screen.
    • Options
      • keyQuickActions - A key mapping for showing the quick actions dialog.
      • cloudRange - Returns the maximum distance clouds can render at.
      • musicFrequency - Returns how frequency the background music handled by the MusicManager should play.
      • showNowPlayingToast - Returns whether the ‘Now Playing’ toast is shown.
      • getFinalSoundSourceVolume - Computes the volume for the given sound source, with non-master sources being scaled by the master source.
    • NarratorStatus#shouldNarrateSystemOrChat - Returns whether the current narration status is anything but OFF.
  • net.minecraft.client.color.ColorLerper - A utility class for lerping between color types based on some partial tick.
  • net.minecraft.client.data.models.BlockModelGenerators#createDriedGhastBlock - Creates the dired ghast block model definition.
  • net.minecraft.client.data.models.model
    • ModelTemplates#DRIED_GHAST - A template that uses the minecraft:block/dried_ghast parent.
    • TextureMapping#driedGhast - Creates the default texture mapping for the dried ghast model.
    • TextureSlot#TENTACLES - Provides a texture key tentacles.
  • net.minecraft.client.model
    • GhastModel#animateTentacles - Animates the tentacles of a ghast.
    • HappyGhastHarnessModel - A model representing the a ghast harness.
    • HappyGhastModel - A model representing a ‘tamed’ ghast.
    • QuadrupedModel#createBodyMesh now takes in two booleans for handling if the left and right hind leg textures are mirrored, respectively.
  • net.minecraft.client.multiplayer.ClientLevel
    • DEFAULT_QUIT_MESSAGE - The component holding the quit game text.
    • disconnect(Copmonent) - Disconnects from the current level instance, showing the associated component.
  • net.minecraft.client.renderer.entity.HappyGhastRenderer - The renderer for a ‘tamed’ ghast.
  • net.minecraft.client.renderer.entity.layers.RopesLayer - The render layer for the ropes used on a ‘tamed’ ghast.
  • net.mienecraft.client.renderer.entity.state.HappyGhastRenderState - The state of a ‘tamed’ ghast.
  • net.minecraft.client.resources.model.EquipmentclientInfo$LayerType#HAPPY_GHAST_BODY - A layer representing the body of a happy ghast.
  • net.minecraft.client.resources.sounds.RidingHappyGhastSoundInstance - A tickable sound instance that plays when riding a happy ghast.
  • net.minecraft.client.sounds
    • MusicManager
      • getCurrentMusicTranslationKey - Returns the translation key of the currently playing music.
      • setMinutesBetweenSongs - Sets the frequency between the background tracks.
      • showNowPlayingToastIfNeeded - Shows the now playing toast if it needs to be seen.
      • $MusicFrequency - The frequency of the background tracks being played.
    • SoundEngine$PlayResult - The starting state of the sound trying to be played.
  • net.minecraft.commands.arguments
    • HexColorArgument - An integer argument that takes in a hexadecimal color.
    • ResourceOrIdArgument
      • createGrammar - Creates the grammar used to parse the argument.
      • $InlineResult - A result that returns a direct holder.
      • $ReferenceResult - A result that returns a reference holder.
      • $Result - An interface that represents the result of some argument parsing.
  • net.minecraft.data.loot.LootTableProvider$MissingTableProblem - A record that holds the key of some missing built-in table generator.
  • net.minecraft.data.recipes.RecipeProvider
    • dryGhast - The recipe for a dried ghast.
    • harness - The recipe for a colored harness.
  • net.minecraft.gametest.framework.GameTestTicker#startTicking - Starts ticking the runner for the game tests.
  • net.minecraft.nbt.NbtUtils
    • addCurrentDataVersion, addDataVersion, adds the data version to some nbt tag.
  • net.minecraft.network.FriendlyByteBuf#writeEither, readEither - Handles an Either with the given stream encoders/decoders.
  • net.minecraft.network.codec.ByteBufCodecs
    • RGB_COLOR - A stream codec that writes the RGB using three bytes.
    • lenientJson - Creates a stream codec that parses a json in lenient mode.
    • optionalTagCodec - Creates a stream codec that parses an Optional-wrapped Tag using the supplied NbtAccounter.
  • net.minecraft.network.protocol.game
    • ServerboundChangeGameModePacket - Changes the current gamemode.
    • ServerboundCustomClickActionPacket - Executes a custom action on the server, currently does nothing.
  • net.minecraft.server.MinecraftServer#handleCustomClickAction - Handles a custom action sent from a click event.
  • net.minecraft.server.level.ServerLevel
    • updateNeighboursOnBlockSet - Updates the neighbors of the current position. If the blocks are not the same (not including their properties), then BlockState#affectNeighborsAfterRemoval is called.
    • waitForChunkAndEntities - Adds a task that causes the server to wait until entities are loaded in the provided chunk range.
  • net.minecraft.sources.SoundSource#UI - Sounds that come from some user interface.
  • net.minecraft.stats
    • RecipeBookSettings#MAP_CODEC
    • ServerRecipeBook#pack, loadUntrusted, $Packed - Handles encoding and decoding the data of the recipe book.
  • net.minecraft.util
    • ARGB
      • setBrightness - Returns the brightness of some color using a float between 0 and 1.
      • color - Returns a ARGB color from a float red and integer alpha.
    • ExtraCodecs
      • VECTOR2F
      • VECTOR3I
      • NBT
    • LenientJsonParser - A json parser using lenient rules.
    • Mth#smallestSquareSide - Takes the ceiled square root of a number.
    • StrictJsonParser - A json parser using strict rules.
  • net.minecraft.world
    • Difficulty#STREAM_CODEC
    • ItemStackWithSlot - A record which holds a stack along with its slot index.
  • net.minecraft.world.entity
    • Entity
      • MAX_MOVEMENTS_HANDELED_PER_TICK - The maximum number of movements that can be applied to an entity in a given tick.
      • isInClouds - Returns whether the entity’s Y position is between the cloud height and four units above.
      • teleportSpectators - Teleports the spectators currently viewing from the player’s perspective.
      • isFlyingVehicle - Returns whether the vehicle can fly.
      • clearMovementThisTick - Clears all movement the entity will make this tick.
    • EntityAttachments#getAverage - Returns the average location of all attachment points.
    • ExperienceOrb
      • awardWithDirection - Adds an experience orb that moves via the specified vector.
      • unstuckIfPossible - Attempts to find and move the orb to a free position.
    • Mob
      • isWithinHome - Returns whether the position is within the entity’s restriction radius.
      • canShearEquipment - Returns whether the current player can shear the equipment off of this mob.
  • net.minecraft.world.entity.ai.control.MoveControl#setWait - Sets the operation to WAIT.
  • net.minecraft.world.entity.ai.goal.TemptGoal
    • stopNavigation, navigateTowards - Handles navigation towards the player.
    • $ForNonPathfinders - A tempt goal that navigates towards a wanted position rather than immediately pathfinding.
  • net.minecraft.world.entity.ai.navigation.PathNavigation#canNavigateGround - Returns whether the entity can pathfind while on the ground.
  • net.minecraft.world.entity.ai.sensing.AdultSensorAnyType - An adult sensor that ignores whether the entity is the same type as the child.
  • net.minecraft.world.entity.animal
    • HappyGhast - An entity representing a happy ghast.
    • HappyGhastAi - The brain of the happy ghast.
  • net.minecraft.world.entity.decoration.ArmorStand
    • setArmorStandPose, getArmorStandPose, $ArmorStandPose - Handles the pose of the armor stand.
  • net.minecraft.world.entity.monster.Ghast
    • faceMovementDirection - Rotates the entity to face its current movement direction.
    • $RandomFloatAroundGoal#getSuitableFlyToPosition - Gets a position that the ghast should fly to.
  • net.minecraft.world.entity.player.Inventory#SLOT_BODY_ARMOR, SLOT_SADDLE - The indicies for the corresponding slot.
  • net.minecraft.world.entity.projectile.ProjectileUtil#computeMargin - Computes the bounding box margin to check for a given entity based on its tick count.
  • net.minecraft.world.item.component
    • ItemAttributeModifiers
      • forEach - Applies the consumer to all attributes within the slot group.
      • $Builder#add - Adds an attribute to apply for a given slot group with a display.
      • $Display - Defines how an attribute modifier should be displayed within its tooltip.
      • $Default - Shows the default attribute display.
      • $Hidden - Does not show any attribute info.
      • $OverrideText - Overrides the attribute text with the component provided.
    • Equippable$Builder
      • setCanBeSheared - Sets whether the equipment can be sheared off the entity.
      • setShearingSound - Sets the sound to play when a piece of equipment is sheared off an entity.
    • ResolvableProfile#pollResolve - Returns the profile of the stored id or name.
  • net.minecraft.world.item.equipment.Equippable#harness - Represents a harness to equip.
  • net.minecraft.world.level
    • CollisionGetter
      • getPreMoveCollisions - Returns an iterable of shapes containing the entity and block collisions at the given bounding box and futue movement direction.
      • getBlockCollisionsFromContext - Gets the block shapes from the given collision context.
    • GameType#STREAM_CODEC
    • Level
      • precipitationAt - Returns the precipitation at a given position.
      • onBlockEntityAdded - Logic to run when a block entity is added to the level.
  • net.minecraft.world.level.block
    • BaseRailBlock#rotate - Rotates the current rail shape in the associated direction.
    • DriedGhastBlock - A block that represents a dried ghast.
  • net.minecraft.world.level.block.entity.trialspawner.TrialSpawner$FullConfig - Represents the entire configuration of a trial.
  • net.minecraft.world.level.dimension.DimensionDefaults
    • CLOUD_THICKNESS - The block thickness of the clouds.
    • OVERWORLD_CLOUD_HEIGHT - The cloud height level in the overworld.
  • net.minecraft.world.level.levelgen.flat.FlatLayerInfo#heightLimited - Returns a new layer info whether the current height is limited to the specified value, as long as that value is not within the maximum range already.
  • net.minecraft.world.phys
    • AABB
      • intersects - Returns whether the BlockPos intersects with this box.
      • distanceToSqr - Returns the squared distance of the bounding boxes from their furthest point.
    • Vec3#rotateClockwise90 - Rotates the vector 90 degrees clockwise (flip x and z and invert new x value).
  • net.minecraft.world.phys.shapes.CollisionContext
    • withPosition - Returns the collision context of an entity with its bottom y position.

List of Changes

  • com.mojang.blaze3d.platform.Window#setGuiScale, getGuiScale now deals with an int instead of a double
  • net.mineraft
    • DetectedVersion no longer implements WorldVersion
    • WorldVersion methods now use record naming schema due to WorldVersion$Simple usage
      • getDataVersion -> dataVersion
      • getId -> id
      • getName -> name
      • getProtocolVersion -> protocolVersion
      • getPackVersion -> packVersion
      • getBuildTime -> buildTime
      • isStable -> stable
  • net.minecraft.client
    • GameNarrator
      • sayChat -> sayChatQueued
      • say -> saySystemQueued
      • sayNow -> saySystemNow
    • Minecraft
      • grabPanoramixScreenshot no longer takes in the window width and height to set
      • disconnect() -> disconnectWithProgressScreen
    • Screenshot#grab, takeScreenshot now takes in an int representing the downscale factor
  • net.minecraft.client.main.GameConfig$QuickPlayData now takes in a $QuickPlayVariant
    • path -> logPath
    • singleplayer -> variant with $QuickPlaySinglePlayerData
    • multiplayer -> variant with $QuickPlayMultiplayerData
    • realms -> variant with $QuickPlayRealmsData
    • null for singleplayer, multiplayer, realms is represented by variant with $QuickPlayDisabled
  • net.minecraft.client.data.models.ItemModelGenerators#generateWolfArmor -> generateTwoLayerDyedItem
  • net.minecraft.client.gui.components.DebugScreenOverlay#render3dCrosshair now takes in the current Camera
  • net.minecraft.client.gui.components.debugchart.ProfilerPieChart
    • RADIUS is now public
    • CHART_Z_OFFSET -> PIE_CHART_THICKNESS, now public
  • net.minecraft.client.multiplayer
    • ClientLevel$ClientLevelData#getClearColorScale -> voidDarknessOnsetRange, not one-to-one
    • MultiPlayerGameMode#createPlayer now takes in an Input instead of a boolean
  • net.minecraft.client.player.LocalPlayer now takes in the last sent Input instead of a boolean for the shift key
    • getLastSentInput - Gets the last sent input from the server.
  • net.minecraft.client.quickplay.QuickPlay#connect now takes in a GameConfig$QuickPlayVariant instead of a GameConfig$QuickPlayData
  • net.minecraft.client.renderer
    • DimensionSpecialEffects no longer takes in the current cloud level and whether there is a ground
    • LightTexture#getTarget -> getTexture
  • net.minecraft.client.renderer.blockentity.BlockEntityRenderer#shouldRenderOffscreen no longer takes in the BlockEntity
  • net.minecraft.client.resources
    • AbstractSoundInstance#sound is now Nullable
    • SoundInstance#getSound is now Nullable
  • net.minecraft.client.sounds
    • SimpleSoundInstance#forMusic now also takes in the float volume
    • SoundEngine now takes in the MusicManager
      • pause -> pauseAllExcept, not one-to-one
      • play now returns a $PlayResult
    • SoundManager now takes in the MusicManager
      • pause -> pauseAllExcept, not one-to-one
      • play now returns a SoundEngine$PlayResult
  • net.minecraft.commands.arguments
    • ResourceOrIdArgument now takes in an arbitrary codec rather than a Holder-wrapped value
      • ERROR_INVALID -> ERROR_NO_SUCH_ELEMENT, now public, not one-to-one
      • VALUE_PARSER -> OPS, now public, not one-toe
    • ResourceSelectorArgument#getSelectedResources no longer takes in the ResourceKey
  • net.minecraft.commands.functions.StringTemplate
    • fromString no longer takes in the line number
    • isValidVariableName is now public
  • net.minecraft.data.recipes.RecipeProvider#colorBlockWithDye -> colorItemWithDye, now takes in the RecipeCategory
  • net.minecraft.gametest.framework.GameTestInfo#prepareTestStructure is now nullable
  • net.minecraft.network
    • Connection#send now takes in a ChannelFutureListener instead of a PacketSendListener
    • FriendlyByteBuf#readJsonWithCodec -> readLenientJsonWithCodec
    • PacketSendListener is now a class whose methods return ChannelFutureListeners instead of PacketSendListeners
      • onSuccess, onFailure are removed
  • net.minecraft.network.codec
    • ByteBufCodecs#fromCodec now has an overload that takes in some ops and a codec
    • StreamCodec#composite now has an overload that takes in ten parameters
  • net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket is now a record
  • net.minecraft.network.protocol.game
    • ClientboundChangeDifficultyPacket is now a record
    • ClientboundCommandsPacket now takes in a $NodeInspector
      • getRoot is now generic, taking in a $NodeBuilder
      • $NodeBuilder - A builder for a given command.
      • $NodeInspector - An agent that checks the information of a given command node.
    • ServerboundChangeDifficultyPacket is now a record
  • net.minecraft.server.ReloadableServerRegistries$Holder#lookup returns a HolderLookup$Provider
  • net.minecraft.server.network.ServerCommonPacketListenerImpl#send now takes in a ChannelFutureListener instead of a PacketSendListener
  • net.minecraft.sounds.Music is now a record
  • net.minecraft.stats.RecipeBookSettings
    • getSettings is now public
    • $TypeSettings is now public
  • net.minecraft.world.entity
    • AreaEffectCloud#setParticle -> setCustomParticle
    • Entity
      • checkSlowFallDistance -> checkFallDistanceAccumulation
      • collidedWithFluid, collidedWithShapeMovingFrom are now public
      • canBeCollidedWith now takes the entity its colliding with
      • spawnAtLocation now has an overload that takes in a Vec3 for the offset position
      • removeLatestMovementRecordingBatch -> removeLatestMovementRecording
    • EntityReference is now final
    • ExperienceOrb now has an overload that takes in two vectors for the position and movement
    • FlyingMob is replaced by calling LivingEntity#travelFlying
    • LivingEntity#canBreatheUnderwater is no longer final
    • Mob
      • restrictTo -> setHomeTo
      • getRestrictCenter -> getHomePosition
      • getRestrictRadius -> getHomeRadius
      • clearRestriction -> clearHome
      • hasRestriction -> hasHome
  • net.minecraft.world.entity.ai.attributes
    • AttributeInstance
      • save -> pack, $Packed; not one-to-one
      • load -> apply, not one-to-one
    • AttributeMap
      • save -> pack; not one-to-one
      • load -> apply, not one-to-one
  • net.minecraft.world.entity.ai.behavior
    • AnimalPanic now has overloads that take in a radius or a position getter
    • BabyFollowAdult#create now returns a OneShot<LivingEntity> and can take in a boolean of whether to target the eye position
    • EntityTracker can now take in a boolean of whether to target the eye position
    • FollowTemptation now has an overload that checks whether the entity needs to track the entity’s eye height.
  • net.minecraft.world.entity.ai.goal.TemptGoal now has an overload that takes in the stop distance
    • mob is now a Mob
    • speedModifier is now protected
  • net.minecraft.world.entity.ai.memory.MemoryModuleType#NEAREST_VISIBLE_ADULT now holds a LivingEntity
  • net.minecraft.world.entity.ai.navigation
    • FlyingPathNavigation, GroundPathNavigation#setCanOpenDoors -> PathNavigation#setCanOpenDoors
  • net.minecraft.world.entity.ai.sensing.AdultSensor now looks for a LivingEntity
    • setNearestVisibleAdult is now protected
  • net.minecraft.world.entity.animal.*Variants#selectVariantToSpawn -> entity.variant.VariantUtils#selectVariantToSpawn, not one-to-one
  • net.minecraft.world.entity.animal.Fox#isJumping -> LivingEntity#isJumping
  • net.minecraft.world.entity.animal.horse.AbstractHorse
    • isJumping -> LivingEntity#isJumping
    • setStanding now takes in an int instead of a boolean for the stand counter
      • the false logic is moved to clearStanding
  • net.minecraft.world.entity.monster
    • Ghast now implements Mob
      • $GhastLookGoal is now public, taking in a Mob
      • $GhastMoveControl is now public, taking in whether it should be careful when moving and a supplied boolean of whether the ghast should stop moving
      • $RandomFloatAroundGoal is now public, taking in a Mob and a block distance
    • Phantom now implements Mob
  • net.minecraft.world.entity.player
    • Abilities
      • addSaveData -> pack, $Packed; not one-to-one
      • loadSaveData -> apply, not one-to-one
    • Player no longer takes in the BlockPos and y rotation
  • net.minecraft.world.entity.projectile
    • AbstractThrownPotion#onHitAsPostion now takes in a HitResult instead of a nullable Entity
    • EyeOfEnder#signalTo now takes in a Vec3 instead of a BlockPos
    • Projectile
      • ownerUUID. cachedOwner -> owner, now protected; not one-to-one
      • setOwner now has an overload to take in an EntityReference
    • ProjectileUtil
      • DEFAULT_ENTITY_HIT_RESULT_MARGIN is now public
      • getEntityHitResult now takes in a Projectile instead of an Entity
  • net.minecraft.world.item.ItemStack
    • forEachModifier now takes in a TriConsumer that provides the modifier display
    • hurtAndBreak now has an overload which gets the EquipmentSlot from the InteractionHand
  • net.minecraft.world.item.equipment.Equippable now takes in whether the equipment can be sheared off an entity and the sound to play when doing so
  • net.minecraft.world.level.BlockGetter
    • forEachBlockIntersectedBetween now returns a boolean indicating that each block visited in the intersected area can be successfully visited
    • $BlockStepVisitor#visit now returns whether the location can be successfully moved to
  • net.minecraft.world.level.block.AbstractCauldronBlock#SHAPE is now protected
  • net.minecraft.world.level.block.entity
    • BlockEntity#getNameForReporting is now public
    • SignBlockEntity#executeClickCommandsIfPresent now takes in a ServerLevel instead of the Level, parameters are reordered
    • StructureBlockEntity#saveStructure now takes in a list of blocks to ignore
  • net.minecraft.world.level.block.entity.trialspawner
    • TrialSpawner now takes in a $FullConfig
      • getConfig -> activeConfig
      • get*Config -> *config
      • getData -> getStateData
    • TrialSpawnerData -> TrialSpawnerStateData, serialized form as TrialSpawnerStateData$Packed, not one-to-one
  • net.minecraft.world.level.block.sounds.AmbientDesertBlockSoundsPlayer#playAmbientBlockSounds has been split into playAmbientSandSounds, playAmbientDryGrassSounds, playAmbientDeadBushSounds, shouldPlayDesertDryVegetationBlockSounds; not one-to-one
  • net.minecraft.world.level.dimension.DimensionType now takes in an optional integer representing the cloud height level
  • net.minecraft.world.level.entity
    • PersistentEntitySectionManager#processPendingLoads is now public
    • UUIDLookup#getEntity can now return null
  • net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate#fillFromWorld now takes in a list of blocks to ignore rather than a single Block
  • net.minecraft.world.level.storage.DataVersion is now a record
  • net.minecraft.world.phys.shapes.CollisionContext#placementContext now takes in a Player instead of an Entity

List of Removals

  • net.minecraft.client.Minecraft#disconnect(Screen)
  • net.minecraft.client.renderer
    • DimensionSpecialEffects#getCloudHeight, hasGround
    • LevelRenderer#updateGlobalBlockEntities
  • net.minecraft.client.renderer.texture.AbstractTexture
    • defaultBlur
    • setFilter
  • net.minecraft.network.chat.Component$Serializer, $SerializerAdapter
  • net.minecraft.network.protocol.game.ServerboundPlayerCommandPacket$Action#*_SHIFT_KEY
  • net.minecraft.server.ReloadableServerRegistries$Holder#getKeys
  • net.minecraft.server.players.PlayerList#getPlayerForLogin
  • net.minecraft.stats
    • RecipeBookSettings#read, write
    • ServerRecipeBook#toNbt, fromNbt
  • net.minecraft.util
    • GsonHelper#fromNullableJson(..., boolean), fromJson(..., boolean)
    • LowerCaseEnumTypeAdapterFactory
  • net.minecraft.world.entity.ai.attributes.AttributeInstance#ID_FIELD, TYPE_CODEC
  • net.minecraft.world.entity.animal.horse.AbstractHorse#setIsJumping
  • net.minecraft.world.entity.animal.sheep.Sheep#getColor
  • net.minecraft.world.entity.monster.Drowned#waterNavigation, groundNavigation
  • net.minecraft.world.entity.projectile.Projectile#findOwner, setOwnerThroughUUID
  • net.minecraft.world.level.Level#disconnect()
  • net.minecraft.world.level.block
    • AbstractCauldronBlock#isEntityInsideContent
    • TerracottaBlock
  • net.minecraft.world.level.block.entity.trialspawner.TrialSpawner
    • *_CONFIG_TAG_NAME
    • codec
  • net.minecraft.world.level.dimension.DimensionType#parseLegacy

Minecraft 1.21.6 -> 1.21.7 Mod Migration Primer

This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.6 to 1.21.7. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.

This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.

If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.

Pack Changes

There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.

Minor Migrations

The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.

List of Additions

  • com.mojang.blaze3d.opengl.DirectStateAccess#copyBufferSubData - Copies all or part of one buffer object’s data store to the data store of another buffer object.
  • com.mojang.blaze3d.pipeline.BlendFunction#INVERT - Inverts the blend factors of the RGB source and destination. Alpha uses the default one from source and zero from destination.
  • com.mojang.blaze3d.systems.CommandEncoder#copyToBuffer - Copies the data store of one buffer slice to another buffer slice.
  • net.minecraft.Util#isAarch64 - Returns whether the OS architecture uses aarch64.
  • net.minecraft.client.gui.GuiGraphics#textHighlight - Adds a highlighted box around the provided bounds.
  • net.minecraft.client.renderer.RenderPipelines#GUI_INVERT - A render pipeline for drawing a gui element with inverted colors.
  • net.minecraft.client.renderer.item.TrackingItemRenderState - A render state that tracks the model sources being used to render the item stack.

List of Changes

  • com.mojang.blaze3d.pipeline.RenderPipeline$Builder#withColorLogic is now deprecated
  • net.minecraft.client.gui.renderer.GuiRenderer#MIN_GUI_Z is now private
  • net.minecraft.client.gui.render.state.GuiItemRenderState now takes in a TrackingItemRenderState instead of a ItemStackRenderState
    • itemStackRenderState now returns a TrackingItemRenderState
  • net.minecraft.client.renderer.RenderPipelines#GUI_TEXT_HIGHLIGHT now uses the ADDITIVE blend function instead of the OR_REVERSE color logic
  • net.minecraft.client.renderer.item.ItemStackRenderState#getModelIdentity -> TrackingItemRenderState#getModelIdentity

List of Removals

  • net.minecraft.client.renderer.item.ItemStackRenderState#clearModelIdentity

Minecraft 1.21.7 -> 1.21.8 Mod Migration Primer

This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.7 to 1.21.8. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.

This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.

If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.

Pack Changes

There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.

Minor Migrations

The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.

List of Additions

  • com.mojang.blaze3d.GraphicsWorkarounds - A helper for working around issues with specific graphics hardware.

Minecraft 1.21.8 -> 1.21.9 Mod Migration Primer

This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.8 to 1.21.9. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.

This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.

If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.

Thank you to:

  • @Soaryn for pointing out some non-recommended rendering usages
  • @Deximus-Maximus for some typos

Pack Changes

There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.

The Debugging Overhaul

The entirety of the debug system has been completely overhauled, from exposing the internal debugging tools to the debug screen. This documentation aims to provide a high level overview for handling your own debug screen and renderer additions.

Debug Renderers

Vanilla now allows users to see the debug renderers provided by the internal API by enabling them through the JVM properties via -DMC_DEBUG_ENABLED with whatever other desired flags. Users can take advantage of these exposed features to handle their own renderers through the vanilla provided pipeline. This overview will explain via patching the existing renderers and subscribers as needed, but these can generally be set up wherever needed. The benefit vanilla provides is its integration into existing objects (e.g. entities, block entities) and the general synchronization across the network. Of course, you can always use a simple boolean instead. After all, although the flags in SharedConstants are final, they are still checked every tick.

Subscribe to Debuggers

In most cases, information that you want to render and debug are stored on the server side. Sometimes, the information in question will be synced on the client, but in most cases it is usually some kind of partial state only necessary for rendering.

// An example object on the server
public record ExampleObject(Block held, int count) {}

// An example on the client
// Count is not used for rendering, only for server logic
public class ExampleRenderState {
    Block held;
}

Therefore, if we want to see the additional data from the server, we need some method to not only synchronize it to the client, but also update it whenever the value changes. To do so, vanilla provides DebugSubscriptions: a class that stores the information required to sync an object if it has changed. The constructor contains two fields: the StreamCodec to sync the object across the network, and an optional int that, when greater than zero, will purge the synced value from the client if there were no more updates within the specified time.

To handle the logic associated with synchronization, the server makes use of TrackingDebugSynchronizers to handle player listeners and sync the object when necessary, and LevelDebugSynchronizers to handle the general tracking and ticking of the synchronizers. This data is then sent to the ClientDebugSubscriber for storage and the DebugRenderer for rendering. Note that clients can only see the debug information if they are either the owner of a singleplayer world or is an operator of the server. Additionally, the client can only request subscriptions that are added to the set provided by ClientDebugSubscriber#requestedSubscriptions.

DebugSubscriptions must be registered to BuiltInRegistries#DEBUG_SUBSCRIPTION:

public static final DebugSubscription<ExampleObject> EXAMPLE_OBJECt = Registry.register(
    BuiltInRegistries.DEBUG_SUBSCRIPTION
    ResourceLocation.withNamespaceAndPath("examplemod", "example_object"),
    new DebugSubscription<>(
        // The stream codec to sync the example object
        StreamCodec.composite(
            ByteBufCodecs.registry(Registries.BLOCK), ExampleObject::block,
            ByteBufCodecs.VAR_INT, ExampleObject::count,
            ExampleObject::new
        ),
        // The maximum number of ticks between updates
        //   before the data is purged from the client
        // Set to zero if it should never expire
        0
    )
);

To be able to check for updates properly, the object used must correctly implement hashCode and equals, not relying on the object identity.

Debug Sources

So, how do we tell the synchronizer to track and update our DebugSubscription? Well, you can extend TrackingDebugSynchronizer or use its subclasses and implement the tracking and syncing logic yourself, either by patching LevelDebugSynchronizers or creating your own. However, if the data you would like to track is directly attached to a LevelChunk, Entity, or BlockEntity and can be updated from their associated server object, you can make use of the DebugValueSource.

DebugValueSource is a way to register DebugSubscriptions as a TrackingDebugSynchronizer$SourceSynchronizer. This will poll and send updates to every player tracking the source with the subscription enabled every tick. Registering a DebugSubscription is done via DebugValueSource#registerDebugValues, taking in the server level and the $Registration interface. The registration is then handled via $Registration#register by passing in the subscription and a supplier to construct the subscription value.

// Assume we have some ExampleObject exampleObject in the below classes

// For some BlockEntity, Entity, or LevelChunk subclass
@Override
public void registerDebugValues(ServerLevel level, DebugValueSource.Registration registrar) {
    super.registerDebugValues(level, registrar);
    // Register our subscription
    registrar.register(
        // The subscription
        EXAMPLE_OBJECT,
        // The supplied subscription object
        () -> this.exampleObject
    );
}

Rendering the Debug Information

Once the information has been synced to the client and stored within ClientDebugSubscriber (assuming you are using the above method), we now need to render that information to the screen. This is typically handled through DebugRenderer#render, which checks the enabled debug renderers via refreshRendererList before running the associated renderers. Technically, it doesn’t particularly matter where as the data can be obtained at any point in the render process, but this will assume you are patching refreshRendererList to add your own renderer to either the opaque or translucent renderers.

All renderers implement DebugRenderer$SimpleDebugRenderer to call render, which provides the current PoseStack, buffer source, camera XYZ, and Frustum. In addition, vanilla passes in a DebugValueAccess via Connection#createDebugValueAccess to get the synched debug information from the ClientDebugSubscriber. DebugRenderer provides simple methods to render text or boxes in specific locations using render*.

The DebugValueAccess contains two types of methods: get*Value to obtain the debug object for that specific source (e.g. position, entity); and forEach*, which loops through all sources sending out the debug object. Which you use depends on which source you registered your DebugSubscription to.

// We will assume that our example object was registered to an entity
public class ExampleObjectRenderer implements DebugRenderer.SimpleDebugRenderer {

    @Override
    public void render(PoseStack poseStack, MultiBufferSource bufferSource, double x, double y, double z, DebugValueAccess access, Frustum frustum) {
        // Loop through all blocks with our example object
        access.forEachEntity(EXAMPLE_OBJECT, (entity, exampleObject) -> {
            // Render the debug info
            DebugRenderer.renderTextOverMob(
                poseStack, bufferSource, entity,
                // Text Y offset (entities display a lot of information)
                100,
                // Text to render
                "Held Count: " + exampleObject.count(),
                // Text color
                0xFFFFFFFF,
                // The scale of the text
                1f
            );
        });
    }
}

Debug Screens

The debug screens allows for users to to enable, disable, or only show in F3 specific components. This modular system allows for modders to add their own debug entries to the screen. Not all parts of this explanation is accessible without a bit more modding work, so those areas will be specifically pointed out.

DebugScreenEntry

Every debug option has its own entry that either defines what is being displayed (e.g., fps, memory), or no-ops to be handled by a separate implementation (e.g., entity hitboxes, chunk borders). This is known as a DebugScreenEntry, which defines three methods.

First is the category. In vanilla, this is almost always DebugEntryCategory#SCREEN_TEXT, as all a debug entry does is draw text to the screen. The other available option RENDERER is only for no-op as the rendering options always rendered independent from the debug screen. DebugEntryCategory is simply a record with a label and some sort of sort key value, so more can be added by calling the constructor. All the category is used for is searching in the debug options screen.

Next is isAllowed. This method determines whether the debug option should render on the screen independent of the entry status. By default, this is true only when the Minecraft#showOnlyReducedInfo accessibility option is false. Some debug entries override this method to always return true, or if some other check passes.

Finally, there is the display method. This is responsible for drawing the text to the screen using the DebugScreenDisplayer. It also takes in the current Level, client chunk, and server chunk. The DebugScreenDisplayer has four methods that each draw text to the screen. First, there is the standard addLine class, which just adds the string to either the left or right side depending on what element its rendered as. These will always come one right after the other. Then, there is addPriorityLine, which will always be added to the top of either the left or the right side. Finally, there is addToGroup, which takes an additional key to render the lines as one separate group with an extra new line added at the end.

public class ExampleDebugEntry implements DebugScreenEntry {

    public static final ResourceLocation GROUP_ONE = ResourceLocation.fromNamespaceAndPath("examplemod", "group_one");
    public static final ResourceLocation GROUP_TWO = ResourceLocation.fromNamespaceAndPath("examplemod", "group_two");


    @Override
    public void display(DebugScreenDisplayer displayer, @Nullable Level level, @Nullable LevelChunk clientChunk, @Nullable LevelChunk serverChunk) {
        // The following will display like so if it is the only entry on the screen:
        // First left!                                                First Right!
        // 
        // Hello world!                                               Random text!
        // Lorem ipsum.
        //                                                            I am another group!
        // I am one group                                             This will appear after with no line breaks!
        // All in a row
        // Provided in a list.
        //

        displayer.addLine("Hello world!");
        displayer.addLine("Lorem ipsum.");
        displayer.addLine("Random text!");

        // These will be displayed first
        displayer.addPriorityLine("First left!");
        displayer.addPriorityLine("First right!");

        // These will be grouped separately based on the key
        displayer.addToGroup(GROUP_ONE, List.of(
            "I am one group",
            "All in a row",
            "Provided in a list."
        ));

        displayer.addToGroup(GROUP_TWO, "I am another group!");
        displayer.addToGroup(GROUP_TWO, "This will appear after with no line breaks!");
    }

    @Override
    public boolean isAllowed(boolean reducedDebugInfo) {
        // Always show regardless of accessibility option
        return true;
    }
}

Then, simply register your entry to DebugScreenEntries to have it display. It can be toggled on through the debug menu using the provided key

// This method is private, so its access will need to be widened
DebugScreenEntries.register(
    // The id, this will be displayed on the options screen
    ResourceLocation.fromNamespaceAndPath("examplemod", "example_entry"),
    // The screen entry
    new ExampleScreenEntry();
);

External Toggles and Checks

What if you want to toggle the active status separately from the options menu? What if you want to check is an entry is enabled to display debug data in-game? This can be done by accessing the DebugScreenEntryList through the Minecraft instance.

Toggling the current status can be done via DebugScreenEntryList#toggleStatus. How this behaves changes depending on what screen is active. Basically, calling toggle will always flip the debug entry on or off: if it’s not currently on screen, it will render on screen and vice versa. If in F3, then toggling on will only render that debug entry when F3 is on.

The status of the entry can then be checked using DebugScreenEntryList#isCurrentlyEnabled. This will only check if the debug screen is in the currently on list and not check DebugScreenEntry#isAllowed.

// Lets create another entry
public static final ResourceLocation EXAMPLE_TOGGLE = DebugScreenEntries.register(
    ResourceLocation.fromNamespaceAndPath("examplemod", "example_toggle"),
    // We're using noop as nothing is being displayed as text
    new DebugEntryNoop();
);

// To toggle:
Minecraft.getInstance().debugEntries.toggleStatus(EXAMPLE_TOGGLE);

// To check if enabled:
if (Minecraft.getInstance().debugEntries.isCurrentlyEnabled(EXAMPLE_TOGGLE)) {
    // ...
}

Profiles

Profiles are defined presets that can be configured to the user’s desire. Currently, profiles are hardcoded to either default or performance. To extend the system, you need to be able to dynamically add an entry to the DebugScreenProfile enum, make the DebugScreenEntries#PROFILES map mutable to add your profile and preset, and modify the debug option screen with your profile button.

  • net.minecraft.SharedConstants
    • DEBUG_SHUFFLE_MODELS - A flag that likely shuffles the model loading order.
    • DEBUG_FLAG_PREFIX - A prefix put in front of every debug flag.
    • USE_DEBUG_FEATURES -> DEBUG_ENABLED
    • DEBUG_RENDER is removed
    • DEBUG_WORLDGENATTEMPT is removed
    • debugGenerateStripedTerrainWithoutNoise is removed
    • DEBUG_RESOURCE_GENERATION_OVERRIDE is removed
    • DEBUG_POI - Enables the POI debug renderer.
    • DEBUG_PANORAMA_SCREENSHOT - When enabled, allows the user to take a panorama screenshot.
    • DEBUG_CHASE_COMMAND - When enabled, adds the chase command.
    • FAKE_MS_LATENCY -> DEBUG_FAKE_LATENCY_MS
    • FAKE_MS_JITTER -> DEBUG_FAKE_JITTER_MS
    • DEBUG_VERBOSE_COMMAND_ERRORS - When enabled, outputs verbose errors through the chat box.
    • DEBUG_DEV_COMMANDS - When enabled, adds the commands used for debugging the game.
  • net.minecraft.client.Minecraft
    • debugEntries - Returns a list of debug features and what should be shown on screen.
    • fpsString, sectionPath, sectionVisibility are removed
    • debugRenderer -> LevelRenderer#debugRenderer
  • net.minecraft.client.gui.Gui
    • renderDebugOverlay is now public
    • shouldRenderDebugCrosshair is removed
  • net.minecraft.client.gui.components.DebugScreenOverlay
    • drawGameInformation, drawSystemInformation are removed
    • getGameInformation, getSystemInformation are removed
    • toggleOverlay is removed
  • net.minecraft.client.gui.components.debug
    • DebugEntryBiome - A debug entry displaying the biome the camera entity is within.
    • DebugEntryCategory - A category that describes how a debug entry is displayed.
    • DebugEntryChunkGeneration - A debug entry displaying the current chunk generation info.
    • DebugEntryChunkRenderStats - A debug entry displaying the current section statistics.
    • DebugEntryChunkSourceStats - A debug entry displaying the general metadata of the chunk sources.
    • DebugEntryEntityRenderStats - A debug entry displaying the general metadata of the entity storage.
    • DebugEntryFps - A debug entry displaying the frames per second and vsync info.
    • DebugEntryGpuUtilization - A debug entry displaying the GPU utilization.
    • DebugEntryHeightmap - A debug entry displaying the height maps at the current position.
    • DebugEntryLight - A debug entry displaying the client light information.
    • DebugEntryLocalDifficulty - A debug entry displaying the current world difficulty and time.
    • DebugEntryLookingAtBlock - A debug entry displaying the block the camera is currently looking at.
    • DebugEntryLookingAtEntity - A debug entry displaying the entity the camera is currently looking at.
    • DebugEntryLookingAtFluid - A debug entry displaying the fluid the camera is currently looking at.
    • DebugEntryMemory - A debug entry displaying the memory allocated and used by the game.
    • DebugEntryNoop - A debug entry displaying nothing.
    • DebugEntryParticleRenderState - A debug entry displaying the number of particles being rendered.
    • DebugEntryPosition - A debug entry displaying the current position and rotation of the camera entity.
    • DebugEntryPostEffect - A debug entry displaying the currently applied post effect.
    • DebugEntrySectionPosition - A debug entry displaying the current section position.
    • DebugEntrySimplePerformanceImpactors - A debug entry displaying the graphics mod, cloud status, and biome blend radius.
    • DebugEntrySoundMood - A debug entry displaying the current sound played and player mood.
    • DebugEntrySpawnCounts - A debug entry displaying the entity spawn counts per mob category.
    • DebugEntrySystemSpecs - A debug entry displaying the specs of the running machine.
    • DebugEntryTps - A debug entry displaying the general ticks per second.
    • DebugEntryVersion - A debug entry displaying the current Minecraft version.
    • DebugScreenDisplayer - An interface that the debug entries use to display elements to the screen.
    • DebugScreenEntries - The debug entries registered by Minecraft.
    • DebugScreenEntry - An element that shows up, if enabled, when the debug overlay is enabled.
    • DebugScreenEntryList - The options information for what debug elements are displayed on screen.
    • DebugScreenEntryStatus - The status of when a debug entry should be displayed.
    • DebugScreenProfile - An enum denoting the profiles that the debug screen can set when deciding what entries to show.
  • net.minecraft.client.gui.screen.debug.DebugOptionsScreen - A screen that allows the user to change the displayed debug entries for a profile.
  • net.minecraft.client.renderer.LevelRenderer
    • getSectionStatistics is now nullable
    • getEntityStatistics is now nullable
    • gameTestBlockHighlightRenderer - The renderer for the block highlight within a game test.
  • net.minecraft.client.renderer.debug.DebugRenderer
    • switchRenderChunkborder -> DebugScreenEntries#CHUNK_BORDERS, not one-to-one
    • toggleRenderOctree -> DebugScreenEntries#CHUNK_SECTION_OCTREE, not one-to-one
  • net.minecraft.client.multiplayer
    • DebugSampleSubscriber -> ClientDebugSubscriber, not one-to-one
    • ClientPacketListener#createDebugValueAccess - Creates the access to get the current debug values.
  • net.minecraft.client.renderer.debug
    • BeeDebugRenderer#addOrUpdateHiveInfo, addOrUpdateBeeInfo, removeBeeInfo are removed
    • BrainDebugRenderer
      • addPoi, removePoi, $PoiInfo are removed
      • setFreeTicketCount is removed
      • addOrUpdateBrainDump, removeBrainDump are removed
    • BreezeDebugRenderer now implements DebugRenderer$SimpleDebugRenderer
      • render now takes in a DebugValueAccess
      • clear, add are removed
    • DebugRenderer no longer takes in the Minecraft instance
      • All field renderers have been removed from public access, instead being store in on of the *Renderers lists
      • worldGenAttemptRenderer is removed
      • renderTextOverBlock - Renders the given stream above the provided block position.
      • renderTextOverMob - Renders the given string over the provided entity.
      • refreshRendererList - Populates the renderer lists with the enabled debug renderers.
      • render, renderAfterTranslucents have been merged into render, where a boolean determines whether to render the translucent or opaque renderers
      • $SimpleDebugRenderer
        • render now takes in a DebugValueAccess and Frustum
        • clear is removed
    • EntityBlockIntersectionDebugRenderer - A debug renderer for displaying the blocks the entity is intersecting with.
    • GameEventListenerRenderer no longer takes in the Minecraft instance
      • trackGameEvent, trackListener are removed
    • GameTestDebugRenderer -> GameTestBlockHighlightRenderer, not one-to-one
      • addMarker -> highlightPos, not one-to-one
    • GoalSelectorDebugRenderer#addGoalSelector, removeGoalSelector are removed
    • NeighborsUpdateRenderer no longer takes in the Minecraft instance
      • addUpdate is removed
    • OctreeDebugRenderer now implements DebugRenderer$SimpleDebugRenderer
    • PathfindingRenderer#addPath is removed
    • PoiDebugRenderer - A debug renderer for displaying the point of interests.
    • RaidDebugRenderer#setRaidCenters is removed
    • RedstoneWireOrientationsRenderer no longer takes in the Minecraft instance
      • addWireOrientation is removed
    • StructureRenderer no longer takes in the Minecraft instance
      • addBoundingBox is removed
    • VillagerSectionsDebugRenderer#setVillageSection, setNotVillageSection are removed
    • WorldGenAttemptRenderer class is removed
  • net.minecraft.core.registries.BuiltInRegistries, Registries#DEBUG_SUBSCRIPTION - A registry for subscriptions to debug handlers.
  • net.minecraft.gametest.framework
    • GameTestAssertPosException#getMessageToShowAtBlock now returns a Component
    • GameTestRunner#clearMarkers is removed
  • net.minecraft.network.protocol.common.custom
    • All classes have been moved to net.minecraft.util.debug
    • They are no longer payloads, instead just records containing the object info and an associated stream codec
    • If the payload class had an associated object inner class, then that class was moved and the payload class removed
    • Otherwise the payload class was added without the *Payload suffix, most of the time with an *Info suffix
  • net.minecraft.network.protocol.game
    • ClientboundDebugBlockValuePacket - A packet sent to the client about a debug value change on a block position.
    • ClientboundDebugChunkValuePacket - A packet sent to the client about a debug value change on a chunk position.
    • ClientboundDebugEntityValuePacket - A packet sent to the client about a debug value change on an entity.
    • ClientboundDebugEventPacket - A packet sent to the client about the debug event fired.
    • ClientboundGameTestHighlightPosPacket - A packet sent to the client about the game test position to highlight.
    • ClientGamePacketListener
      • handleDebugChunkValue - Handles the debug chunk position packet.
      • handleDebugBlockValue - Handles the debug block position packet.
      • handleDebugEntityValue - Handles the debug entity packet.
      • handleDebugEvent - Handles the firing debug event.
      • handleGameTestHighlightPos - Handles the provided position being highlighted.
    • DebugPackets class is removed
    • ServerboundDebugSampleSubscriptionPacket -> ServerboundDebugSubscriptionRequestPacket, not one-to-one
    • ServerGamePacketListener#handleDebugSampleSubscription -> handleDebugSubscriptionRequest, not one-to-one
  • net.minecraft.server.MinecraftServer
    • subscribeToDebugSample is removed
    • debugSubscribers - Returns a map of the tracked subscriptions to the list of players that have it enabled.
  • net.minecraft.server.level
    • ChunkMap
      • isChunkTracked is now public
      • getChunks is removed
    • ServerLevel#debugSynchronizers - Returns the debugger handler and synchronizer for the level.
    • ServerPlayer
      • requestDebugSubscriptions - Sets the debuggers that the player is listening for.
      • debugSubscriptions - Returns the debuggers that the player is listening for.
  • net.minecraft.util.debug
    • DebugSubscription - A tracked data point that can be listened or subscribed to.
    • DebugSubscriptions - Vanilla debug subscriptions.
    • DebugValueAccess - Accesses the values tracked by the debug subscription, used on the client for the debug renderers.
    • DebugValueSource - Defines a source object that provides debug values to track, such as an entity.
    • LevelDebugSynchronizers - Handles sending the subscription data across the network to the tracking clients.
    • ServerDebugSubscribers - Handles the global state of players subscribed to the currently enabled subscriptions.
    • TrackingDebugSynchronizer - Handles the list of players subscribed to a subscription.
  • net.minecraft.util.debugchart
    • DebugSampleSubscriptionTracker class is removed
    • RemoteDebugSampleType now takes in a DebugSubscription
      • subscription - Returns the subscription reported by the sample type.
    • RemoteSampleLogger now takes in ServerDebugSubscribers instead of DebugSampleSubscriptionTracker
  • net.minecraft.world.entity
    • Entity now implements DebugValueSource
    • Mob#sendDebugPackets is removed
  • net.minecraft.world.entity.ai.village.poi
    • PoiManager#getFreeTickets -> getDebugPoiInfo, not one-to-one
    • PoiSection#getDebugPoiInfo - Returns the debug poi info for the given position.
  • net.minecraft.world.level.block.entity
    • BlockEntity now implements DebugValueSource
    • TestInstanceBlockEntity#markError, clearErrorMarkers, getErrorMarkers, $ErrorMarker - Handles the error markers set by the test instance.
  • net.minecraft.world.level.chunk.LevelChunk now implements DebugValueSource
  • net.minecraft.world.level.pathfinder.PathFinder#setCaptureDebug - Sets whether the path should be captured for debugging.
  • net.minecraft.world.level.redstone.CollectingNeighborUpdater#setDebugListener - Sets the listener for block location changes for debugging.

Feature Submissions: The Movie

The entirety of the rendering pipeline, from entities to block entities to particles, has been reworked into a submission / render phase system known as features. This guide will go over the basics of the feature system itself followed by how each major type are implemented using it.

Submission and Rendering

The feature system, like GUIs, is broken into two phases: submission and rendering. The submission phase is handled by the SubmitNodeCollector, which basically collects the data required to abstractly render an object to the screen. This is all done through the submit* methods, which generally take a PoseStack to place the object in 3D space, and any other required data such as the model, state, render type, etc.

Here is a quick overview of what each method takes in:

MethodParameters
submitHitboxA pose stack, render state of the entity, and the hitboxes render state
submitShadowA pose stack, the shadow radius, and the shadow pieces
submitNameTagA pose stack, an optional position, the Y offset, the text component, if the text should be seethrough (like when sneaking), light coordinates, and the camera render state
submitTextA pose stack, the XY offset, the text sequence, whether to add a drop shadow, the font display mode, light coordinates, color, background color, and outline color
submitFlameA pose stack, render state of the entity, and a rotation quaternion
submitLeashA pose stack and the leash state
submitModelA pose stack, entity model, render state, render type, light coordinates, overlay coordinates, tint color, an optional texture, outline color, and an optional crumbling overlay
submitModelPartA pose stack, model part, render type, light coordinates, overlay coordinates, an optional texture, whether to use item glint over entity glint if render type is not transparent, whether to render the glint overlay, tint color, an optional crumbling overlay, and an outline color
submitBlockA pose stack, block state, light coordinates, overlay coordinates, and outline color
submitMovingBlockA pose stack and the moving block render state
submitBlockModelA pose stack, the render type, block state model, RGB floats, light coordinates, overlay coordinates, and outline color
submitItemA pose stack, item display context, light coordinates, overlay coordinates, outline color, tint layers, quads, render type, and foil type
submitCustomGeometryA pose stack, render type, and a function that takes in the current pose and VertexConsumer to create the mesh
submitParticleGroupA SubmitNodeCollector$ParticleGroupRenderer

Technically, the submit* methods are provided by the OrderedSubmitNodeCollector, of which the SubmitNodeCollector extends. This is because features can be submitted to different orders, which function similarly to strata in GUIs. By default, all submit calls are pushed onto order 0. Using SubmitNodeCollector#order with some integer and then calling the submit* method, you can have an object render before or after all features on a given order. This is stored as an AVL tree, where each order’s data is stored in a SubmitNodeCollection. With the current default feature rendering order, this is only used in very specific circumstances, such as rendering a slime’s outer body or equipment layers.

// Assume we have access to the `SubmitNodeCollector` collector

// This will render in order 0
collector.submitModel(...);

// This will render before the `submitModel` call
collector.order(-1).submitShadow(...);

// This will render after the `submitModel` call
collector.order(1).submitNameTag(...);

The render phase is handled through the FeatureRenderDispatcher, which renders the object using their submitted feature renderers. What are feature renderers? Quite literally an arbitrary method that loops through the node contents its going to push to the buffer. Currently, for a given order, the features push their vertices like so: shadows, models, model parts, flame animations, entity name tags, arbitrary text, hitboxes, leashes, items, blocks, custom render pipelines, and finally particles. Each order, starting from the smallest number to the largest, will rerun all of the feature renders until it reaches the end of the tree. All submissions are then cleared for next use.

Most of the feature dispatchers are simply run a loop over its collection. Those that store the render type batch the render calls into one buffer. ModelFeatureRenderer, meanwhile, goes one step further, sorting its translucent models by distance from the camera and sends them to the buffer after all opaque models.

Entity Models

So, how does this affect entities? Let’s start with the root Model that makes up all entity models. Model now has a generic which is used to pass in the state of the backing object to setupAnim, which has also been moved to Model. This means that the base model class is rarely passed around, instead opting for some subtype, like Model$Simple for signs. Given that most EntityModels already require a generic of EntityRenderState, this does not affect anything.

The main change comes from how model part visibility work, such as armors and capes. Every single individual part (e.g. helmet, chestplate) now has their own separate model, meaning that the general part visibility system has been completely removed. You can still provide visibility through the mutable model part in setupAnim, but the general movement is to simply have parts that should be separate models as separate models.

To facilitate this, PartDefinitions now has methods to selectively keep certain parts of models and remove the others. This is done through the clear* and retain* methods. Basically, all of these methods are doing are keeping the part pose while removing any cubes associated with the children queries. retain* allows for certain parts and potentially subparts to keep their cubes. This addition provides a twofold benefit: model layers can deterministically use setupAnim to setup the parts similarly to the base model, and the model texture will only need to contain the retained elements.

Here is an example for creating the armor models for a creeper:

// Deformations for humanoid armor
private static final CubeDeformation OUTER_ARMOR_DEFORMATION = new CubeDeformation(1.0F);
private static final CubeDeformation INNER_ARMOR_DEFORMATION = new CubeDeformation(0.5F);

// Creeper has the following parts:
// - head
// - body
// - right_hind_leg, left_hind_leg
// - right_front_leg, left_front_leg

// We use separate meshes as we are basically isolating the parts we want to keep in each

public static ArmorModelSet<MeshDefinition> createCreeperArmor() {
    // Helmet

    // Create mesh
    MeshDefinition helmetMesh = CreeperModel.createBodyLayer(OUTER_ARMOR_DEFORMATION);
    // Only retain the desired parts
    // Note that body and the legs still exist, they simply have no cubes
    helmetMesh.getRoot().retainExactParts(Set.of("head"));

    // Chestplate

    // Create mesh
    var chestplateMesh = CreeperModel.createBodyLayer(OUTER_ARMOR_DEFORMATION);
    // Only retain the desired parts
    chestplateMesh.getRoot().retainExactParts(Set.of("body"));

    // Leggings

    // Create mesh
    var leggingsMesh = CreeperModel.createBodyLayer(INNER_ARMOR_DEFORMATION);
    // Only retain the desired parts
    leggingsMesh.getRoot().retainExactParts(Set.of("right_hind_leg", "left_hind_leg", "right_front_leg", "left_front_leg"));

    // Boots

    // Create mesh
    var bootsMesh = CreeperModel.createBodyLayer(OUTER_ARMOR_DEFORMATION);
    // Only retain the desired parts
    bootsMesh.getRoot().retainExactParts(Set.of("right_hind_leg", "left_hind_leg", "right_front_leg", "left_front_leg"));

    // Store this all in an ArmorModelSet, which is basically just object holder and mapper
    return new ArmorModelSet<>(
        helmetMesh,
        chestplateMesh,
        leggingsMesh,
        bootsMesh
    );
}

// To register the layer definitions, basically the same process of using the ArmorModelSet
public static final ArmorModelSet<ModelLayerLocation> CREEPER_ARMOR = new ArmorModelSet<>(
    new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "creeper"), "helmet"),
    new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "creeper"), "chestplate"),
    new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "creeper"), "leggings"),
    new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "creeper"), "boots")
);

// In some method where you have access to the Map<ModelLayerLocation, LayerDefinition> builder
ArmorModelSet<LayerDefinition> creeperArmorLayers = createCreeperArmor().map(mesh -> LayerDefinition.create(mesh, 64, 32));
CREEPER_ARMOR.putFrom(creeperArmorLayers, builder);

Entity Renderer

With the change to submission, the EntityRenderer and its associated RenderLayers have also changed. Basically, you can assume almost every method that has the word render has been changed to submit, and MultiBufferSource and light coordinates integer have generally been replaced by SubmitNodeCollector and the associated entity render state.

The new submit method that replaces render in EntityRenderer now takes in the render state of the entity, the PoseStack, the SubmitNodeCollector, and the CameraRenderState. When submitting any element, the location in 3D space is taken by getting the last pose on the PoseStack and storing that for future use.

// A basic entity renderer

// We will assume all the classes listed exist
public class ExampleEntityRenderer extends MobRenderer<ExampleEntity, ExampleEntityRenderState, ExampleModel> {

    public ExampleEntityRenderer(EntityRendererProvider.Context ctx) {
        super(ctx, ctx.bakeLayer(EXAMPLE_MODEL_LAYER), 0.5f);
    }

    @Override
    public void submit(ExampleEntityRenderState renderState, PoseStack poseStack, SubmitNodeCollector collector, CameraRenderState cameraState) {
        super.submit(renderState, poseStack, collector, cameraState);

        // An example of submitting something
        collector.submitCustomGeometry(
            poseStack, // The current pose
            RenderType.solid(), // The render type to use
            ExampleEntityRenderer::addVertices // The method to write the geometry data
        );
    }

    private static void addVertices(PoseStack.Pose pose, VertexConsumer consumer) {
        // Add custom geometry
    }
}

// A render layer

public class CreeperArmorLayer extends RenderLayer<CreeperRenderState, CreeperModel> {

    private final ArmorModelSet<CreeperModel> modelSet;
    private final EquipmentLayerRenderer equipment;

    public CreeperArmorLayer(RenderLayerParent<CreeperRenderState, CreeperModel> parent, ArmorModelSet<CreeperModel> modelSet, EquipmentLayerRenderer equipment) {
        super(parent);
        this.modelSet = modelSet;
        this.equipment = equipment;
    }

    // We will assume we added headEquipment, chestEquipment, legsEquipment, feetEquipment to the CreeperRenderState somehow
    @Override
    public void submit(PoseStack poseStack, SubmitNodeCollector collector, int lightCoords, CreeperRenderState renderState, float yRot, float xRot) {
        this.renderArmorPiece(poseStack, collector, renderState.chestEquipment, EquipmentSlot.CHEST, lightCoords, renderState);
        this.renderArmorPiece(poseStack, collector, renderState.legsEquipment,  EquipmentSlot.LEGS,  lightCoords, renderState);
        this.renderArmorPiece(poseStack, collector, renderState.feetEquipment,  EquipmentSlot.FEET,  lightCoords, renderState);
        this.renderArmorPiece(poseStack, collector, renderState.headEquipment,  EquipmentSlot.HEAD,  lightCoords, renderState);
    }

    // Taken from humanoid armor layer
    private void renderArmorPiece(PoseStack poseStack, SubmitNodeCollector collector, ItemStack stack, EquipmentSlot slot, int lightCoords, CreeperRenderState renderState) {
        Equippable equippable = stack.get(DataComponents.EQUIPPABLE);
        if (equippable != null && equippable.assetId().isPresent() && equippable.slot() == slot) {
            CreeperModel model = this.modelSet.get(slot);
            EquipmentClientInfo.LayerType layer = slot == EquipmentSlot.LEGS
                ? EquipmentClientInfo.LayerType.HUMANOID_LEGGINGS
                : EquipmentClientInfo.LayerType.HUMANOID;
            this.equipmentRenderer.renderLayers(
                layer, // The equipment layer to use
                equippable.assetId().orElseThrow(), // The equipment asset to pull
                model, // The armor model
                renderState, // The entity render state
                stack, // The armor stack
                poseStack, // The pose stack
                collector, // The collector to add the model data to
                lightCoords, // The light coordinates
                renderState.outlineColor // The outline color of the entity
            );
        }
    }
}

// Then, to add it to the creeper renderer constructor
public CreeperRenderer(EntityRendererProvider.Context ctx) {
    // ...
    this.addLayer(new CreeperArmorLayer(
        this, // The parent is the renderer itself
        ArmorModelSet.bake( // Baking the model set
            CREEPER_ARMOR, // The model layer locations
            ctx.getModelSet(), // The model set to map the models from the layer locations
            CreeperModel::new // The mapper for the root part to the model
        ),
        ctx.getEquipmentRenderer() // The renderer for the equipment
    ));
}

Block Entity Renderer

BlockEntityRenderers also use the new submission method, replacing almost every render* with submit. They have taken a play from entities, now having their own BlockEntityRenderState which is extracted from the BlockEntity. As such, BlockEntityRenderer now has a new generic S for the BlockEntityRenderState.

The BlockEntityRenderState, by default, contains information about its position, block state, type, light coordinates, and the current break progress as a ModelFeatureRenderer$CrumblingOverlay. These are all populated through BlockEntityRenderState#extractBase, which is called in BlockEntityRenderer#extractRenderState. Like entities, the render state is first constructed via BlockEntityRenderer#createRenderState before the values are extracted from the block entity. extractRenderState does contain the partial tick and camera position, but this is not passed to the BlockEntityRenderState by default.

As such, the submit method that takes over the render method takes in the render state, a PoseStack for the location in 3D space, the SubmitNodeCollector for pushing the elements to render, and the CameraRenderState.

// We will assume all the classes not specified here exist

// A simple render state
public class ExampleRenderState extends BlockEntityRenderState {
    public float partialTick;
}

// A basic block entity renderer
public class ExampleBlockEntityRenderer implements BlockEntityRenderer<ExampleBlockEntity, ExampleRenderState> {

    public ExampleBlockEntityRenderer(BlockEntityRendererProvider.Context ctx) {
        // Get anything you need from the context
    }

    @Override
    public ExampleRenderState createRenderState() {
        // Create the render state used to submit the block entity to the feature renderer
        return new ExampleRenderState();
    }

    @Override
    public void extractRenderState(ExampleBlockEntity blockEntity, ExampleRenderState renderState, float partialTick, Vec3 cameraPos, @Nullable ModelFeatureRenderer.CrumblingOverlay crumblingOverlay) {
        // Extract the necessary rendering values from the block entity to the render state
        // Always call super or BlockEntityRenderState#extractBase
        super.extractRenderState(blockEntity, renderState, partialTick, cameraPos, crumblingOverlay);

        // Populate any desired values
        renderState.partialTick = partialTick;
    }


    @Override
    public void submit(ExampleRenderState renderState, PoseStack poseStack, SubmitNodeCollector collector, CameraRenderState cameraState) {
        // An example of submitting something
        collector.submitModel(..., renderState.breakProgress);
    }
}

Special Item Models

Since special item models also make use of custom rendering, they have been updated to with the submit change, only replacing MultiBufferSource with the SubmitNodeCollector.

// A basic special item model

// We will assume all the classes listed exist
public class ExampleSpecialModelRenderer implements NoDataSpecialModelRenderer {

    public ExampleSpecialModelRenderer() {}

    @Override
    public void submit(ItemDisplayContext displayContext, PoseStack poseStack, SubmitNodeCollector collector, int lightCoords, int overlayCoords, boolean hasFoil, int outlineColor) {
        // An example of submitting something
        collector.submitModelPart(...);
    }

    @Override
    public void getExtents(Set<Vector3f> extents) {}
}

Particles

Particles have been added to the submission process; however, there are multiple paths depending on how complicated your particle is. A few classes and general names have been reused for an additional purpose as well, sometimes making it difficult to understand how each part works. As such, this document will go over two methods of creating a particle: one more familiar with the old system, and one that explains the underlying nuances from the ground up.

The Separation of Engines and Resources

Before we discuss the two methods, first, let’s go with the overarching changes. ParticleEngine has been functionally split up into two classes: ParticleEngine, which handle the actual ticking and extraction, not submission, of the render state; and ParticleResources, which is the reload listener that registers the ParticleProvider and optionally ParticleResources$SpriteParticleRegistration and reloads the SpriteSet from its ParticleDescription. This underlying behavior hasn’t change (besides the whole extract and submission process), the methods have simply been moved.

ParticleProvider#createParticle also now provides a RandomSource, which can be used as needed.

As for the actual submission and rendering process, this is handled outside of ParticleEngine. More specifically, the LevelRenderer extracts all the particles to submit in ParticlesRenderState via ParticleEngine#extract. Then, in LevelRenderer#addParticlesPass, the resource handles are set to the particle FramePass, to which on execution the particles are submitted via ParticlesRenderState#submit and then rendered through the feature dispatcher via ParticleFeatureRenderer.

A Single Quad

Many particles in the old system were simply made up of a single quad with a texture(s) slapped on it. These particles are SingleQuadParticles, which merges both the previous SingleQuadParticle and TextureSheetParticle into one. The SingleQuadParticle now takes in an initial TextureAtlasSprite to set the first texture, which can then be updated by overriding Particle#tick and calling SingleQuadParticle#setSpriteFromAge for a SpriteSet or directly with setSprite. The tint can also be modified in the tick using setColor and setAlpha. Some also set these directly in SingleQuadParticle#extract, but which to use depends on if you need to override the entire tick or not.

To determine the RenderType that is used to render the quad, SingleQuadParticle#getLayer must be set to the desired $Layer. A $Layer is basically a record defining whether the quad can have translucency, what texture atlas it pulls from, and the render pipeline to use. Vanilla provides TERRAIN, OPAQUE, and TRANSLUCENT similar to the old Particle#getRenderType which it replaces. TERRAIN and TRANSLUCENT both allow transparency, and OPAQUE and TRANSLUCENT pull from the particle atlas while TERRAIN uses the block atlas. A custom $Layer can be created using the constructor.

public static final SingleQuadParticle.Layer EXAMPLE_LAYER = new SingleQuadParticle.Layer(true, TextureAtlas.LOCATION_PARTICLES, RenderPipelines.WEATHER_DEPTH_WRITE);

In addition to all this, you can also set how the particle is rotated by overriding SingleQuadParticle#getFacingCameraMode. $FacingCameraMode is a functional interface that sets the rotation of the particle whenever it is extracted. By default, this means that the texture will always face the camera. Any other method changes and additions are in the list below.

From there, everything else is the same to create the ParticleProvider and register it.

// We will assume we have some SimpleParticleType EXAMPLE_QUAD for our particle
// Additionally, we will assume there is some particle description with our textures to use
public class ExampleQuadParticle extends SingleQuadParticle {

    private final SpriteSet spriteSet;

    // This can be package-private, protected, or public
    // public should be used if the particle will be constructed outside of the provider
    ExampleQuadParticle(ClientLevel level, double x, double y, double z, SpriteSet spriteSet) {
        // We use first to set the initial particle texture
        super(level, x, y, z, spriteSet.first());
    }

    @Override
    public void tick() {
        super.tick();
        // Update the particle image
        this.setSpriteFromAge(spriteSet);
    }

    @Override
    public SingleQuadParticle.Layer getLayer() {
        return EXAMPLE_LAYER;
    }

    // Create the provider
    public static class Provider implements ParticleProvider<SimpleParticleType> {

        private final SpriteSet spriteSet;

        public Provider(SpriteSet spriteSet) {
            this.spriteSet = spriteSet;
        }

        @Override
        public Particle createParticle(SimpleParticleType options, ClientLevel level, double x, double y, double z, double xd, double yd, double zd, RandomSource random) {
            // Create the particle
            return new ExampleQuadParticle(level, x, y, z, this.spriteSet);
        }
    }
}

// Register the provider to `ParticleResources#register`
// Assume access to ParticleResources resources and register has been made public
resources.register(EXAMPLE_QUAD, ExampleQuadParticle.Provider::new);

From the Ground Up

What about rendering some more complex or custom? Well, in those instances, we need to take a deeper dive into how particles are extracted by the ParticleEngine. The Particle class, by itself actually does no extraction, submission, or rendering itself. It simply handles the physics update every tick. The actual extraction logic is handled through a ParticleGroup, while the submission is handled by a ParticleGroupRenderState.

So, what is a ParticleGroup? Well, as the name implies, a particle group holds a group of particles and is responsible for keeping track of, ticking, and extracting the render state of its particles. The generic represents the type of Particle it can keep track of up to the maximum of 16,384 per group (though individual particles can set their own subgroup limit via Particle#getParticleLimit). All SingleQuadParticles are part of the QuadParticleGroup. To extract the render state, the ParticleEngine calls ParticleGroup#extractRenderState, which takes in the current frustum, camera, and partial tick to return a ParticleGroupRenderState.

ParticleGroupRenderState is sort of a mix between a render state, submission handler, and cache. It contains two methods: submit, which takes in the SubmitNodeCollector and submits the group; and clear, which clears all previous cached particle states. Technically, anything can be submitted using the collector, but particles have SubmitNodeCollector$ParticleGroupRenderer: an additional utility to help with caching and rendering. The group renderer contains two methods: prepare, to write the mesh data to a ring buffer; and render, which typically uses the cached buffer to write the data to the shared sequential buffer using the provided RenderPass and draw it to the screen. Only QuadParticleRenderState makes use of the cache and ParticleGroupRenderer as the render states are currently cleared immediately after rendering.

To link the ParticleGroup to a Particle for use, we must set the ParticleRenderType using Particle#getGroup. ParticleRenderType, unlike the previous version, is simply a key for a ParticleGroup. This key is mapped to the group via ParticleEngine#createParticleGroup, and the submission/render order is determined by ParticleEngine#RENDER_ORDER. Both the method and the list must be patched for the particle to be properly managed by your group and extracted for submission.

// We will assume we have some SimpleParticleType EXAMPLE_ONE, EXAMPLE_TWO for our particles
// This example with construct two particles with the same base type to show how the group works

// Create the particle type
public static final ParticleRenderType EXAMPLE_TYPE = new ParticleRenderType("examplemod:example_type");

// Create our particles
public abstract class ExampleParticle extends Particle {

    // You can handle passing to the particle group however you want
    // Making the fields accessible or having a dedicated method
    public final Model<Unit> model;

    protected ExampleParticle(ClientLevel level, double x, double y, double z, Function<EntityModelSet, Model<Unit>> modelFactory) {
        super(level, x, y, z);
        this.model = modelFactory.apply(Minecraft.getInstance().getEntityModels());
    }

    @Override
    public ParticleRenderType getGroup() {
        // Set the particle type to our group
        return EXAMPLE_TYPE;
    }

    @FunctionalInterface
    public interface ExampleParticleFactory<P extends ExampleParticle> {
        
        P create(ClientLevel level, double x, double y, double z);
    }

    protected static <P extends ExampleParticle> ParticleProvider<SimpleParticleType> createProvider(ExampleParticleFactory<P> factory) {
        return (options, level, x, y, z, xd, yd, zd, random) -> factory.create(level, x, y, z);
    }
}

public class ExampleOneParticle extends ExampleParticle {

    ExampleOneParticle(ClientLevel level, double x, double y, double z) {
        super(level, x, y, z, modelSet -> new Model.Simple(new ModelPart(Collections.emptyList(), Collections.emptyMap()), RenderType::entityCutoutNoCull));
    }

    public static ParticleProvider<SimpleParticleType> provider() {
        return ExampleParticle.createProvider(ExampleOneParticle::new);
    }
}

public class ExampleTwoParticle extends ExampleParticle {

    private static final ParticleLimit LIMIT = new ParticleLimit(5);

    ExampleTwoParticle(ClientLevel level, double x, double y, double z) {
        super(level, x, y, z, modelSet -> new Model.Simple(new ModelPart(Collections.emptyList(), Collections.emptyMap()), RenderType::entityCutoutNoCull));
    }

    @Override
    public Optional<ParticleLimit> getParticleLimit() {
        // Limits the number of particles using the LIMIT subgroup to 5
        // Note that since ParticleLimit is a record, any with the same limit will be considered as the same key
        return Optional.of(LIMIT);
    }

    public static ParticleProvider<SimpleParticleType> provider() {
        return ExampleParticle.createProvider(ExampleTwoParticle::new);
    }
}

// Register the providers to `ParticleResources#register`
// Assume access to ParticleResources resources and register has been made public
resources.register(EXAMPLE_ONE, ExampleOneParticle.provider());
resources.register(EXAMPLE_TWO, ExampleTwoParticle.provider());

// Create the render state to submit all particles in the group
// Store whatever you need to submit to the node collector
public record ExampleGroupRenderState(List<Model<Unit>> models) implements ParticleGroupRenderState {

    @Override
    public void submit(SubmitNodeCollector collector) {
        // Submit every particle 
        for (var model : this.models) {
            collector.submitModel(model, ...);
        }
    }
}

// Create the particle group to keep track of the particles and create the render state
// Both EXAMPLE_ONE and EXAMPLE_TWO will be added to this group
public class ExampleParticleGroup extends ParticleGroup<ExampleParticle> {

    public ExampleParticleGroup(ParticleEngine engine) {
        super(engine);
    }

    @Override
    public ParticleGroupRenderState extractRenderState(Frustum frustum, Camera camera, float partialTick) {
        // Create the particle group to submit the particles
        return new ExampleGroupRenderState(
            this.particles.stream().map(particle -> particle.model).toList()
        );
    }
}

// Link the ParticleRenderType to its ParticleGroup
// Assume we have access to ParticleEngine engine
// Assume that ParticleEngine#RENDER_ORDER is made mutable and public
// Assume we can patch ParticleEngine#createParticleGroup
engine.RENDER_ORDER.add(EXAMPLE_TYPE);

// In ParticleEngine
private ParticleGroup<?> createParticleGroup(ParticleRenderType renderType) {
    if (renderType == EXAMPLE_TYPE) {
        // this is referring to the ParticleEngine
        return new ExampleParticleGroup(this);
    }
    // ...
}

Atlas Handler Consolidation

The atlas handler has had some of its logic modified to consolidate other sprites and change how to obtain a TextureAtlasSprite.

First, map decorations, paintings, and GUI sprites are now proper atlases with their own sheets: Sheets#MAP_DECORATIONS_SHEET, PAINTINGS_SHEET, and GUI_SHEET respectively.

Obtaining the TextureAtlasSprite from said sheets are now completely routed through the MaterialSet: a functional interface that takes in a Material (basically a sheet location and texture location), and returns the associated TextureAtlasSprite. The MaterialSet handles texture grabs for item models, block entity renderers, and entity renderers:

// Here is an example material to grab the apple texture from the appropriate sheet
public static final Material APPLE = new Material(
    TextureAtlas.LOCATION_BLOCKS, // The sheet where the item textures are stored
    ResourceLocation.fromNamespaceAndPath("minecraft", "item/apple") // The texture name according to the sprite contents
);
// You can also do the same using Sheets.ITEMS_MAPPER.defaultNamespaceApply("apple")

// For some item model
public class ExampleUnbakedItemModel implements ItemModel.Unbaked {
    
    // ...

    @Override
    public ItemModel bake(ItemModel.BakingContext ctx) {
        TextureAtlasSprite appleTexture = ctx.materials().get(APPLE);
        // ...
    }
}

// For some special item model
public class ExampleUnbakedSpecialModel implements SpecialModelRenderer.Unbaked {
    
    // ...

    @Override
    @Nullable
    public SpecialModelRenderer<?> bake(SpecialModelRenderer.BakingContext ctx) {
        TextureAtlasSprite appleTexture = ctx.materials().get(APPLE);
        // ...
    }
}

// For some block entity renderer
public class ExampleBlockEntityRenderer implements BlockEntityRenderer<ExampleBlockEntity> {

    public ExampleBlockEntityRenderer(BlockEntityRendererProvider.Context ctx) {
        TextureAtlasSprite appleTexture = ctx.materials().get(APPLE);
        // ...
    }

    // ...
}


// For some entity renderer
public class ExampleEntityRenderer implements EntityRenderer<ExampleEntity, ExampleEntityState> {

    public ExampleEntityRenderer(EntityRendererProvider.Context ctx) {
        TextureAtlasSprite appleTexture = ctx.getMaterials().get(APPLE);
        // ...
    }

    // ...
}
  • assets/minecraft/shaders/core
    • blit_screen.json -> screenquad.json, using no-format triangles instead of positioned quads
    • position_color_lightmap.* are removed
    • position_color_tex_lightmap.* are removed
  • com.mojang.blaze3d.vertex
    • CompactVectorArray - An holder that smashes a list of float vectors into a single sequential array.
    • MeshData$SortState#centroids now returns a CompactVectorArray
    • VertexSorting
      • byDistance now takes in a Vector3fc instead of a Vector3f
      • sort now takes in a CompactVectorArray instead of a Vector3f[]
  • net.minecraft.client.Minecraft
    • getTextureAtlas -> AtlasManager#getAtlasOrThrow, not one-to-one
    • getPaintingTextures, getMapDecorationTextures, getGuiSprites -> getAtlasManager, not one-to-one
  • net.minecraft.client.animation.Keyframe now has an overload that takes in the preTarget and postTarget instead of one simple target, taking in a Vector3fc instead of a Vector3f
  • net.minecraft.client.entity
    • ClientAvatarEntity - The client data of the avatar.
    • ClientAvatarState - The movement state of the avatar.
    • ClientMannequin - The client version of the Mannequin entity.
  • net.minecraft.client.gui
    • GuiGraphics
      • renderOutline -> submitOutline
      • renderDeferredTooltip -> renderDeferredElements, not one-to-one
      • submitBannerPatternRenderState now takes in a BannerFlagModel instead of a ModelPart GuiSpriteManager class is removed
  • net.minecraft.client.gui.render.GuiRenderer now takes in the SubmitNodeCollector and FeatureRenderDispatcher
    • MIN_GUI_Z is now public
  • net.minecraft.client.gui.render.pip
    • GuiBannerResultRenderer now takes in a MaterialSet
    • GuiSignRenderer now takes in a MaterialSet
  • net.minecraft.client.gui.render.state.TiledBlitRenderState - A render state for building a sprite using tiling, usually for tile or nine slice textures.
  • net.minecraft.client.gui.render.state.pip.GuiBannerResultRenderState now takes in a BannerFlagModel instead of a ModelPart
  • net.minecraft.client.model
    • AbstractPiglinModel#createArmorMeshSet - Creates the model meshes for each of the humanoid armor slots.
    • ArmedModel now has a generic of the EntityRenderState
      • translateToHand now takes in the entity render state
    • ArmorStandArmorModel#createBodyLayer -> createArmorLayerSet, not one-to-one
    • BellModel$State - Represents the state of the backing object.
    • BookModel$State - Represents the state of the backing object.
    • BreezeModel
      • createBodyLayer -> createBaseMesh, now private
        • Replaced by createBodyLayer, createWindLayer, createEyesLayer
    • CopperGolemModel - A model for the copper golem entity.
    • CopperGolemStatueModel - A model for the coper golem statue.
    • CreakingModel
      • NO_PARTS, getHeadModelParts are removed
      • createEyesLayer - Creates the eyes of the model.
    • EntityModel#setupAnim -> Model#setupAnim
    • GuardianParticleModel - The particle spawned from a guardian.
    • HeadedModel#translateToHead - Transforms the pose stack to the head’s position and rotation.
    • HumanoidArmorModel -> HumanoidModel#createArmorMeshSet, not one-to-one
    • HumanoidModel#copyPropertiesTo is removed
    • Model now takes in a generic representing the render state
    • PlayerCapeModel now extends PlayerModel
    • PlayerEarsModel now extends PlayerModel
    • PlayerModel render state has been broadened to AvatarRenderState
      • Static fields are now protected
      • createArmorMeshSet - Creates the model meshes for each of the humanoid armor slots.
    • SkullModelBase$State - Represents the state of the backing object.
    • SpinAttackEffectModel generic has been broadened to AvatarRenderState
    • VillagerLikeModel now takes in a generic for the render state
      • hatVisible is removed
        • Replaced by VillagerModel#createNoHatModel
      • translateToArms now takes in the render state
    • WardenModel
      • createTendrilsLayer, createHeartLayer, createBioluminescentLayer, createPulsatingSpotsLayer - Creates the layers used by the warden’s RenderLayers.
      • getTendrilsLayerModelParts, getHeartLayerModelParts, getBioluminescentLayerModelParts, getPulsatingSpotsLayerModelParts are removed
    • ZombieVillagerModel
      • createArmorLayer -> createArmorLayerSet, not one-to-one
      • createNoHatLayer - Creates the model without the hat layer.
  • net.minecraft.client.model.geom.ModelPart
    • copyFrom is removed
    • $Polygon#normal is now a Vector3fc instead of a Vector3f
    • $Vertex
      • pos -> x, y, z
      • worldX, worldY, worldZ - Returns the coordinates scaled down by a factor of 16.
  • net.minecraft.client.model.geom.builders.PartDefinition
    • clearRecursively - Clears all children parts and its sub-children.
    • retainPartsAndChildren - Retains the specified parts from its root and any sub-children.
    • retainExactParts - Retains only the top level part, clearing out all others and sub-children.
  • net.minecraft.client.particle
    • AttackSweepParticle now extends SingleQuadParticle
    • BaseAshSmokeParticle now extends SingleQuadParticle and is abstract
    • BlockMarker now extends SingleQuadParticle
    • BreakingItemParticle now extends SingleQuadParticle
      • The constructor takes in a TextureAtlasSprite instead of the ItemStackRenderState
      • $ItemParticleProvider#calculateState -> getSprite, not one-to-one
    • BubbleColumnUpParticle now extends SingleQuadParticle
    • BubbleParticle now extends SingleQuadParticle
    • BubblePopParticle now extends SingleQuadParticle
    • CampfireSmokeParticle now extends SingleQuadParticle
    • CritParticle now extends SingleQuadParticle
    • DragonBreathParticle now extends SingleQuadParticle
      • $Provider generic now uses a PowerParticleOption
    • DripParticle now extends SingleQuadParticle and takes in a TextureAtlasSprite
      • create*Particle methods -> $*Provider classes
    • DustParticleBase now extends SingleQuadParticle
    • ElderGuardianParticleGroup - The particle group responsible for setting up and submitting the elder guardian particle.
    • ExplodeParticle now extends SingleQuadParticle
    • FallingDustParticle now extends SingleQuadParticle
    • FallingLeavesParticle now extends SingleQuadParticle and takes in a TextureAtlasSprite instead of a SpriteSet
    • FireflyParticle now extends SingleQuadParticle and takes in a TextureAtlasSprite
    • FireworkParticles
      • $FlashProvider generic now uses ColorParticleOption
      • $OverlayParticle now extends SingleQuadParticle and takes in a TextureAtlasSprite
    • FlameParticle now takes in a TextureAtlasSprite
    • FlyStraightTowardsParticle now extends SingleQuadParticle and takes in a TextureAtlasSprite
    • FlyTowardsPositionParticle now extends SingleQuadParticle and takes in a TextureAtlasSprite
    • GlowParticle now extends SingleQuadParticle
    • GustParticle now extends SingleQuadParticle
    • HeartParticle now extends SingleQuadParticle and takes in a TextureAtlasSprite
    • HugeExplosionParticle now extends SingleQuadParticle
    • ItemPickupParticle now takes in the EntityRenderState instead of the EntityRenderDispatcher
      • Fields are now all protected aside from the target entity
    • ItemPickupParticleGroup - The particle group responsible for setting up and submitting the item pickup particle.
    • LavaParticle now extends SingleQuadParticle
    • MobAppearanceParticle -> ElderGuardianParticle
    • NoRenderParticleGroup - The particle group that does nothing.
    • NoteParticle now extends SingleQuadParticle and takes in a TextureAtlasSprite
    • Particle
      • rCol, gCol, bCol, alpha -> SingleQuadParticle#rCol, gCol, bCol, alpha
      • roll, oRoll -> SingleQuadParticle#roll, oRoll
      • setColor, setAlpha -> SingleQuadParticle#setColor, setAlpha
      • render, renderCustom -> ParticleGroupRenderState#submit, not one-to-one
      • getRenderType -> getGroup
        • The original purpose of this method has been moved to SingleQuadParticle#getLayer
      • getParticleGroup -> getParticleLimit, not one-to-one
    • ParticleEngine no longer implements PreparableReloadListener
      • The constructor now takes in the ParticleResources instead of the TextureManager
      • close is removed
      • updateCount is now protected
      • render -> extract, not one-to-one
      • destroy -> ClientLevel#addDestroyBlockEffect
      • crack -> ClientLevel#addBreakingBlockEffect
      • clearParticles is now public
      • $MutableSpriteSet -> ParticleResources$MutableSpriteSet
      • $SpriteParticleRegistration -> ParticleResources$SpriteParticleRegistration
    • ParticleGroup - A holder of particles for a specific ParticleRenderType, responsible for ticking and extracting the general render state.
    • ParticleProvider
      • createParticle now takes in the RandomSource
      • $Sprite#createParticle now takes in the RandomSource and returns a SingleQuadParticle instead of a TextureSheetParticle
    • ParticleRenderType no longer takes in the RenderType
      • This record has been repurposed to represent a key for the particle groups
      • TERRAIN_SHEET -> SingleQuadParticle$Layer#TERRAIN
      • PARTICLE_SHEET_OPAQUE -> SingleQuadParticle$Layer#OPAQUE
      • PARTICLE_SHEET_TRANSLUCENT -> SingleQuadParticle$Layer#TRANSLUCENT
      • CUSTOM is replaced by a particle group that is not for ParticleRenderType#SINGLE_QUADS
    • ParticleResources - Loads the particle providers, any necessary descriptions, and computes them into their desired sprite set.
    • PlayerCloudParticle now extends SingleQuadParticle
    • PortalParticle now extends SingleQuadParticle and takes in a TextureAtlasSprite
    • QuadParticleGroup - The particle group responsible for setting up and submitting single quad particles.
    • ReversePortalParticle now takes in a TextureAtlasSprite
    • RisingParticle now extends SingleQuadParticle
    • SculkChargeParticle now extends SingleQuadParticle
    • SculkChargePopParticle now extends SingleQuadParticle
    • SculkChargePopParticle now extends SingleQuadParticle
    • ShriekParticle now extends SingleQuadParticle and takes in a TextureAtlasSprite
    • SimpleAnimatedParticle now extends SingleQuadParticle and is abstract
    • SingleQuadParticle now takes in a TextureAtlasSprite
      • sprite - The texture of the particle.
      • render -> extract, not one-to-one, now taking in the QuadParticleRenderState instead of a VertexConsumer
      • renderRotatedQuad -> extractRotatedQuad, not one-to-one, now taking in the QuadParticleRenderState instead of a VertexConsumer
      • getU0, getU1, getV0, getV1 are no longer abstract
      • getLayer - Sets the render layer of the single quad.
      • $Layer - The layer the single quad should render in.
    • SnowflakeParticle now extends SingleQuadParticle
    • SpellParticle now extends SingleQuadParticle
      • InstantProvider generic now uses SpellParticleOption
    • SplashParticle now takes in a TextureAtlasSprite
    • SpriteSet#first - Returns the first texture in the sprite set.
    • SuspendedParticle now extends SingleQuadParticle and takes in a TextureAtlasSprite
    • SuspendedTownParticle now extends SingleQuadParticle and takes in a TextureAtlasSprite
    • TerrainParticle now extends SingleQuadParticle
    • TextureSheetParticle class is removed, use SingleQuadParticle instead
    • TrailParticle now extends SingleQuadParticle and takes in a TextureAtlasSprite
    • TrialSpawnerDetectionParticle now extends SingleQuadParticle
    • VibrationSignalParticle now extends SingleQuadParticle and takes in a TextureAtlasSprite
    • WakeParticle now extends SingleQuadParticle
    • WaterCurrentDownParticle now extends SingleQuadParticle and takes in a TextureAtlasSprite
    • WaterDropParticle now extends SingleQuadParticle and takes in a TextureAtlasSprite
  • net.minecraft.client.player.AbstractClientPlayer fields are now stored within ClientAvatarState
    • elytraRot* -> *Cloak
    • clientLevel is removed
    • getDeltaMovementLerped -> addWalkedDistance, not one-to-one
    • updateBob - Updates the bobbing motion of the camera.
  • net.minecraft.client.renderer
    • EndFlashState - The render state of the end flashes.
    • GameRenderer now takes in the BlockRenderDispatcher
      • getSubmitNodeStorage - Gets the node submission for feature-like objects.
      • getFeatureRenderDispatcher - Gets the dispatcher for rendering feature-like objects.
      • getLevelRenderState - Gets the render state of dynamic features in a level.
    • ItemInHandRenderer
      • renderItem now takes in a SubmitNodeCollector instead of a MultiBufferSource
      • renderHandsWithItems now takes in a SubmitNodeCollector instead of a MultiBufferSource$BufferSource
    • LevelRenderer now takes in the LevelRenderState and FeatureRenderDispatcher
      • getSectionRenderDispatcher is now nullable
      • tickParticles is removed
      • addParticle is removed
    • MapRenderer now takes in an AtlasManager instead of a MapDecorationTextureManager
      • render now takes in a SubmitNodeCollector instead of a MultiBufferSource
    • OrderedSubmitNodeCollector - A submission handler for holding elements to be drawn in a given order to the screen whenever the features are dispatched.
    • OutlineBufferSource no longer takes in any parameters
      • setColor now takes in a single integer
    • ParticleGroupRenderState - The render state for a group of particles.
    • ParticlesRenderState - The render state for all particles.
    • QuadParticleRenderState - The render group state for all single quad particles.
    • RenderPipelines
      • GUI_TEXT - The pipeline for text in a gui.
      • GUI_TEXT_INTENSITY - The pipeline for text intensity when not colored in a gui.
    • RenderStateShard#TRANSLUCENT_TARGET, PARTICLES_TARGET are removed
    • RenderType
      • pipeline - The RenderPipeline the type uses.
      • opaqueParticle, translucentParticle are removed
      • sunriseSunset, celestial are removed
    • ScreenEffectRenderer now takes in a MaterialSet
      • renderScreenEffect now takes in a SubmitNodeCollector
    • ShapeRenderer
      • renderLineBox now takes in a PoseStack$Pose instead of a PoseStack
      • renderFace now takes in a Matrix4f instead of a PoseStack
    • Sheets
      • GUI_SHEET, MAP_DECORATIONS_SHEET, PAINTINGS_SHEET - Atlas textures.
      • BLOCK_ENTITIES_MAPPER - A mapper for block textures onto block entities.
      • *COPPER* - Materials for copper chests.
      • chooseMaterial now takes in a ChestRenderState$ChestMaterialType instead of a BlockEntity and boolean
    • SkyRenderer
      • END_SKY_LOCATION is now private
      • renderSunMoonAndStars no longer takes in the buffer source
      • renderEndFlash no longer takes in the buffer source
      • renderSunriseAndSunset no longer takes in the buffer source
    • SpecialBlockModelRenderer
      • vanilla now takes in a SpecialModelRenderer$BakingContext instead of an EntityModelSet
      • renderByBlock now takes in a SubmitNodeCollector instead of a MultiBufferSource, and an outline color
    • SubmitNodeCollection - An implementation of OrderedSubmitNodeCollector that holds the submitted features in separate lists.
    • SubmitNodeCollector - An OrderedSubmitNodeCollector that provides a method to change the current order that an element will be rendered in.
    • SubmitNodeStorage - A storage of collections held by some order.
    • SkyRenderer
      • renderEndFlash - Renders the end flashes.
      • initTextures - Gets the texture for the used elements.
      • extractRenderState - Extracts the SkyRenderState from the current level.
    • WeatherEffectRenderer
      • render now takes in the WeatherRenderState instead of an int, float, and Level
        • Those fields have moved to extractRenderState
      • extractRenderState - Extracts the WeatherRenderState from the current level.
      • $ColumnInstance is now public
    • WorldBorderRenderer
      • render now takes in the WorldBorderRenderState instead of the WorldBorder
      • extract - Extracts the WorldBorderRenderState from the current world border.
  • net.minecraft.client.renderer.block
    • BlockRenderDispatcher now takes in a MaterialSet
    • MovingBlockRenderState - A render state for a moving block that implements BlockAndTintGetter.
    • LiquidBlockRenderer#setupSprites now take in the BlockModelShaper and MaterialSet
  • net.minecraft.client.renderer.blockentity
    • Most methods here that take in the MultiBufferSource have been replaced by a SubmitNodeCollector, and a ModelFeatureRenderer$CrumblingOverlay if the method is not used for item rendering
    • Most methods change their name from render* to submit*, with the main submit method now using a BlockEntityRenderState
    • All BlockEntityRenderers now have a BlockEntityRenderState generic
    • AbstractEndPortalRenderer - A block entity renderer for the end portal.
    • AbstractSignRenderer
      • getSignModel now returns a Model$Simple
      • renderSign -> submitSign, now takes in a Model$Simple and no longer takes in a tint color
    • BannerRenderer has an overload that takes in a SpecialModelRenderer$BakingContext
      • The EntityModelSet constructor now takes in the MaterialSet
      • renderPatterns -> submitPatterns now takes in the MaterialSet and ModelFeatureRenderer$CrumblingOverlay, the ModelPart has been replaced with the Model and its render state, a boolean for whether to use the entity glint, and an outline color
        • The overload with two additional booleans has been removed
      • renderSpecial -> submitSpecial, now takes in the outline color
    • BeaconRenderer#renderBeaconBeam -> submitBeaconBeam, no longer takes in the game time long
    • BedRenderer has an overload that takes in a SpecialModelRenderer$BakingContext
      • The EntityModelSet constructor now takes in the MaterialSet
      • renderSpecial -> submitSpecial, now takes in the outline color
    • BlockEntityRenderDispatcher now takes in the MaterialSet and PlayerSkinRenderCache
      • render -> submit, now takes in the BlockEntityRenderState instead of a BlockEntity, no longer takes in the partial tick float, and takes in the CameraRenderState
      • getRenderer now has an overload that can get the renderer from its BlockEntityRenderState
      • tryExtractRenderState - Gets the BlockEntityRenderState from its BlockEntity
      • level, camera, cameraHitResult is removed
      • prepare now only takes in the Camera
      • setLevel is removed
    • BlockEntityRenderer now has another generic S representing the BlockEntityRenderState
      • render -> submit, taking in the BlockEntityRenderState, the PoseStack, the SubmitNodeCollector, and the CameraRenderState
      • createRenderState - Creates the render state object.
      • extractRenderState - Extracts the render state from the block entity.
    • BlockEntityRendererProvider$Context is now a record, taking in a MaterialSet and PlayerSkinRenderCache
      • It now has another generic S representing the BlockEntityRenderState
    • CopperGolemStatueBlockRenderer - A block entity renderer for the copper golem statue.
    • DecoratedPotRenderer has an overload that takes in a SpecialModelRenderer$BakingContext
      • The EntityModelSet constructor now takes in the MaterialSet
      • render overload -> submit, now takes in the outline color
    • HangingSignRenderer
      • createSignModel now returns a Model$Simple
      • renderInHand now takes in a MaterialSet
    • ShelfRenderer - A block entity renderer for a shelf.
    • ShulkerBoxRenderer has an overload that takes in a SpecialModelRenderer$BakingContext
      • The EntityModelSet constructor now takes in the MaterialSet
      • render overload -> submit, now takes in the outline color
    • SignRenderer
      • createSignModel now returns a Model$Simple
      • renderInHand now takes in a MaterialSet
    • SkullBlockRenderer#submitSkull - Submits the skull model to the collector.
    • SpawnerRenderer#renderEntityInSpawner -> submitEntityInSpawner, now takes in the CameraRenderState
    • TestInstanceREnderer now takes in the BlockEntityRendererProvider$Context
  • net.minecraft.client.renderer.blockentity.state
    • BannerRenderState - The render state for the banner block entity.
    • BeaconRenderState - The render state for the beacon block entity.
    • BedRenderState - The render state for the bed block entity.
    • BellRenderState - The render state for the bell block entity.
    • BlockEntityRenderState - The base render state for all block entities.
    • BlockEntityWithBoundingBoxRenderState - The render state for a block entity with a custom bounding box.
    • BrushableBlockRenderState - The render state for a brushable block entity.
    • CampfireRenderState - The render state for the campfire block entity.
    • ChestRenderState - The render state for the chest block entity.
    • CondiutRenderState - The render state for the conduit block entity.
    • CopperGolemStatueRenderState - The render state for the copper golem block entity.
    • DecoratedPotRenderState - The render state for the decorated pot block entity.
    • EnchantTableRenderState - The render state for the enchantment table block entity.
    • EndGatewayRenderState - The render state for the end gateway block entity.
    • EndPortalRenderState - The render state for the end portal block entity.
    • LecternRenderState - The render state for the lectern block entity.
    • PistonHeadRenderState - The render state for the piston head block entity.
    • ShelfRenderState - The render state for the shelf block entity.
    • ShulkerBoxRenderState - The render state for the shulker box block entity.
    • SignRenderState - The render state for the sign block entity.
    • SkullBlockRenderState - The render state for the skull block entity.
    • SpawnerRenderState - The render state for the spawner block entity.
    • TestInstanceRenderState - The render state for the test instance block entity.
    • VaultRenderState - The render state for the vault block entity.
  • net.minecraft.client.renderer.culling.Frustum
    • offset - Offsets the position.
    • pointInFrustum - Checks whether the provided coordinate is within the frustum.
  • net.minecraft.client.renderer.entity
    • Most methods here that take in the MultiBufferSource and light coordinates integer have been replaced by SubmitNodeCollector and a render state param
    • Most methods change their name from render* to submit*
    • AbstractBoatRenderer#renderTypeAdditions -> submitTypeAdditions
    • AbstractMinecartRenderer#renderMinecartContents -> submitMinecartContents
    • AbstractSkeletonRenderer takes in a ArmorModelSet instead of a ModelLayerLocation
    • AbstractZombieRenderer takes in a ArmorModelSet instead of a model
    • ArmorModelSet - A holder that maps some object to each humanoid armor slot. Typically holds the layer definitions, which are then baked into their associated models.
    • BreezeRenderer#enable is removed
    • CopperGolemRenderer - The renderer for the copper golem entity.
    • DisplayRenderer#renderInner -> submitInner
    • EnderDragonRenderer#renderCrystalBeams -> submitCrystalBeams
    • EntityRenderDispatcher now takes in the AtlasManager
      • prepare no longer takes in the Level
      • setRenderShadow, setRenderHitBoxes, shouldRenderHitBoxes are removed
      • extractEntity - Creates the render state from the entity and the partial tick.
      • render -> submit, now takes in the CameraRenderState
      • setLevel -> resetCamera, not one-to-one
      • getPlayerRenderer - Gets the AvatarRenderer from the given client player.
      • overrideCameraOrientation, distanceToSqr, cameraOrientation are removed
    • EntityRenderer
      • NAMETAG_SCALE is now public
      • render(S, PoseStack, MultiBufferSource, int) -> submit(S, PoseStack, SubmitNodeCollector, CameraRenderState)
      • renderNameTag -> submitNameTag, now takes in a CameraRenderState
      • finalizeRenderState - Extracts the information of the render state as a last step after extractRenderState, such as shadows.
    • EntityRendererProvider$Context now takes in the PlayerSkinRenderCache and AtlasManager
      • getModelManager is removed
      • getMaterials - Returns a mapper of material to atlas sprite.
      • getPlayerSkinRenderCache - Gets the render cache of player skins.
      • getAtlas - Returns the atlas for that location.
    • EntityRenderers#createPlayerRenderers now returns a map of PlayerModelTypes to AvatarRenderers
    • ItemEntityRenderer
      • renderMultipleFromCount -> submitMultipleFromCount
      • renderMultipleFromCount(PoseStack, MultiBufferSource, int, ItemClusterRenderState, RandomSource) -> renderMultipleFromCount(PoseStack, SubmitNodeCollector, int, ItemClusterRenderState, RandomSource)
    • ItemRenderer no longer takes in the ItemModelResolver
      • getArmorFoilBuffer -> getFoilRenderTypes, not one-to-one
      • renderStatic methods are removed
    • MobRenderer#checkMagicName - Returns whether the custom name matches the given string.
    • PiglinRenderer takes in a ArmorModelSet instead of a ModelLayerLocation
    • TntMinecartRenderer#renderWhiteSolidBlock -> submitWhiteSolidBlock, now takes in an outline color
    • ZombieRenderer takes in a ArmorModelSet instead of a ModelLayerLocation
    • ZombifiedPiglinPiglinRenderer takes in a ArmorModelSet instead of a ModelLayerLocation
  • net.minecraft.client.renderer.entity.layers
    • ArrowLayer now deals with AvatarRenderState instead of PlayerRenderState
    • BeeStingerLayer now deals with AvatarRenderState instead of PlayerRenderState
    • BlockDecorationLayer - A layer that handles a block model transformed by an entity.
    • BreezeWindLayer now takes in the EntityModelSet instead of the EntityRendererProvider$Context
    • CapeLayer now deals with AvatarRenderState instead of PlayerRenderState
    • CustomHeadLayer now takes in the PlayerSkinRenderCache
    • Deadmau5EarsLayer now deals with AvatarRenderState instead of PlayerRenderState
    • EquipmentLayerRenderer#renderLayers now takes in the render state, SubmitNodeCollector, outline color, and an initial order instead of a MultiBufferSource
    • HumanoidArmorLayer now takes in ArmorModelSets instead of models
      • setPartVisibility is removed
    • ItemInHandLayer#renderArmWithItem -> submitArmWithItem
    • LivingEntityEmissiveLayer now takes in a function for the texture instead of a ResourceLocation and a model instead of the $DrawSelector
      • $DrawSelector is removed
    • ParrotOnShoulderLayer now deals with AvatarRenderState instead of PlayerRenderState
    • PlayerItemInHandLayer now deals with AvatarRenderState instead of PlayerRenderState
    • RenderLayer
      • renderColoredCutoutModel, coloredCutoutModelCopyLayerRender now takes in a Model instead of an EntityModel, a SubmitNodeCollector instead of a MultiBufferSource, and an integer representing the order layer for rendering
      • render -> submit, taking in a SubmitNodeCollector instead of a MultiBufferSource
    • SimpleEquipmentLayer now takes in an order integer
    • SpinAttackEffectLayer now deals with AvatarRenderState instead of PlayerRenderState
    • StuckInBodyLayer now has an additional generic for the render state, also taking in the render state in the constructor
      • numStuck now takes in an AvatarRenderState instead of the PlayerRenderState
    • VillagerProfessionLayer now takes in two models
  • net.minecraft.client.renderer.entity.player.PlayerRenderer -> AvatarRenderer
    • render*Hand now takes in a SubmitNodeCollector instead of a MultiBufferSource
  • net.minecraft.client.renderer.entity.state
    • CopperGolemRenderState - The render state for the copper golem entity.
    • DisplayEntityRenderState#cameraYRot, cameraXRot - The rotation of the camera.
    • EntityRenderState
      • NO_OUTLINE - A constant that represents the color for no outline.
      • outlineColor - The outline color of the entity.
      • lightCoords - The packed light coordinates used to light the entity.
      • shadowPieces, $ShadowPiece - Represents the relative coordinates of the shadow(s) the entity is casting.
    • FallingBlockRenderState fields and implementations have all been moved to MovingBlockRenderState
    • LivingEntityRenderState
      • appearsGlowing -> EntityRenderState#appearsGlowing, now a method
      • customName is removed
    • PaintingRenderState#lightCoords -> lightCoordsPerBlock
    • PlayerRenderState -> AvatarRenderState
      • useItemRemainingTicks, swinging are removed
      • showDeadMouseEars -> showExtraEars
    • SheepRenderState
      • id is removed
      • isJebSheep is now a field instead of a method
    • WitherSkullRenderState#xRot, yRot -> modeState, not one-to-one
  • net.minecraft.client.renderer.feature
    • BlockFeatureRenderer - Renders the submitted blocks, block models, or falling blocks.
    • CustomFeatureRenderer - Renders the submitted geometry via a passed function.
    • FeatureRenderDispatcher - Dispatches all features to render from the submitted node collector objects.
    • FlameFeatureRenderer - Renders the submitted entity on fire animation.
    • HitboxFeatureRenderer - Renders the submitted entity hitbox.
    • ItemFeatureRenderer - Renders the submitted items.
    • LeashFeatureRenderer - Renders the submitted leash attached to entities.
    • ModelFeatureRenderer - Renders the submitted Models.
    • ModelPartFeatureRenderer - Renders the submitted ModelParts.
    • NameTagFeatureRenderer - Renders the submitted name tags.
    • ParticleFeatureRenderer - Renders the submitted particles.
    • ShadowFeatureRenderer - Render the submitted entity shadow.
    • TextFeatureRenderer - Renders the submitted text.
  • net.minecraft.client.renderer.item
    • ItemModel$BakingContext now takes in a MaterialSet and PlayerSkinRenderCache, and implements SpecialModelRenderer$BakingContext
    • ItemStackRenderState#render -> submit, taking in a SubmitNodeCollector instead of a MultiBufferSource and an outline color
  • net.minecraft.client.renderer.special
    • Most methods here that take in the MultiBufferSource have been replaced by SubmitNodeCollector
    • ChestSpecialRenderer now takes in a MaterialSet
      • *COPPER* - Textures for the copper chest.
    • ConduitSpecialRenderer now takes in a MaterialSet
    • CopperGolemStatueSpecialRenderer - A special renderer for the copper golem statue as an item.
    • HangingSignSpecialRenderer now takes in a MaterialSet and a Model$Simple instead of a Model
    • NoDataSpecialModelRenderer#render -> submit, now takes in an outline color
    • PlayerHeadSpecialRenderer now takes in the PlayerSkinRenderCache
    • ShieldSpecialRenderer now takes in a MaterialSet
    • SpecialModelRenderer
      • render -> submit, now takes in an outline color
      • $BakingContext - The context used to bake a special item model.
      • $Unbaked#bake now takes in a SpecialModelRenderer$BakingContext instead of an EntityModelSet
    • SpecialModelRenderers#createBlockRenderers now takes in a SpecialModelRenderer$BakingContext instead of an EntityModelSet
    • StandingSignSpecialRenderer now takes in a MaterialSet and a Model$Simple instead of a Model
  • net.minecraft.client.renderer.state
    • BlockBreakingRenderState - The render state for how far the current block has been broken.
    • BlockOutlineRenderState - The render state for the outline of a block via its VoxelShapes.
    • CameraRenderState - The render state of the camera.
    • LevelRenderState - The render state of the dynamic features in a level.
    • ParticleGroupRenderState - The render state for a group of particles.
    • ParticlesRenderState - The render state for all particles.
    • QuadParticleRenderState - The render group state for all single quad particles.
    • SkyRenderState - The render state of the sky, including the moon and stars.
    • WeatherRenderState - The render state of the current weather.
    • WorldBorderRenderState - The render state of the world border.
  • net.minecraft.client.renderer.texture
    • SkinTextureDownloader is now an instance class rather than a static method holder, taking in a Proxy, TextureManager, and the main thread Executor
      • Most methods that were previously static are now instance methods
    • SpriteContents now takes in an optional AnimationMetadataSection and MetadataSectionType$WithValue list instead of a ResourceMetadata
      • metadata -> getAdditionalMetadata, not one-to-one
    • SpriteLoader
      • DEFAULT_METADATA_SECTIONS is removed
      • stitch is now private
      • runSpriteSuppliers is now private
      • loadAndStitch(ResourceManager, ResourceLocation, int, Executor) isn removed
      • loadAndStitch now takes a set of MetadataSectionTypes instead of a collection
      • $Preparations
        • waitForUpload is removed
        • getSprite - Returns the atlas sprite for a given resource location.
    • TextureAtlasSprite#isAnimated -> SpriteContents#isAnimated
  • net.minecraft.client.renderer.texture.atlas.SpriteResourceLoader#create now takes a set of MetadataSectionTypes instead of a collection
  • net.minecraft.client.resources
    • MapDecorationTextureManager class is removed
    • PaintingTextureManager class is removed
    • PlayerSkin$Model -> PlayerModelType, not one-to-one
      • The constructor not takes in the legacy service name
      • byName -> byLegacyServicesName
    • SkinManager now takes in Services instead of a MinecraftSessionService, and a SkinTextureDownloader
      • lookupInsecure -> createLookup, now taking in a boolean of whether to check for insecure skins
      • getOrLoad -> get
    • TextureAtlasHolder class is removed
  • net.minecraft.client.resources.model
    • AtlasIds -> net.minecraft.data.AtlasIds
    • AtlasSet -> AtlasManager, not one-to-one
      • forEach - Iterates through each of the atlas sheets.
    • Material
      • sprite -> MaterialSet#get
      • buffer now takes in a MaterialSet
    • MaterialSet - A map of material to its atlas sprite.
    • ModelBakery now takes in a MaterialSet and PlayerSkinRenderCache
    • ModelManager is no longer AutoCloseable
      • The constructor takes in the PlayerSkinRenderCache, AtlasManager instead of the TextureManager, and the max mipmap levels integer
      • getAtlas -> MaterialSet#get
      • updateMaxMipLevel -> AtlasManager#updateMaxMipLevel
  • net.minecraft.core.particles
    • ParticleGroup -> ParticleLimit
    • ParticleTypes
      • DRAGON_BREATH now uses a PowerParticleOption
      • EFFECT now uses a SpellParticleOption
      • FLASH now uses a ColorParticleOption
      • INSTANT_EFFECT now uses a SpellParticleOption
    • PowerParticleOption - A particle option for the dragon’s breath.
    • SpellParticleOption - A particle option for potion effects.

The Font Glyph Pipeline

Glyphs have been partially reworked in the backend to both unify both characters and their effects to a single renderable and add a baking flow, albeit delayed. This will provide a brief overview of this new flow.

Let’s start from the top when the assets are reloaded, causing the FontManager to run. The font definitions are loaded and passed to their appropriate GlyphProviderDefinition, which for this example with immediately unpack into a GlyphProvider$Loader. The loader reads whatever information it needs (most likely a texture) and maps it to an associated codepoint as an UnbakedGlyph. An UnbakedGlyph represents a single character containing its GlyphInfo with the position metadata and a bake method to write it to a texture. bake takes in a UnbakedGlyph$Stitcher, which itself takes in a GlyphBitmap to correctly position and upload the glyph along with the GlyphInfo for any offset adjustments. Then, after and resolving and finalizing, the FontSets are created using FontSet#reload. This resets the textures and cache and calls FontSet#selectProviders to store the active list of GlyphProviders and populates the glyphsByWidth by mapping the character advance to a list of matching codepoints. At this point, all of the loading has been done. While the glyphs are stored in their unbaked format, they are not baked and cached until that specific character is rendered.

Now, let’s move onto the FontDescription. A FontDescription provides a one-to-one map to a GlyphSource, which is responsible for obtaining the glyphs. Vanilla provides three FontDescriptions: $Resource for mapping to the FontSet (the font JSON name) as mentioned above, $AtlasSprite to interpret an atlas as a bunch of glyphs, and $PlayerSprite for rendering the player head and hat. For a given Component, the FontDescription used can be set as its Style via Style#withFont.

So, let’s assume you are drawing text to the screen using FontDescription#DEFAULT, which uses the defined assets/minecraft/font/default.json. Eventually, this will either call Font#drawInBatch or drawInBatch8xOutline. Then, whether through the StringSplitter or directly, the GlyphSource is obtained from the FontDescription. Then, GlyphSource#getGlyph is called. For the FontDescription$AtlasSprite and $PlayerSprite, this just returns a wrapper around the texture in question. For the $Resource though, this internally calls FontSet#getGlyph, which stores the UnbakedGlyph as part of a FontSet$DelayedBake, which it then immediately resolves to the BakedGlyph by calling UnbakedGlyph#bake to write the glyph to some texture.

A BakedGlyph contains two methods: the GlyphInfo for the position metadata like before, and a method called createGlyph, which returns a TextRenderable: a renderer to draw the glyph to the screen. TextRenderable also has a subinterface called PlainTextRenderable for help with texture sprites. Internally, all resource BakedGlyphs are BakedSheetGlyphs, as the UnbakedGlyph$Stitcher#stitch called just wraps around GlyphStitcher#stitch. You can think of the BakedSheetGlyph as a view onto a 256x256 FontTextures, where if there is not enough space on one FontTexture, then a new FontTexture is created.

BakedSheetGlyph also implements EffectGlyph, which is likely supposed to render some sort of effect on the text. This functionality, while it is currently implemented as just another object, is only used for the white glyph, which goes unused.

Object Info

ObjectInfos are the server side implementations to construct the FontDescription used to render an arbitrary object through the glyph pipeline. Each info takes in the FontDescription and a regular String to display a simple description. Additionally, it takes in a MapCodec to encode and decode from the object contents.

Note that for custom FontDescriptions to map to a source properly, you will need to somehow modify FontManager$CachedFontProvider#getGlyphSource or implement a custom Font$Provider.

// A basic font description
public static record BlockDescription(Block block) implements FontDescription {}

// A simple object info
public record BlockInfo(Block block) implements ObjectInfo {
    // The codec to send the information over the network
    public static final MapCodec<BlockInfo> MAP_CODEC = BuiltInRegistries.BLOCK.byNameCodec().fieldOf("block");

    @Override
    public FontDescription fontDescription() {
        // The font description to render
        return new BlockDescription(this.block);
    }

    @Override
    public String description() {
        // Just a text description of the object
        return Objects.toString(BuiltInRegistries.BLOCK.getKey(this.block));
    }

    @Override
    public MapCodec<? extends ObjectInfo> codec() {
        return MAP_CODEC;
    }
}

// Create the `GlyphSource` and `PlainTextRenderable` used to render the object
public record BlockRenderable(...) implements PlainTextRenderable {
    // ...
}

public static GlyphSource create(Block block) {
    return new SingleSpriteSource(...);
}

The ObjectInfo also needs to be rendered to ObjectInfos#ID_MAPPER:

// Assumes the the mapper has been made public
ObjectInfos.ID_MAPPER.put("examplemod:block", BlockInfo.MAP_CODEC);

Component Contents

Component contents also now use an id mapper instead of holding the id on the type. This means that creating a custom component is done by somehow hooking into ComponentSerialization#bootstrap and registering the map codec of your ComponentContents implementation to the mapper.

Data Sources

Data sources has received a similar treatment to component contents, now using an id mapper instead of holding the id on the type. The data source is then registered by registering to DataSources#ID_MAPPER the map codec of your DataSource. Note that the mapper field is private, so you will probably need to use an available workaround.

  • com.mojang.blaze3d.font
    • GlyphInfo
      • bake -> UnbakedGlyph#bake, now takes in a UnbakedGlyph$Stitcher instead of a function
        • The function behavior is replaced by UnbakedGlyph$Stitcher#stitch
      • $SpaceGlyphInfo -> GlyphInfo#simple and EmptyGlyph, not one-to-one
      • $Stitched -> UnbakedGlyph, not one-to-one
    • GlyphProvider#getGlyph now returns an UnbakedGlyph
    • SheetGlyphInfo -> GlyphBitmap
  • net.minecraft.client.gui
    • Font no longer takes in a function and boolean, instead a Font$Provider
      • random is now private
      • $GlyphVisitor
        • acceptGlyph now takes in a TextRenderable instead of a BakedGlyph$GlyphInstance
        • acceptEffect now only takes in a TextRenderable
      • $PreparedTextBuilder#accept now has an override that takes in a BakedGlyph instead of its codepoint
      • $Provider - A simple interface for providing the glyph source based on its description, along with the empty glyph.
    • GlyphSource - An interface that holds the baked glyphs based on its codepoint.
  • net.minecraft.client.gui.font
    • AtlasGlyphProvider - A glyph provider based off a texture atlas.
    • FontManager now takes in the AtlasManager and PlayerSkinRenderCache
    • FontSet now takes in a GlyphStitcher instead of a TextureManager and no longer takes in the name
      • name is removed
      • source - Returns the glyph source depending given whether only non-fishy glyphs should be seen.
      • getGlyphInfo, getGlyph -> getGlyph, now package-private, not one-to-one
      • getRandomGlyph now takes in a RandomSource and a codepoint instead of the GlyphInfo, returning a BakedGlyph
      • whiteGlyph now returns an EffectGlyph
      • $GlyphSource - A source that can get the glyphs to bake.
    • FontTexture#add now takes in a GlyphInfo and GlyphBitmap, returning a BakedSheetGlyph
    • GlyphStitcher - A class that creates BakedGlyphs from its glyph information.
    • PlainTextRenderable - An implementation of TextRenderable that determines how a sprite is rendered.
    • PlayerGlyphProvider - A glyph provider for rendering the player head and hat.
    • SingleSpriteSource - A glyph source that only contains one glyph, such as a texture.
    • TextRenderable - Represents how a text representation, like a glyph in a font, is rendered.
  • net.minecraft.client.gui.font.glyphs
    • BakedGlyph is now an interface that creates the renderable object
      • It original purpose has been moved to BakedSheetGlyph
    • EffectGlyph - An interface that creates the renderable effect of some glyph.
    • EmptyGlyph now implements UnbakedGlyph instead of extending BakedGlyph
      • The constructor takes in the text advance of the glyph.
    • SpecialGlyphs#bake now returns a BakedSheetGlyph
      • This method is technically new.
  • net.minecraft.client.gui.font.providers
    • BitmapProvider$Glyph now implements UnbakedGlyph instead of GlyphInfo$Stitched
    • UnihexProvider$Glyph now implements UnbakedGlyph instead of GlyphInfo$Stitched
  • net.minecraft.client.gui.render.state
    • GlyphEffectRenderState is removed
      • Use GlyphRenderState
    • GlyphRenderState now takes in a TextRenderable instead of a BakedGlyph$Instance
  • net.minecraft.network.chat
    • Component#object - Creates a mutable component with object contents.
    • ComponentContents#type -> codec, dropping the string id
      • $Type is removed
    • ComponentSerialization
      • createLegacyComponentMatcher no longer requires a StringRepresentable generic, instead taking in a id mapper using String keys
      • $FuzzyCodec now takes in a collection of map codecs instead of a list
    • FontDescription - An identifier that describes a font, typically as a location or sprite.
    • Style is now final
      • getFont now returns a FontDescription
      • withFont now takes in a FontDescription instead of a ResourceLocation
      • DEFAULT_FONT is removed
  • net.minecraft.network.chat.contents
    • BlockDataSource -> .data.BlockDataSource
    • DataSource -> .data.DataSource
      • type -> codec, dropping the string id
    • EntityDataSource -> .data.EntityDataSource
    • *Contents
      • CODEC -> MAP_CODEC
      • TYPE is removed
    • ObjectContents - An arbitrary piece of content that can be written as part of a component, like a sprite.
    • StorageDataSource -> .data.StorageDataSource
  • net.minecraft.network.chat.contents.data.DataSources - All vanilla-registered data sources.
  • net.minecraft.network.chat.contents.objects
    • AtlasSprite - An object info for a sprite in a texture atlas.
    • ObjectInfo - Information relating the references for an arbitrary object through the glyph pipeline.
    • ObjectInfos - All vanilla object infos.
    • PlayerSprite - An object info for a player head and hat texture.

The JSON-RPC Management Servers

Minecraft has introduced support for remotely managing dedicated servers through a JSON-RPC websocket. This can be enabled through the management-server-enabled property, which listens for a server on localhost:25585 by default. The entire system handles not only constructing the network requests sent via JsonElements, but also the schemas each request uses. These schemas can then be generated through the JsonRpcApiSchema data provider.

There are two types of RPC methods supported by the system: IncomingRpcMethods for requests from the management server, and OutgoingRpcMethods to either notify or request information from the management server. Both of these are static registry objects, but rather than implementing the interfaces, they are typically constructed and registered through their associated builders.

Schemas

Schemas, as the name implies, are the specification of the JSON objects. They are constructed in a similar fashion JsonElements. Most are constructed as Schema#records, with their field and types being populated via withField, before being stored in a SchemaComponent, which maps a reference name to the schema. Then the Schemas can be obtained via asRef or asArray to get the object or array implementation, respectively. The SchemaComponents themselves and registered to the list Schema#SCHEMA_REGISTRY for reference resolving.

// An example json for changing the weather:
{
    "weather": "clear|rain|thunder",
    "duration": -1,
}

Here is what the associated schema component would look like:

public static final SchemaComponent WEATHER_SCHEMA = new SchemaComponent(
    // The reference name
    // While we can use colon, it would need to be percent encoded as defined by RFC 3986
    "examplemod_weather",
    // The schema to use
    Schema.record()
        .withField("weather", Schema.ofEnum(List.of("clear", "rain", "thunder")))
        .withField("duration", Schema.INT_SCHEMA)
);

// Register the schema to the registry
Schema.getSchemaRegistry().add(WEATHER_SCHEMA);

Note that schemas currently cannot specify whether an individual property is optional or not.

IncomingRpcMethod

IncomingRpcMethods are constructed and registered through the method builder. These methods take in the handler function to update the minecraft server, a codec for the result, and an optional codec for the parameters sent from the management server. From there, the builder contains methods towards the discovery service and how to execute the method. $IncomingRpcMethodBuilder#response and param define the parameters and response sent by the management server. description is used by the discovery service for the schemas. undiscoverable hides the route by default. Finally, notOnMainThread tells the method that it can run off the main thread. Once the desired methods are called, then either build or register can be used to construct the object, taking in the route endpoint as a namespace and path.

The methods passed in take in the MinecraftApi for communicating with the dedicated server through specified ‘services’, and the current ClientInfo connection. It also takes in the parameter object if it exists.

// Construct the dto object
public record WeatherDto(String weather, int duration) {
    public static final Codec<WeatherDto> CODEC = RecordCodecBuilder.create(
        instance -> instance.group(
            Codec.STRING.fieldOf("weather").forGetter(WeatherDto::weather),
            Codec.INT.fieldOf("duration").forGetter(WeatherDto::duration),
        )
        .apply(instance, WeatherDto::new)
    );

    // Create the incoming method handler
    public static WeatherDto handleWeather(MinecraftApi api, WeatherDto params, ClientInfo info) {
        // Note that the api makes the server private since it expects the
        // logic to be handled through one of the middle layer services.
        // We will assume the `server` field was made public somehow.
        if (params.weather().equals("clear")) {
            api.server.overworld().setWeatherParameters(params.duration(), 0, false, false);
        } else if (params.weather().equals("rain")) {
            api.server.overworld().setWeatherParameters(0, params.duration(), true, false);
        } else if (params.weather().equals("thunder")) {
            api.server.overworld().setWeatherParameters(0, params.duration(), true, true);
        }

        return params;
    }
}

// Construct and register the method endpoint
IncomingRpcMethod.method(
    // The handler method
    WeatherDto::handleWeather,
    // The codec for the parameters
    WeatherDto.CODEC,
    // The codec for the result
    WeatherDto.CODEC
)
    // Sets the description of the route
    .description("Sets the weather")
    // The parameters
    .param(new ParamInfo(
        // The name of the object
        "weather",
        // The schema
        WEATHER_SCHEMA.asRef()
    ))
    // The response
    .response(new ResultInfo(
        // The name of the object
        "weather",
        // The schema
        WEATHER_SCHEMA.asRef()
    ))
    // Build and register the route
    .register(
        BuiltInRegistries.INCOMING_RPC_METHOD,
        // The endpoint namespace
        "examplemod",
        // The endpoint path
        "weather/update"
    );

OutgoingRpcMethod

OutgoingRpcMethods are constructed and registered through the notification or request builder. Notifications typically only send parameters with no returned result, while requests provide a result as well. In either case, they just take in codecs for the params or result when present. $OutgoingRpcMethod#response and param define the parameters and response sent by the minecraft server. description is used by the discovery service for the schemas. Once the desired methods are called, then register can be used to construct the object, taking in the route endpoint as a namespace and path and wrapping it in a Holder$Reference.

Currently, vanilla only broadcasts notifications through the NotificationService: a remote logger for specific method actions, like player join or changing game rule. While there are results, they must be read via Connection#sendRequest and handled asynchronously.

// Construct the outgoing method
// Since the minecraft server will be sending these, we need to hold the object
public static final Holder.Reference<OutgoingRpcMethod.ParmeterlessNotification> SOMETHING_HAPPENED = OutgoingRpcMethod.notification()
        .description("Something happened!")
        .register("examplemod", "something");

// Send notification, assume we have access to the `ManagementServer` managementServer
managementServer.forEachConnection(connection -> connection.sendNotification(SOMETHING_HAPPENED));
  • net.minecraft.SharedConstants#RPC_MANAGEMENT_SERVER_API_VERSION - The API version for JSON RPC server management.
  • net.minecraft.core.registries
    • BuiltInRegistries, Registries
      • INCOMING_RPC_METHOD - Registry for queries to the RPC service.
      • OUTGOING_RPC_METHOD - Registry for broadcasts from the RPC service.
  • net.minecraft.server
    • MinecraftServer
      • notificationManager - Returns the current notification manager.
      • onGameRuleChanged - Handles what happens when the game rule of the current server changes.
      • getOperatorUserPermissionLevel -> operatorUserPermissionLevel
      • isLevelEnabled -> isAllowedToEnterPortal, not one-to-one
      • setPvpAllowed replaced by GameRules#RULE_PVP
      • setFlightAllowed replaced by DedicatedServerProperties#allowFlight
      • isCommandBlockEnabled is no longer abstract
      • isSpawnerBlockEnabled - Returns whether spawner blocks can spawn entities.
      • getPlayerIdleTimeout -> playerIdleTimeout
      • kickUnlistedPlayers no longer takes in the CommandSourceStack
      • pauseWhileEmptySeconds -> pauseWhenEmptySeconds
      • getSpawnProtectionRadius -> DedicatedServer#spawnProtectionRadius
      • isUsingWhiteList - Handles enabling whitelist users for the server.
      • setAutoSave, isAutoSave - Handles whether the server should auto save every so often.
  • net.minecraft.server.dedicated
    • DedicatedServer now takes in a LevelLoadListener instead of a ChunkProgressListenerFactory
      • setAllowFlight - Sets whether the players can fly in the server.
      • setDifficulty - Sets the game difficulty of the server.
      • viewDistance, setViewDistance - Handles the view distance of the server (renderable chunks).
      • simulationDistance, setSimulationDistance - Handles the simulation distance of the server (logic running chunks).
      • setMaxPlayers - Sets the maximum number of players that can join the server.
      • setSpawnProtectionRadius - Sets the radius of chunks that should be under spawn protection.
      • setRepliesToStatus - Sets whether the game uses the legacy query handler.
      • setHidesOnlinePlayers - Sets whether online players should be hidden from other players.
      • setOperatorUserPermissionLevel - Sets the permission level of operator users.
      • statusHeartbeatInterval, setStatusHeartbeatInterval - Handles the interval that the management server will check the minecraft server is still alive.
      • entityBroadcastRangePercentage, setEntityBroadcastRangePercentage - Handles the broadcast range scalar for entity tracking.
      • forceGameMode, setForceGameMode - Handles forcing all game modes for the users.
      • gameMode, setGameMode - Sets the default game mode of the server.
      • setAcceptsTransfers - Sets whether the server accepts client transfers from other servers.
      • setPauseWhenEmptySeconds - Sets the number of seconds that the server should wait until it stops ticking when there are no players.
    • DedicatedServerProperties
      • pvp replaced by GameRules#RULE_PVP
      • allowFlight, motd, forceGameMode, enforceWhitelist, difficulty, gameMode, spawnProtection, opPermissionLevel, viewDistance, simulationDistance, enableStatus, hideOnlinePlayers, entityBroadcastRangePercentage, pauseWhenEmptySeconds, acceptsTransfers are now mutable properties
      • allowNether replaced by GameRules#RULE_ALLOW_NETHER
      • spawnMonsters replaced by GameRules#RULE_SPAWN_MONSTERS
      • enabledCommandBlock replaced by GameRules#RULE_COMMAND_BLOCKS_ENABLED
      • managementServerEnabled - Returns whether a management server is enabled.
      • managementServerHost - Returns the host the management server is communicating on.
      • managementServerPort - Returns the port the management server is communicating on.
      • statusHeartbeatInterval - Returns the heartbeat interval the management server sends to make sure the minecraft server is still alive.
      • MANAGEMENT_SERVER_TLS_ENABLED_KEY, MANAGEMENT_SERVER_TLS_KEYSTORE_KEY, MANAGEMENT_SERVER_TLS_KEYSTORE_PASSWORD_KEY - TLS keystore setup for communication with the management server.
      • managementServerSecret - The authorization token secret.
      • managementServerTlsEnabled - If TLS should be used as the communication protocol.
      • managementServerTlsKeystore - Specifies the filepath used for the TLS keystore.
      • managementServerTlsKeystorePassword - Specifies the password for the keystore file.
    • Settings#getMutable - Gets a mutable property for the settings key and default.
  • net.minecraft.server.jsonrpc
    • Connection - The inbound handler for json elements sent by the management server.
    • IncomingRpcMethod - A definition and handler for the incoming message sent by the management server.
    • IncomingRpcMethods - All vanilla incoming RPC handlers.
    • JsonRPCErrors - An enum of errors that can be thrown when attempting to read, parse, or execute the method.
    • JsonRpcLogger - A general logger for things performed by the minecraft server, whether communication or logic.
    • JsonRpcNotificationService - A notification service that broadcasts to all connected minecraft servers.
    • JsonRPCUtils - A utility for request objects and errors.
    • ManagementServer - A basic websocket comms for the minecraft server to communicate with the management server.
    • OutgoingRpcMethod - A definition and handler for outgoing requests to the management server.
    • OutgoingRpcMethods - All vanilla outgoing RPC handlers.
    • PendingRpcRequest - A pending request made by the minecraft server to the management server.
  • net.minecraft.server.jsonrpc.api
    • MethodInfo - Defines a method that is handled by the management server, either inbound or outbound.
    • ParamInfo - Defines the parameters a specific method takes in.
    • PlayerDto - A data transfer object representing the player.
    • ReferenceUtil - A utility for creating a local reference URI.
    • ResultInfo - Defines the response a specific method returns.
    • Schema - An implementation of the json schema used the discovery service, parameters, and results.
    • SchemaComponent - A reference definition of some component within a schema.
  • net.minecraft.server.jsonrpc.dataprovider.JsonRpcApiSchema - A data provider that generates the json schema from the discovery service.
  • net.minecraft.server.jsonrpc.internalapi
    • GameRules - An api that gets the current game rule value.
    • MinecraftAllowListService - A minecraft middle layer that handles communication from the management server about the allow list.
    • MinecraftAllowListServiceImpl - The allow list implementation.
    • MinecraftApi - A minecraft api that handles all the services that communicate with the management server.
    • MinecraftBanListService - A minecraft middle layer that handles communication from the management server about the ban list.
    • MinecraftBanListServiceImpl - The ban list implementation.
    • MinecraftExecutorService - A minecraft middle layer that submits an arbitrary runnable or supplier to execute on the server.
    • MinecraftExecutorServiceImpl - The executor implementation.
    • MinecraftGameRuleService - A minecraft middle layer that handles communication from the management server about the game rules.
    • MinecraftExecutorServiceImpl - The executor implementation.
    • MinecraftOperatorListService - A minecraft middle layer that handles communication from the management server about the operator commands.
    • MinecraftOperatorListServiceImpl - The operator list implementation.
    • MinecraftPlayerListService - A minecraft middle layer that handles communication from the management server about the player list.
    • MinecraftPlayerListServiceImpl - The player list implementation.
    • MinecraftServerSettingsService - A minecraft middle layer that handles communication from the management server about the server settings.
    • MinecraftServerSettingsServiceImpl - The server settings implementation.
    • MinecraftServerStateService - A minecraft middle layer that handles communication from the management server about the current server state and send messages.
    • MinecraftServerStateServiceImpl - The server state implementation.
  • net.minecraft.server.jsonrpc.methods
    • AllowlistService - A service that handles communication from the management server about the allow list.
    • BanlistService - A service that handles communication from the management server about the player ban list.
    • ClientInfo - An identifier for the current minecraft server connection to the management server.
    • DiscoveryService - A service that displays the schemas of all services supported by the management server.
    • EncodeJsonRpcException - An exception thrown when attempting to encode the json packet.
    • GameRulesService - A service that handles communication from the management server about the game rules.
    • IllegalMethodDefinitionException - An exception thrown when the method definition provided is illegal.
    • InvalidParameterJsonRpcException - An exception thrown when the parameters to the method are invalid.
    • InvalidRequestJsonRpcException - An exception thrown when the request is invalid.
    • IpBanlistService - A service that handles communication from the management server about the ip ban list.
    • Message - A data transfer object representing a literal or translatable component.
    • MethodNotFoundJsonRpcException - An exception thrown when a 404 error occurs, indicating that the method doesn’t exist.
    • OperatorService - A service that handles communication from the management server about the operator commands.
    • PlayerService - A service that handles communication from the management server about the player list.
    • RemoteRpcErrorException - An exception thrown when something goes wrong on the management server.
    • ServerSettingsService - A service that handles communication from the management server about the server settings.
    • ServerStateService - A service that handles communication from the management server about the current server state and send messages.
  • net.minecraft.server.jsonrpc.security
    • AuthenticationHandler - Handles the validation of the authentication token bearer in the request.
    • JsonRpcSslContextProvider - Provides the keystore context for the TLS communication.
    • SecurityConfig - Handles the secret key, from checking basic validaty to generating a new one.
  • net.minecraft.server.jsonrpc.websocket
    • JsonToWebSocketEncoder - A message to message encoder for a json.
    • WebSocketToJsonCodec - A message to message decoder for a json.
  • net.minecraft.server.notifications
    • EmptyNotificationService - A notification service that does nothing.
    • NotificationManager - A manager for handling multiple notification services.
    • NotificationService - A service that defines prospective actions taken by a listener, like a management server.
  • net.minecraft.server.players
    • BanListEntry
      • getReason can now be null
      • getReasonMessage - Returns the translatable component of the ban reason.
    • IpBanList now takes in the NotificationService
      • add, remove - Handles entries on the list.
    • PlayerList now takes in the NotificationService instead of the max players
      • maxPlayers is removed
      • op now has an override for the permission level and bypass limit boolean
      • setUsingWhiteList -> MinecraftServer#setUsingWhiteList
      • getPlayer - Gets a player by their name.
    • ServerOpList now takes in the NotificationService
      • add, remove - Handles entries on the list.
    • StoredUserEntry#getUser is now public
    • StoredUserList now takes in the NotificationService
      • add, remove now return a boolean if successful
      • remove(StoredUserEntry<K>) is removed
      • clear - Clears all stored users.
    • UserBanList now takes in the NotificationService
      • add, remove - Handles entries on the list.
    • UserWhiteList now takes in the NotificationService
      • add, remove - Handles entries on the list.

Input Handling Consolidation

Input handling has previously passed around the raw values, each in their own separate argument, provided by GLFW. However, a good bit of the handling logic is redundant, as specific keys are commonly checked, or all values are passed around in a game of hot potato from one method to the next. With this in mind, the input handlers in GuiEventListener and other calls, are now handled through event objects. These objects still contain the info GLFW passed through; however, now they have a lot of common checks through the super InputWithModifiers interface.

There are two types of events: KeyEvents for key presses, and MouseButtonEvents for mouse presses. Key, scancode, and modifiers are wrapped into the KeyEvent. Button, modifiers, and the XY screen position are wrapped into the MouseButtonEvent. As such, it is generally a drag-and-drop replacement of just removing any of the parameters mentioned above and replacing them with their appropriate event.

Key Mapping Categories

Key mappings have changed slightly, no longer taking in a raw string for its category, and instead using a KeyMapping$Category record, which is essentially a namspaced string. Categories can be created using KeyMapping$Category#register; otherwise, an error will be thrown whenever the mapping is used as part of a comparator.

public static final KeyMapping.Category EXAMPLE = KeyMapping.Category.register(ResourceLocation.withNamespaceAndPath("examplemod", "example"));

Double-Click Expansion

GuiEventListener#mouseClicked now takes in whether the click was in fact a double-click as a boolean.

// For some Screen subclass (or AbstractWidget or any GUI object rendering)

@Override
public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) {
    // ...
    return false;
}
  • com.mojang.blaze3d.platform.InputConstants
    • MOD_SHIFT, MOD_ALT, MOD_SUPER, MOD_CAPS_LOCK, MOD_NUM_LOCK - Modifier keys to transform a key input.
    • KEY_LWIN, KEY_RWIN -> KEY_LSUPER, KEY_RSUPER
    • getKey now takes in a KeyEvent instead of the key and scancode ints
    • isKeyDown, setupKeyboardCallbacks, setupMouseCallbacks, grabOrReleaseMouse, updateRawMouseInput now take in a Window instead of the long handle
  • net.minecraft.client
    • KeyboardHandler
      • keyPress is now private
      • setup now takes in a Window instead of the long handle
    • KeyMapping now takes in a $Category instead of a String
      • shouldSetOnIngameFocus - Returns whether the key is mapped to some value on the keyboard.
      • restoreToggleStatesOnScreenClosed - Restores the toggled keys to its state during in-game actions.
      • key is now protected
      • release is now protected
      • CATEGORY_* -> $Category#*
        • Key can be obtained via $Category#id
        • Component is available through $Category#label
      • getCategory now returns a $Category instead of a String
      • matches now takes in a KeyEvent instead of the key and scancode ints
      • matchesMouse now takes in a MouseButtonEvent instead of the button int
    • Minecraft#ON_OSX -> InputQuirks#ON_OSX
    • MouseHandler#setup now takes in a Window instead of the long handle
    • ToggleKeyMapping now has an overload that takes in an input type
      • The constructor now takes in a KeyMapping$Category instead of a String, and a boolean that represents if the previous state of the key binding should be restored
  • net.minecraft.client.gui.components
    • AbstractButton#onPress now takes in an InputWithModifiers
    • AbstractScrollArea#updateScrolling now takes in a MouseButtonEvent instead of the button info and XY positions
    • AbstractWidget
      • onClick now takes in a MouseButtonEvent instead of the XY positions and whether the button was double-clicked
      • onRelease now takes in a MouseButtonEvent instead of the XY positions
      • onDrag now takes in a MouseButtonEvent instead of the XY positions
      • isValidClickButton now takes in the MouseButtonInfo instead of the button int
    • CommandSuggestions
      • keyPressed now takes in a KeyEvent instead of the key, scancode, modifiers int
      • mouseClicked now takes in a MouseButtonEvent instead of the button info and XY positions
      • $SuggestionsList
        • mouseClicked no longer takes in the button int
        • keyPressed now takes in a KeyEvent instead of the key, scancode, modifiers int
    • MultilineTextField#keyPressed now takes in a KeyEvent instead of the key int
  • net.minecraft.client.gui.components.events.GuiEventListener
    • DOUBLE_CLICK_THRESHOLD_MS -> MouseHandler#DOUBLE_CLICK_THRESHOLD_MS
    • mouseClicked now takes in a MouseButtonEvent instead of the button info and XY positions, and whether the button was double-clicked
    • mouseReleased now takes in a MouseButtonEvent instead of the button info and XY positions
    • mouseDragged now takes in a MouseButtonEvent instead of the button info and XY positions
    • keyPressed now takes in a KeyEvent instead of the key, scancode, modifiers int
    • keyReleased now takes in a KeyEvent instead of the key, scancode, modifiers int
    • charTyped now takes in a CharacterEvent instead of the codepoint char and modifiers int
  • net.minecraft.client.gui.font.TextFieldHelper
    • charTyped now takes in a CharacterEvent instead of the codepoint char
    • keyPressed now takes in a KeyEvent instead of the key int
  • net.minecraft.client.gui.navigation.CommonInputs class is removed
    • selected -> InputWithModifiers#isSelection
    • confirm -> InputWithModifiers#isConfirmation
  • net.minecraft.client.gui.screens.Screen
    • hasControlDown -> Minecraft#hasControlDown, InputWithModifiers#hasControlDown
    • hasShiftDown -> Minecraft#hasShiftDown, InputWithModifiers#hasShiftDown
    • hasAltDown -> Minecraft#hasAltDown, InputWithModifiers#hasAltDown
    • isCut -> InputWithModifiers#isCut
    • isPaste -> InputWithModifiers#isPaste
    • isCopy -> InputWithModifiers#isCopy
    • isSelectAll -> InputWithModifiers#isSelectAll
  • net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
    • hasClickedOutside no longer takes in the button int
    • checkHotbarKeyPressed now takes in a KeyEvent instead of the key and modifiers int
  • net.minecraft.client.gui.screens.options.controls.KeyBindsList$CategoryEntry now takes in a KeyMapping$Category instead of the Component
  • net.minecraft.client.gui.screens.recipebook
    • hasClickedOutside no longer takes in the button int
    • RecipeBookPage#mouseClicked now takes in a MouseButtonEvent instead of the button info and XY positions, and whether the button was double-clicked
  • net.minecraft.client.input
    • CharacterEvent - Some kind of input interaction generates a codepoint with the currently active modifiers.
    • InputQuirks - A utility for quirks between operating systems when handling inputs.
    • InputWithModifiers - Defines an input with the currently active modifiers, along with some common input checks.
    • KeyEvent - Some kind of input interaction generates a key by the scancode with the currently active modifiers.
    • MouseButtonEvent - Some kind of input interaction generates a button at the XY position.
    • MouseButtonInfo - Some kind of input interaction generates a button with the currently active modifiers.

Level#isClientSide now private

The Level#isClientSide field is now private, so all queries must be made to the method version:

// For some Level level
level.isClientSide();
  • net.minecraft.world.level.Level#isClientSide field is now private

Minor Migrations

The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.

Item Owner

Minecraft has further abstracted the holder of an item in item models to its own interface: ItemOwner. An ItemOwner is defined by three things: the level the owner is in, the position of the owner, and the Y rotation (in degrees) of the owner to indicate the facing direction. ItemOwners are implemented on every Entity; however, their position can be offset by using ItemOwner#offsetFromOwner or creating a ItemOwner$OffsetFromOwner.

Currently, only the new shelf block uses the offset owner so that compasses are not randomly spinning when placed.

  • net.minecraft.client.renderer.entity.ItemRenderer#renderStatic now takes in an optional ItemOwner instead of a LivingEntity
  • net.minecraft.client.renderer.item
    • ItemModel#update now takes in an ItemOwner instead of a LivingEntity
    • ItemModelResolver#updateForTopItem, appendItemLayers now takes in an ItemOwner instead of a LivingEntity
  • net.minecraft.client.renderer.item.properties.numeric
    • NeedleDirectionHelper#get, calculate now takes in an ItemOwner instead of a LivingEntity
    • RangeSelectItemModelProperty#get now takes in an ItemOwner instead of a LivingEntity
    • Time$TimeSource#get now takes in an ItemOwner instead of a Entity
  • net.minecraft.world.entity
    • Entity now implements ItemOwner
    • ItemOwner - Represents the owner of the item being rendered.

Container User

As this new version of Minecraft introduces the copper golem (a vanilla mob that can interact with inventories), the concept of an entity that can use a container has been abstracted into its own interface: ContainerUser. ContainerUsers are expected to be implemented on some LivingEntity subclass. Since the actual inventory logic is handled elsewhere, ContainerUser only has two methods: hasContainerOpen, which checks whether the living entity is currently opening some container (e.g., barrel, chest); and getContainerInteractionRange, which determines the radius in blocks that the entity can interact with some container.

  • net.minecraft.world.Container
    • startOpen, stopOpen now take in a ContainerUser instead of a Player
    • getEntitiesWithContainerOpen - Returns the list of ContainerUsers that are interacting with this container.
  • net.minecraft.world.entity.ContainerUser - Typically an entity that can interact with and open a container.
  • net.minecraft.world.entity.player.Player now implements ContainerUser
  • net.minecraft.world.level.block.entity.EnderChestBlockEntity#startOpen, stopOpen now take in a ContainerUser instead of a Player

Name And Id

Unless a GameProfile is needed, Minecraft now passes around a NameAndId for every player instead. As the name implies, NameAndId contains the UUID and name of the player, as that is usually all that’s necessary for most logic involving a player entity.

  • net.minecraft.commands.arguments.GameProfileArgument
    • getGameProfiles now return a collections of NameAndIds
    • $Result#getNames now return a collections of NameAndIds
  • net.minecraft.network.codec.ByteBufCodecs#PLAYER_NAME - A 16 byte string stream codec of the player name.
  • net.minecraft.network.protocol.status.ServerStatus$Players#Sample now is a list of NameAndIds rather than GameProfiles
  • net.minecraft.server
    • MinecraftServer
      • getProfilePermissions now takes in a NameAndId instead of a GameProfile
      • isSingleplayerOwner now takes in a NameAndId instead of a GameProfile
      • ANONYMOUS_PLAYER_PROFILE is now a NameAndId
    • Services now takes in a UserNameToIdResolver instead of a GameProfileCache, and a ProfileResolver
  • net.minecraft.server.players
    • GameProfileCache -> UserNameToIdResolver, CachedUserNameToIdResolver; not one-to-one
      • getAsync is removed
      • add(GameProfile) is removed
    • NameAndId - An object that holds the UUID and name of a profile.
    • PlayerList
      • load -> loadPlayerData, not one-to-one
      • canPlayerLogin now takes in a NameAndId instead of a GameProfile
      • disconnectAllPlayersWithProfile now takes in a UUID instead of a GameProfile
      • op, deop now take in a NameAndId instead of a GameProfile
      • isWhiteListed, isOp now take in a NameAndId instead of a GameProfile
      • canBypassPlayerLimit now takes in a NameAndId instead of a GameProfile
    • ServerOpList now takes in NameAndId as its first generic
      • canBypassPlayerLimit now takes in a NameAndId instead of a GameProfile
    • ServerOpListEntry now takes in NameAndId as its generic and for the constructor
    • UserBanList now takes in NameAndId as its first generic
      • isBanned now takes in a NameAndId instead of a GameProfile
    • UserBanListEntry now takes in NameAndId as its generic and for the constructor
    • UserWhiteList now takes in NameAndId as its first generic
      • isWhiteListed now takes in a NameAndId instead of a GameProfile
    • UserWhiteListEntry now takes in NameAndId as its generic and for the constructor
  • net.minecraft.world.entity.player.Player#nameAndId - Returns the name and id of the player.
  • net.minecraft.world.level.storage.PlayerDataStorage#load(Player, ProblemReporter) -> load(NameAndId), returns an Optional<CompoundTag>

Typed Entity Data

Data components for storing block and entity data have been changed from using CustomData to the type safe variant TypedEntityData. TypedEntityData is pretty much the same as CustomData, storing a CompoundTag, except that it is represented by some IdType generic like EntityType or BlockEntityType. All of the methods within CustomData relating to block entities and entities have moved to TypedEntityData.

Spawn eggs use the TypedEntityData to store the EntityType that it will spawn. The logic of spawning is still tied to the SpawnEggItem subclass.

  • net.minecraft.core.component.DataComponents#ENTITY_DATA, BLOCK_ENTITY_DATA are now TypeEntityData with EntityType and BlockEntityType ids, respectively
  • net.minecraft.world.entity.EntityType#updateCustomEntityTag now takes in a TypedEntityData instead of CustomData
  • net.minecraft.world.item.Item$Properties#spawnEgg - Adds the ENTITY_DATA component with the entity type.
  • net.minecraft.world.item.component
    • CustomData
      • CODEC_WITH_ID is removed
      • COMPOUND_TAG_CODEC - A codec for a flattened compound tag.
      • parseEntityId, parseEntityType are removed
      • loadInto -> TypedEntityData#loadInto
      • update, read, size are removed
      • contains -> TypedEntityData#contains
      • getUnsafe -> TypedEntityData#getUnsafe
    • TypedEntityData - A custom data that provides a type-safe identifier.
  • net.minecraft.world.level.Spawner#appendHoverText, getSpawnEntityDisplayName now take in a TypedEntityData instead of a CustomData
  • net.minecraft.world.level.block.entity.BeehiveBlockEntity$Occupant#entityData is now a TypedEntityData

Reload Listener Shared State

PreparableReloadListener now have an option to share their data between other reload listeners through the use of the PreparableReloadListener#prepareSharedState. prepareSharedState is ran on the main thread before reload is called, which can store arbitrary values to some $SharedKey as basically a dictionary lookup. Then, once reload is called, the stored data can be obtained and used via the key. Normally, the shared values used are some kind of CompletableFuture and joined within.

public class FirstExampleListener implements PreparableReloadListener {

    // Create the key to write the shared data to
    public static final PreparableReloadListener.StateKey<CompletableFuture<Void>> EXAMPLE = new PreparableReloadListener.StateKey<>();

    @Override
    public void prepareSharedState(PreparableReloadListener.SharedState state) {
        // Add the data to the shared state
        state.set(EXAMPLE, CompletableFuture.allOf());
    }

    @Override
    public CompletableFuture<Void> reload(PreparableReloadListener.SharedState state, Executor tasksExecutor, PreparableReloadListener.PreparationBarrier barrier, Executor reloadExecutor) {
        // Use the shared state
        var example = state.get(EXAMPLE);
    }
}


public class SecondExampleListener implements PreparableReloadListener {

    @Override
    public CompletableFuture<Void> reload(PreparableReloadListener.SharedState state, Executor tasksExecutor, PreparableReloadListener.PreparationBarrier barrier, Executor reloadExecutor) {
        // Use the shared state in a different listener
        var example = state.get(FirstExampleListener.EXAMPLE);
    }
}
  • net.minecraft.server.packs.resources
    • PreparableReloadListener
      • reload now takes in a PreparableReloadListener$SharedState instead of a ResourceManager
      • prepareSharedState - A method called before the reload listener is reloaded to share data between reloading listeners.
      • $SharedState - A general dictionary that can provide resources between reload listeners, though they should typically be in the form of CompletableFutures.
      • $StateKey - A key into the shared state.
    • SimpleReloadInstance$StateFactory#create now takes in a PreparableReloadListener$SharedState instead of a ResourceManager

Ticket Flags

TicketType has been updated to take a bit flag representing the flag’s properties rather than a boolean and enum.

// This needs to be registered to BuiltInRegistries#TICKET_TYPE
public static final TicketType EXAMPLE = new TicketType(
    20L, // The number of ticks before the ticket is timed out and removed, set to 0 if the ticket should never time out
    // The bit flags to set, see below for replacements and explanations of the new flags
    TicketType.FLAG_SIMULATION | TicketType.FLAG_LOADING
);
  • net.minecraft.server.level.TicketType now takes in a bitmask of flags rather than a boolean and ticket use
    • FLAG_PERSIST, persist replace the boolean
    • FLAG_LOADING replaces $TicketUse#LOADING
    • FLAG_SIMULATION replaces $TicketUse#SIMULATION
    • FLAG_KEEP_DIMENSION_ACTIVE, shouldKeepDimensionActive - When set, prevents the level from unloading.
    • FLAG_CAN_EXPIRE_IF_UNLOADED, canExpireIfUnloaded - When set, the ticket expires if the chunk is unloaded.
    • START -> PLAYER_SPAWN, SPAWN_SEARCH
    • $TicketUse class is removed
  • net.minecraft.world.level.TicketStorage
    • shouldKeepDimensionActive - Checks if the dimension active flag is set on any tickets in the storage.
    • removeTicketIf now takes a $TicketPredicate instead of a BiPredicate
    • $TicketPredicate - Tests the ticket at a given chunk position.

Respawn Data

The respawn logic has been consolidated into a single object known as LevelData$RespawnData. The respawn data holds the global position (a level key and block position) and the rotation of the entity. All calls to the original angle and position methods have been replaced by Level#setRespawnData or getRespawnData, which delegates to the MinecraftServer and eventually the level data.

  • net.minecraft.client.multiplayer.ClientLevel#setDefaultSpawnPos -> Level#setRespawnData
  • net.minecraft.network.protocol.game.ClientboundSetDefaultSpawnPositionPacket is now a record
    • The parameters have been replaced with a LevelData$RespawnData object
  • net.minecraft.server.MinecraftServer
    • findRespawnDimension - Gets the default ServerLevel that the player should respawn in.
    • setRespawnData - Sets the default spawn position.
    • getRespawnData - Gets the default spawn position.
  • net.minecraft.server.level
    • ServerLevel#setDefaultSpawnPos -> Level#setRespawnData
    • ServerPlayer$RespawnConfig now takes in a LevelData$RespawnData instead of the dimension, position, and angle
      • Fields are still accessible from the respawn data
  • net.minecraft.world.level.Level#getSharedSpawnPos, getSharedSpawnAngle -> getRespawnData, getWorldBorderAdjustedRespawnData, not one-to-one
  • net.minecraft.world.level.storage
    • LevelData
      • getSpawnPos, getSpawnAngle -> getRespawnData, not one-to-one
      • $RespawnData - Defines the global position, yaw, and pitch of where to respawn the players by default.
    • WritableLevelData#setSpawn now only takes in the LevelData$RespawnData

The ‘On Shelf’ Transform

Models now have a new transform for determining how an item sits on a shelf called on_shelf.

  • net.minecraft.client.renderer.block.model.ItemTransforms#fixedFromBottom - A transform that expects the item to be sitting on some fixed bottom, like a shelf.
  • net.minecraft.world.item.ItemDisplayContext#ON_SHELF - When an item is placed on a shelf.

Client Asset Split

ClientAsset has been reworked to better specify what the asset is referencing. Currently, vanilla adds ClientAsset$Texture to specify that the asset is a texture, which further subclasses to $DownloadedTexture for textures downloaded from the internet, and $ResourceTexture for textures accessible from some existing resource on the disk.

  • net.minecraft.advancements.DisplayInfo now takes in an optional ClientAsset$ResourceTexture for the background instead of a ClientAsset
  • net.miencraft.client.renderer.texture.SkinTextureDownloader#downloadAndRegisterSkin now returns a future for the ClientAsset$Texture instead of a ResourceLocation
  • net.minecraft.client.resources
    • PlayerSkin -> net.minecraft.world.entity.player.PlayerSkin
      • The constructor now takes in ClientAsset$Textures instead of ResourceLocation and Strings
      • texture, textureUrl -> body
      • capeTexture -> cape
      • elytraTexture -> elytra
      • insecure - Constructs a PlayerSkin with insecure set to false.
      • with - Builds a PlayerSkin from its $Patch.
      • $Patch - A packed object representing the skin in other files or when sending across the network.
    • SkinManager$TextureCache#getOrLoad now returns a future for the ClientAsset$Texture instead of a ResourceLocation
  • net.minecraft.core.ClientAsset is now an interface instead of a record
    • Original implementation moved to $ResourceTexture
    • id still exists as a method
    • texturePath -> $Texture#texturePath
    • CODEC, DEFAULT_FIELD_CODEC, STREAM_CODEC -> $ResourceTexture#*
    • $DownloadedTexture - A texture downloaded from the internet.
    • $Texture - A client asset which defines a texture.
  • net.minecraft.world.entity.animal.CatVariant#assetInfo now takes in a ClientAsset$ResourceTexture instead of a ClientAsset
  • net.minecraft.world.entity.animal.frog.FrogVariant#assetInfo now takes in a ClientAsset$ResourceTexture instead of a ClientAsset
  • net.minecraft.world.entity.animal.wolf.WolfVariant$AssetInfo#* now take in a ClientAsset$ResourceTexture instead of a ClientAsset
  • net.minecraft.world.entity.variant.ModelAndTexture#asset now takes in a ClientAsset$ResourceTexture instead of a ClientAsset

Cursor Types

The current cursor on screen can now change to a native CursorType, via GLFW#glfwCreateStandardCursor in a GUI via GuiGraphics#requestCursor, or Window#selectCursor anywhere else. Note that Window#setAllowCursorChanges must be true, which can be set through the options menu.

  • com.mojang.blaze3d.platform.Window
    • setAllowCursorChanges - Sets whether the cursor can be changed to a different standard shape.
    • selectCursor - Sets the current cursor to the specified type.
  • com.mojang.blaze3d.platform.cursor
    • CursorType - A definition of a GLFW standard cursor shape.
      • createStandardCursor - Creates a standard cursor from its shape, name, and fallback.
    • CursorTypes - Blaze3d’s cursor types.
  • net.minecraft.client.Options#allowCursorChanges - Sets whether the cursor can be changed to a different standard shape.
  • net.minecraft.client.gui.GuiGraphics
    • requestCursor - Requests the cursor to submit to be rendered.
    • applyCursor - Applies the cursor change for rendering.

New Tags

  • minecraft:block
    • wooden_shelves
    • copper_chests
    • lightning_rods
    • copper
    • copper_golem_statues
    • incorrect_for_copper_tool
    • chains
    • lanterns
    • bars
  • minecraft:entity_types
    • cannot_be_pushed_onto_boats
    • accepts_iron_golem_gift
    • candidate_for_iron_golem_gift
  • minecraft:item
    • wooden_shelves
    • copper_chests
    • lightning_rods
    • copper
    • copper_golem_statues
    • copper_tool_materials
    • repairs_copper_armor
    • chains
    • lanterns
    • bars
    • shearable_from_copper_golem

List of Additions

  • com.mojang.blaze3d.GraphicsWorkarounds#isGlOnDx12 - Returns whether the renderer is using DirectX 12.
  • com.mojang.blaze3d.opengl.GlStateManager#incrementTrackedBuffers - Increments the number of buffers used by the game.
  • com.mojang.blaze3d.systems.TimerQuery#isRecording - Returns whether there is a query that’s currently active.
  • net.minecraft.SharedConstants#RESOURCE_PACK_FORMAT_MINOR, DATA_PACK_FORMAT_MINOR - The minor component of the pack version.
  • net.minecraft.advancements.critereon.MinMaxBounds
    • bounds - Returns the bounds of the value.
    • $FloatDegrees - A bounds for a float representing the degree of some angle.
  • net.minecraft.client
    • Minecraft
      • isOfflineDevelopedMode - Returns whether the game is in offline developer mode.
      • canSwitchGameMode - Whether the player entity exists and has a game mode.
      • playerSkinRenderCache - Returns the cache holding the player’s render texture.
      • canInterruptScreen - Whether the current screen can be closed by another screen.
      • packetProcessor - Returns the processor that schedules and handles packets.
    • Options
      • invertMouseX - When true, inverts the X mouse movement.
      • toggleAttack - When true, sets the attack key to be toggleable.
      • toggleUse - When true, sets the use key to be toggleable.
      • sprintWindow - Time window in ticks where double-tapping the forward key activates sprint.
      • saveChatDrafts - Returns whether the message being typed in chat should be retained if the box is closed.
      • keySpectatorHotbar - A key that pulls up the spectator hotbar menu.
    • ToggleKeyMapping#shouldRestoreStateOnScreenClosed - Whether the previous toggle state should be restored after screen close.
  • net.minecraft.client.animation.definitions.CopperGolemAnimation - The animations for the copper golem.
  • net.minecraft.client.data.models.BlockModelGenerators
    • and - ANDs the given conditions together.
    • createShelf - Creates a shelf block state from a base and a particle texture.
    • addShelfPart - Adds a variant for a model for all the shelf’s states.
    • forEachHorizontalDirection - Performs an operation for a pair of directions and rotations.
    • shelfCondition - Constructs a condition based on the state of the shelf.
    • createCopperGolemStatues - Creates all copper golem statues.
    • createCopperGolemStatue - Creates a copper golem statue for the provided block, copper block, and weathered state.
    • createCopperChests - Creates all copper chests.
    • createCopperLantern - Creates a lantern and hanging lantern.
    • createCopperChain - Creates a chain.
    • createCopperChainItem - Creates a chain item model.
  • net.minecraft.client.data.models.model
    • ModelTemplate
      • SHELF_* - Model templates for constructing a shelf into a multipart.
      • LIGHTNING_ROD - Model template for a lightning rod.
      • CHAIN - Model template for a chain.
      • BARS_* - Model templates for constructing a bars-like block.
    • TexturedModel#CHAIN - A model provider for a chain.
    • TextureMapping#bars - A texture mapping for a bars-like block.
    • TextureSlot#BARS - A reference to the #bars texture.
  • net.minecraft.client.gui
    • Gui#renderDeferredSubtitles - Renders the subtitles on screen.
    • GuiGraphics#getSprite - Gets a TextureAtlasSprite from its material.
  • net.minecraft.client.gui.components
    • AbstractScrollArea#isOverScrollbar - Returns whether the current cursor position is over the scroll bar.
    • AbstractSelectionList
      • sort - Sorts the entries within the list.
      • swap - Swaps the position of two entries in the list
      • clearEntriesExcept - Removes all entries that don’t match the provided element.
      • getNextY - Returns the Y component to render the scrolled component.
      • entriesCanBeSelected - Whether the entries in the list can be selected.
      • scrollToEntry - Scrolls the bar such that the selected entry is on screen.
      • removeEntries - Removes all entries that are in the provided list.
      • $Entry
        • set* - Sets the component size.
        • getContent* - Get the content size and positions.
    • ChatComponent
      • saveAsDraft, discardDraft - Handles the draft message in the chat box.
      • createScreen, openScreen, preserveCurrentChatScreen, restoreChatScreen - Handles screen behavior depending on the draft chat option.
      • $ChatMethod - Defines what type of message is the chat.
      • $Draft - Defines a draft message in the chat box.
    • EditBox
      • DEFAULT_HINT_STYLE - The style of the default hints.
      • SEARCH_HINT_STYLE - The style of the searchable hints, such as in a recipe book.
      • $TextFormatter - An interface used to format the string in the box.
    • FittingMultiLineTextWidget#minimizeHeight - Sets the height of the widget to the inner height and padding.
    • FocusableTextWidget$BackgroundFill - An enum that represents when the background should be filled.
    • ItemDisplayWidget#renderTooltip - Submits the tooltip to render.
    • MultiLineLabel$Align - Handles the alignment of the label.
    • MultilineTextField#selectWordAtCursor - Selects the word whether the cursor is currently located.
    • SpriteIconButton$Builder#withTooltip - Sets the tooltip to display the message.
    • StringWidget
      • setMaxWidth - Sets the max width of the string and how to handle the extra width.
      • $TextOverflow - What to do if the text is longer than the max width.
  • net.minecraft.client.gui.components.events.GuiEventListener#shouldTakeFocusAfterInteraction - When true, sets the element as focused when clicked.
  • net.minecraft.client.gui.screens
    • ChatScreen
      • isDraft - Whether there is a message that hasn’t been sent in the box.
      • exitReason - The reason the chat screen was closed.
      • shouldDiscardDraft - Whether the current draft message should be discarded.
      • $ChatConstructor - A constructor for the chat screen based on the draft state.
      • $ExitReason - The reason the chat screen was closed.
    • FaviconTexture#isClosed - Returns whether the texture has been closed.
    • LevelLoadingScreen
      • update - Updates the current load tracker and reason.
      • $Reason - The reason for changing the level loading screen.
    • Overlay#tick - Ticks the overlay.
    • Screen
      • panoramaShouldSpin - Returns whether the rendered panorama should spin its camera.
      • setNarrationSuppressTime - Sets until when the narration should be suppressed for.
      • isInGameUi - Returns whether the screen is opened while playing the game, not the pause menu.
      • isAllowedInPortal - Whether this screen can be open during the portal transition effect.
      • canInterruptWithAnotherScreen - Whether this screen can be closed by another screen, defaults to ‘close on escape’ screens.
  • net.minecraft.client.gui.screens.inventory.AbstractCommandBlockScreen#addExtraControls - Adds any extra widgets to the command block screen.
  • net.minecraft.client.gui.screens.multiplayer
    • CodeOfConductScreen - A screens that displays the code of conduct text for a server.
    • ServerSelectionList$Entry
      • matches - Returns whether the provided entry matches this one.
      • join - Handles how the client joins to the server entry.
  • net.minecraft.client.gui.screens.reporting.ChatSelectionScreen$ChatSelectionList#ITEM_HEIGHT - The height of each entry in the list.
  • net.minecraft.client.gui.screens.worldselection.WorldSelectionList
    • returnToScreen - Returns to the previous screen after reloading the world list.
    • $Builder - Creates a new WorldSelectionList.
    • $Entry#getLevelSummary - Returns the summary of the selected world.
    • $EntryType - A enum representing what type of world the entry is.
    • $NoWorldsEntry - An entry where there are no worlds to select from.
  • net.minecraft.client.main.GameConfig$GameData#offlineDeveloperMode - Whether the game is offline and is ran for development.
  • net.minecraft.client.multiplayer
    • ClientCommonPacketListenerImpl
      • seenPlayers - All players that have been seen, regardless of if they are currently online, by this player.
      • seenInsecureChatWarning - If the player has seen the insecure chat warning.
      • $CommonDialogAccess - A dialog access used by the client network.
    • ClientConfigurationPacketListenerImpl#DISCONNECTED_MESSAGE - The message to display on disconnect because of not accepting the code of conduct.
    • ClientExplosionTracker - Tracks the explosions made on the client, specifically to handle particles.
    • ClientLevel
      • endFlashState - Handles the state of the flashes of light that appear in the end.
      • trackExplosionEffects - Tracks an explosion to handle its particles.
    • ClientPacketListener
      • getSeenPlayers - Returns all players seen by this player.
      • getPlayerInfoIgnoreCase - Gets the player info for the provided profile name.
  • net.minecraft.client.player.LocalPlayerResolver - A profile resolver for the local player.
  • net.minecraft.client.resources.WaypointStyle#ICON_LOCATION_PREFIX - The prefix for waypoint icons.
  • net.minecraft.client.server.IntegratedServer#MAX_PLAYERS - The maximum number of players allowed in an locally hosted server.
  • net.minecraft.client.sounds
    • DirectionalSoundInstance - A sound that changes position based on the direction of the camera.
    • SoundEngineExecutor#startUp - Creates the thread to run the engine on.
    • SoundPreviewHandler - A utility for previewing how some event would sound like with the given settings.
  • net.minecraft.core
    • BlockPos#betweenCornersInDirection - An iterable that iterates through the provided bounds in the direction provided by the vector.
    • Direction#axisStepOrder - Returns a list of directions that the given vector should be checked in.
  • net.minecraft.core.particles.ExplosionParticleInfo - The particle that used as part of an explosion.
  • net.minecraft.data.loot.BlockLootSubProvider#createCopperGolemStatueBlock - The loot table for a copper golem statue.
  • net.minecraft.data.loot.packs
    • VanillaBlockInteractLoot - A sub provider for vanilla block loot from entity interaction.
    • VanillaChargedCreeperExplosionLoot - A sub provider for vanilla entity loot from charged creeper explosions.
    • VanillaEntityInteractLoot - A sub provider for vanilla entity loot from entity interaction.
  • net.minecraft.data.recipes.RecipeProvider#shelf - Constructs a shelf recipe from one item.
  • net.minecraft.data.worldgen.BiomeDefaultFeatures#addNearWaterVegetation - Adds the vegetation when near a body of water.
  • net.minecraft.gametest.framework.GameTestHelper#getTestDirection - Gets the direction that the test is facing.
  • net.minecraft.network
    • FriendlyByteBuf#readLpVec3, writeLpVec3 - Handles syncing a compressed Vec3.
    • LpVec3 - A vec3 network handler that compresses and decompresses a vector into at most two bytes and two integers.
    • PacketProcessor - A processor for packets to be scheduled and handled.
  • net.minecraft.network.chat.CommonComponents#GUI_COPY_TO_CLIPBOARD - The message to display when copying a chat to the clipboard.
  • net.minecraft.network.protocol.configuration
    • ClientboundCodeOfConductPacket - A packet the sends the code of conduct of a server to the joining client.
    • ClientConfigurationPacketListener#handleCodeOfConduct - Handles the code of conduct sent from the server.
    • ServerboundAcceptCodeOfConductPacket - A packet that sends the acceptance response of a client reading the code of conduct from a server.
    • ServerConfigurationPacketListener#handleAcceptCodeOfConduct - Handles the acceptance of the code of conduct from the client.
  • net.minecraft.network.syncher.EntityDataSerializers
    • WEATHERING_COPPER_STATE - The weather state of the copper on the golem.
    • COPPER_GOLEM_STATE - The logic state of the copper golem.
    • RESOLVABLE_PROFILE - The resovlable profile of an entity.
  • net.minecraft.server.MinecraftServer
    • selectLevelLoadFocusPos - Returns the loading center position of the server, usually the shared spawn position.
    • getLevelLoadListener - Returns the listener used to track level loading.
    • getCodeOfConducts - Returns a map of file names to their code of conduct text.
    • enforceGameTypeForPlayers - Sets the game type of all players.
    • packetProcessor - Returns the packet processor for the server.
  • net.minecraft.server.commands.FetchProfileCommand - Fetches the profile of a given user.
  • net.minecraft.server.dedicated.DedicatedServerProperties#codeOfConduct - Whether the server has a code of conduct.
  • net.minecraft.server.level
    • ChunkLoadCounter - Keeps track of chunk loading when a level is loading or the player spawns.
    • ChunkMap
      • getLatestStatus - Returns the latest status for the given chunk position.
      • isTrackedByAnyPlayer - Checks whether the entity is tracked by any player.
      • forEachEntityTrackedBy - Loops through each entity tracked by the given player.
      • forEachReadyToSendChunk - Loops through each chunk that is ready to be sent to the client.
    • ServerChunkCache
      • hasActiveTickets - Checks whether the current level has any active tickets keeping it loaded.
      • addTicketAndLoadWithRadius - Adds a ticket to some location and loads the chunk and radius around that location.
    • ServerEntity$Synchronizer - Handles sending packets to tracking entities.
    • ServerLevel#isSpawningMonsters - Returns whether the server can spawn monsters.
    • ServerPlayer$SavedPosition - Holds the current position of the player on disk.
  • net.minecraft.server.level.progress.ChunkLoadStatusView - A status view for the loading chunks.
  • net.minecraft.server.network.ConfigurationTask#tick - Calls the task every tick until it returns true, then finishes the task.
  • net.minecraft.server.network.config
    • PrepareSpawnTask - A configuration task that finds the spawn of the player.
    • ServerCodeOfConductConfigurationTask - A configuration task that sends the code of conduct to the client.
  • net.minecraft.server.packs.OverlayMetadataSection
    • codecForPackType - Constructs a codec for the section given the pack type.
    • forPackType - Gets the metadata section type from the pack type.
  • net.minecraft.server.packs.metadata.MetadataSectionType#withValue, $WithValue - Holds a metadata section along with its provided value.
  • net.minecraft.server.packs.metadata.pack
    • PackFormat - Represents the major and minor revision of a pack.
    • PackMetadataSection#forPackType - Gets the metadata section type from the pack type.
  • net.minecraft.server.packs.repository.PackCompatibility#UNKNOWN - The compatibility of the pack with the game is unknown as the major version is set to the max integer value.
  • net.minecraft.server.packs.resources.ResourceMetadata#getTypedSection, getTypedSections - Gets the metadata sections for the provided types.
  • net.minecraft.server.players.ProfileResolver - Resolves a game profile from its name or UUID.
  • net.minecraft.util
    • ExtraCodecs
      • gameProfileCodec - Creates a codec for a GameProfile given the UUID codec.
      • $LateBoundIdMapper#values - Returns a set of values within the mapper.
    • InclusiveRange#map - Maps a range from one generic to another.
    • Mth#ceilLong - Returns the double rounded up to the nearest long.
  • net.minecraft.util.random
    • Weighted#streamCodec - Constructs a stream codec for the weighted entry.
    • WeightedList#streamCodec - Constructs a stream codec for the weighted list.
  • net.minecraft.util.thread.BlockableEventLoop#shouldRunAllTasks - Returns if there are any blocked tasks.
  • net.minecraft.world.Nameable#getPlainTextName - Returns the string of the name component.
  • net.minecraft.world.entity
    • Avatar - An entity that makes up the base of a player.
    • EntityReference
      • getEntity - Returns the entity given the type class and the level.
      • Static getEntity, getLivingEntity, getPlayer - Returns the entity given its EntityReference and level.
    • EntityType
      • MANNEQUIN - The mannequin entity type.
      • STREAM_CODEC - The stream codec for an entity type.
      • $Builder#notInPeaceful - Sets the entity to not spawn in peaceful mode.
    • Entity
      • canInteractWithLevel - Whether the entity can interact with the current level.
      • isInShallowWater - Returns whether the player is in water but not underwater.
      • getAvailableSpaceBelow - Returns the amount of space in the Y direction between the entity and the collider, offset by the given value.
      • collectAllColliders - Returns all entity collisions.
    • InsideBlockEffectType#CLEAR_FREEZE - A in-block effect that clears the frozen ticks.
    • LivingEntity
      • dropFromEntityInteractLootTable - Drops loot from a table from an entity interaction.
      • shouldTakeDrowningDamage - Whether the entity should take damage from drowning.
    • Mob#WEARING_ARMOR_UPGRADE_MATERIAL_CHANCE, WEARING_ARMOR_UPGRADE_MATERIAL_ATTEMPTS - Constants for the armor material upgrade.
    • PositionMoveRotation#withRotation - Creates a new object with the provided XY rotation.
    • Relative
      • rotation - Gets the set of relative rotations from the XY booleans.
      • position - Gets the set of relative positions from the XYZ booleans.
      • direction - Gets the set of relative deltas from the XYZ booleans.
  • net.minecraft.world.entity.ai.Brain#isBrainDead - Returns whether the brain does not have any memories, snesors, or behaviors.
  • net.minecraft.world.entity.ai.behavior.TransportItemsBetweenContainers - A behavior where an entity will move items between visited containers.
  • net.minecraft.world.entity.ai.memory.MemoryModuleType
    • VISITED_BLOCK_POSITIONS - Important block positions visited.
    • TRANSPORT_ITEMS_COOLDOWN_TICKS - How many ticks to wait before transporting items.
    • UNREACHABLE_TRANSPORT_BLOCK_POSITIONS - Holds a list of positions that are impossible to get to.
  • net.minecraft.world.entity.ai.navigation.GroundPathNavigation#setCanPathToTargetsBelowSurface - Sets whether the entity can target other entities that are underneath a non-air block below the starting position.
  • net.minecraft.world.entity.animal.coppergolem
    • CopperGolem - The copper golem entity.
    • CopperGolemAi - The brain logic for the copper golem.
    • CopperGolemOxidationLevel - A record holding the source events and textures for a given oxidation level.
    • CopperGolemOxidationLevels - All vanilla oxidation levels.
    • CopperGolemState - The current logic state the copper golem is in.
  • net.minecraft.world.entity.decoration
    • HangingEntity#canCoexist - Whether any other hanging entities are in the same position as this one. By default, makes sure that the entities are not the same entity type and not facing the same direction.
    • Mannequin - An avatar that does not have a connected player.
  • net.minecraft.world.entity.player
    • Player
      • isMobilityRestricted - Returns whether the player has the blindness effect.
      • handleShoulderEntities - Handles the entities on the player’s shoulders.
      • extractParrotVariant, convertParrotVariant, *ShoulderParrot* - Handles the parrot on the player’s shoulders.
    • PlayerModelPart#CODEC - The codec for the model part.
  • net.minecraft.world.entity.raid.Raids#getRaidCentersInChunk - Returns the number of raid centers in the given chunk.
  • net.minecraft.world.entity.vehicle.MinecartFurnace#addFuel - Adds fuel to the furnace to push the entity.
  • net.minecraft.world.item
    • BucketItem#getContent - Returns the fluid held in the bucket.
    • Item$TooltipContext#isPeaceful - Returns true if the difficulty is set to peaceful.
    • ToolMaterial#COPPER - The copper tool material.
    • WeatheringCopperItems - A record of items that represent each of the weathering copper states.
  • net.minecraft.world.item.equipment
    • ArmorMaterials#COPPER - The copper armor material.
    • EquipmentAssets#COPPER - The key reference to the copper equipment asset.
    • ResolvableProfile
      • skinPatch - Returns the player skin reference.
      • $Static - Uses the already resolved game profile.
      • $Dynamic - Dynamically resolves the game profile on use.
      • $Partial - Represents part of the game profile depending on whatever information is provided to the component.
  • net.minecraft.world.level
    • BaseCommandBlock$CloseableCommandBlockSource - A command source typically for a command block.
    • ChunkPos#contains - Whether the given block position is in the chunk.
    • GameRules#RULE_SPAWNER_BLOCKS_ENABLED - Whether spawner blocks should spawn entities.
    • Level
      • getEntityInAnyDimension - Gets the entity by UUID.
      • getPlayerInAnyDimension - Gets the player by UUID.
      • hasEntities - Returns whether the provided bounds has entities matching the type and predicate.
      • palettedContainerFactory - Returns the factory used to create paletted containers.
  • net.minecraft.world.level.border.WorldBorder$Settings#toWorldBorder - Constructs a world border from the settings.
  • net.minecraft.world.level.block
    • Block#dropFromBlockInteractLootTable - Drops the loot when interacting with a block.
    • ChestBlock
      • chestCanConnectTo - Returns whether the chest can merge with another block.
      • getConnectedBlockPos - Gets the connected block position of the chest.
      • getOpenChestSound, getCloseChestSound - Returns the sounds played on chest open / close.
      • getChestType - Returns the type of the chest based on the surrounding chests.
    • ChiseledBookShelfBlock#FACING, SLOT_*_OCCUPIED - The block state properties of the chiseled bookshelf.
    • CopperChestBlock - The block for the copper chest.
    • CopperGolemStatueBlock - The block for the copper golem statue.
    • SelectableSlotContainer - A container whose slot can be selected based on in-game interaction.
    • ShelfBlock - A block for the shelf.
    • SideChainPartBlock - A helper for providing how the chain of a shelf should be displayed.
    • WeatheringCopper$WeatherState
      • BY_ID - The mapper of enum ordinal to state.
      • STREAM_CODEC - The stream codec for the state.
      • next - Gets the next state in the ordinal.
      • previous - Gets the previous state in the ordinal.
    • WeatheringCopperBarsBlock - The block for weathering copper bars.
    • WeatheringCopperBlocks - A record of blocks that represent each of the weathering copper states.
    • WeatheringCopperChainBlock - The block for weathering copper chains.
    • WeatheringCopperChestBlock - The block for the weathering copper chest.
    • WeatheringCopperGolemStatueBlock - The block for the weathering copper golem statue.
    • WeatheringLanternBlock - The block for weathering lanterns.
    • WeatheringLightningRodBlock - The block for the weathering lightning rod.
  • net.minecraft.world.level.block.entity
    • BaseContainerBlockEntity#isLocked - Returns whether the block entity has a lock.
    • CopperGolemStatueBlockEntity - The block entity for the copper golem statue.
    • ListBackedContainer - A container that is baked by a list of items.
    • ShelfBlockEntity - The block entity for the shelf.
  • net.minecraft.world.level.block.entity.vault.VaultConfig#playerDetector - Returns the detector used to detect specific entities.
  • net.minecraft.world.level.block.state.BlockBehaviour#shouldChangedStateKeepBlockEntity, $BlockStateBase#shouldChangedStateKeepBlockEntity - Returns whether the block entity should be kept if the block is changed to a different block.
  • net.minecraft.world.level.block.state.properties.SideChainPart - The location of where the chain of an object is connected to.
  • net.minecraft.world.level.chunk
    • Configuration - Configures what type of pallete should be created.
    • PalettedContainerFactory - A factory for constructing paletted containers using the provided strategies.
    • PalettedContainerRO#bitsPerEntry - Returns the number of bits needed to represent an entry.
    • PaletteResize#noResizeExpected - Returns a resizer that throws an exception.
  • net.minecraft.world.level.levelgen
    • Beardifier#EMPTY - An instance with no pieces or junctions.
    • DensityFunction#invert - Inverts the density output by putting the result one over the value.
    • DensityFunctions#findTopSurface - Finds the top surface between the two bounds.
    • NoiseChunk#maxPreliminarySurfaceLevel - Returns the largest preliminary surface level.
    • NoiseRouterData#NOISE_ZERO - A constant containing the base noise level for layer zero in the overworld.
  • net.minecraft.world.level.levelgen.blending.Blender#isEmpty - Returns whether there is no blending data present.
  • net.minecraft.world.level.levelgen.structure.BoundingBox
    • encapsulating - Returns the smallest box that includes the given boxes.
    • STREAM_CODEC - The stream codec for the bounding box.
  • net.minecraft.world.level.levelgen.structure.structures.JigsawStructure$MaxDistance - The maximum horizontal and vertical distance the jigsaw can expand to.
  • net.minecraft.world.level.pathfinder.Path#STREAM_CODEC - The stream codec of the path.
  • net.minecraft.world.level.portal.TeleportTransition#createDefault - Creates the default teleport transition.
  • net.minecraft.world.level.storage.loot.LootContext
    • $BlockEntityTarget - Specifies targets when interacting with a block entity.
    • $EntityTarget
      • TARGET_ENTITY - The entity being targeted by another, typically the object dropping the loot.
      • INTERACTING_ENTITY - The entity interacting with the object dropping the loot.
    • $ItemStackTarget - Specifies targets when interacting or using an item stack.
  • net.minecraft.world.level.storage.loot.parameters
    • LootContextParams
      • TARGET_ENTITY - The entity being targeted by another, typically the object dropping the loot.
      • INTERACTING_ENTITY - The entity interacting with the object dropping the loot.
    • LootContextParamSets
      • ENTITY_INTERACT - An entity being interacted with.
      • BLOCK_INTERACT - A block being interacted with.
  • net.minecraft.world.phys.Vec3#X_AXIS, Y_AXIS, Z_AXIS - The unit vector in the positive direction of each axis.
  • net.minecraft.world.phys.shapes.CollisionContext
    • alwaysCollideWithFluid - Whether the collision detector should always collide with a fluid in its path.
    • emptyWithFluidCollisions - Returns an empty collision context while checking for any fluid collisions.
  • net.minecraft.world.waypoints.PartialTickSupplier - Gets the partial tick given the provided entity.

List of Changes

  • com.mojang.blaze3d.buffers.GpuBuffer#size is now private
  • com.mojang.blaze3d.opengl
    • DirectStateAccess
      • bufferSubData, mapBufferRange, unmapBuffer, flushMappedBufferRange now take in the buffer usage bit mask
      • create now takes in the GraphicsWorkarounds
    • GlStateManager#_texImage2D, _texSubImage2D now takes in a ByteBuffer instead of an IntBuffer
    • VertexArrayCache#bindVertexArray can now take in a nullable GlBuffer
  • com.mojang.blaze3d.platform
    • ClipboardManager#getClipboard, setClipboard now take in a Window instead of the long handle
    • MacosUtil#exitNativeFullscreen, clearResizableBit, getNsWindow now take in a Window instead of the long handle
    • Window#getWindow -> handle
  • com.mojang.blaze3d.systems
    • CommandEncoder#writeToTexture now takes in a ByteBuffer instead of an IntBuffer
    • RenderSystem#flipFrame now takes in a Window instead of the long handle
    • TimerQuery#getInstance now returns the raw instance rather than an optional-wrapped instance
  • com.mojang.blaze3d.vertex
    • PoseStack$Pose#set is now public
    • VertexConsumer#addVertexWith2DPose no longer takes in the z component
  • net.minecraft
    • CrashReportCategory#formatLocation now has an overload that doesn’t take in the LevelHeightAccessor
    • DetectedVersion#createFromConstants -> createBuiltIn, now public, taking in the id, name, and optional stable boolean
    • SharedConstants#*_PACK_FORMAT -> *_PACK_FORMAT_MAJOR
    • WorldVersion
      • packVersion now returns a PackFormat
      • $Simple now takes in a PackFormat for the resourcePackVersion and datapackVersion
  • net.minecraft.advancements.critereon
    • MinMaxBounds now requires its generic to be Comparable
      • min, max are now default
      • unwrapPoint -> $Bounds#asPoint
      • fromReader is now public
      • $Doubles, $Ints now take in $Bounds for its values
    • WrappedMinMaxBounds -> MinMaxBounds$Bounds, not one-to-one
  • net.minecraft.client
    • Minecraft
      • setLevel no longer takes in the ReceivingLevelScreen$Reason
      • cameraEntity is now private
      • openChatScreen is now public, taking in the ChatComponent$ChatMethod
      • setCamerEntity can now take in a null entity
      • forceSetScreen -> setScreenAndShow
      • getMinecraftSessionService -> services, now returning a Service instance
        • The MinecraftSessionService can be obtained via Service#sessionService
    • Options#invertYMouse -> invertMouseY
    • User no longer takes in the user type
  • net.minecraft.client.data.models.BlockModelGenerators
    • condition now has an overload that takes in an enum or boolean property
    • createLightningRod now takes in the regular and waxed blocks
    • createIronBars -> createBarsAndItem, createBars; not one-to-one
  • net.minecraft.client.gui.GuiGraphics#submitSignRenderState now takes in a Model$Simple instead of a Model
  • net.minecraft.client.gui.components
    • AbstractScrollArea#renderScrollbar now takes in the current XY position of the cursor.
    • AbstractSelectionList no longer takes in the header height
      • itemHeight -> defaultEntryHeight
      • addEntry, addEntryToTop now takes in the height of the element
      • removeEntryFromTop no longer returns anything
      • updateSizeAndPosition can now take in an X component
      • renderItem now takes in the entry instead of five integers
      • renderSelection now takes in the entry instead of four integers
      • removeEntry no longer returns anything
      • $Entry now implements LayoutElement
      • render, renderBack -> renderContent
    • ContainerObjectSelectionList no longer takes in the headerh height
    • EditBox#setFormatter -> addFormatter, not one-to-one
    • FocusableTextWidget now takes in a $BackgroundFill instead of a boolean
    • MultiLineLabel
      • renderCentered, renderLeftAligned, renderLeftAlignedNoShadow -> render, not one-to-one
      • getStyleAtCentered, getStyleAtLeftAligned -> getStyle, not one-to-one
    • ObjectSelectionList no longer takes in the headerh height
    • SpriteIconButton now takes in a WidgetSprites instead of a ResourceLocation, and toolip Component
      • sprite is now a WidgetSprites
      • $Builder#sprite now has an overload that takes in a WidgetSprites
      • $CenteredIcon now takes in a WidgetSprites instead of a ResourceLocation, and toolip Component
      • $TextAndIcon now takes in a WidgetSprites instead of a ResourceLocation, and toolip Component
    • WidgetSprites now has an overload with a single ResourceLocation
  • net.minecraft.client.gui.components.spectator.SpectatorGui#onMouseMiddleClick -> onHotbarActionKeyPressed
  • net.minecraft.client.gui.render.state
    • GuiElementRenderState#buildVertices no longer takes in the z component
    • GuiRenderState#forEachElement now takes in a Consumer<GuiElementRenderState> instead of a GuiRenderState$LayeredElementConsumer
  • net.minecraft.client.gui.render.state.pip.GuiSignRenderState now takes in a Model$Simple instead of a Model
  • net.minecraft.client.gui.screens
    • ChatScreen now takes in a boolean representing whether the message is a draft
      • initial is now protected
    • EditServerScreen -> ManageServerScreen
    • InBedChatScreen now takes in the initial text and whether there is a draft mesage in the box
    • LevelLoadingScreen now takes in a LevelLoadTracker and LevelLoadingScreen$Reason
    • PauseScreen#disconnectFromWorld -> Minecraft#disconnectFromWorld
    • ReceivingLevelScreen has been merged into LevelLoadingScreen
    • Screen
      • renderWithTooltip -> renderWithTooltipAndSubtitles
      • $NarratableSearchResult is now a record
      • isValidCharacterForName now takes in a codepoint int instead of a char
  • net.minecraft.client.gui.screens.achievement.StatsScreen
    • initLists, initButtons merged into onStatsUpdated
    • $ItemRow#getItem is now protected
  • net.minecraft.client.gui.screens.dialog.DialogScreen$WarningScreen#create now takes in a DialogConnectionAccess
  • net.minecraft.client.gui.screens.inventory.tooltip.ClientActivePlayersTooltip$ActivePlayersTooltip#profiles now is a list of PlayerSkinRenderCache$RenderInfos instead of ProfileResults
  • net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen
    • *_BUTTON_WIDTH are now private
    • join is now public
  • net.minecraft.client.gui.screens.options.OptionsScreen#CONTROLS is now public
  • net.minecraft.client.gui.screens.packs
    • PackSelectionModel now takes in a Consumer<PackSelectionModel$EntryBase> instead of a Runnable
      • $EntryBase is now public
    • TransferableSelectionList now is a list of $Entrys instead of $PackEntrys
      • $PackEntry is no longer static and extends $Entry
  • net.minecraft.client.gui.screens.worldselection
    • CreateWorldScreen#openFresh, testWorld, createFromExisting now take in a Runnable instead of a Screen
    • WorldSelectionList now has a package-private constructor
      • getScreen now returns a basic Screen
      • $WorldListEntry is now static
        • canJoin -> canInteract, not one-to-one
  • net.minecraft.client.gui.spectator.PlayerMenuItem now only takes in the PlayerInfo
  • net.minecraft.client.main.GameConfig$UserData no longer takes in the PropertyMaps
  • net.minecraft.client.multiplayer
    • ClientHandshakePacketListenerImpl now takes in a LevelLoadTracker
    • CommonListenerCookie now takes in a LevelLoadTracker, map of seen players, and whether the insecure chat warning has been shown
    • LevelLoadStatusManager -> LevelLoadTracker, not one-to-one
      • CLOSE_DELAY_MS -> LEVEL_LOAD_CLOSE_DELAY_MS, now public
    • TransferState now takes in a map of seen players and whether the insecure chat warning has been shown
  • net.minecraft.client.multiplayer.chat.ChatListener#clearQueue -> flushQueue
  • net.minecraft.client.renderer
    • DimensionSpecialEffects#forceBrightLightmap -> hasEndFlashes, not one-to-one
    • LevelEventHandler now takes in a ClientLevel instead of the Level and LevelRenderer
    • LevelRenderer
      • prepareCullFrustum is now private
      • renderLevel now takes in an additional Matrix4f for the frustum
  • net.minecraft.client.resources.WaypointStyle#validate is now public
  • net.minecraft.client.server.IntegratedServer now takes in a LevelLoadListener instead of a ChunkProgressListenerFactory
  • net.minecraft.client.sounds
    • SoundEngine#updateCategoryVolume no longer takes in the gain
    • SoundEngineExecutor#flush -> shutDown, not one-to-one
    • SoundManager#updateSourceVolume no longer takes in the gain
  • net.minecraft.commands.arguments.coordinates
    • LocalCoordinates is now a record
    • WorldCoordinate is now a record
    • WorldCoordinates is now a record
  • net.minecraft.commands.arguments.selector.EntitySelectorParser
    • getDistance, getLevel can now be null
    • *Rot* methods now return or use MinMaxBounds$FloatDegrees
      • Return values can be null
  • net.minecraft.core.Registry
    • getRandomElementOf -> HolderGetter#getRandomElementOf
    • registerForHolder now has an additional generic, making the Holder$Reference returned hold the actual object type instead of the registry type
  • net.minecraft.core.component.PatchedDataComponentMap#set now has an overload that takes in a TypedDataComponent
  • net.minecraft.data.worldgen.TerrainProvider methods now use a BoundedFloatFunction generic instead of ToFloatFunction
  • net.minecraft.gametest.framework
    • GameTestHelper
      • spawn now has overloads that take in some number of entities to spawn
      • setBlock now has overloads to take in a direction for block facing
      • fail now has an overload that takes in a string
    • GameTestRunner now takes in whether the level should be cleared for more space to spawn between batches
      • $Builder#haltOnError no longer takes in any parameters
  • net.minecraft.nbt.NbtUtils#addDataVersion, addCurrentDataVersion now has an overload that takes in a Dynamic instead of a CompoundTag or ValueOutput
  • net.minecraft.network
    • FriendlyByteBuf#readSectionPos, writeSectionPos -> SectionPos#STREAM_CODEC
    • VarInt#MAX_VARINT_SIZE is now public
  • net.minecraft.network.protocol.PacketUtils#ensureRunningOnSameThread now takes in a PacketProcessor instead of a BlockableEventLoop
  • net.minecraft.network.protocol.game
    • ClientboundAddEntityPacket#getXa, getYa, getZa -> getMovement
    • ClientboundExplodePacket now takes in a radius, block count, and the block particles to display
    • ClientboundPlayerRotationPacket now takes in whether the XY rotation is relative
    • ClientboundSetEntityMotionPacket#getXa, getYa, getZa -> getMovement
  • net.minecraft.server
    • SPAWN_POSITION_SEARCH_RADIUS is now public
    • MinecraftServer now takes in a LevelLoadListener instead of a ChunkProgressListenerFactory
      • createLevels no longer takes in a ChunkProgressListener
      • getSessionService, getProfileKeySignatureValidator, getProfileRepository, getProfileCache -> services, not one-to-one
        • getProfileCache is now nameToIdCache, not one-to-one
      • updateMobSpawningFlags is now public
  • net.minecraft.server.level
    • ChunkMap no longer takes in the ChunkProgressListener
      • getTickingGenerated -> allChunksWithAtLeastStatus, not one-to-one
      • broadcast, broadcastAndSend -> sendToTrackingPlayers, sendToTrackingPlayersFiltered, sendToTrackingPlayersAndSelf; not one-to-one
    • PlayerRespawnLogic -> PlayerSpawnFinder, not one-to-one
    • ServerChunkCache no longer takes in the ChunkProgressListener
      • broadcastAndSend -> sendToTrackingPlayersAndSelf, not one-to-one
      • broadcast -> sendToTrackingPlayers, not one-to-one
    • ServerEntity now takes in a $Synchronizer instead of the brodcast method references
    • ServerEntityGetter#getNearestEntity now has an overload that takes in a TagKey of entities instead of a class
    • ServerLevel no longer takes in the ChunkProgressListener
      • waitForChunkAndEntities -> waitForEntities, not one-to-one
      • tickCustomSpawners no longer takes in the tick friendlies boplean
  • net.minecraft.server.level.chunk
    • ChunkAccess now takes in a PalettedContainerFactory instead of a Registry<Biome>
  • net.minecraft.server.level.progress
    • ChunkProgressListener -> LevelLoadListener, not one-to-one
    • ChunkProgressListenerFactory -> MinecraftServer#createChunkLoadStatusView, not one-to-one
    • LoggerChunkProgressListener -> LoggingLevelLoadListener, not one-to-one
    • ProcessorChunkProgressListener, StoringChunkProgressListener -> LevelLoadProgressListener, not one-to-one
  • net.minecraft.server.packs
    • AbstractPackResources#getMetadataFromStream now takes in a PackLocationInfo
    • OverlayMetadataSection
      • TYPE -> CLIENT_TYPE, SERVER_TYPE
      • overlaysForVersion now takes in a PackFormat instead of an integer
      • $OverlayEntry now takes in an InclusiveRange<PackFormat> instead of an InclusiveRange<Integer>
        • isApplicable now takes in a PackFormat instead of an integer
  • net.minecraft.server.packs.metadata.pack.PackMetadataSection now takes in an InclusiveRange<PackFormat> instead of the raw pack format and integer pack.
    • CODEC -> FALLBACK_CODEC, now private
    • TYPE -> CLIENT_TYPE, SERVER_TYPE, FALLBACK_TYPE
  • net.minecraft.server.packs.repository
    • Pack#readPackMetadata now takes in a PackFormat and PackType instead of an integer
    • PackCompatibility#forVersion now takes in PackFormats instead of integers
  • net.minecraft.util
    • CubicSpline methods and inner classes now use BoundedFloatFunction instead of ToFloatFunction
    • ExtraCodecs
      • GAME_PROFILE_WITHOUT_PROPERTIES -> AUTHLIB_GAME_PROFILE, now a Codec and public
      • GAME_PROFILE -> STORED_GAME_PROFILE, now a MapCodec
    • StringRepresentable#createNameLookup now can take in an arbitrary object and return a string
      • The base overload that takes in the object array uses getSerializedName
    • StringUtil#isAllowedChatCharacter now takes in an int codepoint instead of a char
    • ToFloatFunction -> BoundedFloatFunction
      • This still exists as a standard interface to convert some object to a float
  • net.minecraft.world.entity
    • AgeableMob#finalizeSpawn is now nullable
    • Entity
      • startRiding(Entity) is now final
      • startRiding(Entity, boolean) now takes in an additional boolean of whether to trigger the game event and criteria triggers
      • killedEntity now takes in the DamageSource
      • moveOrInterpolateTo now has overloads that take in an XY rotation, a Vec3 position, or all three as optionals
      • lerpMotion now takes in a Vec3 instead of three doubles
      • forceSetRotation now takes in whether the XY rotation is relative
      • teleportSetPosition now has an overload that takes in both the starting and end position
    • EntityReference is now private, constructed using the of static constructors
      • getEntity now takes in a UUIDLookup<? extends UniquelyIdentifyable> instead of a UUIDLookup<? super StoredEntityType>
      • get now takes in a Level instead of a UUIDLookup
    • EntityType now takes in whether the entity is allowed in peaceful mode
      • create, loadEntityRecursive now has an overload that takes in an EntityType
    • LivingEntity
      • shouldDropLoot now takes in the ServerLevel
      • dropFromLootTable now has overloads to take in a specific loot table key and how the items should be dispensed
      • getSlotForHand -> InteractionHand#asEquipmentSlot
    • Mob#shouldDespawnInPeaceful -> EntityType#isAllowedInPeaceful, not one-to-one
    • Pose now implements StringRepresentable, has an associated Codec
  • net.minecraft.world.entity.ai.village.poi
    • PoiManager#add now returns a PoiRecord
    • PoiSection#add now returns a PoiRecord
  • net.minecraft.world.entity.animal.Animal#usePlayerItem -> Mob#usePlayerItem
  • net.minecraft.world.entity.animal.armadillo.Armadillo#brushOffScute now takes in an Entity and ItemStack
  • net.minecraft.world.entity.player
    • Player now extends Avatar instead of LivingEntity
      • DATA_SHOULDER_* -> DATA_SHOULDER_PARROT_*, now private
      • oBob, bob -> ClientAvatarState#bob0, bob
      • *Cloak* -> ClientAvatarState#*Cloak*
      • setEntityOnShoulder -> ServerPlayer#setEntityOnShoulder
      • *ShoulderEntity* -> ServerPlayer#*ShoulderEntity*
      • setMainArm -> Avatar#setMainArm
      • CROUCH_BB_HEIGHT, SWIMMING_BB_WIDTH, SWIMMING_BB_HEIGHT, STANDING_DIMENSIONS have been moved to Avatar
      • POSES -> Avatar#POSES, now protected
    • PlayerModelPart now implements StringRepresentable
  • net.minecraft.world.entity.projectile.Projectile
    • deflect now takes in an EntityReference of the owner instead of the Entity itself
    • onDeflection no longer takes in the direct Entity
    • checkLeftOwner now checks if the projectile is outside the collision range only when leftOwner and leftOwnerChecked are both false
      • The original logic pertaining to this method has been moved to isOutsideOwnerCollisionRange, which is still private
  • net.minecraft.world.entity.vehicle.MinecartBehavior#lerpMotion now takes in a Vec3 instead of three doubles
  • net.minecraft.world.item
    • ItemStack#set now has an overload that takes in a TypedDataComponent
    • SpawnEggItem no longer takes in the EntityType
      • spawnsEntity no longer takes in the HolderLookup$Provider
      • getType no longer takes in the HolderLookup$Provider
  • net.minecraft.world.item.component
    • Bees#STREAM_CODEC now requires a RegistryFriendlyByteBuf
    • ResolvableProfile is now a sealed class with a protected constructor, created through the static createResolved, createUnresolved
      • pollResolve, resolve, isResolved -> resolveProfile, not one-to-one
  • net.minecraft.world.item.enchantment.effects.ExplodeEffect now takes in a list of block particles to display
  • net.minecraft.world.level
    • BaseCommandBlock no longer implements CommandSource
      • createCommandSourceStack now takes in a CommandSource
    • BaseSpawner#getoSpin -> getOSpin
    • CustomSpawner#tick no longer takes in the tick friendlies boolean
    • GameRules
      • availableRules is now public
      • $BooleanValue#create is now public
      • $IntegerValue#create is now public
    • Level no longer implements UUIDLookup
      • explode now takes in a weighter list of explosion particles to display
      • neighborUpdater is now a CollectingNeighborUpdater
      • tickBlockEntities is now public
    • ServerExplosion#explode now returns the number of blocks exploded
  • net.minecraft.world.level.border
    • BorderChangeListener
      • onBorderSizeSet -> onSetSize
      • onBorderSizeLerping -> onLerpSize
      • onBorderCenterSet -> onSetCenter
      • onBorderSetWarningTime -> onSetWarningTime
      • onBorderSetWarningBlocks -> onSetWarningBlocks
      • onBorderSetDamagePerBlock -> onSetDamagePerBlock
      • onBorderSetDamageSafeZone -> onSetSafeZone
    • WorldBorder now extends SavedData
      • getLerpRemainingTime -> getLerpTime
      • *DamageSafeZone -> *SafeZone
      • DEFAULT_SETTINGS -> $Settings#DEFAULT
      • createSettings has been replaced with the $Settings constructor
      • $BorderExtent#getLerpRemainingTime -> getLerpTime
      • $Settings is now a record, meaning all getters now use the record format
  • net.minecraft.world.level.block
    • BeehiveBlock#dropHoneycomb(Level, BlockPos) -> dropHoneyComb(ServerLevel, ItemStack, BlockState, BlockEntity, Entity, BlockPos)
    • CaveVines#use entity is no longer nullable
    • ChestBlock now takes in an open and close sound
    • ChiseledBookShelfBlock now implements SelectableSlotContainer
      • BOOKS_PER_ROW is now private
  • net.minecraft.world.level.block.entity
    • ChiseledBookShelfBlockEntity now implements ListBackedContainer
      • count -> ListBackedContainer#count
    • ContainerOpenersCounter
      • isOwnContainer is now public
      • incrementOpeners, decrementOpeners now takes in a LivingEntity instead of a Player
      • getPlayersWithContainerOpen -> getEntitiesWithContainerOpen, now public, not one-to-one
  • net.minecraft.world.level.block.state.BlockBehaviour
    • getAnalogOutputSignal, $BlockStateBase#getAnalogOutputSignal now takes in the direction the signal is coming from
    • $Properties#noCollission -> noCollision
  • net.minecraft.world.level.block.state.properties.BlockStateProperties#CHISELED_BOOKSHELF_SLOT_*_OCCUPIED -> SLOT_*_OCCUPIED
  • net.minecraft.world.level.chunk
    • GlobalPalette#create -> Configuration#createPalette
    • HashMapPalette no longer takes in the IdMap
      • create no longer takes in the IdMap and PaletteResize
    • LevelChunkSection now takes in a PalettedContainerFactory instead of a Registry<Biome>
    • LinearPalette no longer takes in the IdMap
      • create no longer takes in the IdMap and PaletteResize
    • Palette
      • idFor, read, write, getSerializedSize now takes in an IdMap
      • copy no longer takes in the PaletteResize
      • $Factory#create no longer takes in the IdMap and PaletteResize
    • PalettedContainer no longer takes in the IdMap
      • codec* no longer takes in the IdMap
      • unpack is now public, visible for testing
      • $Configuration -> Configuration$Simple
      • $Strategy -> Strategy
        • getConfiguration now takes in an int instead of an IdMap, now protected
    • PalettedContainerRO
      • pack no longer takes in the IdMap
      • $PackedData now takes in the bits per entry int
      • $Unpacker#read no longer takes in the IdMap
    • PaletteResize is now public
    • ProtoChunk now takes in a PalettedContainerFactory instead of a Registry<Biome>
    • SingleValuePalette no longer takes in the IdMap and PaletteResize
      • create no longer takes in the IdMap and PaletteResize
  • net.minecraft.world.level.chunk.storage.SerializableChunkData#containerFactory now takes in a PalettedContainerFactory instead of a Registry<Biome>
    • parse now takes in a PalettedContainerFactory instead of a RegistryAccess
  • net.minecraft.world.level.entity.UUIDLookup#getEntity -> lookup
  • net.minecraft.world.level.gameevent
    • BlockPositionSource is now a record
    • EntityPositionSource#getUuid is now public
  • net.minecraft.world.level.levelgen
    • Beardifier now takes in lists instead of iterators and a nullable BoundingBox
    • DensityFunctions%Coordinate now implements BoundedFloatFunction instead of ToFloatFunction
    • NoiseRouter#initialDensityWithoutJaggedness -> preliminarySurfaceLevel
  • net.minecraft.world.level.levelgen.structure.pools.JigsawPlacement#addPieces now takes in a JigsawStructure$MaxDistance instead of an integer
  • net.minecraft.world.level.levelgen.structure.structures.JigsawStructure now takes in a JigsawStructure$MaxDistance instead of an integer
  • net.minecraft.world.level.pathfinder.Path is now final
  • net.minecraft.world.level.portal.TeleportTransition#missingRespawnBlock no longer takes in the Entity to get the respawn data from
  • net.minecraft.world.level.storage
    • PrimaryLevelData now takes in an optional wrapped WorldBorder$Settings
    • ServerLevelData#*WorldBorder -> *LegacyWorldBorderSettings, now dealing with optional wrapped WorldBorder$Settings
  • net.minecraft.world.level.storage.loot.functions
    • CopyComponentsFunction
      • copyComponents has been split to copyComponentsFromEntity, copyComponentsFromBlockEntity
      • $Source is now an interface
        • Original implementation is in $BlockEntitySource
        • getReferencedContextParams -> contextParam, not one-to-one
    • CopyNameFunction
      • copyName now takes in a $Source instead of a $NameSource
      • $NameSource -> $Source, now a record, not one-to-one
  • net.minecraft.world.level.storage.loot.providers.nbt.ContextNbtProvider
    • CODEC -> MAP_CODEC, not one-to-one
    • $Getter -> $Source
      • get now has an overload that takes in the generic
      • getReferencedContextParams -> contextParam, not one-to-one
  • net.minecraft.world.phys.shapes.EntityCollisionContext now takes in a boolean instead of a Predicate<FluidState>
    • EMPTY -> $Empty, not one-to-one
  • net.minecraft.world.waypoints.TrackedWaypoint
    • STREAM_CODEC is now final
    • yawAngleToCamera now takes in a PartialTickSupplier
    • pitchDirectionToCamera now takes in a PartialTickSupplier

List of Removals

  • com.mojang.blaze3d.audio.Listener#setGain, getGain
  • com.mojang.blaze3d.opengl
    • GlShaderModule#compile
    • GlStateManager
      • _glUniform1, _glUniform2, _glUniform3, _glUniform4
      • _glUniformMatrix4
      • glActiveTexture, _getActiveTexture
  • com.mojang.blaze3d.pipeline.RenderTarget#viewWidth, viewHeight
  • com.mojang.blaze3d.systems.RenderSystem
    • getQuadVertexBuffer
    • setModelOffset, resetModelOffset, getModelOffset
  • com.mojang.blaze3d.vertex
    • DefaultVertexFormat#BLIT_SCREEN
    • VertexConsumer#setWhiteAlpha
  • net.minecraft
    • SharedConstants#VERSION_STRING
    • Util#getVmArguments
  • net.miencraft.advancements.critereon.MinMaxBounds$BoundsFactory, $BoundsFromReaderFactory
  • net.minecraft.client
    • Camera#FOG_DISTANCE_SCALE
    • Minecraft
      • getProgressListener
      • getProfileKeySignatureValidator, canValidateProfileKeys
    • Options#RENDER_DISTANCE_TINY, RENDER_DISTANCE_NORMAL
    • User#getType, $Type
  • net.minecraft.client.gui.components
    • AbstractSelectionList
      • headerHeight, associated constructor has been removed
      • setSelectedIndex, getFirstElement, getEntry
      • isSelectedItem
      • renderHeader, renderDecorations
      • ensureVisible
      • remove
    • OptionsList#getMouseOver
    • StringWidget#alignLeft, alignCenter, alignRight`
  • net.minecraft.client.gui.render.state.GuiRenderState
    • down, $Node#down
    • $LayeredElementConsumer
  • net.minecraft.client.gui.screens.LevelLoadingScreen#renderChunks
  • net.minecraft.client.gui.screens.achievement.StatsScreen#setActiveList
  • net.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen
    • BUTTON_ROW_WIDTH, FOOTER_HEIGHT
    • setSelected
    • joinSelectedServer
  • net.minecraft.client.main.GameConfig$UserData#userProperties, profileProperties
  • net.minecraft.client.renderer.chunk.ChunkSectionLayer#outputTarget
  • net.minecraft.client.resources.SkinManager#getInsecureSkin
  • net.minecraft.gametest.framework.GameTestTicker#startTicking
  • net.minecraft.network.syncher.EntityDataSerializers#COMPOUND_TAG
  • net.minecraft.server.MinecraftServer#getSpawnRadius
  • net.minecraft.server.dedicated.DedicatedServer#storeUsingWhiteList
  • net.minecraft.server.level
    • ServerChunkCache#getTickingGenerated
    • ServerPlayer#loadGameTypes
  • net.minecraft.server.packs.resources.ResourceMetadata
    • copySections
    • $Builder
  • net.minecraft.world.entity.Entity
    • spawnAtLocation(ServerLevel, ItemLike, int)
    • getServer
  • net.minecraft.world.entity.decoration.HangingEntity#HANGING_ENTITY
  • net.minecraft.world.entity.item.ItemEntity#copy
  • net.minecraft.world.entity.monster
    • Creeper#canDropMobsSkull, increaseDroppedSkulls
    • Zombie#getSkull
  • net.minecraft.world.entity.player.Player
    • getScoreboard
    • isModelPartShown
  • net.minecraft.world.entity.vehicle.MinecartTNT#explode(double)
  • net.minecraft.world.item.Item#verifyComponentsAfterLoad
  • net.minecraft.world.level
    • BlockGetter#MAX_BLOCK_ITERATIONS_ALONG_TRAVEL
    • GameRules#RULE_SPAWN_CHUNK_RADIUS
  • net.minecraft.world.level.border
    • BorderChangeListener$DelegateBorderChangeListener
    • WorldBorder
      • closestBorder
      • $DistancePerDirection
      • $Settings#read, write
  • net.minecraft.world.level.block.FletchingTableBlock
  • net.minecraft.world.level.block.entity.SkullBlockEntity
    • CHECKED_MAIN_THREAD_EXECUTOR
    • setup, clear
    • fetchGameProfile
    • setOwner
  • net.minecraft.world.level.portal.TeleportTransition(ServerLevel, Entity, TeleportTransition.PostTeleportTransition)
  • net.minecraft.world.level.storage.loot.providers.nbt.ContextNbtProvider
    • BLOCK_ENTITY
    • $Getter#getId

Minecraft 1.21.9 -> 1.21.10 Mod Migration Primer

This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.9 to 1.21.10. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.

This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.

If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.

Thank you to:

  • @melanx for a typo

Pack Changes

There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.

Minor Migrations

The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.

List of Additions

  • net.minecraft.world.entity.decoration.HangingEntity#getPopBox - Returns the bounding box indicating where the entity will pop off if colliding.

List of Changes

net.minecraft.world.level.block.state.BlockBehaviour#entityInside now takes in a boolean indicating whether the entity is intersecting or inside the block

Minecraft 1.21.10 -> 1.21.11 Mod Migration Primer

This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.10 to 1.21.11. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.

This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.

If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.

Thank you to:

  • @xfacthd for some educated guesses regarding the usage annotations
  • @dinnerbone for pointing out gizmos can also be submitted on the server in singleplayer worlds
  • @thatgravyboat for pointing out the change in parameter orders for Mth#clampedLerp

Pack Changes

There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.

The Rename Shuffle

Many core classes, method, and parameters have been shuffled around and renamed while still retaining their individual function. The following is a list of the most important changes

ResourceLocation to Identifier

All references to ResourceLocation, whether in method names, parameters, or other classes, have been replaced with Identifier.

The util Package

Most utility classes have been moved to net.minecraft.util. These will need to be reimported.

critereon to criterion

net.minecraft.advancements.critereon has been renamed to net.minecraft.advancements.criterion. These will need to be reimported.

Entity and Object Subpackages

Both net.minecraft.client.model and net.minecraft.world.entity have been reorganized into additional subpackages based on the type of backing object. These will need to be reimported.

  • net.minecraft
    • BlockUtil -> .util.BlockUtil
    • FileUtil -> .util.FileUtil
    • ResourceLocationException -> IdentifierException
    • Util -> .util.Util
  • net.minecraft.advancements.critereon -> .advancements.criterion
  • net.minecraft.client.gui.screens.inventory.JigsawBlockEditScreen#isValidResourceLocation -> isValidIdentifier
  • net.minecraft.client.model
    • AbstractBoatModel -> .object.boat.AbstractBoatModel
    • AbstractEquineModel -> .animal.equine.AbstractEquineModel
    • AbstractPiglinModel -> .monster.piglin.AbstractPiglinModel
    • AbstractZombieModel -> .monster.zombie.AbstractZombieModel
    • AllayModel -> .animal.allay.AllayModel
    • ArmadilloModel -> .animal.armadillo.ArmadilloModel
    • ArmorStandArmorModel -> .object.armorstand.ArmorStandArmorModel
    • ArmorStandModel -> .object.armorstand.ArmorStandModel
    • ArrowModel -> .object.projectile.ArrowModel
    • AxolotlModel -> .animal.axolotl.AxolotlModel
    • BannerFlagModel -> .object.banner.BannerFlagModel
    • BannerModel -> .object.banner.BannerModel
    • BatModel -> .ambient.BatModel
    • BeeModel -> .animal.bee.BeeModel
    • BeeStingerModel -> .animal.bee.BeeStingerModel
    • BellModel -> .object.bell.BellModel
    • BlazeModel -> .monster.blaze.BlazeModel
    • BoatModel -> .object.boat.BoatModel
    • BoggedModel -> .monster.skeleton.BoggedModel
    • BookModel -> .object.book.BookModel
    • BreezeModel -> .monster.breeze.BreezeModel
    • CamelModel -> .animal.camel.CamelModel
    • CamelSaddleModel -> .animal.camel.CamelSaddleModel
    • CatModel -> .animal.feline.CatModel
    • ChestModel -> .object.chest.ChestModel
    • ChickenModel -> .animal.chicken.ChickenModel
    • CodModel -> .animal.fish.CodModel
    • ColdChickenModel -> .animal.chicken.ColdChickenModel
    • ColdCowModel -> .animal.cow.ColdCowModel
    • ColdPigModel -> .animal.pig.ColdPigModel
    • CopperGolemModel -> .animal.golem.CopperGolemModel
    • CopperGolemStatueModel -> .object.statue.CopperGolemStatueModel
    • CowModel -> .animal.cow.CowModel
    • CreakingModel -> .monster.creaking.CreakingModel
    • CreeperModel -> .monster.creeper.CreeperModel
    • DolphinModel -> .animal.dolphin.DolphinModel
    • DonkeyModel -> .animal.equine.DonkeyModel
    • DrownedModel -> .monster.zombie.DrownedModel
    • ElytraModel -> .object.equipment.ElytraModel
    • EndCrystalModel -> .object.crystal.EndCrystalModel
    • EndermanModel -> .monster.enderman.EndermanModel
    • EndermiteModel -> .monster.endermite.EndermiteModel
    • EquineSaddleModel -> .animal.equine.EquineSaddleModel
    • EvokerFangsModel -> .effects.EvokerFangsModel
    • FelineModel -> .animal.feline.FelineModel
    • FoxModel -> .animal.fox.FoxModel
    • FrogModel -> .animal.frog.FrogModel
    • GhastModel -> .monster.ghast.GhastModel
    • GiantZombieModel -> .monster.zombie.GiantZombieModel
    • GoatModel -> .animal.goat.GoatModel
    • GuardianModel -> .monster.guardian.GuardianModel
    • GuardianParticleModel -> .monster.guardian.GuardianParticleModel
    • HappyGhastHarnessModel -> .animal.ghast.HappyGhastHarnessModel
    • HappyGhastModel -> .animal.ghast.HappyGhastModel
    • HoglinModel -> .monster.hoglin.HoglinModel
    • HorseModel -> .animal.equine.HorseModel
    • IllagerModel -> .monster.illager.IllagerModel
    • IronGolemModel -> .animal.golem.IronGolemModel
    • LavaSlimeModel -> .monster.slime.MagmaCubeModel
    • LeashKnotModel -> .object.leash.LeashKnotModel
    • LlamaModel -> .animal.llama.LlamaModel
    • LlamaSpitModel -> .animal.llama.LlamaSpitModel
    • MinecartModel -> .object.cart.MinecartModel
    • OcelotModel -> .animal.feline.OcelotModel
    • PandaModel -> .animal.panda.PandaModel
    • ParrotModel -> .animal.parrot.ParrotModel
    • PhantomModel -> .monster.phantom.PhantomModel
    • PiglinHeadModel -> .object.skull.PiglinHeadModel
    • PiglinModel -> .monster.piglin.PiglinModel
    • PigModel -> .animal.pig.PigModel
    • PlayerCapeModel -> .player.PlayerCapeModel
    • PlayerEarsModel -> .player.PlayerEarsModel
    • PlayerModel -> .player.PlayerModel
    • PolarBearModel -> .animal.polarbear.PolarBearModel
    • PufferfishBigModel -> .animal.fish.PufferfishBigModel
    • PufferfishMidModel -> .animal.fish.PufferfishMidModel
    • PufferfishSmallModel -> .animal.fish.PufferfishSmallModel
    • RabbitModel -> .animal.rabbit.RabbitModel
    • RaftModel -> .object.boat.RaftModel
    • RavagerModel -> .monster.ravager.RavagerModel
    • SalmonModel -> .animal.fish.SalmonModel
    • SheepFurModel -> .animal.sheep.SheepFurModel
    • SheepModel -> .animal.sheep.SheepModel
    • ShieldModel -> .object.equipment.ShieldModel
    • ShulkerBulletModel -> .object.projectile.ShulkerBulletModel
    • ShulkerModel -> .monster.shulker.ShulkerModel
    • SilverfishModel -> .monster.silverfish.SilverfishModel
    • SkeletonModel -> .monster.skeleton.SkeletonModel
    • SkullModel -> .object.skull.SkullModel
    • SkullModelBase -> .object.skull.SkullModelBase
    • SlimeModel -> .monster.slime.SlimeModel
    • SnifferModel -> .animal.sniffer.SnifferModel
    • SnowGolemModel -> .animal.golem.SnowGolemModel
    • SpiderModel -> .monster.spider.SpiderModel
    • SpinAttackEffectModel -> .effects.SpinAttackEffectModel
    • SquidModel -> .animal.squid.SquidModel
    • StriderModel -> .monster.strider.StriderModel
    • TadpoleModel -> .animal.frog.TadpoleModel
    • TridentModel -> .object.projectile.TridentModel
    • TropicalFishModelA -> .animal.fish.TropicalFishSmallModel
    • TropicalFishModelB -> .animal.fish.TropicalFishLargeModel
    • TurtleModel -> .animal.turtle.TurtleModel
    • VexModel -> .monster.vex.VexModel
    • VillagerModel -> .npc.VillagerModel
    • WardenModel -> .monster.warden.WardenModel
    • WarmCowModel -> .animal.cow.WarmCowModel
    • WindChargeModel -> .object.projectile.WindChargeModel
    • WitchModel -> .monster.witch.WitchModel
    • WitherBossModel -> .monster.wither.WitherBossModel
    • WolfModel -> .animal.wolf.WolfModel
    • ZombieModel -> .monster.zombie.ZombieModel
    • ZombieVillagerModel -> .monster.zombie.ZombieVillagerModel
    • ZombifiedPiglinModel -> .monster.piglin.ZombifiedPiglinModel
  • net.minecraft.client.model.dragon
    • DragonHeadModel -> .model.object.skull.DragonHeadModel
    • EnderDragonModel -> .model.monster.dragon.EnderDragonModel
  • net.minecraft.client.resources.sounds
    • AbstractSoundInstance#location -> identifier
    • SoundInstance#getLocation -> getIdentifier
  • net.minecraft.client.searchtree
    • IdSearchTree
      • resourceLocationSearchTree -> identifierSearchTree
      • searchResourceLocation -> searchIdentifier
    • ResourceLocationSearchTree -> IdentifierSearchTree
  • net.minecraft.commands.arguments.ResourceLocationArgument -> IdentifierArgument
  • net.minecraft.network.FriendlyByteBuf#readResourceLocation, writeResourceLocation -> readIdentifier, writeIdentifier
  • net.minecraft.resources
    • ResourceKey#location -> identifier
    • ResourceLocation -> Identifier
  • net.minecraft.util.ResourceLocationPattern -> IdentifierPattern
  • net.minecraft.util.parsing.packrat.commands.ResourceLocationParseRule -> IdentifierParseRule
  • net.minecraft.world.entity.GlowSquid -> .animal.squid.GlowSquid
  • net.minecraft.world.entity.animal
    • AbstractCow -> .cow.AbstractCow
    • AbstractFish -> .fish.AbstractFish
    • AbstractGolem -> .golem.AbstractGolem
    • AbstractSchoolingFish -> .fish.AbstractSchoolingFish
    • Bee -> .bee.Bee
    • Cat -> .feline.Cat
    • CatVariant -> .feline.CatVariant
    • CatVariants -> .feline.CatVariants
    • Chicken -> .chicken.Chicken
    • ChickenVariant -> .chicken.ChickenVariant
    • ChickenVariants -> .chicken.ChickenVariants
    • Cod -> .fish.Cod
    • Cow -> .cow.Cow
    • CowVariant -> .cow.CowVariant
    • CowVariants -> .cow.CowVariants
    • Dolphin -> .dolphin.Dolphin
    • Fox -> .fox.Fox
    • HappyGhast -> .happyghast.HappyGhast
    • HappyGhastAi -> .happyghast.HappyGhastAi
    • IronGolem -> .golem.IronGolem
    • MushroomCow -> .cow.MushroomCow
    • Ocelot -> .feline.Ocelot
    • Panda -> .panda.Panda
    • Parrot -> .parrot.Parrot
    • Pig -> .pig.Pig
    • PigVariant -> .pig.PigVariant
    • PigVariants -> .pig.PigVariants
    • PolarBear -> .polarbear.PolarBear
    • Pufferfish -> .fish.Pufferfish
    • Rabbit -> .rabbit.Rabbit
    • Salmon -> .fish.Salmon
    • ShoulderRidingEntity -> .parrot.ShoulderRidingEntity
    • SnowGolem -> .golem.SnowGolem
    • Squid -> .squid.Squid
    • TropicalFish -> .fish.TropicalFish
    • Turtle -> .turtle.Turtle
    • WaterAnimal -> .fish.WaterAnimal
  • net.minecraft.world.entity.animal.coppergolem.* -> .animal.golem.*
  • net.minecraft.world.entity.animal.horse.* -> .animal.equine.*
  • net.minecraft.world.entity.boss.EnderDragonPart -> .enderdragon.EnderDragonPart
  • net.minecraft.world.entity.decoration
    • Painting -> .painting.Painting
    • PaintingVariant -> .painting.PaintingVariant
    • PaintingVariants -> .painting.PaintingVariants
  • net.minecraft.world.entity.monster
    • AbstractIllager -> .illager.AbstractIllager
    • AbstractSkeleton -> .skeleton.AbstractSkeleton
    • Bogged -> .skeleton.Bogged
    • CaveSpider -> .spider.CaveSpider
    • Drowned -> .zombie.Drowned
    • Evoker -> .illager.Evoker
    • Husk -> .zombie.Husk
    • Illusioner -> .illager.Illusioner
    • Parched -> .skeleton.Parched
    • Pillager -> .illager.Pillager
    • Skeleton -> .skeleton.Skeleton
    • SpellcasterIllager -> .illager.SpellcasterIllager
    • Spider -> .spider.Spider
    • Stray -> .skeleton.Stray
    • Vindicator -> .illager.Vindicator
    • WitherSkeleton -> .skeleton.WitherSkeleton
    • Zombie -> .zombie.Zombie
    • ZombieVillager -> .zombie.ZombieVillager
    • ZombifiedPiglin -> .zombie.ZombifiedPiglin
  • net.minecraft.world.entity.npc
    • AbstractVillager -> .villager.AbstractVillager
    • Villager -> .villager.Villager
    • VillagerData -> .villager.VillagerData
    • VillagerDataHolder -> .villager.VillagerDataHolder
    • VillagerProfession -> .villager.VillagerProfession
    • VillagerTrades -> .villager.VillagerTrades
    • VillagerType -> .villager.VillagerType
    • WanderingTrader -> .wanderingtrader.WanderingTrader
    • WanderingTraderSpawner -> .wanderingtrader.WanderingTraderSpawner
  • net.minecraft.world.entity.projectile
    • AbstractArrow -> .arrow.AbstractArrow
    • AbstractHurtingProjectile -> .hurtingprojectile.AbstractHurtingProjectile
    • AbstractThrownPotion -> .throwableitemprojectile.AbstractThrownPotion
    • Arrow -> .arrow.Arrow
    • DragonFireball -> .hurtingprojectile.DragonFireball
    • Fireball -> .hurtingprojectile.Fireball
    • LargeFireball -> .hurtingprojectile.LargeFireball
    • SmallFireball -> .hurtingprojectile.SmallFireball
    • Snowball -> .throwableitemprojectile.Snowball
    • SpectralArrow -> .arrow.SpectralArrow
    • ThrowableItemProjectile -> .throwableitemprojectile.ThrowableItemProjectile
    • ThrownEgg -> .throwableitemprojectile.ThrownEgg
    • ThrownEnderpearl -> .throwableitemprojectile.ThrownEnderpearl
    • ThrownExperienceBottle -> .throwableitemprojectile.ThrownExperienceBottle
    • ThrownLingeringPotion -> .throwableitemprojectile.ThrownLingeringPotion
    • ThrownSplashPotion -> .throwableitemprojectile.ThrownSplashPotion
    • ThrownTrident -> .arrow.ThrownTrident
    • WitherSkull -> .hurtingprojectile.WitherSkull
  • net.minecraft.world.entity.projectile.windcharge.* -> .projectile.hurtingprojectile.windcharge.*
  • net.minecraft.world.entity.vehicle
    • AbstractBoat -> .boat.AbstractBoat
    • AbstractChestBoat -> .boat.AbstractChestBoat
    • AbstractMinecart -> .minecart.AbstractMinecart
    • AbstractMinecartContainer -> .minecart.AbstractMinecartContainer
    • Boat -> .boat.Boat
    • ChestBoat -> .boat.ChestBoat
    • ChestRaft -> .boat.ChestRaft
    • Minecart -> .minecart.Minecart
    • MinecartBehavior -> .minecart.MinecartBehavior
    • MinecartChest -> .minecart.MinecartChest
    • MinecartCommandBlock -> .minecart.MinecartCommandBlock
    • MinecartFurnace -> .minecart.MinecartFurnace
    • MinecartHopper -> .minecart.MinecartHopper
    • MinecartSpawner -> .minecart.MinecartSpawner
    • MinecartTNT -> .minecart.MinecartTNT
    • NewMinecartBehavior -> .minecart.NewMinecartBehavior
    • OldMinecartBehavior -> .minecart.OldMinecartBehavior
    • Raft -> .boat.Raft
  • net.minecraft.world.level.gamerules.GameRule#getResourceLocation -> getIdentifier

Oh Hey, Another Rendering Rewrite

More of the rendering pipeline has been rewritten, with the majority focused on samplers, RenderType creation, and mipmaps.

The Separation of Samplers

Blaze3d has separated setting the AddressModes and FilterModes when reading texture data into GpuSampler. As the name implies, a GpuSampler defines how to sample data from a buffer, such as a texture. GpuSampler contains four methods: getAddressModeU / getAddressModeV for determining how the sampler should behave when reading the UV positions (either repeat or clamp), getMinFilter / getMagFilter for determining how to minify or magnify the texture respectively (either nearest neighbor or linear), getMaxAnisotropy for the largest anisotropic filtering level that can be used, and getMaxLod for the maximum level-of-detail on a texture.

Samplers can be created via GpuDevice#createSampler, but that is not necessary unless you want to specify a different anisotropic filtering level greater than 1, or a maximum level-of-detail that is not 0 or 1000. If the default, as there are only 32 possible combinations, vanilla creates all GpuSamplers and stores them in a cache, accessible via RenderSystem#getSamplerCache, followed by SamplerCache#getSampler:

// Raw call
GpuSampler sampler = RenderSystem.getDevice().createSampler(
    // U address mode
    AddressMode.CLAMP_TO_EDGE,
    // V address mode
    AddressMode.CLAMP_TO_EDGE,
    // Minification filter
    FilterMode.LINEAR,
    // Magnification filter
    FilterMode.NEAREST,
    // The maximum anisotropic filtering level
    // Vanilla uses either 1, 2, 4, or 8 for level rendering
    4f,
    // The maximum level of detail for a texture
    // Vanilla either uses an 0 for the default,
    // or an empty optional for moving objects and
    // uploading to an atlas.
    OptionalDouble.of(0.0)
);

// Sampler cache method
GpuSampler sampler = RenderSystem.getSamplerCache().getSampler(
    // U address mode
    AddressMode.CLAMP_TO_EDGE,
    // V address mode
    AddressMode.CLAMP_TO_EDGE,
    // Minification filter
    FilterMode.LINEAR,
    // Magnification filter
    FilterMode.NEAREST,
    // Whether to use 1000 or 0 for the maximum level-of-detail
    true
);

To make user of the sampler for a texture, when binding the texture in a render pass (via RenderPass#bindTexture), you must now specify the sampler to use in addition to the texture view:

try (RenderPass pass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(...)) {
    // Set other parameters
    pass.bindTexture(
        // The name of the sampler2D uniform, usually in the fragment shader
        "Sampler0",
        // The texture to sample
        ...,
        // The sampler to use
        sampler
    );

    // Draw buffer
}

Setting up the post processor has not changed from the user perspective as only clamp to edge address modes may be selected.

The RenderType Shuffle

Creating a RenderType has been reworked to some degree. While most of the features from the previous implementation still exist, they have been changed to match the new rendering system where direct OpenGL is abstracted away and only accessed through their defined pipelines and RenderSystem.

Existing Types

Existing types have been moved from RenderType to RenderTypes (e.g., RenderType#solid -> RenderTypes#solid).

Custom Types

Originally, to create a RenderType, you would construct a $CompositeState using RenderStateShards. Each RenderStateShard would define how the pass should be setup and teardown when building some mesh, whether that was setting textures, the render target, model transforms, etc. Then, the $CompositeState would be built for use in whatever rendering application was needed.

The new system splits the render definition in two: the RenderSetup, and our RenderType. The RenderSetup, as the name implies, sets up the renderer to be used when drawing to a texture. Teardown is completely removed as it is either handled directly when drawing the RenderType or uses newly constructed states that can just be thrown away. RenderType, on the other hand, is simply a named RenderSetup. It only handles drawing the mesh data and making some fields of the setup public for use in other buffer implementations. Multiple types can have the same RenderSetup as a number of existing types dynamically populate the texture used by the sampler and/or the outline of the object.

A RenderSetup can be created through its builder via RenderSetup#Builder, supply the RenderPipeline to use. Once the builder properties are set, the actual setup can be created via RenderSetup$RenderSetupBuilder#createRenderSetup:

public static final RenderSetup EXAMPLE_SETUP = RenderSetup.builder(
    // The pipeline to use.
    // This can affect what settings are allowed from the setup.
    RenderPipelines.ITEM_ENTITY_TRANSLUCENT_CULL
)
    // Specifies the texture to bind to the provided sampler.
    // The sampler must be defined by the pipeline via `RenderPipeline$Builder#withSampler`.
    // The texture is represented as an absolute location.
    .withTexture(
        // 'Sampler0' is defined by the pipeline.
        "Sampler0",
        // Points to 'assets/minecraft/entity/wolf/wolf_armor_crackiness_low.png'.
        Identifier.withDefaultNamespace("textures/entity/wolf/wolf_armor_crackiness_low.png"),
        // An optional supplied `GpuSampler` to sample the texture with.
        // The returned value with be cached after first resolution.
        () -> RenderSystem.getSamplerCache().getClampToEdge(FilterMode.NEAREST)
    )
    // When set, allows the pipeline to use the light texture.
    // 'Sampler2' must be defined by the pipeline via `RenderPipeline$Builder#withSampler`.
    .useLightmap()
    // When set, allows the pipeline to use the overlay texture.
    // 'Sampler1' must be defined by the pipeline via `RenderPipeline$Builder#withSampler`.
    .useOverlay()
    // When set, uses `RenderTypes#crumbling` to overlay the block destroy stages
    // based on the crumbling progress for an entity model.
    // This is only implemented in `ModelFeatureRenderer`.
    .affectsCrumbling()
    // When set, sorts the quads based on the set `ProjectionType` in
    // `RenderSystem#getProjectionType`.
    // This is only implemented when getting the buffers from `MultiBufferSource$BufferSource`.
    .sortOnUpload()
    // Sets the initial capacity of the used buffer.
    // This is only used when constructing the initial buffers in `RenderBuffers`
    // All custom applications of sources already have some defined buffer with the determined size.
    .bufferSize(786432)
    // An object-wrapped consumer that transforms the model view matrix.
    // Vanilla implementations exist in `LayeringTransform`, applying
    // the transformation through the projection type:
    // - `NO_LAYERING`: Do nothing.
    // - `VIEW_OFFSET_Z_LAYERING`: Offsets the Z by 1 based on its `ProjectionType`
    // - `VIEW_OFFSET_Z_LAYERING_FORWARD`: Offsets the Z by -11 based on its `ProjectionType`
    .setLayeringTransform(
        // We can also construct a new transform
        new LayeringTransform(
            // The name of the transform
            "examplemod:example_layer",
            // The transform should not push or pop to the stack
            // Only translate, scale, or rotate
            stack -> stack.translate(0f, 0.1f, 0f)
        )
    )
    // Sets the output target that this setup should write to,
    // unless overridden by the `RenderSystem#output*Override` textures.
    // This is typically the main target, though it can be other vanilla
    // targets or a custom one if you plan to handle it.
    .setOutputTarget(OutputTarget.MAIN_TARGET)
    // An object-wrapped supplier that provides the texture matrix.
    // This is typically used to modify the texture UV coordinates
    // in the vertex shader before sampling in the fragment shader.
    // Vanilla only uses this for the glint effect and breeze/energy:
    // - `DEFAULT_TEXTURING`: Do nothing.
    // - `GLINT_TEXTURING`: Translates based on the glint speed, rotates pi/18, and scales by 8.
    // - `ENTITY_GLINT_TEXTURING`: Translates based on the glint speed, rotates pi/18, and scales by 0.5.
    // - `ARMOR_ENTITY_GLINT_TEXTURING`: Translates based on the glint speed, rotates pi/18, and scales by 0.16.
    // - `$OffsetTextureTransform`: Translates the texture by the provided XY coordinates.
    .setTextureTransform(
        // We can also construct a new transform
        new TextureTransform(
            // The name of the transform
            "examplemod:example_texture",
            // The transform to apply to the texture
            () -> new Matrix4f().translation(0f, 1f, 0f).scale(1.5f)
        )
    )
    // Sets how an outline of the mesh should be handled:
    // - `NONE`: Do nothing.
    // - `IS_OUTLINE`: This is an outline and should write to the outline buffer source.
    // - `AFFECTS_OUTLINE`: This defines the shape of the outline and should use `RenderTypes#OUTLINE` to draw it.
    // Checked when writing to the outline buffer source or,
    // if the outline color for a feature is not 0
    .setOutline(RenderSetup.OutlineProperty.AFFECTS_OUTLINE)
    // Builds the setup for use in a render type.
    .createRenderSetup();

Then, the RenderType can be created via create.

public static final RenderType EXAMPLE_TYPE = RenderType.create(
    // The name of the type for debugging
    "examplemod:example_type",
    // The render setup to use
    EXAMPLE_SETUP
);

MeshData can be written to the output target using RenderType#draw.

Mipmap Strategy Metadata

A texture’s mcmeta can now specify the mipmap_strategy to use in the textures section. There are four available strategies, with auto defaulting to mean if there is no transparency, an cutout when there is transparency.

StrategyDescription
meanThe default that averages the color between four pixels for the current mipmap level.
cutoutmean, except that all levels are generated from the original texture, with alpha snapped to 0 or 1 using a threshold of 0.2.
strict_cutoutcutout, except that it sets the alpha snaps using a threshold of 0.6.
dark_cutoutmean, except that the surrounding pixels are only included in the average if their alpha is not 0.
// In `assets/examplemod/textures/block/example/example_block.png.mcmeta
{
    "texture": {
        // Uses the chosen strategy
        "mipmap_strategy": "cutout",
        // Determines how much the cutoff should be biased
        // when determining whether a pixel is either fully
        // opaque or transparent.
        // Larger numbers means higher alpha cutoff while
        // lower values use a lower alpha cutoff.
        "alpha_cutoff_bias": 0.2
    }
}

Block and Terrain Split

RenderPipelines that were used by both a standalone block and the terrain has been split into separate pipelines: one with prefix _BLOCK and _TERRAIN, respectively. This includes the solid, cutout, translucent, and tripwire pipelines. No block variant exists for the translucent pipeline.

Item Atlases

The block atlas no longer contains textures specifically for items. Those have been moved to their own atlas named minecraft:items, with the id stored at AtlasIds#ITEMS.

If a given Material can use both block and item textures, then it should be supplied with the ModelManager#BLOCK_OR_ITEM special case.

  • com.mojang.blaze3d.buffers
    • GpuBuffer, size now uses a long for the size
      • slice now uses longs for the length and offset
    • GpuBufferSlice now uses longs for the length and offset
  • com.mojang.blaze3d.opengl
    • BufferStorage
      • createBuffer now uses in a long for the size
      • mapBuffer now uses longs for the length and offset
    • DirectStateAccess
      • bufferSubData now uses in a long for the offset
      • mapBufferRange, flushMappedBufferRange, copyBufferSubData now use longs for the length and offset
    • GlBuffer now uses a long for the size
    • GlDevice now takes in a ShaderSource instead of a BiFunction
      • getOrCompileShader now takes in a ShaderSource instead of a BiFunction
    • GlRenderPass
      • samplers now is a hash map of strings to GlRenderPass$TextureViewAndSamplers
      • $TextureViewAndSampler - A record that defines a sampler with its sampled texture.
    • GlSampler - The OpenGL implementation of a gpu sampler.
    • GlStateManager
      • _glBufferSubData now uses in a long for the offset
      • _glMapBufferRange now uses longs for the length and offset
    • GlTexture#modesDirty, flushModeChanges are removed
    • GlTextureView#getFbo - Gets the framebuffer object of a texture, using the cache if present.
  • com.mojang.blaze3d.pipeline.RenderTarget#filterMode, setFilterMode are removed
  • com.mojang.blaze3d.platform.TextureUtil
    • solidify - Modifies the texture by packing and unpacking the pixels to better help with non-darkened interiors within mipmaps.
    • fillEmptyAreasWithDarkColor - Sets empty pixels to an empty pixel whose RGB value is the darkest color in the image.
  • com.mojang.blaze3d.shaders.ShaderSource - A functional interface that gets the shader source from its id and type as a string.
  • com.mojang.blaze3d.systems
    • CommandEncoder#copyTextureToBuffer now uses a long for the offset
    • GpuDevice
      • createSampler - Creates a sampler for some source to destination with the desired address and filter modes.
      • precompilePipeline now takes in a ShaderSource instead of a BiFunction
      • getMaxSupportedAnisotropy - The maximum anisotropic filtering level supported by the hardware.
      • createBuffer now uses in a long for the size
    • RenderPass#bindTexture now takes in a GpuSampler
    • RenderSystemnow uses in a long for the size
      • samplerCache - Returns a cache of samples containing all possible combinations.
      • TEXTURE_COUNT is removed
      • setupOverlayColor, teardownOverlayColor are removed
      • setShaderTexture, getShaderTexture are removed
      • setTextureMatrix, resetTextureMatrix, getTextureMatrix are removed
      • lineWidth -> VertexConsumer#setLineWidth
      • getShaderLineWidth -> Window#getAppropriateLineWidth
      • initRenderer now takes in a ShaderSource instead of a BiFunction
    • SamplerCache - A cache of all possible samplers that may be used by the renderer.
  • com.mojang.blaze3d.textures
    • GpuSampler - A buffer sampler with the specified UV address modes and minification and magnification filters.
    • GpuTexture
      • addressModeU -> GpuSampler#getAddressModeU
      • addressModeV -> GpuSampler#getAddressModeV
      • minFilter -> GpuSampler#getMinFilter
      • magFilter -> GpuSampler#getMagFilter
      • setAddressMode, setTextureFilter have been replaced by SamplerCache#getSampler, not one-to-one
      • useMipmaps, setUseMipmaps are removed
  • net.minecraft.client
    • Options#textureFiltering - The chosen texture sampling method when viewed at an angle or from a distance.
    • TextureFilteringMethod - The sampling method when viewing a texture at an angle or from a distance.
  • net.minecraft.client.gui.render.TextureSetup now takes in the GpuSamplers for each of the textures
    • This also includes the static constructors
  • net.minecraft.client.particle.SingleQuadParticle$Layer#ITEMS - A layer for particles with item textures.
  • net.minecraft.client.renderer
    • FaceInfo
      • $Constants -> $Extent
      • $VertexInfo is now a record
    • ItemBlockRenderTypes#getRenderType(ItemStack)
    • LightTexture#turnOffLightLayer, turnOnLightLayer are removed
    • LevelRenderer#resetSampler - Resets the chunk layer sampler.
    • PostPass
      • $Input#bilinear - Whether to use a bilinear filter.
      • $TextureInput now takes in a boolean representing whether to use a bilinear filter
    • RenderPipelines
      • SOLID -> SOLID_BLOCK, SOLID_TERRAIN
      • CUTOUT -> CUTOUT_BLOCK, CUTOUT_TERRAIN
      • CUTOUT_MIPPED is removed
      • TRANSLUCENT -> TRANSLUCENT_TERRAIN
      • TRIPWIRE -> TRIPWIRE_BLOCK, TRIPWIRE_TERRAIN
      • ANIMATE_SPRITE_SNIPPET, ANIMATE_SPRITE_BLIT, ANIMATE_SPRITE_INTERPOLATION - Pipelines for animated sprites.
    • RenderStateShard has been replaced with RenderSetup, not one-to-one
      • $LightmapStateShard -> RenderSetup#useLightmap
      • $OverlayStateShard -> RenderSetup#useOverlay
      • $MultiTextureStateShard, $TextureStateShard -> RenderSetup#textures
      • $LayeringStateShard -> RenderSetup#layeringTransform, LayeringTransform
      • $LineStateShard -> VertexConsumer#setLineWidth
      • $OutputStateShard -> RenderSetup#outputTarget, OutputTarget
      • $TexturingStateShard, $OffsetTexturingStateShard -> RenderSetup#textureTransform, TextureTransform
    • RenderType has been split into two separate concepts, not one-to-one
      • All of the stored RenderTypes have been moved to RenderTypes
      • The actual class usage has moved to .rendertype.RenderType, where it does the work of $CompositeRenderType
    • Sheets#translucentBlockItemSheet - A render type for translucent block items.
  • net.minecraft.client.renderer.block
    • BlockRenderDispatcher no longer takes in the supplied SpecialBlockModelRenderer
    • LiquidBlockRenderer now takes in a MaterialSet
      • setupSprites has been moved into the LiquidBlockRenderer constructor
  • net.minecraft.client.renderer.block.model
    • BakedQuad
      • vertices -> position*, packedUV*, not one-to-one
      • position - Gets the position vector given the index.
      • packedUV - Gets the packed UV given the index.
    • BlockElementRotation now takes in a Vector3fc for the origin and a Matrix4fc transform
      • The constructor also takes in a $RotationValue instead of a Direction$Axis and angle float
      • $EulerXYZRotation - A XYZ rotation in degrees.
      • $RotationValue - An interface that defines the rotation transformation.
      • $SingleAxisRotation - A rotation in degrees around a single axis.
    • FaceBakery
      • VERTEX_COUNT -> BakedQuad#VERTEX_COUNT
      • VERTEX_INT_SIZE, COLOR_INDEX, UV_INDEX are removed
      • bakeQuad now takes in a ModelBaker$PartCache
      • extractPositions is removed
    • SimpleModelWrapper#bake now returns a BlockModelPart
    • SimpleUnbakedGeometry#bake now takes in a ModelBaker instead of a SpriteGetter
    • TextureSlots$parseTextureMap no longer takes in an Identifier
    • Variant
      • withZRot - Rotates the model state around the Z axis.
      • $SimpleModelState now takes in a Z Quadrant
        • withZ - Sets the Z quadrant of the model state.
    • VariantMutator#Z_ROT - Rotates a model around the Z axis.
  • net.minecraft.client.renderer.chunk
    • ChunkSectionLayer no longer takes in whether to use mipmaps
      • CUTOUT_MIPPED is removed
      • texture is removed
    • ChunkSectionsToRender now takes in the GpuTextureView
      • dynamicTransforms -> chunkSectionInfos
      • renderGroup now takes in the GpuSampler
  • net.minecraft.client.renderer.item
    • BlockModelWrapper constructor is now package-private
      • computeExtents now returns an array of Vector3fcs
    • ItemStackRenderState$LayerRenderState
      • NO_EXTENTS_SUPPLIER is now a supplied array of Vector3fcs
      • setExtents now takes in a supplied array of Vector3fcs
  • net.minecraft.client.renderer.rendertype.RenderTypes
    • MOVING_BLOCK_SAMPLER - A sampler for blocks that are in motion.
    • solid -> solidMovingBlock
    • cutout -> cutoutMovingBlock
    • tripwire -> tripwireMovingBlock
  • net.minecraft.client.renderer.texture
    • AbstractTexture#setUseMipmaps is removed
    • MipmapGenerator#generateMipLevels now takes in the name of the texture, a MipmapStrategy to determine how a specific texture should be mip mapped, and a float for the alpha cutoff bias
    • MipmapStrategy - A enum defines the strategies used when constructing a mipmap for a texture.
    • OverlayTexture#setupOverlayColor, teardownOverlayColor replaced by getTextureView, not one-to-one
    • SpriteContents now takes in an optional TextureMetadataSection to determine the sprite’s metadata
      • UBO_SIZE - The uniform buffer object size of the sprite contents.
      • createTicker -> createAnimationState, not one-to-one
      • uploadFirstFrame no longer takes in the texture ints, instead a mip level int
      • $AnimatedTexture#createTicker, uploadFirstFrame -> createAnimationState, not one-to-one
      • $Ticker -> $AnimationState, not one-to-one
        • tickAndUpload -> tick, getDrawUbo, needsToDraw, drawToAtlas; not one-to-one
    • SpriteTicker interface is removed
    • Stitcher now takes in the anisotropic filtering level
      • $Holder(T, int) is removed
      • $Region#walk now takes in a padding int
      • $SpriteLoader no longer takes in the minimum width/height
        • load now takes in a padding int
    • TextureAtlas now implements TickableTexture instead of Tickable
    • TextureAtlasSprite now implements AutoCloseable
      • The constructor takes in a padding int
      • createTicker -> createAnimationState, not one-to-one
      • getUOffset, getVOffset, uvShrinkRatio are removed
      • uploadFirstFrame now takes in the mip level int
      • uploadSpriteUbo - Uploads the atlas sprite to the to the buffer.
      • $Ticker interface is removed
    • TextureManager no longer implements Tickable
    • Tickable -> TickableTexture
  • net.minecraft.client.renderer.texture.atlas
    • SpriteSource$SpriteSupplier -> $DiscardableLoader
      • Function superinterface is now represented as $Loader
        • apply -> get
    • SpriteSourceList#list now returns a list of SpriteSource$Loaders
  • net.minecraft.client.resources.metadata.texture.TextureMetadataSection now takes in a MipmapStrategy to determine how a specific texture should be mip mapped, and a float for the alpha cutoff bias
  • net.minecraft.client.resources.model
    • ModelBaker
      • missingBlockModelPart - The missing block model.
      • parts - A cache of previously constructed vectors.
      • $PartCache - A cache that interns previously constructed vertices in a quad.
    • ModelBakery
      • *_STILL - Fluid still texture locations.
      • $MissingModels now takes in a BlockModelPart missing model
    • ModelManager
      • BLOCK_OR_ITEM - A special case that causes the model manager to check both the item and block atlas.
      • specialBlockModelRenderer now returns the raw renderer instead of a supplied value.
  • net.minecraft.data.AtlasIds#ITEMS - The item atlas identifier.
  • net.minecraft.world.level.block.LeavesBlock#setCutoutLeaves - Sets whether the leaves is using cutout rendering.

Gizmos

Gizmos are the newest iteration in the submission and rendering decoupling, this time for debug renderers. However, the underlying structure to submit gizmos for rendering is much more complex since debug renderers can submit objects at nearly any point during the client’s process.

What is a Gizmo?

A Gizmo is basically an object that submits some object primitives – specifically points, lines, triangle fans, quads, and text – for rendering. Each gizmo essentially strings together these primitives via emit into its desired shape. During the render process, these make use of the RenderPipelines#DEBUG_* pipelines to render their primitives to the screen. Creating a new gizmo is as simple as extending the interface:

// Store some parameters like a render state to submit the element primitives
public record ExampleGizmo(Vec3 start, Vec3 end) implements Gizmo {

    @Override
    public void emit(GizmoPrimitives gizmos, float alphaMultiplier) {
        // Submit any elements here
        gizmos.addLine(this.start, this.end, ARGB.multiplyAlpha(0, alphaMultiplier), 3f);
    }
}

Actually submitting the elements happens through Gizmos#addGizmo. This stores the gizmo to be emitted and drawn to the screen, as long as it is called during Minecraft#tick or any rendering on the client – which is how the debug renderers emit theirs, IntegratedServer#tickServer in a singleplayer world, or packet processing on either side. All of the methods in Gizmos call addGizmo internally, which is why the method is typically absent outside its class:

// Somewhere in GameRenderer#render

Gizmos.addGizmo(new ExampleGizmo(Vec3.ZERO, Vec3.X_AXIS));

// Calls addGizmo internally
Gizmos.point(Vec3.ZERO, 0, 5f);

Calling addGizmo returns a GizmoProperties, which sets some properties for when the element is drawn, assuming that GizmoCollector is not a NOOP. GizmoProperties provides three methods:

MethodDescription
setAlwaysOnTopClears the depth texture before rendering.
persistForMillisKeeps the gizmo on screen for the specified amount of time before disappearing.
fadeOutFades the disappearing when persisted for a certain amount of time.

Putting it Together

With that, how can you submit gizmos for rendering pretty much anywhere in the client pipeline? Well, this all starts from Gizmos#withCollector and SimpleGizmoCollector.

SimpleGizmoCollector is basically just a list that holds the collected gizmos to render. During the rendering process, SimpleGizmoCollector#drainGizmos is called, copying the gizmos over to a separate list for the renderer to Gizmo#emit, before drawing to the screen through the familiar frame pass and buffer source. drainGizmos then clears the internal list based on GizmoProperties#persistForMillis, or immediately if not specified, for the next frame.

To actually collect these elements, there is a rather convoluted process. Minecraft, LevelRenderer, and IntegratedServer have their own SimpleGizmoCollector. This is done by setting the collector using Gizmo#withCollector, which returns a Gizmos$TemporaryCollection. The collection is AutoCloseable that, when closed, releases the held collector on the local thread. So, the collectors are wrapped in a try-with-resources to facilitate the submission during these periods. Then, during the debug pass, the per tick gizmos are merged with the per frame gizmos and drawn to the screen via addTemporaryGizmos, quite literally at the last moment in LevelRenderer#renderLevel. The IntegratedServer gizmos in a singleplayer world are stored in a volatile field, allowing it to be accessed from the client thread.

  • net.minecraft.client.Minecraft
    • collectPerTickGizmos - Returns a collection of all gizmos to emit.
    • getPerTickGizmos - Gets the gizmos to draw to the screen.
  • net.minecraft.client.renderer
    • LevelRenderer#collectPerFrameGizmos - Returns a collection of all gizmos to emit.
    • OrderedSubmitNodeCollector#submitHitbox is removed
    • ShapeRenderer
      • renderShape now takes in a line width float
      • renderLineBox -> Gizmos#cuboid, not one-to-one
      • addChainedFilledBoxVertices -> Gizmos#cuboid, not one-to-one
      • renderFace -> Gizmos#rect, not one-to-one
      • renderVector -> Gizmos#line, not one-to-one
    • SubmitNodeCollection#getHitboxSubmits is removed
    • SubmitNodeStorage$HitboxSubmit record is removed
  • net.minecraft.client.renderer.debug
    • DebugRenderer
      • render -> emitGizmos, no longer takes in the PoseStack, BufferSource or boolean, now taking in the partial tick float
      • renderFilledUnitCube -> Gizmos#cuboid, not one-to-one
      • renderFilledBox -> Gizmos#cuboid, not one-to-one
      • renderTextOverBlock -> Gizmos#billboardTextOverBlock, not one-to-one
      • renderTextOverMob -> Gizmos#billboardTextOverMob, not one-to-one
      • renderFloatingText -> Gizmos#billboardText, not one-to-one
      • renderVoxelShape -> LevelRenderer#renderHitOutline, now private, not one-to-one
      • SimpleDebugRenderer$render -> emitGizmos, no longer takes in the PoseStack, BufferSource or boolean, now taking in the partial tick float
    • GameTestBlockHighlightRenderer
      • render -> emitGizmos, taking in no parameters
      • renderMarker no longer takes in the PoseStack or buffer source
      • $Marker#get* are removed
    • LightDebugRenderer now takes in two flags determining whether to show the block or sky light
    • PathfindingRenderer#renderPath, renderPathLine no longer take in the PoseStack or buffer source
  • net.minecraft.client.renderer.entity.EntityRenderer#extractAdditionalHitboxes is removed
  • net.minecraft.client.renderer.entity.state
    • EntityRenderState#hitboxesRenderState, serverHitboxesRenderState are removed
    • HitboxesRenderState class is removed
    • ServerHitboxesRenderState class is removed
  • net.minecraft.client.renderer.feature.HitboxFeatureRenderer -> EntityHitboxDebugRenderer, not one-to-one
  • net.minecraft.client.renderer.gizmos.DrawableGizmoPrimitives - A storage and renderer for primitive shapes. or gizmos.
  • net.minecraft.client.renderer.texture
    • AbstractTexture
      • sampler, getSampler - Returns the GpuSampler used by the texture.
      • setClamp -> GpuSampler#getAddressMode*, not one-to-one
      • setFilter -> GpuSampler#get*Filter, not one-to-one
    • ReloadableTexture no longer takes in the address mode and filter booleans
  • net.minecraft.client.server.IntegratedServer#getPerTickGizmos - Gets the gizmos to draw to the screen for the current tick.
  • net.minecraft.gizmos
    • ArrowGizmo - A gizmo that draws an arrow.
    • CircleGizmo - A gizmo that draws an approximate circle with twenty vertices.
    • CuboidGizmo - A gizmo that draws a rectangular prism.
    • Gizmo - An object that can emit simple shape primitives to draw.
    • GizmoCollector - An add-only collector.
    • GizmoPrimitives - Shape primitives that can be drawn.
    • GizmoProperties - Properties that apply to how the gizmo should be drawn.
    • Gizmos - A collection of static methods for creating gizmos and collecting them.
    • GizmoStyle - A property holder to define how a gizmo should be drawn. These are used by the gizmos themselves and not the actual primitives.
    • LineGizmo - A gizmo that draws a line.
    • PointGizmo - A gizmo that draws a point.
    • RectGizmo - A gizmo that draws a rectangle.
    • SimpleGizmoCollector - A collector implementation for adding gizmos before sending them off for rendering.
    • TextGizmo - A gizmo that draws text.
  • net.minecraft.server.MinecraftServer#processPacketsAndTick - Handles server ticking and packet processing.

Permission Overhaul

The permission level integer has been expanded into an entirely new system that is both simple yet complicated. There are three main parts: Permissions, PermissionSets, and PermissionChecks.

Permissions

Permissions are functionally data objects that define some sort of state. Vanilla provides two types of permissions: Permission$Atom, which just is a unique unit object; and Permission$HasCommandLevel, which holds the desired PermissionLevel for a command. Both of the data objects are registered as map codecs for dumping the command report.

// Attempts to query moderator level permissions.
public static final Permission COMMANDS_MODERATOR = new Permission.HasCommandLevel(PermissionLevel.MODERATORS);

A custom permission can be created through some class or record that extends Permission with an associated MapCodec registered to its static registry:

// This does not check whether the user has the given permission
// It is literally just holding data representing the permission state
public record HasExamplePermission(int state) implements Permission {
    public static final MapCodec<HasExamplePermission> MAP_CODEC = Codec.INT.fieldOf("state")
        .xmap(HasExamplePermission::new, HasExamplePermission::state);
    
    @Override
    public MapCodec<HasExamplePermission> codec() {
        return HasExamplePermission.MAP_CODEC;
    }
}

// In some registration handler
Registry.register(
    BuiltInRegistries.PERMISSION_TYPE
    Identifier.withNamespaceAndPath("examplemod", "has_example_permission"),
    HasExamplePermission.MAP_CODEC
);

// Storing the permission for use
public static final Permission HAS_STATE_ONE = new HasExamplePermission(1);

Permission Sets

If Permissions define the queryable state, then PermissionSets are the permissions the user actually has. PermissionSet is a functional interface that checks whether the user has the desired permission state (via hasPermission). Vanilla uses a LevelBasedPermissionSet for checking whether the permission queried matches the current PermissionLevel. As a permission set is usually checked against some swathe of permissions, multiple permission sets can be combined into one via PermissionSet#union. It functionally performs an OR operation, meaning that if a set does not check a permission, it should default to false.

public interface ExamplePermissionSet extends PermissionSet {

    // Keep track of the user's state for our permissions
    int state();

    @Override
    default boolean hasPermission(Permission permission) {
        // Check our permission
        if (permission instanceof HasExamplePermission example) {
            return this.state() >= example.state();
        }

        // Otherwise ignore
        return false;
    }
}

// Storing a permission set
// Could also be implemented or stored on the desired target
public static ExamplePermissionSet STATE_ONE = () -> 1;

// Check whether the permission set has the desired permission
STATE_ONE.hasPermission(HAS_STATE_ONE);

Currently, there is no simple method to store custom permission sets on the desired user. CommandSourceStack does have a method to union other permission sets via withMaximumPermission, but that would need to be handled within the associated createCommandSourceStack method. The normal LevelBasedPermissionSet can typically be queried through a permissions method, though there is no common interface across objects, even though PermissionSetSupplier seems to exist for that purpose.

Permission Checks

Now, a PermissionSet never directly checks a Permission within the codebase. That would require having the object accessible at all times. Instead, a PermissionCheck object is created, which takes in the PermissionSet and checks whether the user has the desired data to continue execution. Vanilla provides two types of checks: $AlwaysPass, which means it will always return true; and $Require, which requires the set to have the desired Permission. The checks also have a map codec for dumping the command report.

// Requires the permission set has acccess to moderator commands
public static final PermissionCheck LEVEL_MODERATORS = new PermissionCheck.Require(COMMANDS_MODERATOR);

Custom permission checks can be created through some class or record that implements check and registers the map codec to its static registry:

public static record AnyOf(List<Permission> permissions) implements PermissionCheck {
    public static final MapCodec<AnyOf> MAP_CODEC = Permission.CODEC.listOf().fieldOf("permissions")
        .xmap(AnyOf::new, AnyOf::permissions);

    @Override
    public boolean check(PermissionSet permissionSet) {
        return this.permissions.stream().filter(perm -> permissionSet.hasPermission(perm)).findAny().isPresent();
    }

    @Override
    public MapCodec<AnyOf> codec() {
        return MAP_CODEC;
    }
}

// In some registration handler
Registry.register(
    BuiltInRegistries.PERMISSION_CHECK_TYPE
    Identifier.withNamespaceAndPath("examplemod", "any_of"),
    AnyOf.MAP_CODEC
);

// Storing the check for use in a command
public static final PermissionCheck CHECK_STATE_ONE = new AnyOf(List.of(
    HAS_STATE_ONE,
    Permissions.COMMANDS_GAMEMASTER
));

// For some command
Commands.literal("example").requires(Commands.hasPermission(CHECK_STATE_ONE));
  • net.minecraft.client.multiplayer.ClientSuggestionProvider no longer implements PermissionSource
    • The constructor now takes in a PermissionSet instead of a boolean
    • allowsRestrictedCommands -> ClientPacketListener#ALLOW_RESTRICTED_COMMANDS, now private, not one-to-one
  • net.minecraft.client.player.LocalPlayer#setPermissionLevel -> setPermissions, not one-to-one
  • net.minecraft.commands
    • Commands
      • LEVEL_* are now PermissionChecks instead of ints
      • hasPermission now takes in a PermissionCheck instead of an int, and returns a PermissionProviderCheck instead of a PermissionCheck
      • createCompilationContext - Creates a source stack with the given permissions.
    • CommandSourceStack no longer implements PermissionSource
      • The constructor now takes in a PermissionSet instead of an int
      • The protected constructor is now private
      • withPermission now takes in a PermissionSet instead of an int
      • withMaximumPermission now takes in a PermissionSet instead of an int
    • ExecutionCommandSource now extends PermissionSetSupplier instead of PermissionSource
    • PermissionSource interface is removed
    • SharedSuggestionProvider now extends PermissionSetSupplier
  • net.minecraft.commands.arguments.selector.EntitySelectorParser#allowSelectors now has an overload that takes in a PermissionSetSupplier
  • net.minecraft.core.registries
    • BuiltInRegistries#PERMISSION_TYPE, Registries#PERMISSION_TYPE - An object that defines some data requirement.
    • BuiltInRegistries#PERMISSION_CHECK_TYPE, Registries#PERMISSION_CHECK_TYPE - A predicate that checks whether the set has the required data.
  • net.minecraft.server
    • MinecraftServer
      • operatorUserPermissionLevel -> operatorUserPermissions, not one-to-one
      • getFunctionCompilationLevel -> getFunctionCompilationPermissions, not one-to-one
      • getProfilePermissions now returns a LevelBasedPermissionSet
    • ReloadableServerResources#loadResources now takes in a PermissionSet instead of an int
    • ServerFunctionLibrary now takes in a PermissionSet instead of an int
    • WorldLoader$InitConfig now takes in a PermissionSet instead of an int
  • net.minecraft.server.commands.PermissionCheck -> .server.permissions.PermissionCheck, not one-to-one
  • net.minecraft.server.dedicated.DedicatedServerProperties
    • opPermissionLevel -> opPermissions, not one-to-one
    • functionPermissionLevel -> functionPermissions, not one-to-one
    • deserializePermissions, serializePermission - Reads and writes the chosen level permission set.
  • net.minecraft.server.jsonrpc.internalapi
    • MinecraftOperatorListService#op now takes in an optional PermissionLevel instead of an int
    • MinecraftServerSettingsService
      • getOperatorUserPermissionLevel -> getOperatorUserPermissions, not one-to-one
      • setOperatorUserPermissionLevel -> setOperatorUserPermissions, not one-to-one
  • net.minecraft.server.jsonrpc.methods
    • OperatorService$OperatorDto#permissionLevel now takes in an optional PermissionLevel instead of an int
    • ServerSettingsService
      • operatorUserPermissionLevel now returns a PermissionLevel instead of an int
      • setOperatorUserPermissionLevel now takes in and returns a PermissionLevel instead of an int
  • net.minecraft.server.permissions
    • LevelBasedPermissionSet - A set of permissions that checks whether the user has an equal or higher command permission level.
    • Permission - Data related to the user’s permissions, such as command level.
    • PermissionCheckTypes - The types of permission checks vanilla provides.
    • PermissionLevel - Defines a level sequence for a permission.
    • PermissionProviderCheck - A predicate that checks that tests the supplier’s permission set against a check.
    • Permissions - The permissions vanilla provides.
    • PermissionSet - A set of a permissions to user has, but mostly defines a method to determine whether a user has the desired permission.
    • PermissionSetSupplier - An object that supplies a PermissionSet.
    • PermissionSetUnion - A union of multiple permission sets.
    • PermissionTypes - The types of permissions vanilla provides.
  • net.minecraft.server.players
    • PlayersList#op now takes in an optional LevelBasedPermissionSet instead of an int
    • ServerOpListEntry now takes in a LevelBasedPermissionSet instead of an int
      • getLevel -> permissions, not one-to-one
  • net.minecraft.world.entity.player.Player#getPermissionLevel, hasPermissions -> permissions, not one-to-one
  • net.minecraft.world.entity.projectile.ProjectileUtils
    • getHitEntitiesAlong - Gets the entities hit along the provided path.
    • getManyEntityHitResult - Gets all entities hit along the path of the two points within the bounding box.
  • net.minecraft.world.entity.projectile.arrow.AbstractArrow#findHitEntities - Gets all entities hit by the vector.

New Data Components

With the addition of the spear, a number of data components have been added to provide the associated functionality. The following is an brief overview of these components.

Use Effects

DataComponents#USE_EFFECTS defines some effects to apply to the player that is using (e.g., right-clicking) an item. Currently, there are only three types of effects: whether the player can sprint when using the item, whether the use interaction causes vibrations, and the scalar that is applied to the player’s horizontal movement.

// For some item registration
new Item(new Item.Properties.component(
    DataComponents.USE_EFFECTS,
    new UseEffects(
        // Whether the player can sprint while using the item
        true,
        // Whether on item use that a vibration is sent from the player
        false
        // The scalar applied to the player's horizontal movement
        0.5f
    )
));

Damage Type

DataComponents#DAMAGE_TYPE defines the damage type applied to an entity when hit with this item. It takes in either the ResourceKey of the damage type or the DamageType object itself.

// For some item registration
new Item(new Item.Properties.component(
    DataComponents.DAMAGE_TYPE,
    new EitherHolder<>(
        // The damage type this item applies to the attacked entity
        DamageTypes.FALLING_ANVIL
    )
));

Swing Animation

DataComponents#SWING_ANIMATION defines the animation to play when swinging or attacking (e.g., left-clicking) with the item. There are three types of animation to play: SwingAnimationType#NONE, which does nothing; WHACK, which plays the standard swing animation; and STAB, which plays the spear thrust animation. The length of the animation can also be specified.

// For some item registration
new Item(new Item.Properties.component(
    DataComponents.SWING_ANIMATION,
    new SwingAnimation(
        // The animation to play
        SwingAnimationType.NONE,
        // The amount of time to play the animation for, in ticks
        20
    )
));

Minimum Attack Charge

DataComponents#MINIMUM_ATTACK_CHARGE determines how long the player must wait before making another attack with the item. The charge is a value between 0 and 1, which determines percentage of the delay to wait before making another attack. The delay is determined by the player’s attack speed. This is checked twice if the player’s action is a stab.

// For some item registration
new Item(new Item.Properties.component(
    DataComponents.MINIMUM_ATTACK_CHARGE,
    // The percentage of time the player must wait before making another attack with this item
    0.5f
));

Attack Range

DataComponents#ATTACK_RANGE determines the range that an entity can attack another entity from when attacking with this item. If not set, it defaults to the entity’s interaction range attribute. The range specified is for the player, with mob reach determined by the range times the mob factor. A range can also be specified for the player when in creative mode, overriding the default range.

// For some item registration
new Item(new Item.Properties.component(
    DataComponents.ATTACK_RANGE,
    new AttackRange(
        // The minimum range in blocks for this item to hit the entity.
        // Must be between [0, 64]; defaults to 0.
        0.4f,
        // The maximum range in blocks for this item to hit the entity.
        // Must be between [0,64]; defaults to 3.
        4.5f,
        // The minimum range in blocks for this item to hit the entity,
        // provided the holding entity is a player in creative mode.
        // This supercedes the minimum range.
        // Must be between [0, 64]; defaults to 0.
        0f,
        // The maximum range in blocks for this item to hit the entity,
        // provided the holding entity is a player in creative mode.
        // This supercedes the maximum range.
        // Must be between [0,64]; defaults to 3.
        5f,
        // The margin to inflate the hitbox by in blocks, compensating
        // for potential precision issues.
        // Must be between [0,1]; defaults to 0.3.
        0.25f,
        // A scalar to multiply the minimum and maximum range by to determine
        // a non-player entity's reach.
        // Must be between [0,2]; defaults to 1.
        1.1f
    )
));

Piercing Weapon

DataComponents#PIERCING_WEAPON sets the player’s attack as not an attack, but as a stab or piercing attack. This is a separate action than swinging, which either attacks the entity or breaks a block. A piercing weapon can attack an entity, but is unable to break blocks. It also applies any enchantment effects for lunging. Piercing weapons are only applied to the player.

The logic pipeline flows like so:

  • If Player#cannotAttackWithItem returns true, then the pipeline is terminated
  • Piercing attack is handled via:
    • Client - MultiPlayerGameMode#piercingAttack
    • Server - PiercingWeapon#attack
  • Server-only:
    • Get all entities that:
      • Are within the entity’s attack range DataComponents#ATTACK_RANGE
      • Are within the hitbox constructed from the reach starting at the player’s eye position
      • If PiercingWeapon#canHitEntity returns true:
        • Player is not invulnerable or dead, and
        • Either:
          • Entity is an Interaction entity
        • Or:
          • Entity can be hit by a projectile
          • If both players, that this player can harm the other player
          • Is not a passenger of the same vehicle
    • Call LivingEntity#stabAttack on each entity
  • LivingEntity#onAttack is fired
  • LivingEntity#lungeForwardMaybe is fired
  • Server-only:
    • PiercingWeapon#makeHitSound is played if at least one entity was hit
    • PiercingWeapon#makeSound is played
  • LivingEntity#swing is fired
// For some item registration
new Item(new Item.Properties.component(
    DataComponents.PIERCING_WEAPON,
    new PiercingWeapon(
        // Whether being hit by this item deals knockback to the entity.
        true,
        // Whether being hit by this item dismounts the entity from its vehicle.
        true,
        // The sound to play when attacking with this item.
        // If the optional is empty, no sound is played.
        Optional.of(SoundEvents.LLAMA_SWAG),
        // The sound to play when this item hits an entity.
        // If the optional is empty, no sound is played.
        Optional.of(SoundEvents.ITEM_BREAK)
    )
));

Kinetic Weapon

DataComponents#KINETIC_WEAPON affects an entity’s use (e.g., right-click) behavior. On right-click, if an item has the component, then KineticWeapon#damageEntities is called every tick instead of Item#onUseTick, only on the server. The kinetic weapon also calls LivingEntity#stabAttack to damage its entities similar to piercing attack. In fact, the component itself is similar to PiercingWeapon, except with a few additional fields to handle the kinetic damage applied and to make it accessible to all living entities instead of only the player.

For the stab attack to occur, one of the conditions (dismount, knockback, damage) must be present and return true. The attack range is obtained from the DataComponents#ATTACK_RANGE component. If a stab attack occurs, then the SPEAR_MOBS_TRIGGER criteria will be fired on the server.

// For some item registration
new Item(new Item.Properties.component(
    DataComponents.KINETIC_WEAPON,
    new KineticWeapon(
        // The number of ticks to wait before this entity can attempt to contact
        // (e.g., damage) another entity.
        10,
        // The number of ticks to wait before attempting to stab any entities in range.
        20,
        // The condition to check whether an attack from this item will dismount
        // an entity in a vehicle.
        // If the optional is not present, then it will default to false.
        Optional.of(new KineticWeapon.Condition(
            // The maximum number of ticks from first use plus delay that this
            // condition may return true.
            100,
            // The minimum speed the entity must be traveling for this condition
            // to succeed.
            // The speed is calculated as the dot product of the delta movement
            // and the view vector multiplied by 20.
            // Vanilla spears use values from 7-14 for dismount and 5.1 for knockback.
            9f,
            // The minimum speed relative to the attacking entity that this entity
            // must be traveling for this condition to succeed.
            // Vanilla spears use 4.6 for damage.
            5f
        )),
        // The condition to check whether an attack from this item will cause knockback
        // to an entity.
        // If the optional is not present, then it will default to false.
        Optional.of(KineticWeapon.Condition.ofAttackerSpeed(
            // Maximum ticks
            100,
            // Entity traveling speed
            5.1f
        )),
        // The condition to check whether an attack from this item will damage an
        // entity.
        // If the optional is not present, then it will default to false.
        Optional.of(KineticWeapon.Condition.ofRelativeSpeed(
            // Maximum ticks
            100,
            // Relative traveling speed
            4.6f
        )),
        // The movement of the item during the third person attack animation
        // Vanilla spears use 0.38.
        0.38f,
        // A multiplier to apply to the damage of an entity
        // The damage is calculated as the relative traveling speed of this entity
        // to its target.
        4f,
        // The sound to play when first using this item.
        // If the optional is empty, no sound is played.
        Optional.of(SoundEvents.LLAMA_SWAG),
        // The sound to play when this item hits an entity.
        // If the optional is empty, no sound is played.
        Optiona.of(SoundEvents.ITEM_BREAK)
    )
));
  • net.minecraft.core.components
    • DataComponents
      • USE_EFFECTS - The effects to apply to the entity when using the item.
      • MINIMUM_ATTACK_CHARGE - The minimum amount of time to attack with the item.
      • DAMAGE_TYPE - The DamageType the item deals
      • PIERCING_WEAPON - A weapon with some hitbox range that lunges towards the entity.
      • KINETIC_WEAPON - A weapon with some hitbox range that requires some amount of forward momentum.
      • SWING_ANIMATION - The animation applied when swinging an item.
      • ATTACK_RANGE - Sets a custom attack range when using the item, overriding the normal entity interaction range.
  • net.minecraft.core.component.DataComponentType#ignoreSwapAnimation, $Builder#ignoreSwapAnimation - When true, the swap animation does not affect the data component ‘usage’.
  • net.minecraft.core.component.predicates
    • AnyValue - A predicate that checks if the component exists on the getter.
    • DataComponentPredicate
      • $Type is now an interface
        • Its original implementation has been replaced by $TypeBase
      • $AnyValueType - A type that uses the AnyValue predicate.
      • $ConcreteType - A type that defines a specific predicate.
  • net.minecraft.network.protocol.game.ServerboundInteractPacket#isWithinRange - Whether the interaction from the player is within the valid range to execute.
  • net.minecraft.world.entity
    • LivingEntity
      • SWING_DURATION -> SwingAnimation#duration, not one-to-one
      • stabbedEntities - The number of recent entities attacked by a kinetic weapon.
      • entityAttackRange - The range that this entity can attack.
      • getActiveItem - The currently used item, or the mainhand item.
    • Mob
      • chargeSpeedModifier - The modifier applied to the movement speed when charging.
      • canFireProjectileWeapon -> canUseNonMeleeWeapon, now taking in an ItemStack instead of a ProjectileWeaponItem
      • getAttackBoundingBox now takes in a horizontal inflation offset
  • net.minecraft.world.entity.ai.behavior
    • ChargeAttack - Handles a charge attack performed by a mob.
    • SpearApproach - Approaches the enemy when holding a kinetic weapon.
    • SpearAttack - Attacks the enemy with a kinetic weapon.
    • SpearRetreat - Flees from the attacked target after using a kinetic weapon.
  • net.minecraft.world.entity.ai.goal.SpearUseGoal - Handles a mob using a spear.
  • net.minecraft.world.entity.ai.memory.MemoryModuleType
    • SPEAR_FLEEING_TIME - The number of ticks the entity has been fleeing for after using a kinetic weapon.
    • SPEAR_FLEEING_POSITION - The position the entity flees to after using a kinetic weapon.
    • SPEAR_CHARGE_POSITION - The position the entity charges to when using a kinetic weapon.
    • SPEAR_ENGAGE_TIME - How long this entity has been engaged with its enemy when using a kinetic weapon.
    • SPEAR_STATUS - The status of the entity when using a kinetic weapon.
  • net.minecraft.world.entity.player.Player
    • hasEnoughFoodToDoExhaustiveManoeuvres - Returns whether the player can perform an exhaustive manuever.
    • canInteractWithEntity -> isWithinEntityInteractionRange
    • isWithinAttackRange - If the bounding box being targeted is within the player’s range.
    • canInteractWithBlock -> isWithinBlockInteractionRange
    • CREATIVE_ENTITY_INTERACTION_RANGE_MODIFIER_VALUE - A modifiers that increases the maximum range of an interaction by the given amount.
  • net.minecraft.world.item
    • Item#getDamageSource -> getItemDamageSource, now deprecated
    • ItemStack
      • getSwingAnimation - Returns the swing animation of the item.
      • getDamageSource - Returns the damage source the item provides when hit.
      • causeUseVibration - Sends the game event if the item on use can cause vibrations.
    • SwingAnimationType - The type of animation played when swinging the item.
  • net.minecraft.world.item.component
    • AttackRange - The hitbox range of this item.
    • KineticWeapon - A weapon that requires some amount of forward momentum.
    • PiercingWeapon - A weapon that lunges towards the entity.
    • SwingAnimation - The animation applied when swinging an item.
    • UseEffects - The effects to apply to the entity when using the item.

The Timeline of Environment Attributes

Environment attributes, as the name implies, defines a set of properties or modifications (‘attributes’) for a given dimension and/or biome (‘environment’). They are stored directly within the biome or dimension type under the attributes field, or as part of a mutable timeline under the tracks field. Each attribute can represent anything from the visual settings to gameplay behavior, interpolating between different values as defined. Vanilla provides their available attributes within EnvironmentAttributes while the stored attributes are obtained from Level#environmentAttributes.

// For some DimensionType json
// In `data/examplemod/dimension_type/example_dimension.json`
{
    // Defines the attributes to apply within the dimension
    "attributes": {
        // Sets the cloud height
        // More technically, modifies the value by overriding it
        "minecraft:visual/cloud_height": 90
    },
    // ...
}

// For some Biome json
// In `data/examplemod/worldgen/biome/example_biome.json`
{
    // Defines the attributes to apply within the biome
    // Defaults or modifies those in the dimension
    // These attributes must be positional
    "attributes": {
        "minecraft:visual/cloud_height": {
            // Instead of setting the value, apply a modifier
            "modifier": "add",
            // Adds 60 to 90, making this biome have a cloud height of 150
            "argument": 60
        }
    }
    // ...
}

// For some Timeline json
// In `data/examplemod/timeline/example_timeline.json
{
    // The number of ticks this track takes before repeating
    "period_ticks": 24000,
    // Defines the attributes to interpolate between
    // based on the defined keyframes.
    // Defaults or modifies those in the biome, or dimension
    "tracks": {
        "minecraft:visual/cloud_height": {
            // The keyframes that define certain values of the attribute
            "keyframes": [
                {
                    // The tick representing the keyframe
                    "tick": 12000,
                    // The argument that modifies the value
                    // In this case, adds 1 to 60 + 90, making this have a cloud height of 151
                    "value": 1
                },
                {
                    // The tick representing the keyframe
                    "tick": 23999,
                    // The argument that modifies the value
                    // In this case, adds 0 to 60 + 90, making this have a cloud height of 150
                    "value": 0
                }
            ],
            // Instead of setting the value, applies a modifier to the argument
            "modifier": "add",
            // The sampler function to apply when interpolating between ticks
            "ease": "linear"
        }
    }
}

When calling EnvironmentAttributeSystem#getValue, the attribute value is obtained through the layers defined by the Level:

  1. Read the default value from the registered attribute (via EnvironmentAttribute#defaultValue).
  2. Apply the modifier from the dimension, or do nothing if one does not exist for this attribute.
  3. Apply the modifier from the biome, or do nothing if one does not exist.
  4. Apply the modifiers from all active timelines defined in the DimensionType, or do nothing if none exist. Timeline order is not guaranteed.
  5. If the dimension can have weather (skylight, no ceiling, and not the end), apply the modifiers from the WeatherAttributes.
  6. If on the client (i.e. ClientLevel), apply the sky flashes modifier.
  7. Sanitize the final value to be in the range defined by the EnvironmentAttribute.

This is highly oversimplified and introduces many new concepts, so let’s break it down further by creating our own environment attribute and timeline.

Custom Environment Attributes

Environment attributes are created through the $Builder, via EnvironmentAttribute#builder, taking the type value it represents (e.g., float, integer, object). The builder only requires one value to be set: the defaultValue. This is used if the attribute is not overridden by a dimension or biome. If the attribute value should have a valid set of states, then an AttributeRange can be set via valueRange. The AttributeRange is basically a unary operator that transforms the input into its ‘valid’ state via sanitize. It also verifies that the value passed in through the JSON is in a ‘valid’ state via validate.

From there, there are three more methods responsible for determining the logic used to compute the value. $Builder#syncable syncs the attribute to the client, which is required for any attribute that causes some sort of change that is not specific to the server (e.g., visuals, audio, or common code). notPositional means that the attribute cannot be applied on a biome (still settable in a dimension or timeline), else an exception is thrown. Finally spatiallyInterpolated will attempt to interpolate using the attribute type between different biomes to apply a more seamless transition. Vanilla only handles client side attributes for spatial interpolation. Anything on the server must handle their own SpatialAttributeInterpolator.

Finally the actual attribute can be obtained via $Builder#build. This value must be registered to BuiltInRegistries#ENVIRONMENT_ATTRIBUTE:

public static final EnvironmentAttribute<Boolean> EXAMPLE_ATTRIBUTE = Registry.register(
    BuiltInRegistries.ENVIRONMENT_ATTRIBUTE,
    Identifier.withNamespaceAndPath("examplemod", "example_attribute"),
    EnvironmentAttribute.builder(
        // The attribute type
        // Must match the generic for the attribute value
        AttributeTypes.BOOLEAN
    )
        // The value this attribute should have by default
        .defaultValue(false)
        // Syncs this value to the client
        .syncable()
        .build()
);
// For some DimensionType json
// In `data/examplemod/dimension_type/example_dimension.json`
{
    "attributes": {
        "examplemod:example_attribute": true
    },
    // ...
}

// For some Biome json
// In `data/examplemod/worldgen/biome/example_biome.json`
{
    "attributes": {
        "examplemod:example_attribute": {
            "modifier": "xor",
            "argument": true
        }
    }
    // ...
}

// For some Timeline json
// In `data/examplemod/timeline/example_timeline.json
{
    "period_ticks": 24000,
    "tracks": {
        "examplemod:example_attribute": {
            "keyframes": [
                {
                    "tick": 12000,
                    "value": false
                },
                {
                    "tick": 23999,
                    "value": true
                }
            ],
            "modifier": "and",
            "ease": "linear"
        }
    }
}

Custom Attribute Types

Every environment attribute has an associated attribute type that is statically registered to BuiltInRegistries#ATTRIBUTE_TYPE. Not only does this define how to serialize the object value, but it also contains the modifications that can be applied to the value along with how to interpolate between spaces and frames. In fact, all of the builder settings, including syncable and spatiallyInterpolated, rely on the attribute type to determine what does it mean to perform that action. Without it, the attribute couldn’t even be read from the dimension or biome JSON, much less the actual logic behind getting the value of the attribute.

As such, the attribute type can be broken into three parts: the serialization codec, the modifier library, and the interpolation functions.

// We will use this example object for explaining the attribute type
public record ExampleObject(int value1, boolean value2) {
    // The default value
    public static final ExampleObject DEFAULT = new ExampleObject(0, false);
}

Type Serialization

Serialization of the attribute type is handled through a codec of that type, both to disk (biome and dimension JSON) and network ($Builder#syncable):

// The codec to serialize the attribute type value
public static final Codec<ExampleObject> CODEC = RecordCodecBuilder.create(
    instance -> instance.group(
        Codec.INT.fieldOf("value1").forGetter(ExampleObject::value1),
        Codec.BOOL.fieldOf("value2").forGetter(ExampleObject::value2)
    ).apply(instance, ExampleObject::new)
);

Modifier Library

The modifier library is a map of AttributeModifier$OperationId to AttributeModifiers that determine what operations can be performed on the default value. If the map contains no operations, the the default value cannot be mutated. All of the static constructors for AttributeType add the OVERRIDE modifier, allowing for the dimension and/or biome to set the value. This map should be thought of as a pseudo-registry (basically keys to unique values), as the default codec used to serialize is for a BiMap via an id resolver.

An AttributeModifier defines two generics: the first being the environment attribute value type, and the second being an arbitrary object to apply the operation with. The modifier has two methods: apply, which takes in the value and the argument to return a new value; and argumentCodec to properly serialize the argument. For any operation, all possible mutations must be implemented within a single AttributeModifier:

// Modifiers only handling a part of the object
public static final AttributeModifier<ExampleObject, Integer> ADD = new AttributeModifier<>() {

    @Override
    public ExampleObject apply(ExampleObject subject, Integer argument) {
        // Apply the operation to the subject
        return new ExampleObject(subject.value1() + argument, subject.value2());
    }

    @Override
    public Codec<Integer> argumentCodec(EnvironmentAttribute<ExampleObject> attribute) {
        // Construct the codec to deserialize the argument
        return Codec.INT;
    }
};

public static final AttributeModifier<ExampleObject, Boolean> OR = new AttributeModifier<>() {

    @Override
    public ExampleObject apply(ExampleObject subject, Boolean argument) {
        // Apply the operation to the subject
        return new ExampleObject(subject.value1(), subject.value2() || argument);
    }

    @Override
    public Codec<Boolean> argumentCodec(EnvironmentAttribute<ExampleObject> attribute) {
        // Construct the codec to deserialize the argument
        return Codec.BOOL;
    }
};

// A modifier handling all possible object combinations
public static final AttributeModifier<ExampleObject, Either<ExampleObject, Either<Integer, Boolean>>> AND = new AttributeModifier<>() {

    @Override
    public ExampleObject apply(ExampleObject subject, Either<ExampleObject, Either<Integer, Boolean>> argument) {
        return argument.map(
            arg -> new ExampleObject(subject.value1() & arg.value1(), subject.value2() && arg.value2()),
            either -> either.map(
                arg -> new ExampleObject(subject.value1() & arg, subject.value2()),
                arg -> new ExampleObject(subject.value1(), subject.value2() && arg)
            )
        );
    }

    @Override
    public Codec<Either<ExampleObject, Either<Integer, Boolean>>> argumentCodec(EnvironmentAttribute<ExampleObject> attribute) {
        // Construct the codec to deserialize the argument
        // We can use the attribute codec for the value type
        return Codec.either(attribute.valueCodec(), Codec.either(Codec.INT, Codec.BOOL));
    }
};

// Constructing the library
// The argument can be any value as long as it can be serialized and handled
// If using one of the static constructors for the attribute type, the override
// handler is added automatically along with the associated modifier codec for
// the map
public static final Map<AttributeModifier.OperationId, AttributeModifier<ExampleObject, ?>> EXAMPLE_LIBRARY = Map.of(
    AttributeModifier.OperationId.ADD, ADD,
    AttributeModifier.OperationId.OR, OR,
    AttributeModifier.OperationId.AND, AND
);

Type Interpolation

To support interpolation, whether for client frames (because of $Builder#syncable), spatial ($Builder#spatiallyInterpolated), states (weather), or keyframes (timelines), there needs to be some function that, given some step between 0 and 1 (either time or position), how are the two values merged. This is handled through a LerpFunction, of which the generic is the environment attribute value type. For non-interpolated values, this normally uses LerpFunction#ofStep, which acts like a simple threshold between the two values. More specifically, spatial will set the threshold as 0.5 while the partial tick, keyframe, and state change will only consider full steps (meaning always the next value). However, this function can be however you choose to define it:

// Step represents the value between 0 and 1 to interpolation
// Original represents the step at 0
// Next represents the step at 1
public static final LerpFunction<ExampleObject> EXAMPLE_SPATIAL_LERP = (step, original, next) -> {
    return new ExampleObject(
        Mth.lerp(step, original.value1(), next.value1()),
        step >= 0.5f ? next.value2() : original.value2()
    );
}

public static final LerpFunction<ExampleObject> EXAMPLE_PARTIAL_LERP = (step, original, next) -> {
    return new ExampleObject(
        Mth.lerp(step, original.value1(), next.value1()),
        next.value2()
    );
}

// Will always return the first value
public static final LerpFunction<ExampleObject> EXAMPLE_KEYFRAME_LERP = LerpFunction.ofConstant();

// Will change to the next state after 0.1 of the step has past
public static final LerpFunction<ExampleObject> EXAMPLE_STATE_CHANGE_LERP = LerpFunction.ofStep(0.1f);

Putting it all Together

With each of these parts, an AttributeType can now be constructed. This is typically done using one of the static constructors: ofInterpolated for values that define their interpolation function, or ofNotInterpolated, for values that are okay just snapping between two values. For common use cases, unless your value transitions between something that is inherently obvious to the player (e.g., visuals like fog or sky color), then interpolation is generally unnecessary.

If you decide to use the AttributeType instance constructor instead, you will also have to create a codec to serialize the modifier map. See AttributeType#createModifierCodec on how to do so.

// The attribute type must be statically registered to be handled correctly
public static final AttributeType<ExampleObject> EXAMPLE_ATTRIBUTE_TYPE = Registry.register(
    BuiltInRegistries.ATTRIBUTE_TYPE,
    Identifier.withNamespaceAndPath("examplemod", "example_attribute_type"),
    new AttributeType<>(
        // The codec for the value
        ExampleObject.CODEC,
        // The map of operations that can be modified
        // `OVERRIDE` is automatically added for serialization
        EXAMPLE_LIBRARY,
        // The codec used to serialize the modifier library
        Util.make(() -> {
            ImmutableBiMap<AttributeModifier.OperationId, AttributeModifier<Value, ?>> map = ImmutableBiMap.builder()
                .put(AttributeModifier.OperationId.OVERRIDE, AttributeModifier.override())
                .putAll(EXAMPLE_LIBRARY)
                .buildOrThrow();
            return ExtraCodecs.idResolverCodec(AttributeModifier.OperationId.CODEC, map::get, map.inverse()::get);
        }),
        // The function interpolating between two keyframes in a timeline
        EXAMPLE_KEYFRAME_LERP,
        // The function interpolating between two states (only used for attributes in the weather maps)
        EXAMPLE_STATE_CHANGE_LERP,
        // The function interpolating between two spatial coordinates
        EXAMPLE_SPATIAL_LERP,
        // The function interpolating between client frames
        EXAMPLE_PARTIAL_LERP
    )
);

From there, we can create an EnvironmentAttribute that uses said type:

public static final EnvironmentAttribute<ExampleObject> EXAMPLE_OBJECT_ATTRIBUTE = Registry.register(
    BuiltInRegistries.ENVIRONMENT_ATTRIBUTE,
    Identifier.withNamespaceAndPath("examplemod", "example_object_attribute"),
    EnvironmentAttribute.builder(
        EXAMPLE_ATTRIBUTE_TYPE
    )
        .defaultValue(ExampleObject.DEFAULT)
        // Possible because of the codec and partial tick lerp
        .syncable()
        // Possible because of the spatial lerp
        .spatiallyInterpolated()
        .build()
);
// For some DimensionType json
// In `data/examplemod/dimension_type/example_dimension.json`
{
    "attributes": {
        "examplemod:example_object_attribute": {
            "value1": 10,
            "value2": true
        }
    },
    // ...
}

// For some Biome json
// In `data/examplemod/worldgen/biome/example_biome.json`
{
    "attributes": {
        "examplemod:example_object_attribute": {
            // Must use one of the arguments defined in the library
            // In this case either 'add', 'or', or 'and'
            "modifier": "and",
            // This can be either a boolean, integer, or object
            // because of how the serializer was defined
            "argument": false
        }
    }
    // ...
}

// For some Timeline json
// In `data/examplemod/timeline/example_timeline.json
{
    "period_ticks": 24000,
    "tracks": {
        "examplemod:example_object_attribute": {
            "keyframes": [
                {
                    "tick": 12000,
                    // This can be either a boolean, integer, or object
                    // because of how the serializer was defined
                    "value": 1
                },
                {
                    "tick": 23999,
                    // This can be either a boolean, integer, or object
                    // because of how the serializer was defined
                    "value": {
                        "value1": 0,
                        "value2": false
                    }
                }
            ],
            // Must use one of the arguments defined in the library
            // In this case either 'add', 'or', or 'and'
            "modifier": "and",
            "ease": "linear"
        }
    }
}

Timelines

Timelines are method of modifying attributes based on the current game time. More specifically, they define some keyframes that the values are interpolated between, first determining the step using the EasingType function, and second using AttributeType#keyframeLerp to get the value. This is not only a replacement of Schedules in brains, but also attributes relating to the day/night cycle (e.g., sky color, slime spawn chance, etc.). These function as a layer after the biome modifiers are applied for both positional and non-positional attributes.

Timelines are activated based on the DimensionType#timelines tag, which are prefixed with in_ (e.g. minecraft:in_overworld is the timeline tag for the overworld). All dimension tags include the minecraft:universal tag, meaning all timelines tagged within will run within all dimensions (provided they add the universal tag).

The vanilla timelines are like so:

  • minecraft:day: The day/night cycle
  • minecraft:moon: The moon phase and spawn chance
  • minecraft:villager_schedule: What Activity a villager performs
  • minecraft:early_game: Stops pillager patrol spawns for the first few days

The associated tags are the following;

  • minecraft:universal
    • minecraft:villager_schedule
  • minecraft:in_overworld - Overworld dimension
    • #minecraft:universal
    • minecraft:day
    • minecraft:moon
    • minecraft:early_game
  • minecraft:in_nether - Nether dimension
    • #minecraft:universal
  • minecraft:in_end - End dimension
    • #minecraft:universal

Keyframes

Each Timeline is made up of keyframes responsible for determining what the argument to the modifier should be at a given tick. These keyframes are then compiled into a list called a KeyframeTrack, baked into a KeyframeTrackSampler when constructing the attribute layers. Every two adjacent keyframes (including the first and last) is considered a KeyframeTrackSampler$Segment. This is what’s used to sample an attribute at a given tick.

Let’s say we have the following (keyframe, value) segment (100, 0) -> (200, 1) and we are currently at tick 150. How do we choose what argument to use? Well, this is performed in two operations. First, we calculate the step: a value between 0 and 1 that determines how much to interpolate the value with. The step is calculated first linearly: (current_tick - start_segment_tick) / (end_segment_tick - start_segment_tick). Then, the step is passed into the desired EasingType, which is a function that takes in a 0-1 value and returns a 0-1 value, such as in_out_bounce or out_back. You can also create your own EasingType like so:

// `EasingType#registerSimple` must be made public
EasyingType.registerSimple(
    // The name of the function
    "examplemod:ease",
    // The function to apply to the value
    // For smooth transitions, the function should map 0 -> 0 and 1 -> 1
    original -> 0.5f * (float) Mth.sin(Math.PI * (3 * original - 0.5)) + 0.5f
);

Then, it passes the step to the AttributeType#keyframeLerp function along with the two arguments to get the lerped argument to apply.

Attribute Tracks

With the keyframes determining the arguments, we apply the arguments to the attribute through an AttributeTrack, baked into an AttributeTrackSampler when constructing the attribute layers. An AttributeTrack contains the KeyframeTrack to get the arguments, and an ArgumentModifier to apply the argument to the value. Note that there can only be one modifier for a given track.

These AttributeTracks are then stored in a map of attributes to tracks, which define our Timeline. The timeline also contains an optional integer indicating the period of the tracks. The ‘period’, in this case, acts as one full run of all tracks in the timeline. Values outside of the period are modulo’d. Most timelines use 24000 for the period as that represents one Minecraft day in ticks.

Custom Timelines

Custom Timelines are added to the timeline datapack registry:

// For some Timeline json
// In `data/examplemod/timeline/example_timeline.json
{
    // Runs for every 3000 ticks (1/8 of a day)
    "period_ticks": 3000,
    "tracks": {
        // The attribute(s) to modify
        "examplemod:example_object_attribute": {
            // The easing function to determine the step between arguments
            "ease": "examplemod:ease",
            // The list of keyframes defining the arguments at set ticks
            // The arguments are then interpolated using the easing function
            // and keyframe lerp
            "keyframes": [
                {
                    // The tick for which this argument is the given value
                    "tick": 1500,
                    // Adds 10 to the attribute
                    "value": 10
                },
                // In-between, uses the easing function to step down between
                // 10 and 0
                {
                    "tick": 2999,
                    // Adds 0 to the attribute
                    "value": 0
                }
                // In-between, uses the easing function to step up between
                // 0 and 10
            ],
            // The modifier to use when applying the argument
            // to the value
            "modifier": "add"
        }
    }
}
  • net.minecraft.client
    • Camera#attributeProbe - Gets the client environment attribute probe for values and interpolation.
    • Minecraft
      • getSituationalMusic now returns Music instead of MusicInfo
      • getMusicVolume - Gets the volume of the background music, or normal volume if the open screen has background music.
  • net.minecraft.client.multiplayer.ClientLevel
    • effects is removed
    • getSkyDarken -> EnvironmentAttributes#SKY_LIGHT_COLOR, SKY_LIGHT_FACTOR; not one-to-one
    • getSkyColor -> EnvironmentAttributes#SKY_COLOR, not one-to-one
    • getCloudColor -> EnvironmentAttributes#CLOUD_COLOR, not one-to-one
    • getStarBrightness -> EnvironmentAttributes#STAR_BRIGHTNESS, not one-to-one
    • getSkyFlashTime is now private
  • net.minecraft.client.renderer
    • DimensionSpecialEffects class is removed, replaced entirely by EnvironmentAttributes
    • SkyRenderer
      • renderSkyDisc now takes in a single ARGB int instead of three RGB floats
      • renderSunMoonAndStars now take in two additional floats for the moon and star rotation
  • net.minecraft.client.renderer.state.SkyRenderState
    • skyType -> skybox, not one-to-one
    • isSunriseOrSunset, timeOfDay are removed
    • moonAngle, starAngle - The angle of the moon and stars.
  • net.minecraft.client.resources.sounds.BiomeAmbientSoundsHandler no longer takes in the BiomeManager
  • net.minecraft.client.sounds
    • MusicInfo -> Minecraft#getSituationalMusic, getMusicVolume; not one-to-one
    • MusicManager#startPlaying now takes in the Music instead of the MusicInfo
  • net.minecraft.core.registries
    • BuiltInRegistries, Registries#ENVIRONMENT_ATTRIBUTE - The registry for the environment attributes.
    • BuiltInRegistries, Registries#ATTRIBUTE_TYPE - The registry for the attribute types.
    • BuiltInRegistires, Registries#SCHEDULE are removed
    • Registries#TIMELINE - The registry key for the timeline.
  • net.minecraft.data.tags.TimelineTagsProvider - The tags provider for the timeline.
  • net.minecraft.server.level.ServerLevel#getMoonBrightness - Returns the brightness of the moon.
  • net.minecraft.sounds.Music#event -> sound
  • net.minecraft.tags.TimelineTags - The tags for the timeline.
  • net.minecraft.util
    • BinaryAnimator$EasingFunction -> EasingType
    • CubicSampler -> GaussianSampler, SpatialAttributeInterpolator; not one-to-one
    • KeyframeTrack - A track of keyframes and the easing performed between them.
    • KeyframeTrackSampler - A keyframe track that replays based on the period, lerping between values using the provided function.
  • net.minecraft.world.attribute
    • AmbientSounds - The sounds that ambiently play within an environment.
    • AttributeRange - An interface meant to validate inputs and sanitize the corresponding value into an appropriate bound.
    • AttributeType - A type definition of the operations and modifications that can be performed by an attribute.
    • AttributeTypes - A registry of all vanilla attribute types.
    • BackgroundMusic - The background music that plays within an environment.
    • BedRule - The rules of how beds function within an environment.
    • EnvironmentAttribute - A definition of some attribute within an environment.
    • EnvironmentAttributeLayer - A layer that modifies a value.
    • EnvironmentAttributeMap - A map of attribute definitions to their argument and modifier.
    • EnvironmentAttributeProbe - The attribute handler for getting and interpolating between values. Used only by the camera.
    • EnvironmentAttributeReader - A reader that can lookup the environment attributes either by dimension or position.
    • EnvironmentAttributes - A registry of all vanilla environment attributes.
    • EnvironmentAttributeSystem - A reader implementation that gets and spatially interpolates environment attributes.
    • LerpFunction - A functional interface that takes in some value between 0-1 along with the start and end values to interpolate between.
    • WeatherAttributes - Attributes maps for applying weather layers.
  • net.minecraft.world.attribute.holder
    • AttributeModifier - A modifier that takes in the attribute value along with some argument (typically a value of the same type) to produce a modified value.
    • BooleanModifier - Modifier for a boolean with a boolean argument.
    • ColorModifier - Modifier for an ARGB integer with some argument, typically integers.
    • FloatModifier - Modifier for a float with some argument, typical floats or a float with an alpha interpolator.
    • FloatWithAlpha - A record containing some value and an alpha typically used for blending.
  • net.minecraft.world.entity.ai.Brain
    • getSchedule is removed
    • setSchedule now takes in an EnvrionmentAttribute<Activity> instead of a Schedule
    • updateActivityFromSchedule now takes in the EnvironmentAttributeSystem and position instead of the day time
  • net.minecraft.world.entity.animal.bee.Bee#isNightOrRaining replaced with EnvironmentAttributes#BEES_STAY_IN_HIVE
  • net.minecraft.world.entity.player.Player$BedSleepingProblem is now a record
    • NOT_POSSIBLE_HERE -> BedRule#EXPLODES
    • NOT_POSSIBLE_NOW -> BedRule#CAN_SLEEP_WHEN_DARK
  • net.minecraft.world.entity.schedule
    • Keyframe -> .minecraft.util.Keyframe, not one-to-one
    • Schedule is removed, its logic replaced by Timeline, Timelines
    • ScheduleBuilder is remvoed, its logic replaced by Timeline$Builder
    • Timeline -> .world.timeline.Timeline, not one-to-one
  • net.minecraft.world.entity.variant.SpawnContext now takes in the EnvironmentAttributeReader
  • net.minecraft.world.level
    • Level
      • isMoonVisible replaced by EnvironmentAttributes#MOON_ANGLE
      • getSunAngle replaced by EnvironmentAttributes#SUN_ANGLE
      • canHaveWeather is now public
    • LevelAccessor now implements LevelReader instead of LevelTimeAccess
    • LevelReader#environmentAttributes - Returns the manager for get the environment attribute within a dimension and its associated biomes.
    • LevelTimeAccess interface is removed
    • MoonPhase
      • CODEC - The codec for the moon phase.
      • PHASE_LENGTH - The number of ticks that a moon phase is present for.
      • startTick - The start tick for a particular phase.
  • net.minecraft.world.level.biome
    • AmbientAdditionsSettings -> .world.attribute.AmbientAdditionsSettings
    • AmbientMoodSettings -> .world.attribute.AmbientMoodSettings
    • AmbientParticleSettings -> .world.attribute.AmbientParticle
    • Biome now takes in the EnvironmentAttributeMap
      • getSkyColor -> EnvironmentAttributes#SKY_COLOR
      • getFogColor -> EnvironmentAttributes#FOG_COLOR
      • getAttributes - Gets the attributes for this biome.
      • getWaterFogColor -> EnvironmentAttributes#WATER_FOG_COLOR
      • getAmbientParticle -> EnvironmentAttributes#AMBIENT_PARTICLES
      • getAmbientLoop -> AmbientSounds#loop environment attribute
      • getAmbientMood -> AmbientSounds#mood environment attribute
      • getAmbientAdditions -> AmbientSounds#additions environment attribute
      • getBackgroundMusic -> EnvironmentAttributes#BACKGROUND_MUSIC
      • getBackgroundMusicVolume -> EnvironmentAttributes#MUSIC_VOLUME
      • $Builder
        • putAttributes - Puts all attributes from another map.
        • setAttribute - Sets an environment attribute.
        • modifyAttribute - Modifies an attribute source for the biome.
    • BiomeSpecialEffects is now a record
      • getFogColor -> EnvironmentAttributes#FOG_COLOR
      • getWaterFogColor -> EnvironmentAttributes#WATER_FOG_COLOR
      • getSkyColor -> EnvironmentAttributes#SKY_COLOR
      • getAmbientParticleSettings -> EnvironmentAttributes#AMBIENT_PARTICLES
      • getAmbientLoopSoundEvent -> AmbientSounds#loop environment attribute
      • getAmbientMoodSettings -> AmbientSounds#mood environment attribute
      • getAmbientAdditionsSettings -> AmbientSounds#additions environment attribute
      • getBackgroundMusic -> EnvironmentAttributes#BACKGROUND_MUSIC
      • getBackgroundMusicVolume -> EnvironmentAttributes#MUSIC_VOLUME
  • net.minecraft.world.level.block
    • BedBlock#canSetSpawn -> BedRule#canSetSpawn environment attribute
    • CreakingHeartBlock#isNaturalNight replaced by EnvironmentAttributes#CREAKING_ACTIVE
    • RespawnAnchorBlock#canSetSpawn now takes in the ServerLevel and BlockPos
  • net.minecraft.world.level.dimension
    • BuiltinDimensionTypes#*_EFFECTS are removed
    • DimensionDefaults#OVERWORLD_CLOUD_HEIGHT is now a float
    • DimensionType
      • fixedTime -> hasFixedTime, now a boolean instead of a OptionalLong
      • natural, effectsLocation are removed
      • skybox - The skybox to display within the dimension.
      • cardinalLightType - The type of light permeating through a dimension.
      • timelines - A set of timelines that modify the environment attributes of this dimension.
      • ultraWarm -> EnvironmentAttributes#WATER_EVAPORATES, FAST_LAVA, DEFAULT_DRIPSTONE_PARTICLE
      • bedWorks -> EnvironmentAttributes#BED_RULE
      • respawnAnchorWorks -> EnvironmentAttributes#RESPAWN_ANCHOR_WORKS
      • cloudHeight -> EnvironmentAttributes#CLOUD_HEIGHT
      • attribute - Gets the attributes for this dimension.
      • piglinSafe, $MonsterSettings#piglinSafe -> EnvironmentAttributes#PIGLINS_ZOMBIFY
      • hasRaids, $MonsterSettings#hasRaids -> EnvironmentAttributes#CAN_START_RAID
      • timeOfDay is removed
      • moonPhase replaced by EnvironmentAttributes#MOON_PHASE
      • hasEndFlashes - Returns whether the skybox is the end.
      • $CardinalLightType - The light permeating through a dimension.
      • $Skybox - The skybox of a dimension.
  • net.minecraft.world.level.material.FogType#DIMENSION_OR_BOSS is removed
  • net.minecraft.world.timeline
    • AttributeTrack - A track that applies the attribute modifier with the argument sampled from the given keyframe track.
    • AttributeTrackSampler - A baked attribute track.
    • Timeline - A map of attributes to tracks that are applied based on the given time in ticks modulo the period.
    • Timelines - All vanilla timelines.

The Game Rule Shuffle

The gamerule system has been overhauled to a degree, allowing its keys to be stored as proper registry objects while still having its values limited to either integers or booleans. Most of the classes are basically just combinations of others.

Existing Game Rules

Existing game rules are still in a GameRules class, just moved to a different location. Their fields have been renamed and seem to follow some basic rules:

  1. Rules no longer have the RULE_ prefix
  2. Rules now have underscores separating words
  3. The DO prefix is removed from rule names (e.g. RULE_DOENTITYDROPS -> ENTITY_DROPS)
  4. The SPAWNING suffix has been replaced with the SPAWN_ prefix (e.g. RULE_DOMOBSPAWNING -> SPAWN_MOBS)
  5. The DISABLE prefix is removed, meaning that their values are inverted (e.g., RULE_DISABLERAIDS -> RAIDS)

While there are some edge cases, searching for a specific word in the previous game rule name will most likely lead you to the new name (e.g., searching for ADVANCEMENT in RULE_ANNOUNCEADVANCEMENTS leads to SHOW_ADVANCEMENT_MESSAGES).

To actually get a value from the game rules, you would use GameRules#get instead of the previous getBoolean and getInteger. The type is obtained from the generic on the registered GameRule.

// With ServerLevel level
boolean fallDamage = level.getGameRules().get(GameRules.FALL_DAMAGE);

Additionally, setting the game rule is now simplified to calling GameRules#set – taking in the GameRule, value, and the current server if the changes are propogated through MinecraftServer#onGameRuleChanged, which it should generally be.

// With ServerLevel level
level.getGameRules().set(GameRules.FALL_DAMAGE, false, level.getServer());

Creating a Game Rule

Game rules are created through the GameRule class, which is basically a type definition of how the game rule functions depending on its caller. Its generic represents the type of the value being held. The only hardcoded concepts that separate this from being a general type is that the actual arguments can be limited to a specific range, and that they store the default value. Otherwise, the fields are mostly the same from its previous counterparts in GameRules$Type and GameRules$Key.

Then, once created, the GameRule must be statically registered to BuiltInRegistries#GAME_RULE

public static final GameRule<Integer> EXAMPLE_RULE = Registry.register(
    BuiltInRegistries.GAME_RULE
    Identifier.withNamespaceAndPath("examplemod", "example_rule"),
    new GameRule(
        // The category that best represents the game rule.
        // This is only used by the edit game rule screen
        // when first constructing the world.
        // A custom category can be created by calling
        // `GameRuleCategory#register` or just its constructor
        // as the sort order goes unused
        GameRuleCategory.register(
            Identifier.withNamespaceAndPath("examplemod", "example_category")
        ),
        // The type of the game rule, represenative of the
        // JSON schema version of the generic.
        // This is only used by the management system for
        // checking an untyped rule.
        GameRuleType.INT,
        // The argument type used for serializing the value
        // in commands.
        // This can be range-limited based on the constructor.
        IntegerArgumentType.integer(0, 5),
        // A caller that runs typically during the visiting process
        // for each game rule.
        // This caller is only used by the edit game rules screen
        // for adding the correct component that modifies the value.
        // `GameRuleTypeVisitor#visit` should not be used here
        // as the visitor already calls that function.
        GameRuleTypeVisitor::visitInteger,
        // The codec used to serialize the game rules to disk
        // or for the managment service.
        // This can be range-limited based on the constructor.
        Codec.intRange(0, 5),
        // A function that maps the set value to an integer
        // result used when setting or querying the game rule
        // via a command.
        // This is the only case when a result of `0` does not
        // mean the command has failed.
        gameRuleValue -> gameRuleValue,
        // The default value to set for this rule.
        3,
        // A feature flag set that are required for this game rule
        // to be enabled in game.
        // An empty flag set means it should be enabled at all times.
        FeatureFlagSet.of()
    )
);

net.minecraft.client.gui.screens.worldselection - EditGameRulesScreen - $BooleanRuleEntry now takes in a GameRule<Boolean> instead of a GameRules$BooleanValue - $EntryFactory no longer bounds its generic - $IntegerRuleEntry now takes in a GameRule<Integer> instead of a GameRules$IntegerValue - InitialWorldCreationOptions#disabledGameRules is now a GameRuleMap

  • net.minecraft.core.registries.BuiltInRegistries#GAME_RULE, Registries#GAME_RULE - Game rule registry.
  • net.minecraft.gametest.framework.TestEnvironmentDefinition
    • $SetGameRules now takes in a GameRulesMap instead of $Entrys
      • entry, $Entry are removed
  • net.minecraft.server.MinecraftServer#onGameRuleChanged now takes in the GameRule and value instead of the string key and $Value wrapper
  • net.minecraft.server.jsonrpc.api.Schema
    • RULE_TYPE_SCHEMA is now a GameRuleType instead of a GameRulesService$RuleType
    • TYPED_GAME_RULE_SCHEMA is now a GameRulesService$GameRuleUpdate instead of a GameRulesService$TypedRule
    • UNTYPED_GAME_RULE_SCHEMA is now a GameRulesService$GameRuleUpdate instead of a GameRulesService$UntypedRule
  • net.minecraft.server.jsonrpc.internalapi
    • GameRules interface is removed
    • MinecraftGameRuleService#getRule -> getRuleValue
  • net.minecraft.server.jsonrpc.methods.GameRulesService
    • $RuleType is removed
    • $TypedRule, $UntypedRule -> $GameRuleUpdate, not one-to-one
  • net.minecraft.server.notifications.NotificationService#onGameRuleChanged now takes in the GameRule and value instead of the string key and $Value wrapper
  • net.minecraft.world.level.GameRules
    • The static rule keys are now located in .gamerules.GameRules without the RULE_ prefix and underscores in-between words
      • DO is removed from the name (e.g. RULE_DOENTITYDROPS -> ENTITY_DROPS)
      • SPAWNING names now start with SPAWN_ (e.g. RULE_DOMOBSPAWNING -> SPAWN_MOBS)
    • The map behavior linking the key to its associated value is now handled by GameRuleMap
      • getBoolean, getInteger -> get
    • $Key, $Type -> GameRule, not one-to-one
      • GameRule implements FeatureElement
    • $Category -> GameRuleCategory, not one-to-one
    • $Value, $BooleanValue, $IntegerValue are removed, replaced with the direct object being wrapped
    • $GameRuleTypeVisitor -> GameRuleTypeVisitor

Minor Migrations

The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.

Usage Annotations

Mojang has recently given some integer values and flags an annotation, marking its intended usage. This does not affect modders in any way, as it likely seems to be a way to perform static analysis on the values passed around, probably for some kind of validation.

  • com.mojang.blaze3d.buffers.GpuBuffer$Usage - An annotation that marks whether a given integer defines the usage flags of the particular buffer.
  • com.mojang.blaze3d.platform.InputConstants$Value - An annotation that marks whether a given integer defines the input of a device.
  • com.mojang.blaze3d.buffers.GpuTexture$Usage - An annotation that marks whether a given integer defines the usage flags of the particular texture.
  • net.minecraft.client.input
    • InputWithModifiers$Modifiers - An annotation that marks whether a given integer defines the modifiers of an input.
    • KeyEvent$Action - An annotation that marks whether a given integer defines the action being performed by the input (i.e., press, release, repeat).
    • MouseButtonInfo
      • $Action - An annotation that marks whether a given integer defines the action being performed by the mouse (i.e., press, release, repeat).
      • $MouseButton - An annotation that marks whether a given integer defines the input of a mouse.
  • net.minecraft.server.level.TicketType$Flags - An annotation that marks whether a given integer defines the flags of a ticket type.
  • net.minecraft.world.level.block.Block$UpdateFlags - An annotation that marks whether a given integer defines the flags for a block update.

Text Collectors

ActiveTextCollector is a method of submitting strings and components to render, meant to provide common utilities for alignment, especially with text that goes off the screen. While this does not necessarily replace GuiGraphics#drawString, a few widgets require the use of the ActiveTextCollector, such as AbstractStringWidget#renderLines.

An ActiveTextCollector can be created by calling one of the GuiRenderer#textRenderer* methods. They take in a $HoveredTextEffects, which handles how to render the component hover and click event, and a Style consumer callback for any additional handling. It also stores a set of default parameters, which basically represent the current pose opacity and screen rectangle.

There are two methods two submit a piece of text for rendering: accept for standard strings, and acceptScrolling* for screens that go out of the rectangle, scrolling back and forth on the screen at a rate of roughly one unit per second (see the accessibility settings for an example). accept takes in, at most, five parameters: the alignment of the X position (TextAlignment#LEFT is like normal, CENTER the center of the text, RIGHT the end of the text), the X position for the alignment, Y position, parameters to override, and the text. acceptScrolling takes in, at most, seven parameters: the text, the starting X position center aligned, the leftmost X position, the rightmost X position, the topmost Y position, the bottommost Y position, and the parameters to override.

// In some method with GuiGraphics graphics
ActiveTextCollector collector = graphics.textRenderer(
    // Render hover and click events
    HoveredTextEffects.TOOLTIP_AND_CURSOR;
);

collector.accept(
    // Align the text to the center
    TextAlignment.CENTER,
    // Start X (in this case the center position)
    20,
    // Start Y
    0,
    // The parameters to use
    collector.defaultParameters(),
    // The text to display
    Component.literal("Hello world!")
);
  • net.minecraft.client.gui
    • ActiveTextCollector - A helper for rendering text with certain parameters and alignments.
    • GuiGraphics now takes in the mouse XY
      • textRenderer* - Methods for constructing the helper for submit text in their appropriate location.
      • $HoveredTextEffects - An enum that defines the text effects to apply when using the text collector.
  • net.minecraft.client.gui.components
    • AbstractButton now extends AbstractWidget$WithInactiveMessage instead of AbstractWidget
      • renderWidget is now final
        • Use renderContents instead to submit elements
        • renderDefaultSprite should be called in renderContents to blit the default sprite
      • renderString -> renderDefaultLabel, not one-to-one
    • AbstractSliderButton now extends AbstractWidget$WithInactiveMessage instead of AbstractWidget
    • AbstractStringWidget
      • visitLines - Handles submitting text elements to the screen.
      • setColor, getColor are removed
        • Use the ActiveTextCollector in visitLines instead
      • setComponentClickHandler - Set the handler for when a component with the provided style is clicked.
    • AbstractWidget
      • renderScrollingString -> renderScrollingStringOverContents, not one-to-one
      • getAlpha - Gets the alpha of the widget.
      • $WithInactiveMessage - A widget that can change the message to display when inactive.
    • Button is now abstract
      • $Plain replicates the previous behavior
    • ChatComponent
      • MESSAGE_BOTTOM_TO_MESSAGE_TOP - The height of a chat component.
      • render now takes in a Font and a boolean for whether to change the curse on insertions
      • captureClickableText - Captures the clickable text to submit.
      • handleChatQueueClicked replaced by QUEUE_EXPAND_ID, not one-to-one
      • getClickedComponentStyleAt -> $ChatGraphicsAccess#handleMessage, not one-to-one
      • getMessageTagAt -> $ChatGraphicsAccess#handleTag, handleTagIcon; not one-to-one
      • getWidth, getHeight, getScale are now private
      • $AlphaCalculator - Calculates the alpha for a given chat line.
      • $ChatGraphicsAccess - An interface for handling the submission of the chat input.
      • $LineConsumer no longer takes in the first three ints
    • FittingMultilineTextWidget#setColor is removed
      • Use the ActiveTextCollector in visitLines instead
    • MultiLineLabel
      • render, getStyle -> visitLines, not one-to-one
      • $Align -> TextAlignment
    • MultiLineTextWidget#setColor, configureStyleHandling are removed
      • Use the ActiveTextCollector in visitLines instead
    • SplashRenderer now takes in a Component instead of a String
    • SpriteIconButton#renderSprite - Submits the sprite icon.
    • StringWidget#setColor is removed
      • Use the ActiveTextCollector in visitLines instead
    • TabButton now extends AbstractWidget$WithInactiveMessage instead of AbstractWidget
      • renderString -> renderLabel, now private, not one-to-one
  • net.minecraft.client.gui.screens.inventory.BookViewScreen#getClickedComponentStyleAt -> visitText, now private, not one-to-one

Shared Text Areas Debugger

A new debug has been added that draws the bounding box each glyph, including the empty glyph. The color shifts slightly between each glyph for ease of differentiation, and changes entirely depending on if there is some combination of a click or hover event.

  • net.minecraft.SharedConstants#DEBUG_ACTIVE_TEXT_AREAS - A flag for the debugger drawing the bounds and effects of each glyph.
  • net.minecraft.client.gui.Font
    • prepareText now has an overload of whether to render something in the empty areas
    • $GlyphVisitor
      • acceptGlyph now takes in a TextRenderable$Styled instead of a TextRenderable
      • acceptEmptyArea - Accepts an empty area to draw to the screen.
    • $PreparedTextBuilder now takes in whether to include the empty areas for rendering
  • net.minecraft.client.gui.font
    • ActiveArea - Defines the bounds and style of the area to draw.
    • EmptyArea - An area with nothing within it.
    • PlainTextRenderable now implements TextRenderable$Styled instead of TextRenderable
      • width, height, ascent - The bounds of the object.
    • TextRenderable$Styled - A text renderable that defines some active area for its bounds.
  • net.minecraft.client.gui.font.glyphs.BakedGlyph#createGlyph now returns a TextRenderable$Styled

JSpecify Annotations

Mojang has moved from using a mix of their own annotations to those available in JSpecify when required. As such, instead of all fields, methods, and parameters being marked as nonnull by default, it is replaced by NullMarked, which considers a type usage non-null unless explictly annotated as Nullable, barring some special cases.

  • com.mojang.blaze3d.FieldsAreNonnullByDefault, MethodsReturnNonnullByDefault are removed
  • com.mojang.math.FieldsAreNonnullByDefault, MethodsReturnNonnullByDefault are removed
  • net.minecraft.FieldsAreNonnullByDefault, MethodsReturnNonnullByDefault are removed

Slot Sources

Slot sources are an expansion upon the previous contents drop system in shulker boxes allowing any loot table to pulls its entries from some container slots. This can be used in any location where a LootContext is enabled, though it is currently only implemented as a loot pool entry.

In vanilla, a slot source works by having some LootContextArg, which points to some loot context param value, return an object that implements SlotProvider. Currently, this refers to any Container or Entity implementation. The SlotProvider is then used by SlotSource#provide to construct a SlotCollection: a stream of deep copied ItemStacks. The stacks stored in the collection are then passed to the output of the pool. As this is all done in one of the SlotSource#provide implementations, it can reference anything (not just SlotProvider) as long as it can transform that data into the SlotCollection.

// A slot source whose 'slots' are the elements
// within an item tag.
public record TagSlotSource(TagKey<Item> tag) implements SlotSource {

    public static final MapCodec<TagSlotSource> MAP_CODEC = TagKey.codec(Registries.ITEM)
        .fieldOf("tag").xmap(TagSlotSource::new, TagSlotSource::tag);
    
    @Override
    public SlotCollection provide(LootContext ctx) {
        // Get the holder set for the tag
        Optional<HolderSet.Named<Item>> holderSetOpt = ctx.getResolver()
            .lookup(Registries.ITEM).flatMap(getter -> getter.get(this.tag));
        
        // Stream the elements and map to a SlotCollection
        return holderSetOpt.map(holderSet ->
            // `Item#getDefaultInstance` returns a new copy, so it can be used.
            // If the ItemStack already exists, then `ItemStack#copy` should be
            // called on each.
            (SlotCollection) () -> holderSet.stream().map(holder -> holder.value().getDefaultInstance())
        ).orElse(SlotCollection.EMPTY);
    }

    @Override
    public MapCodec<? extends SlotSource> codec() {
        // The codec used to serialize the slot source
        return MAP_CODEC;
    }
}

// The map codec needs to be registered to the slot source type registry
Registry.register(
    BuiltInRegistries.SLOT_SOURCE_TYPE
    Identifier.withNamespaceAndPath("examplemod", "tag"),
    TagSlotSource.MAP_CODEC
);
// An example loot table
{
    // ...
    "pools": [
        {
            "rolls": 1.0,
            "bonus_rolls": 0.0,
            "entries": [
                {
                    // Use the slot source loot pool
                    "type": "minecraft:slots",
                    "slot_source": {
                        // Our slot source
                        "type": "examplemod:tag",
                        "tag": "minecraft:planks"
                    }
                }
            ]
        }
        // ...
    ]
}
  • net.minecraft.advancements.criterion.SlotsPredicate#matches now takes in a SlotProvider instead of an Entity
  • net.minecraft.core.registries.BuiltInRegistries#SLOT_SOURCE_TYPE, Registries#SLOT_SOURCE_TYPE - Slot source type registry.
  • net.minecraft.world.Container now extends SlotProvider
    • getSlot - Gets an access for a single item.
  • net.minecraft.world.entity
    • Entity now implements SlotProvider
    • SlotAccess
      • NULL is removed
      • forContainer -> forListElement, not one-to-one
    • SlotProvider - An object that provides some access to its internal storage via slots.
  • net.minecraft.world.item.slot
    • CompositeSlotSource - A composite of multiple slot sources.
    • ContentsSlotSource - Gets the slot contents.
    • EmptySlotSource - An empty slot source.
    • FilteredSlotSource - Filters the provided slot source pased on the item predicate.
    • GroupSlotSource - Groups multiple slot sources together into one concatenated collection.
    • LimitSlotSource - Limits the provided slot source to a maximum size.
    • RangeSlotSource - Gets the desired range of slots.
    • SlotCollection - A collection of slots to grab the item copies from.
    • SlotSource - Given a loot context, returns a collection of slots to provide.
    • SlotSources - The slot sources provided by vanilla.
    • TransformedSlotSource - Transforms the provided slot source.
  • net.minecraft.world.level.storage.loot.ContainerComponentManipulator#getSlots - Gets the slots of a data component on the stack.
  • net.minecraft.world.level.storage.loot.entries
    • LootPoolEntries#SLOTS - A pool that uses slots from a source.
    • SlotLoot - A pool that gets its items from some slot source.

Zombie Nautilus Variant

Zombie nautilus are the newest addition to the variant datapack registry objects, taking in the familiar model and texture override along with the spawn conditions:

// A file located at:
// - `data/examplemod/zombie_nautilus_variant/example_zombie_nautilus.json`
{
    // Points to a texture at `assets/examplemod/textures/entity/nautilus/example_zombie_nautilus.png`
    "asset_id": "examplemod:entity/nautilus/example_zombie_nautilus",
    // Defines the `ZombieNautilusVariant$ModelType` that's used to select what entity model to render the zombie nautilus variant with
    "model": "warm",
    "spawn_conditions": [
        // The conditions for this variant to spawn
        {
            "priority": 0
        }
    ]
}
  • net.minecraft.core.component.DataComponents#ZOMBIE_NAUTILUS_VARIANT - The variant of the zombie nautilus.
  • net.minecraft.core.registries.Registries#ZOMBIE_NAUTILUS_VARIANT - The registry key for the zombie nautilus variant.
  • net.minecraft.network.syncher.EntityDataSerializers#ZOMBIE_NAUTILUS_VARIANT - The variant of the zombie nautilus.
  • net.minecraft.world.entity.animal.nautilus
    • ZombieNautilusVariant - A variant of a zombie nautilus.
    • ZombieNautilusVariants - All vanilla zombie nautilus variants.

OptionEnum Removal

OptionEnum has been removed in favor of simply calling the OptionInstance$Enum constructor with the desired values and codec. As such, most byId methods have been replaced with some codec and the translatable entry is now stored as a Component than the translation key string.

  • net.minecraft.client
    • AttackIndicatorStatus no longer implements OptionEnum
      • byId -> LEGACY_CODEC, not one-to-one
      • getKey -> caption, not one-to-one
    • CloudStatus no longer implements OptionEnum
      • getKey -> caption, not one-to-one
    • InactivityFpsLimit no longer implements OptionEnum
      • getKey -> caption, not one-to-one
    • OptionInstance#forOptionEnum is removed
    • PrioritizeChunkUpdate no longer implements OptionEnum
      • getKey -> caption, not one-to-one
      • byId -> LEGACY_CODEC, not one-to-one
  • net.minecraft.client.sounds.MusicManager$MusicFrequency no longer implements OptionEnum
    • getKey -> caption, not one-to-one
  • net.minecraft.server.level.ParticleStatus no longer implements OptionEnum
    • getKey -> caption, not one-to-one
    • byId -> LEGACY_CODEC, not one-to-one
  • net.minecraft.util.OptionEnum is removed
  • net.minecraft.world.entity.HumanoidArm no longer implements OptionEnum
    • BY_ID is now private
    • getKey -> caption, not one-to-one
  • net.minecraft.world.entity.player.ChatVisbility no longer implements OptionEnum
    • byId -> LEGACY_CODEC, not one-to-one
    • getKey -> caption, not one-to-one

Specific Logic Changes

  • net.minecraft.client.renderer.entity.EntityRenderState#lightCoords now defaults to 0xF000F0.
  • net.minecraft.client.gui.screens.inventory.AbstractContainerScreen#keyPressed no longer returns true if the key is not handled by the screen, instead returning false.
  • net.minecraft.util.Mth#clampedLerp parameters have been reordered for both overloads. The methods now take in the step, the original value, and the next value; instead of the original value, next value, and the step value.

Tag Changes

  • minecraft:biome
    • plays_underwater_music is removed
      • Replaced by BackgroundMusic#underwaterMusic environment attribute
    • has_closer_water_fog is removed
      • Replaced by EnvironmentAttributes#WATER_FOG_END_DISTANCE
    • increased_fire_burnout is removed
      • Replaced by EnvironmentAttributes#INCREASED_FIRE_BURNOUT
    • snow_golem_melts is removed
      • Replaced by EnvironmentAttributes#SNOW_GOLEM_MELTS
    • without_patrol_spawns is removed
      • Replaced by EnvironmentAttributes#CAN_PILLAGER_PATROL_SPAWN
    • spawns_coral_variant_zombie_nautilus
  • minecraft:block
    • can_glide_through
  • minecraft:entity_type
    • burn_in_daylight
    • can_float_while_ridden
    • can_wear_nautilus_armor
    • nautilus_hostiles
  • minecraft:item
    • camel_husk_food
    • zombie_horse_food
    • nautilus_bucket_food
    • nautilus_food
    • nautilus_taming_items
    • spears
    • enchantable/lunge
    • enchantable/sword -> enchantable/melee_weapon, enchantable/sweeping
  • minecraft:timeline
    • universal
    • in_overworld
    • in_nether
    • in_end

List of Additions

  • com.mojang.blaze3d.GraphicsWorkarounds#isAmd - Whether the GPU’s vendor is AMD.
  • com.mojang.blaze3d.opengl
    • GlConst#GL_POINTS - Defines the points primitive as the type to render.
    • GlTimerQuery - The OpenGL implementation of querying an object, typically the time elapsed.
  • com.mojang.blaze3d.platform.InputConstants#MOUSE_BUTTON_* - The inputs of a mouse click, represented by numbers as they may have different intended purposes.
  • com.mojang.blaze3d.systems
    • CommandEncoder#timerQueryBegin, timerQueryEnd - Handlers for keeping track of the time elapsed.
    • GpuQuery - A query for an arbitrary object, such as the time elapsed.
  • com.mojang.blaze3d.vertex
    • DefaultVertexFormat
      • POSITION_COLOR_LINE_WIDTH - A vertex format that specifies the position, color, and line width.
      • POSITION_COLOR_NORMAL_LINE_WIDTH - A vertex format that specifies the position, color, normal, and line width.
    • VertexFormat$Mode#POINTS - A vertex mode that draws points.
    • VertexFormatElement#LINE_WIDTH - A vertex element that takes in one float representing the width.
  • com.mojang.math
    • OctahedralGroup
      • BLOCK_ROT_* - Constants representing the block rotations.
      • permutation - Returns the symmetric group.
    • Quadrant#fromXYZAngles - Gets the octahedral group that represents the three quadrant rotations.
    • SymmetricGroup3#inverse - Returns the inverse group.
  • net.minecraft
    • SharedConstants
      • MAX_CLOUD_DISTANCE - The maximum cloud range to be rendered by the player.
      • DEFAULT_RANDOM_TICK_SPEED - The default random tick speed.
    • Util#localizedDateFormatter - Returns the localized DateTimeFormatter for the given style.
  • net.minecraft.advancements.criterion
    • DataComponentMatchers$Builder#any - Matches whether there exists some data for the component.
    • SpearMobsTrigger - A trigger that checks the number of entities the player has speared with a kinetic weapon.
  • net.minecraft.client
    • GuiMessage
      • splitLines - Splits the component into lines with the desired width.
      • getTagIconLeft - Gets the width of the content with an additional four pixel padding.
    • KeyMapping$Category#DEBUG - The debug keyboard category.
    • MusicToastDisplayState - An enum representing how the toast for music should be displayed.
    • NarratorStatus#LEGACY_CODEC - A codec to deserialize the enum narrator status.
    • OptionInstance
      • $IntRangeBase
        • next - Gets the next value.
        • previous - Gets the previous value.
      • $SliderableEnum - A slider that selects between enum options.
      • $SliderableValueSet
        • next - Gets the next value.
        • previous - Gets the previous value.
    • Options
      • keyToggleGui - A key mapping that toggles the in-game gui.
      • keyToggleSpectatorShaderEffects - A key mapping that toggles the shader effects tied to a camera entity.
      • keyDebug*, debugKeys - Key mappings for the debug renderers.
      • weatherRadius - Returns the radius of the weather particles to render in an area.
      • cutoutLeaves - Whether leaves should render in cutout or solid.
      • vignette - Whether a vignette should be applied to the screen.
      • improvedTransparency - Whether to use the transparency post processor.
      • chunkSectionFadeInTime - The amount of second that should be taken for a chunk to fade in when first rendered.
      • maxAnisotropyBit - The bit value of the anisotrophic filtering level.
      • maxAnisotropyValue - The ansiotrophic filtering level.
  • net.minecraft.client.animation.definitions.NautilusAnimation - The animation definitions for the nautilus.
  • net.minecraft.client.data.models.ItemModelGenerators
    • generateSpear - Generates the spear item model.
    • generateItemWithTintedBaseLayer - Generates a two layered item model whose base layer is tinted.
  • net.minecraft.client.data.models.model.ModelTemplates#SPEAR_IN_HAND - A template for the spear in hand model.
  • net.minecraft.client.gui.components
    • AbstractButton#setOverrideRenderHighlightedSprite - Overrides whether to use the focused enabled/disabled sprite.
    • Checkbox#adjustWidth - Sets the width of the widget using the message, font, and its initial X position.
    • CycleButton
      • $Builder#withSprite - Sets the supplier used to get the sprite based on the current button state.
      • $DisplayState - How the button shoud be displayed.
      • $SpriteSupplier - Gets the sprite location given the current button state.
    • EditBox#setInvertHighlightedTextColor - Sets whether to invert the highlighted text color.
    • FocusableTextWidget
      • getPadding - Returns the text padding.
      • updateWidth - Updates the width the text can take up.
      • updateHeight - Update the height the text can take up.
      • $Builder - Builds the component.
    • MultiLineTextWidget#getTextX, getTextY - Gets the text position.
    • OptionsList
      • addHeader - Adds a header entry.
      • resetOption - Resets the option value.
      • $AbstractEntry - Defines the element within the selection list.
      • $HeaderEntry - An entry that represents the header of a section.
      • $OptionInstanceWidget - A record containing the widget and optionally the option instance.
    • ResettableOptionWidget - A widget that can reset its value to a default.
    • SelectableEntry - A utility for checking whether the mouse is in a specific region.
  • net.minecraft.client.gui.layouts.HeaderAndFooterLayout#MAGIC_PADDING - A common padding between the elements.
  • net.minecraft.client.gui.screens.advancements
    • AdvancementTab#canScrollHorizontally, canScrollVertically - Checks whether the tab data can be scrolled in a given direction.
    • AdvancementTabType#getWidth, getHeight - Gets the width / height of the tab.
  • net.minecraft.client.gui.screens.debug.DebugOptionsScreen#getOptionList - Returns the list of options for the debug screen.
  • net.minecraft.client.gui.screens.inventory
    • AbstractMountInventoryScreen - A screen representing a mount’s inventory.
    • EffectsInInventory
      • SPACING - The spacing between effects.
      • SPRITE_SQUARE_SIZE - The size of the effect icon.
    • NautilusInventoryScreen - The screen for the nautilus inventory.
  • net.minecraft.client.gui.screens.options
    • OptionsSubScreen#resetOption - Resets the option value to its default.
    • VideoSettingsScreen#updateTransparencyButton - Sets the transparency button to the current option value.
  • net.minecraft.client.gui.screens.packs.TransferableSelectionList$PackEntry#ICON_SIZE - The size of the pack icon.
  • net.minecraft.client.gui.screens.recipebook.RecipeBookTabButton#select, unselect - Handles tab display selection.
  • net.minecraft.client.input.InputQuirks#EDIT_SHORTCUT_KEY_LEFT, EDIT_SHORTCUT_KEY_RIGHT -> InputWithModifiers#hasControlDownWithQuirk, not one-to-one
  • net.minecraft.client.model.HumanoidModel$ArmPose
    • SPEAR - The spear third person arm pose.
    • animateUseItem - Modifies the PoseStack given the entity state, use time, arm, and stack.
    • affectsOffhandPose - Whether the arm animation will affect the offhand pose.
  • net.minecraft.client.model.animal.nautilus
    • NautilusArmorModel - The armor model for a nautilus.
    • NautilusModel - The model for a nautilus.
    • NautilusSaddleModel - The saddle model for a nautilus.
  • net.minecraft.client.model.effects.SpearAnimations - The animations performed when using a spear.
  • net.minecraft.client.model.geom
    • ModelLayers
      • *NAUTILUS* - The model layers for the nautilus.
      • UNDEAD_HORSE*_ARMOR - The armor model layers for the undead horse.
    • PartName
      • INNER_MOUTH, LOWER_MOUTH - Part names for a mouth.
      • SHELL - Part name for a shell.
      • *_CORAL* - Part names for the corals on a zombie nautilus.
  • net.minecraft.client.model.geom.builders.UVPair#pack, unpack* - Handles packing/unpacking of a UV into a long.
  • net.minecraft.client.model.monster.nautilus.ZombieNautilusCoralModel - The model for the warm variant of a zombie nautilus.
  • net.minecraft.client.model.monster.skeleton.SkeletonModel#createSingleModelDualBodyLayer - Creates a parched layer definition.
  • net.minecraft.client.multiplayer
    • ClientPacketListener#hasClientLoaded - Whether the client is loaded.
    • MultiPlayerGameMode#piercingAttack - Initiates a lunging attack.
  • net.minecraft.client.player.LocalPlayer#raycastHitResult - Gets the hit result for the camera entity for the given partial tick.
  • net.minecraft.client.renderer
    • DynamicUniforms
      • CHUNK_SECTION_UBO_SIZE - The uniform buffer object size for the chunk section.
      • writeChunkSections - Writes a varargs of chunk sections to the uniform storage.
      • $ChunkSectionInfo - The dynamic uniform for the chunk section.
    • GameRenderer
      • updateCamera - Calls the setup function for the camera.
      • getPanoramicScreenshotParameters - Get the screenshot parameters for panoramic mode.
    • PanoramicScreenshotParameters - The screenshot parameters for panoramic mode.
    • Sheets#CELESTIAL_SHEET - The atlas for the celestial textures.
  • net.minecraft.client.renderer.blockentity.BlockEntityWithBoundingBoxRenderer#STRUCTURE_VOIDS_COLOR - The void color for a structure.
  • net.minecraft.client.renderer.chunk.SectionRenderDispatcher$RenderSection
    • getVisibility - Returns the current alpha of the chunk.
    • setFadeDuration - Sets the amount of time it should take for a chunk to fade in.
    • setWasPreviouslyEmpty, wasPreviouslyEmpty - Handles whether the section did not previously exist.
  • net.minecraft.client.renderer.entity
    • CamelHuskRenderer - The entity renderer for a camel husk.
    • CamelRenderer#createCamelSaddleLayer - Creates the saddle layer for the camel.
    • NautilusRenderer - The entity renderer for a nautilus.
    • ParchedRenderer - The entity renderer for a parched.
    • ZombieNautilusRenderer - The entity renderer for a zombie nautilus.
  • net.minecraft.client.renderer.entity.state
    • ArmedEntityRenderState
      • swingAnimationType - The animation to play when swinging their hand.
      • ticksUsingItem - How many ticks the item has been used for.
      • getUseItemStackForArm - Returns the held item stack based on the arm.
    • LivingEntityRenderState#ticksSinceKineticHitFeedback - The amount of ticks since this entity was hit with a kinetic weapon.
    • NautilusRenderState - The entity render state of a nautilus.
    • UndeadRenderState - The entity render state for an undead humanoid.
  • net.minecraft.client.renderer.item.ItemModelResolver#swapAnimationScale - Gets the scale of the swap animation for the stack.
  • net.minecraft.client.renderer.state.LevelRenderState#gameTime - The current game time.
  • net.minecraft.client.resources.SplashManager component fields - The components for the special messages.
  • net.minecraft.client.resources.model
    • BlockModelRotation#IDENTITY - The identity rotation.
    • EquipmentClientInfo#NAUTILUS_* - The layers for the nautilus.
  • net.minecraft.core.Vec3i
    • multiply - Multiplies each component with a provided scalar.
    • toMutable - Returns a mutable Vector3i.
  • net.minecraft.data.AtlasIds#CELESTIAL_SHEET - The atlas for the celestial textures.
  • net.minecraft.data.recipes.RecipeProvider#waxedChiseled - The recipe for a waxed chiseled block.
  • net.minecraft.gametest.framework.GameTestHelper#getAbsoluteDirection - Returns the absolute direction from the test relative direction.
  • net.minecraft.nbt.NbtAccounter
    • defaultQuota - An accounter with a maximum of 2 MiB allocated.
    • uncompressedQuota - An accounter with a maximum of 100 MiB allocated.
  • net.minecraft.network.chat.MutableComponent#withoutShadow, Style#withoutShadow - Removes the drop shadow from the text.
  • net.minecraft.network.protocol.game.ServerboundPlayerActionPacket$Action#STAB - The player performed the stab action.
  • net.minecraft.network.syncher.EntityDataSerializers#HUMANOID_ARM - The main hand of the humanoid.
  • net.minecraft.resources.Identifier#toShortString - Returns the string of the location. Namespace is omitted if minecraft.
  • net.minecraft.server
    • MinecraftServer
      • getServerActivityMonitor - Returns the monitor that sends the server activity notification.
      • getStopwatches - Returns a map of ids to timers.
    • ServerScoreboard#storeToSaveDataIfDirty - Writes the data if dirty.
  • net.minecraft.server.commands.StopwatchCommand - A command that starts or stops a stopwatch.
  • net.minecraft.server.dedicated.DedicatedServerProperties#managementServerAllowedOrigins - The origins a request from the management server can come from.
  • net.minecraft.server.jsonrpc.OutgoingRpcMethods#SERVER_ACTIVITY_OCCURRED - A request made from the minecraft server about server activity occurring.
  • net.minecraft.server.jsonrpc.api.Schema
    • BOOL_OR_INT_SCHEMA - A schema for a field that can be either a boolean or integer.
    • typedCodec - Returns the codec for the schema.
    • info - Returns a copy of the schema.
  • net.minecraft.server.level
    • ChunkMap#getChunkDataFixContextTag - Returns the datafix tag for the chunk data.
    • ServerLevel
      • getDayCount - Gets the number of days that has passed.
      • canSpreadFireAround - Whether fire can spread at the given block position.
  • net.minecraft.server.network
    • EventLoopGroupHolder - A holder for managing the event loop and channels for communicating with some end, whether local or socket-based.
    • ServerGamePacketListenerImpl#resetFlyingTicks - Resets how long the player has been flying.
  • net.minecraft.server.notifications
    • NotificationService#serverActivityOccurred - Notifies the management server that activity has occurred.
    • ServerActivityMonitor - The monitor that sends the server activity notification
  • net.minecraft.util
    • ARGB
      • srgbToLinearChannel - Converts the sRGB value into a linear color space.
      • linearToSrgbChannel - Converts the linear value into a sRGB color space.
      • meanLinear - Computes the mean using the linear color space for four values, then converting it back into sRGB.
      • addRgb - Adds the RGB channels, using the alpha from the first value.
      • subtractRgb - Subtracts the RGB channels, using the alpha from the first value.
      • multiplyAlpha - Multiplies the alpha value into the provided ARGB value.
      • linearLerp - Linearly interpolates the color by converting into the linear color space.
      • white, black - Colors with the provided alpha.
      • alphaBlend - Blends two colors along with their alpha value.
      • vector4fFromARGB32 - Converts an ARGB value to four floats.
    • Ease - A utility full of easing functions.
    • ExtraCodecs
      • NON_NEGATIVE_LONG, POSITIVE_LONG - Longs with the listed constraints.
      • longRange - A long codec that validates whether it is between the provided range.
      • STRING_RGB_COLOR, STRING_ARGB_COLOR - A codec allowing for an (A)RGB value expressed in hex form as a string.
      • MAX_PROPERTY_NAME_LENGTH, MAX_PROPERTY_VALUE_LENGTH, MAX_PROPERTY_SIGNATURE_LENGTH, MAX_PROPERTIES - Constants related to serializing the property map.
    • Mth
      • cube - Cubes a number.
      • chessboardDistance - Computes the absolute maximum difference between two pairs of coordinates; the larger axis difference is returned.
    • SpecialDates - A utility containing the dates that Mojang changes some behavior or rendering for.
    • TriState
      • CODEC - The codec for the tristate.
      • from - Turns a boolean into a tristate.
  • net.minecraft.util.profiling.jfr.JvmProfiler#onClientTick - Runs on client tick, taking in the current FPS.
  • net.minecraft.util.profiling.jfr.event.ClientFpsEvent - An event that keeps track of the client FPS.
  • net.minecraft.util.profiling.jfr.stats.FpsStat - A record containing the client FPS.
  • net.minecraft.world
    • LockCode#canUnlock - Whether the given player can unlock this code.
    • Stopwatch - A record that holds the creation time and amount of time that has elapsed.
    • Stopwatches - A tracker for starting, managing, and stopping stopwatches.
  • net.minecraft.world.effect
    • MobEffects#BREATH_OF_THE_NAUTILUS - Prevents the user from losing air underwater.
    • MobEffectUtil#shouldEffectsRefillAirsupply - Whether the entity has an effect that refills the air supply while under a liquid.
  • net.minecraft.world.entity
    • Entity
      • getHeadLookAngle - Calculates the view vector of the head rotation.
      • updateDataBeforeSync - Updates the data stored in the entity before syncing to the client.
      • computeSpeed - Computes last known speed and position of the entity.
      • getKnownSpeed - Gets the last known speed of the entity.
      • hasMovedHorizontallyRecently - If the last known speed’s horizontal distance is larger than 0, more specifically the margin of error.
    • EntityProcessor - A post processor for an entity when loading.
    • EntityEvent#KINETIC_HIT - An event fired when an entity is hit with a kinetic weapon.
    • HumanoidArm#STREAM_CODEC - The network codec for the arm enum.
    • LivingEntity
      • DEFAULT_KNOCKBACK - The default knockback applied to an entity on hit.
      • itemSwapTicker - The amount of time taken when swapping items.
      • recentKineticEnemies - The attackers that have recently attacked with a kinetic weapon.
      • lungeForwardMaybe - Apply the lunge effects.
      • causeExtraKnockback - Applies an multiplicative force to the knockback.
      • wasRecentlyStabbed, rememberStabbedEntity - Handles enemies that were stabbed with a kinetic weapon.
      • stabAttack - Handles when a mob is stabbed by this entity.
      • onAttack - Handles when this entity has attacked another entity.
      • getTicksUsingItem - Returns the number of ticks this item has been used for.
      • getTicksSinceLastKineticHitFeedback - The number of ticks that has passed since this entity was last hit with a kinetic weapon.
      • shouldTravelInFluid - If this entity should travel in the given fluid.
      • travelInWater - Moves an entity as if they were in water.
    • Mob#sunProtectionSlot - The equipment slot that protects the entity from the sun.
    • NeutralMob#level - Returns the level the entity is in.
    • PlayerRideableJumping#getPlayerJumpPendingScale - Returns the scalar to apply to the entity on player jump.
  • net.minecraft.world.entity.ai.attributes.Attributes#DEFAULT_ATTACK_SPEED - The default attack speed.
  • net.minecraft.world.entity.ai.memory.MemoryModuleType
    • CHARGE_COOLDOWN_TICKS - The number of cooldown ticks after a charge attack.
    • ATTACK_TARGET_COOLDOWN - The number of cooldown ticks before attacking a target.
  • net.minecraft.world.entity.ai.sensing.TemptingSensor#forAnimal - A sensor that special cases animal entities for check if the desired item is food.
  • net.minecraft.world.entity.animal.camel
    • Camel
      • getDashingSound, getDashReadySound - Camel dashing sounds.
      • getStandUpSound, getSitDownSound - Camel sit/stand sounds.
      • getSaddleSound - Camel saddle sound.
    • CamelHusk - The camel husk entity.
  • net.minecraft.world.entity.animal.equine.AbstractHorse#isMobControlled - Whether a mob can control this horse.
  • net.minecraft.world.entity.animal.nautilus
    • AbstractNautilus - The core of the nautilus entity.
    • Nautilus - The nautilus entity.
    • NautilusAi - The brain of a nautilus.
    • ZombieNautilus - The zombie nautilus entity.
    • ZombieNautilusAi - The brain of a zombie nautilus.
  • net.minecraft.world.entity.decoration.HangingEntity#hasLevelCollision - Whether this entity is colliding with a block or the border in a given bounds.
  • net.minecraft.world.entity.monster.skeleton.Parched - The parched entity.
  • net.minecraft.world.entity.monster.zombie.Husk$HuskGroupData - The group data for the husk.
  • net.minecraft.world.entity.player.Player
    • cannotAttackWithItem - Checks whether the player cannot attack with the item.
    • getItemSwapScale - Returns the scalar to use for the item swap animation.
    • resetOnlyAttackStrengthTicker - Resets the attack strength ticker.
    • openNautilusInventory - Opens the inventory of the interacted nautilus.
    • applyPostImpulseGraceTime, isInPostImpulseGraceTime - Handles the grace time between impulses.
  • net.minecraft.world.food.FoodData#hasEnoughFood - Whether the current food level is greater than 6 hunger (or three full hunger bars).
  • net.minecraft.world.inventory
    • AbstractMountInventoryMenu - The inventory menu for a mount.
    • NautilusInventoryMenu - The inventory menu of a nautilus.
  • net.minecraft.world.item
    • HoneycombItem#WAXED_RECIPES - A map of waxed block to their recipe categories and name.
    • Item$Properties
      • spear - Adds the spear components.
      • nautilusArmor - Adds the nautilus armor components.
    • ItemStack#matchesIgnoringComponents - Whether the stack matches ignoring all components that match the predicate.
    • ItemUseAnimation
      • TRIDENT - The trident use animation.
      • hasCustomArmTransform - Whether the animation provides a custom transform to the arm.
  • net.minecraft.world.item.enchantment
    • Enchantment#doLunge - Applies the post piercing attack effect.
    • EnchantmentEffectComponents#POST_PIERCING_ATTACK - The effect to apply after a piercing attack.
    • EnchantmentHelper#doLungeEffects - Applies the effect on lunge.
    • LevelBasedValue$Exponent - Applies an exponent given the base and power.
  • net.minecraft.world.item.enchantment.effects
    • ApplyEntityImpulse - An entity effect that adds an impulse in the direction of the look angle.
    • ApplyExhaustion - An entity effect that applies food exhaustion to the player if they are using the enchanted item.
    • ScaleExponentially - A value effect that multiplies the value by a number raised to some exponent.
  • net.minecraft.world.level
    • Chunk#isValid - Whether the chunk pos is within the maximum allowed coordinate world (within the 30 million block radius).
    • CollisionGetter
      • noEntityCollision - Whether the entity is not colliding with another entity in the given bounds.
      • noBorderCollision - Whether the entity is not colliding with the world border in the given bounds.
    • Level#isInValidBounds - Whether the block position is not outside the maximum allowed coordinate world (build height for Y axis, 30 million block radius for XZ axis).
    • MoonPhase - An enum representing the phases of the moon.
  • net.minecraft.world.level.border.WorldBorder$MovingBorderExtent#getPreviousSize - Gets the previous size of the border.
  • net.minecraft.world.level.chunk.storage
    • IOWorker#STORE_EMPTY - A supplied null tag.
    • LegacyTagFixer - An interface that handles how to upgrade a tag, like for the chunk.
    • SimpleRegionStorage
      • isOldChunkAround - Whether the chunk from a previous version still exists in this version.
      • injectDatafixingContext - When the context is not null, adds it to the given tag.
      • markChunkDone - Marks a chunk as finished for upgrading to the current version.
      • chunkScanner - Gets the access used to scan chunks.
  • net.minecraft.world.level.levelgen.structure.LegacyStructureDataHandler#LAST_MONOLYTH_STRUCTURE_DATA_VERSION - Returns the last data version containing glitched monolyths.
  • net.minecraft.world.level.storage.loot.LootContextArg - An argument for a loot context to query.
  • net.minecraft.world.level.storage.loot.functions.DiscardItem - A loot function that discards the loot, returning an empty stack.
  • net.minecraft.world.phys.Vec3
    • offsetRandomXZ - Offsets the point by a random amount in the XZ direction.
    • rotation - Computes the rotation of the vector.
    • applyLocalCoordinatesToRotation - Adds the components relative to the current rotation of the vector.
    • isFinite - Returns whether all components of the vector are finite (not NaN or infinity) values.
  • net.minecraft.world.scores
    • Scoreboard
      • packPlayerTeams - Packs the player teams into a serializable format.
      • packObjectives - Packs the objectives into a serializable format.
      • packDisplaySlots - Packs the display slots into a serializable format.
    • ScoreboardSaveData
      • getData, setData - Handles the packed scoreboard.
      • Packed$EMPTY - Represents an empty scoreboard.
  • net.minecraft.world.waypoints.Waypoint$Icon#copyFrom - Copies the icon color and style from another icon.

List of Changes

  • com.mojang.blaze3d.platform.Lighting#updateLevel now takes in a DimensionType$CardinalLightType instead of a boolean for whether the level is the nether or not
  • com.mojang.blaze3d.systems.GpuDevice#createTexture now has an overload that takes in a supplied label instead of the raw string
  • com.mojang.blaze3d.vertex.VertexConsumer
    • addVertex, addVertexWith2DPose now take in the interface, ‘read only’ variants of its arguments (e.g., Vector3f -> Vector3fc)
    • putBulkData no longer takes the final boolean to read the buffer data to determine the initial color
  • com.mojang.math
    • OctahedralGroup
      • fromXYAngles -> Quadrant#fromXYAngles
      • permute -> SymmetricGroup3#permuteAxis
    • SymmetricGroup3
      • permutation -> permute
      • permuteVector -> OctahedralGroup#rotate
    • Transformation now takes in the interface, ‘read only’ variants of its arguments (e.g., Vector3f -> Vector3fc)
      • This also applies to the argument getter methods
  • net.minecraft
    • FileUtil#isValidStrictPathSegment -> containsAllowedCharactersOnly, now private
      • Replaced by isValidPathSegment
    • Minecraft
      • disconnectWithProgressScreen now takes in a boolean of whether to stop the sound engine
      • disconnect now takes in a boolean of whether to stop the sound engine
    • SharedConstants
      • DEBUG_WATER -> DebugScreenEntries#VISUALIZE_WATER_LEVELS, not one-to-one
      • DEBUG_HEIGHTMAP -> DebugScreenEntries#VISUALIZE_HEIGHTMAP, not one-to-one
      • DEBUG_COLLISION -> DebugScreenEntries#VISUALIZE_COLLISION_BOXES, not one-to-one
      • DEBUG_SUPPORT_BLOCKS -> DebugScreenEntries#VISUALIZE_ENTITY_SUPPORTING_BLOCKS, not one-to-one
      • DEBUG_LIGHT -> DebugScreenEntries#VISUALIZE_BLOCK_LIGHT_LEVELS, VISUALIZE_SKY_LIGHT_LEVELS; not one-to-one
      • DEBUG_SKY_LIGHT_SECTIONS -> DebugScreenEntries#VISUALIZE_SKY_LIGHT_SECTIONS, not one-to-one
      • DEBUG_SOLID_FACE -> DebugScreenEntries#VISUALIZE_SOLID_FACES, not one-to-one
      • DEBUG_CHUNKS -> DebugScreenEntries#VISUALIZE_CHUNKS_ON_SERVER, not one-to-one
  • net.minecraft.advancements.criterion.EntityFlagsPredicate now takes in optional booleans for if the entity is in water or fall flying
    • The associated $Builder methods have also been added
  • net.minecraft.client
    • Camera
      • setup now takes in a Level instead of a BlockGetter
      • get* has been replaced by their record alternatives (e.g. getEntity -> entity)
      • Vector3f return values are replaced with Vector3fc
    • GraphicsStatus -> GraphicsPreset, not one-to-one
    • KeyMapping now has an overload that takes in the sort order
    • MouseHandler#lastClickTime -> lastClick, now private, not one-to-one
    • OptionInstance$OptionInstanceSliderButton now implements ResettableOptionWidget
    • Options
      • graphicsMode -> graphicsPreset, applyGraphicsPreset
      • showNowPlayingToast -> musicToast, not one-to-one
  • net.minecraft.client.data.models
    • EquipmentAssetProvider#humanoidAndHorse -> humanoidAndMountArmor
    • ItemModelGenerators
      • getSpans -> getSideFaces, not one-to-one
      • $SpanFacing -> $SideDirection, not one-to-one
      • $Span -> $SideFace, not one-to-one
    • ItemModelOutput#accept now has an overload that takes in the ClientItem$Properties
  • net.minecraft.client.gui
    • Font#NO_SHADOW -> Style#NO_SHADOW
    • GuiGraphics
      • textHighlight now takes in a boolean of whether to render the background rectangle
      • submitOutline -> renderOutline
  • net.minecraft.client.gui.components
    • AbstractButton#handleCursor -> handleCursor, now protected
    • AbstractSliderButton
      • HANDLE_WIDTH is now protected
      • canChangeValue, setValue are now protected
    • AbstractWidget#message is now protected
    • CycleButton now implements ResettableOptionWidget
      • builder now has an overload to take in a supplied default value
      • booleanBuilder now takes in a boolean to choose which component to default to
      • $Builder now takes in a supplied default value
        • displayOnlyValue(boolean) -> displayState, not one-to-one
    • FocusableTextWidget constructor is now package private, use builder instead
    • OptionsList now passes in an $AbstractEntry to the generic rather than an $Entry
      • addSmall now has an overload that takes in an OptionInstance
      • $Entry now extends $AbstractEntry
      • $OptionEntry class is removed
        • big -> $Entry#big
        • small -> $Entry#small
    • StringWidget#clipText is now public static, taking in the Font
  • net.minecraft.client.gui.components.debug
    • DebugScreenEntryList
      • toggleF3Visible -> toggleDebugOverlay
      • setF3Visible -> setOverlayVisible
      • isF3Visible -> isOverlayVisible
    • DebugScreenEntryStatus#IN_F3 -> IN_OVERLAY
  • net.minecraft.client.gui.components.debugchart.AbstractDebugChart#COLOR_GREY -> CommonColors#TEXT_GRAY
  • net.minecraft.client.gui.components.toasts.ToastManager
    • createNowPlayingToast -> initializeMusicToast, now private, not one-to-one
    • removeNowPlayingToast -> setMusicToastDisplayState, not one-to-one
  • net.minecraft.client.gui.navigation.ScreenRectangle#transform* methods now take in the interface, ‘read only’ variants of its arguments (e.g., Vector3f -> Vector3fc)
  • net.minecraft.client.gui.render.state.* now take in the interface, ‘read only’ variants for its pose (e.g., Vector3f -> Vector3fc)
    • GuiTextRenderState now takes in whether to draw the empty space around each glyph
  • net.minecraft.client.gui.screens
    • DeathScreen now takes in the LocalPlayer
    • Screen now has an overload that takes in the Minecraft instance and Font to use
      • minecraft is now final
      • font is now final
      • init(Minecraft, int, int) -> init(int, int)
      • resize(Minecraft, int, int) -> init(int, int)
      • handleComponentClicked -> ChatScreen#handleComponentClicked, now private
      • handleClickEvent has been moved to their associated classes instead of one super interface (e.g., BookViewScreen#handleClickEvent)
  • net.minecraft.client.gui.screens.advancements
    • AdvancementsScreen#renderWindow now takes in the mouse XY ints
    • AdvancementTab#drawTab now takes in the mouse XY ints
  • net.minecraft.client.gui.screens.debug.DebugOptionsScreen$OptionList is now public
  • net.minecraft.client.gui.screens.inventory
    • AbstractCommandBlockEditScreen#populateAndSendPacket no longer takes in the BaseCommandBlock
    • AbstractContainerScreen#renderSlots, renderSlot now take in the mouse XY ints
    • CreativeModeInventoryScreen#renderTabButton now takes in the mouse XY ints
    • EffectsInInventory#renderEffects -> render
    • HorseInventoryScreen now extends AbstractMountInventoryScreen
    • MinecartCommandBlockEditScreen now takes in a MinecartCommandBlock instead of a BaseCommandBlock
  • net.minecraft.client.gui.screens.multiplayer.ServerSelectionList$OnlineServerEntry now implements SelectableEntry
  • net.minecraft.client.gui.screens.packs.TransferableSelectionList$PackEntry now implements SelectableEntry
  • net.minecraft.client.gui.screens.recipebook
    • RecipeBookComponent#initFilterButtonTextures -> getFilterButtonTextures, not one-to-one
    • RecipeBookTabButton now implements ImageButton instead of StateSwitchingButton
      • The constructor now takes in the XY position along with the Button$OnPress consumer
  • net.minecraft.client.gui.screens.worldselection.WorldSelectionList$WorldListEntry is no longer static, now implements SelectableEntry
  • net.minecraft.client.model
    • AnimationUtils
      • animateCrossbowCharge now takes in a float instead of an int
      • animateZombieArms now takes in an UndeadRenderState instead of two floats
    • HumanoidModel
      • setupAttackAnimation no longer takes in a float
      • getArm is now public from protected
  • net.minecraft.client.model.geom.ModelPart#getExtentsForGui now takes in a Consumer<Vector3fc> instead of a set
  • net.minecraft.client.model.geom.builders.UVPair is now a record
  • net.minecraft.client.multiplayer
    • MultiPlayerGameMode#isAlwaysFlying -> isSpectator
    • ServerStatusPinger#pingServer now takes in an EventLoopGroupHolder
  • net.minecraft.client.renderer
    • CloudRenderer#render now takes in the game time long
    • DynamicUniforms#writeTransform, $Transform no longer take in the line width float
    • GameRenderer#setPanoramicMode -> setPanoramicScreenshotParameters, not one-to-one
    • GlobalSettingsUniform#update now takes in the Camera and whether to use Rotated Grid Super Sampling (RGSS)
    • ItemBlockRenderTypes#setFancy -> setCutoutLeaves
    • ItemInHandRenderer no longer takes in the ItemRenderer
    • LevelRenderer#isSectionCompiled -> isSectionCompiledAndVisible
    • RenderPipelines
      • LINE_STRIP -> LINES or LINES_TRANSLUCENT, not one-to-one
      • DEBUG_LINE_STRIP -> DEBUG_POINTS, not one-to-one
    • RenderType
      • LINE_STRIP, lineStrip -> RenderTypes#LINES, LINES_TRANSLUCENT, linesTranslucent; not one-to-one
      • debugLineStrip -> debugPoint, not one-to-one
    • SkyRenderer now takes in the TextureManager and AtlasManager
      • extractRenderState now takes in a Camera instead of the camera position
      • renderSunMoonAndStars now takes in a MoonPhase instead of an int
    • UniformValue
      • $IVec3Uniform now takes in a Vector3ic instead of a Vector3i
      • $Vec2Uniform now takes in a Vector2fc instead of a Vector2f
      • $Vec3Uniform now takes in a Vector3fc instead of a Vector3f
      • $Vec4Uniform now takes in a Vector4fc instead of a Vector4f
    • WeatherEffectRenderer#tickRainParticles now takes in an int for the weather radius
    • WorldBorderRenderer#extract now takes in a float for the partial tick
  • net.minecraft.client.renderer.blockentity
    • BannerRenderer#getExtents now takes in a Consumer<Vector3fc> instead of a set
    • BedRenderer#getExtents now takes in a Consumer<Vector3fc> instead of a set
    • BellRenderer#BELL_RESOURCE_LOCATION -> BELL_TEXTURE
    • DecoratedPotRenderer#getExtents now takes in a Consumer<Vector3fc> instead of a set
    • EnchantTableRenderer#BOOK_LOCATION -> BOOK_TEXTURE
    • ShulkerBoxRenderer#getExtents now takes in a Consumer<Vector3fc> instead of a set
    • TestInstanceRenderer no longer takes in the BlockEntityRendererProvider$Context
  • net.minecraft.client.renderer.blockentity.state.BlockEntityWithBoundingBoxRenderState$InvisibleBlockType$STRUCUTRE_VOID -> STRUCTURE_VOID
  • net.minecraft.client.renderer.chunk.ChunkSectionLayer#textureView -> texture, not one-to-one
  • net.minecraft.client.renderer.entity.EntityRenderDispatcher no longer takes in the ItemRenderer
  • net.minecraft.client.renderer.entity.layers
    • CarriedBLockLayer no longer takes in the BlockRenderDispatcher
    • IronGolemFlowerLayer no longer takes in the BlockRenderDispatcher
    • ItemInHandLayer#submitArmWithItem now takes in the held ItemStack
  • net.minecraft.client.renderer.entity.state
    • ArmedEntityRenderState
      • *HandItem -> *HandItemState, *HandItemStack; not one-to-one
      • extractArmedRenderState now takes in the partial tick float
    • HorseRenderState#bodyArmorItem -> EquineRenderState#bodyArmorItem
    • HumanoidRenderState
      • attackTime -> ArmedEntityRenderState#attackTime
      • ticksUsingItem is now a float
    • IllagerRenderState now extends UndeadRenderState
      • ticksUsingItem is now a float
    • ZombieRenderState now extends UndeadRenderState
    • ZombifiedPiglinRenderState now extends UndeadRenderState
  • net.minecraft.client.renderer.fog.FogRenderer#setupFog no longer takes in the boolean
  • net.minecraft.client.renderer.fog.environment
    • AtmosphericFogEnvironment now extends FogEnvironment instead of AirBasedFogEnvironment
    • FogEnvironment#setupFog no longer takes in the Entity and BlockPos, instead the Camera
  • net.minecraft.client.renderer.item.ClientItem$Properties now takes in a float for changing the scale of the swap animation
  • net.minecraft.client.renderer.special.SpecialModelRenderer#getExtents now takes in a Consumer<Vector3fc> instead of a set
  • net.minecraft.client.renderer.state.SkyRenderState#moonPhase is now a MoonPhase instead of an int
  • net.minecraft.client.resources.SplashManager
    • prepare now returns a list of Components instead of strings
    • apply now takes in a list of Components instead of strings
  • net.minecraft.client.resources.model.BlockModelRotation is now a class
    • by -> get, not one-to-one
  • net.minecraft.client.resources.sounds
    • RidingHappyGhastSoundInstance -> RidingEntitySoundInstance, not one-to-one
    • RidingMinecartSoundInstance now extends RidingEntitySoundInstance instead of AbstractTickableSoundInstance
      • The constructor now takes in the SoundEvent, volume min and max, and amplifier
    • SimpleSoundInstance#forMusic no longer takes in the volume
  • net.minecraft.client.sounds
    • SoundEngine no longer takes in the MusicManager
      • updateCategoryVolume -> refreshCategoryVolume
      • setVolume -> updateCategoryVolume, not one-to-one
    • SoundManager no longer takes in the MusicManager
      • updateSourceVolume -> refreshCategoryVolume
      • setVolume -> updateCategoryVolume, not one-to-one
  • net.minecraft.gametest.framework.GameTestHelper
    • spawn now has an overload that takes in the EntitySpawnReason or three ints for the position
    • assetTrue, assetFalse, assertValueEqual now has an overload that takes in a String instead of a Component
    • assertEntityData now has an overload that takes in the AABB bounding box
    • getRelativeBounds is now public
    • assertEntityPosition -> assertEntityPresent, not one-to-one
  • net.minecraft.nbt
    • CompoundTag#remove now returns the removed tag
    • NbtUtils#getDataVersion now has an overload that only takes in the CompoundTag
  • net.minecraft.network
    • Connection
      • NETWORK_WORKER_GROUP -> EventLoopGroupHolder#NIO, not one-to-one
      • NETWORK_EPOLL_WORKER_GROUP -> EventLoopGroupHolder#EPOLL, not one-to-one
      • LOCAL_WORKER_GROUP -> EventLoopGroupHolder#LOCAL, not one-to-one
      • connectToServer, connect now take in an EventLoopGroupHolder instead of a boolean
    • FriendlyByteBuf
      • writeVector3f now takes in a Vector3fc instead of a Vector3f
      • writeQuaternion now takes in a Quaternionfc instead of a Quaternionf
      • DEFAULT_NBT_QUOTA -> NbtAccounter#DEFAULT_NBT_QUOTA
  • net.minecraft.network.codec
    • ByteBufCodecs
      • VECTOR3F now uses a Vector3fc instead of a Vector3f
      • QUATERNIONF now uses a Quaternionfc instead of a Quaternionf
    • StreamCodec#composite now has ten and twelve parameter variants
  • net.minecraft.network.chat
    • ComponentUtils#mergeStyles now has an overload that takes in and returns a Component
    • MutableComponent is now final
  • net.minecraft.network.protocol.game
    • ClientboundHorseScreenOpenPacket -> ClientboundMountScreenOpenPacket
    • ClientGamePacketListener#handleHorseScreenOpen -> handleMountScreenOpen
    • GamePacketTypes#CLIENTBOUND_HORSE_SCREEN_OPEN -> CLIENTBOUND_MOUNT_SCREEN_OPEN
  • net.minecraft.network.numbers
    • FixedFormat is now a record
    • StyledFormat is now a record
  • net.minecraft.network.syncher.EntityDataSerializers
    • VECTOR3 now uses a Vector3fc instead of a Vector3f
    • QUATERNION now uses a Quaternionfc instead of a Quaternionf
  • net.minecraft.server
    • MinecraftServer
      • isAllowedToEnterPortal -> ServerLevel#isAllowedToEnterPortal
      • isSpawningMonsters -> ServerLevel#isSpawningMonsters
      • isPvpAllowed -> ServerLevel#isPvpAllowed
      • isCommandBlockEnabled -> ServerLevel#isCommandBlockEnabled
      • isSpawnerBlockEnabled -> ServerLevel#isSpawnerBlockEnabled
      • getGameRules -> ServerLevel#getGameRules
      • isEpollEnabled -> useNativeTransport
    • ServerScoreboard no longer implements its own saved data type, instead using the packed ScoreboardSaveData
      • TYPE -> ScoreboardSavedData#TYPE
  • net.minecraft.server.jsonrpc
    • IncomingRpcMethod now takes in two generics for the parameters to the request and the result response
      • $Builder now has constructors for parameterless and parameter functions, replacing $Factory
        • response, param now take in their Schemas
    • OutgoingRpcMethod$Factory now takes in the generic params and result
  • net.minecraft.server.jsonrpc.api
    • MethodInfo, $Named now takes in two generics for the parameters to the request and the result response
      • PARAMS_CODEC -> paramsTypedCodec, now private, not one-to-one
      • MAP_CODEC -> typedCodec, now package-private, not one-to-one
    • ParamInfo now takes in a generic for the parameter
      • CODEC -> typedCodec, not one-to-one
    • ResultInfo now takes in a generic for the result response
      • CODEC -> typedCodec, not one-to-one
    • Schema now takes in a generic for the type it represents
      • The constructor now takes in a list of types instead of an optional, an non-optional property map, non-oprional enuma values, and the codec to serialize the type
      • ofTypes now has an overload that takes in a list of types
    • SchemaComponent now takes in a generic for the type it represents
  • net.minecraft.server.jsonrpc.security.AuthenticationHandler now implements ChannelDuplexHandler instead of ChannelInboundHandlerAdapter
    • The constructor now takes in a string set of allowed origins
    • $SecurityCheckResult#allowed now has an overload that specifies whether the token was sent through the websocket protocol
  • net.minecraft.server.level
    • ChunkMap now extends SimpleRegionStorage instead of ChunkStorage
    • ServerLevel#drop no longer returns a boolean
  • net.minecraft.server.network.ServerConnectionListener
    • SERVER_EVENT_GROUP -> EventLoopGroupHolder#NIO, not one-to-one
    • SERVER_EPOLL_EVENT_GROUP -> EventLoopGroupHolder#EPOLL, not one-to-one
  • net.minecraft.stats.ServerStatsCounter now takes in a Path instead of a File
    • parseLocal -> parse, not one-to-one
    • toJson now returns a JsonElement instead of a String
  • net.minecraft.util
    • ARGB#lerp -> srgbLerp
    • ExtraCodecs now use the interface, ‘read only’ variants for its generic (e.g., Vector3f -> Vector3fc)
    • Mth
      • easeInOutSine -> Ease#inOutSine
      • sin, cos now takes in a double instead of a float
      • absMax now has overloads that uses ints or floats
    • TriState now implements StringRepresentable
  • net.minecraft.util.profiling.jfr.Percentiles#evaluate now has an overload that takes in an int[]
  • net.minecraft.util.profiling.jfr.parse.JfrStatsResult now takes in an FPS stat
    • tickTimes -> serverTickTimes
  • net.minecraft.util.profiling.jfr.stats.TimedStatSummary#summary now returns an optional of the TimeStatSummary
  • net.minecraft.util.worldupdate.WorldUpgrader
    • $AbstractUpgrader no longer takes in a generic
      • createStorage now returns a SimpleRegionStorage instead of the generic
      • tryProcessOnePosition now takes in a SimpleRegionStorage instead of the generic
    • $DimensionToUpgrade no longer takes in a generic, instead using SimpleRegionStorage
  • net.minecraft.world.RandomSequences no longer takes in the world seed
    • codec -> CODEC
    • get, reset now takes in the world seed
  • net.minecraft.world.entity
    • Avatar#DATA_PLAYER_MAIN_HAND now uses a HumanoidArm generic instead of a byte
    • Entity#hasImpulse -> needsSync
    • EntityType#loadEntityRecursive now takes in an EntityProcessor instead of a Function
    • LivingEntity#invulnerableDuration -> INVULNERABLE_DURATION
    • Mob#playAttackSound -> LivingEntity#playAttackSound
    • NeutralMob
      • TAG_ANGER_TIME -> TAG_ANGER_END_TIME, not one-to-one
      • getRemainingPersistentAngerTime -> getPersistentAngerEndTime, not one-to-one
      • setRemainingPersistentAngerTime -> setTimeToRemainAngry, setPersistentAngerEndTime; second is not one-to-one
      • getPersistentAngerTarget, setPersistentAngerTarget now deal with EntityReferences
  • net.minecraft.world.entity.ai.sensing.SensorType#*_TEMPTATIONS -> FOOD_TEMPTATIONS, not one-to-one
  • net.minecraft.world.entity.ai.util
    • GoalUtils
      • mobRestricted now takes in a double instead of an int
      • isRestricted now has an overload that takes in a Vec3
    • LandRandomPos
      • getPosAway now has an overload that takes in an additional double for the start/end radians
      • generateRandomPosTowardDirection now takes in a double instead of an int
    • RandomPos
      • generateRandomDirectionWithinRadians now takes in doubles for the start/end radians
      • generateRandomPosTowardDirection now takes in a double instead of an int
  • net.minecraft.world.entity.animal.equine.AbstractHorse#getInventorySize -> AbstractMountInventoryMenu#getInventorySize
  • net.minecraft.world.entity.monster.Monster#checkMonsterSpawnRules now expanded its type generic to extends Mob instead of Monster
  • net.minecraft.world.entity.monster.skeleton.Bogged#*_ATTACK_INTERVAL -> AbstractSkeleton#INCREASED_*_ATTACK_INTERVAL
  • net.minecraft.world.entity.monster.zombie
    • Husk#checkHuskSpawnRules -> Monster#checkSurfaceMonsterSpawnRules, not one-to-one
    • Zombie
      • doUnderWaterConversion now takes in the ServerLevel
      • convertToZombieType now takes in the ServerLevel
  • net.minecraft.world.entity.npc.villager
    • AbstractVillager
      • updateTrades now takes in the ServerLevel
      • addOffersFromItemListings now takes in the ServerLevel
    • Villager#shouldRestock now takes in the ServerLevel
    • VillagerTrades$ItemListing#getOffer now takes in the ServerLevel
  • net.minecraft.world.entity.player.Player
    • openMinecartCommandBlock now takes in a MinecartCommandBlock instead of a BaseCommandBlock
    • sweepAttack -> doSweepAttack, now private, not one-to-one
    • respawn -> LocalPlayer#respawn
    • CLIENT_LOADED_TIMEOUT_TIME -> ServerGamePacketListenerImpl#CLIENT_LOADED_TIMEOUT_TIME
    • clientLoadedTimeoutTimer, tickClientLoadTimeout -> ServerGamePacketListenerImpl#tickClientLoadTimeout
    • hasClientLoaded -> ServerGamePacketListenerImpl#hasClientLoaded
    • setClientLoaded -> ServerGamePacketListenerImpl#markClientLoaded, markClientUnloadedAfterDeath, restartClientLoadTimerAfterRespawn; not one-to-one
  • net.minecraft.world.entity.projectile.Projectile constructor is now protected instead of package private
  • net.minecraft.world.entity.vehicle.VehicleEntity#shouldSourceDestroy is now protected instead of package private
  • net.minecraft.world.entity.vehicle.minecart
    • AbstractMinecart now takes in the ServerLevel
    • MinecartCommandBlock$MinecartCommandBase is now package-private
  • net.minecraft.world.inventory.HorseInventoryMenu now extends AbstractMountInventoryMenu
  • net.minecraft.world.item.component.ItemAttributeModifiers#compute now takes in the Attribute holder
  • net.minecraft.world.item.enchantment.effects.PlaySoundEffect now takes in a list of sound events instead of a single
  • net.minecraft.world.level
    • BaseCommandBlock
      • performCommand now takes in a ServerLevel instead of a Level
      • onUpdated now takes in a ServerLevel
      • createCommandSourceStack now takes in a ServerLevel
      • $CloseableCommandBlockSource now takes in a ServerLevel, with its constructor protected
    • CollisionGetter#noBlockCollision now has an overload that takes in an additional boolean of whether to check liquid collisions.
    • Level#getGameTime -> LevelAccessor#getGameTime
    • LevelAccessor#getCurrentDifficultyAt -> ServerLevelAccessor#getCurrentDifficultyAt
    • LevelTimeAccess#getMoonPhase now returns a MoonPhase instead of an int
  • net.minecraft.world.level.biome
    • AmbientAdditionsSettings is now a record
    • AmbientMoodSettings is now a record
    • AmbientParticleSettings is now a record
  • net.minecraft.world.level.block.entity.BaseContainerBlockEntity#canUnlock -> sendChestLockedNotifications, not one-to-one
  • net.minecraft.world.level.border
    • BorderChangeListener#onLerpSize now takes in an additional long for the game time
    • WorldBorder can now take in the WorldBorder$Settings
      • getMin*, getMax* now have an overload that takes in the partial tick float
      • lerpSizeBetween now takes in an additional long for the game time
      • applySettings -> applyInitialSettings, not one-to-one
        • The original behavior can be replicated by passing the settings into the constructor
      • $BorderExtent#getMin*, getMax* now takes in the partial tick float
  • net.minecraft.world.level.chunk.storage
    • RecreatingSimpleRegionStorage now takes in a supplied LegacyTagFixer
    • SimpleRegionStorage now takes in a supplied LegacyTagFixer
      • write now has an overload that takes in a supplied CompoundTag
      • upgradeChunkTag now has an overload that takes in a a nullable tag comntext
  • net.minecraft.world.level.dimension.DimensionType
    • MOON_PHASES is now an array of MoonPhases and private
    • moonPhase now returns a MoonPhase instead of an int
  • net.minecraft.world.level.levelgen.structure.LegacyStructureDataHandler now implements LegacyTagFixer
    • The constructor now takes in the DataFixer
    • removeIndex -> LegacyTagFixer#markChunkDone
    • updateFromLegacy now private
    • getLegacyStructureHandler now takes in the DataFixer, a supplied DimensionDataStorage, and returns a supplied LegacyTagFixer
  • net.minecraft.world.level.levelgen.structure.structures.NetherFortressPieces$StartPiece fields are now package-private
  • net.minecraft.world.level.saveddata.SavedDataType no longer takes in a SavedData$Context, removing the function argument constructor
  • net.minecraft.world.level.storage
    • DimensionDataStorage no longer takes in a SavedData$Context
    • FileNameDateFormatter#create -> FORMATTER
    • LevelStorageSource
      • UNCOMPRESSED_NBT_QUOTA -> NbtAccounter#UNCOMPRESSED_NBT_QUOTA, now public
      • $LevelDirectory#corruptedDataFile, rawDataFile now take in a ZonedDateTime instead of a LocalDateTime
  • net.minecraft.world.level.storage.loot.LootContext
    • $BlockEntityTarget now implements LootContextArg$SimpleGetter
      • getParam -> contextParam
    • $EntityTarget now implements LootContextArg$SimpleGetter
      • getParam -> contextParam
    • $ItemStackTarget now implements LootContextArg$SimpleGetter
      • getParam -> contextParam
  • net.minecraft.world.level.storage.loot.functions
    • CopyComponentsFunction
      • $*Source -> $DirectSource, not one-to-one
      • $Source -> LootContextArg$Getter, not one-to-one
    • CopyNameFunction#copyName now takes in a LootContextArg instead of a $Source
      • $Source -> LootContextArg, not one-to-one
    • FilteredFunction now takes in an Optional pass and fail LootItemFunction instead of just a modifier
      • The function can now be builder through a $Builder via filtered
  • net.minecraft.world.phys.Vec3 now takes in a Vector3fc instead of a Vector3f
  • net.minecraft.world.phys.shapes.Shapes#rotateHorizontal, rotateAll, rotateAttachFace now have overloads to take in the OctahedralGroup
  • net.minecraft.world.scores
    • Score now has a public constructor for the $Packed value
      • MAP_CODEC -> Score$Packed ands its $Packed#MAP_CODEC
    • Scoreboard$PackedScore#score now takes in a Score$Packed instead of a Score
    • ScoreboardSavedData now takes in a ScoreboardSaveData$Packed instead of a Scoreboard
      • FILE_ID merged into type
      • loadFrom -> ServerScoreboard#load
      • pack -> ServerScoreboard#store, now private, not one-to-one

List of Removals

  • com.mojang.blaze3d.vertex.VertexFormat$Mode#LINE_STRIP
  • net.minecraft.Util#lastOf
  • net.minecraft.client
    • Minecraft#useFancyGraphics
    • GuiMessage#icon
    • StringSplitter
      • formattedIndexByWidth, componentStyleAtWidth
      • splitLines(FormattedText, int, Style, FormattedText)
  • net.minecraft.client.gui.Font#wordWrapHeight(String, int)
  • net.minecraft.client.gui.components
    • CycleButton
      • onOffBuilder()
      • $Builder#withInitialValue
    • StateSwitchingButton
  • net.minecraft.client.gui.screens.inventory
    • EffectsInInventory#renderTooltip
    • InventoryScreen#renderEntityInInventory
  • net.minecraft.client.gui.screens.packs.PackSelectionScreen#clearSelected
  • net.minecraft.client.player.LocalPlayer#USING_ITEM_SPEED_FACTOR
  • net.minecraft.client.renderer
    • ItemModelGenerator#createOrExpandSpan
    • GpuWarnlistManager#dismissWarningAndSkipFabulous, isSkippingFabulous
    • RenderPipelines
      • DEBUG_STRUCTURE_QUADS, DEBUG_SECTION_QUADS
    • SkyRenderer#initTextures
  • net.minecraft.client.renderer.fog.environment
    • AirBasedFogEnvironment
    • DimensionOrBossFogEnvironment
    • FogEnvironment#onNotApplicable
  • net.minecraft.client.resources.model.BlockModelRotation#actualRotation
  • net.minecraft.gametest.framework.GameTestHelper#setNight, setDayTime
  • net.minecraft.network.FriendlyByteBuf#readDate, writeDate
  • net.minecraft.server
    • MinecraftServer#hasGui
    • ServerScoreboard#createData, addDirtyListener
  • net.minecraft.server.jsonrpc.IncomingRpcMethod$Factory
  • net.minecraft.server.jsonrpc.methods.IllegalMethodDefinitionException
  • net.minecraft.server.jsonrpc.security.AuthenticationHandler#AUTH_HEADER
  • net.minecraft.util
    • DebugBuffer
    • LazyLoadedValue
  • net.minecraft.util.thread.NamedThreadFactory
  • net.minecraft.world.entity.Mob#isSunBurnTick
  • net.minecraft.world.entity.animal.armadillo.ArmadilloAi#getTemptations
  • net.minecraft.world.entity.animal.axolotl.AxolotlAi#getTemptations
  • net.minecraft.world.entity.animal.camel.CamelAi#getTemptations
  • net.minecraft.world.entity.animal.equine.ZombieHorse#checkZombieHorseSpawnRules
    • Use Monster#checkMonsterSpawnRules instead
  • net.minecraft.world.entity.animal.goat.GoatAi#getTemptations
  • net.minecraft.world.entity.animal.sniffer.SnifferAi#getTemptations
  • net.minecraft.world.entity.player.Player#playNotifySound
  • net.minecraft.world.entity.raid.Raid#TICKS_PER_DAY
  • net.minecraft.world.level
    • BaseCommandBlock
      • getLevel
      • getUsedBy, getPosition
    • Level#TICKS_PER_DAY
  • net.minecraft.world.level.border.WorldBorder$Settings#toWorldBorder
    • Use the WorldBorder constructor instead
  • net.minecraft.world.level.chunk.storage
    • ChunkStorage
    • RecreatingChunkStorage
  • net.minecraft.world.level.saveddata.SavedData$Context
  • net.minecraft.world.phys.Vec3#fromRGB24

Minecraft 1.21.11 -> 26.1 Mod Migration Primer

This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.11 to 26.1. This does not look at any specific mod loader, just the changes to the vanilla classes.

This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.

If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.

Thank you to:

  • @Shnupbups for some grammatical fixes
  • @cassiancc for information about Java 25 IDE support
  • @boq for information regarding IME support
  • @lolothepro for a typo

Pack Changes

There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.

Java 25 and Deobfuscation

26.1 introduces two new changes into the general pipeline.

First, the Java Development Kit has been upgraded from 21 to 25. Vanilla makes use of these new features, such as JEP 447, which allows statements before super within constructors. For users within the modding scene, please make sure to update accordingly, or take advantage of your IDE or build tool features. Microsoft’s OpenJDK can be found here.

You may need to update your IDE to support Java 25. If using Eclipse, you will need at least either 2025-12, or 2025-09 with the Java 25 Support marketplace plugin. If using IntelliJ IDEA, you will need at least 2025.2.

Vanilla has also returned to being deobfuscated, meaning that all value types now have the official names provided by Mojang. There are still some things that are not captured due to the Java compilation process, such as inlining primitive and string constants, but the majority are now provided. This will only have a change for users or mod loaders who used a different value type mapping set from the official mappings.

Loot Type Unrolling

Loot pool entries, item functions, item conditions, nbt providers, number providers, score providers, int providers, and float providers no longer use a wrapping object type to act as the registered instance. Now, the registries directly take in the MapCodec used for the serialization and deserialization process. As such, the *Type classes or records that held the codec have been removed. Additionally, getType is now renamed to codec, taking in the registered MapCodec.

// The following is an example with LootItemFunctions, but can roughly apply to the other instances as well

public record NoopItemFunction() implements LootItemFunction {
    public static final NoopItemFunction INSTANCE = new NoopItemFunction();
    // The map codec used as the registry object
    public static final MapCodec<NoopItemFunction> MAP_CODEC = MapCodec.unit(INSTANCE);

    // Replaces getType
    @Override
    public MapCodec<NoopItemFunction> codec() {
        // Return the registry object
        return MAP_CODEC;
    }
}

// Register the map codec to the appropriate registry
Registry.register(BuiltInRegistries.LOOT_FUNCTION_TYPE, Identifier.fromNamespaceAndPath("examplemod", "noop"), NoopItemFunction.MAP_CODEC);
  • net.minecraft.core.registries.BuiltInRegistries, Registries
    • LOOT_POOL_ENTRY_TYPE now holds a LootPoolEntryContainer map codec instead of a LootPoolEntryType
    • LOOT_FUNCTION_TYPE now holds a LootItemFunction map codec instead of a LootItemFunctionType
    • LOOT_CONDITION_TYPE now holds a LootItemCondition map codec instead of a LootItemConditionType
    • LOOT_NUMBER_PROVIDER_TYPE now holds a NumberProvider map codec instead of a LootNumberProviderType
    • LOOT_NBT_PROVIDER_TYPE now holds a NbtProvider map codec instead of a LootNbtProviderType
    • LOOT_SCORE_PROVIDER_TYPE now holds a ScoreboardNameProvider map codec instead of a LootScoreProviderType
    • FLOAT_PROVIDER_TYPE now holds a FloatProvider map codec instead of a FloatProviderType
    • INT_PROVIDER_TYPE now holds a IntProvider map codec instead of a IntProviderType
  • net.minecraft.util.valueproviders now renames CODEC fields to MAP_CODEC
    • FloatProvider subtypes are now all records
    • IntProvider subtypes, except for WeightedListInt, are now all records
    • FloatProvider is now an interface from a class
      • CODEC -> FloatProviders#CODEC
      • codec -> FloatProviders#codec
      • getType -> codec, not one-to-one
      • getMinValue -> min
      • getMaxValue -> max
    • FloatProviders - All vanilla float providers to register.
    • FloatProviderType interface is removed
      • Singleton fields have all been removed, use map codecs in each class instead
      • codec -> FloatProvider#codec
    • IntProvider is now an interface from a class
      • CODEC -> IntProviders#CODEC
      • NON_NEGATIVE_CODEC -> IntProviders#NON_NEGATIVE_CODEC
      • POSITIVE_CODEC -> IntProviders#POSITIVE_CODEC
      • codec -> IntProviders#codec
      • validateCodec -> IntProviders#validateCodec
      • getMinValue -> minInclusive
      • getMaxValue -> maxInclusive
      • getType -> codec, not one-to-one
    • IntProviders - All vanilla int providers to register.
    • IntProviderType interface is removed
      • Singleton fields have all been removed, use map codecs in each class instead
      • codec -> IntProvider#codec
  • net.minecraft.world.level.storage.loot.entries now renames CODEC fields to MAP_CODEC
    • LootPoolEntries singleton fields have all been removed
      • The map codecs in each class should be used instead
      • bootstrap - Registers the loot pool entries.
    • LootPoolEntryContainer#getType -> codec, not one-to-one
    • LootPoolEntryType record is removed
  • net.minecraft.world.level.storage.loot.functions now renames CODEC fields to MAP_CODEC
    • LootItemFunction#getType -> codec, not one-to-one
    • LootItemFunctions singleton fields have all been removed
      • The map codecs in each class should be used instead
      • bootstrap - Registers the loot item functions.
    • LootItemFunctionType record is removed
  • net.minecraft.world.level.storage.loot.predicates now renames CODEC fields to MAP_CODEC
    • LootItemCondition#getType -> codec, not one-to-one
    • LootItemConditions singleton fields have all been removed
      • The map codecs in each class should be used instead
      • bootstrap - Registers the loot item conditions.
    • LootItemConditionType record is removed
  • net.minecraft.world.level.storage.loot.providers.nbt now renames CODEC fields to MAP_CODEC
    • LootNbtProviderType record is removed
    • NbtProvider now implements LootContextUser
      • getType -> codec, not one-to-one
    • NbtProviders singleton fields have all been removed
      • The map codecs in each class should be used instead
      • bootstrap - Registers the nbt providers.
    • LootItemConditionType record is removed
  • net.minecraft.world.level.storage.loot.providers.number now renames CODEC fields to MAP_CODEC
    • LootNumberProviderType record is removed
    • NumberProvider#getType -> codec, not one-to-one
    • NumberProviders singleton fields have all been removed
      • The map codecs in each class should be used instead
      • bootstrap - Registers the number providers.
  • net.minecraft.world.level.storage.loot.providers.score now renames CODEC fields to MAP_CODEC
    • LootScoreProviderType record is removed
    • ScoreProvider now implements LootContextUser
      • getType -> codec, not one-to-one
    • ScoreProviders singleton fields have all been removed
      • The map codecs in each class should be used instead
      • bootstrap - Registers the score providers.

Validation Overhaul

The validation handler used to collect and then report problems with data-generated content has been overhauled. This is not, and has never been a replacement for field validation. The validation handler is specifically for more easily handling validation between multiple pieces of information that may not be exposed to a single field, such as whether a loot provider can be used for the given context params.

All validated objects implement either Validatable, or CriterionTriggerInstance specifically for advancement criteria. Both of these methods provide one method: validate, which is used to check the validity of an object. validate takes in a ValidationContext, which essentially holds the ProblemReporter used to collect issues, the current context params, and a reference resolver. CriterionTriggerInstance provides a ValidationContextSource, but this can be transformed to a ValidationContext using one of the context methods, providing the context params to check against. If the specific object cannot be validated, then ValidationContext#reportProblem is called, detailing the specific issue.

// For some object that implements Validatable

@Override
public void validate(ValidationContext ctx) {
    // Check if a specific condition is validated.
    if (this.foo() != this.bar()) {
        // If not, report that there is an issue.
        ctx.reportProblem(() -> "'Foo' does not equal 'bar'.");
    }
}

If the object itself does not have any issues, but rather the specific fields, then the reporter can follow the stack trace while checking the individual elements using one of the ValidationContext#for* methods, performing something similar.

// For some object that implements Validatable
// Let's assume it has a list of children objects.

@Override
public void validate(ValidationContext ctx) {
    for (int i = 0; i < this.children.size(); i++) {
        // Get specific context for child in list
        var childCtx = ctx.forIndexedField("children", i);
        // Check if a specific condition is validated.
        if (this.foo() != this.bar()) {
            // If not, report that there is an issue.
            childCtx.reportProblem(() -> "'Foo' does not equal 'bar'.");
        }
    }
}

Validatable also provides some static utilities for checking other Validatable fields.

// For some object that implements Validatable
// Assume some child object also implements Validatable

@Override
public void validate(ValidationContext ctx) {
    Validatable.validate(ctx, "child", this.child);
}

After Validatable is implemented on all required objects, the validation can then be called depending on where it is used (typically after deserialization or before serialization). The call stack for these is typically the following:

// For some Validatable validatable
// Let's assume we have access to the HolderGetter.Provider provider.
// The parameter itself is optional if not available.

// Create the problem collector and validation context.
// The context params should only include the ones that are being provided.
ProblemReporter reporter = new ProblemCollector.Collector();
ValidationContext ctx = new ValidationContext(reporter, LootContextParamSets.ALL_PARAMS, provider);

// Call the validator
validatable.validate(ctx);

This can also be appended to the end of codecs via Codec#validate:

public record ExampleObject() implements Validatable {
    public static final Codec<ExampleObject> CODEC = MapCodec.unitCodec(
        ExampleObject::new
    ).validate(
        // Supply the validator along with the context params to check against.
        // This method does not have access to the registry provider.
        Validatable.validatorForContext(LootContextParamSets.ALL_PARAMS)
    );

    @Override
    public void validate(ValidationContext ctx) {
        // ...
    }
}
  • net.minecraft.advancements.CriterionTriggerInstance#validate now takes in a ValidationContextSource instead of a CriterionValidator
  • net.minecraft.advancements.criterion
    • ContextAwarePredicate now implements Validatable
    • CriterionValidator -> ValidationContextSource and Validatable
      • Validatable contains the validate* methods
      • ValidationContextSource holds the context and reporters
  • net.minecraft.world.item.enchantment
    • ConditionalEffect now implements Validatable
      • conditionCodec is replaced by calling validate after load
    • TargetedConditionalEffect now implements Validatable
  • net.minecraft.world.level.storage.loot
    • IntRange now implements LootContextUser
      • getReferencedContextParams replaced by validate
    • LootContext$VisitedEntry generic must now extend Validatable
    • LootContextUser now implements Validatable
    • LootDataType generic must now extend Validatable
      • The constructor now takes in a $ContextGetter instead of a $Validator
      • runValidation now takes in the ValidationContextSource instead of a ValidationContext
        • Also has an overload taking in a HolderLookup instead of a key-value pair
      • createSimpleValidator, createLootTableValidator, $Validator replaced by Validatable
      • $ContextGetter - Gets the ContextKeySet for some value.
    • LootPool now implements Validatable
    • LootTable now implements Validatable
    • Validatable - An interface which handles the validation of its instance within the given context.
    • ValidationContext
      • forField - Creates a context for a given field.
      • forIndexedField - Creates a context for a given entry in a list.
      • forMapField - Creates a context for a given key in a map.
      • setContextKeySet is removed
    • ValidationContextSource - The source for the defined context where the validation is taking place.
  • net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer now implements Validatable
  • net.minecraft.world.level.storage.loot.functions
    • SetAttributesFunction$Modifier now implements LootContextUser
    • SetStewEffectFunction$EffectEntry now implements LootContextUser

Datapack Villager Trades

Villager trades has now become a data-generated registry from its original map-based setup. While basic impressions make it seem like that system is more limited, it is actually just as extensible, though in a rather convoluted way because the trades are functionally a loot table itself to determine what MerchantOffers a trader can provide. For the purposes of understanding, this section will go over the basics of the trade rewrite, along with how each previous item listing can be converted to a VillagerTrade.

Understanding the Trade Format

All trades are expressed as VillagerTrades, which at its core determines what a trader wants and what it gives in return. Each trade can also provide modifiers to the item itself or its cost, or whether the specific trade can be made at all with the given condition. Each trade also specifies the number of trades that can be made, how much xp to give, or the price multiple that is multiplied with the user’s reputation. A VillagerTrade is then turned into a MerchantOffer via getOffer, taking in the LootContext, typically with a context param of LootContextParamSets#VILLAGER_TRADE, providing the trader itself (THIS_ENTITY) and its position (ORIGIN).

The trades themselves are within data/<namespace>/villager_trade/<path>. Typically the path contains the profession and level the trade is for, such as examplemod:example_profession/1/example_trade

// For some villager trade 'examplemod:example_profession/1/example_trade'
// JSON at 'data/examplemod/villager_trade/example_profession/1/example_trade.json'
{
    // The stack the trader wants.
    "wants": {
        // The item of the stack.
        "id": "minecraft:apple",
        // A number provider used to determine how much
        // of the item that it wants. Once the count is
        // determined, any additional cost on the `gives`
        // stack (via `ADDITIONAL_TRADE_COST` component)
        // is added to the count before being clamped to
        // the max stack size.
        // If not specified, defaults to 1.
        "count": {
            "type": "minecraft:uniform",
            "min": 1,
            "max": 5
        },
        // Any components that stack should have. The stack
        // must have the exact components specified.
        // If not specified, then no components will be
        // checked, meaning that this is ignored.
        "components": {
            // Map of registry key to component value.
            "minecraft:custom_name": "Apple...?"
        }
    },
    // An additional stack the trader wants.
    // If not specified, the trader only checks `wants`.
    "additional_wants": {
        "id": "minecraft:emerald"
    },
    // The stack template the trader gives in return.
    "gives": {
        // The item of the stack.
        "id": "minecraft:golden_apple",
        // A number [1, 99].
        // If not specified, defaults to 1.
        "count": 1,
        // The components to apply to the stack.
        // If not specified, just applies the default
        // item components.
        "components": {
            "minecraft:custom_name": "Not an Apple"
        }
    },
    // A number provider to determine how many times
    // the trade can be performed by the player before
    // the trader restocks. The value will always be at
    // least 1. 
    // If not specified, defaults to 4.
    "max_uses": {
        "type": "minecraft:uniform",
        "min": 1,
        "max": 20
    },
    // A number provider to determine the price multiplier
    // to apply to the cost of the item based on the player's
    // reputation with the trader and the item demand,
    // calculated from how many times the player has performed
    // the trade. This should generally be a small number as
    // the maximum reputation a user can have per trader is 150,
    // though it's more likely to have a reputation of 25 at most.
    // However, the trade must always have a minimum of one item,
    // even if the reputation discount multiplied with the reputation
    // indicates 100% or more off.
    // If not specified, defaults to 0.
    "reputation_discount": {
        "type": "minecraft:uniform",
        "min": 0,
        "max": 0.05
    },
    // A number provider to determine the amount of experience
    // the player obtains from performing the trade with the trader.
    // This is typically around 5-30 xp for vanilla trades.
    // If not specified, defaults to 1.
    "xp": {
        "type": "minecraft:uniform",
        "min": 10,
        "max": 20
    },
    // A loot item condition that determines whether the
    // trader can provide the trade to the player.
    // If not specified, defaults to always true.
    "merchant_predicate": {
        // This trade can only be performed by villagers
        // from a desert or snow village.
        "condition": "minecraft:entity_properties",
        "entity": "this",
        "predicate": {
            "predicates": {
                "minecraft:villager/variant": [
                    "minecraft:desert",
                    "minecraft:snow"
                ]
            }
        }
    },
    // A list of loot item functions that modify the item
    // offered from `gives` to the player.
    // If not specified, `gives` is not modified.
    "given_item_modifiers": [
        {
            // Chooses a random enchantment from the provided tag
            "function": "minecraft:enchant_randomly",
            // If this is true, the trade cost increases the
            // number of `wants` items required.
            "include_additional_cost_component": true,
            "only_compatible": false,
            "options": "#minecraft:trades/desert_common"
        }
    ],
    // Can either be an enchantment id, such as "minecraft:protection",
    // or a list of enchantment ids, such as ["minecraft:protection", "minecraft:smite", ...],
    // or an enchantment tag, such as "#minecraft:trades/desert_common".
    // When provided, if the `gives` item after modifiers contains an
    // enchantment in this list, then the number of `wants` items required
    // is multiplied by 2.
    // If not specified, does nothing.
    "double_trade_price_enchantments": "#minecraft:trades/desert_common"
}

The Trades of a Trader

Every trader can make many trades, typically choosing from a specified pool known as a TradeSet. Trade sets themselves are a separate datapack registry that consumes VillagerTrades. Each set of trades determines how many trades can be offered and if the same trade can be chosen more than once. The trades that are offered are computed within AbstractVillager#addOffersFromTradeSet, first calling TradeSet#calculateNumberOfTrades to get the number of offers, and then using either AbstractVillager#addOffersFromItemListings or AbstractVillager#addOffersFromItemListingsWithoutDuplicates to choose the offers to use.

Note that if duplicate trades are allowed, there is a potential race condition where if all trades’ merchant_predicates fail, then the offers will loop forever. This is because the method always assumes that there will be one trade that can be made.

The trade sets are within data/<namespace>/trade_set/<path>. Typically the path contains the profession and level the trade is for, such as examplemod:example_profession/level_1.json

// For some trade set 'examplemod:example_profession/level_1'
// JSON at 'data/examplemod/villager_trade/trade_set/level_1.json'
{
    // Can either be a villager trade id, such as "examplemod:example_profession/1/example_trade",
    // or a list of trade ids, such as ["examplemod:example_profession/1/example_trade", "minecraft:farmer/1/wheat_emerald", ...],
    // or an trade tag, such as "#examplemod:example_profession/level_1".
    // This is the set of trades that can be offered by the trader.
    // This should always be a villager trade tag so allow other users
    // to easily add their own trades to a trader.
    "trades": "#examplemod:example_profession/level_1",
    // A number provider that determines the number of offers that can be
    // made by the trader.
    "amount": {
        "type": "minecraft:uniform",
        "min": 1,
        "max": 5
    },
    // Whether the same trade can be used to make multiple offers.
    // If not specified, defaults to false.
    "allow_duplicates": true,
    // An identifier that determines the unique random instance to
    // user when determining the offers.
    // If not specified, uses the level random.
    "random_sequence": "examplemod:example_profession/level_1"
}

Where the villager trade tag could be:

// For some tag 'examplemod:example_profession/level_1'
// JSON at 'data/examplemod/tags/villager_trade/example_profession/level_1.json'
{
    "values": [
        "examplemod:example_profession/1/example_trade"
    ]
}

This also means trades can be easily added to existing trade sets by adding to the associated tag:

// For some tag 'minecraft:farmer/level_1'
// JSON at 'data/minecraft/tags/villager_trade/farmer/level_1.json'
{
    "values": [
        "examplemod:example_profession/1/example_trade"
    ]
}

Meanwhile, adding to a new VillagerProfession is done by mapping the level int to the trade set key in tradeSetsByLevel:

public static final VillagerProfession EXAMPLE = Registry.register(
    BuiltInRegistries.VILLAGER_PROFESSION,
    Identifier.fromNamespaceAndPath("examplemod", "example_profession"),
    new VillagerProfession(
        Component.literal(""),
        p -> true,
        p -> true,
        ImmutableSet.of(),
        ImmutableSet.of(),
        null,
        // A map of profession level to trade set keys
        Int2ObjectMap.ofEntries(
            Int2ObjectMap.entry(
                // The profession level
                1,
                // The trade set id
                ResourceKey.create(Registries.TRADE_SET, Identifier.fromNamespaceAndPath("examplemod", "example_profession/level_1"))
            )
        )
    )
);

Item Listing Conversions

With all this in mind, we can now convert item listings to their new data-generated villager trades.

Emeralds <-> Items

For the following trades:

public static final VillagerTrades.ItemListing ITEM_TO_EMERALD = new VillagerTrades.EmeraldForItems(
    // The item the trader wants.
    Items.WHEAT,
    // The number of items the trader wants.
    20,
    // The maximum number of times the trade can be made
    // before restock.
    16,
    // The amount of experience given for the trade.
    2,
    // The number of emeralds given in return.
    1
);

public static final VillagerTrades.ItemListing EMERALD_TO_ITEM = new VillagerTrades.ItemsForEmeralds(
    // The item the trader will give in return.
    Items.BREAD,
    // The number of emeralds the trader wants.
    1,
    // The number of items the trader will give.
    6,
    // The maximum number of times the trade can be made
    // before restock.
    16,
    // The amount of experience given for the trade.
    1,
    // The price multiplier to apply to the offer, given
    // reputation and demand.
    0.05f
);

Their equivalent would be:

// For some villager trade 'examplemod:item_to_emerald'
// JSON at 'data/examplemod/villager_trade/item_to_emerald.json'
{
    "gives": {
        // The number of emeralds given in return.
        "count": 1,
        "id": "minecraft:emerald"
    },
    // The maximum number of times the trade can be made
    // before restock.
    "max_uses": 16,
    // The price multiplier to apply to the offer, given
    // reputation and demand.
    // `EmeraldForItems` hardcoded this to 0.05
    "reputation_discount": 0.05,
    "wants": {
        // The number of items the trader wants.
        "count": 20,
        // The item the trader wants.
        "id": "minecraft:wheat"
    },
    // The amount of experience given for the trade.
    "xp": 2
}


// For some villager trade 'examplemod:emerald_to_item'
// JSON at 'data/examplemod/villager_trade/emerald_to_item.json'
{
    "gives": {
        // The number of items the trader will give.
        "count": 6,
        // The item the trader will give in return.
        "id": "minecraft:bread"
    },
    // The maximum number of times the trade can be made
    // before restock.
    "max_uses": 16,
    // The price multiplier to apply to the offer, given
    // reputation and demand.
    "reputation_discount": 0.05,
    "wants": {
        "id": "minecraft:emerald",
        // The number of emeralds the trader wants.
        "count": 1
    },
    // The amount of experience given for the trade.
    "xp": 1
}

Items and Emeralds -> Items

For the following trade:

public static final VillagerTrades.ItemListing ITEM_EMERALD_TO_ITEM = new VillagerTrades.ItemsAndEmeraldsToItems(
    // The item the trader wants.
    Items.COD,
    // The number of items the trader wants. 
    6,
    // The number of emeralds the trader additionally wants.
    1,
    // The item the trader will give in return.
    Items.COOKED_COD,
    // The number of items the trader will give.
    6,
    // The maximum number of times the trade can be made
    // before restock.
    16,
    // The amount of experience given for the trade.
    1,
    // The price multiplier to apply to the offer, given
    // reputation and demand.
    0.05f
);

The equivalent would be:

// For some villager trade 'examplemod:item_emerald_to_item'
// JSON at 'data/examplemod/villager_trade/item_emerald_to_item.json'
{
    // The emeralds the trader additionally wants.
    "additional_wants": {
        "id": "minecraft:emerald",
    },
    "gives": {
        // The number of items the trader will give.
        "count": 6,
        // The item the trader will give in return.
        "id": "minecraft:cooked_cod"
    },
    // The maximum number of times the trade can be made
    // before restock.
    "max_uses": 16,
    // The price multiplier to apply to the offer, given
    // reputation and demand.
    "reputation_discount": 0.05,
    "wants": {
        // The number of items the trader wants. 
        "count": 6,
        // The item the trader wants.
        "id": "minecraft:cod"
    },
    // The amount of experience given for the trade.
    "xp": 1
}

Emeralds -> Dyed Armor

For the following trade:

public static final VillagerTrades.ItemListing EMERALD_TO_DYED_ARMOR = new VillagerTrades.DyedArmorForEmeralds(
    // The item the trader will give in return and dye.
    Items.LEATHER_HELMET,
    // The number of emeralds the trader wants.
    5,
    // The maximum number of times the trade can be made
    // before restock.
    12,
    // The amount of experience given for the trade.
    5
);

The equivalent would be:

// For some villager trade 'examplemod:emerald_to_dyed_armor'
// JSON at 'data/examplemod/villager_trade/emerald_to_dyed_armor.json'
{
    "given_item_modifiers": [
        {
            // Sets the random dye(s) on the armor.
            "function": "minecraft:set_random_dyes",
            "number_of_dyes": {
                "type": "minecraft:sum",
                "summands": [
                    1.0,
                    {
                        "type": "minecraft:binomial",
                        "n": 2.0,
                        "p": 0.75
                    }
                ]
            }
        },
        {
            // Checks that the dye was successfully applied
            // to the item.
            "function": "minecraft:filtered",
            "item_filter": {
                "items": "minecraft:leather_helmet",
                "predicates": {
                    "minecraft:dyed_color": {}
                }
            },
            // If it fails, discards the offer.
            "on_fail": {
                "function": "minecraft:discard"
            }
        }
    ],
    "gives": {
        "count": 1,
        // The item the trader will give in return and dye.
        "id": "minecraft:leather_helmet"
    },
    // The maximum number of times the trade can be made
    // before restock.
    "max_uses": 12,
    // The price multiplier to apply to the offer, given
    // reputation and demand.
    "reputation_discount": 0.05,
    "wants": {
        // The number of emeralds the trader wants.
        "count": 5,
        "id": "minecraft:emerald"
    },
    // The amount of experience given for the trade.
    "xp": 5
}

Emeralds -> Enchanted Item

For the following trade:

public static final VillagerTrades.ItemListing EMERALD_TO_ENCHANTED_BOOK = new VillagerTrades.EnchantBookForEmeralds(
    // The amount of experience given for the trade.
    30,
    // The minimum level used when selecting the stored enchantments on the book.
    3,
    // The maximum level used when selecting the stored enchantments on the book.
    3,
    // A tag containing the list of available enchantments to select from for the book.
    EnchantmentTags.TRADES_DESERT_SPECIAL
);

public static final VillagerTrades.ItemListing EMERALD_TO_ENCHANTED_ITEM = new VillagerTrades.EnchantedItemForEmeralds(
    // The item the trader will give in return and try to enchant.
    Items.FISHING_ROD,
    // The base number of emeralds the trader wants.
    3,
    // The maximum number of times the trade can be made
    // before restock.
    3,
    // The amount of experience given for the trade.
    10,
    // The price multiplier to apply to the offer, given
    // reputation and demand.
    0.2f
);

The equivalent would be:

// For some villager trade 'examplemod:emerald_to_enchanted_book'
// JSON at 'data/examplemod/villager_trade/emerald_to_enchanted_book.json'
{
    // The trader expects a book to write the enchantment to.
    "additional_wants": {
        "id": "minecraft:book"
    },
    // Trade cost for emeralds increased when in the double trade price
    // tag.
    "double_trade_price_enchantments": "#minecraft:double_trade_price",
    "given_item_modifiers": [
        {
            "function": "minecraft:enchant_with_levels",
            "include_additional_cost_component": true,
            "levels": {
                "type": "minecraft:uniform",
                // The minimum level used when selecting the stored enchantments on the book.
                "min": 3,
                // The maximum level used when selecting the stored enchantments on the book.
                "max": 3
            },
            // The list of available enchantments to select from for the book.
            "options": [
                "minecraft:efficiency"
            ]
        },
        {
            // Make sure the enchantment was added successfully with the given level.
            "function": "minecraft:filtered",
            "item_filter": {
                "items": "minecraft:enchanted_book",
                "predicates": {
                    "minecraft:stored_enchantments": [
                        {
                            "levels": {
                                // The minimum level used when selecting the stored enchantments on the book.
                                "min": 3,
                                // The maximum level used when selecting the stored enchantments on the book.
                                "max": 3
                            }
                        }
                    ]
                }
            },
            // Discard on failure
            "on_fail": {
                "function": "minecraft:discard"
            }
        }
    ],
    // The trader gives the enchanted book.
    "gives": {
        "count": 1,
        "id": "minecraft:enchanted_book"
    },
    // The maximum number of times the trade can be made
    // before restock was hardcoded to 12.
    "max_uses": 12,
    // The price multiplier to apply to the offer, given
    // reputation and demand, hardcoded to 0.2.
    "reputation_discount": 0.2,
    "wants": {
        "count": {
            "type": "minecraft:sum",
            "summands": [
                // A hardcoded computation based on the min and max
                // level of the enchantment.
                11.0,
                {
                    "type": "minecraft:uniform",
                    "max": 35.0,
                    "min": 0.0
                }
            ]
        },
        "id": "minecraft:emerald"
    },
    // The amount of experience given for the trade.
    "xp": 30
}

// For some villager trade 'examplemod:emerald_to_enchanted_item'
// JSON at 'data/examplemod/villager_trade/emerald_to_enchanted_item.json'
{
    "given_item_modifiers": [
        {
            // Applies the enchantment to the given equipment.
            "function": "minecraft:enchant_with_levels",
            "include_additional_cost_component": true,
            "levels": {
                "type": "minecraft:uniform",
                "max": 20,
                "min": 5
            },
            "options": "#minecraft:on_traded_equipment"
        },
        {
            // Checks to make sure the enchantment was applied.
            "function": "minecraft:filtered",
            "item_filter": {
                "items": "minecraft:fishing_rod",
                "predicates": {
                    "minecraft:enchantments": [
                        {}
                    ]
                }
            },
            // On fail, give nothing.
            "on_fail": {
                "function": "minecraft:discard"
            }
        }
    ],
    "gives": {
        "count": 1,
        // The item the trader will give in return and try to enchant.
        "id": "minecraft:fishing_rod"
    },
    // The maximum number of times the trade can be made
    // before restock.
    "max_uses": 3,
    // The price multiplier to apply to the offer, given
    // reputation and demand.
    "reputation_discount": 0.2,
    "wants": {
        "count": {
            "type": "minecraft:sum",
            "summands": [
                // The base number of emeralds the trader wants.
                3,
                {
                    // The variation based on the enchantment level.
                    // Originally, this would be the value used in the
                    // item function, but since they are now isolated,
                    // these values could differ.
                    "type": "minecraft:uniform",
                    "max": 20,
                    "min": 5
                }
            ]
        },
        "id": "minecraft:emerald"
    },
    // The amount of experience given for the trade.
    "xp": 10
}

Items and Emeralds -> Potion Effect Item

For the following trade:

public static final VillagerTrades.ItemListing EMERALD_TO_SUSPICIOUS_STEW = new VillagerTrades.SuspiciousStewForEmerald(
    // The effect applied by the suspicious stew.
    MobEffects.NIGHT_VISION,
    // The number of ticks the effect should be active for.
    100,
    // The amount of experience given for the trade.
    15
);

public static final VillagerTrades.ItemListing ITEM_EMERALD_TO_TIPPED_ARROW = new VillagerTrades.TippedArrowForItemsAndEmeralds(
    // The item the trader additionally wants.
    Items.ARROW,
    // The number of items the trader additionally wants.
    5,
    // The item the trader will give in return.
    Items.TIPPED_ARROW,
    // The number of items the trader will give.
    5,
    // The number of emeralds the trader wants.
    2,
    // The maximum number of times the trade can be made
    // before restock.
    12,
    // The amount of experience given for the trade.
    30
);

The equivalent would be:

// For some villager trade 'examplemod:emerald_to_suspicious_stew'
// JSON at 'data/examplemod/villager_trade/emerald_to_suspicious_stew.json'
{
    "given_item_modifiers": [
        {
            "effects": [
                {
                    // The effect applied by the suspicious stew.
                    "type": "minecraft:night_vision",
                    // The number of ticks the effect should be active for.
                    "duration": 100
                }
                // Vanilla merges all suspicious stew offers
                // into one since this function picks one
                // stew effect at random.
            ],
            "function": "minecraft:set_stew_effect"
        }
    ],
    "gives": {
        "count": 1,
        "id": "minecraft:suspicious_stew"
    },
    // The maximum number of times the trade can be made
    // before restock, hardcoded to 12.
    "max_uses": 12,
    // The price multiplier to apply to the offer, given
    // reputation and demand, hardcoded to 0.05.
    "reputation_discount": 0.05,
    "wants": {
        "id": "minecraft:emerald"
    },
    // The amount of experience given for the trade.
    "xp": 15
}

// For some villager trade 'examplemod:item_emerald_to_tipped_arrow'
// JSON at 'data/examplemod/villager_trade/item_emerald_to_tipped_arrow.json'
{
    "additional_wants": {
        // The number of items the trader additionally wants.
        "count": 5,
        // The item the trader additionally wants.
        "id": "minecraft:arrow"
    },
    "given_item_modifiers": [
        {
            // Applies a random potion effect from the tradable potions.
            // Original implementation just picked any potion at random.
            "function": "minecraft:set_random_potion",
            "options": "#minecraft:tradeable"
        }
    ],
    "gives": {
        // The number of items the trader will give.
        "count": 5,
        // The item the trader will give in return.
        "id": "minecraft:tipped_arrow"
    },
    // The maximum number of times the trade can be made
    // before restock.
    "max_uses": 12,
    // The price multiplier to apply to the offer, given
    // reputation and demand, hardcoded to 0.05.
    "reputation_discount": 0.05,
    "wants": {
        // The number of emeralds the trader wants.
        "count": 2,
        "id": "minecraft:emerald"
    },
    // The amount of experience given for the trade.
    "xp": 30
}

Emeralds -> Treasure Map

For the following trade:

public static final VillagerTrades.ItemListing EMERALD_TO_TREASURE_MAP = new VillagerTrades.TreasureMapForEmeralds(
    // The number of emeralds the trader wants.
    8,
    // A tag containing a list of treasure structures to find the nearest of.
    StructureTags.ON_TAIGA_VILLAGE_MAPS,
    // The translation key of the map name.
    "filled_map.village_taiga",
    // The icon used to decorate the treasure location found on the map.
    MapDecorationTypes.TAIGA_VILLAGE,
    // The maximum number of times the trade can be made
    // before restock.
    12,
    // The amount of experience given for the trade.
    5
);

The equivalent would be:

// For some villager trade 'examplemod:emerald_to_treasure_map'
// JSON at 'data/examplemod/villager_trade/emerald_to_treasure_map.json'
{
    "additional_wants": {
        // An item the trader additionally wants, hardcoded to compass.
        "id": "minecraft:compass"
    },
    "given_item_modifiers": [
        {
            // Finds a treasure structure to display on the map.

            // The icon used to decorate the treasure location found on the map.
            "decoration": "minecraft:village_taiga",
            // A tag containing a list of treasure structures to find the nearest of.
            "destination": "minecraft:on_taiga_village_maps",
            "function": "minecraft:exploration_map",
            "search_radius": 100
        },
        {
            // Sets the name of the map.

            "function": "minecraft:set_name",
            "name": {
                // The translation key of the map name.
                "translate": "filled_map.village_taiga"
            },
            "target": "item_name"
        },
        {
            // Check to make sure a structure was found.

            "function": "minecraft:filtered",
            "item_filter": {
                "items": "minecraft:filled_map",
                "predicates": {
                    "minecraft:map_id": {}
                }
            },
            "on_fail": {
                "function": "minecraft:discard"
            }
        }
    ],
    "gives": {
        "count": 1,
        // Returns a map filled with the treasure location.
        "id": "minecraft:map"
    },
    // The maximum number of times the trade can be made
    // before restock.
    "max_uses": 12,
    // The price multiplier to apply to the offer, given
    // reputation and demand, hardcoded to 0.05.
    "reputation_discount": 0.05,
    "wants": {
        // The number of emeralds the trader wants.
        "count": 8,
        "id": "minecraft:emerald"
    },
    // The amount of experience given for the trade.
    "xp": 5
}

Villager Variants

Some traders would provide different options depending on the villager type it was as one giant map of item listings. Now, each type has its own individual villager trade, using a merchant_predicate to check whether the offer can be made to the specific villager type:

// For some villager trade 'examplemod:villager_type_item'
// JSON at 'data/examplemod/villager_trade/villager_type_item.json'
{
    // ...
    "merchant_predicate": {
        // Check the entity.
        "condition": "minecraft:entity_properties",
        "entity": "this",
        "predicate": {
            "predicates": {
                // Villager type must be desert for this trade to be chosen.
                "minecraft:villager/variant": "minecraft:desert"
            }
        }
    },
    // ...
}
  • net.minecraft.core.registries.Registries
    • TRADE_SET - A key to the registry holding a list of trades.
    • VILLAGER_TRADE - A key to the registry holding a single trade.
  • net.minecraft.tags.VillagerTradeTags - Tags for villager trades.
  • net.minecraft.world.entity.npc.villager
    • AbstractVillager#addOffersFromItemListings -> addOffersFromTradeSet, taking in a key for the trade set rather than the $ItemListings and number of offers; not one-to-one
    • VillagerProfession now takes in a map of trader level to TradeSet
      • getTrades - Returns the trades set key for the given level.
    • VillagerTrades has been split into many different classes and implementations
      • TRADES, EXPERIMENTAL_TRADES, WANDERING_TRADER_TRADES is now represented by the VillagerProfession#tradeSetsByLevel
        • As they are now datapack entries, they are stored in their respective datapacks
        • TRADES, EXPERIMENTAL_TRADES are represented by data/minecraft/trade_set/<profession>/*
        • WANDERING_TRADER_TRADES are represented by data/minecraft/trade_set/wandering_trader/*
      • $DyedArmorForEmeralds -> VillagerTrades#dyedItem, addRandomDye; not one-to-one
      • $EmeraldForItems -> VillagerTrade, not one-to-one
      • $EmeraldsForVillagerTypeItem -> VillagerTrades#registerBoatTrades, see usage, not one-to-one
      • $EnchantBookForEmeralds -> VillagerTrades#enchantedBook, not one-to-one
      • $EnchantedItemForEmeralds -> VillagerTrades#enchantedItem, not one-to-one
      • $ItemListing -> VillagerTrade
      • $ItemsAndEmeraldsToItems -> VillagerTrade with additionalWants
      • $ItemsForEmeralds -> VillagerTrade, not one-to-one
      • $SuspiciousStewForEmerald -> VillagerTrade with SetStewEffectFunction
      • $TippedArrowForItemsAndEmeralds -> VillagerTrade with SetRandomPotionFunction
      • $TreasureMapForEmeralds -> VillagerTrades$VillagerExplorerMapEntry, see usage, not one-to-one
      • $TypeSpecificTrade -> VillagerTrades#villagerTypeRestriction, villagerTypeHolderSet; not one-to-one
  • net.minecraft.world.item.enchantment.providers.TradeRebalanceEnchantmentProviders interface is removed
    • Replaced by TradeRebalanceVillagerTrades, TradeRebalanceRegistries
  • net.minecraft.world.item.trading
    • TradeCost - An ItemStack that is being traded to some trader.
    • TradeRebalanceVillagerTrades - All trades part of the trade rebalance datapack.
    • TradeSet - A set of trades that can be performed by a trader at some level.
    • TradeSets - All vanilla trades sets for some trader at some level.
    • VillagerTrade - A trade between the trader and the player.
    • VillagerTrades - All vanilla trades.
  • net.minecraft.world.level.storage.loot.parameters.LootContextParamSets#VILLAGER_TRADE - A loot context when a villager trade is taking place, containing the trade origin and the trading entity.

Level#random field now protected

The Level#random field is now protected instead of public. As such, uses should transition to using the public getRandom method.

// For some Level level
RandomSource random = level.getRandom();
  • net.minecraft.world.level.Level#random field is now protected instead of public
    • Use getRandom method instead

Data Component Initializers

Data components have begun their transition from being moved off the raw object and onto the Holder itself. This is to properly handle objects that are not available during construction, such as datapack registry objects for items. Currently, this is only implemented for Items, but the system allows for any registry object, given its wrapped-holder, to store some defined data components.

Data components are attached to their holders through the DataComponentInitializers. During object construction, DataComponentInitializers#add is called, providing the ResourceKey identifier of the registry object, along with a DataComponentInitializers$Initializer. The initializer takes in three parameters: the builder for the component map, the full registries HolderLookup$Provider, and the key passed to DataComponentInitializers#add. The initializer functions like a consumer, also allowing for additional initializers to be chained via $Initializer#andThen or to easily add a component via $Initializer#add.

// For some custom registry object
public ExampleObject(ResourceKey<ExampleObject> id) {
    // Register the data component initializer
    BuiltInRegistries.DATA_COMPONENT_INITIALIZERS.add(
        // The identifier for the registry object
        id,
        // The initializer function, taking in a component builder,
        // the registries context, and the id
        (components, context, key) -> components
            .set(DataComponents.MAX_DAMAGE, 1)
            .set(DataComponents.DAMAGE_TYPE, context.getOrThrow(DamageTypes.SPEAR))
    );
}

From there, the data components are initialized or reinitialized whenever ReloadableServerResources#loadResources is called (on datapack reload). The datapack objects are loaded first, then the components are set on the Holder$References. From there, the components can be gathered via Holder#components.

// For some Holder<ExampleObject> EXAMPLE_HOLDER
DataComponentMap components = EXAMPLE_HOLDER.components();

Items

Since components are now initialized during resource reload, Item$Properties provides two methods to properly delay component initialization until such data components are loaded: delayedComponent and delayedHolderComponent. delayedComponent takes in the component type and a function that takes in the HolderLookup$Provider and returns the component value. delayedHolderCOmponent delegates to delayedComponent, taking in a ResourceKey and setting the registry object as the component value.

public static final Item EXAMPLE_ITEM = new Item(
    new Item.Properties()
        .delayedComponent(
            // The component type whose construction
            // should be lazily initialized.
            DataComponents.JUKEBOX_PLAYABLE,
            // A function that takes in the registries
            // and returns the component value.
            context -> new JukeboxPlayable(context.getOrThrow(
                JukeboxSongs.THIRTEEN
            ))
        )
        .delayedHolderComponent(
            // The component type which has a
            // holder value type.
            DataComponents.DAMAGE_TYPE
            // The resource key for a registry
            // object of the associated holder
            // generic type.
            DamageTypes.SPEAR
        )
        // ...
);

Recipes

Since data components now hold the true values from being lazily initialized after resource reload, Recipe#assemble no longer takes in the HolderLookup$Provider. Instead, it assumes that the recipe has all the required data stored passed into the recipe, either on a stack or directly.

  • net.minecraft.core
    • Holder
      • areComponentsBound - Whether the components have been bound to the holder.
      • components - The components of the object stored on the holder.
      • direct, $Direct now can take in the DataComponentMap
      • $Reference#bindComponents - Stores the components on the holder reference.
    • Registry#componentLookup - Gets the lookup of component to holders.
    • WritableRegistry#bindTag -> bindTags, now taking in a map of keys to holder lists instead of one mapping
  • net.minecraft.core.component
    • DataComponentInitializers - A class that handles initializing the data components for component-attached objects.
    • DataComponentLookup - A lookup that maps the component type to the holders that use it.
    • DataComponentMap$Builder#addValidator - Adds a validator for the components on the object.
    • DataComponentPatch
      • get now takes in a DataComponentGetter and returns the raw component value
      • $Builder#set now has an overload that takes in an iterable of TypedDataComponents
    • DataComponents
      • DAMAGE_TYPE now is a holder-wrapped DamageType instead of EitherHolder-wrapped
      • PROVIDES_TRIM_MATERIAL now is a holder-wrapped TrimMaterial instead of ProvidesTrimMaterial
      • CHICKEN_VARIANT now is a holder-wrapped ChickenVariant instead of EitherHolder-wrapped
      • ZOMBIE_NAUTILUS_VARIANT now is a holder-wrapped ZombieNautilusVariant instead of EitherHolder-wrapped
      • PROVIDES_BANNER_PATTERNS is now a HolderSet instead of a TagKey
  • net.minecraft.core.registries
    • BuiltInRegistries#DATA_COMPONENT_INITIALIZERS - A list of data components attached to registry entries.
    • Registries#componentsDirPath - The path directory for the components in a registry.
  • net.minecraft.data.PackOutput#createRegistryComponentPathProvider - The path provider for the components registry report.
  • net.minecraft.data.info.ItemListReport -> RegistryComponentsReport, not one-to-one
  • net.minecraft.resources
    • NetworkRegistryLoadTask - A load task that handles registering registry objects and tags from the network, or else from a resource.
    • RegistryDataLoader
      • $PendingRegistration -> RegistryLoadTask$PendingRegistration
      • $RegistryData now takes in a RegistryValidator instead of a boolean
      • $RegistryLoadTask -> RegistryLoadTask, not one-to-one
    • RegistryValidator - An interface that validates the entries in a registry, storing all errors in a map.
    • ResourceManagerRegistryLoadTask - A load task that handles registering registry objects and tags from the local resource manager.
  • net.minecraft.server.ReloadableServerResources#updateStaticRegistryTags -> updateComponentsAndStaticRegistryTags, not one-to-one
  • net.minecraft.world.item
    • EitherHolder class is removed
    • Item
      • CODEC_WITH_BOUND_COMPONENTS - An item codec that validates that the components are bound.
      • $Properties
        • delayedComponent - Sets the component lazily, providing the HolderLookup$Provider to get any dynamic elements.
        • delayedHolderComponent - Sets the component lazily for some holder-wrapped registry object.
    • ItemStack#validateComponents is now private from public
    • JukeboxPlayable now holds a holder-wrapped JukeboxSong instead of an EitherHolder-wrapped variant
    • JukeboxSong#fromStack no longer takes in the HolderLookup$Provider
    • SpawnEggItem
      • spawnEntity is now static
      • byId now returns an optional holder-wrapped Item instead of a SpawnEggItem
      • eggs is removed
      • getType is now static
      • spawnOffspringFromSpawnEgg is now static
  • net.minecraft.world.item.component
    • BlocksAttacks now holds an optional holder set-wrapped DamageType instead of a TagKey
    • DamageResistant now holds a holder set DamageType instead of a TagKey
    • InstrumentComponent now holds a holder-wrapped Instrument instead of an EitherHolder-wrapped variant
      • unwrap is removed
    • ProvidesTrimMaterial now holds a holder-wrapped TrimMaterial instead of an EitherHolder-wrapped variant
  • net.minecraft.world.item.crafting
    • Recipe#assemble no longer takes in the HolderLookup$Provider
    • SmithingTrimRecipe#applyTrim no longer takes in the HolderLookup$Provider
  • net.minecraft.world.item.equipment.trim.TrimMaterials#getFromIngredient is removed
  • net.minecraft.world.level.storage.loot.functions.SetInstrumentFunction, #setInstrumentOptions now takes in a holder set-wrapped Instrument instead of a TagKey
  • net.minecraft.world.timeline.Timeline#validateRegistry - Validates that each time marker was only defined once.

Item Instances and Stack Templates

ItemStacks now have an immutable instance known as an ItemStackTemplate. Similar to the ItemStack, it contains the holder-wrapped Item, the number of items it represents, and a DataComponentPatch of the components to apply to the stack. The template can be transformed to a stack via create, or apply if adding additional data components. An ItemStack can likewise be turned into a template via ItemStackTemplate#fromNonEmptyStack. Templates are now used in place of ItemStacks were immutability is required (e.g., advancements, recipes, etc.). They provide a regular CODEC, a MAP_CODEC, and a STREAM_CODEC for network communication.

ItemStackTemplate apple = new ItemStackTemplate(
    // The item of the stack
    Items.APPLE.builtInRegistryHolder(),
    // The number of items held
    5,
    // The components applied to the stack
    DataComponentPatch.builder()
        .set(DataComponents.ITEM_NAME, Component.literal("Apple?"))
        .build()
);

// Turn the template into a stack
ItemStack stack = apple.create();

// Creating a template from a non-empty stack
ItemStackTemplate fromStack = ItemStackTemplate.fromNonEmptyStack(stack);

To help standardize accessing the general components between the two, both the template and the stack implement ItemInstance, which provides access to the standard holder method checks, the count, and the DataComponentGetter. The common interface also means that if it doesn’t matter whether the stack is mutable or not, then the ItemInstance can be used as the type.

// Both are item instances
ItemInstance stack = new ItemStack(Items.APPLE);
ItemInstance template = new ItemStackTemplate(Items.APPLE);

// Get the holder or check something
Holder<Item> item = stack.typeHolder();
template.is(Items.APPLE);

// Get the number of items in the stack or template
int stackCount = stack.count();
int templateCount = template.count();

// Get the component values
Identifier stackModel = stack.get(DataComponents.ITEM_MODEL);
Identifier templateModel = template.get(DataComponents.ITEM_MODEL);

Recipe Builders

Due to the addition of ItemStackTemplates, RecipeBuilders have changed slightly in their implementation. First, the builder no longer stores an Item for the result, instead defining the defaultId as the resource key recipe. As such, this allows for a more clear method of defining custom recipes that do not export an Item.

Of course, the change to this new format just has defaultId return RecipeBuilder#getDefaultRecipeId with the ItemInstance (either a stack or template), like so:

public class ExampleRecipeBuilder implements RecipeBuilder {

    // The result of the recipe
    private final ItemStackTemplate result;

    public ExampleRecipeBuilder(ItemStackTemplate result) {
        this.result = result;
    }

    @Override
    public ResourceKey<Recipe<?>> defaultId() {
        // Get the default recipe id from the result
        return RecipeBuilder.getDefaultRecipeId(this.result);
    }

    // Implement everything else below
    // ...
}
  • net.minecraft.advancements
    • Advancement$Builder#display now takes in an ItemStackTemplate instead of an ItemStack
    • DisplayInfo now takes in an ItemStackTemplate instead of an ItemStack
      • getIcon now returns an ItemStackTemplate instead of an ItemStack
  • net.minecraft.advancements.criterion
    • AnyBlockInteractionTrigger#trigger now takes in an ItemInstance instead of an ItemStack
    • ItemPredicate now implements a predicate of ItemInstance instead of ItemStack
    • ItemUsedOnLocationTrigger#trigger now takes in an ItemInstance instead of an ItemStack
  • net.minecraft.client.particle.BreakingItemParticle$ItemParticleProvider#getSprite now takes in an ItemStackTemplate instead of an ItemStack
  • net.minecraft.commands.arguments.item
    • ItemInput is now a record
      • serialize is removed
      • createItemStack no longer takes in the boolean to check the size
    • ItemParser#parse now returns an ItemResult instead of an ItemParser$ItemResult
      • $ItemResult merged into ItemInput
  • net.minecraft.core.component.predicates
    • BundlePredicate now deals with an iterable of ItemInstances rather than ItemStacks
    • ContainerPredicate now deals with an iterable of ItemInstances rather than ItemStacks
  • net.minecraft.core.particles.ItemParticleOption now takes in an ItemStackTemplate instead of an ItemStack
    • There is also an overload for a regular Item
    • getItem now returns an ItemStackTemplate instead of an ItemStack
  • net.minecraft.data.recipes
    • RecipeBuilder
      • getResult is removed
      • defaultId - The default identifiers for the recipe made with this builder.
      • getDefaultRecipeId now takes in an ItemInstance instead of an ItemLike
    • RecipeProvider
      • oreSmelting, oreBlasting now take in a CookingBookCategory
      • oreCooking no longer takes in the RecipeSerializer and now takes in a CookingBookCategory
      • cookRecipes, simpleCookingRecipe no longer take in the RecipeSerializer
      • shapeless now takes in an ItemStackTemplate instead of an ItemStack
    • ShapedRecipeBuilder now takes in an ItemStackTemplate for the result, with the ItemLike moved to an overload
      • Both constructors are private
    • ShapelessRecipeBuilder now takes in an ItemStackTemplate for the result instead of an ItemStack
    • SimpleCookingRecipeBuilder now takes in an ItemStackTemplate for the result, with the ItemLike moved to an overload
      • generic no longer takes in the RecipeSerializer and now takes in a CookingBookCategory
      • blasting, smelting now take in a CookingBookCategory
    • SingleItemRecipeBuilder now takes in an ItemStackTemplate for the result, with the ItemLike moved to an overload
      • The ItemStackTemplate constructor is made private
    • SmithingTransformRecipeBuilder now takes in an ItemStackTemplate for the result instead of an Item
    • TransmuteRecipeBuilder now takes in an ItemStackTemplate for the result instead of a Holder<Item>
      • The constructor is private
      • transmute now has an overload that takes in the ItemStackTemplate for the result
      • addMaterialCountToOutput, setMaterialCount - Handles the size of the result stack based on the number of materials used.
  • net.minecraft.network.chat.HoverEvent$ShowItem now takes in an ItemStackTemplate instead of an ItemStack
  • net.minecraft.server.dialog.body.ItemBody now takes in an ItemStackTemplate instead of an ItemStack
  • net.minecraft.world.entity.LivingEntity
    • dropFromEntityInteractLootTable now takes in an ItemInstance instead of an ItemStack for the tool
    • dropFromShearingLootTable now takes in an ItemInstance instead of an ItemStack for the tool
  • net.minecraft.world.item
    • BundleItem#getSelectedItemStack -> getSelectedItem, now returning an ItemStackTemplate instead of an ItemStack
    • Item
      • getCraftingRemainder now returns an ItemStackTemplate instead of an ItemStack
      • $Properties#craftRemainder now has an overload that takes in the ItemStackTemplate
    • ItemInstance - A typed item instance that can query the item, the size, and its components.
    • ItemStack now implements ItemInstance
      • SINGLE_ITEM_CODEC, STRICT_CODEC, STRING_SINGLE_ITEM_CODEC, SIMPLE_ITEM_CODEC are removed
      • getMaxStackSize -> ItemInstance#getMaxStackSize
    • ItemStackTemplate - A record containing the immutable components of a stack: the item, count, and components.
  • net.minecraft.world.item.component
    • BundleContents now takes in a list of ItemStackTemplates instead of ItemStacks
      • items now returns a list of ItemStackTemplates instead of an iterable of ItemStacks
      • itemsCopy is removed
      • getSelectedItem - Returns the stack template of the selected item, or null if no item is selected.
    • ChargedProjectile is now a record
      • The constructor takes in a list of ItemStackTemplates instead of ItemStacks
      • of -> ofNonEmpty
      • getItems -> itemCopies
    • ItemContainerContents
      • stream -> allItemsCopyStream
      • nonEmptyStream -> nonEmptyItemCopyStream
      • nonEmptyItems, nonEmptyItemsCopy -> nonEmptyItems, now returning an iterable of ItemStackTemplates instead of ItemStacks
    • UseRemainder now takes in an ItemStackTemplate instead of an ItemStack
  • net.minecraft.world.item.crafting
    • AbstractCookingRecipe now takes in an ItemStackTemplate instead of an ItemStack for the result
      • $Factory#create now takes in an ItemStackTemplate instead of an ItemStack for the result
    • BlastingRecipe now takes in an ItemStackTemplate instead of an ItemStack for the result
    • CampfireCookingRecipe now takes in an ItemStackTemplate instead of an ItemStack for the result
    • ShapedRecipe now takes in an ItemStackTemplate instead of an ItemStack for the result
    • ShapelessRecipe now takes in an ItemStackTemplate instead of an ItemStack for the result
    • SingleItemRecipe now takes in an ItemStackTemplate instead of an ItemStack for the result
      • result now returns an ItemStackTemplate instead of an ItemStack
      • $Factory#create now takes in an ItemStackTemplate instead of an ItemStack for the result
    • SmeltingRecipe now takes in an ItemStackTemplate instead of an ItemStack for the result
    • SmithingTransformRecipe now takes in an ItemStackTemplate instead of an ItemStack for the result
    • SmokingRecipe now takes in an ItemStackTemplate instead of an ItemStack for the result
    • StonecutterRecipe now takes in an ItemStackTemplate instead of an ItemStack for the result
    • TransmuteRecipe now takes in an ItemStackTemplate instead of an ItemStack for the result
    • TransmuteResult -> ItemStackTemplate, not one-to-one
      • isResultUnchanged is removed
      • apply -> TransmuteRecipe#createWithOriginalComponents, not one-to-one
  • net.minecraft.world.item.crafting.display.SlotDisplay$ItemStackSlotDisplay now takes in an ItemStackTemplate instead of an ItemStack
  • net.minecraft.world.item.enchantment.EnchantmentHelper#getItemEnchantmentLevel now takes in an ItemInstance instead of an ItemStack
  • net.minecraft.world.level.block.Block
    • dropFromBlockInteractLootTable now takes in an ItemInstance instead of an ItemStack
    • getDrops now takes in an ItemInstance instead of an ItemStack
  • net.minecraft.world.level.block.entity.DecoratedPotBlockEntity#createdDecoratedPotItem -> createdDecoratedPotInstance
    • createDecoratedPotTemplate creates the ItemStackTemplate instead of the ItemStack
  • net.minecraft.world.level.storage.loot
    • LootContext$ItemStackTarget now implements an ItemInstance generic for the argument getter instead of the ItemStack
    • LootContextArg$ArgCodecBuilder#anyItemStack now requires a function taking in an ItemInstance context key instead of an ItemStack context key
  • net.minecraft.world.level.storage.loot.parameters.LootContextParams#TOOL is now an ItemInstance context key instead of an ItemStack context key

Serializer Records and Recipe Info

Recipes have been slightly reworked in their implementation. First, RecipeSerializer is now a record taking in the MapCodec and StreamCodec used to serialize and deserialize the recipe. As such, Serializer classes have been removed in their entirety, replaced with providing the codecs to the record during registration:

// Assume some ExampleRecipe implements Recipe
// We'll say there's also only one INSTANCE
public static final RecipeSerializer<ExampleRecipe> EXAMPLE_RECIPE = new RecipeSerializer<>(
    // The map codec for reading the recipe to/from disk.
    MapCodec.unit(INSTANCE),
    // The stream codec for reading the recipe to/from the network.
    StreamCodec.unit(INSTANCE)
);

Second, some common data regarding the recipe settings and book information have been sectioned into separate objects. These objects are passed into the recipe as part of the constructor and used to more cleanly handle similar implementations across all recipes.

Vanilla provides four of these common object classes, split into two separate categories. Recipe$CommonInfo is used for general recipe settings. Meanwhile, Recipe$BookInfo is used for recipe book information, with CraftingRecipe$CraftingBookInfo for crafting recipes, and AbstractCookingRecipe$CookingBookInfo for cooking recipes (e.g., smelting, blasting, etc.). The common object classes provide methods for constructing the codecs as required, which can then be passed into the relevant recipe codec.

These classes are typically passed through the Recipe subclasses, used as boilerplate to implement abstract methods. None of the data in these objects are directly available outside the implementation itself, only through the methods defined in the Recipe interface. Because of this, classes like NormalCraftingRecipe, CustomRecipe, SimpleSmithingRecipe, and SingleItemRecipe, and AbstractCookingRecipe can be used to create a new recipe implementation by implementing a few methods.

Note that these common info classes are a design philosophy, which you can choose to implement if desired. It’s only when building off existing recipe subtypes that you are required to make use of them.

  • net.minecraft.data.recipes
    • CustomCraftingRecipeBuilder - A recipe builder that creates an arbitrary crafting recipe from some common and crafting book information.
    • RecipeBuilder
      • determineBookCategory -> determineCraftingBookCategory
      • createCraftingCommonInfo - Creates the common recipe info.
      • createCraftingBookInfo - Creates the crafting book info.
    • RecipeUnlockAdvancementBuilder - An advancement builder for unlocking a recipe.
    • SpecialRecipeBuilder, special now takes in a supplied Recipe instead of a function of CraftingBookCategory to Recipe
      • unlockedBy - The criteria required to unlock the recipe advancement.
  • net.minecraft.world.item.crafting
    • AbstractCookingRecipe now takes in the Recipe$CommonInfo and $CookingBookInfo instead of the group and CookingBookCategory
      • $Factory#create now takes in the Recipe$CommonInfo and $CookingBookInfo instead of the group and CookingBookCategory
      • $Serializer replaced by cookingMapCodec, cookingStreamCodec
      • $CookingBookInfo - A record containing the common cooking information for the recipe book.
    • BannerDuplicateRecipe now takes in the banner Ingredient and the ItemStackTemplate result instead of the CraftingBookCategory
      • MAP_CODEC, STREAM_CODEC, SERIALIZER - Serializers for the recipe.
    • BlastingRecipe now takes in the Recipe$CommonInfo and $AbstractCookingRecipeCookingBookInfo instead of the group and CookingBookCategory
      • MAP_CODEC, STREAM_CODEC, SERIALIZER - Serializers for the recipe.
    • BookCloningRecipe now takes in the Ingredient source and material, the MinMaxBounds$Ints defining the generations that can be copied, and the ItemStackTemplate result instead of the CraftingBookCategory
      • ALLOWED_BOOK_GENERATION_RANGES, DEFAULT_BOOK_GENERATION_RANGES - Ranges for the book generation cloning.
      • MAP_CODEC, STREAM_CODEC, SERIALIZER - Serializers for the recipe.
    • CampfireCookingRecipe now takes in the Recipe$CommonInfo and AbstractCookingRecipe$CookingBookInfo instead of the group and CookingBookCategory
      • MAP_CODEC, STREAM_CODEC, SERIALIZER - Serializers for the recipe.
    • CraftingRecipe$CraftingBookInfo - A record containing the common crafting information for the recipe book.
    • CustomRecipe no longer takes in anything to its constructor
      • $Serializer is removed, replaced by its implementation’s codecs
    • DecoratedPotRecipe now takes in the Ingredient patterns for each side along with the ItemStackTemplate result instead of the CraftingBookCategory
      • MAP_CODEC, STREAM_CODEC, SERIALIZER - Serializers for the recipe.
    • DyeRecipe now takes in the Recipe$CommonInfo and CraftingRecipe$CraftingBookInfo along with the Ingredient target and dye and the ItemStackTemplate result instead of the CraftingBookCategory
      • MAP_CODEC, STREAM_CODEC, SERIALIZER - Serializers for the recipe.
    • FireworkRocketRecipe now takes in the Ingredient shell, fuel, and star along with the ItemStackTemplate result instead of the CraftingBookCategory
      • MAP_CODEC, STREAM_CODEC, SERIALIZER - Serializers for the recipe.
    • FireworkStarFadeRecipe now takes in the Ingredient target and dye along with the ItemStackTemplate result instead of the CraftingBookCategory
      • MAP_CODEC, STREAM_CODEC, SERIALIZER - Serializers for the recipe.
    • FireworkStarRecipe now takes in the $Shape to Ingredient map; the Ingredient trail, twinkle, fuel, and dye; along with the ItemStackTemplate result instead of the CraftingBookCategory
      • MAP_CODEC, STREAM_CODEC, SERIALIZER - Serializers for the recipe.
    • MapCloningRecipe replaced with TransmuteRecipe
    • MapExtendingRecipe now extends CustomRecipe instead of ShapedRecipe
      • The constructor now takes in the Ingredient map and material along with the ItemStackTemplate result instead of the CraftingBookCategory
      • MAP_CODEC, STREAM_CODEC, SERIALIZER - Serializers for the recipe.
    • NormalCraftingRecipe - A class that defines the standard implementation for a crafting recipe.
    • Recipe
      • showNotification, group are no longer default
      • $BookInfo - The information for the recipe book.
      • $CommonInfo - The common information across all recipes.
    • RecipeSerializer is now a record containing the MapCodec and StreamCodec
      • The registered entries have been moved to RecipeSerializers
      • register is removed
    • RecipeSerializers - All vanilla serializers for recipes.
    • RepairItemRecipe no longer takes in anything
      • INSTANCE - The recipe serializer singleton.
      • MAP_CODEC, STREAM_CODEC, SERIALIZER - Serializers for the recipe.
    • ShapedRecipe now extends NormalCraftingRecipe instead of implementing CraftingRecipe
      • The constructor now takes in the Recipe$CommonInfo and CraftingRecipe$CraftingBookInfo instead of the group and CraftingBookCategory
      • $Serializer -> MAP_CODEC, STREAM_CODEC, SERIALIZER; not one-to-one
    • ShapelessRecipe now extends NormalCraftingRecipe instead of implementing CraftingRecipe
      • The constructor now takes in the Recipe$CommonInfo and CraftingRecipe$CraftingBookInfo instead of the group and CraftingBookCategory
      • $Serializer -> MAP_CODEC, STREAM_CODEC, SERIALIZER; not one-to-one
    • ShieldDecorationRecipe now takes in the Ingredient banner and target along with the ItemStackTemplate result instead of the CraftingBookCategory
      • MAP_CODEC, STREAM_CODEC, SERIALIZER - Serializers for the recipe.
    • SimpleSmithingRecipe - A class that defines the standard implementation of a smithing recipe.
    • SingleItemRecipe now takes in the Recipe$CommonInfo instead of the group
      • commonInfo - The common information for the recipe.
      • $Factory#create now takes in the Recipe$CommonInfo instead of the group
      • $Serializer -> simpleMapCodec, simpleStreamCodec; not one-to-one
    • SmeltingRecipe now takes in the Recipe$CommonInfo and AbstractCookingRecipe$CookingBookInfo instead of the group and CookingBookCategory
      • MAP_CODEC, STREAM_CODEC, SERIALIZER - Serializers for the recipe.
    • SmithingTransformRecipe now extends SimpleSmithingRecipe instead of implementing SmithingRecipe
      • The constructor now takes in the Recipe$CommonInfo
      • $Serializer -> MAP_CODEC, STREAM_CODEC, SERIALIZER; not one-to-one
    • SmithingTrimRecipe now extends SimpleSmithingRecipe instead of implementing SmithingRecipe
      • The constructor now takes in the Recipe$CommonInfo
      • $Serializer -> MAP_CODEC, STREAM_CODEC, SERIALIZER; not one-to-one
    • SmokingRecipe now takes in the Recipe$CommonInfo and AbstractCookingRecipe$CookingBookInfo instead of the group and CookingBookCategory
      • MAP_CODEC, STREAM_CODEC, SERIALIZER - Serializers for the recipe.
    • StonecutterRecipe now takes in the Recipe$CommonInfo instead of the group
      • MAP_CODEC, STREAM_CODEC, SERIALIZER - Serializers for the recipe.
    • TippedArrowRecipe -> ImbueRecipe, not one-to-one
      • The constructor now takes in the Recipe$CommonInfo and CraftingRecipe$CraftingBookInfo along with the Ingredient source and material and the ItemStackTemplate result instead of the CraftingBookCategory
      • MAP_CODEC, STREAM_CODEC, SERIALIZER - Serializers for the recipe.
    • TransmuteRecipe now extends NormalCraftingRecipe instead of implementing CraftingRecipe
      • The constructor now takes in the Recipe$CommonInfo and CraftingRecipe$CraftingBookInfo along with the MinMaxBounds$Ints and boolean handling the material count and adding it to the result instead of the group and CraftingBookCategory
      • $Serializer -> MAP_CODEC, STREAM_CODEC, SERIALIZER; not one-to-one
  • net.minecraft.world.item.crafting.display.SlotDisplay
    • $OnlyWithComponent - A display only with the contents having the desired components.
    • $WithAnyPotion - A display with the contents having any potion contents component.
  • net.minecraft.world.level.storage.loot.functions.SmeltItemFunction#smelted now can take in whether to use the input material count

Dye Component

Specifying whether an item can be used as a dye material is now handled through the DYE data component. The component specifies a DyeColor, which can be set via Item$Properties#component:

public static final Item EXAMPLE_DYE = new Item(new Item.Properties().component(
    DataComponents.DYE, DyeColor.WHITE
));

However, a dye material’s behavior is not fully encompassed by the component alone. In most cases, the component is used in conjunction with some other tag or subclass to get the desired behavior.

Entities and Signs

Dying sheeps and signs are handled purely through the DyeItem subclass, checking if the item has the DYE component.

Dying the collars of wolfs and cats, on the other hand, can be any item, assuming it has the DYE component. Additionally, the item must be in the ItemTags#WOLF_COLLAR_DYES or ItemTags#CAT_COLLAR_DYES tag, respectively.

Dye Recipes

The DyeRecipe, formerly named ArmorDyeRecipe, can take any target ingredient and apply the colors of the dye ingredients to obtain the desired result with the associated DYED_COLOR component. Any item can be considered a dye; however, those without the DYE component will default to DyeColor#WHITE. Armor makes used of RecipeProvider#dyedItem to allow any item in the ItemTags#DYES tag to dye armor. However, bundles and shulker boxes have their color components as different items, meaning instead the default recipes are tied directly to the vanilla DyeItem, meaning a separate recipe will need to be generated for applying dyes to those items.

The loom, firework star, and firework star face recipes on the other hand expect any dye material to have the DYE component. The loom has an additional requirement of the item being in the ItemTags#LOOM_DYES tag.

  • net.minecraft.core.component.DataComponents#DYE - Represents that an item can act as a dye for the specific color.
  • net.minecraft.data.recipes.RecipeProvider
    • dyedItem - Creates a dyed item recipe.
    • dyedShulkerBoxRecipe - Creates a dyed shulker box recipe.
    • dyedBundleRecipe - Creates a dyed bundle recipe.
  • net.minecraft.world.item
    • BundleItem
      • getAllBundleItemColors, getByColor are removed
    • DyeColor#VALUES - A list of all dye colors.
    • DyeItem no longer takes in the DyeColor
      • getDyeColor, byColor are removed
  • net.minecraft.world.item.component.DyedItemColor#applyDyes now takes in a list of DyeColors instead of DyeItems
    • An overload can also take in a DyedItemColor component instead of the ItemStack
  • net.minecraft.world.item.crafting.ArmorDyeRecipe -> DyeRecipe, not one-to-one
  • net.minecraft.world.item.crafting.display.SlotDisplay$DyedSlotDemo - A display for demoing dying an item.
  • net.minecraft.world.level.block
    • BannerBlock#byColor is removed
    • ShulkerBoxBlock#getBlockByColor, getColoredItemStack are removed

World Clocks and Time Markers

World clocks are objects that represent some time that increases every tick from when the world first loads. These clocks are used as timers to properly handle timing-based events (e.g., the current day, sleeping). Vanilla provides two world clocks: one for minecraft:overworld and one for minecraft:the_end.

Creating a clock is rather simple: just an empty, datapack registry object in world_clock.

// For some world clock 'examplemod:EXAMPLE_CLOCK'
// JSON at 'data/examplemod/world_clock/EXAMPLE_CLOCK.json'
{}

From there, you can query the clock state through the ClockManager via Level#clockManager or MinecraftServer#clockManager:

// For some Level level
// Assume we have some ResourceKey<WorldClock> EXAMPLE_CLOCK

// Get the clock reference
Holder.Reference<WorldClock> clock = level.registryAccess().getOrThrow(EXAMPLE_CLOCK);

// Query the clock time
long ticksPassed = level.clockManager().getTotalTicks(clock);

If accessing the clock from the server, you can also modify the state of the clock:

// For some ServerLevel level
// Assume we have some ResourceKey<WorldClock> EXAMPLE_CLOCK

// Get the clock reference
Holder.Reference<WorldClock> clock = level.registryAccess().getOrThrow(EXAMPLE_CLOCK);

// Get the server clock manager
ServerClockManager clockManager = level.clockManager();

// Set the total number of ticks that have passed
clockManager.setTotalTicks(clock, 0L);

// Add the a certain value to the number of ticks
clockManager.addTicks(clock, 10L);

// Pause the clock
clockManager.setPaused(
    clock,
    // `true` to pause.
    // `false` to unpause.
    true
);

Marking Timelines

On its own, world clocks are rather limited in scope as you have to keep track of the number of ticks that have passed. However, when used with timelines, specific recurring times can be marked to handle timing-based events.

As a refresher, Timelines are a method of modifying attributes based on some WorldClock. Currently, all vanilla timelines use the minecraft:overworld world clock to keep track of their timing, via the clock field. All timelines must define a clock it uses; however, be aware that clocks to not support any synchronization by default, meaning that updating the time on one clock will not affect the other.

// For some timeline 'examplemod:example_timeline'
// In `data/examplemod/timeline/example_timeline.json
{
    // Uses the custom clock.
    // Any changes to the clock time will only affect
    // timelines using this clock.
    // e.g., `minecraft:overworld` will not be changed.
    "clock": "examplemod:example_clock",
    // Perform actions on a 24,000 tick interval.
    "period_ticks": "24000",
    // ...
}


// For some timeline 'examplemod:example_timeline_2'
// In `data/examplemod/timeline/example_timeline_2.json
{
    // Uses the same clock as the one above.
    // Changes to the clock time will affect both
    // timelines.
    "clock": "examplemod:example_clock",
    // Perform actions on a 1,000 tick interval.
    "period_ticks": "1000",
    // ...
}

// For some timeline 'examplemod:example_overworld'
// In `data/examplemod/timeline/example_overworld.json
{
    // Uses the vanilla overworld clock.
    // Changes to the clock time will not affect
    // the above timelines as they use a different
    // clock.
    "clock": "minecraft:overworld",
    // Perform actions on a 6,000 tick interval.
    "period_ticks": "6000",
    // ...
}

Timelines can also define time markers, which is just some identifier for a time within the timeline period for a world clock. These are commonly used within commands (e.g. /time set), to check if a certain time has passed (e.g. village sieges), or to skip to the given time (e.g. waking up from sleep). Time markers are defined in time_markers, specifying the ticks within the period and whether it can be show_in_commands. As time markers are identified by their world clock, timelines using the same world clock cannot define the same time markers.

// For some timeline 'examplemod:example_timeline'
// In `data/examplemod/timeline/example_timeline.json
{
    // The identifier of the clock.
    "clock": "examplemod:example_clock",
    // Perform actions on a 24,000 tick interval.
    "period_ticks": "24000",
    // The markers within the period specified by the timeline
    "time_markers": {
        // A marker
        "examplemod:example_marker": {
            // The number of ticks within the period
            // that this marker represents.
            // e.g., 5000, 29000, 53000, etc.
            "ticks": 5000,
            // When true, allows the time marker to be
            // suggested in the command. If false,
            // the time marker can still be used in the
            // command, it just won't be suggested.
            "show_in_commands": true
        }
    }
    // ...
}

Once the time markers are defined, they are registered for a world clock in the ServerClockManager, allowing them to be used given the ResourceKey.

// For some ServerLevel level
// Assume we have some ResourceKey<WorldClock> EXAMPLE_CLOCK
// Assume we have some ResourceKey<ClockTimerMarker> EXAMPLE_MARKER

// Get the clock reference
Holder.Reference<WorldClock> clock = level.registryAccess().getOrThrow(EXAMPLE_CLOCK);

// Get the server clock manager
ServerClockManager clockManager = level.clockManager();

// Check if the time is at the specified marker
// This should be used when checking for a specific time event every tick
boolean atMarker = clockManager.isAtTimeMarker(clock, EXAMPLE_MARKER);

// Skip to the time specified by the marker
// If the world clock is at 3000, sets the clock time to 5000
// If the world clock is at 6000, sets the clock time to 29000
// Returns whether the time was set, which is always true if the marker
// exists for the clock.
boolean timeSet = clockManager.skipToTimeMarker(clock, EXAMPLE_MARKER);
  • net.minecraft.client.ClientClockManager - Manages the ticking of the world clocks on the client side.
  • net.minecraft.client.gui.components.debug.DebugEntryDayCount - Displays the current day of the Minecraft world.
  • net.minecraft.client.multiplayer
    • ClientLevel
      • setTimeFromServer no longer takes in the long day time nor the boolean of whether to tick the day time
      • $ClientLevelData#setDayTime is removed
    • ClientPacketListener#clockManager - Gets the client clock manager.
  • net.minecraft.client.renderer.EndFlashState#tick now takes in the end clock time instead of the game time
  • net.minecraft.commands.arguments.ResourceArgument
    • getClock - Gets a reference to the world clock given the string resource identifier.
    • getTimeline - Gets a reference to the timeline given the string resource identifier.
  • net.minecraft.core.registries.Registries#WORLD_CLOCK - The registry identifier for the world clock.
  • net.minecraft.gametest.framework.TestEnvironmentDefinition
    • $TimeOfDay -> $ClockTime, not one-to-one
    • $Timelines - A test environment that uses a list of timelines.
  • net.minecraft.network.protocol.game.ClientboundSetTimePacket now takes in a map of clocks to their network states instead of the day time long and boolean
  • net.minecraft.server
    • MinecraftServer
      • forceTimeSynchronization -> forceGameTimeSynchronization, not one-to-one
      • clockManager - The server clock manager.
  • net.minecraft.server.level.ServerLevel
    • setDayTime, getDayCount are removed
    • setEnvironmentAttributes - Sets the environment attribute system to use.
  • net.minecraft.world.attribute.EnvironmentAttributeSystem$Builder#addTimelineLayer now takes in the ClockManager instead of a LongSupplier
  • net.minecraft.world.clock
    • ClockManager - A manager that gets the total number of ticks that have passed for a world clock.
    • ClockNetworkState - The current state of the clock to sync over the network.
    • ClockState - The current state of the clock, including the total number of ticks and whether the clock is paused.
    • ClockTimeMarker - A marker that keeps track of a certain period of time for a world clock.
    • ClockTimeMarkers - All vanilla time markers.
    • PackedClockStates - A map of clocks to their states, compressed for storage or other use.
    • ServerClockManager - Manages the ticking of the world clocks on the server side.
    • WorldClock - An empty record that represents a key for timing some location.
    • WorldClocks - All vanilla world clocks.
  • net.minecraft.world.level
    • Level
      • getDayTime -> getOverworldClockTime, not one-to-one
      • clockManager - The clock manager.
      • getDefaultClockTime - Gets the clock time for the current dimension.
    • LevelReader#getEffectiveSkyBrightness - Gets the sky brightness with the current darkening factor.
  • net.minecraft.world.level.dimension.DimensionType now takes in a default, holder-wrapped WorldClock
  • net.minecraft.world.level.storage
    • LevelData#getDayTime is removed
    • ServerLevelData
      • setDayTime is removed
      • setClockStates, clockStates - Handles the current states of the world clocks.
  • net.minecraft.world.level.storage.loot.predicates.TimeCheck now takes in a holder-wrapped WorldClock
    • time now takes in a holder-wrapped WorldClock
    • $Builder now takes in a holder-wrapped WorldClock
  • net.minecraft.world.timeline
    • AttributeTrack#bakeSampler now takes in a holder-wrapped WorldClock
    • AttributeTrackSampler now takes in a holder-wrapped WorldClock, and a ClockManager instead of a LongSupplier for the day time getter
    • Timeline now takes in a holder-wrapped WorldClock along with a map of time markers to their infos
      • #builder now takes in a holder-wrapped WorldClock
      • getPeriodCount - Gets the number of times a period has occurred within the given timeframe.
      • getCurrentTicks now takes in the ClockManager instead of the Level
      • getTotalTicks now takes in the ClockManager instead of the Level
      • clock - Returns the holder-wrapped WorldClock.
      • registerTimeMarkers - Registers all ClockTimeMarker defined in this timeline.
      • createTrackSampler now takes in a ClockManager instead of a LongSupplier for the day time getter
      • $Builder#addTimeMarker - Adds a time markers at the given tick, along with whether the marker can be suggested in commands.
    • Timelines#DAY -> OVERWORLD_DAY

Splitting the Primary Level Data into Saved Data

Some of the WorldData settings have been moved into SavedData, allowing for levels / dimensions to have more customizability. This addition also brings along some changes to how SavedData is referenced and queried.

Saved Data Changes

SavedDataType now identifies some SavedData using an Identifier, which is resolved against the data folder. This change allows subdirectories within the data folder, as the data storage will first create all missing parent directories before attempting to write the file.

public class ExampleData extends SavedData {

    public static final SavedDataType<ExampleData> TYPE = new SavedDataType<>(
        // The identifier for the saved data to resolve against
        // Data can be found in:
        // `<world_folder>/dimensions/<dimension_namespace>/<dimension_path>/data/examplemod/example/data.dat`
        Identifier.fromNamespaceAndPath("examplemod", "example/data"),
        // The constructor to create a new saved data
        ExampleData::new,
        // The codec to serialize the new saved data
        MapCodec.unitCodec(ExampleData::new),
        // The data fixer type
        // Either some patched enum value or null depending on mod loader implementation.
        null
    );
}

The SavedData can then be queried through the SavedDataStorage, renamed from DimensionDataStorage. This was renamed because the MinecraftServer instance now has its own data storage for global instances in addition to the levels. This means that any global saved data should be stored on the server instance rather than the overworld.

// Given a MinecraftServer server
ExampleData data = server.getDataStorage().computeIfAbsent(ExampleData.TYPE);


// Given a ServerLevel level
ExampleData data = level.getDataStorage().computeIfAbsent(ExampleData.TYPE);

Additional Saved Data

The following information is now stored as saved data:

  • Custom boss events
  • Ender dragon fight
  • Game rules
  • Wandering trader spawning
  • Weather
  • World generation settings

Of these, only the ender dragon fight is on a per-level / dimension basis. The rest are still stored and accessed through the server data storage. Custom boss events, on the other hand, remain unique as it is up to the implementer to determine what players are part of the event.

  • net.minecraft.client.Minecraft#doWorldLoad now takes in the optional GameRules
  • net.minecraft.client.gui.screens.worldselection
    • CreateWorldCallback now takes in the LevelDataAndDimensions$WorldDataAndGenSettings and the optional GameRules instead of the PrimaryLevelData
    • EditGameRulesScreen -> AbstractGameRulesScreen
      • Implementations in .screens.options.InWorldGameRulesScreen and WorldCreationGameRulesScreen
    • WorldOpenFlows
      • createLevelFromExistingSettings now takes in the LevelDataAndDimensions$WorldDataAndGenSettings and the optional GameRules instead of the WorldData
      • loadWorldStem now takes in the LevelStorageSource$LevelStorageAccess
  • net.minecraft.client.server.IntegratedServer now takes in the optional GameRules
  • net.minecraft.server
    • MinecraftServer now takes in the optional GameRules
      • getGlobalGameRules - Gets the game rules for the overworld dimension.
      • getWorldGenSettings - Gets the generation settings for the world.
      • getWeatherData - Gets the weather data for the server.
      • getDataStorage - Gets the saved data storage for the server.
      • getGameRules - Gets the game rules for the server.
    • WorldStem now takes in the LevelDataAndDimensions$WorldDataAndGenSettings instead of the WorldData
  • net.minecraft.server.bossevents
    • CustomBossEvent now takes in a UUID for the identifier along with a Runnable for the callback
      • getTextId -> customId
      • addOfflinePlayer is removed
      • getValue -> value
      • getMax -> max
      • load now takes in the UUID identifier along with a Runnable for the callback
    • CustomBossEvents now extends SavedData
      • create now takes in a RandomSource
      • save, load -> TYPE, not one-to-one
  • net.minecraft.server.dedicated.DedicatedServer now takes in the optional GameRules
  • net.minecraft.server.level
    • ChunkMap#getChunkDataFixContextTag now takes in an optional Identifier instead of a ResourceKey
    • ServerBossEvent now takes in an UUID for the id
      • setDirty - Marks the boss event as dirty for saving.
    • ServerLevel no longer takes in the RandomSequences
      • setWeatherParameters -> MinecraftServer#setWeatherParameters
      • getWeatherData - Gets the weather data for the server.
      • getRandomSequence -> MinecraftServer#getRandomSequence
      • getRandomSequences -> MinecraftServer#getRandomSequences
  • net.minecraft.world.entity.npc.wanderingtrader.WanderingTraderSpawner now takes in the SavedDataStorage instead of the ServerLevelData
    • MIN_SPAWN_CHANCE is now public from private
  • net.minecraft.world.entity.raid.Raids#TYPE_END, getType are removed
  • net.minecraft.world.level
    • Level#prepareWeather is removed
    • LevelSettings is now a record
      • The constructor now takes in the $DifficultySettings instead of just the Difficulty
      • withDifficultyLock - The settings with whether the difficulty is locked.
      • copy - Copies the settings.
      • $DifficultySettings - The settings for the difficulty.
  • net.minecraft.world.level.dimension.DimensionType now takes in a boolean for whether the dimension can have an ender dragon fight
  • net.minecraft.world.level.dimension.end
    • DragonRespawnAnimation -> DragonRespawnStage, not one-to-one
    • EndDragonFight -> EnderDragonFight, not one-to-one
  • net.minecraft.world.level.gamerules.GameRuleMap now extends SavedData
    • TYPE - The saved data type.
    • reset - Resets the rule to its default value.
  • net.minecraft.world.level.levelgen.WorldGenSettings is now a final class instead of a record, extending SavedData
    • encode, decode replaced with TYPE
    • of - Constructs the generation settings.
  • net.minecraft.world.level.saveddata
    • SavedDataType now takes in an Identifier instead of a string for the id
    • WanderingTraderData - The saved data for the wandering trader.
    • WeatherData - The saved data for the weather.
  • net.minecraft.world.level.storage
    • DimensionDataStorage -> SavedDataStorage, not one-to-one
    • LevelData#isThundering, isRaining, setRaining now in WeatherData
    • LevelDataAndDimensions now takes in a $WorldDataAndGenSettings instead of the WorldData
      • $WorldDataAndGenSettings - Holds the world data and generation settings.
    • LevelResource is now a record
    • PrimaryLevelData fields have been moved to their respective saved data classes
      • PLAYER -> OLD_PLAYER
      • SINGLEPLAYER_UUID - A string that represents the UUID of the player in a singleplayer world.
      • WORLD_GEN_SETTINGS -> OLD_WORLD_GEN_SETTINGS
      • writeLastPlayed - Writes the last played player.
      • writeVersionTag - Writes the data version tag.
    • ServerLevelData
      • setThundering, getRainTime, setRainTime, setThunderTime, getThunderTime, getClearWeatherTime, setClearWeatherTime moved to WeatherData
      • getWanderingTraderSpawnDelay, setWanderingTraderSpawnDelay, getWanderingTraderSpawnChance, setWanderingTraderSpawnChance, getWanderingTraderId, setWanderingTraderId moved to WanderingTraderData
      • getLegacyWorldBorderSettings, setLegacyWorldBorderSettings replaced by WorldBorder
      • getScheduledEvents -> MinecraftServer#getScheduledEvents
      • getGameRules replaced by GameRuleMap
    • WorldData
      • getCustomBossEvents, setCustomBossEvents replaced by CustomBossEvents
      • createTag no longer takes in the RegistryAccess
      • getGameRules replaced by GameRuleMap
      • getLoadedPlayerTag -> getSinglePlayerUUID, not one-to-one
      • endDragonFightData, setEndDragonFightData replaced by EnderDragonFight
      • worldGenOptions replaced by WorldGenSettings saved data
  • net.minecraft.world.level.timers.TimerQueue now extends SavedData
    • The constructor now takes in the $Packed events instead of the TimerCallbacks and Stream of event data
    • store replaced by CODEC, TYPE, codec
    • loadEvent, storeEvent replaced by $Event$Packed#codec
    • $Event is now a record
      • $Packed - The packed event data.
    • $Packed - The packed time queue.

Even More Rendering Changes

Materials and Dynamic Layer Selection

Block and item models now no longer specify what RenderType or ChunkSectionLayer they belong to. Instead, this is computed when loading the model, determing the associated layer for each quad. This means that ItemBlockRenderTypes is removed, with setting the RenderType for an item removed altogether.

To determine what layer a quad or face gets set to, the Transparency of the texture is computed. Specifically, it checks that, for the UV area mapped to the quad, if there are any pixels that are transparent (have an alpha of 0), or translucent (have an alpha that is not 0 or 255). For the ChunkSectionLayer, ChunkSectionLayer#TRANSLUCENT is used if there is a translucent pixel, else CUTOUT is used if there is a transparent pixel, else SOLID. For the item RenderType, Sheets#translucentItemSheet and translucentBlockItemSheet for block items are used if there is a translucent pixel, or cutoutItemSheet and cutoutBlockItemSheet for block items. The Transparency also affects using MipmapStrategy#AUTO, using CUTOUT instead of MEAN as the default if there is a transparent pixel.

One can influence a quad’s Transparency through the Material texture defined by the model JSON. A Material specifies the texture’s sprite, which represents the relative path to the texture, and optionally force_translucent, which forces any quad using this texture to use Transparency#TRANSLUCENT (transparent is false while translucent is true):

// For some model `examplemod:example_model`
// In: `assets/examplemod/models/example_model.json`
{
    "parent": "minecraft:block/template_glass_pane_post",
    "textures": {
        // A Material can be a simple texture reference
        // Points to `assets/minecraft/textures/block/glass_pane_top.png`
        "edge": "minecraft:block/glass_pane_top",
        // Or it can be an object
        "pane": {
            // The relative texture reference for faces using this key
            // Points to `assets/minecraft/textures/block/glass.png`
            "sprite": "minecraft:block/glass",
            // When true, sets all faces using this texture key to
            // always have a transparent pixel.
            "force_translucent": true
        }
    }
    // ...
}

This change also defines the rendering order, where all solid quads are rendered first, followed by cutout quads, and finally translucent quads, sorted by distance from the camera.

Materials and Sprites

As you may have noticed, Materials were originally used to define some texture in an atlas. The addition of materials in texture JSONs have changed the naming of these classes. Materials now explicitly refer to texture references within model JSONs. This means that all references to the raw texture location have been replaced with Material, if unbaked, and Material$Baked, if baked. Additionally, the SpriteGetter is now MaterialBaker.

As for the original Material, these are now known as sprites, where Material is renamed to SpriteId, and MaterialSet is renamed to SpriteGetter.

Quad Particle Layers

The SingleQuadParticle$Layers have been split into OPAQUE_* and TRANSLUCENT_* layers, depending on if the particle texture used by the atlas contains a translucent pixel. Note that ‘opaque’ in this instance means cutout, where pixels with an alpha of less than 0.1 are discarded. If not creating a new layer, $Layer#bySprite can be used to determine what layer the particle texture should use.

public class ExampleParticle extends SingleQuadParticle {

    private final SingleQuadParticle.Layer layer;

    public SingleQuadParticle(ClientLevel level, double x, double y, double z, TextureAtlasSprite sprite) {
        super(level, x, y, z, sprite);
        this.layer = SingleQuadParticle.Layer.bySprite(sprite);
    }

    @Override
    protected SingleQuadParticle.Layer getLayer() {
        return this.layer;
    }
}

Block Models

The pipeline for rendering individual block models outside of the general world context has been rewritten similarly to ItemModels, where a ‘block model’ updates some render state, which then submits its elements for rendering. As such, most of the block model classes have been either rewritten or reorganized to a degree.

Due to the block model name being synonymous with the model JSONs in general, many classes were moved and rename to separate the model JSONs, from the block state JSONs, from the now block models. As such, geometry for models that originally had ‘block’ in the name were changed to ‘cuboid’: (e.g., BlockModel -> CuboidModel, BlockModelWrapper -> CuboidItemModelWrapper). Additionally, parts of the rendering process referring to the definitions within a block state JSON were changed from ‘block’ to ‘block state’ (e.g., BlockModelPart -> BlockStateModelPart, BlockModelDefinition -> BlockStateModelDispatcher). You can consider most of the ‘block model’ classes to be new, with those renamed replacing the SpecialBlockModelRenderer system.

The block model system starts from the ModelManager after all models and definitions are loaded and resolved, ready to be baked. Block models are loaded through BuiltInBlockModels#crateBlockModels, which links some BlockState to a BlockModel$Unbaked. Similarly to item models, the unbaked instance defines the properties of how the block model should be constructed. These are stored within LoadedBlockModels, to which they are then subsequently baked after all JSONs into BlockModels via bake. This BlockState to BlockModel map is then stored within the BlockModelSet, ready to be queried through get, or more commonly through BlockModelResolver#update, which calls in the model set. Any models not defined lazily resolve to a wrapper around the BlockStateModel.

Vanilla provides six BlockModel implementations for common usage. There is EmptyBlockModel, which submit no elements, and as such renders nothing; and BlockStateModelWrapper, which wraps around and displays the associated BlockStateModel. Then, there are equivalents for changing the model based on some property switch (SelectBlockModel), a conditional boolean (ConditionalBlockModel), and composing multiple models together (CompositeBlockModel). Finally, there is the SpecialBlockModelWrapper, which submits its elements through the stored SpecialModelRenderer, the unified submitter between item and block models.

// As the block model system is hardcoded through its in-code bootstrap,
// this example will assume there exists some method to get access to the
// `BuiltInBlockModels$Builder` builder.

// We will also assume we have some Block EXAMPLE_BLOCK_* to attach the models to.

// Regular block model
builder.put(
    // A factory that takes in the `BlockColors` and `BlockState` to return
    // a `BlockModel$Unbaked`.
    (colors, state) -> new BlockStateModelWrapper.Unbaked(
        // The state to get the `BlockStateModel` of.
        state,
        // The tint layers for the model.
        colors.getTintSources(state),
        // An optional transformation to apply to the `PoseStack` before
        // submitting the model.
        Optional.empty(new Transformation(new Matrix4f().translation(0.5f, 0.5f, 0.5f)))
    ),
    // The block to use this model for. Will loop through a construct one
    // per state.
    EXAMPLE_BLOCK_1
);

// Block model switched on some property
builder.put(
    (colors, state) -> new SelectBlockModel.Unbaked(
        // An optional transformation to apply to the `PoseStack` before
        // submitting the model.
        Optional.empty(),
        // A record containing the property to switch on, along with the
        // values when a specific block model should be selected.
        new SelectBlockModel.UnbakedSwitch<>(
            // The `SelectBlockModelProperty` to switch on. The property
            // value is determined from the `BlockState` and its `BlockDisplayContext`.
            (state, displayContext) -> state.getRenderShape(),
            // The list of cases to determine what `BlockModel` to use.
            List.of(
                new SelectBlockModel.SwitchCase<>(
                    // The list of values this model applies to.
                    List.of(RenderShape.INVISIBLE),
                    // The model to use when this property is met.
                    new EmptyBlockModel.Unbaked()
                )
            ),
            // An optional fallback if no switch case matches the state's
            // property.
            Optional.of(new EmptyBlockModel.Unbaked())
        )
    ),
    EXAMPLE_BLOCK_2
);

// Block model based on some conditional
builder.put(
    (colors, state) -> new ConditionalBlockModel.Unbaked(
        // An optional transformation to apply to the `PoseStack` before
        // submitting the model.
        Optional.empty(),
        // The `ConditionalBlockModelProperty` that determines the
        // `boolean` from the `BlockState`.
        BlockState::isSignalSource,
        // The model to display when the property returns `true`.
        new EmptyBlockModel.Unbaked(),
        // The model to display when the property returns `false`.
        new EmptyBlockModel.Unbaked()
    ),
    EXAMPLE_BLOCK_3
);

// A composite block model
builder.put(
    (colors, state) -> new CompositeBlockModel.Unbaked(
        // The first model to display.
        new EmptyBlockModel.Unbaked(),
        // The second model to display.
        new EmptyBlockModel.Unbaked(),
        // An optional transformation to apply to the `PoseStack` before
        // submitting the model.
        Optional.empty()
    ),
    EXAMPLE_BLOCK_4
);

// Special block model
builder.put(
    (colors, state) -> new SpecialBlockModelWrapper.Unbaked(
        // The unbaked `SpecialModelRenderer` used to submit elements for the
        // model.
        new BellSpecialRenderer.Unbaked(),
        // An optional transformation to apply to the `PoseStack` before
        // submitting the model.
        Optional.empty()
    ),
    EXAMPLE_BLOCK_5
);

During the feature submission process, block models are handled through the BlockModelResolver and BlockModelRenderState. This is similar to how other render states work. First, BlockModelResolver#update sets up the BlockModelRenderState. Setup is handled through either the basic path – BlockModelRenderState#setupModel, add the model parts to the returned list, then setupTints, or through setupSpecialModel for the special renderers. Then, the render state submits its elements for rendering through BlockModelRenderState#submit. The render state also provides submitOnlyOutline which uses the outline render type, and submitWithZOffset which uses the sold entity forward Z-offset render type.

// BlockEntity example
public class ExampleRenderState extends BlockEntityRenderState {
    // Hold the render state.
    public final BlockModelRenderState exampleBlock = new BlockModelRenderState();
}

public class ExampleRenderer implements BlockEntityRenderer<ExampleBlockEntity, ExampleRenderState> {

    // The display context for use in the block entity renderer.
    public static final BlockDisplayContext BLOCK_DISPLAY_CONTEXT = BlockDisplayContext.create();
    private final BlockModelResolver blockResolver;

    public ExampleRenderer(BlockEntityRendererProvider.Context ctx) {
        super(ctx);
        // Get the model resolver.
        this.blockResolver = ctx.blockModelResolver();
    }

    @Override
    public void extractRenderState(ExampleBlockEntity blockEntity, ExampleRenderState state, float partialTick, Vec3 cameraPosition, ModelFeatureRenderer.CrumblingOverlay breakProgress) {
        super.extractRenderState(blockEntity, state, partialTick, cameraPosition, breakProgress);

        // Update the model state.
        this.blockResolver.update(state.exampleBlock, Blocks.DIRT.defaultBlockState(), BLOCK_DISPLAY_CONTEXT);
    }

    @Override
    public void submit(ExampleRenderState state, PoseStack pose, SubmitNodeCollector collector, CameraRenderState camera) {
        super.submit(state, pose, collector, camera);

        // Submit the model state for rendering.
        state.exampleBlock.submit(
            // The current pose stack,
            pose,
            // The node collector.
            collector,
            // The light coordinates.
            state.lightCoords,
            // The overlay coordinates.
            OverlayTexture.NO_OVERLAY,
            // The outline color.
            0
        );


    }
}

// Entity example
public class ExampleRenderState extends EntityRenderState {
    // Hold the render state.
    public final BlockModelRenderState exampleBlock = new BlockModelRenderState();
}

public class ExampleRenderer extends EntityRenderer<ExampleEntity, ExampleRenderState> {

    // The display context for use in the entity renderer.
    public static final BlockDisplayContext BLOCK_DISPLAY_CONTEXT = BlockDisplayContext.create();
    private final BlockModelResolver blockResolver;

    public ExampleRenderer(EntityRendererProvider.Context ctx) {
        super(ctx);
        // Get the model resolver.
        this.blockResolver = ctx.getBlockModelResolver();
    }

    @Override
    public void extractRenderState(ExampleEntity entity, ExampleRenderState state, float partialTick) {
        super.extractRenderState(entity, state, partialTick);

        // Update the model state.
        this.blockResolver.update(state.exampleBlock, Blocks.DIRT.defaultBlockState(), BLOCK_DISPLAY_CONTEXT);
    }

    @Override
    public void submit(ExampleRenderState state, PoseStack pose, SubmitNodeCollector collector, CameraRenderState camera) {
        super.submit(state, pose, collector, camera);

        // Submit the model state for rendering.
        state.exampleBlock.submit(
            // The current pose stack.
            pose,
            // The node collector.
            collector,
            // The light coordinates.
            state.lightCoords,
            // The overlay coordinates.
            OverlayTexture.NO_OVERLAY,
            // The outline color.
            state.outlineColor
        );
    }
}

Block Tint Sources

BlockColor has been completely replaced by BlockTintSource, which sets the ARGB tint of a particular index based on the desired context. There are three contexts a tint source can provide:

  • color for the general context, used by BlockModels
  • colorInWorld for the world context, used by ModelBlockRenderer#tesselateBlock
  • colorAsTerrainParticle for the particle context, used by the falling dust and terrain particle

In addition, BlockTintSource provides a relevantProperties if the Propertys of a BlockState are used to determine what color to tint. This is used by the LevelRenderer to determine whether a change in state requires a model to be re-rendered.

BlockTintSources are still registered to BlockColors via register, taking in a list of sources followed by the vararg of blocks. The tintindex specfied in the model JSON is used to index into the tint source list.

// Assume access to BlockColors colors
colors.register(
    // The list of tints to apply to some block model.
    List.of(
        // "tintindex": 0
        (state) -> 0xFFFF0000,
        // "tintindex": 1
        new BlockTintSource() {

            @Override
            public int color(BlockState state) {
                return 0xFF00FF00;
            }

            @Override
            public int colorInWorld(BlockState state, BlockAndTintGetter level, BlockPos pos) {
                return 0xFF0000FF;
            }
        }
    ),
    // The blocks these tint sources will apply to.
    EXAMPLE_BLOCK_1
);

Removing the Old Block and Item Renderers

Since ItemModels and BlockModel are now fully handled through their own feature submission pipeline, BlockRenderDispatcher and ItemRenderer have been completely removed, replaced by the corresponding systems.

Object Definition Transformations

ItemModels and BlockModels can now take in an optional Transformation, which transforms how the model should be displayed. As such, the $Unbaked#bake methods now take in the parent Matrix4fc transformation, to which the transformation is multiplied to via Transformation#compose. For item models, this is known as a local transform separate from the model JSON item transform. The local transforms are always applied after the item transform.

Note that adding support for transformations should always be done through Transformation#compose as the matrices passed around are mutable by nature. Assume any custom methods not performed through a vanilla interface should copy before performing any modifications.

Quad Instance

The brightness / tint color, lightmap, and overlay coordinates have been consolidated into a single object: QuadInstance. The mutable class sets its values through its associated set* methods, and can pull the information for each quad vertex via the get* methods. Brightness and tinting are stored together as the color, rather them being two separate values.

QuadInstance does not replace all usecases, such as when adding a single vertex. It only updates methods for the VertexConsumer, splitting putBulkData into putBlockBakedQuad for quads in block models, and putBakedQuad for all other uses.

In addition, mmany methods used to upload BakedQuads to a buffer now take in a BlockQuadOutput. This has the same parameters as VertexConsumer#putBlockBakedQuad, and was added due to the section renderer uploading to a newly allocated BufferBuilder for use with the uber buffer.

Gui Extractor

GUI classes methods have gone through a massive renaming scheme, indicating that the submitted elements are ‘extracted’ into a general tree to be submitted and then rendered. As such, methods that began with draw* or render* are now prefixed with extract*, and potentially suffixed with *RenderState (e.g., Renderable#render -> extractRenderState, AbstractContainerScreen#renderLabels -> extractLabels, AbstractWidget#renderWidget -> extractWidgetRenderState). Some shorthands were also expanded, either by renamining or replacing the method with another (e.g., AbstractContainerScreen#renderBg replaced by Screen#extractBackground).

GuiGraphics was also renamed to GuiGraphicsExtractor in the same fashion. The methods follow similar patterns to the rest of the GUI changes (e.g. hline -> horizontalLine), except that draw*, render*, and submit* prefixes along with *RenderState suffixes are removed (e.g. renderOutline -> outline, submitEntityRenderState -> entity). The only rename is that *String* method names are replaced with *Text*.

Fluid Models

Defining a fluid’s textures and tint has now been moved out of the FluidRenderer (previously LiquidBlockRenderer) and into its own separate FluidModel record. Initially, given the small number of fluids, the unbaked variants (FluidModel$Unbaked) are stored as constants. Then, after BlockModel have been baked, the fluid models are baked via FluidStateModelSet#bake, linking a Fluid to its FluidModel. This map is then stored within the FluidStateModelSet, ready to be queried through get.

A FluidModel$Unbaked has four arguments: three Materials for the still, flowing, and optional overlay textures; and one for the BlockTintSource. The tint is obtained via BlockTintSource#colorInWorld. During the baking process, it will determine the ChunkSectionLayer based on the transparency of the provided materials.

// As the fluid model system is hardcoded within its baking, this example
// will assume there exists some method to get modifiable access to the
// `Map<Fluid, FluidModel>` fluidModels returned by `FluidStateModelSet#bake`.

// We will also assume we have some Fluid EXAMPLE_FLUID* to attach the models to.

FluidModel.Unbaked exampleFluidModel = new FluidModel.Unbaked(
    // The texture for the still fluid.
    new Material(
        // The relative identifier for the texture.
        // Points to `assets/examplemod/textures/block/example_fluid_still.png`
        Identifier.fromNamespaceAndPath("examplemod", "block/example_fluid_still"),
        // When true, sets all faces using this texture key to
        // always have a transparent pixel.
        true
    ),
    // The texture for the flowing fluid.
    new Material(Identifier.fromNamespaceAndPath("examplemod", "block/example_fluid_flowing")),
    // If not null, the texture for the overlay when the side of the fluid is
    // occluded by a `HalfTransparentBlock` or `LeavesBlock`.
    null,
    // If not null, the tint source to apply to the fluid's texture when in
    // the world.
    null
);

// Assume we have access to the `MaterialBaker` materials.

FluidModel exampleBakedFluidModel = exampleFluidModel.bake(
    // The baker to grab the atlas sprites for the materials.
    materials,
    // A supplied debug name to properly report which models have
    // missing textures.
    () -> "examplemod:example_fluid_model"
);

fluidModels.put(
    // The fluid the model should be used by.
    EXAMPLE_FLUID,
    // The baked fluid model.
    exampleBakedFluidModel
);
fluidModels.put(EXAMPLE_FLUID_FLOWING, exampleBakedFluidModel);

Name Tag Offsets

EntityRenderer#submitNameTag has been renamed to submitNameDisplay, now optionally taking in the y offset from the name tag attachment.

Tint Getter

BlockAndTintGetter is now a client only interface attached to the ClientLevel. It previous uses were replaced with BlockAndLightGetter – which BlockAndTintGetter now extends – with the tint and lighting directions stripped.

Pipeline Depth and Color

Depth and color methods defined in the RenderPipeline have been consolidated into two state objects.

The DepthTestFunction, write boolean, and the bias floats are now stored in DepthStencilState. DepthTestFunction has been replaced with a more generic CompareOp, which defines how to compare two numbers. Each function has an simple equivalent, with NO_DEPTH_TEST replaced by CompareOp#ALWAYS_PASS. The depth information can be added to the pipeline via RenderPipeline$Builder#withDepthStencilState.

The optional BlendFunction and color / alpha booleans are now stored in ColorTargetState. The booleans are consolidated into an int using the lower four bits as flags: 1 is red, 2 is green, 4 is blue, and 8 is alpha. The color boolean uses 7 for red, green, and blue; the alpha boolean uses 8; while both combined use 15. The LopicOp is removed entirely. The color information can be added to the pipeline via RenderPipeline$Builder#withColorTargetState.

public static final RenderPipeline EXAMPLE_PIPELINE = RenderPipeline.builder()
    .withLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "pipeline/example"))
    .withVertexShader(ResourceLocation.fromNamespaceAndPath("examplemod", "example"))
    .withFragmentShader(ResourceLocation.fromNamespaceAndPath("examplemod", "example"))
    .withVertexFormat(DefaultVertexFormat.POSITION_TEX_COLOR, VertexFormat.Mode.QUADS)
    .withShaderDefine("ALPHA_CUTOUT", 0.5)
    .withSampler("Sampler0")
    .withUniform("ModelOffset", UniformType.VEC3)
    .withUniform("CustomUniform", UniformType.INT)
    .withPolygonMode(PolygonMode.FILL)
    .withCull(false)
    // Sets the color target when writing the buffer data.
    .withColorTargetState(new ColorTargetState(
        // Specifies the functions to use when blending two colors with alphas together.
        // Made up of the `SourceFactor` and `DestFactor`.
        // First two are for RGB, the last two are for alphas.
        // If the optional is empty, then blending is disabled.
        Optional.of(BlendFunction.TRANSLUCENT),
        // The mask determining what colors to write to the buffer.
        // Represented as a four bit value
        // 0001 - Write the red channel..
        // 0010 - Write the green channel.
        // 0100 - Write the blue channel.
        // 1000 - Write the alpha channel.
        ColorTargetState.WRITE_RED | ColorTargetState.WRITE_GREEN | ColorTargetState.WRITE_BLUE | ColorTargetState.WRITE_ALPHA
    ))
    // Sets the depth stencil when writing the buffer data.
    .withDepthStencilState(new DepthStencilState(
        // Sets the depth test function to use when rendering objects at varying
        // distances from the camera.
        // Values:
        // - ALWAYS_PASS           (GL_ALWAYS)
        // - LESS_THAN             (GL_LESS)
        // - LESS_THAN_OR_EQUAL    (GL_LEQUAL)
        // - EQUAL                 (GL_EQUAL)
        // - NOT_EQUAL             (GL_NOTEQUAL)
        // - GREATER_THAN_OR_EQUAL (GL_GEQUAL)
        // - GREATER_THAN          (GL_GREATER)
        // - NEVER_PASS            (GL_NEVER)
        CompareOp.LESS_THAN_OR_EQUAL,
        // Whether to mask writing values to the depth buffer
        false,
        // The scale factor used to calculate the depth values for the polygon.
        0f,
        // The unit offset used to calculate the depth values for the polygon.
        0f
    ))
    .build()
;

Blaze3d Backends

CommandEncoder, GpuDevice, and RenderPassBackend has been split into the *Backend interface, which functions similarly to the previous interface, and the wrapper class, which holds the backend and provides delegate calls, performing any validation necessary. The *Backend interfaces now explicitly perform the operation without checking whether the operation is valid.

Solid and Translucent Features

Feature rendering has been further split into two passes: one for solid render types, and one for translucent render types. As such, most render methods now have a renderSolid and renderTranslucent method, respectively. Those which only render solid or translucent data only have one of the methods.

Camera State

The Camera has been updated similarly to other render state implementations where the camera is extracted to the CameraRenderState during GameRenderer#renderLevel, and that is passed around with the data required to either submit and render elements.

Due to this change, FogRenderer#setupFog now returns the FogData, containing all the information needed to render the fog, instead of just its color, and storing that in CameraRenderState#fogData.

  • Some shaders within assets/minecraft/shaders/core now use texture over texelFetch
    • entity.vsh
    • item.vsh
    • rendertype_leash.vsh
    • rendertype_text.vsh
    • rendertype_text_background.vsh
    • rendertype_text_intensity.vsh
  • assets/minecraft/shaders/core
    • block.vsh#minecraft_sample_lightmap -> sample_lightmap.glsl#sample_lightmap
    • rendertype_crumbling no longer takes in texCoord2 (lightmap)
    • rendertype_entity_alpha, rendertype_entity_decal merged into entity.fsh using a DissolveMaskSampler
    • rendertype_item_entity_translucent_cull -> item, not one-to-one
    • rendertype_translucent_moving_block is removed
      • This now uses the the shaders provided by the ChunkSectionLayer
  • com.mojang.blaze3d
    • GLFWErrorCapture - Captures errors during a GL process.
    • GLFWErrorScope - A closable that defines the scope of the GL errors to capture.
  • com.mojang.blaze3d.opengl
    • GlProgram#BUILT_IN_UNIFORMS, INVALID_PROGRAM are now final
    • GlBackend - A GPU backend for OpenGL.
    • GlCommandEncoder now implements CommandEncoderBackend instead of CommandEncoder, the class now package-private
      • getDevice is removed
    • GlConst#toGl now takes in a CompareOp instead of the DepthTestFunction
    • GlDevice now implements GpuDeviceBackend instead of GpuDevice, the class now package-private
      • The constructor now takes in a GpuDebugOptions containing the log level, whether to use synchronous logs, and whether to use debug labels instead of those parameters being passed in directly
    • GlRenderPass now implements RenderPassBackend instead of RenderPass, the class now package-private
      • The constructor now takes in the GlDevice
    • GlStateManager#_colorMask now takes an int for the color mask instead of four booleans
  • com.mojang.blaze3d.platform
    • ClientShutdownWatchdog now takes in the Minecraft instance
    • DebugMemoryUntracker#untrack is removed
    • GLX#make(T, Consumer) is removed
    • NativeImage
      • computeTransparency - Returns whether there is at least one transparent or translucent pixel in the image.
        • This crashes if the image’s area is greater than 512MiB, or 2GiB with color data.
      • isClosed - Whether the image is closed or deallocated.
    • Transparency - An object of whether some image has a translucent and/or transparent pixel.
    • Window now takes the GpuBackend instead of the ScreenManager
      • createGlfwWindow - Directly creates the GLFW window with the provided settings.
      • updateDisplay -> updateFullscreenIfChanged, not one-to-one
      • isResized, resetIsResized - Handles whether the window has been resized.
      • backend - Returns the GpuBackend.
      • $WindowInitFailed constructor is now public from private
    • WindowEventHandler#resizeDisplay -> resizeGui
  • com.mojang.blaze3d.pipeline
    • ColorTargetState - A record containing the blend function and mask for the color.
    • DepthStencilState - A record containing the data for the depth stencil.
    • RenderPipeline now takes in the ColorTargetState instead of the optional BlendFunction, color and alpha booleans, and LogicOp; and the DepthStencilState instead of the DepthTestFunction, depth boolean, and bias floats
      • getDepthTestFunction, isWriteDepth, getDepthBiasScaleFactor, getDepthBiasConstant -> getDepthStencilState, not one-to-one
      • getColorLogic, getBlendFunction, isWriteColor, isWriteAlpha -> getColorTargetState, not one-to-one
      • $Builder
        • withDepthTestFunction, withDepthWrite, withDepthBias -> withDepthStencilState, not one-to-one
        • withBlend, withColorWrite, withColorLogic -> withColorTargetState, not one-to-one
      • $Snippet now takes in the ColorTargetState instead of the optional BlendFunction, color and alpha booleans, and LogicOp; and the DepthStencilState instead of the DepthTestFunction and depth boolean
  • com.mojang.blaze3d.platform
    • BackendOptions - A configuration for initializing the backend with.
    • DepthTestFunction -> CompareOp, not one-to-one
      • NO_DEPTH_TEST -> CompareOp#ALWAYS_PASS
      • EQUAL_DEPTH_TEST -> CompareOp#EQUAL
      • LEQUAL_DEPTH_TEST -> CompareOp#LESS_THAN_OR_EQUAL
      • LESS_DEPTH_TEST -> CompareOp#LESS_THAN
      • GREATER_DEPTH_TEST -> CompareOp#GREATER_THAN
    • GLX
      • _initGlfw now takes in the BackendOptions
      • glfwBool - 1 if true, 0 if false.
    • LogicOp enum is removed
  • com.mojang.blaze3d.shaders.GpuDebugOptions - The debug options for the GPU pipeline.
  • com.mojang.blaze3d.systems
    • BackendCreationException - An exception thrown when the GPU backend couldn’t be created.
    • CommandEncoder -> CommandEncoderBackend
      • The original interface is now a class wrapper around the interface, delegating to the backend after performing validation checks
    • GpuBackend - An interface responsible for creating the used GPU device and window to display to.
    • GpuDevice -> GpuDeviceBackend
      • The original interface is now a class wrapper around the interface, delegating to the backend after performing validation checks
      • setVsync - Sets whether VSync is enabled.
      • presentFrame - Swaps the front and back buffers of the window to display the present frame.
      • isZZeroToOne - Whether the 0 to 1 Z range is used instead of -1 to 1.
    • RenderPass -> RenderPassBackend
      • The original interface is now a class wrapper around the interface, delegating to the backend after performing validation checks
    • RenderSystem
      • pollEvents is now public
      • flipFrame no longer takes in the Window
      • initRenderer now only takes in the GpuDevice
      • limitDisplayFPS -> FramerateLimiter#limitDisplayFPS
      • initBackendSystem now takes in the BackendOptions
  • com.mojang.blaze3d.vertex
    • DefaultVertexFormat#BLOCK no longer takes in the normal vector
    • PoseStack#mulPose, $Pose#mulPose now has an overload that takes in the Transformation
    • QuadInstance - A class containing the color, light coordinates, and overlay of a quad.
    • TlsfAllocator - A two-level segregate fit allocator for dynamic memory allocation.
    • UberGpuBuffer - A buffer for uploading dynamically sized data to the GPU, used for chunk section layers.
    • VertexConsumer
      • putBulkData -> putBlockBakedQuad, putBakedQuad; not one-to-one
        • Brightness float array, color floats, lightmap int array, and overlay int are replaced with QuadInstance
        • putBlockBakedQuad replaces the PoseStack$Pose with the XYZ float block position
      • addVertex(PoseStack$Pose, Vector3f) -> addVertex(PoseStack$Pose, Vector3fc)
      • setNormal(PoseStack$Pose, Vector3f) -> setNormal(PoseStack$Pose, Vector3fc)
  • com.mojang.math
    • MatrixUtil
      • checkPropertyRaw is now public from private
      • isOrthonormal is removed
    • Transformation
      • IDENTITY is now public from private
        • Replaces identity method
      • getTranslation -> translation
      • getLeftRotation -> leftRotation
      • getScale -> scale
      • getRightRotation -> rightRotation
      • compose - Applies the transformation to the given matrix, if present.
  • net.minecraft.SharedConstants
    • DEBUG_DUMP_INTERPOLATED_TEXTURE_FRAMES is removed
    • DEBUG_PREFER_WAYLAND - When true, prevents the platform initialization hint from being set to X11 if both Wayland and X11 are supported.
  • net.minecraft.client
    • Camera
      • BASE_HUD_FOV - The base hud field-of-view.
      • setup -> update, not one-to-one
      • extractRenderState - Extract the state of the camera.
      • getFov - Gets the field-of-view.
      • getViewRotationMatrix - Gets the matrix for a projection view.
      • setEntity - Sets the entity the camera is attached to.
      • getNearPlane now takes in the float field-of-view
      • panoramicForwards - The forward vector when in panorama mode.
      • getPartialTickTime is removed
      • setLevel - Sets the level the camera is in.
      • getCameraEntityPartialTicks - Gets the partial tick based on the state of the entity.
    • DeltaTracker#advanceTime replaced by advanceGameTime when the boolean was true, and advanceRealTime
      • advanceGameTime, advanceRealTime were previously private, now public
    • FramerateLimiter - A utility for limiting the framerate of the client.
    • Minecraft
      • noRender is removed
      • useAmbientOcclusion is removed
      • getBlockRenderer is removed
      • getItemRenderer is removed
    • Options
      • getCloudsType -> getCloudStatus
      • exclusiveFullscreen - When true, fullscreen mode takes full control of the monitor.
  • net.minecraft.client.color.block
    • BlockColor replaced by BlockTintSource, not one-to-one
      • getColor -> colorInWorld, colorAsTerrainParticle; not one-to-one
    • BlockColors
      • getColor replaced by getTintSources, getTintSource; not one-to-one
      • register now takes in a list of BlockTintSources instead of a BlockColor
    • BlockTintSource - A source for how to tint a BlockState in isolation or with context.
    • BlockTintSources - Utilites for common block tint sources.
  • net.minecraft.client.data.models
    • BlockModelGenerators
      • createSuffixedVariant now takes in a function of Material to TextureMapping for the textures instead of just an Identifier
      • createAirLikeBlock now takes in a Material instead of an Identifier for the particle texture
      • generateSimpleSpecialItemModel now takes in an optional Transformation
      • createChest now has an overload that takes in the MutiblockChestResources textures
    • ItemModelGenerators#generateLayeredItem now takes in Materials instead of Identifiers for the textures
  • net.minecraft.client.data.models.model
    • ItemModelUtils
      • specialModel now has overloads that take in the Transformation
      • conditional now has overloads that take in the Transformation
      • select now has an overload that takes in the Transformation
      • selectBlockItemProperty now has an overload that takes in the Transformation
    • TexturedModel#createAllSame now takes in a Material instead of an Identifier for the texture
    • TextureMapping
      • put, putForced now take in a Material instead of an Identifier for the texture
      • get now returns a Material instead of an Identifier for the texture
      • copyAndUpdate now takes in a Material instead of an Identifier for the texture
      • updateSlots - Replaces all slots using the provided mapper function.
      • forceAllTranslucent - Sets the force translucency flag for all material textures.
      • defaultTexture, cube, cross, plant, rail, wool, crop, singleSlot, particle, torch, cauldron, layer0 now take in a Material instead of an Identifier for the texture
      • column, door, layered now take in Materials instead of Identifiers for the textures
      • getBlockTeture, getItemTexture now return a Material instead of an Identifier for the texture
  • net.minecraft.client.entity.ClientAvatarEntity#belowNameDisplay -> Entity#belowNameDisplay
  • net.minecraft.client.gui
    • Font
      • drawInBatch, drawInBatch8xOutline now take in a Matrix4fc instead of a Matrix4f for the pose
      • $GlyphVisitor#forMultiBufferSource now takes in a Matrix4fc instead of a Matrix4f for the pose
    • Gui
      • render* methods have been renamed to extract*
      • render -> extractRenderState
      • $RenderFunction interface is removed
    • GuiGraphics -> GuiGraphicsExtractor
      • hLine -> horizontalLine
      • vLine -> verticalLine
      • renderOutline -> outline
      • drawCenteredString -> centeredText
      • drawString -> text
      • drawStringWithBackdrop -> textWithBackdrop
      • renderItem -> item
      • renderFakeItem -> fakeItem
      • renderItemDecorations -> itemDecorations
      • submitMapRenderState -> map
      • submitEntityRenderState -> entity
      • submitSkinRenderState -> skin
      • submitBookModelRenderState -> book
      • submitBannerPatternRenderState -> bannerPattern
      • submitSignRenderState -> sign
      • submitProfilerChartRenderState -> profilerChart
      • renderTooltip -> tooltip
      • renderComponentHoverEffect -> componentHoverEffect, now private instead of public
  • net.minecraft.client.gui.components
    • Most methods that begin with render* or draw* have been renamed to either extract* or extract*RenderState depending on usage.
    • AbstractWidget#renderWidget -> extractWidgetRenderState
    • DebugScreenOverlay#render3dCrosshair now takes in the CameraRenderState instead of the Camera, and the gui scale int
    • LogoRenderer#renderLogo -> extractRenderState
    • PlayerFaceRenderer -> PlayerFaceExtractor
      • draw -> extractRenderState
    • Renderable#render -> extractRenderState
    • StringWidget#clipText -> ComponentRenderUtils#clipText
    • TextCursorUtils#draw* -> extract*
  • net.minecraft.client.gui.components.debugchart
    • AbstractDebugChart
      • drawChart -> extractRenderState
      • drawDimensions -> extractSampleBars
      • drawMainDimension -> extractMainSampleBar
      • drawAdditionalDimensions -> extractAdditionalSampleBars
      • renderAdditionalLinesAndLabels -> extractAdditionalLinesAndLabels
      • drawStringWithShade -> extractStringWithShade
    • ProfilerPieChart#render -> extractRenderState
  • net.minecraft.client.gui.components.spectator.SpectatorGui#render* -> extract*
  • net.minecraft.client.gui.components.toasts
    • NowPlayingToast#renderToast -> extractToast
    • Toast#render -> extractRenderState
    • ToastManager, $ToastInstance#render -> extractRenderState
    • TutorialToast$Icons#render -> extractRenderState
  • net.minecraft.client.gui.contextualbar.ContextualBarRenderer
    • renderBackground -> extractBackground
    • render -> extractRenderState
    • renderExperienceLevel -> extractExperienceLevel
  • net.minecraft.client.gui.font
    • PlainTextRenderable#renderSprite now takes in a Matrix4fc instead of a Matrix4f for the pose
    • TextRenderable#render now takes in a Matrix4fc instead of a Matrix4f for the pose
  • net.minecraft.client.gui.render
    • DynamicAtlasAllocator - An allocator for handling a dynamically sized texture atlas.
    • GuiItemAtlas - An atlas for all items displayed in a user interface.
    • GuiRenderer#incrementFrameNumber -> endFrame, not one-to-one
  • net.minecraft.client.gui.render.state.* -> .client.rendererer.state.gui.*
    • GuiItemRenderState no longer takes in the String name
      • name is removed
  • net.minecraft.client.gui.render.state.pip.* -> .client.rendererer.state.gui.pip.*
  • net.minecraft.client.gui.screens
    • LevelLoadingScreen#renderChunks -> extractChunksForRendering
    • Screen
      • renderWithTooltipAndSubtitles -> extractRenderStateWithTooltipAndSubtitles
      • renderBackground -> extractBackground
      • renderBlurredBackground -> extractBlurredBackground
      • renderPanorama -> extractPanorama
      • renderMenuBackground -> extractMenuBackground
      • renderMenuBackgroundTexture -> extractMenuBackgroundTexture
      • renderTransparentBackground -> extractTransparentBackground
  • net.minecraft.client.gui.screens.advancements
    • AdvancementTab#draw* -> extract*
    • AdvancementTabType
      • draw -> extractRenderState
      • drawIcon -> extractIcon
    • AdvancementWidget
      • draw -> extractRenderState
      • draw* -> extract*
  • net.minecraft.client.gui.screens.inventory
    • Most methods that begin with render* or draw* have been renamed to either extract* or extract*RenderState depending on usage.
    • AbstractContainerScreen
      • renderContents -> extractContents
      • renderCarriedItem -> extractCarriedItem
      • renderSnapbackItem -> extractSnapbackItem
      • renderSlots -> extractSlots
      • renderTooltip -> extractTooltip
      • renderLabels -> extractLabels
      • renderBg replaced by Screen#extractBackground
      • renderSlot -> extractSlot
    • AbstractMountInventoryScreen#drawSlot -> extractSlot
    • AbstractSignEditScreen#renderSignBackground -> extractSignBackground
    • CyclingSlotBackground#render -> extractRenderState
    • EffectsInInventory#render -> extractRenderState
    • InventoryScreen#renderEntityInInventoryFollowsMouse -> extractEntityInInventoryFollowsMouse
    • ItemCombinerScreen#renderErrorIcon -> extractErrorIcon
  • net.minecraft.client.gui.screens.inventory.tooltip
    • ClientTooltipComponent
      • renderText -> extractText
      • renderImage -> extractImage
    • TooltipRenderUtil#renderTooltipBackground -> extractTooltipBackground
  • net.minecraft.client.gui.screens.options
    • DifficultyButtons is now a record that takes in the LayoutElement, CycleButton for the difficulty, the LockIconButton, and the current Level
      • create now takes in the Level and returns the DifficultyButtons instead of a LayoutElement
      • refresh - Sets the data of the held button components.
    • HasDifficultyReaction - An interface that responds to when the difficulty has changed.
    • OptionsScreen now implements HasDifficultyReaction
    • WorldOptionsScreen now implements HasDifficultyReaction
      • The constructor now takes in the Level
  • net.minecraft.client.gui.screens.recipebook
    • GhostSlots
      • render -> extractRenderState
      • renderTooltip -> extractTooltip
    • RecipeBookComponent#render* -> extract*
    • RecipeBookPage
      • render -> extractRenderState
      • renderTooltip -> extractTooltip
  • net.minecraft.cilent.gui.screens.reporting.ChatSelectionScreen$ChatSelectionList#renderItem -> extractItem
  • net.minecraft.client.gui.screens.worldselection.AbstractGameRulesScreen$GameRuleEntry#renderLabel -> extractLabel
  • net.minecraft.client.gui.spectator.SpectatorMenuItem#renderIcon -> extractIcon
  • net.minecraft.client.model.Model#renderType now has an overload that returns the passed in function
  • net.minecraft.client.model.object.book.BookModel$State no longer takes in the animation pos, and moves the open float to the first parameter
    • forAnimation - Gets the current state of the animation for the book based on the progress.
  • net.minecraft.client.model.object.statue.CopperGolemStatueModel now uses Unit for the generic instead of Direction
  • net.minecraft.client.multiplayer.ClientLevel now implements BlockAndTintGetter
    • update - Updates the lighting of the level.
  • net.minecraft.client.multiplayer.chat.GuiMessageTag$Icon#draw -> extractRenderState
  • net.minecraft.client.particle
    • Particle#getLightColor -> getLightCoords
    • SimpleVerticalParticle - A particle that moves vertically.
    • SingleQuadParticle$Layer
      • TERRAIN -> OPAQUE_TERRAIN, TRANSLUCENT_TERRAIN
      • ITEMS -> OPAQUE_ITEMS, TRANSLUCENT_ITEMS
      • bySprite - Gets the layer from the atlas sprite.
  • net.minecraft.client.renderer
    • CachedOrthoProjectionMatrixBuffer, CachedPerspectiveProjectionMatrixBuffer, PerspectiveProjectionMatrixBuffer -> ProjectionMatrixBuffer with sometimes Projection, not one-to-one
    • CloudRenderer now takes in the cloud range int
    • CubeMap no longer takes in the Minecraft instance
    • GameRenderer now takes in the ModelManager instead of the BlockRenderDispatcher
      • PROJECTION_Z_NEAR -> Camera#PROJECTION_Z_NEAR
      • setPanoramicScreenshotParameters, getPanoramicScreenshotParameters -> Camera#enablePanoramicMode, disablePanoramicMode; not one-to-one
      • isPanoramicMode -> Camera#isPanoramicMode
      • getProjectionMatrix -> Camera#getViewRotationProjectionMatrix, not one-to-one
      • updateCamera -> Camera#update, not one-to-one
      • getRenderDistance is removed
      • cubeMap -> GuiRenderer#cubeMap, now private from protected
      • getDarkenWorldAmount -> getBossOverlayWorldDarkening
      • lightTexture -> lightmap, levelLightmap; not one-to-one
      • getLevelRenderState replaced by getGameRenderState, returning the GameRenderState instead of the LevelRenderState
      • pick -> Minecraft#pick, now private from public
      • render split between update, extract, and render; with the boolean now taking in whether to advance the game time rather than render the level
    • GlobalSettingsUniform now takes in the Vec3 camera position instead of the main Camera itself
    • ItemBlockRenderTypes is removed
      • getChunkRenderType, getMovingBlockRenderType now stored within BakedQuad$SpriteInfo
      • getRenderLayer(FluidState) -> FluidModel#layer, not one-to-one
      • setCutoutLeaves is removed
        • This should be obtained directly from the options
    • MultiblockChestResources - A record containing some data based on the ChestType.
    • LevelRenderer now takes in the GameRenderState instaed of the LevelRenderState
      • update - Updates the level.
      • renderLevel now takes in the CameraRenderState instead of the Camera, a Matrix4fc instead of a Matrix4f from the model view, and the ChunkSectionsToRender; it no longer takes in the Matrix3f for the projection matrices
      • extractLevel - Extracts the level state.
      • prepareChunkRenders is now public instead of private
      • captureFrustum, killFrustum, getCapturedFrustum are removed
      • getLightColor -> getLightCoords, now taking in the BlockAndLightGetter instead of the BlockAndTintGetter
      • $BrightnessGetter#packedBrightness now takes in the BlockAndLightGetter instead of the BlockAndTintGetter
    • LightTexture -> Lightmap
      • tick -> LightmapRenderStateExtractor#tick
      • updateLightTexture -> render
      • pack -> LightCoordsUtil#pack
      • block -> LightCoordsUtil#block
      • sky -> LightCoordsUtil#sky
      • lightCoordsWithEmission -> LightCoordsUtil#lightCoordsWithEmission
    • MaterialMapper -> SpriteMapper
    • OrderedSubmitNodeCollector
      • submitBlock is removed
      • submitBlockModel now takes in a list of BlockStateModelParts instead of the BlockStateModel, and an array of ints (array of tint colors) instead of three floats for a single color
      • submitItem no longer takes in the RenderType
      • submitModel now has overloads that takes in the Identifier for the texture, or a SpriteId with the SpriteGetter along with an int tint color
      • submitBreakingBlockModel - Submits the block breaking overlay.
    • PanoramaRenderer replaced by Panorama
      • registerTextures -> GuiRenderer#registerPanoramaTextures
      • render -> extractRenderState
    • PanoramicScreenshotParameters record is removed
    • PostChain now takes in a Projection and ProjectionMatrixBuffer instead of an CachedOrthoProjectionMatrixBuffer
      • load now takes in a Projection and ProjectionMatrixBuffer instead of an CachedOrthoProjectionMatrixBuffer
    • RenderPipelines
      • ENTITY_CUTOUT_NO_CULL -> ENTITY_CUTOUT
        • The original cutout with cull is replaced by ENTITY_CUTOUT_CULL
      • ENTITY_CUTOUT_NO_CULL_Z_OFFSET -> ENTITY_CUTOUT_Z_OFFSET
      • ENTITY_SMOOTH_CUTOUT -> END_CRYSTAL_BEAM
      • ENTITY_NO_OUTLINE replaced by ENTITY_TRANSLUCENT, render type constructed with affects outline being false
      • ENTITY_DECAL, DRAGON_EXPLOSION_ALPHA -> ENTITY_CUTOUT_DISSOLVE, not one-to-one
      • ITEM_ENTITY_TRANSLUCENT_CULL -> ENTITY_TRANSLUCENT_CULL, ITEM_CUTOUT, ITEM_TRANSLUCENT; not one-to-one
      • TRANSLUCENT_MOVING_BLOCK replaced by TRANSLUCENT_BLOCK
      • BANNER_PATTERN - A pipeline for rendering the patterns on a banner.
    • ScreenEffectRenderer#renderScreenEffect now takes in booleans for whether the player is in first person and whether to hide the GUI
    • Sheets
      • *CHEST_*LOCATION* have been combined into one of the CHEST_* fields based on what the resource was for
      • translucentBlockSheet - A cullable entity item translucent render type using the block atlas.
      • cutoutBlockItemSheet - An item cutout render type using the block atlas.
      • bannerSheet -> RenderTypes#entityTranslucent, not one-to-one
      • cutoutItemSheet - An item cutout render type using the item atlas.
      • get*Material -> get*Sprite
      • chooseMaterial -> chooseSprite
    • SpecialBlockModelRenderer replaced by BuiltInBlockModels, not one-to-one
      • renderByBlock -> BlockModelRenderState#submit*, not one-to-one
    • SubmitNodeCollection
      • getBlockSubmits is removed
      • getBreakingBlockModelSubmits - Gets the submitted breaking block overlay.
    • SubmitNodeCollector$ParticleGroupRenderer
      • isEmpty - Whether there are no particles to render in this group.
      • prepare now takes whether the particles are being prepared for the translucent layer
      • render no longer takes in the translucent boolean
    • SubmitNodeStorage
      • $BlockModelSubmit now takes in a list of BlockStateModelParts instead of the BlockStateModel, and an array of ints (array of tint colors) instead of three floats for a single color
      • $BlockSubmit is removed
      • $BreakingBlockModelSubmit - A record containing the information to render the block breaking overlay.
      • $ItemSubmit no longer takes in the RenderType
      • $MovingBlockSubmit, $NameTagSubmit, $ShadowSubmit, $TextSubmit now take in a Matrix4fc instead of a Matrix4f for the pose
    • VirtualScreen replaced by GpuBackend
  • net.minecraft.client.renderer.block
    • BlockAndTintGetter - A getter for positional block tinting (e.g., biomes).
    • BlockModelRenderState - The render state for a block model.
    • BlockModelResolver - A helper for setting up the render state for a BlockState.
    • BlockModelSet - Holds the BlockModel associated with each BlockState.
    • BlockModelShaper -> BlockStateModelSet, not one-to-one
      • getParticleIcon -> getParticleMaterial, now returning a Material$Baked instead of a TextureAtlasSprite
      • getBlockModel -> get
      • getModelManager, replaceCache are removed
    • BlockQuadOutput - A functional interface for writing the baked quad information to some output, like a buffer.
    • BlockRenderDispatcher class is removed
      • getBlockModelShaper -> getModelSet, not one-to-one
      • renderBreakingTexture replaced with SubmitNodeCollector#submitBreakingBlockModel
      • renderBatched replaced with direct call to ModelBlockRenderer#tesselateBlock
      • renderLiquid replaced with direct call to FluidRenderer#tesselate
      • renderSingleBlock is now inlined within BlockFeatureRenderer#renderBlockModelSubmits, a private method
        • Use ModelBlockRenderer#tesselateBlock as an alternative
    • FluidModel - The base fluid model that holds the data for the renderer.
    • FluidStateModelSet - Holds the FluidModel associated with each Fluid.
    • LoadedBlockModels - A task for baking the BlockModel for each BlockState.
    • LiquidBlockRenderer -> FluidRenderer, not one-to-one
      • The constructor now takes in the FluidStateModelSet instead of the SpriteGetter
      • tesselate now takes in a FluidRenderer$Output instead of a VertexConsumer
      • $Output - Gets the VertexConsumer to use for the ChunkSectionLayer.
    • ModelBlockRenderer now takes in booleans for ambient occlusion and culling
      • tesselateBlock now takes in a BlockQuadOutput instead of a VertexConsumer, the XYZ floats instead of a PoseStack, the BlockStateModel instead of the list of BlockModelParts, no longer takes in the cull boolean and int overlay, and takes in the seed long
      • tesselateWithAO -> tesselateAmbientOcclusion, now private instead of public
      • tesselateWithoutAO -> tesselateFlat, now private instead of public
      • renderModel is now inlined within BlockFeatureRenderer#renderBlockModelSubmits, a private method
      • forceOpaque - Whether the block textures should be opaque instead of translucent.
      • enableCaching -> BlockModelLighter$Cache#enable
      • clearCache -> BlockModelLighter$Cache#disable
      • $AdjacencyInfo -> BlockModelLighter$AdjacencyInfo, now private instead of protected
      • $AmbientOcclusionRenderStorage is replaced by BlockModelLighter, not one-to-one
      • $AmbientVertexRemap -> BlockModelLighter$AmbientVertexRemap
      • $Cache -> BlockModelLighter$Cache
      • $CommonRenderStorage is replaced by BlockModelLighter, not one-to-one
      • $SizeInfo -> BlockModelLighter$SizeInfo
    • MovingBlockRenderState#level -> cardinalLighting, lightEngine; not one-to-one
    • SelectBlockModel - A block model that determined or selected by its resolved property.
  • net.minecraft.client.renderer.block.model
    • BakedQuad -> .client.resources.model.geometry.BakedQuad
      • The constructor now takes in a $MaterialInfo instead of the TextureAtlasSprite, int tint index, int light emission, and boolean shade
      • FLAG_TRANSLUCENT - A flag that marks the baked quad has having translucency.
      • FLAG_ANIMATED - A flag that marks the baked quad has having an animated texture.
      • isTinted -> $MaterialInfo#isTinted
      • $MaterialFlags - An annotation that marks whether a given integer defines the flags for a material.
      • $MaterialInfo - A record holding the information on how to render the quad.
    • BlockDisplayContext - An object that represents the display context of a block.
    • BlockElement -> .client.resources.model.cuboid.CuboidModelElement
    • BlockElementFace -> .client.resources.model.cuboid.CuboidFace
    • BlockElementRotation -> .client.resources.model.cuboid.CuboidRotation
    • BlockModel - The base block model that updates the render state for use outside the world context.
      • The original implementation has been moved to .client.resources.model.cuboid.CuboidModel
    • BlockModelDefinition -> .block.dispatch.BlockStateModelDispatcher
    • BlockModelPart -> .block.dispatch.BlockStateModelPart
      • particleIcon -> particleMaterial, now returning a Material$Baked instead of a TextureAtlasSprite
      • materialFlags - Handles the flags for the material(s) used by the model.
    • BlockStateModel -> .block.dispatch.BlockStateModel
      • particleIcon -> particleMaterial, now returning a Material$Baked instead of a TextureAtlasSprite
      • materialFlags, hasMaterialFlag - Handles the flags for the material(s) used by the model.
    • BlockStateModelWrapper - The basic block model that contains the model, tints, and transformation.
    • CompositeBlockModel - Overlays multiple block models together.
    • ConditionalBlockModel - A block model that shows a different model based on a boolean obtained from some property.
    • EmptyBlockModel - A block model that shows nothing.
    • FaceBakery -> .client.resources.model.cuboid.FaceBakery
      • bakeQuad overload now takes in a ModelBaker instead of the ModelBaker$PartCache, and a Material$Baked instead of a TextureAtlasSprite
        • It also has an overload taking in the fields of the BlockElementFace instead of the object itself
      • Another bakedQuad ovrload now takes in the BakedQuad$MaterialInfo instead of the int tint index and light emission, and the shade boolean
    • ItemModelGenerator -> .client.resources.model.cuboid.ItemModelGenerator
    • ItemTransform -> .client.resources.model.cuboid.ItemTransform
    • ItemTransforms -> .client.resources.model.cuboid.ItemTransforms
    • SimpleModelWrapper -> .client.resources.model.SimpleModelWrapper
      • The constructor now takes in a Material$Baked instead of a TextureAtlasSprite for the particle
    • SimpleUnbakedGeometry -> .client.resources.model.cuboid.UnbakedCuboidGeometry
    • SingleVariant -> .block.dispatch.SingleVariant
    • SpecialBlockModelWrapper - A block model for models that submit their elements through SpecialModelRenderers.
    • TextureSlots -> .client.resources.model.sprite.TextureSlots
    • Variant -> .block.dispatch.Variant
    • VariantMutator -> .block.dispatch.VariantMutator
    • VariantSelector -> .block.dispatch.VariantSelector
  • net.minecraft.client.renderer.block.model.multipart.* -> .block.dispatch.multipart.*
  • net.minecraft.client.renderer.block.model.properties.conditional
    • ConditionalBlockModelProperty - A property that computes some boolean from the BlockState.
    • IsXmas - Returns whether the current time is between December 24th - 26th.
  • net.minecraft.client.renderer.block.model.properties.select
    • DisplayContext - A case based on the current BlockDisplayContext.
    • SelectBlockModelProperty - A property that computes some switch state from the BlockState.
  • net.minecraft.client.renderer.blockentity
    • AbstractEndPortalRenderer
      • renderCube -> submitCube, now protected and static from private
      • submitSpecial - Submits the end portal cube, used by the special renderer.
      • getExtents - Gets the vertices of each face.
      • getOffsetUp, getOffsetDown are removed
      • renderType is removed
    • AbstractSignRenderer now takes in a generic for the SignRenderState
      • getSignModel now takes in the SignRenderState generic instead of the BlockState and WoodType
      • getSignModelRenderScale, getSignTextRenderScale, getTextOffset, translateSign replaced by SignRenderState#transformations, SignRenderState$SignTransformations
      • getSignMaterial -> getSignSprite
    • BannerRenderer
      • TRANSFORMATIONS - The transformations to apply when on the wall or ground.
      • submitPatterns no longer takes in the base SpriteId, whether the pattern has foil, and the outline color
      • submitSpecial now takes in the BannerBlock$AttachmentType
    • BedRenderer
      • submitSpecial is removed
        • This is replaced by calling submitPiece twice, or making a composite for each bed part via the BedSpecialRenderer
      • submitPiece is now public from private, taking in the BedPart instead of the Model$Simple, Direction, or the boolean of whether to translate in the Z direction
      • getExtents now takes in the BedPart
      • modelTransform - Gets the transformation for the given Direction.
    • BlockEntityRenderDispatcher now takes in the BlockModelResolver instead of the BlockRenderDispatcher, and no longer takes in the ItemRenderer
      • prepare now takes in a Vec3 camera position instead of the Camera itself
    • BlockEntityRendererProvider$Context now takes in the BlockModelResolver instead of the BlockRenderDispatcher, and no longer takes in the ItemRenderer
      • materials -> sprites
    • ChestRenderer
      • LAYERS - Holds the model layers of the chest.
      • modelTransformation - Gets the transformation for the given Direction.
    • ConduitRenderer#DEFAULT_TRANSFORMATION - The default transformation to apply.
    • CopperGolemStatueBlockRenderer#modelTransformation - Gets the transformation for the given Direction.
    • DecoratedPotRenderer#modelTransformation - Gets the transformation for the given Direction.
    • HangingSignRenderer now uses a HangingSignRenderState
      • MODEL_RENDER_SCALE is now private from public
      • TRANSFORMATIONS - The transformations to apply when on the wall or ground.
      • translateBase -> baseTransformation, now private from public
      • $AttachmentType -> HangingSignBlock$Attachment
        • byBlockState -> $Models#get
      • $ModelKey record is removed
    • ShulkerBoxRenderer
      • modelTransform - Gets the transformation for the given Direction.
      • getExtents no longer takes in the Direction
    • SignRenderer -> StandingSignRenderer
      • TRANSFORMATIONS - The transformations to apply when on the wall or ground.
      • createSignModel now takes in a PlainSignBlock$Attachment instead of a boolean for whether the block is standing
    • SkullBlockRenderer
      • TRANSFORMATIONS - The transformations to apply when on the wall or ground.
      • submitSkull no longer takes in the Direction or float rotation
    • WallAndGroundTransformations - A class that holds a map of Directions to transforms to apply for the wall, and an int function to compute the ground transformations, with the int segments generally acting as the number of rotation states.
  • net.minecraft.client.renderer.blockentity.state
    • BannerRenderState
      • angle -> transformation, not one-to-one
      • standing -> attachmentType, not one-to-one
    • BedRenderState#isHead -> part, not one-to-one
    • BlockEntityRenderState#blockState is now private from public
    • ChestRenderState#angle -> facing, not one-to-one
    • CondiutRenderState -> ConduitRenderState
    • CopperGolemStatueRenderState#oxidationState - The current oxidation state.
    • HangingSignRenderState - The render state for the hanging sign.
    • ShelfRenderState#facing - The direction the shelf is facing.
    • SignRenderState#woodType - The type of wood the sign is made of.
    • SkullblockRenderState#direction, rotationDegrees -> transformation, not one-to-one
    • StandingSignRenderState - The render state for the standing sign.
  • net.minecraft.client.renderer.chunk
    • ChunkSectionLayer now takes in a boolean for whether the layer is translucent rather than just sorting on upload
      • byTransparency - Gets the layer by its transparency setting.
      • sortOnUpload -> translucent, not one-to-one
      • vertexFormat - The vertex format of the pipeline used by the layer.
    • ChunkSectionsToRender#drawsPerLayer -> drawGroupsPerLayer, with its value being a int to list of draws map
    • CompiledSectionMesh
      • uploadMeshLayer replaced by isVertexBufferUploaded, setVertexBufferUploaded
      • uploadLayerIndexBuffer replaced by isIndexBufferUploaded, setIndexBufferUploaded
    • RenderRegionCache#createRegion now takes in the ClientLevel instead of the Level
    • SectionBuffers -> SectionRenderDispatcher$RenderSectionBufferSlice, not one-to-one
    • SectionCompiler now takes in the booleans for ambient occlusion and cutout leaves, the BlockStateModelSet, the FluidStateModelSet, and the BlockColors instead of the BlockRenderDispatcher
    • SectionMesh
      • getBuffers -> getSectionDraw, not one-to-one
      • $SectionDraw - The draw information for the section.
    • SectionRenderDispatcher now takes in the SectionCompiler instead of the BlockRenderDispatcher and BlockEntityRenderDispatcher
      • getRenderSectionSlice - Gets the buffer slice of the section mesh to render for the chunk layer.
      • uploadAllPendingUploads -> uploadGlobalGeomBuffersToGPU, not one-to-one
      • lock, unlock - Handles locking the dispatcher when copying data from location to another, usually for GPU allocation.
      • getToUpload is removed
      • setLevel now takes in the SectionCompiler
      • $RenderSection
        • upload, uploadSectionIndexBuffer -> addSectionBuffersToUberBuffer, now private
        • $CompileTask
          • doTask now returns a $SectionTaskResult instead of a CompletableFuture
      • $SectionTaskResult -> $RenderSection$CompileTask$SectionTaskResult
  • net.minecraft.client.renderer.culling.Frustum now takes in a Matrix4fc instead of a Matrix4f for the model view
    • set - Copies the information from another frustum.
  • net.minecraft.client.renderer.entity
    • AbstractBoatRenderer now takes in the Identifier texture
      • renderType is removed
    • AbstractMinecartRenderer
      • BLOCK_DISPLAY_CONTEXT - The context of how to display the block inside the minecart.
      • submitMinecartContents now takes in a BlockModelRenderState instead of the BlockState
    • CopperGolemRenderer#BLOCK_DISPLAY_CONTEXT - The context of how to display the antenna block.
    • DisplayRenderer
      • BLOCK_DISPLAY_CONTEXT - The context of how to display the displayed block.
      • blockModelResolver - The block model resolver.
    • EndermanRenderer#BLOCK_DISPLAY_CONTEXT - The context of how to display the held block.
    • EntityRenderDispatcher now takes in the BlockModelResolver instead of the BlockRenderDispatcher
    • EntityRenderer#submitNameTag -> submitNameDisplay, now optionally taking in the y position int as an offset from the name tag attachment
    • EntityRendererProvider$Context now takes in the BlockModelResolver instead of the BlockRenderDispatcher
      • getMaterials -> getSprites
      • getBlockRenderDispatcher replaced by getBlockModelResolver
    • IronGolemRenderer#BLOCK_DISPLAY_CONTEXT - The context of how to display the held block.
    • ItemFrameRenderer#BLOCK_DISPLAY_CONTEXT - The context of how to display the displayed block.
    • ItemRenderer class is removed
      • Use the ItemStackRenderState to submit elements to the feature dispatcher instead
      • ENCHANTED_GLINT_ARMOR -> ItemFeatureRenderer#ENCHANTED_GLINT_ARMOR
      • ENCHANTED_GLINT_ITEM -> ItemFeatureRenderer#ENCHANTED_GLINT_ITEM
      • NO_TINT -> ItemFeatureRenderer#NO_TINT
      • getFoilBuffer -> ItemFeatureRenderer#getFoilBuffer
      • getFoilRenderType -> ItemFeatureRenderer#getFoilRenderType, now public from private
    • MushroomCowRenderer#BLOCK_DISPLAY_CONTEXT - The context of how to display the attached blocks.
    • SnowGolemRenderer#BLOCK_DISPLAY_CONTEXT - The context of how to display the head block.
    • TntRenderer#BLOCK_DISPLAY_CONTEXT - The context of how to display the TNT block.
    • TntMinecartRenderer#submitWhiteSolidBlock now takes in a BlockModelRenderState instead of the BlockState
  • net.minecraft.client.renderer.entity.layers
    • BlockDecorationLayer now takes in a function that returns a BlockModelRenderState instead of an optional BlockState
    • MushroomCowMushroomLayer no longer takes in the BlockRenderDispatcher
    • SnowGolemHeadLayer no longer takes in the BlockRenderDispatcher
  • net.minecraft.client.renderer.entity.state
    • AvatarRenderState#scoreText -> EntityRenderState#scoreText
    • BlockDisplayEntityRenderState#blockRenderState -> blockModel, now a BlockModelRenderState instead of a BlockRenderState
    • CopperGolemRenderState#blockOnAntenna now a BlockModelRenderState instead of an optional BlockState
    • EndermanRenderState#carriedBlock now a BlockModelRenderState instead of a nullable BlockState
    • IronGolemRenderState#flowerBlock - The flower held by the iron golem.
    • ItemFrameRenderState#frameModel - The model of the item frame block.
    • MinecartRenderState#displayBlockState -> displayBlockModel, now a BlockModelRenderState instead of a BlockState
    • MushroomCowRenderState#mushroomModel - The model of mushrooms attached to the cow.
    • SnowGolemRenderState#hasPumpkin -> headBlock, now a BlockModelRenderState instead of a boolean
    • TntRenderState#blockState now a BlockModelRenderState instead of a nullable BlockState
  • net.minecraft.client.renderer.features
    • Feature render methods have been split into renderSolid for solid render types, and renderTranslucent for see-through render types
    • Some render* methods now take in the OptionsRenderState
    • BlockFeatureRenderer
      • renderSolid now takes in the BlockStateModelSet instead of the BlockRenderDispatcher
      • renderTranslucent now takes in the BlockStateModelSet and the crumbling MultiBufferSource$BufferSource instead of the BlockRenderDispatcher
    • FeatureRenderDispatcher now takes in the GameRenderState and ModelManager
      • renderAllFeatures has been split into renderSolidFeatures and renderTranslucentFeatures
        • The original method now calls both of these methods, first solid then translucent
      • clearSubmitNodes - Clears the submit node storage.
      • renderTranslucentParticles - Renders collected translucent particles.
    • FlameFeatureRenderer#render -> renderSolid
    • LeashFeatureRenderer#render -> renderSolid
    • NameTagFeatureRenderer#render -> renderTranslucent
    • ShadowFeatureRenderer#render -> renderTranslucent
    • TextFeatureRenderer#render -> renderTranslucent
  • net.minecraft.client.renderer.fog
    • FogData#color - The color of the fog.
    • FogRenderer
      • setupFog now returns a FogData instead of the Vector4f fog color
      • updateBuffer - Updates the buffer with the fog data.
  • net.minecraft.client.renderer.gizmos.DrawableGizmoPrimitives#render now takes in a Matrix4fc instead of a Matrix4f for the model view
  • net.minecraft.client.renderer.item
    • BlockModelWrapper -> CuboidItemModelWrapper
      • The constructor no longer takes in the RenderType function, and now takes in the Matrix4fc transformation
      • $Unbaked now takes in an optional Transformation
    • CompositeModel$Unbaked now takes in an optional Transformation
    • ConiditionalItemModel$Unbaked now takes in an optional Transformation
    • ItemModel
      • $BakingContext
        • materials -> sprites
        • missingItem - Gets the missing item model with the given Matrix4fc transformation.
      • $Unbaked#bake now takes in the Matrix4fc transformation from any parent client items
    • ItemStackRenderState
      • pickParticleIcon -> pickParticleMaterial, now returning a Material$Baked instead of a TextureAtlasSprite
      • $LayerRenderState
        • EMPTY_TINTS - An int array representing no tints to apply.
        • setRenderType is removed
        • setParticleIcon -> setParticleMaterial, now taking a Material$Baked instead of a TextureAtlasSprite
        • setTransform -> setItemTransform
        • setLocalTransform - Sets the client item transform that’s applied after item display transforms.
        • prepareTintLayers -> tintLayers, not one-to-one
    • MissingItemModel#withTransform - Gets a missing item model with the given transform.
    • ModelRenderProperties#particleIcon -> particleMaterial, now taking a Material$Baked instead of a TextureAtlasSprite
    • RangeSelectItemModel$Unbaked now takes in an optional Transformation
    • SelectItemModel
      • $ModelSelector#get no longer supports nullable ItemModels.
      • $Unbaked now takes in an optional Transformation
      • $UnbakedSwitch#bake now takes in the Matrix4fc transformation
    • SpecialModelWrapper now takes in the Matrix4fc transformation
      • $Unbaked now takes in an optional Transformation
  • net.minecraft.client.renderer.rendertype
    • RenderType#outputTarget - Gets the output target.
    • RenderTypes
      • MOVING_BLOCK_SAMPLER replaced by createMovingBlockSetup, now private
      • entityCutoutNoCull -> entityCutout
        • The original cutout with cull is replaced by entityCutoutCull
      • entityCutoutNoCullZOffset -> entityCutoutZOffset
      • entitySmoothCutout -> endCrystalBeam
      • entityNoOutline -> entityTranslucent with affectsOutline as false
      • entityDecal, dragonExplosionAlpha -> entityCutoutDissolve, not one-to-one
      • itemEntityTranslucentCull -> entityTranslucentCullItemTarget, itemCutout, itemTranslucent; not one-to-one
      • bannerPattern - The render type for rendering the patterns of banners.
  • net.minecraft.client.renderer.special
    • BannerSpecialRenderer, $Unbaked now take in the BannerBlock$AttachmentType
      • $Unbaked now uses BannerPatternLayers for the generic
    • BedSpecialRenderer, $Unbaked now take in the BedPart
      • $Unbaked now implements NoDataSpecialModelRenderer$Unbaked
    • BellSpecialRenderer - A special renderer for the bell.
    • BookSpecialRenderer - A special renderer for the book on the enchantment table.
    • ChestSpecialRenderer$Unbaked now implements NoDataSpecialModelRenderer$Unbaked
      • The constructor now takes in the ChestType
      • *_CHEST_TEXTURE is removed from the field name, now a MultiBlockChestResources
      • ENDER_CHEST_TEXTURE -> ENDER_CHEST
    • ConduitSpecialRenderer$Unbaked now implements NoDataSpecialModelRenderer$Unbaked
    • CopperGolemStatueSpecialRenderer$Unbaked now implements NoDataSpecialModelRenderer$Unbaked
    • DecoratedPotSpecialRenderer$Unbaked now uses PotDecorations for the generic
    • EndCubeSpecialRenderer - A special renderer for the end portal cube.
    • HangingSignSpecialRenderer$Unbaked now implements NoDataSpecialModelRenderer$Unbaked
      • The constructor now takes in the HangingSignBlock$Attachment
    • NoDataSpecialModelRenderer
      • submit no longer takes in the ItemDisplayContext
      • $Unbaked - The unbaked renderer for a special model renderer not needing extracted data.
    • PlayerHeadSpecialRenderer$Unbaked now uses PlayerSkinRenderCache$RenderInfo for the generic
    • ShieldSpecialRenderer
      • DEFAULT_TRANSFORMATION - The default transformation to apply.
      • $Unbaked now uses DataComponentMap for the generic
    • ShulkerBoxSpecialRenderer, $Unbaked no longer takes in the Direction orientation
      • $Unbaked now implements NoDataSpecialModelRenderer$Unbaked
    • SkullSpecialRenderer$Unbaked now implements NoDataSpecialModelRenderer$Unbaked
    • SpecialModelRenderer
      • submit no longer takes in the ItemDisplayContext
      • $BakingContext
        • materials -> sprites
        • $Simple replaced by BlockModel$BakingContext, ItemModel$BakingContext
          • materials -> sprites
      • $Unbaked now has the generic of the argument to extract from the representing object
    • SpecialModelRenderers#createBlockRenderers -> BuiltInBlockModels#createBlockModels, not one-to-one
    • StandingSignSpecialRenderer$Unbaked now implements NoDataSpecialModelRenderer$Unbaked
      • The constructor now takes in the PlainSignBlock$Attachment
    • TridentSpecialRenderer
      • DEFAULT_TRANSFORMATION - The default transformation to apply.
      • $Unbaked now implements NoDataSpecialModelRenderer$Unbaked
  • net.minecraft.client.renderer.state.* -> .state.level.*
  • net.minecraft.client.renderer.state
    • GameRenderState - The render state of the game.
    • OptionsRenderState - The render state of the client user options.
    • WindowRenderState - The render state of the game window.
  • net.minecraft.client.renderer.state.gui.GuiRenderState#submit* methods have been renamed to add*
  • net.minecraft.client.renderer.state.level
    • BlockBreakingRenderState is now a record, and no longer extends MovingBlockRenderState
      • The constructor takes in the BlockPos, BlockState, and the current int progress
    • CameraEntityRenderState - The render state for the camera entity.
    • CameraRenderState
      • xRot, yRot - The rotation of the camera.
      • entityPos is removed
      • isPanoramicMode - Whether the camera is in panorama mode.
      • cullFrustum - The cull frustum.
      • fogType, fogData - Fog metadata.
      • hudFov - The hud field-of-view.
      • depthFar - The depth Z far plane.
      • projectionMatrix, viewRotationMatrix - The matrices for moving from world space to screen space.
      • entityRenderState - The entity the camera is attached to.
    • LevelRenderState
      • lastEntityRenderStateCount - The number of entities being rendered to the screen.
      • cloudColor, cloudHeight - Cloud metadata.
    • LightmapRenderState - The render state for the lightmap.
  • net.minecraft.client.renderer.texture
    • MipmapGenerator#generateMipLevels now takes in the computed Transparency of the image
    • SpriteContents
      • transparency - Gets the transparency of the sprite.
      • getUniqueFrames now returns an IntList instaed of an IntStream
      • computeTransparency - Computes the transparency of the selected UV bounds.
      • $AnimatedTexture#getUniqueFrames now returns an IntList instaed of an IntStream
    • TextureAtlasSprite#transparency - Gets the transparency of the sprite.
  • net.minecraft.client.resources.model
    • AtlasManager -> .model.sprite.AtlasManager
    • BlockModelRotation -> .client.renderer.block.dispatch.BlockModelRotation
    • Material -> .model.sprite.SpriteId, not one-to-one
    • MaterialSet -> .model.sprite.SpriteGetter
    • MissingBlockModel -> .model.cuboid.MissingCuboidModel
    • ModelBaker
      • sprites -> materials
      • parts -> interner
      • $PartCache -> $Interner
        • vector(float, float, float) is removed
        • materialInfo - Gets the interned material info object.
    • ModelBakery
      • BANNER_BASE -> Sheets#BANNER_BASE
      • SHIELD_BASE -> Sheets#SHIELD_BASE
      • NO_PATTERN_SHIELD -> Sheets#SHIELD_BASE_NO_PATTERN
      • LAVA_* -> FluidStateModelSet#LAVA_MODEL, now private from public
      • WATER_* -> FluidStateModelSet#WATER_MODEL, now private from public
      • $BakingResult#getBlockStateModel - Gets the BlockStateModel from the BlockState.
      • $MissingModels now takes in a MissingItemModel instead of an ItemModel for the Item, and a FluidModel
    • ModelManager
      • BLOCK_OR_ITEM is removed
      • getMissingBlockStateModel -> BlockStateModelSet#missingModel
      • getBlockModelShaper -> getBlockStateModelSet, not one-to-one
      • getBlockModelSet - Gets the map of BlockState to block model.
      • specialBlockModelRenderer is removed
      • getFluidStateModelSet - Gets the map of Fluid to fluid model.
    • ModelState -> .client.renderer.block.dispatch.ModelState
    • QuadCollection -> .model.geometry.QuadCollection
      • addAll - Adds all elements from another quad collection.
      • materialFlags, hasMaterialFlag - Handles the flags for the material(s) used by the model.
    • ResolvedModel#resolveParticleSprite -> resolveParticleMaterial, now returning a Material$Baked instead of a TextureAtlasSprite
    • SpriteGetter -> .model.sprite.MaterialBaker
    • UnbakedGeometry -> .model.geometry.UnbakedGeometry
    • WeightedVariants -> .client.renderer.block.dispatch.WeightedVariants
  • net.minecraft.client.resources.model.sprite.Material - A reference to a texture sprite, along with whether to force translucency on the texture.
  • net.minecraft.world.entity.animal.Animal#isBrightEnoughToSpawn now takes in a BlockAndLightGetter instead of the BlockAndTintGetter
  • net.minecraft.world.level
    • BlockAndTintGetter -> BlockAndLightGetter
      • BlockAndTintGetter is now client only, implementing BlockAndLightGetter
      • getShade -> cardinalLighting; not one-to-one
      • getBlockTint -> BlockAndTintGetter#getBlockTint
    • CardinalLighting - Holds the lighting applied in each direction.
    • EmptyBlockAndTintGetter -> BlockAndTintGetter#EMPTY
    • LevelReader now implements BlockAndLightGetter instead of BlockAndTintGetter
  • net.minecraft.world.level.block
    • BannerBlock$AttachmentType - Where the banner attaches to another block.
    • CeilingHangingSignBlock now implements HangingSignBlock
      • getAttachmentPoint - Gets where the sign attaches to another block.
    • HangingSignBlock - An interface that defines a hanging sign attached to another block.
    • PlainSignBlock - An inteface that defines a plain sign attached to another block.
    • StandingSignBlock now implements PlainSignBlock
    • WallingHangingSignBlock now implements HangingSignBlock
    • WallSignBlock now implements PlainSignBlock
  • net.minecraft.world.level.block.state.BlockBehaviour#getLightBlock, $BlockStateBase#getLightBlock -> getLightDampening
  • net.minecraft.world.level.block.state.properties
    • BedPart#CODEC - The codec for the bed part.
    • ChestType#CODEC - The codec for the chest type.
  • net.minecraft.world.level.dimension.DimensionType$CardinalLightType -> CardinalLighting$Type

Minor Migrations

The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.

Plantable Tags

The blocks to determine whether a plantable can survive or be placed on has been moved to block and fluid tags. Each of these tags starts with support_* along with the block (e.g., bamboo, cactus) or group (e.g., crops, dry_vegetation). This is handled by the relevant block subclasses overriding either Block#canSurvive, or for vegetation VegetationBlock#mayPlaceOn.

  • net.minecraft.world.level.block
    • AttachedStemBlock now takes in a TagKey for the blocks it can be placed on
    • FarmBlock -> FarmlandBlock
    • FungusBlock -> NetherFungusBlock, not one-to-one
    • RootsBlock -> NetherRootsBlock, not one-to-one
    • WaterlilyBlock -> LilyPadBlock, not one-to-one
    • StemBlock now takes in a TagKey for the blocks it can be placed on, and a TagKey for the blocks its fruit can be placed on

Container Screen Changes

The usage of AbstractContainerScreens has changed slightly, requiring some minor changes. First imageWidth and imageHeight are now final, settable as parameters within the constructor. If these two are not specified, they default to the original 176 x 166 background image.

// Assume some AbstractContainerMenu subclass exists
public class ExampleContainerScreen extends AbstractContainerScreen<ExampleContainerMenu> {

    // Constructor
    public ExampleContainerScreen(ExampleContainerMenu menu, Inventory playerInventory, Component title) {
        // Specify image width and height as the last two parameters in the constructor
        super(menu, playerInventory, title, 256, 256);
    }
}

Additionally, the AbstractContainerScreen#render override now calls renderTooltip at the end of the call stack. This means that, in most cases, you should not override render in subtypes of the AbstractContainerScreen. Everything can be done in one of the other methods provided by the class.

  • net.minecraft.client.gui.screens.inventory.AbstractContainerScreen now optionally takes in the background image width and height
    • imageWidth, imageHeight are now final
    • DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT - The default width and height of the container background image.
    • slotClicked now takes is a ContainerInput instead of a ClickType
    • render override now calls renderTooltip by default
  • net.minecraft.world.inventory
    • AbstractContainerMenu#clicked now takes in a ContainerInput instead of a ClickType
    • ClickType -> ContainerInput

New Tag Providers

A new TagsProvider has been added that provides a utility for working with Holder$References, known as HolderTagProvider. This is only used by the PotionTagsProvider.

Additionally, the TagBuilder now provides a method of setting the replace field on a tag, which removes all previous read entries during deserialization.

  • net.minecraft.data.tags
    • FeatureTagsProvider - A tag provider for ConfiguredFeatures.
    • HolderTagProvider - A tag provider with a utility for appending tags by their reference holder.
    • KeyTagProvider#tag now has an overload of whether to replace the entries in the tag.
    • PotionTagsProvider - A provider for potion tags.
    • TradeRebalanceTradeTagsProvider - A provider for villager trade tags for the trade rebalance.
    • VillagerTradesTagsProvider - A provider for villager trade tags.
  • net.minecraft.tags
    • FeatureTags - Tags for ConfiguredFeatures.
    • TagBuilder#shouldReplace, setReplace - Handles the replace field that removes all previously read entries during deserialization.

Test Environment State Tracking

TestEnvironmentDefinitions can now keep track of the original state of the world when being created, such that it can be properly restored on run. This is done through a generic known as the ‘SavedDataType’. On setup, each environment will return the generic data representing the original state of what was modified. Then, on teardown, the original state will be restored to the level for the next test case.

// The generic should represent the original data stored on the level
public record RespawnEnvironment(LevelData.RespawnData respawn) implements TestEnvironmentDefinition<LevelData.RespawnData> {

    @Override
    public LevelData.RespawnData setup(ServerLevel level) {
        // Modify the level while logging the original state.
        var original = level.getRespawnData();
        level.setRespawnData(this.respawn);

        // Return the original state.
        return original;
    }

    @Override
    public void teardown(ServerLevel level, LevelData.RespawnData original) {
        // Reset the state of the level to the original values.
        level.setRespawnData(original);
    }
    
    @Override
    public MapCodec<RespawnEnvironment> codec() {
        // Return the registered MapCodec here.
        // ...
    }
}
  • net.minecraft.gametest.framework.TestEnvironmentDefinition now has a generic representing the original state of the given modification performed by the test environment
    • setup now returns the generic representing the original state
    • teardown is no longer default, taking in the original state to restore
    • activate, $Activation - Handles an active test environment.

Typed Instance

TypedInstance is an interface that is attached to certain objects that represent an instance of some other ‘type’ object. For example, and Entity is a typed instance of EntityType, or a BlockState is a typed instance of Block. This interface is meant as a standard method to provide access to the type Holder and check whether the backing type, and therefore the instance, is equivalent to some identifier, tag, or raw object via is.

// For some Entity entity, check the EntityType
entity.is(EntityType.PLAYER);

// For some ItemStack itemStack, check the Item
itemStack.is(ItemTags.BUTTONS);

// For some BlockEntity blockEntity, check the BlockEntityType
blockEntity.is(BlockEntityType.CHEST);

// For some BlockState blockState, check the Block
blockState.is(Blocks.DIRT);

// For some FluidState fluidState, check the Fluid
fluidState.is(FluidTags.WATER);
  • net.minecraft.core.TypedInstance - An interface that represents that this object is an instance for some other ‘type’ object.
  • net.minecraft.world.entity
    • Entity now implements TypedInstance<EntityType<?>>
    • EntityType#is -> TypedInstance#is
      • Now on the Entity instance
  • net.minecraft.world.item.ItemStack now implements TypedInstance<Item>
    • getItemHolder -> typeHolder
    • getTags -> tags
  • net.minecraft.world.level.block.entity
    • BlockEntity now implements TypedInstance<BlockEntityType>
    • BlockEntityType#getKey is removed
  • net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase now implements TypedInstance<Block>
    • getBlockHolder -> typeHolder
    • getTags -> tags
  • net.minecraft.world.level.material.FluidState now implements TypedInstance<Fluid>
    • holder -> typeHolder
    • getTags -> tags

Entity Textures and Adult/Baby Models

Entity textures within assets/minecraft/textures/entity/* have now been sorted into subdirectories (e.g., entity/panda for panda textures, or entity/pig for pig textures). Most textures have been named with the entity type starting followed by an underscore along with its variant (e.g., arrow_tipped for tipped arrow, pig_cold for the cold pig variant, or panda_brown for the brown panda variant).

Additionally, some animal models have been split into separate classes for the baby and adult variants. These models either directly extend an abstract model implementation (e.g., AbstractFelineModel) or the original model class (e.g., PigModel).

  • net.minecraft.client.animation.definitions
    • BabyArmadilloAnimation - Animations for the baby armadillo.
    • BabyAxolotlAnimation - Animations for the baby axolotl.
    • BabyRabbitAnimation - Animations for the baby rabbit.
    • CamelBabyAnimation - Animations for the baby camel.
    • FoxBabyAnimation - Animations for the baby fox.
    • RabbitAnimation - Animations for the rabbit.
  • net.minecraft.client.model
    • HumanoidModel
      • ADULT_ARMOR_PARTS_PER_SLOT, BABY_ARMOR_PARTS_PER_SLOT - A map of equipment slot to model part keys.
      • createBabyArmorMeshSet - Creates the armor model set for a baby humanoid.
      • createArmorMeshSet can now take in a map of equipment slot to model part keys for what to retain
      • setAllVisible is removed
    • QuadrupedModel now has a constructor that takes in a function for the RenderType
  • net.minecraft.client.model.animal.armadillo
    • AdultArmadilloModel - Entity model for the adult armadillo.
    • ArmadilloModel is now abstract
      • The constructor now takes in the definitions for the walk, roll out/up, and peek animations
      • BABY_TRANSFORMER has been directly merged into the layer definition for the BabyArmadilloModel
      • HEAD_CUBE, RIGHT_EAR_CUBE, LEFT_EAR_CUBE are now protected instead of private
      • createBodyLayer -> AdultArmadilloModel#createBodyLayer, BabyArmadilloModel#createBodyLayer
    • BabyArmadilloModel - Entity model for the baby armadillo.
  • net.minecraft.client.model.animal.axolotl.AxolotlModel -> AdultAxolotlModel, BabyAxolotlModel
  • net.minecraft.client.model.animal.bee
    • AdultBeeModel - Entity model for the adult bee.
    • BabyBeeModel - Entity model for the baby bee.
    • BeeModel is now abstract
      • BABY_TRANSFORMER has been directly merged into the layer definition for the BabyBeeModel
      • BONE, STINGER, FRONT_LEGS, MIDDLE_LEGS, BACK_LEGS are now protected instead of private
      • bone is now protected instead of private
      • createBodyLayer -> AdultBeeModel#createBodyLayer, BabyBeeModel#createBodyLayer
      • bobUpAndDown - Bobs the bee up and down at the desired speed, depending on its current age.
  • net.minecraft.client.model.animal.camel
    • AdultCamelModel - Entity model for the adult camel.
    • BabyCamelModel - Entity model for the baby camel.
    • CamelModel is now abstract
      • The constructor now takes in the definitions for the walk, sit with/without pose, standup, idle, and dash animations
      • BABY_TRANSFORMER has been directly merged into the layer definition for the BabyCamelModel
      • createBodyLayer -> AdultCamelModel#createBodyLayer, BabyCamelModel#createBodyLayer
    • CameSaddleModel now extends AdultCamelModel instead of CamelModel
  • net.minecraft.client.model.animal.chicken
    • AdultChickenModel - Entity model for the adult chicken.
    • BabyChickenModel - Entity model for the baby chicken.
    • ChickenModel is now abstract
      • RED_THING -> AdultChickenModel#RED_THING
      • BABY_TRANSFORMER has been directly merged into the layer definition for the BabyChickenModel
      • createBodyLayer -> AdultChickenModel#createBodyLayer
      • createBaseChickenModel -> AdultChickenModel#createBaseChickenModel
    • ColdChickenModel now extends AdultChickenModel
  • net.minecraft.client.model.animal.cow.BabyCowModel - Entity model for the baby cow.
  • net.minecraft.client.model.animal.dolphin.BabyDolphinModel - Entity model for the baby dolphin.
  • net.minecraft.client.model.animal.equine
    • AbstractEquineModel now has an overload that directly specifies the ModelParts to use
      • BABY_TRANSFORMER has been directly merged into the layer definition for the BabyDonkeyModel
      • rightHindLeg, leftHindLeg, rightFrontLeg, leftFrontLeg are now protected from private
      • createBabyMesh -> BabyHorseModel#createBabyMesh, not one-to-one
      • offsetLegPositionWhenStanding - Offsets the position of the legs when the entity is standing.
      • getLegStandAngle, getLegStandingYOffset, getLegStandingZOffset, getLegStandingXRotOffset, getTailXRotOffset - Offsets and angles for parts of the equine model.
      • animateHeadPartsPlacement - Animates the head based on its eating and standing states.
    • BabyDonkeyModel - Entity model for the baby donkey.
    • BabyHorseModel - Entity model for the baby horse.
    • DonkeyModel now has an overload that directly specifies the ModelParts to use
      • createBabyLayer -> BabyDonkeyModel#createBabyLayer
    • EquineSaddleModel#createFullScaleSaddleLayer is removed Merged into createSaddleLayer, with the baby variant removed
  • net.minecraft.client.model.animal.feline
    • CatModel -> AdultCatModel, BabyCatModel; not one-to-one
    • FelineModel -> AbstractFelineModel, not one-to-one
      • Implementations in AdultFelineModel and BabyFelineModel
    • OcelotModel -> AdultOcelotModel, BabyOcelotModel; not one-to-one
  • net.minecraft.client.model.animal.fox
    • AdultFoxModel - Entity model for the adult fox.
    • BabyFoxModel - Entity model for the baby fox.
    • FoxModel is now abstract
      • BABY_TRANSFORMER has been directly merged into the layer definition for the BabyFoxModel
      • body, rightHindLeg, leftHindLeg, rightFontLeg, leftFrontLeg, tail are now protected instead of private
      • createBodyLayer -> AdultFoxModel#createBodyLayer, BabyFoxModel#createBodyLayer
      • set*Pose - Methods for setting the current pose of the fox.
  • net.minecraft.client.model.animal.goat
    • BabyGoatModel - Entity model for the baby goat.
    • GoatModel#BABY_TRANSFORMER has been directly merged into the layer definition for the BabyGoatModel
  • net.minecraft.client.model.animal.llama
    • BabyLlamaModel - Entity model for the baby llama.
    • LlamaModel#createBodyLayer no longer takes in the boolean for if the entity is a baby
  • net.minecraft.client.model.animal.panda
    • BabyPandaModel - Entity model for the baby panda.
    • PandaModel
      • BABY_TRANSFORMER has been directly merged into the layer definition for the BabyPandaModel
      • animateSitting - Animates the panda sitting.
  • net.minecraft.client.model.animal.pig.BabyPigModel - Entity model for the baby pig.
  • net.minecraft.client.model.animal.polarbear
    • BabyPolarBearModel - Entity model for the baby polar bear.
    • PolarBearModel#BABY_TRANSFORMER has been directly merged into the layer definition for the BabyPolarBearModel
  • net.minecraft.client.model.animal.rabbit
    • AdultRabbitModel - Entity model for the adult rabbit.
    • BabyRabbitModel - Entity model for the baby rabbit.
    • RabbitModel is now abstract
      • The constructor now takes in two animation definitions for the hop and idle head tilt
      • FRONT_LEGS, BACK_LEGS - The child name for the entity legs.
      • LEFT_HAUNCH, RIGHT_HAUNCH are now protected
      • createBodyLayer -> AdultRabbitModel#createBodyLayer, BabyRabbitModel#createBodyLayer; not one-to-one
  • net.minecraft.client.model.animal.sheep
    • BabySheepModel - Entity model for the baby sheep.
    • SheepModel#BABY_TRANSFORMER has been directly merged into the layer definition for the BabySheepModel
  • net.minecraft.client.model.animal.sniffer
    • SnifferModel#BABY_TRANSFORMER has been directly merged into the layer definition for the SniffletModel
    • SniffletModel - Entity model for the baby sniffer.
  • net.minecraft.client.model.animal.squid
    • BabySquidModel - Entity model for the baby squid.
    • SquidModel#createTentacleName is now protected from private
  • net.minecraft.client.model.animal.turtle
    • AdultTurtleModel - Entity model for the adult turtle.
    • BabyTurtleModel - Entity model for the baby turtle.
    • TurtleModel is now abstract
      • The constructor can how take in the render type function
      • BABY_TRANSFORMER has been directly merged into the layer definition for the BabyTurtleModel
      • createBodyLayer -> AdultTurtleModel#createBodyLayer, BabyTurtleModel#createBodyLayer
  • net.minecraft.client.model.animal.wolf
    • AdultWolfModel - Entity model for the adult wolf.
    • BabyWolfModel - Entity model for the baby wolf.
    • WolfModel is now abstract
      • ModelPart fields are now all protected
      • createMeshDefinition -> AdultWolfModel#createBodyLayer, BabyWolfModel#createBodyLayer; not one-to-one
      • shakeOffWater - Sets the body rotation when shaking off water.
      • setSittingPose - Sets the sitting pose of the wolf.
  • net.minecraft.client.model.geom
    • ModelLayers
      • COLD_CHICKEN_BABY is removed
      • COLD_PIG_BABY is removed
      • PIG_BABY_SADDLE is removed
      • SHEEP_BABY_WOOL_UNDERCOAT is removed
      • WOLF_BABY_ARMOR is removed
      • DONKEY_BABY_SADDLE is removed
      • HORSE_BABY_ARMOR is removed
      • HORSE_BABY_SADDLE is removed
      • MULE_BABY_SADDLE is removed
      • SKELETON_HORSE_BABY_SADDLE is removed
      • UNDEAD_HORSE_BABY_ARMOR is removed
      • ZOMBIE_HORSE_BABY_SADDLE is removed
      • STRIDER_BABY_SADDLE is removed
    • PartNames#WAIST - The waist part.
  • net.minecraft.client.model.monster.hoglin
    • BabyHoglinModel - Entity model for the baby hoglin.
    • HoglinModel
      • BABY_TRANSFORMER has been directly merged into the layer definition for the BabyHoglinModel
      • head is now protected from private
      • createBabyLayer -> BabyHoglinModel#createBodyLayer
  • net.minecraft.client.model.monster.piglin
    • AbstractPiglinModel is now abstract
      • leftSleeve, rightSleeve, leftPants, rightPants, jacket are removed
      • ADULT_EAR_ANGLE_IN_DEGREES, BABY_EAR_ANGLE_IN_DEGREES - The angle of the piglin ears.
      • createMesh replaced by AdultPiglinModel#createBodyLayer, AdultZombifiedPiglinModel#createBodyLayer, BabyPiglinModel#createBodyLayer, BabyZombifiedPiglinModel#createBodyLayer
      • createBabyArmorMeshSet - Create the armor meshes for the baby piglin model.
      • getDefaultEarAngleInDegrees - Gets the default ear angle.
    • AdultPiglinModel - Entity model for the adult piglin.
    • AdultZombifiedPiglinModel - Entity model for the adult zombified piglin.
    • BabyPiglinModel - Entity model for the baby piglin.
    • BabyZombifiedPiglinModel - Entity model for the baby zombified piglin.
    • PiglinModel is now abstract
    • ZombifiedPiglinModel is now abstract
  • net.minecraft.client.model.monster.strider
    • AdultStriderModel - Entity model for the adult strider.
    • BabyStriderModel - Entity model for the baby strider.
    • StriderModel is now abstract
      • BABY_TRANSFORMER has been directly merged into the layer definition for the BabyStriderModel
      • rightLeg, leftLeg, body are now protected from private
      • SPEED - The speed scalar of the movement animation.
      • customAnimations - Additional animation setup.
      • animateBristle - Animates the bristles of the strider.
  • net.minecraft.client.model.monster.zombie
    • BabyDrownedModel - Entity model for the baby drowned.
    • BabyZombieModel - Entity model for the baby zombie.
    • BabyZombieVillagerModel - Entity model for the baby zombie villager.
  • net.minecraft.client.model.npc
    • BabyVillagerModel - Entity model for the baby villager.
    • VillagerModel#BABY_TRANSFORMER has been directly merged into the layer definition for the BabyVillagerModel
  • net.minecraft.client.renderer.entity
    • AxolotlRenderer now takes in an EntityModel<AxolotlRenderState> for its generic
    • CamelHuskRenderer now extends MobRenderer instead of CamelRenderer
    • CamelRenderer#createCamelSaddleLayer is now static
    • CatRenderer now takes in an AbstractFelineModel for its generic
    • DonkeyRenderer now takes in an EquipmentClientInfo$LayerType and ModelLayerLocation for the saddle layer and model, and splits the DonkeyRenderer$Type into the adult type and baby type
      • $Type
        • DONKEY_BABY - A baby variant of the donkey.
        • MULE_BABY - A baby variant of the mule.
    • OcelotRenderer now takes in an AbstractFelineModel for its generic
    • UndeadHorseRenderer now takes in an EquipmentClientInfo$LayerType and ModelLayerLocation for the saddle layer and model, and splits the UndeadHorseRenderer$Type into the adult type and baby type
      • $Type
        • SKELETON_BABY - A baby variant of the skeleton horse.
        • ZOMBIE_BABY - A baby variant of the zombie horse.
  • net.minecraft.client.renderer.entity.layers.CatCollarLayer now takes in an AbstractFelineModel for its generic
  • net.minecraft.client.renderer.entity.state
    • AxolotlRenderState
      • swimAnimation - The state of swimming.
      • walkAnimationState - The state of walking on the ground, not underwater.
      • walkUnderWaterAnimationState - The state of walking underwater.
      • idleUnderWaterAnimationState - The state of idling underwater but not on the ground.
      • idleUnderWaterOnGroundAnimationState - The state of idling underwater while touching the seafloor.
      • idleOnGroundAnimationState - The state of idling on the ground, not underwater.
      • playDeadAnimationState - The state of playing dead.
    • RabbitRenderState
      • hopAnimationState - The state of the hop the entity is performing.
      • idleHeadTiltAnimationState - The state of the head tilt when performing the idle animation.
  • net.minecraft.client.resources.model.EquipmentClientInfo$LayerType#HUMANOID_BABY - The baby humanoid equipment layer.
  • net.minecraft.sounds.SoundEvents#PIG_EAT_BABY - Ths sound played when a baby big is eating.
  • net.minecraft.world.entity.AgeableMob
    • canUseGoldenDandelion - Whether a golden dandelion can be used to agelock an entity.
    • setAgeLocked - Sets the entity as agelocked.
    • makeAgeLockedParticle - Creates the particles when agelocking an entity.
    • AGE_LOCK_DOWNWARDS_MOVING_PARTICLE_Y_OFFSET - The Y offset for the particle’s starting position.
  • net.minecraft.world.entity.animal.axolotl.Axolotl
    • swimAnimation - The state of swimming.
    • walkAnimationState - The state of walking on the ground, not underwater.
    • walkUnderWaterAnimationState - The state of walking underwater.
    • idleUnderWaterAnimationState - The state of idling underwater but not on the ground.
    • idleUnderWaterOnGroundAnimationState - The state of idling underwater while touching the seafloor.
    • idleOnGroundAnimationState - The state of idling on the ground, not underwater.
    • playDeadAnimationState - The state of playing dead.
    • $AnimationState -> $AxolotlAnimationState
  • net.minecraft.world.entity.animal.chicken.ChickenVariant now takes in a resource for the baby texture
  • net.minecraft.world.entity.animal.cow.CowVariant now takes in a resource for the baby texture
  • net.minecraft.world.entity.animal.cat.CatVariant now takes in a resource for the baby texture
    • CatVariant#assetInfo - Gets the entity texture based on whether the entity is a baby.
  • net.minecraft.world.entity.animal.equine.AbstractHorse#BABY_SCALE - The scale of the baby size compared to an adult.
  • net.minecraft.world.entity.animal.frog.Tadpole
    • ageLockParticleTimer - A timer for how long the particles for the agelocked entity should spawn.
    • setAgeLocked, isAgeLocked - Handles agelocking for the tadpole.
  • net.minecraft.world.entity.animal.goat.Goat
    • BABY_DEFAULT_X_HEAD_ROT - The default head X rotation for the baby variant.
    • MAX_ADDED_RAMMING_X_HEAD_ROT - The maximum head X rotation.
    • addHorns, removeHorns are removed
  • net.minecraft.world.entity.animal.pig.PigVariant now takes in a resource for the baby texture
  • net.minecraft.world.entity.animal.rabbit.Rabbit
    • hopAnimationState - The state of the hop the entity is performing.
    • idleHeadTiltAnimationState - The state of the head tilt when performing the idle animation.
  • net.minecraft.world.entity.animal.wolf
    • WolfSoundVariant -> WolfSoundVariant$WolfSoundSet
      • The class itself now holds two sound sets for the adult wolf and baby wolf.
    • WolfSoundVariants$SoundSet#getSoundEventSuffix -> getSoundEventIdentifier
  • net.minecraft.world.entity.animal.wolf.WolfVariant now takes in an asset info for the baby variant
  • net.minecraft.world.item.equipment.EquipmentAssets#TRADER_LLAMA_BABY - Equipment asset for baby trader llamas.

The Removal of interactAt

Entity#interactAt has been removed, with all further invocation merged with Entity#interact. Originally, Entity#interactAt was called if the hit result was within the entity’s interaction range. If interactAt did not consume the action (i.e., InteractionResult#consumesAction returns false), then Entity#interact is called. Now, Entity#interact is called if within the entity’s interaction range, taking in the Vec3 location of interaction.

// In some Entity subclass

@Override
public InteractionResult interact(Player player, InteractionHand hand, Vec3 location) {
    // Handle the interaction
    super.interact(player, hand, location);
}

interactAt checks if result does not consume the interaction, and if not calls interact Now, interact is called with the entity hit

  • net.minecraft.client.multiplayer.MultiPlayerGameMode
    • interact now takes in the EntityHitResult
    • interactAt is removed
  • net.minecraft.world.entity.Entity
    • interact now takes in a Vec3 for the location of the interaction
    • interactAt is removed
  • net.minecraft.world.entity.player.Player#interactOn now takes in a Vec3 for the location of the interaction

ChunkPos, now a record

ChunkPos is now a record. The BlockPos constructor has been replaced by ChunkPos#containing while the packed long constructor has been replaced by ChunkPose#unpack.

  • net.minecraft.world.level.ChunkPos is now a record
    • ChunkPos(BlockPos) -> containing
    • ChunkPos(long) -> unpack
    • toLong, asLong -> pack

No More Tripwire Pipelines

The tripwire render pipeline has been completely removed. Now, tripwires make use of cutout with an alpha_cutoff_bias of 0.1 for the texture.

  • net.minecraft.client.renderer.RenderPipelines#TRIPWIRE_BLOCK, TRIPWIRE_TERRAIN are removed
  • net.minecraft.client.renderer.chunk
    • ChunkSectionLayer#TRIPWIRE is removed
    • ChunkSectionLayerGroup#TRIPWIRE is removed
  • net.minecraft.client.renderer.rendertype.RenderTypes#tripwireMovingBlock is removed

Activities and Brains

Activities, which define how a living entity behaves during a certain phase, now are stored and passed around through ActivityData. This contains the activity type, the behaviors to perform along with their priorities, the conditions on when this activity activates, and the memories to erase when the activity has stopped. Brain#provider now takes in an $ActivitySupplier to construct a list of ActivityData the entity performs.

Brains have also changed slightly. First, the Brain itself is not directly serializable. Instead, the brain is $Packed into the record, holding a map of its current memories. To get the memory types used, they are typically extracted from those that the Sensor#requires. Additionally, LivingEntity#brainProvider no longer exists, instead opting to store the provider in a static constant on the entity itself. This means that brains are now completely constructed through the makeBrain method, taking in the previous $Packed data:

// For some ExampleEntity extends LivingEntity
// Assume extends Mob subclass
private static final Brain.Provider<ExampleEntity> BRAIN_PROVIDER = Brain.provider(
    // The list of sensors the entity uses.
    ImmutableList.of(),
    // A function that takes in the entity and returns a list of activities.
    entity -> List.of(
        new ActivityData(
            // The activity type
            Activity.CORE,
            // A list of priority and behavior pairs
            ImmutableList.of(Pair.of(0, new MoveToTargetSink())),
            // A set of memory conditions for the activity to run
            // For example, this memory value must be present
            ImmutableSet.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT)),
            // The set of memories to erase when the activity has stopped
            ImmutableSet.of(MemoryModuleType.ATTACK_TARGET)
        )
    )
);

@Override
protected Brain.Provider<ExampleEntity> makeBrain(Brain.Packed packedBrain) {
    // Make the brain, populating any previous memories
    return BRAIN_PROVIDER.makeBrain(this, packedBrain);
}
  • net.minecraft.world.entity.LivingEntity
    • brainProvider is removed
    • makeBrain now takes in a Brain$Packed instead of a Dynamic
  • net.minecraft.world.entity.ai
    • ActivityData - A record containing the activity being performed, the behaviors to perform during that activity, any memory conditions, and what memories to erase once stopped.
    • Brain is now protected, taking in a list of ActivityData, a MemoryMap instead of an immutable list of memories, a RandomSource, and not the supplied Codec
      • The public constructor no longer takes in anything
      • provider now has an overload that only takes in the sensor types, defaulting the memory types to an empty list
        • Some provider methods also take in the Brain$ActivitySupplier to perform
      • codec, serializeStart are replaced by pack, Brain$Packed
      • addActivityAndRemoveMemoryWhenStopped, addActivityWithConditions merged into addActivity
        • Alternatively use ActivityData#create
      • copyWithoutBehaviors is removed
      • getMemories replaced by forEach
      • $ActivitySupplier - Creates a list of activities for the entity.
      • $MemoryValue is removed
      • $Packed - A record containing the data to serialize the brain to disk.
      • $Provider#makeBrain now takes in the entity and the Brain$Packed to deserialize the memories
      • $Visitor - Visits the memories within a brain, whether defined but empty, present, or present with some timer.
  • net.minecraft.world.entity.ai.behavior.VillagerGoalPackages#get*Package no longer take in the VillagerProfession
  • net.minecraft.world.entity.ai.memory
    • ExpirableValue -> MemorySlot, not one-to-one
      • The original ExpirableValue is now a record that defines when a memory should expire, rather than be updated itself
    • MemoryMap - A map linking the memory type to its stored value.
    • MemoryModuleType - Whether a memory can be serialized.
  • net.minecraf.tworld.entity.ai.sensing.Sensor#randomlyDelayStart - How long to delay a sensor.
  • net.minecraft.world.entity.animal.allay.AllayAi
    • SENSOR_TYPES, MEMORY_TYPES -> BRAIN_PROVIDER, now private; not one-to-one
    • makeBrain -> getActivities, not one-to-one
  • net.minecraft.world.entity.animal.armadillo.ArmadilloAi#makeBrain, brainProvider -> getActivities, now protected, not one-to-one
  • net.minecraft.world.entity.animal.axolotl
    • AxolotlSENSOR_TYPES -> BRAIN_PROVIDER, now private; not one-to-one
    • AxolotlAi
      • makeBrain -> getActivities, not one-to-one
      • initPlayDeadActivity, now protected, no longer taking in anything
      • initFightActivity, now protected, no longer taking in anything
      • initCoreActivity, now protected, no longer taking in anything
      • initIdleActivity, now protected, no longer taking in anything
  • net.minecraft.world.entity.animal.camel.CamelAi#makeBrain, brainProvider -> getActivities, now protected, not one-to-one
  • net.minecraft.world.entity.animal.frog
    • Frog#SENSOR_TYPES -> BRAIN_PROVIDER, now private; not one-to-one
    • FrogAi#makeBrain -> getActivities, not one-to-one
    • Tadpole#SENSOR_TYPES -> BRAIN_PROVIDER, now private; not one-to-one
  • net.minecraft.world.entity.animal.frog.TadpoleAi#makeBrain -> getActivities, now public, not one-to-one
  • net.minecraft.world.entity.animal.goat
    • Goat#SENSOR_TYPES -> BRAIN_PROVIDER, now private; not one-to-one
    • GoatAi#makeBrain -> getActivities, not one-to-one
  • net.minecraft.world.entity.animal.golem.CopperGolemAi#makeBrain, brainProvider -> getActivities, now protected, not one-to-one
  • net.minecraft.world.entity.animal.happyghast.HappyGhastAi#makeBrain, brainProvider -> getActivities, now protected, not one-to-one
  • net.minecraft.world.entity.animal.nautilus
    • NautilusAi
      • SENSOR_TYPES,MEMORY_TYPES -> Nautilus#BRAIN_PROVIDER, now private, not one-to-one
      • makeBrain, brainProvider -> getActivities, now public, not one-to-one
    • ZombieNautilusAi
      • SENSOR_TYPES,MEMORY_TYPES -> ZombieNautilus#BRAIN_PROVIDER, now private, not one-to-one
      • makeBrain, brainProvider -> getActivities, now public, not one-to-one
  • net.minecraft.world.entity.animal.sniffer.SnifferAi#makeBrain -> getActivities, now public, not one-to-one
  • net.minecraft.world.entity.monster.Zoglin
    • SENSOR_TYPES -> BRAIN_PROVIDER, now private, not one-to-one
    • getActivities - The activities the zoglin performs.
  • net.minecraft.world.entity.monster.breeze.BreezeAi#makeBrain -> getActivities, not one-to-one
  • net.minecraft.world.entity.monster.creaking.CreakingAi#makeBrain, brainProvider -> getActivities, now protected, not one-to-one
  • net.minecraft.world.entity.monster.hoglin
    • Hoglin#SENSOR_TYPES -> BRAIN_PROVIDER, now private; not one-to-one
    • HoglinAi#makeBrain -> getActivities, not one-to-one
  • net.minecraft.world.entity.monster.piglin
    • Piglin#SENSOR_TYPES,MEMORY_TYPES -> BRAIN_PROVIDER, now private, not one-to-one
    • PiglinAi#makeBrain -> getActivities, now public, not one-to-one
    • PiglinBrute#SENSOR_TYPES,MEMORY_TYPES -> BRAIN_PROVIDER, now private, not one-to-one
    • PiglinBruteAi#makeBrain -> getActivities, now public, not one-to-one
  • net.minecraft.world.entity.monster.warden.WardenAi#makeBrain -> getActivities, not one-to-one

File Fixer Upper

The file fixer upper is a new system to help with upgrading game files between versions, in conjunction with the data fixer upper. Similar to how the data within files can be modified or ‘upgraded’ between Minecraft versions via data fixers, file fixers can modify anything within a world directory, from moving files and directories to deleting them outright. As such, file fixers are always applied before data fixers.

Unlike when upgrading when data fixers, file fixers change the structure of the world folder. Because of this, downgrading is rarely possible, as the file names and locations will have likely changed location.

File fixers are applied through a FileFix, which defines some operation(s) to perform on a file using makeFixer. This is done typically through the addFileContentFix, providing access to the desired files through the FileAccess, and then modifying the data like any other Dynamic instance. Operations are commonly defined as FileFixOperations, which can move the file structure around.

The file fixes are then applied through the FileFixerUpper, which uses a copy-on-write file system to operate on the files. The fixer is constructed using the $Builder, using addSchema and addFixer to apply the fixers for the desired version. During the upgrade process, the files are created in a temporary folder, then moved to the world folder. The original world folder is moved to another folder before being deleted.

  • net.minecraft.client.gui.screens.FileFixerAbortedScreen - A screen that’s shown when the file fixing has been aborted.
  • net.minecraft.client.gui.screens.worldselection.FileFixerProgressScreen - A screen that’s displayed when attempting to show the progress of upgrading and fixing the world files.
  • net.minecraft.server.packs.linkfs
    • DummyFileAttributes -> .minecraft.util.DummyFileAttributes
    • LinkFSPath
      • DIRECTORY_ATTRIBUTES -> DummyFileAttributes#DIRECTORY
      • FILE_ATTRIBUTES -> DummyFileAttributes#FILE
  • net.minecraft.util
    • ExtraCodecs
      • pathCodec - A codec for a path, converting from a string and storing with Unix separators.
      • relaiveNormalizedSubPathCodec - A codec for a path, normalized and validated to make sure it is relative.
      • guardedPathCodec - A codec for a path, resolved and relativatized from some base path.
    • FileUtil
      • isPathNormalized, createPathToResource are removed
      • isEmptyPath - Returns whether the path is empty.
    • Util#safeMoveFile - Safely moves a file from some source to a destination with the given options.
  • net.minecraft.util.filefix
    • AbortedFileFixException - An exception thrown when the file fix has been aborted and was unable to revert moves.
    • AtmoicMoveNotSupportedFileFixException - An exception thrown when the user file system does not support atomic moves.
    • CanceledFileFixException - An exception thrown when the file fix upgrade proccess is canceled.
    • FailedCleanupFileFixException - An exception thrown when the file fix was not able to move or delete folders for cleanup.
    • FileFix - A fixer that performs some operation on a file.
    • FileFixerUpper - The file fixers to perform operations with.
    • FileFixException - An exception thrown when attempting to upgrade a world through the file fixer.
    • FileFixUtil - A utility for performing some file operations.
    • FileSystemCapabilities - The capabilities of the file system from a directory.
  • net.minecraft.util.filefix.access
    • ChunkNbt - Handles upgrading a chunk nbt.
    • CompressedNbt - Handles upgrading a compressed nbt file.
    • FileAccess - Provides an reference to some file resource(s), given its relation.
    • FileAccessProvider - A provider of file accesses, given some relation to the origin.
    • FileRelation - A definition of how a file relates to some origin bpath.
    • FileResourceType - Defines the type of resource to access.
    • FileResourceTypes - All defined file resource types.
    • LevelDat - Handles upgrading a level dat.
    • PlayerData - Handles upgrading the player data.
    • SavedDataNbt - Handles upgrading the saved data.
  • net.minecraft.util.filefix.fixes.* - The vanilla fixes to apply to the file(s).
  • net.minecraft.util.filefix.operations
    • ApplyInFolders - Applies the given operations within the related folders.
    • DeleteFileOrEmptyDirectory - Deletes the target file or empty directory.
    • FileFixOperation - An operation performed within some base directory.
    • FileFixOperations - All vanilla file fix operations.
    • GroupMove - Moves some directory, applying any move operation on its contents.
    • ModifyContent - Modifies the content of a file.
    • Move - Moves a file from some source to some destination.
    • RegexMove - Moves all files that match the given source pattern to the destination, replacing the matched sections.
  • net.minecraft.util.filefix.virtualfilesystem
    • CopyOnWriteFileStore - A file store using the copy-on-write principle.
    • CopyOnWriteFileSystem - A file system using the copy-on-write principle.
    • CopyOnWriteFSPath - A path using the copy-on-write principle.
    • CopyOnWriteFSProvider - A file system provider using the copy-on-write principle.
    • DirectoryNode - A directory node for some copy-on-write file system path.
    • FileMove - A record containing the path a file has been moved from to.
    • FileNode - A file node for some copy-on-write file system path.
    • Node - A node for some copy-on-write file system path.
  • net.minecraft.util.filefix.virtualfilesystem.exception
    • CowFSCreationException - A CowFSFileSystemException when the file system cannot be created.
    • CowFSDirectoryNotEmptyException - A DirectoryNotEmptyException specifically for a copy-on-write system.
    • CowFSFileAlreadyExistsException - A FileAlreadyExistsException specifically for a copy-on-write system.
    • CowFSFileSystemException - A FileSystemException specifically for a copy-on-write system.
    • CowFSIllegalArgumentException - An IllegalArgumentException when attempting to operate upon a copy-on-write system.
    • CowFSNoSuchFileException - A NoSuchFileException specifically for a copy-on-write system.
    • CowFSNotDirectoryException - A NotDirectoryException specifically for a copy-on-write system.
    • CowFSSymlinkException - A CowFSCreationException when attempting to use the copy-on-write system with a symlink.
  • net.minecraft.util.worldupdate
    • UpgradeProgress
      • getTotalFiles -> getTotalFileFixState, not one-to-one
      • addTotalFiles -> addTotalFileFixOperations, not one-to-one
      • getTypeFileFixStats, getRunningFileFixerStats - Gets the fixer stats for the specific file group.
      • incrementFinishedOperations, incrementFinishedOperationsBy - Increments the number of operations that have finished.
      • setType, getType - Gets the type of the upgrade progress.
      • setApplicableFixerAmount - Sets the total number of finished operations for the running file fixers.
      • incrementRunningFileFixer - Increments the number of finished operations.
      • logProgress - Logs the progress of the upgrade every second.
      • $FileFixStats - A counter for the operations performed / finished.
      • $Type - The type of upgrade being performed on the world data.
    • WorldUpgrader no longer takes in the WorldData
      • STATUS_* messages have been combined in UpgradeStatusTranslator
        • This also contains the specific datafix type
      • running, finished, progress, totalChunks, totalFiles, converted, skipped, progressMap, status have all been moved into UpgradeProgress, stored in upgradeProgress
      • getProgress -> getTotalProgress, not one-to-one
      • $AbstractUpgrader, $SimpleRegionStorageUpgrader -> RegionStorageUpgrader, no longer taking in the supplied LegacyTagFixer, not one-to-one
        • $ChunkUpgrader, $EntityUpgrader, $PoiUpgrader are now just constructed within WorldUpgrader#work
        • $Builder#setLegacyFixer is removed
      • $ChunkUpgrader#tryProcessOnePosition has been partially abstracted into getDataFixContentTag, verifyChunkPosAndEraseCache, verifyChunkPos
      • $FileToUpgrade -> FileToUpgrade
  • net.minecraft.world.level.ChunkPos#getRegionX, getRegionZ - Gets the region the chunk is in.
  • net.minecraft.world.level.chunk.ChunkGenerator#getTypeNameForDataFixer now returns an optional Identifier instead of a ResourceKey
  • net.minecraft.world.level.chunk.storage
    • LegacyTagFixer interface is removed
    • RecreatingSimpleRegionStorage no longer takes in the supplied LegacyTagFixer
    • SimpleRegionStorage no longer takes in the supplied LegacyTagFixer
      • markChunkDone is removed
  • net.minecraft.world.level.levelgen.structure
    • LegacyStructureDataHandler class is removed
    • StructureFeatureIndexSavedData class is removed
  • net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager
    • STRUCTURE_RESOURCE_DIRECTORY_NAME -> STRUCTURE_DIRECTORY_NAME, not one-to-one
    • WORLD_STRUCTURE_LISTER, RESOURCE_TEXT_STRUCTURE_LISTER - Id converters for the structure nbts.
    • save now has an overload that takes in the path, StructureTemplate, and boolean for whether to write the data as text
    • createAndValidatePathToGeneratedStructure -> TemplatePathFactory#createAndValidatePathToStructure, not one-to-one
    • worldTemplates, testTemplates - The template path factories.
  • net.minecraft.world.level.levelgen.structure.templatesystem.loader
    • DirectoryTemplateSource - A template source for some directory.
    • ResourceManagerTemplateSource - A template source for the resource manager.
    • TemplatePathFactory - A factory that gets the path to some structure.
    • TemplateSource - A loader for structure templates.
  • net.minecraft.world.level.storage
    • LevelStorageSource
      • getLevelDataAndDimensions now takes in the $LevelStorageAccess
      • readExistingSavedData - Reads any existing saved data.
      • writeGameRules - Writes the game rules to the saved data.
      • $LevelStorageAccess#releaseTemporarilyAndRun - Releases the access and runs before recreating the lock.
        • collectIssues - Collects any issues when attempting to upgrade the data.
        • getSummary -> fixAndGetSummary, fixAndGetSummaryFromTag; not one-to-one
        • getDataTag -> getUnfixedDataTag, not one-to-one
        • getDataTagFallback -> getUnfixedDataTagWithFallback, not one-to-one
        • saveDataTag no longer takes in the RegistryAccess
        • saveLevelData - Saves the level dat.
    • LevelSummary now takes in whether it requires file fixing
      • UPGRADE_AND_PLAY_WORLD - A component telling the user to upgrade their world and play.
      • requiresFileFixing - Whether the level requires file fixing.
      • $BackupStatus#FILE_FIXING_REQUIRED - Whether file fixing is require to play this level on this version.

Chat Permissions

The chat system now has an associated set of permissions indicating what messages the player can send or receive. Permissions#CHAT_SEND_MESSAGES and CHAT_SEND_COMMANDS determine if the player can send messages or commands, respectively. Likewise, CHAT_RECEIVE_PLAYER_MESSAGES and CHAT_RECEIVE_SYSTEM_MESSAGES if the player can receive messages from other players or the system, respectively. Note that all of these permissions are only handled clientside and are not validated serverside.

  • net.minecraft.SharedConstants#DEBUG_CHAT_DISABLED - A flag that disables the chat box.
  • net.minecraft.client
    • GuiMessage -> .multiplayer.chat.GuiMessage
    • GuiMessageTag -> .multiplayer.chat.GuiMessageTag
    • Minecraft
      • getChatStatus -> computeChatAbilities, not one-to-one
      • $ChatStatus -> ChatRestriction, not one-to-one
  • net.minecraft.client.gui.Gui#setChatDisabledByPlayerShown, isShowingChatDisabledByPlayer - Handles whether the chat is disabled by the shown player.
  • net.minecraft.client.gui.components
    • ChatComponent
      • GO_TO_RESTRICTIONS_SCREEN - An identifier for redirecting to the restrictions screen.
      • setVisibleMessageFilter - Sets the message filter function.
      • render, captureClickableText now take in the $DisplayMode instead of a boolean for if the player is chatting
      • addMessage is now private
        • Split for use into addClientSystemMessage, addServerSystemMessage, addPlayerMessage
      • $DisplayMode - How the chat should be displayed.
    • CommandSuggestions
      • USAGE_FORMAT, USAGE_OFFSET_FROM_BOTTOM, LINE_HEIGHT - Constants for showing the command suggestions.
      • setRestrictions - Sets the restrictions of the messages that can be typed.
      • hasAllowedInput - Whether the chat box can allow input.
  • net.minecraft.client.gui.screens.ChatScreen#USAGE_BACKGROUND_COLOR - The background color of the command suggestions box.
  • net.minecraft.client.gui.screens.multiplayer.RestrictionsScreen - A screen for settings the restrictions of the player’s chat box.
  • net.minecraft.client.gui.screens.reporting.ReportPlayerScreen now takes in a boolean for if the chat is disabled or blocked
  • net.minecraft.client.multiplayer.chat
    • ChatAbilities - The set of restrictions the player has on chatting with the chat box.
    • ChatListener
      • handleSystemMessage boolean is now used for if the system is remote instead of overlay
        • The overlay is now handled through handleOverlay
    • GuiMessageSource - The source the message came from.
  • net.minecraft.client.player.LocalPlayer now takes in the ChatAbilities
    • chatAbilities, refreshChatAbilities - Handles the chat abilities.
  • net.minecraft.server.permissions.Permissions
    • CHAT_SEND_MESSAGES - If the player can send chat messages.
    • CHAT_SEND_COMMANDS - If the player can send commands.
    • CHAT_RECEIVE_PLAYER_MESSAGES - If the player can receive other player messages.
    • CHAT_RECEIVE_SYSTEM_MESSAGES - If the player can receive system messages.
    • CHAT_PERMISSIONS - A set of available chat permissions.
  • net.minecraft.world.entity.player.Player#displayClientMessage split into sendSystemMessage when overlay message was false, and sendOverlayMessage when the overlay message was true

More Entity Sound Variant Registries

Cats, chickens, cows, and pigs now have sound variants: a databack registry object that specifies the sounds an entity plays. This does not need to be directly tied to an actual entity variant, as it only defines the sounds an entity plays, typically during Mob#finalizeSpawn.

For cows:

// A file located at:
// - `data/examplemod/cow_sound_variant/example_cow_sound.json`
{
    // The registry name of the sound event to play randomly on idle.
    "ambient_sound": "minecraft:entity.cow.ambient",
    // The registry name of the sound event to play when killed.
    "death_sound": "minecraft:entity.cow.death",
    // The registry name of the sound event to play when hurt.
    "hurt_sound": "minecraft:entity.cow.hurt",
    // The registry name of the sound event to play when stepping.
    "step_sound": "minecraft:entity.cow.step"
}

For chickens and pigs:

// A file located at:
// - `data/examplemod/chicken_sound_variant/example_chicken_sound.json`
{
    // The sounds played when an entity's age is greater than or equal to 0 (an adult).
    "adult_sounds": {
        // The registry name of the sound event to play randomly on idle.
        "ambient_sound": "minecraft:entity.chicken.ambient",
        // The registry name of the sound event to play when killed.
        "death_sound": "minecraft:entity.chicken.death",
        // The registry name of the sound event to play when hurt.
        "hurt_sound": "minecraft:entity.chicken.hurt",
        // The registry name of the sound event to play when stepping.
        "step_sound": "minecraft:entity.chicken.step"
    },
    // The sounds played when an entity's age is less than 0 (a baby).
    "baby_sounds": {
        "ambient_sound": "minecraft:entity.baby_chicken.ambient",
        "death_sound": "minecraft:entity.baby_chicken.death",
        "hurt_sound": "minecraft:entity.baby_chicken.hurt",
        "step_sound": "minecraft:entity.baby_chicken.step"
    }
}

For pigs:

// A file located at:
// - `data/examplemod/pig_sound_variant/example_pig_sound.json`
{
    // The sounds played when an entity's age is greater than or equal to 0 (an adult).
    "adult_sounds": {
        // The registry name of the sound event to play randomly on idle.
        "ambient_sound": "minecraft:entity.pig.ambient",
        // The registry name of the sound event to play when killed.
        "death_sound": "minecraft:entity.pig.death",
        // The registry name of the sound event to play when eating.
        "eat_sound": "minecraft:entity.pig.eat",
        // The registry name of the sound event to play when hurt.
        "hurt_sound": "minecraft:entity.pig.hurt",
        // The registry name of the sound event to play when stepping.
        "step_sound": "minecraft:entity.pig.step"
    },
    // The sounds played when an entity's age is less than 0 (a baby).
    "baby_sounds": {
        "ambient_sound": "minecraft:entity.baby_pig.ambient",
        "death_sound": "minecraft:entity.baby_pig.death",
        "eat_sound": "minecraft:entity.baby_pig.eat",
        "hurt_sound": "minecraft:entity.baby_pig.hurt",
        "step_sound": "minecraft:entity.baby_pig.step"
    }
}

For cats:

// A file located at:
// - `data/examplemod/cat_sound_variant/example_cat_sound.json`
{
    // The sounds played when an entity's age is greater than or equal to 0 (an adult).
    "adult_sounds": {
        // The registry name of the sound event to play randomly on idle when tamed.
        "ambient_sound": "minecraft:entity.cat.ambient",
        // The registry name of the sound event to play when non-tamed and tempted by food.
        "beg_for_food_sound": "minecraft:entity.cat.beg_for_food",
        // The registry name of the sound event to play when killed.
        "death_sound": "minecraft:entity.cat.death",
        // The registry name of the sound event to play when fed.
        "eat_sound": "minecraft:entity.cat.eat",
        // The registry name of the sound event to play when hissing, typically at a pursuing phantom.
        "hiss_sound": "minecraft:entity.cat.hiss",
        // The registry name of the sound event to play when hurt.
        "hurt_sound": "minecraft:entity.cat.hurt",
        // The registry name of the sound event to play when purring, typically when in love or lying down.
        "purr_sound": "minecraft:entity.cat.purr",
        // The registry name of the sound event to play randomly on idle when tamed 25% of the time.
        "purreow_sound": "minecraft:entity.cat.purreow",
        // The registry name of the sound event to play randomly on idle when not tamed.
        "stray_ambient_sound": "minecraft:entity.cat.stray_ambient"
    },
    // The sounds played when an entity's age is less than 0 (a baby).
    "baby_sounds": {
        "ambient_sound": "minecraft:entity.baby_cat.ambient",
        "beg_for_food_sound": "minecraft:entity.baby_cat.beg_for_food",
        "death_sound": "minecraft:entity.baby_cat.death",
        "eat_sound": "minecraft:entity.baby_cat.eat",
        "hiss_sound": "minecraft:entity.baby_cat.hiss",
        "hurt_sound": "minecraft:entity.baby_cat.hurt",
        "purr_sound": "minecraft:entity.baby_cat.purr",
        "purreow_sound": "minecraft:entity.baby_cat.purreow",
        "stray_ambient_sound": "minecraft:entity.baby_cat.stray_ambient"
    }
}
  • net.minecraft.core.registries.Registries
    • CAT_SOUND_VARIANT - The registry key for the sounds a cat should make.
    • CHICKEN_SOUND_VARIANT - The registry key for the sounds a chicken should make.
    • COW_SOUND_VARIANT - The registry key for the sounds a cow should make.
    • PIG_SOUND_VARIANT - The registry key for the sounds a pig should make.
  • net.minecraft.network.synched.EntityDataSerializers
    • CAT_SOUND_VARIANT - The entity serializer for the sounds a cat should make.
    • CHICKEN_SOUND_VARIANT - The entity serializer for the sounds a chicken should make.
    • COW_SOUND_VARIANT - The entity serializer for the sounds a cow should make.
    • PIG_SOUND_VARIANT - The entity serializer for the sounds a pig should make.
  • net.minecraft.sounds.SoundEvents
    • CAT_* sounds are now either Holder$References or stored in the map of CAT_SOUNDS
    • CHICKEN_* sounds are now either Holder$References or stored in the map of CHICKEN_SOUNDS
    • COW_* sounds are stored in the map of COW_SOUNDS
    • PIG_* sounds are now either Holder$References or stored in the map of PIG_SOUNDS
  • net.minecraft.world.entity.animal.chicken
    • ChickenSoundVariant - The sounds that are played for a chicken variant.
    • ChickenSoundVariants - All vanilla chicken variants.
  • net.minecraft.world.entity.animal.cow
    • AbstractCow#getSoundSet - Gets the sounds a cow makes.
    • CowSoundVariant - The sounds that are played for a cow variant.
    • CowSoundVariants - All vanilla cow variants.
  • net.minecraft.world.entity.animal.feline
    • CatSoundVariant - The sounds that are played for a cat variant.
    • CatSoundVariants - All vanilla cat variants.
  • net.minecraft.world.entity.animal.chicken
    • ChickenSoundVariant - The sounds that are played for a chicken variant.
    • ChickenSoundVariants - All vanilla chicken variants.
  • net.minecraft.world.entity.animal.pig
    • PigSoundVariant - The sounds that are played for a pig variant.
    • PigSoundVariants - All vanilla pig variants.

Audio Changes

Audio devices are now handled through the DeviceTracker which, depending on the backing machine, allows for either the machine to send system events when audio devices change, or using a standard polling interval to requery the list of available devices.

  • com.mojang.blaze3d.audio
    • AbstractDeviceTracker - An abstract tracker for managing the changes of audio devices.
    • CallbackDeviceTracker - A device tracker that uses the SOFT system events callback to determine changes.
    • DeviceList - A list of all audio devices, including the default device, if available.
    • DeviceTracker - An interface for managing the changes of audio devices.
    • Library
      • NO_DEVICE is now public from private
      • init now takes in the DeviceList
      • getDefaultDeviceName moved to DeviceList#defaultDevice
      • getCurrentDeviceName -> currentDeviceName
      • hasDefaultDeviceChanged moved to AbstractDeviceTracker, not one-to-one
      • getAvailableSoundDevices moved to DeviceList, not one-to-one
      • createDeviceTracker - Creates the tracker for managing audio device changes.
      • getDebugString -> getChannelDebugString
    • PollingDeviceTracker - A device tracker that uses polling intervals to determine changes.
    • SoundBuffer
      • format - The format of the sound stream.
      • size - The number of bytes in the sound stream.
      • isValid - If the sound stream is in a valid state.
  • net.minecraft.client.Options
    • DEFAULT_SOUND_DEVICE is now private from public
    • isSoundDeviceDefault - Checks if the device is the default audio device.
  • net.minecraft.client.gui.components.debug
    • DebugEntrySoundCache - A debug entry displaying the current cache for loaded sound streams.
    • DebugScreenEntries#SOUND_CACHE - The identifier for the sound stream cache debug information.
  • net.minecraft.client.sounds
    • SoundBufferLibrary
      • enumerate - Loops through all cached sounds, outputting its id, size, and format.
      • $DebugOutput - An interface that accepts some sound metadata.
        • $Counter - An output implementation that keepts track of the number of sound streams and the total size.
    • SoundEngine
      • getDebugString -> getChannelDebugString, getSoundCacheDebugStats; not one-to-one
      • $DeviceCheckState is removed
    • SoundManager#getDebugString -> getChannelDebugString, getSoundCacheDebugStats; not one-to-one

Input Message Editor Support

Minecraft now has support for Input Message Editors (IME), which allow complex characters from languages like Chinese or Hindi to be inputted instead of the temporary preedit text. The preedit text is displayed as an overlay within the game, while any other IME features provided by the host OS. With this addition, support can be added within screens through GuiEventListener#preeditUpdated, or by using an existing vanilla widget which implements the method.

  • com.mojang.blaze3d.platform
    • InputConstants#setupKeyboardCallbacks now takes in the GLFWCharCallbackI instead of GLFWCharModsCallbackI for the character typed callback, GLFWPreeditCallbackI to handle inputting complex characters via an input method editor, and GLFWIMEStatusCallbackI for notifying about the status of the editor
    • MessageBox - A utility for creating OS native messages boxes.
    • TextInputManager - A manager for handling when text is inputted in the game window.
      • setTextInputArea - Sets the area where the predicted text cursor should appear.
      • startTextInput, stopTextInput - Handles toggling the input message editor.
  • net.minecraft.client
    • KeyboardHandler
      • resubmitLastPreeditEvent - Repeats the last preedit event that was sent.
      • submitPreeditEvent - Tells the listener that the preedit text has been updated.
    • Minecraft
      • textInputManager - Returns the input manager.
      • onTextInputFocusChange - Changes the editor input status based on if the text input is focused.
  • net.minecraft.client.gui.GuiGraphics
    • setPreeditOverlay - Sets the overlay drawing the preedit text.
    • renderDeferredElements now takes in the ints for the mouse position and the game time delta ticks float
  • net.minecraft.client.gui.components
    • IMEPreeditOverlay - The overlay for displaying the preedit text for an input message editor.
    • TextCursorUtils - A utility for drawing the text cursor.
  • net.minecraft.client.gui.components.events.GuiEventListener#preeditUpdated - Listens for when the preedit text changes.
  • net.minecraft.client.input
    • CharacterEvent no longer takes in the modifier int set
    • PreeditEvent - An event containing the preedit text along with the cursor location.

Cauldron Interaction Dispatchers

Cauldron interactions have been reorganized somewhat, with all registration being moved to CauldronInteractions from CauldronInteraction. In addition, the backing $InteractionMap for a cauldron type has been replaced with a $Dispatcher that can register interactions for both tags and items. Tags are checked before items.

CauldronInteractions.EMPTY.put(
    // The Item or TagKey to use
    ItemTags.WOOL,
    // The cauldron interaction to apply
    (state, level, pos, player, hand, itemInHand) -> InteractionResult.TRY_WITH_EMPTY_HAND
);
  • net.minecraft.core.cauldron
    • CauldronInteraction
      • All fields regarding to registering interactions to a map have been moved to CauldronInteractions
        • INTERACTIONS -> CauldronInteractions#ID_MAPPER, now private
      • DEFAULT - The default interaction with a cauldron
      • $InteractionMap -> $Dispatcher, not one-to-one
    • CauldronInteractions - All vanilla cauldron interactions.

Rule-Based Block State Providers

RuleBasedStateProvider now extends BlockStateProvider, allowing it to be used wherever a state provider is required. It’s implementation hasn’t changed, now only requiring rule_based_state_provider to be specified as the type. As such, all configurations that used RuleBasedBlockStateProvider have been broadened to allow any BlockStateProvider.

  • net.minecraft.world.level.levelgen.feature.configurations
    • DiskConfiguration now takes in a BlockStateProvider instead of a RuleBasedBlockStateProvider
    • TreeConfiguration now takes in a BlockStateProvider instead of a RuleBasedBlockStateProvider
      • belowTrunkProvider is now a BlockStateProvider instead of a RuleBasedBlockStateProvider
      • $TreeConfigurationBuilder now takes in a BlockStateProvider instead of a RuleBasedBlockStateProvider
  • net.minecraft.world.level.levelgen.feature.stateproviders
    • BlockStateProvider#getOptionalState - Gets the state of the block, or otherwise null.
    • BlockStateProviderType#RULE_BASED_STATE_PROVIDER - The type for the rule based state provider.
    • RuleBasedBlockStateProvider -> RuleBasedStateProvider, now a class, implementing BlockStateProvider
      • The constructor can now take in a nullable fallback BlockStateProvider
      • ifTrueThenProvide - If the predicate is true, provide the given block.
      • simple -> always
      • $Builder - A builder for constructing the rules for the block to place.

Fluid Logic Reorganization

Generic entity fluid movement has been moved into a separate EntityFluidInteraction class, where all tracked fluids are updated and then potentially pushed by the current at a layer time.

  • net.minecraft.world.entity
    • Entity
      • updateInWaterStateAndDoFluidPushing -> updateFluidInteraction, not one-to-one
      • updateFluidHeightAndDoFluidPushing -> EntityFluidInteraction#update
      • getFluidInteractionBox - Gets the bounding box of the entity during fluid interactions.
      • modifyPassengerFluidInteractionBox - Returns the modified bounding box of the entity when riding in some vehicle.
    • EntityFluidInteraction - A handler for managing the fluid interactions and basic movement with an entity.
  • net.minecraft.world.level.chunk.LevelChunkSection#hasFluid - Whether the chunk section has a fluid block.

Removal of Random Patch Feature

The random patch feature has been completely removed in favor of using placements like most other features. To convert, the ConfiguredFeature defined as part of the configuration should be its own file. Then, the placements should specify the CountPlacement, followed by the RandomOffsetPlacement using a TrapezoidInt, and finished with a BlockPredicateFilter:

// In `data/examplemod/worldgen/configured_feature/example_configured_feature.json`
{
    // Previously config.feature.feature
    "type": "minecraft:simple_block",
    "config": {
        "to_place": {
            "type": "minecraft:simple_state_provider",
            "state": {
                "Name": "minecraft:sweet_berry_bush",
                "Properties": {
                    "age": "3"
                }
            }
        }
    }
}

// In `data/examplemod/worldgen/placed_feature/example_placed_feature.json`
{
    "feature": "examplemod:example_configured_feature",
    "placement": [
        {
            // Previously config.tries
            "type": "minecraft:count",
            "count": 96
        },
        {
            "type": "minecraft:random_offset",
            "xz_spread": {
                // Previously config.xz_spread
                // The min and max are additive inverses
                "type": "minecraft:trapezoid",
                "max": 7,
                "min": -7,
                "plateau": 0
            },
            "y_spread": {
                // Previously config.y_spread
                "type": "minecraft:trapezoid",
                "max": 3,
                "min": -3,
                "plateau": 0
            }
        },
        {
            // Previously config.feature.placement
            // This contains the placements of the original placed feature
            "type": "minecraft:block_predicate_filter",
            "predicate": {
                "type": "minecraft:all_of",
                "predicates": [
                    {
                        "type": "minecraft:matching_block_tag",
                        "tag": "minecraft:air"
                    },
                    {
                        "type": "minecraft:matching_blocks",
                        "blocks": "minecraft:grass_block",
                        "offset": [ 0, -1, 0 ]
                    }
                ]
            }
        }
    ]
}
  • net.minecraft.data.worldgen.features
    • FeatureUtils#simpleRandomPatchConfiguration, simplePatchConfiguration are removed
      • Typically replaced by Feature#SIMPLE_BLOCK with placements for random offset and filters
    • NetherFeatures#PATCH_* fields no longer has the PATCH_* prefix
    • VegetationFeatures
      • PATCH_* fields no longer has the PATCH_* prefix
      • WILDFLOWERS_BIRCH_FOREST, WILDFLOWERS_MEADOW -> WILDFLOWER, not one-to-one
      • PALE_FOREST_FLOWERS -> PALE_FOREST_FLOWER
  • net.minecraft.world.level.biome.BiomeGenerationSettings#getFlowerFeatures -> getBoneMealFeatures
  • net.minecraft.world.level.levelgen.feature
    • ConfiguredFeature#getFeatures -> getSubFeatures, now returning a stream of holders-wrapped ConfiguredFeatures without this feature
    • Feature
      • FLOWER, NO_BONEMEAL_FLOWER are removed
      • RANDOM_PATCH is removed
    • RandomPatchFeature class is removed
  • net.minecraft.world.level.levelgen.feature.configurations
    • FeatureConfiguration#getFeatures -> getSubFeatures, now returning a stream of holders-wrapped ConfiguredFeatures
    • RandomPatchConfiguration record is removed
  • net.minecraft.world.level.levelgen.placement.PlacedFeature#getFeatures now returns a stream of holders-wrapped ConfiguredFeatures with this feature concatenated

Specific Logic Changes

  • Picture-In-Picture submission calls are now taking in 0xF000F0 instead of 0x000000 for the light coordinates.
  • net.minecraft.client.multiplayer.RegistryDataCollector#collectGameRegistries boolean parameter now handles only updating components from synchronized registries along with tags.
  • net.minecraft.client.renderer.RenderPipelines#VIGNETTE now blends the alpha with a source of zero and a destination of one.
  • net.minecraft.server.packs.PathPackResources#getResource, listPath, listResources resolves the path using the identifier’s namespace first.
  • net.minecraft.world.entity.EntitySelector#CAN_BE_PICKED can now find entities in spectator mode, assuming Entity#isPickable is true.
  • net.minecraft.world.entity.ai.sensing.NearestVisibleLivingEntitySensor#requires is no longer implemented by default.
  • net.minecraft.world.level.levelgen.WorldOptions#generate_features field in JSON has been renamed to generate_structures to match its java field name.
  • net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate#ONLY_IN_AIR_PREDICATE now matches the air tag instead of just the air block.
  • net.minecraft.world.level.timers
    • FunctionCallback, FunctionTagCallback now use id instead of Name when serializing
    • TimerCallbacks now uses type instead of Type when serializing

Data Component Additions

  • dye - Sets the item as a dye material, used in specific circumstances.
  • additional_trade_cost - A modifier that offsets the trade cost by the specified amount.
  • pig/sound_variant - The sounds a pig should make.
  • cow/sound_variant - The sounds a cow should make.
  • chicken/sound_variant - The sounds a chicken should make.
  • cat/sound_variant - The sounds a cat should make.

Environment Attribute Additions

  • visual/block_light_tint - Tints the color of the light emitted by a block.
  • visual/night_vision_color - The color when night vision is active.
  • visual/ambient_light_color - The color of the ambient light in an environment.

Tag Changes

  • minecraft:block
    • bamboo_plantable_on -> supports_bamboo
    • mushroom_grow_block -> overrides_mushroom_light_requirement
    • small_dripleaf_placeable -> supports_small_dripleaf
    • big_dripleaf_placeable -> supports_big_dripleaf
    • dry_vegetation_may_place_on -> supports_dry_vegetation
    • snow_layer_cannot_survive_on -> cannot_support_snow_layer
    • snow_layer_can_survive_on -> support_override_snow_layer
    • enables_bubble_column_drag_down
    • enables_bubble_column_push_up
    • supports_vegetation
    • supports_crops
    • supports_stem_crops
    • supports_stem_fruit
    • supports_pumpkin_stem
    • supports_melon_stem
    • supports_pumpkin_stem_fruit
    • supports_melon_stem_fruit
    • supports_sugar_cane
    • supports_sugar_cane_adjacently
    • supports_cactus
    • supports_chorus_plant
    • supports_chorus_flower
    • supports_nether_sprouts
    • supports_azalea
    • supports_warped_fungus
    • supports_crimson_fungus
    • supports_mangrove_propagule
    • supports_hanging_mangrove_propagule
    • supports_nether_wart
    • supports_crimson_roots
    • supports_warped_roots
    • supports_wither_rose
    • supports_cocoa
    • supports_lily_pad
    • supports_frogspawn
    • support_override_cactus_flower
    • cannot_support_seagrass
    • cannot_support_kelp
    • grows_crops
    • mud
    • moss_blocks
    • grass_blocks
    • substrate_overworld
    • beneath_tree_podzol_replaceable
    • beneath_bamboo_podzol_replaceable
    • cannot_replace_below_tree_trunk
    • ice_spike_replaceable
    • forest_rock_can_place_on
    • huge_brown_mushroom_can_place_on
    • huge_red_mushroom_can_place_on
    • prevents_nearby_leaf_decay
  • minecraft:enchantment
    • trades/desert_special is removed
    • trades/jungle_special is removed
    • trades/plains_special is removed
    • trades/savanna_special is removed
    • trades/snow_special is removed
    • trades/swamp_special is removed
    • trades/taiga_special is removed
  • minecraft:entity_type
    • cannot_be_age_locked
  • minecraft:fluid
    • supports_sugar_cane_adjacently
    • supports_lily_pad
    • supports_frogspawn
    • bubble_column_can_occupy
  • minecraft:item
    • metal_nuggets
    • dyeable is removed, split between:
      • dyes
      • loom_dyes
      • loom_patterns
      • cauldron_can_remove_due
      • cat_collar_dyes
      • wolf_collar_dyes
    • mud
    • moss_blocks
    • grass_blocks
  • minecraft:potion
    • tradable
  • minecraft:worldgen/configured_feature
    • can_spawn_from_bone_meal

List of Additions

  • net.minecraft.advancements.criterion
    • FoodPredicate - A criterion predicate that can check the food level and saturation.
    • MinMaxBounds
      • validateContainedInRange - Returns a function which validates the target range and returns as a data result.
      • $Bounds#asRange - Converts the bounds into a Range.
  • net.minecraft.client
    • Minecraft#sendLowDiskSpaceWarning - Sends a system toast for low disk space.
    • Options#keyDebugLightmapTexture - A key mapping to show the lightmap texture.
  • net.minecraft.client.gui.components
    • AbstractScrollArea
      • scrollbarWidth - The width of the scrollbar.
      • defaultSettings - Constructs the default scrollbar settings given the scroll rate.
      • $ScrollbarSettings - A record containing the metadata for the scrollbar.
    • DebugScreenOverlay
      • showLightmapTexture - Whether to render the lightmap texture on the overlay.
      • toggleLightmapTexture - Toggles whether the lightmap texture should be rendered.
    • ScrollableLayout
      • setMinHeight - Sets the minimum height of the container layout.
      • $ReserveStrategy - What to use when reserving the width of the scrollbar within the layout.
    • Tooltip
      • component - The component of a tooltip to display.
      • style - The identifier used to compute the tooltip background and frame.
  • net.minecraft.client.gui.components.debug
    • DebugEntryDetailedMemory - A debug entry displaying the detailed memory usage.
    • DebugEntryLookingAt#getHitResult - Gets the hit result of the camera entity.
    • DebugEntryLookingAtEntityTags - A debug entry for displaying an entity’s tags.
    • DebugScreenEntries
      • DETAILED_MEMORY - The identifier for the detailed memory usage debug entry.
      • LOOKING_AT_ENTITY_TAGS - The identifier for the entity tags debug entry.
  • net.minecraft.client.gui.navigation.FocusNavigationEvent$ArrowNavigation#with - Sets the previous focus of the navigation.
  • net.minecraft.client.gui.screens.GenericWaitingScreene#createWaitingWithoutButton - Creates a waiting screen without showing the button to cancel.
  • net.minecraft.client.gui.screens.options
    • DifficultyButtons - A class containing the layout element to create the difficulty buttons.
    • HasGamemasterPermissionReaction - An interface marking an option screen as able to respond to changing gamemaster permissions.
    • OptionsScreen#getLastScreen - Returns the previous screen that navigated to this one.
    • WorldOptionsScreen - A screen containing the options for the current world the player is in.
  • net.minecraft.client.gui.screens.worldselection.EditWorldScreen#conditionallyMakeBackupAndShowToast - Only makes the backup and shows a toast if the passed in boolean is true; otherwise, returns a false future.
  • net.minecraft.client.multiplayer.MultiPlayerGameMode#spectate - Sends a packet to the server that the player will spectate the given entity.
  • net.minecraft.client.multiplayer.prediction.BlockStatePredictionHandler#onTeleport - Runs when a player is moved on the server, typically from some kind of teleportation (e.g. commands, riding an entity).
  • net.minecraft.client.renderer
    • LightmapRenderStateExtractor - Extracts the render state for the lightmap.
    • UiLightmap - The lightmap when in a user interface.
    • RenderPipelines
      • LINES_DEPTH_BIAS - A render pipeline that sets the polygon depth offset factor to -1 and the units to -1.
      • ENTITY_CUTOUT_DISSOLVE - A render pipeline that dissolves an entity model into the background using a mask sampler.
  • net.minecraft.client.renderer.rendertype.RenderType#hasBlending - Whether the pipeline has a defined blend function.
  • net.minecraft.commands.ArgumentVisitor - A helper for visiting the arguments for a command.
  • net.minecraft.commands.arguments.selector.EntitySelector#COMPILABLE_CODEC - A CompilableString codec wrapped around an EntitySelectorParser.
  • net.minecraft.core.component.predicates
    • DataComponentPredicates#VILLAGER_VARIANT - A predicate that checks a villager type.
    • VillagerTypePredicate - A predicate that checks a villager’s type.
  • net.minecraft.core.dispenser.SpawnEggItemBehavior - The dispenser behavior for spawn eggs.
  • net.minecraft.core.registries.ConcurrentHolderGetter - A getter that reads references from a local cache, synchronizing to the original when necessary.
  • net.minecraft.data
    • BlockFamilies
      • END_STONE - A family for end stone variants.
      • getFamily - Gets the family for the base block, when present.
    • BlockFamily
      • $Builder#tiles, $Variant#TILES - The block that acts as the tiles variant for some base block.
      • $Builder#bricks, $Variant#BRICKS - The block that acts as the bricks variant for some base block.
      • $Builder#cobbled, $Variant#COBBLED - The block that acts as the cobbled variant from some base block.
    • DataGenerator$Uncached - A data generator which does not cache any information about the files generated.
  • net.minecraft.data.recipes.RecipeProvider
    • bricksBuilder, tilesBuilder - Builders for the bricks and tiles block variants.
    • generateCraftingRecipe, generateStonecutterRecipe - Generates the appropriate recipes for the given block family.
    • getBaseBlock -> getBaseBlockForCrafting
    • bredAnimal - Unlocks the recipe if the player has bred two animals together.
  • net.minecraft.gametest.framework
    • GameTestEvent#createWithMinimumDelay - Creates a test event with some minimum delay.
    • GameTestHelper
      • getBoundsWithPadding - Gets the bounding box of the test area with the specified padding.
      • runBeforeTestEnd - Runs the runnable at one tick before the test ends.
      • despawnItem - Despawns all item entities within the distance of the position.
      • discard - Discards the entity.
      • setTime - Sets the time of the dimension’s default clock.
      • placeBlock - Places the given block at the relative position and direction.
    • GameTestInstance#padding - The number of blocks spaced around each game test.
    • GameTestSequence#thenWaitAtLeast - Waits for at least the specified number of ticks before running the runnable.
  • net.minecraft.nbt.TextComponentTagVisitor
    • $PlainStyling - A styling that stores the nbt in a component literal map.
    • $RichStyling - A styling that stores the nbt with syntax highlighting and formatting.
    • $Styling - An interface defining how the read tag should be styled.
    • $Token - The tokens used to more richly represent the tag datas.
  • net.minecraft.network.chat.ResolutionContext - The context that the component is being resolved to a string within.
  • net.minecraft.network.chat.contents.NbtContents#NBT_PATH_CODEC - A CompilableString codec wrapped around a NbtPathArgument$NbtPath.
  • net.minecraft.network.chat.contents.data.BlockDataSource#BLOCK_POS_CDEC - A CompilableString codec wrapped around Coordinates.
  • net.minecraft.network.protocol.game
    • ClientboundGameRuleValuesPacket - A packet that sends the game rule values in string form to the client.
    • ClientboundGamePacketListener#handleGameRuleValues - Handles the game rule values sent from the server.
    • ClientboundLowDiskSpaceWarningPacket - A packet sent to the client warning about low disk space on the machine.
    • ClientGamePacketListener#handleLowDiskSpaceWarning - Handles the warning packet about low disk space.
    • ServerboundAttackPacket - A packet sent to the server about what entity the player attacked.
    • ServerboundClientCommandPacket$Action#REQUEST_GAMERULE_VALUES - Requests the game rule values from the server.
    • ServerboundSetGameRulePacket - A packet that sends the game rules entries to set from the client.
    • ServerboundSpectateEntityPacket - A packet sent to the server about what entity the player wants to spectate.
    • ServerGamePacketListener
      • handleAttack - Handles the player’s attack on an entity.
      • handleSpectateEntity - Handles the player wanting to spectate an entity.
      • handleSetGameRule - Handles setting the game rules from the client.
  • net.minecraft.resources
    • FileToIdConverter#extensionMatches - Checks if the identifier ends with the specified extension.
    • Identifier
      • ALLOWED_NAMESPACE_CHARACTERS - The characters allowed in an identifier’s namespace.
      • resolveAgainst - Resolves the path from the given root by checking /<namespace>/<path>.
  • net.minecraft.server
    • Bootstrap#shutdownStdout - Closes the stdout stream.
    • MinecraftServer
      • DEFAULT_GAME_RULES - The supplied default game rules for a server.
      • warnOnLowDiskSpace - Sends a warning if the disk space is below 64 MiB.
      • sendLowDiskSpaceWarning - Sends a warning for low disk space.
  • net.minecraft.server.commands.SwingCommand - A command that calls LivingEntity#swing for all targets.
  • net.minecraft.server.level.ServerPlayer
    • sendBuildLimitMessage - Sends an overlay message if the player cannot build anymore in the cooresponding Y direction.
    • sendSpawnProtectionMessage - Sends an overlay message if the player cannot modify the terrain due to spawn protection.
  • net.minecraft.server.packs.AbstractPackResources#loadMetadata - Loads the root pack.mcmeta.
  • net.minecraft.server.packs.resources.ResourceMetadata$MapBased - A resource metadata that stores the sections in a map.
  • net.minecraft.tags.TagLoader$ElementLookup#fromGetters - Constructs an element lookup from the given HolderGetters depending on whether the element is required or not.
  • net.minecraft.util
    • ARGB#gray - Gets a grayscale color based on the given brightness.
    • CompilableString - A utility for taking some string pattern and compiling it to an object through some parser.
    • LightCoordsUtil - A utility for determining the light coordinates from light values.
    • ProblemReporter$MapEntryPathElement - A path element for some entry key in a map.
    • Util#allOfEnumExcept - Gets the set of all enums except the provided value.
  • net.minecraft.util.thread.BlockableEventLoop#hasDelayedCrash - Whether there is a crash report queued.
  • net.minecraft.util.valueproviders.TrapezoidInt - Samples a random value with a trapezoidal distribution.
  • net.minecraft.world.InteractionHand#STREAM_CODEC - The network codec for the interaction hand.
  • net.minecraft.world.attribute
    • AttributeType#toFloat - Gets the attribute value as a float, or throws an exception if not defined.
    • AttributeTypes#INTEGER - An integer attribute type.
    • LerpFunction#ofInteger - A lerp function for an integer value.
  • net.minecraft.world.attribute.modifier
    • AttributeModifier#INTEGER_LIBRARY - A library of operators to apply for integers.
    • IntegerModifier - A modifier that applies some argument to the integer value.
  • net.minecraft.world.entity
    • AgeableMob
      • AGE_LOCK_COOLDOWN_TICKS - The number of ticks to wait before the entity can be age locked/unlocked.
      • ageLockParticleTimer - The time for displaying particles while age locking/unlocking.
    • Entity
      • applyEffectsFromBlocksForLastMovements - Applies any block effects to this entity for the last movement, used by items.
      • $Flags - An annotation that marks a particular value as a bitset of flags for an entity.
    • LivingEntity#getLiquidCollisionShape - Return’s the bounds of the entity when attempting to collide with a liquid.
    • Mob
      • asValidTarget - Checks whether an entity is a valid target (can attack) for this entity.
      • getTargetUnchecked - Gets the raw target without checking if its valid.
      • canAgeUp - If the entity can grow up into a more mature variant.
      • setAgeLocked, isAgeLocked - Whether the entity cannot grow up.
    • NeutralMob#getTargetUnchecked - Gets the raw target without checking if its valid.
    • TamableAnimal#feed - The player gives the stack as food, healing them either based on the stored component or some default value.
  • net.minecraft.world.entity.ai.behavior
    • BehaviorControl#getRequiredMemories - The list of memories required by the behavior.
    • GoAndGiveItemsToTarget$ItemThrower - An interface that handles what should occur if an item is thrown because of this entity’s behavior.
  • net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder$TriggerWithResult#memories - The list of memories required by the behavior.
  • net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities#nearbyEntities - The list of entities within the follow range of this one.
  • net.minecraft.world.entity.decoration.LeashFenceKnotEntity
    • getKnot - Finds the knot at the given position, else returns an empty optional.
    • createKnot - Creates a new knot and adds it to the level.
  • net.minecraft.world.entity.monster.piglin
    • PiglinAi
      • MAX_TIME_BETWEEN_HUNTS - The maximum number of seconds before a piglin begins to hunt again.
      • findNearbyAdultPiglins - Returns a list of all adult piglins in this piglin’s memory.
  • net.minecraft.world.entity.raid.Raid
    • getBannerComponentPatch - Gets the components of the banner pattern.
    • getOminousBannerTemplate - Gets the stack template for the omnious banner.
  • net.minecraft.world.inventory.SlotRanges
    • MOB_INVENTORY_SLOT_OFFSET - The start index of a mob’s inventory.
    • MOB_INVENTORY_SIZE - The size of a mob’s inventory.
  • net.minecraft.world.item.component.BundleContents#BEEHIVE_WEIGHT - The weight of a beehive.
  • net.minecraft.world.item.enchantment.EnchantmentTarget#NON_DAMAGE_CODEC - A codec that only allows the attacker and victim enchantment targets.
  • net.minecraft.world.level.block.BigDripleafBlock#canGrowInto - Whether the dripleaf can grow into the specified position.
  • net.minecraft.world.level.block.grower.TreeGrower#getMinimumHeight - If present, gets the base height of the trunk placer.
  • net.minecraft.world.level.block.state
    • BlockBehaviour$PostProcess - An interface that gets the position to mark for post-processing.
    • StateDefinition
      • propertiesCodec - The map codec for the state properties.
      • isSingletonState - If the definition only contains one state.
    • StateHolder#isSingletonState - If the holder only contains one state.
  • net.minecraft.world.level.block.state.properties
    • NoteBlockInstrument
      • TRUMPET - The sound a copper block makes when placed under a note block.
      • TRUMPET_EXPOSED - The sound an exposed copper block makes when placed under a note block.
      • TRUMPET_OXIDIZED - The sound an oxidized copper block makes when placed under a note block.
      • TRUMPET_WEATHERED - The sound a weathered copper block makes when placed under a note block.
    • Property$Value#valueName - Gets the name of the value.
  • net.minecraft.world.level.dimension.DimensionDefaults
    • BLOCK_LIGHT_TINT - The default tint for the block light.
    • NIGHT_VISION_COLOR - The default color when in night vision.
    • TURTLE_EGG_HATCH_CHANCE - The chance of a turtle egg hatching on a random tick.
  • net.minecraft.world.level.gamerules.GameRule#getIdentifierWithFallback - Gets the identifier of the game rule, or else the unregistered identifier.
  • net.minecraft.world.level.levelgen
    • NoiseBasedChunkGenerator#getInterpolatedNoiseValue - Gets the interpolated density at the given position, or the not-a-number value if the Y is outside the range of the noise settings.
    • NoiseChunk#getInterpolatedDensity - Computes the full noise density.
  • net.minecraft.world.level.levelgen.feature.AbstractHugeMushroomFeature#MIN_MUSHROOM_HEIGHT - The minimum mushroom height.
  • net.minecraft.world.level.levelgen.feature.configurations.BlockBlobConfiguration - The configuration for the block blob feature.
  • net.minecraft.world.level.levelgen.feature.trunkplacers.TrunkPlacer#getBaseHeight - Returns the minimum height of the trunk.
  • net.minecraft.world.level.levelgen.placement.RandomOffsetPlacement#ofTriangle - Creates a trapezoidal distribution to select from for the XZ and Y range.
  • net.minecraft.world.level.material
    • FluidState#isFull - If the fluid amount is eight.
    • LavaFluid#LIGHT_EMISSION - The amount of light the lava fluid emits.
  • net.minecraft.world.level.pathfinder.PathType#BIG_MOBS_CLOSE_TO_DANGER - A path malus for mobs with an entity width greater than a block.
  • net.minecraft.world.level.storage.LevelStorageSource#writeWorldGenSettings - Wriets the world generation settings to its saved data location.
  • net.minecraft.world.level.storage.loot.functions
    • EnchantRandomlyFunction$Builder#withOptions - Specifies the enchantments that can be used to randomly enchant this item.
    • SetRandomDyesFunction - An item function that applies a random dye (if the item is in the dyeable tag) to the DYED_COLOR component from the provided list.
    • SetRandomPotionFunction - An item function that applies a random potion to the POTION_CONTENTS component from the provided list.
  • net.minecraft.world.level.storage.loot.parameters.LootContextParams#ADDITIONAL_COST_COMPONENT_ALLOWED - Enables a trade to incur an additional cost if desired by the wanted stack or modifiers.
  • net.minecraft.world.level.storage.loot.predicates.EnvironmentAttributeCheck - A loot condition that checks whether that given attribute matches the provided value.
  • net.minecraft.world.level.storage.loot.providers.number
    • EnvironmentAttributeValue - A provider that gets the attribute value as a float.
    • Sum - A provider that sums the value of all provided number providers.
  • net.minecraft.world.phys.AABB$Builder#isDefined - Checks if there is at least one point making up the bounding box.

List of Changes

  • net.minecraft.advancements.criterion
    • EntityTypePredicate#matches now takes in a holder-wrapped EntityType instead of the raw type itself
    • KilledTrigger$TriggerInstance#entityPredicate -> entity
    • PlayerPredicate now takes in a FoodPredicate
      • Can be set using PlayerPredicate$Builder#setFood
  • net.minecraft.client.gui
    • GuiGraphics
      • blit now has an overload that takes in the GpuTextureView and the GpuSampler
      • setTooltipForNextFrame now has an overload that takes in a list of FormattedCharSequences for the tooltip and whether to replace any existing tooltip
    • ItemSlotMouseAction#onSlotClicked now takes in a ContainerInput instead of a ClickType
  • net.minecraft.client.gui.components
    • AbstractContainerWidget now takes in an AbstractScrollArea$ScrollbarSettings
    • AbstractScrollArea now takes in an AbstractScrollArea$ScrollbarSettings
      • scrollbarVisible -> scrollable
      • scrollBarY is now public
      • scrollRate is now longer abstract
    • AbstractTextAreaWidget now takes in an AbstractScrollArea$ScrollbarSettings
    • PopupScreen$Builder#setMessage -> addMessage, not one-to-one
    • ScrollableLayout$Container now takes in an AbstractScrollArea$ScrollbarSettings
    • Tooltip#create now has an overload that takes in an optional TooltipComponent and style Identifier
  • net.minecraft.client.gui.components.debug
    • DebugEntryLookingAtBlock, DebugEntryLookingAtFluid -> DebugEntryLookingAt
      • More specifically, $BlockStateInfo, $BlockTagInfo, $FluidStateInfo, $FluidTagInfo
    • DebugEntryLookingAtEntity#GROUP is now public
    • DebugScreenEntries
      • LOOKING_AT_BLOCK -> LOOKING_AT_BLOCK_STATE, LOOKING_AT_BLOCK_TAGS
      • LOOKING_AT_FLUID -> LOOKING_AT_FLUID_STATE, LOOKING_AT_FLUID_TAGS
    • DebugScreenEntryList now takes in a DataFixer
  • net.minecraft.client.gui.components.tabs.TabNavigationBar#setWidth -> updateWidth, not one-to-one
  • net.minecraft.client.gui.navigation.FocusNavigationEvent$ArrowNavigation now takes in a nullable ScreenRectangle for the previous focus
  • net.minecraft.client.gui.screens
    • ConfirmScreen#layout is now final
    • DemoIntroScreen replaced by ClientPacketListener#openDemoIntroScreen, now private
    • GenericWaitingScreen now takes in three booleans for showing the loading dots, the cancel button, and whether the screen should close on escape
  • net.minecraft.client.gui.screens.inventory.AbstractMountInventoryScreen#mount is now final
  • net.minecraft.client.gui.screens.options
    • OptionsScreen now implements HasGamemasterPermissionReaction
      • The constructor now takes in a boolean for if the player is currently in a world
      • createDifficultyButton now handles within WorldOptionsScreen#createDifficultyButtons, not one-to-one
    • WorldOptionsScreen now implements HasGamemasterPermissionReaction
      • createDifficultyButtons -> DifficultyButtons#create, now public
  • net.minecraft.client.multiplayer
    • ClientLevel#syncBlockState can now take in a nullable player position
    • MultiPlayerGameMode#handleInventoryMouseClick now takes in a ContainerInput instead of a ClickType
    • WeatherEffectRenderer#render no longer takes in the MultiBufferSource
  • net.minecraft.client.renderer.block.ModelBlockRenderer$Cache#getLightColor -> getLightCoords
  • net.minecraft.client.renderer.blockentity.state
    • BrushableBlockRenderState#itemState is now final
    • EndPortalRenderState is now a final set of Directions rather than an EnumSet
    • ShelfRenderState#items is now final
  • net.minecraft.client.renderer.entity.state
    • FallingBlockRenderState#movingBlockRenderState is now final
    • HumanoidRenderState#attackArm -> ArmedEntityRenderState#attackArm
    • WitherRenderState#xHeadRots, yHeadRots are now final
  • net.minecraft.client.resources.sounds.AbstractSoundInstance#random is now final
  • net.minecraft.commands.SharedSuggestionProvider#getCustomTabSugggestions -> getCustomTabSuggestions
  • net.minecraft.commands.arguments.ComponentArgument#getResolvedComponent now takes in a non-nullable Entity
  • net.minecraft.commands.arguments.selector.SelectorPattern replaced by CompilableString
  • net.minecraft.core.HolderGetter$Provider#get, getOrThrow now has overloads that take in the TagKey
  • net.minecraft.data
    • BlockFamily
      • shouldGenerateRecipe -> shouldGenerateCraftingRecipe, shouldGenerateStonecutterRecipe
      • $Builder#dontGenerateRecipe -> dontGenerateCraftingRecipe, generateStonecutterRecipe
    • DataGenerator is now abstract
      • The constructor now only takes in the Path output, not the WorldVersion or whether to always generate
        • The original implementation can be founded in DataGenerator$Cached
      • run is now abstract
    • Main#addServerProviders -> addServerDefinitionProviders, no longer taking in the dev boolean, not one-to-one
    • The remaining logic has been put into addServerConverters, taking in the dev boolean but not the report boolean
  • net.minecraft.data.loot.BlockLootSubProvider
    • explosionResistant is now private
    • enabledFeatures is now private
    • map is now private
  • net.minecraft.data.recipes
    • RecipeProvider$FamilyRecipeProvider -> $FamilyCraftingRecipeProvider, $FamilyStonecutterRecipeProvider
    • SingleItemRecipeBuilder#stonecutting moved to a parameter on the BlockFamily
  • net.minecraft.data.structures.SnbtToNbt now has an overload that takes in a single input folder path
  • net.minecraft.gametest.framework
    • GameTestHelper
      • assertBlockPresent now has an overload that only takes in the block to check for
      • moveTo now has overloads for taking in the BlockPos and Vec3 for the position
      • assertEntityInstancePresent now has an overload that inflates (via a double) the bounding box to check entities within
    • GameTestServer#create now takes in an int for the number of times to run all matching tests
    • StructureUtils#testStructuresDir split into testStructuresTargetDir, testStructuresSourceDir
    • TestData now takes in an int for the number of blocks padding around the test
  • net.minecraft.nbt
    • NbtUtils
      • addDataVersion now uses a generic for the Dynamic instead of the explicit nbt tag
      • getDataVersion now has an overload that defaults to -1 if the version is not specified
    • TextComponentTagVisitor can now take in a $Styling and a boolean of whether to sort the keys
      • handleEscapePretty is now a private instance method from protected static
  • net.minecraft.network.FriendlyByteBuf
    • readVec3, writeVec3 replaced with Vec3#STREAM_CODEC
    • readLpVec3, writeLpVec3 replaced with Vec3#LP_STREAM_CODEC
  • net.minecraft.network.chat
    • Component
      • nbt now takes in a CompilableString instead of a String
      • object now has an overload that takes in a Component fallback
    • ComponentContents#resolve now takes in a ResolutionContext instead of the CommandSourceStack and Entity
    • ComponentUtils#updateForEnttiy -> resolve, taking in the ResolutionContext instead of the CommandSourceStack and Entity
    • LastSeenMessages#EMPTY is now final
  • net.minecraft.network.chat.contents
    • NbtContents is now a record, the constructor taking in a CompilableString instead of a String
    • ObjectContents now takes in an optional Component for the fallback if its contents cannot be validated
  • net.minecraft.network.chat.contents.data
    • BlockDataSource now takes in a CompilableString for the Coordinates instead of the pattern and compiled position
    • EntityDataSource now takes in a CompilableString for the EntitySelector instead of the pattern and compiled selector
  • net.minecraft.network.chat.contents.objects.ObjectInfo#description -> defaultFallback
  • net.minecraft.network.protocol.game
    • ClientboundSetEntityMotionPacket is now a record
    • ServerboundContainerClickPacket now takes in a ContainerInput instead of a ClickType
    • ServerboundInteractPacket is now a record, now taking in the Vec3 interaction location
  • net.minecraft.references
    • Blocks -> BlockIds
    • Items -> ItemIds
  • net.minecraft.resources
    • FileToIdConverter is now a record
    • RegistryDataLoader#load now returns a CompletableFuture of the frozen registry access
  • net.minecraft.server.MinecraftServer now takes in a boolean of whether to propogate crashes, usually to throw a delayed crash
    • throwIfFatalException -> BlockableEventLoop#throwDelayedException, now private, not one-to-one
    • setFatalException -> BlockableEventLoop#delayCrash, relayDelayCrash; not one-to-one
  • net.minecraft.server.commands.ChaseCommand#DIMENSION_NAMES is now final
  • net.minecraft.server.dedicated.DedicatedServerProperties#acceptsTransfers is now final
  • net.minecraft.server.packs
    • BuiltInMetadata has been merged in ResourceMetadata
      • get -> ResourceMetadata#getSection
      • of -> ResourceMetadata#of
    • PathPackResources#getNamespaces now has a static overload that takes in the root directory Path
    • VanillaPackResourcesBuilder#setMetadata now takes in a ResourceMetadata instead of a BuiltInMetadata
  • net.minecraft.server.players.OldUsersConverter#serverReadyAfterUserconversion replaced by areOldUserListsRemoves, now public
  • net.minecraft.tags.TagLoader
    • loadTagsFromNetwork now takes in a Registry instead of a WritableRegistry, returning a map of tag keys to a list of holder entries
    • loadTagsForRegistry now has an overload which takes in registry key along with an element lookup, returning a map of tag keys to a list of holder entries
  • net.minecraft.util
    • Brightness
      • pack -> LightCoordsUtil#pack
      • block -> LightCoordsUtil#block
      • sky -> LightCoordsUtil#sky
    • RandomSource#createNewThreadLocalInstance -> createThreadLocalInstance
      • Now has an overload to specify the seed
    • Util#copyAndAdd now has an overload that takes in a varargs of elements
  • net.minecraft.util.thread
    • BlockableEventLoop now takes in a boolean of whether to propogate crashes, usually to throw a delayed crash
    • ReentrantBlockableEventLoop now takes in a boolean of whether to propogate crashes, usually to throw a delayed crash
  • net.minecraft.world.InteractionResult$ItemContext#NONE, DEFAULT are now final
  • net.minecraft.world.attribute
    • AttributeType now takes in a ToFloatFunction for use in a number provider
      • ofInterpolated now takes in a ToFloatFunction
    • EnvironmentAttributeReader#getValue now has an overload that takes in the LootContext
  • net.minecraft.world.entity
    • Avatar is now abstract
    • Entity
      • fluidHeight is now final
      • getTags -> entityTags
      • getRandomY now has an overload that specifies the spread double
    • Leashable$Wrench#ZERO is now final
    • LivingEntity
      • interpolation is now final
      • swingingArm is now nullable
      • canAttackType -> canAttack, not one-to-one, taking in the LivingEntity instead of the EntityType
      • lungeForwardMaybe -> postPiercingAttack
      • entityAttackRange -> getAttackRangeWith, now taking in the ItemStack used to attack
  • net.minecraft.world.entity.ai.behavior
    • GoAndGiveItemsToTarget now takes in the $ItemThrower
      • throwItem -> BehaviorUtils#throwItem, not one-to-one
    • SpearAttack no longer takes in the approach distance float
    • TryLaySpawnOnWaterNearLand -> TryLaySpawnOnFluidNearLand, not one-to-one
  • net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder#sequence now takes in a Oneshot for the second entry instead of a Trigger
  • net.minecraft.world.entity.ai.goal
    • BoatGoals -> FollowPlayerRiddenEntityGoal$FollowEntityGoal
      • BOAT is replaced by ENTITY
    • FollowBoatGoal -> FollowPlayerRiddenEntityGoal, not one-to-one
  • net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal#targetConditions is now final
  • net.minecraft.world.entity.ai.sensing.NearestVisibleLivingEntitySensor#getMemory -> getMemoryToSet
  • net.minecraft.world.entity.decoration.Mannequin#getProfile -> Avatar#getProfile, now public and abstract
    • Still implemented in Mannequin
  • net.minecraft.world.entity.item.ItemEntity#DEFAULT_HEALTH is now public from private
  • net.minecraft.world.entity.monster.breeze.Breeze#idle, slide, slideBack, longJump, shoot, inhale are now final
  • net.minecraft.world.entity.monster.piglin.PiglinAi#isZombified now takes in the Entity instead of the EntityType
  • net.minecraft.world.entity.monster.warden.Warden#roarAnimationState, sniffAnimationState, emergeAnimationState, diggingAnimationState, attackAnimationState, sonicBoomAnimationState are now final
  • net.minecraft.world.entity.monster.zombie.Zombie#handleAttributes now takes in the EntitySpawnReason
  • net.minecraft.world.entity.player
    • Input#EMPTY is now final
    • Player
      • currentImpulseImpactPos -> LivingEntity#currentImpulseImpactPos
      • currentExplosionCause -> LivingEntity#currentExplosionCause
      • setIgnoreFallDamageFromCurrentImpulse -> LivingEntity#setIgnoreFallDamageFromCurrentImpulse
      • applyPostImpulseGraceTime -> LivingEntity#applyPostImpulseGraceTime
      • isIgnoringFallDamageFromCurrentImpulse -> LivingEntity#isIgnoringFallDamageFromCurrentImpulse
      • tryResetCurrentImpulseContext -> LivingEntity#tryResetCurrentImpulseContext
      • resetCurrentImpulseContext -> LivingEntity#resetCurrentImpulseContext
      • isInPostImpulseGraceTime -> LivingEntity#isInPostImpulseGraceTime
      • isWithinAttackRange now takes in the ItemStack attacked with
  • net.minecraft.world.entity.vehicle.minecart.NewMinecartBehavior$MinecartStep#EMPTY is now final
  • net.minecraft.world.inventory.AbstractContainerMenu#getQuickCraftPlaceCount now takes in the number of quick craft slots instead of the set of slots itself
  • net.minecraft.world.item
    • BundleItem#getSelectedItem -> getSelectedItemIndex
    • CreativeModeTab$Output is now protected from public
    • EnderpearlItem#PROJECTILE_SHOOT_POWER is now final
    • Item$Properties#requiredFeatures now has an overload that takes in a FeatureFlagSet
    • Items#register* methods are now private from public
    • ItemUtils#onContainerDestroyed now takes in a Stream of ItemStacks instead of an Iterable
    • SignApplicator#tryApplyToSign, canApplyToSign now take in the ItemStack being used
    • SnowballItem#PROJECTILE_SHOOT_POWER is now final
    • ThrowablePotionItem#PROJECTILE_SHOOT_POWER is now final
    • WindChargeItem#PROJECTILE_SHOOT_POWER is now final
  • net.minecraft.world.item.alchemy.Potions now deal with Holder$References instead of the super Holder
  • net.minecraft.world.item.component
    • AttackRange
      • minRange -> minReach
      • maxRange -> maxReach
      • minCreativeRange -> minCreativeReach
      • maxCreativeRange -> maxCreativeReach
    • BundleContents
      • weight now returns a DataResult-wrapped Fraction instead of the raw object
      • getSelectedItem -> getSelectedItemIndex
    • WrittenBookContent
      • tryCraftCopy -> craftCopy
      • resolveForItem, resolve now take in the ResolutionContext and HolderLookup$Provider instead of the CommandSourceStack and Player
  • net.minecraft.world.item.enchantment
    • ConditionalEffect#codec no longer takes in the ContextKeySet
    • Enchantment#doLunge -> doPostPiercingAttack
    • EnchantmentHelper#doLungeEffects -> doPostPiercingAttackEffects
    • TargetedConditionalEffect#codec, equipmentDropsCodec no longer take in the ContextKeySet
  • net.minecraft.world.item.enchantment.effects.EnchantmentAttributeEffect#CODEC -> MAP_CODEC
  • net.minecraft.world.item.equipment.Equippable#canBeEquippedBy now takes in a holder-wrapped EntityType instead of the raw type itself
  • net.minecraft.world.item.trading.VillagerTrades#LIBRARIAN_5_EMERALD_NAME_TAG was replaced with LIBRARIAN_5_EMERALD_YELLOW_CANDLE, LIBRARIAN_5_EMERALD_RED_CANDLE, not one-to-one
    • The original trade was moved to WANDERING_TRADER_EMERALD_NAME_TAG
  • net.minecraft.world.level
    • LevelAccessor no longer implements LevelReader
    • LevelHeightAccessor#isInsideBuildHeight now has an overload that takes in the BlockPos
  • net.minecraft.world.level.block
    • BigDripleafBlock#canPlaceAt now takes in the LevelReader instead of the LevelHeightAccessor, and no longer takes in the old state
    • BubbleColumnBlock#updateColumn now takes in the bubble column Block
    • FireBlock#setFlammable is now private from public
    • MultifaceSpreader$DefaultSpreaderConfig#block is now final
    • SnowyDirtBlock -> SnowyBlock
    • SpreadingSnowyDirtBlock -> SpreadingSnowyBlock
      • The constructor now takes in the ResourceKey for the ‘base’ block, or the block when the snow or any other decoration (e.g. grass) is removed
  • net.minecraft.world.level.block.entity.TestInstanceBlockEntity
    • getTestBoundingBox - The bounding box of the test inflated by its padding.
    • getTestBounds - The axis aligned bounding box of the test inflated by its padding.
  • net.minecraft.world.level.block.entity.vault
    • VaultConfig#DEFAULT, CODEC are now final
    • VaultServerData#CODEC is now final
    • VaultSharedData#CODEC is now final
  • net.minecraft.world.level.block.state
    • BlockBehaviour
      • $BlockStateBase now takes in an array of Propertys and Comparable values instead of one value map, and no longer takes in the MapCodec
        • hasPostProcess -> getPostProcessPos, not one-to-one $Properties#hasPostProcess -> getPostProcessPos, not one-to-one
    • BlockState now takes in an array of Propertys and Comparable values instead of one value map, and no longer takes in the MapCodec
    • StateHolder now takes in an array of Propertys and Comparable values instead of one value map, and no longer takes in the MapCodec
      • populateNeighbours -> initializeNeighbors, now package-private instead of public; not one-to-one
      • getValues now returns a stream of Property$Values
      • codec now takes in the function that gets the state definition from some object
  • net.minecraft.world.level.chunk.ChunkAccess#blendingData is now final
  • net.minecraft.world.level.chunk.storage.SimpleRegionStorage#upgradeChunkTag now takes in an int for the target version
  • net.minecraft.world.level.gameevent.vibrations.VibrationSystem$Data#CODEC is now final
  • net.minecraft.world.level.gamerules.GameRules now has an overload that takes in a list of GameRules
  • net.minecraft.world.level.levelgen
    • NoiseRouterData#caves no longer takes in the HolderGetter for the NormalNoise$NoiseParameters
    • WorldDimensions#keysInOrder now takes in a set of LevelStem keys instead of a stream
  • net.minecraft.world.level.levelgen.blockpredicates
    • TrueBlockPredicate#INSTANCE is now final
    • UnobstructedPredicate#INSTANCE is now final
  • net.minecraft.world.level.levelgen.feature
    • AbstractHugeMushrromFeature
      • isValidPosition now takes in a WorldGenLevel instead of the LevelAccessor
      • placeTrunk now takes in the WorldGenLevel instead of the LevelAccessor
      • makeCap now takes in the WorldGenLevel instead of the LevelAccessor
    • BlockBlobFeature now uses a BlockBlobConfiguration generic
    • Feature
      • FOREST_ROCK replaced by BLOCK_BLOB
      • ICE_SPIKE replaced by SPIKE
    • IceSpikeFeature -> SpikeFeature, not one-to-one
      • SpikeFeature is now EndSpikeFeature, not one-to-one
        • NUMBER_OF_SPIKES -> EndSpikeFeature#NUMBER_OF_SPIKES
        • getSpikesForLevel -> EndSpikeFeature#getSpikesForLevel
  • net.minecraft.world.level.levelgen.feature.configurations
    • HugeMushroomFeatureConfiguration is now a record, taking in a can place on BlockPredicate
    • SpikeConfiguration -> EndSpikeConfiguration is now a record
      • The original SpikeConfiguration is now for the ice spike, taking in the blocks to use, along with predicates of where to place and whether it can replace a block present
    • TreeConfiguration
      • dirtProvider, forceDirt have been replaced by belowTrunkProvider
        • dirtProvider commonly uses CAN_PLACE_BELOW_OVERWORLD_TRUNKS
        • forceDirt commonly uses PLACE_BELOW_OVERWORLD_TRUNKS
      • $TreeConfigurationBuilder
        • dirtProvider, dirt, forceDirt have been replaced by belowTrunkProvider
  • net.minecraft.world.level.levelgen.feature.foliageplacers.FoliagePlacer
    • createFoliage now takes in a WorldGenLevel isntead of a LevelSimulatedReader
    • placeLeavesRow, placeLeavesRowWithHangingLeavesBelow now take in a WorldGenLevel isntead of a LevelSimulatedReader
    • tryPlaceExtension, tryPlaceLeaf now take in a WorldGenLevel isntead of a LevelSimulatedReader
  • net.minecraft.world.level.levelgen.feature.rootplacers.RootPlacer#placeRoots, placeRoot now take in a WorldGenLevel instead of a LevelSimulatedReader
  • net.minecraft.world.level.levelgen.feature.stateproviders
    • BlockStateProvider#getState now takes in the WorldGenLevel
  • net.minecraft.world.level.levelgen.feature.treedecorators
    • TreeDecorator$Context now takes in a WorldGenLevel instead of the LevelSimulatedReader
      • level now returns a WorldGenLevel instead of the LevelSimulatedReader
  • net.minecraft.world.level.levelgen.feature.trunkplacers.TrunkPlacer
    • placeTrunk now takes in a WorldGenLevel instead of the LevelSimulatedReader
    • setDirtAt -> placeBelowTrunkBlock, now taking in a WorldGenLevel instead of the LevelSimulatedReader
    • placeLog now takes in a WorldGenLevel instead of the LevelSimulatedReader
    • placeLogIfFree now takes in a WorldGenLevel instead of the LevelSimulatedReader
    • validTreePos now takes in a WorldGenLevel instead of the LevelSimulatedReader
    • isFree now takes in a WorldGenLevel instead of the LevelSimulatedReader
  • net.minecraft.world.level.levelgen.placement.BiomeFilter#CODEC is now final
  • net.minecraft.world.level.levelgen.structure.TemplateStructurePiece#template, placeSettings are now final
  • net.minecraft.world.level.levelgen.structure.pools.alias
    • DirectPoolAlias#CODEC is now final
    • RandomGroupPoolAlias#CODEC is now final
    • RandomPoolAlias#CODEC is now final
  • net.minecraft.world.level.levelgen.structure.templatesystem.LiquidSettings#CODEC is now final
  • net.minecraft.world.level.levelgen.synth.PerlinNoise#getValue no longer takes in the boolean for whether to flat the Y value instead of applying the frequency factor
  • net.minecraft.world.level.material.FluidState now takes in an array of Propertys and Comparable values instead of one value map, and no longer takes in the MapCodec
  • net.minecraft.world.level.pathfinder.PathType
    • DANGER_POWDER_SNOW -> ON_TOP_OF_POWDER_SNOW
    • DANGER_FIRE -> FIRE_IN_NEIGHBOR
    • DAMAGE_FIRE -> FIRE
    • DANGER_OTHER -> DAMAGING_IN_NEIGHBOR
    • DAMAGE_OTHER -> DAMAGING,
    • DANGER_TRAPDOOR -> ON_TOP_OF_TRAPDOOR
  • net.minecraft.world.level.saveddata.maps.MapItemSavedData#tickCarriedBy now takes in a nullable ItemFrame
  • net.minecraft.world.level.storage.loot.functions
    • EnchantRandomlyFunction now takes in a boolean of whether to include the additional trade cost component from the stack being enchanted
      • Set via $Builder#includeAdditionalCostComponent
    • EnchantWithLevelsFunction now takes in a boolean of whether to include the additional trade cost component from the stack being enchanted
      • Set via $Builder#includeAdditionalCostComponent
      • $Builder#fromOptions -> withOptions, now with overload to take in an optional HolderSet

List of Removals

  • net.minecraft.SharedConstants#USE_WORKFLOWS_HOOKS
  • net.minecraft.client.data.models.BlockModelGenerators#createGenericCube
  • net.minecraft.client.Minecraft#delayCrashRaw
  • net.minecraft.client.gui.components.EditBox#setFilter
  • net.minecraft.client.multiplayer.ClientPacketListener#getId
  • net.minecraft.client.renderer.Sheets
    • shieldSheet
    • bedSheet
    • shulkerBoxSheet
    • signSheet
    • hangingSignSheet
    • chestSheet
  • net.minecraft.client.renderer.rendertype.RenderTypes#weather
  • net.minecraft.data.loot.BlockLootSubProvider(Set, FeatureFlagSet, Map, HolderLookup$Provider)
  • net.minecraft.gametest.framework.StructureUtils#DEFAULT_TEST_STRUCTURES_DIR
  • net.minecraft.nbt.NbtUtils
    • addCurrentDataVersion
    • prettyPrint(Tag)
  • net.minecraft.server.packs.AbstractPackResources#getMetadataFromStream
  • net.minecraft.server.players.PlayerList#getSingleplayerData
  • net.minecraft.util
    • Mth#createInsecureUUID
    • LightCoordsUtil#UI_FULL_BRIGHT
  • net.minecraft.world
    • ContainerListener
    • Difficulty#getKey
    • SimpleContainer#addListener, removeListener
  • net.minecraft.world.entity.ai.memory.MemoryModuleType#INTERACTABLE_DOORS
  • net.minecraft.world.entity.monster.Zoglin#MEMORY_TYPES
  • net.minecraft.world.entity.monster.creaking.Creaking#MEMORY_TYPES
  • net.minecraft.world.entity.monster.hogling.Hoglin#MEMORY_TYPES
  • net.minecraft.world.item
    • BundleItem#hasSelectedItem
    • Item#getName()
    • ItemStack
      • isFramed, getFrame
      • setEntityRepresentation, getEntityRepresentation
  • net.minecraft.world.item.component
    • BundleContents
      • getItemUnsafe
      • hasSelectedItem
    • WrittenBookContent#MAX_CRAFTABLE_GENERATION
  • net.minecraft.world.level.block.LiquidBlock#SHAPE_STABLE
  • net.minecraft.world.level.levelgen.feature
    • Feature#isStone, isDirt, isGrassOrDirt
  • net.minecraft.world.level.levelgen.material.WorldGenMaterialRule
  • net.minecraft.world.level.storage.loot.functions.SetOminousBottleAmplifierFunction#amplifier

Source And Attribution

This docs tree was assembled from the upstream primers in:

  • Repository: https://github.com/ChampionAsh5357/neoforged-github
  • Branch: update/26.1
  • Primer root: primers/

Coverage used for this compilation

The compiled direct-port guide includes these upstream primer steps:

  • 1.21.1 -> 1.21.2/3
  • 1.21.2/3 -> 1.21.4
  • 1.21.4 -> 1.21.5
  • 1.21.5 -> 1.21.6
  • 1.21.6 -> 1.21.7
  • 1.21.7 -> 1.21.8
  • 1.21.8 -> 1.21.9
  • 1.21.9 -> 1.21.10
  • 1.21.10 -> 1.21.11
  • 1.21.11 -> 26.1

Attribution

Per the upstream primers/README.md:

  • Primers for versions 1.12 - 1.15 were written by @williewillus.
  • Primers for versions 1.16 - 1.17 were written by @50ap5ud5.
  • All newer primers, including the ones used here, were written by @ChampionAsh5357.

Licensing note

The detailed primers copied into this docs tree remain under their upstream licenses and attribution requirements.

For the exact license text and upstream breakdown, refer to:

  • repo/primers/README.md
  • repo/primers/LICENSE-CHAMPIONASH5357
  • repo/primers/LICENSE-50AP5UD5
  • repo/primers/LICENSE-WILLIEWILLUS