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
ItemStackbest 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.guiFontdrawInBatchno longer returns anythingprepareText- 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_CUTOFFis 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 theMultiBufferSource,Matrix4f,$DisplayMode, packed light coords, and the inverse depth boolean
GuishouldRenderDebugCrosshair- 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.
GuiGraphicsnow takes in aGuiRenderStateinstead of theMultiBufferSource$BufferSourceMAX_GUI_Z,MIN_GUI_Zare removedposenow returns aMatrix3x2fStackflushis removednextStratum- Adds another layer to traverse through that renders after all nodes in the previous tree.- All methods no longer take in a
RenderType,VertexConsumer, orFunction<ResourceLocation, RenderType>, instead specifying aRenderPipelineand aTextureSetupdepending on the call drawString,drawStringWithBackdropno longer returns anythingdraw*Stringmethods must now pass in an ARGB value, where A cannot be 0.renderItem(ItemStack, int, int, int, int)is removeddrawSpecialis removed, replaced by individualsubmit*RenderStatedepending on the special caseblurBeforeThisStratum- 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 forrenderDeferredTooltipto be called when not present or overriddenrenderDeferredTooltip- Adds the tooltip information to be rendered on a new stratum.blitSpritenow has an overload that takes in a float R tint color$ScissorStack#peek- Gets the last rectangle on the stack.
LayeredDrawclass is removed
net.minecraft.client.gui.componentsAbstractTextAreaWidgetnow has an overload which takes in two additional booleans of whether to show the background or decorationsAbstractWidget#getTooltipis removedCycleButton$Builder#displayOnlyValuenow has an overload that takes in thebooleanto setEditBoxsetCentered- Sets whether the text position should be centered.setTextShadow- Sets whether the text should have a drop shadow effect.
FocusableTextWidgetcan now take in a boolean indicating whether to fill the backgroundDEFAULT_PADDINGis now public
ImageWidget#updateResource- Updates the sprite of the image on the component.ItemDisplayWidget- A widget that displays anItemStack.LogoRenderer#keepLogoThroughFade- When true, keeps the logo visible even when the title screen is fading.MultiLineEditBoxis now package private and should be constructed viabuilder, calling the$Builder#set*methodssetLineLimit- Sets the line limit of the text field.setValuenow has an overload that takes in thebooleanto determine whether it should force pass the max line limit
MultiLineLabelgetStyleAtCentered- Computes the component style for centered text.getStyleAtLeftAligned- Computes the component style for left aligned text.
MultilineTextField#NO_CHARACTER_LIMIT->NO_LIMITsetLineLimit- Sets the maximum number of lines that can be written on the text field.hasLineLimit- Returns whether the text field has some line limit.setValuenow has an overload that takes in thebooleanto 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#rendernow takes in a float for the R color instead of an intWidgetTooltipHolder#refreshTooltipForNextRenderPassnow takes in theGuiGraphicsand the XY position
net.minecraft.client.gui.components.spectator.SpectatorGui#renderTooltip->renderActionnet.minecraft.client.gui.components.tabsLoadingTab- A tab that indicates information is currently being loaded.Tab#getTabExtraNarration- Returns the hint narration of the tab.TabManagercan now take in twoConsumers on what to do when a tab is selected or deselectedTabNavigationBargetTabs- 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.toastsNowPlayingToast- A toast that displays the currently playing background music.ToastxPos,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.
ToastManagernow takes in theOptionsshowNowPlayingToast,hideNowPlayingToast,createNowPlayingToast,removeNowPlayingToast- Handles the 'Now Playing' music toast.$ToastInstance#resetToast- Resets the toast.
net.minecraft.client.gui.contextualbarContextualBarRenderer- 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.GlyphRenderTypesnow takes in aRenderPipelinefor the gui renderingnet.minecraft.client.gui.font.glyphs.BakedGlyphnow takes in aGpuTextureViewextractEffect- 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,renderEffectnow takes in an additional boolean that sets the Z offset to0when true and0.001when 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.ScreenRectangletransformAxisAlignednow takes in aMatrix3x2finstead of aMatrix4fintersects- 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.renderGuiRenderer- 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.pipGuiBannerResultRenderer- 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.stateBlitRenderState- 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.pipGuiBannerResultRenderState- 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.screensConfirmScreenlayout- Defines a vertical list of elements spaced by eight units.yesButton,noButton->yesButtonComponent,noButtonComponentyesButton,noButtonnow represent the actual buttons
addAdditionalText- Adds any additional text before the buttons in the layout.addButtons- Adds the buttons in the layout.
PauseScreenrendersNowPlayingToast- Returns whether the 'Now Playing' toast should be rendered.onDisconnect->disconnectFromWorld, now public and static; not one-to-one
ScreenCUBE_MAP->net.minecraft.client.renderer.GameRenderer#cubeMapPANORAMA->net.minecraft.client.renderer.GameRenderer#panoramarenderBlurredBackgroundnow takes in theGuiGraphics*TooltipForNextRenderPassmethods are either removed or moved toGuiGraphicsFADE_IN_TIME- Represents how much time in milliseconds does it take for some element to fade in.fadeWidgets- Sets the alpha of theAbstractWidgets 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.dialogButtonListDialogScreen- 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 ofDialogListDialogs.DialogScreen- A screen for some dialog modal.DialogScreens- A factory registry of dialog modals to their associated screen.MultiButtonDialogScreen- A button list ofMultiActionDialogs.ServerLinksDialogScreen- A button list ofServerLinksDialogs.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.bodyDialogBodyHandler- A list of body elements describing the contents between the title and actions/inputs.DialogBodyHandlers- A registry ofDialogBodys to theirDialogBodyHandlers.
net.minecraft.client.gui.screens.dialog.inputInputControlHandler- A user input handler.InputControlHandlers- A registry ofInputControls to theirInputControlHandlers.
net.minecraft.client.gui.screens.inventoryAbstractContainerScreenSLOT_ITEM_BLIT_OFFSETis removedrenderContents- 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-oneBookEditScreenTEXT_*,IMAGE_*,BACKGROUND_TEXTURE_*are now public
BookSignScreen- A screen for signing a book.BookViewScreencloseScreen->closeContainerOnServer, not one-to-one$BookAccess#getPagenow returns aComponent
EffectsInInventoryrenderEffectsis now publicrenderTooltiphas been overloaded to a public method
InventoryScreen#renderEntityInInventoryno longer takes in the XY offset, instead taking in 4ints to represent the region to render toItemCombinerScreen#renderFgis removed
net.minecraft.client.gui.screens.inventory.tooltipClientTooltipComponent#renderTextno longer takes in the pose and buffer, instead theGuiGraphicsto submit the text for renderingTooltipRenderUtil#renderTooltipBackgroundno longer takes in a Z offset
net.minecraft.client.gui.screens.multiplayer.ServerLinksScreenclass is removed, replaced by dialog modalnet.minecraft.client.gui.screens.socialPlayerEntry#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$ScrollAreaclass is removed, replaced by theScrollableLayoutnet.minecraft.client.model.geom.ModelPart#getExtentsForGui- Gets the set of vectors representing the part transformed into their appropriate space.net.minecraft.client.multiplayer.ClientCommonPacketListenerImplshowDialog- 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.rendererGameRendererno longer takes in aResourceManagerITEM_ACTIVATION_ANIMATION_LENGTHis removedsetRenderHandis removedrenderZoomedis removedgetPanorama- Returns the panorama renderer.
LightTexture#getTexture->getTextureView, not one-to-oneMapRenderer#WIDTH,HEIGHTare now publicPanoramaRenderer#registerTextures- Registers the texture for use by the cube map.PostPass$Input#texturenow returns aGpuTextureViewinstead of aGpuTextureRenderPipelinesGUI_OVERLAY,GUI_GHOST_RECIPE_OVERLAY,GUI_TEXTURED_OVERLAYare removedGUI_TEXTURED_PREMULTIPLIED_ALPHA- A pipeline that assumes the textures have already had their transparency premultiplied during the composite stage.
RenderStateShard$Builder#addno longer takes in whether the shard should be blurred$TextureStateShardno longer takes in aTriStateto set the blur mode
RenderTypedebugLineis removedgui,guiOverlay,guiTexturedOverlay,guiOpaqueTexturedBackground,guiNauseaOverlay,guiTextHighlight,guiGhostRecipeOverlay,guiTexturedare removedvignetteis removedcrosshairis removedmojangLogois removed
ScreenEffectRendereris now an instance implementation instead of simply a static method- The constructor takes in the current
Minecraftinstance and aMultiBufferSource renderScreenEffectis now an instance method, taking in whether the entity is sleeping and the partial tickresetItemActivation,displayItemActivation- Handles when an item is automatically activated (e.g., totem).
- The constructor takes in the current
net.minecraft.client.renderer.blockentity*Renderer#getExtents- Adds the transformed vectors representing all models to a set.HangingSignRendererMODEL_RENDER_SCALEis now publictranslateBaseis now public
SignRendererRENDER_SCALEis now publicapplyInHandTransforms- 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.ItemRendererGUI_SLOT_CENTER_X,GUI_SLOT_CENTER_Y,ITEM_DECORATION_BLIT_OFFSETare removedCOMPASS_*->SPECIAL_*
net.minecraft.client.renderer.itemClientItem$Properties#oversizedInGui- When true, allows an item to render outside the 16x16 box in a GUI; otherwise, clips the size to the box.ItemStackRenderStatesetAnimated,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.specialPlayerHeadSpecialRenderer- Renders an player head based on its render info.SkullSpecialRenderernow implementsNoDataSpecialModelRenderer, no longer taking in the model or texture override, instead just theRenderTypeto useSpecialModelRenderer#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.registriesBuiltInRegistries#DIALOG_TYPE,DIALOG_ACTION_TYPE,INPUT_CONTROL_TYPE,DIALOG_BODY_TYPERegistries#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.chatClientEvent$Action#SHOW_DIALOG,CUSTOMvalueCodec- 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.
CommonComponentsGUI_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.commonClientboundClearDialogPacket- Closes the current dialog screen.ClientboundShowDialogPacket- Opens a new dialog screen.ServerboundCustomClickActionPacket- Sends a custom action to the server.
net.minecraft.server.dialogActionButton- A button that can perform someActionon 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 registeringDialogs.DialogTypes- A registry of map codecs to encode some dialog model.Input- A handler that maps some key to anInputControl.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.actionAction- 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 aClickEventon activation.
net.minecraft.server.dialog.bodyDialogBody- 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.inputBooleanInput- 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.clientCameranow implementsTrackedWaypoint$CameraMinecraft#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.GameRenderernow implementsTrackedWaypoint$Projectornet.minecraft.client.resourcesWaypointStyle- 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.gameClientboundTrackedWaypointPacket- 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$Methodenum is removednet.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.entityEntity#getRequiresPrecisePosition,setRequiresPrecisePosition- Handles when a more precise position is needed for tracking.LivingEntitynow implementsWaypointTransmitter
net.minecraft.world.waypointsTrackedWaypoint- A waypoint that is identified by some UUID or string, displayed via aWaypoint$Icon, and specified via$Type.TrackedWaypointManager- A waypoint manager forTrackedWaypoints.Waypoint- An interface that represents some positional location. This holds no information, and is typically used in the context ofTrackedWaypoint.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.buffersBufferTypeenum is removedBufferUsageenum is removedGpuBuffernow takes two ints represent the size and usage, the type is no longer specifiedtypeis removedusagenow returns an intslice- 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.GpuFenceis now an interface, with its OpenGL implementation moved toblaze3d.opengl.GlFenceStd140Builder- A buffer inserter for an interface block laid out in thestd140format. 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.openglAbstractUniformis removed, replaced by theStd140*classesBufferStorage- A class that create buffers given its types. Its implementations define its general usage.DirectStateAccesscreateBuffer- 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.
GlBuffernow takes in aDirectStateAccess, two ints, and aByteBufferinstead of aGlDebugLabeland itsBuffer*enumsinitializedis removedpersistentBuffer- Holds a reference to an immutable section of some buffer.$ReadView->$GlMappedView
GlCommandEncoderexecuteDrawMultiplenow takes in a collection of strings that defines the list of required uniforms and a generic indicating the object of the draw callexecuteDrawnow takes in twoint, the number of instances of the specified range of indices to be rendered and the base vertex
GlConst#toGlforBufferTypeandBufferUsage->bufferUsageToGlFlag,bufferUsageToGlEnumGlDebugLabel#pushDebugGroup,popDebugGroup- Profiler commands for grouping similar calls.GlDeviceUSE_GL_ARB_buffer_storage- Sets the extension flag forGL_ARB_buffer_storage.getBufferStorage- Returns the storage responsible for creating buffers.
GlProgramUniformfields have been removedsafeGetUniform,setDefaultUniformsare removedbindSampleris removedgetSamplerLocations,getSamplers,getUniforms->getUniformswhich returns a map of names to theirUniformobjects
GlRenderPassuniformsnow is aHashMap<String, GpuBufferSlice>dirtSamplersis removedsamplersmap now holds aGpuTextureViewvaluepushedDebugGroups- 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.
GlTexturenow takes in an additional integer for the usage and depth/layersflushModeChangesnow takes in anintwhich represents the texture targetaddViews,removeViews- Manages the views looking at a texture for some mip levels.
GlTextureView- A view implementation of a texture for some mip levels.Uniformis now a sealed interface which is implemented as either a buffer object, texel buffer, or a sampler
com.mojang.blaze3d.pipelineBlendFunction#PANORAMAis removedCompiledRenderPipeline#containsUniformis removedRenderPipeline$Builder#withUniformnow has an overload that can take in aTextureFormat$UniformDescriptionnow takes in a nullableTextureFormat
RenderTargetcolorTextureView,depthTextureView,getColorTextureView,getDepthTextureView- A view of the current color and depth textures.blitAndBlendToTexturenow takes in aGpuTextureViewinstead of aGpuTexture
com.mojang.blaze3d.platform.Lightningis nowAutoCloseablesetup*->setupFor, an instance method that takes in an$EntryupdateLevel- Updates the lighting buffer, taking in whether to use the nether diffused lighting.
com.mojang.blaze3d.shadersFogShape->net.minecraft.client.renderer.fog.FogData, not one-to-oneUniformTypenow only holds two types:UNIFORM_BUFFER, orTEXEL_BUFFER, and no longer takes in a count
com.mojang.blaze3d.systemsCommandEncoderclearColorAndDepthTexturesnow has an overload that takes in fourints representing the region to clear the texture information withinwriteToBuffer,mapBuffer(GpuBuffer, int, int)now take in aGpuBufferSliceinstead of aGpuBuffercreateFence- Creates a new sync fence.createRenderPassnow takes in aSupplier<String>, used for determining the name of the pass to use as a debug group, andGpuTextureViews instead ofGpuTextureswriteToTexturenow takes in an additionalintrepresenting the depth or layer to write topresentTexturenow takes in aGpuTextureViewinstead of aGpuTexture
GpuDevicecreateBufferno longer takes in aBufferUsage, withBufferTypereplaced by anintgetUniformOffsetAlignment- Returns the uniform buffer offset alignment.createTexturenow takes in additionalsintfor the usage and the number of depth/layers, seeGpuTextureconstantscreateTextureView- Creates a view of a texture for a certain range of mip levels.
RenderPassenableScissoris removedbindSamplercan now take in a nullableGpuTextureViewsetUniformcan either take in aGpuBufferorGpuBufferSliceinstead of the raw inputsdrawIndexednow takes the followingints: the base vertex, the start index, the number of elements, and the prim countdrawMultipleIndexednow takes in a collection of strings that defines the list of required uniforms and a generic indicating the object of the draw callpushDebugGroup,popDebugGroup- Profiler commands for grouping similar calls.$UniformUploader#uploadnow takes in aGpuBufferSliceinstead of an array offloats$Drawnow has a generic that passed in to upload any uniforms to the buffer
RenderSystemSCISSOR_STATE->scissorStateForRenderTypeDraws, now private- Accessible through
getScissorStateForRenderTypeDraws
- Accessible through
enableScissor,disableScissor->enableScissorForRenderTypeDraws,disableScissorForRenderTypeDraws, not one to onePROJECTION_MATRIX_UBO_SIZE- Returns the size of the projection matrix uniformsetShaderFog,getShaderFognow deals with aGpuBufferSlicesetShaderGlintAlpha,getShaderGlintAlphais removedsetShaderLights,getShaderLightsnow deals with aGpuBufferSlicesetShaderColor,getShaderColorsetup*Lightingmethods are removedsetProjectionMatrix,getProjectionMatrix(nowgetProjectionMatrixBuffer) now deals with aGpuBufferSlicesetShaderGameTime,getShaderGameTime->setGlobalSettingsUniform,getGlobalSettingsUniform; not one-to-onegetDynamicUniforms- Returns a list of uniforms to write for the shader.bindDefaultUniforms- Binds the default uniforms to be used within aRenderPassoutputColorTextureOverride,outputDepthTextureOverrideare nowGpuTextureViewssetupOverlayColor,setShaderTexture,getShaderTexturenow operate onGpuTextureViews instead ofGpuTextures
com.mojang.blaze3d.texturesGpuTexturenow takes in an int representing the usage flags and number of depth/layersusage- 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.vertexByteBufferBuildernow takes in a long for the maximum capacityexactlySized- 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.rendererCachedOrthoProjectionMatrixBuffer- 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.CloudRendererFLAG_INSIDE_FACE,FLAG_USE_TOP_COLORare now privateRADIUS_BLOCKSis removedendFrame- Ends the current frame being rendered to by constructing a fence.
CubeMapis nowAutoCloseablerenderno 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.FogParametersrecord is removed, now stored in a generalGpuBufferSliceFogRenderernow implementsAutoCloseable->.fog.FogRendererendFrame- 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.setupFogno longer takes in theFogMode, returning nothing$FogData#modeis removed, replaced byskyEnd,cloudEnd$FogModeenums have been replaced withNONEandWORLD, not one-to-one
GameRenderergetGlobalSettingsUniform- 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.LevelRendererendFrame- Ends the current frame being rendered to by constructing a fence.renderLevelnow takes in aGpuBufferSlice, the fog vector, and whether the current position is foggy instead of theGameRenderer
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#rendernow 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.PostChainloadnow takes in theCachedOrthoProjectionMatrixBufferaddToFrameno longer takes in theConsumer<RenderPass>processno longer takes in theConsumer<RenderPass>
PostChainConfig$FixedSizedTargetrecord is removed$FullScreenTargetrecord is removed$InternalTargetis now a record which can take in an optional width, height, whether the target is persistent, and the clear color to use$Pass#uniformsis now aMap<String, List<UniformValue>>$Uniformrecord is removed
PostPassis nowAutoCloseable, taking in aMap<String, List<UniformValue>>for the uniforms along with a list ofPostPass$InputsaddToFrameno longer takes in theConsumer<RenderPass>, with theMatrix4fpassed in as aGpuBufferSlice$InputbindTois removedtexture- Constructs aGpuTexturefor the input given the map of resources.samplerName- Returns the name of the sampler.
SkyRenderer#renderSunMoonAndStarsno longer takes in theFogParametersUniformValue- 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.environmentAirBasedFogEnvironment- An environment whose color is derived from the air of the biomeAtmosphericFogEnvironment- 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.textureAbstractTexturesetUseMipmaps- 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_0to_5.ReloadableTexture#doLoadis now protected
net.minecraft.world.level.material.FogTypeDIMENSION_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.tagsBlockItemTagsProvider- A provider that generates tags for block items, using the block and item tag equivalents as a starting point.IntrinsicHolderTagsProvidertagnow returns the rawTagAppender$IntrinsicTagAppenderclass is removed
ItemTagsProviderclass is removedKeyTagProvider- A provider which appends elements via theirResourceKey.TagsProvidertagis removed$TagAppender->TagAppender, not one-to-one
VanillaItemTagsProvidernow implementsIntrinsicHolderTagsProviderBlockToItemConverter- 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.ServerPlayerloadAndSpawnParentVehiclenow takes in aValueInputloadAndSpawnEnderPearlsnow takes in aValueInputloadGameTypesnow takes in aValueInput
net.minecraft.server.players.PlayerList#loadtakes in aProblemReporter, returning an optionalValueInputnet.minecraft.util.ProblemReporterDISCARDING- A reporter which discards all reporters.forChildnow takes in a$PathElementreportnow takes in a$Problem$Collectornow has a constructor that takes in the root$PathElementisEmpty- Returns whether there are no reports.forEach- Loops through all available problems.getReportnow returns a regularStringgetTreeReport- Gets the report and all its children using DFS.
$ElementReferencePathElement- A path element that references someResourceKey.$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 someResourceKeyas the root.$RootFieldPathElement- A path element that references some string as the root.$ScopedCollector- A collector that logs warnings when problems arise.
net.minecraft.worldContainerHelpersaveAllItemsnow takes in aValueOutputinstead of aCompoundTag, and no longer takes in aHolderLookup$Providerwhile returning nothingloadAllItemsnow takes in aValueInputinstead of aCompoundTag, and no longer takes in aHolderLookup$Provider
LockCode#addToTag,fromTagnow takes in aValueOutput/ValueInputinstead of aCompoundTag, and no longer takes in aHolderLookup$ProviderRandomziableContainer#tryLoadLootTable,trySaveLootTablenow takes in aValueOutput/ValueInputinstead of aCompoundTagSimpleContainerfromTag->fromItemList, not one-to-onecreateTag->storeAsItemList, not one-to-one
net.minecraft.world.entityEntitysaveAsPassengernow takes in aValueOutputinstead of aCompoundTagsavenow takes in aValueOutputinstead of aCompoundTagsaveWithoutIdnow takes in aValueOutputinstead of aCompoundTag, returning nothingloadnow takes in aValueInputinstead of aCompoundTagreadAdditionalSaveDatanow takes in aValueInputinstead of aCompoundTagaddAdditionalSaveDatanow takes in aValueOutputinstead of aCompoundTagproblemPath- Returns the path element to report problems from.
EntityRenferencestorenow takes in aValueOutputinstead of aCompoundTagread,readWithOldOwnerConversionnow take in aValueInputinstead of aCompoundTag
EntityUUID_TAG->TAG_UUIDcreate,bynow take in aValueInputinstead of aCompoundTagloadEntityRecursivenow takes in aValueInputinstead of aCompoundTagloadEntitiesRecursivenow takes in aValueInput$ValueInputListinstead of a list of nbt tagsloadStaticEntitynow takes in aValueInputinstead of aCompoundTag
EntityReference#store- Writes the reference data to theValueOutput.Leashable#readLeashData,writeLeashDatanow take in aValueInput/ValueOutputinstead of aCompoundTagLivingEntity#ATTRIBUTES_FIELD->TAG_ATTRIBUTESNeutralMob#addPersistentAngerSaveData,readPersistentAngerSaveDatanow take in aValueOutput/ValueInputinstead of aCompoundTag
net.minecraft.world.entity.npc.InventoryCarrier#readInventoryFromTag,writeInventoryToTagnow take in aValueInput/ValueOutputinstead of aCompoundTagnet.minecraft.world.entity.player.Inventorysavenow takes in aValueOutput$TypedOutputList, returning nothingloadnow takes in aValueOutput$TypedInputList
net.minecraft.world.entity.variant.VariantUtilswriteVariantnow takes in aValueOutputinstead of aCompoundTagreadVariantnow takes in aValueInputinstead of aCompoundTag, and no longer takes in aRegistryAccess
net.minecraft.world.entity.vehicle.ContainerEntity#addChestVehicleSaveData,readChestVehicleSaveDatanow take in aValueOutput/ValueInputinstead of aCompoundTag, and no longer takes in aHolderLookup$Providernet.minecraft.world.inventory.PlayerEnderChestContainerfromTag->fromSlots, not one-to-onecreateTag->storeAsSlots, not one-to-one
net.minecraft.world.itemBlockItem#setBlockEntityDatanow takes in aTagValueOutputinstead of aCompoundTagItemStack#parse,saveare removed
net.minecraft.world.levelBaseCommandBlock#save,loadnow take in aValueOutput/ValueInputinstead of aCompoundTag, and no longer takes in aHolderLookup$Provider, returning nothingBaseSpawner#save,loadnow take in aValueOutput/ValueInputinstead of aCompoundTag, returning nothing
net.minecraft.world.level.block.SculkSpreader#save,loadnow take in aValueOutput/ValueInputinstead of aCompoundTagnet.minecraft.world.level.block.entity.BlockEntityload*methods now take in aValueInputinstead of aCompoundTag, and no longer takes in aHolderLookup$Providersave*methods now take in aValueOutputinstead of aCompoundTag, and no longer takes in aHolderLookup$ProviderremoveComponentsFromTagnow takes in aValueOutputinstead of aCompoundTagparseCustomNameSafenow takes in aValueInputand key instead of a tag andHolderLookup$ProviderproblemPath- 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.storagePlayerDataStorage#loadnow returns aValueInputinstead of aCompoundTag, taking in aProblemReporterTagValueInput- 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.ValidationContextforChild,enterElementnow takes in aProblemReporter$PathElementinstead of aStringreportProblemnow takes in aProblemReporter$Probleminstead of aString$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.entriesAlternativesEntry#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.ServerPlayerserverfield is now privateserverLevel->level, still returnsServerLevel
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.EntityRenderStateleashStatenow returns a list of$LeashStates$LeashState#slack- Whether the leash has any slack.
net.minecraft.world.entityEntityshearOffAllLeashConnections- 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.setLeashOffsetis removedgetLeashOffset->Leashable#getLeashOffset
LeashableMAXIMUM_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-oneleashDistanceTo- 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.handleLeashAtDistanceis removedangularFriction- 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-onesupportQuadLeash- 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#getMobEffectTexturesis removednet.minecraft.client.gui.Gui#getMobEffectSprite- Gets the location of the mob effect sprite.net.minecraft.client.resources.MobEffectTextureManageclass is removedAtlasIds#MOB_EFFECTSis 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.multiplayerClientPacketListenergetCommandsnow returns aClientSuggestionProvidergenericsendUnattendedCommandnow takes in aScreeninstead of aboolean
ClientSuggestionListenernow implementsPermissionSource, taking in a boolean of whether it allows restricted commandsallowRestrictedCommands- Returns whether restricted commands can be suggested.
net.minecraft.commandsCommands#hasPermission- Returns a permission check for the given level.CommandSourceStacknow implementsPermissionSourceExecutionCommandSourcenow implementsPermissionSourcePermissionSource- Returns the source of the permission to run a command.SharedSuggestionProvidersuggestResgitryElementsnow takes in aHolderLookupinstead of aRegistrylistSuggestions- Lists the suggestion for some registry elements.hasPermissionis removed
net.minecraft.commands.synchronization.SuggestionProvidersAVAILABLE_SOUNDS,SUMMONABLE_ENTITIESnow take in aSharedSuggestionProviderfor their genericcast- Casts the suggestion provider to the correct type.safelySwapis removed$Wrapper->$RegisteredSuggestion
net.minecraft.world.entity.Entity#getCommandSenderWorldis 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.animationAnimationDefinition#bake- Bakes a defined animation to be used on aModel.KeyframeAnimation- A baked animation used to moveModelParts on a givenModel.KeyframeAnimations#animate->KeyframeAnimation$Entry#apply
net.minecraft.client.model.ModelgetAnyDescendantWithNameis removedanimate->KeyframeAnimation#applyanimateWalk-KeyframeAnimation#applyWalkapplyStatic->KeyframeAnimation#applyStatic
net.minecraft.client.model.geom.ModelPartgetAllPartsnow returns aListcreatePartLookup- Creates a lookup of part names to theirModelPart, 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.rendererItemBlockRenderTypesgetChunkRenderTypenow returns aChunkSectionLayergetRenderLayer(FluidState)now returns aChunkSectionLayer
RenderTypetranslucentis removedgetRenderTarget,getRenderPipelineis removedchunkBufferLayersis removed
net.minecraft.client.renderer.chunkChunkSectionLayer- 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->SectionCopyRenderChunkRegion->RenderSectionRegionRenderRegionCache#createRegionnow takes in alonginstead of aSectionPosSectionCompiler$ResultsglobalBlockEntities-> -net.minecraft.client.multiplayer.ClientLevel#getGloballyRenderedBlockEntitiesrenderedLayersnow takes in aChunkSectionLayerfor the key
SectionMesh- An interface that defines the mesh of a given section within a chunkSectionRenderDispatchergetBatchToCount->getCompileQueueSizesetCamera,getCameraPositionare removedblockUntilClearis removedclearBatchQueue->clearCompileQueue, now public$CompiledSection->CompiledSectionMesh$RenderSectiongetBuffersis removeduploadSectionLayer(RenderType, MeshData)->upload(Map, CompiledSectionMesh), not one-to-oneuploadSectionIndexBuffernow takes in aCompiledSectionMeshand aChunkSectionLayerinstead of aRenderTypegetDistToPlayerSqris removedgetCompiled->getSectionMesh, not one-to-onerebuildSectionAsyncno longer takes in theSectionRenderDispatchersetDynamicTransformIndex,getDynamicTransformIndexare removed
$SectionBuffers->SectionBuffers$TranslucencyPointOfView->TranslucencyPointOfView
net.minecraft.server.level.ChunkMap#getUpdatingChunkIfPresentis now publicnet.minecraft.world.level.TicketStoragepurgeStaleTicketsnow takes in theChunkMapremoveTicketIfnow takes in aBiPredicateinstead of aPredicate, taking in the chunk position and the ticket
net.minecraft.world.level.chunk.ChunkAccess#isSectionEmptyis removed
Tag Changes
minecraft:blockplays_ambient_desert_block_soundsis split intotriggers_ambient_desert_sand_block_sounds,triggers_ambient_desert_dry_vegetation_block_soundshappy_ghast_avoidstriggers_ambient_dried_ghast_block_sounds
minecraft:dialogpause_screen_additionsquick_actions
minecraft:entity_typecan_equip_harnessfollowable_friendly_mobs
minecraft:itemharnesseshappy_ghast_foodhappy_ghast_tempt_items
List of Additions
com.mojang.blaze3d.pipelineBlendFunction#TRANSLUCENT_PREMULTIPLIED_ALPHA- A blend function that assumes the target has a premultiplied alpha from the composite step.RenderPipelinegetSortKey- 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.RenderSystemoutputColorTextureOverride- Holds a texture containing the override color used instead of whatever is specified in theRenderTypetarget.outputDepthTextureOverride- Holds a texture containing the override depth used instead of whatever is specified in theRenderTypetarget.
com.mojang.blaze3d.textures.GpuTexture#setUseMipmaps- Sets whether the texture should use mipmaps at different distances.net.minecraftFileUtil#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.critereonItemUsedOnLocationTrigger$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.clientGameNarrator#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.OptionskeyQuickActions- 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 theMusicManagershould 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 butOFF.
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.modelModelTemplates#DRIED_GHAST- A template that uses theminecraft:block/dried_ghastparent.TextureMapping#driedGhast- Creates the default texture mapping for the dried ghast model.TextureSlot#TENTACLES- Provides a texture keytentacles.
net.minecraft.client.modelGhastModel#animateTentacles- Animates the tentacles of a ghast.HappyGhastHarnessModel- A model representing the a ghast harness.HappyGhastModel- A model representing a 'tamed' ghast.QuadrupedModel#createBodyMeshnow takes in two booleans for handling if the left and right hind leg textures are mirrored, respectively.
net.minecraft.client.multiplayer.ClientLevelDEFAULT_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.soundsMusicManagergetCurrentMusicTranslationKey- 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.argumentsHexColorArgument- An integer argument that takes in a hexadecimal color.ResourceOrIdArgumentcreateGrammar- 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.RecipeProviderdryGhast- 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.NbtUtilsaddCurrentDataVersion,addDataVersion, adds the data version to some nbt tag.
net.minecraft.network.FriendlyByteBuf#writeEither,readEither- Handles anEitherwith the given stream encoders/decoders.net.minecraft.network.codec.ByteBufCodecsRGB_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 anOptional-wrappedTagusing the suppliedNbtAccounter.
net.minecraft.network.protocol.gameServerboundChangeGameModePacket- 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.ServerLevelupdateNeighboursOnBlockSet- Updates the neighbors of the current position. If the blocks are not the same (not including their properties), thenBlockState#affectNeighborsAfterRemovalis 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.statsRecipeBookSettings#MAP_CODECServerRecipeBook#pack,loadUntrusted,$Packed- Handles encoding and decoding the data of the recipe book.
net.minecraft.utilARGBsetBrightness- 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.
ExtraCodecsVECTOR2FVECTOR3INBT
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.worldDifficulty#STREAM_CODECItemStackWithSlot- A record which holds a stack along with its slot index.
net.minecraft.world.entityEntityMAX_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.ExperienceOrbawardWithDirection- Adds an experience orb that moves via the specified vector.unstuckIfPossible- Attempts to find and move the orb to a free position.
MobisWithinHome- 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 toWAIT.net.minecraft.world.entity.ai.goal.TemptGoalstopNavigation,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.animalHappyGhast- An entity representing a happy ghast.HappyGhastAi- The brain of the happy ghast.
net.minecraft.world.entity.decoration.ArmorStandsetArmorStandPose,getArmorStandPose,$ArmorStandPose- Handles the pose of the armor stand.
net.minecraft.world.entity.monster.GhastfaceMovementDirection- 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.componentItemAttributeModifiersforEach- 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$BuildersetCanBeSheared- 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.levelCollisionGettergetPreMoveCollisions- 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_CODECLevelprecipitationAt- Returns the precipitation at a given position.onBlockEntityAdded- Logic to run when a block entity is added to the level.
net.minecraft.world.level.blockBaseRailBlock#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.DimensionDefaultsCLOUD_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.physAABBintersects- Returns whether theBlockPosintersects 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.CollisionContextwithPosition- Returns the collision context of an entity with its bottom y position.
List of Changes
com.mojang.blaze3d.platform.Window#setGuiScale,getGuiScalenow deals with anintinstead of adoublenet.mineraftDetectedVersionno longer implementsWorldVersionWorldVersionmethods now use record naming schema due toWorldVersion$SimpleusagegetDataVersion->dataVersiongetId->idgetName->namegetProtocolVersion->protocolVersiongetPackVersion->packVersiongetBuildTime->buildTimeisStable->stable
net.minecraft.clientGameNarratorsayChat->sayChatQueuedsay->saySystemQueuedsayNow->saySystemNow
MinecraftgrabPanoramixScreenshotno longer takes in the window width and height to setdisconnect()->disconnectWithProgressScreen
Screenshot#grab,takeScreenshotnow takes in anintrepresenting the downscale factor
net.minecraft.client.main.GameConfig$QuickPlayDatanow takes in a$QuickPlayVariantpath->logPathsingleplayer->variantwith$QuickPlaySinglePlayerDatamultiplayer->variantwith$QuickPlayMultiplayerDatarealms->variantwith$QuickPlayRealmsData- null for
singleplayer,multiplayer,realmsis represented byvariantwith$QuickPlayDisabled
net.minecraft.client.data.models.ItemModelGenerators#generateWolfArmor->generateTwoLayerDyedItemnet.minecraft.client.gui.components.DebugScreenOverlay#render3dCrosshairnow takes in the currentCameranet.minecraft.client.gui.components.debugchart.ProfilerPieChartRADIUSis now publicCHART_Z_OFFSET->PIE_CHART_THICKNESS, now public
net.minecraft.client.multiplayerClientLevel$ClientLevelData#getClearColorScale->voidDarknessOnsetRange, not one-to-oneMultiPlayerGameMode#createPlayernow takes in anInputinstead of aboolean
net.minecraft.client.player.LocalPlayernow takes in the last sentInputinstead of abooleanfor the shift keygetLastSentInput- Gets the last sent input from the server.
net.minecraft.client.quickplay.QuickPlay#connectnow takes in aGameConfig$QuickPlayVariantinstead of aGameConfig$QuickPlayDatanet.minecraft.client.rendererDimensionSpecialEffectsno longer takes in the current cloud level and whether there is a groundLightTexture#getTarget->getTexture
net.minecraft.client.renderer.blockentity.BlockEntityRenderer#shouldRenderOffscreenno longer takes in theBlockEntitynet.minecraft.client.resourcesAbstractSoundInstance#soundis nowNullableSoundInstance#getSoundis nowNullable
net.minecraft.client.soundsSimpleSoundInstance#forMusicnow also takes in thefloatvolumeSoundEnginenow takes in theMusicManagerpause->pauseAllExcept, not one-to-oneplaynow returns a$PlayResult
SoundManagernow takes in theMusicManagerpause->pauseAllExcept, not one-to-oneplaynow returns aSoundEngine$PlayResult
net.minecraft.commands.argumentsResourceOrIdArgumentnow takes in an arbitrary codec rather than aHolder-wrapped valueERROR_INVALID->ERROR_NO_SUCH_ELEMENT, now public, not one-to-oneVALUE_PARSER->OPS, now public, not one-toe
ResourceSelectorArgument#getSelectedResourcesno longer takes in theResourceKey
net.minecraft.commands.functions.StringTemplatefromStringno longer takes in the line numberisValidVariableNameis now public
net.minecraft.data.recipes.RecipeProvider#colorBlockWithDye->colorItemWithDye, now takes in theRecipeCategorynet.minecraft.gametest.framework.GameTestInfo#prepareTestStructureis now nullablenet.minecraft.networkConnection#sendnow takes in aChannelFutureListenerinstead of aPacketSendListenerFriendlyByteBuf#readJsonWithCodec->readLenientJsonWithCodecPacketSendListeneris now a class whose methods returnChannelFutureListeners instead ofPacketSendListenersonSuccess,onFailureare removed
net.minecraft.network.codecByteBufCodecs#fromCodecnow has an overload that takes in some ops and a codecStreamCodec#compositenow has an overload that takes in ten parameters
net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacketis now a recordnet.minecraft.network.protocol.gameClientboundChangeDifficultyPacketis now a recordClientboundCommandsPacketnow takes in a$NodeInspectorgetRootis 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.
ServerboundChangeDifficultyPacketis now a record
net.minecraft.server.ReloadableServerRegistries$Holder#lookupreturns aHolderLookup$Providernet.minecraft.server.network.ServerCommonPacketListenerImpl#sendnow takes in aChannelFutureListenerinstead of aPacketSendListenernet.minecraft.sounds.Musicis now a recordnet.minecraft.stats.RecipeBookSettingsgetSettingsis now public$TypeSettingsis now public
net.minecraft.world.entityAreaEffectCloud#setParticle->setCustomParticleEntitycheckSlowFallDistance->checkFallDistanceAccumulationcollidedWithFluid,collidedWithShapeMovingFromare now publiccanBeCollidedWithnow takes the entity its colliding withspawnAtLocationnow has an overload that takes in aVec3for the offset positionremoveLatestMovementRecordingBatch->removeLatestMovementRecording
EntityReferenceis now finalExperienceOrbnow has an overload that takes in two vectors for the position and movementFlyingMobis replaced by callingLivingEntity#travelFlyingLivingEntity#canBreatheUnderwateris no longerfinalMobrestrictTo->setHomeTogetRestrictCenter->getHomePositiongetRestrictRadius->getHomeRadiusclearRestriction->clearHomehasRestriction->hasHome
net.minecraft.world.entity.ai.attributesAttributeInstancesave->pack,$Packed; not one-to-oneload->apply, not one-to-one
AttributeMapsave->pack; not one-to-oneload->apply, not one-to-one
net.minecraft.world.entity.ai.behaviorAnimalPanicnow has overloads that take in a radius or a position getterBabyFollowAdult#createnow returns aOneShot<LivingEntity>and can take in abooleanof whether to target the eye positionEntityTrackercan now take in abooleanof whether to target the eye positionFollowTemptationnow has an overload that checks whether the entity needs to track the entity's eye height.
net.minecraft.world.entity.ai.goal.TemptGoalnow has an overload that takes in the stop distancemobis now aMobspeedModifieris nowprotected
net.minecraft.world.entity.ai.memory.MemoryModuleType#NEAREST_VISIBLE_ADULTnow holds aLivingEntitynet.minecraft.world.entity.ai.navigationFlyingPathNavigation,GroundPathNavigation#setCanOpenDoors->PathNavigation#setCanOpenDoors
net.minecraft.world.entity.ai.sensing.AdultSensornow looks for aLivingEntitysetNearestVisibleAdultis nowprotected
net.minecraft.world.entity.animal.*Variants#selectVariantToSpawn->entity.variant.VariantUtils#selectVariantToSpawn, not one-to-onenet.minecraft.world.entity.animal.Fox#isJumping->LivingEntity#isJumpingnet.minecraft.world.entity.animal.horse.AbstractHorseisJumping->LivingEntity#isJumpingsetStandingnow takes in anintinstead of abooleanfor the stand counter- the
falselogic is moved toclearStanding
- the
net.minecraft.world.entity.monsterGhastnow implementsMob$GhastLookGoalis now public, taking in aMob$GhastMoveControlis now public, taking in whether it should be careful when moving and a supplied boolean of whether the ghast should stop moving$RandomFloatAroundGoalis nowpublic, taking in aMoband a block distance
Phantomnow implementsMob
net.minecraft.world.entity.playerAbilitiesaddSaveData->pack,$Packed; not one-to-oneloadSaveData->apply, not one-to-one
Playerno longer takes in theBlockPosand y rotation
net.minecraft.world.entity.projectileAbstractThrownPotion#onHitAsPostionnow takes in aHitResultinstead of a nullableEntityEyeOfEnder#signalTonow takes in aVec3instead of aBlockPosProjectileownerUUID.cachedOwner->owner, now protected; not one-to-onesetOwnernow has an overload to take in anEntityReference
ProjectileUtilDEFAULT_ENTITY_HIT_RESULT_MARGINis now publicgetEntityHitResultnow takes in aProjectileinstead of anEntity
net.minecraft.world.item.ItemStackforEachModifiernow takes in aTriConsumerthat provides the modifier displayhurtAndBreaknow has an overload which gets theEquipmentSlotfrom theInteractionHand
net.minecraft.world.item.equipment.Equippablenow takes in whether the equipment can be sheared off an entity and the sound to play when doing sonet.minecraft.world.level.BlockGetterforEachBlockIntersectedBetweennow returns a boolean indicating that each block visited in the intersected area can be successfully visited$BlockStepVisitor#visitnow returns whether the location can be successfully moved to
net.minecraft.world.level.block.AbstractCauldronBlock#SHAPEis now protectednet.minecraft.world.level.block.entityBlockEntity#getNameForReportingis now publicSignBlockEntity#executeClickCommandsIfPresentnow takes in aServerLevelinstead of theLevel, parameters are reorderedStructureBlockEntity#saveStructurenow takes in a list of blocks to ignore
net.minecraft.world.level.block.entity.trialspawnerTrialSpawnernow takes in a$FullConfiggetConfig->activeConfigget*Config->*configgetData->getStateData
TrialSpawnerData->TrialSpawnerStateData, serialized form asTrialSpawnerStateData$Packed, not one-to-one
net.minecraft.world.level.block.sounds.AmbientDesertBlockSoundsPlayer#playAmbientBlockSoundshas been split intoplayAmbientSandSounds,playAmbientDryGrassSounds,playAmbientDeadBushSounds,shouldPlayDesertDryVegetationBlockSounds; not one-to-onenet.minecraft.world.level.dimension.DimensionTypenow takes in an optional integer representing the cloud height levelnet.minecraft.world.level.entityPersistentEntitySectionManager#processPendingLoadsis now publicUUIDLookup#getEntitycan now return null
net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate#fillFromWorldnow takes in a list of blocks to ignore rather than a singleBlocknet.minecraft.world.level.storage.DataVersionis now a recordnet.minecraft.world.phys.shapes.CollisionContext#placementContextnow takes in aPlayerinstead of anEntity
List of Removals
net.minecraft.client.Minecraft#disconnect(Screen)net.minecraft.client.rendererDimensionSpecialEffects#getCloudHeight,hasGroundLevelRenderer#updateGlobalBlockEntities
net.minecraft.client.renderer.texture.AbstractTexturedefaultBlursetFilter
net.minecraft.network.chat.Component$Serializer,$SerializerAdapternet.minecraft.network.protocol.game.ServerboundPlayerCommandPacket$Action#*_SHIFT_KEYnet.minecraft.server.ReloadableServerRegistries$Holder#getKeysnet.minecraft.server.players.PlayerList#getPlayerForLoginnet.minecraft.statsRecipeBookSettings#read,writeServerRecipeBook#toNbt,fromNbt
net.minecraft.utilGsonHelper#fromNullableJson(..., boolean),fromJson(..., boolean)LowerCaseEnumTypeAdapterFactory
net.minecraft.world.entity.ai.attributes.AttributeInstance#ID_FIELD,TYPE_CODECnet.minecraft.world.entity.animal.horse.AbstractHorse#setIsJumpingnet.minecraft.world.entity.animal.sheep.Sheep#getColornet.minecraft.world.entity.monster.Drowned#waterNavigation,groundNavigationnet.minecraft.world.entity.projectile.Projectile#findOwner,setOwnerThroughUUIDnet.minecraft.world.level.Level#disconnect()net.minecraft.world.level.blockAbstractCauldronBlock#isEntityInsideContentTerracottaBlock
net.minecraft.world.level.block.entity.trialspawner.TrialSpawner*_CONFIG_TAG_NAMEcodec
net.minecraft.world.level.dimension.DimensionType#parseLegacy