# Minecraft 1.21.5 -> 1.21.6 模组迁移入门文档

本文档是一个高层次、非详尽的概述，介绍如何将您的模组从 1.21.5 迁移到 1.21.6。本文不涉及任何特定的模组加载器，只关注原版类的变更。所有提供的名称均使用官方的 Mojang 映射。

本入门文档采用 [知识共享署名 4.0 国际许可协议](http://creativecommons.org/licenses/by/4.0/) 授权，因此您可以自由地将其用作参考，并请留下链接以便其他读者查阅。

如果存在任何不正确或缺失的信息，请在本仓库提交 issue，或在 Neoforged Discord 服务器中 @ChampionAsh5357。

感谢：

- @Soaryn 提供了一些 `ItemStack` 最佳实践和拼写修复
- @earthcomputer 提供了绘制字符串时的颜色更改

## 资源包变更

原版中有许多面向用户的变更为未在下面讨论，但这些变更可能与模组制作者相关。您可以在 [Misode 的版本更新日志](https://misode.github.io/versions/?id=1.21.6&tab=changelog) 中找到它们的列表。

## GUI 变更

GUI 渲染系统与之前的版本相比发生了重大变化。虽然表面上看起来有些相似，但实际的实现细节要复杂得多且迂回。本文将以高层次概述新系统，并提供一些基本示例。

### 准备与渲染

渲染 GUI 已分为两个阶段：“准备”和“渲染”。

准备阶段是我们通常认为的 GUI 渲染方法（例如，`Gui#render`、`AbstractContainerScreen#renderBg` 等）。这些方法现在不再实际渲染组件，而是将它们提交给 `GuiRenderState` 以存储在“渲染”阶段使用。`GuiRenderState` 存储在 `GameRenderer` 上，并传递给 `GuiGraphics`，后者使用前述方法将所需对象添加到渲染状态。

渲染阶段实际处理所有对象的渲染。这是通过 `GuiRenderer` 处理的，它从 `GuiRenderState` 读取数据，并在经过一些委托的准备和排序后，将对象渲染到屏幕上。`GuiRenderer` 也存储在 `GameRenderer` 上。

### 元素排序

现在，元素是如何渲染到屏幕上的？在之前的版本中，这主要基于渲染调用的顺序。然而，新系统使用两种不同的排序方法。第一种方法使用层和线性树来处理深度。第二种方法基于三个因素（按优先级顺序）使用比较器：`ScreenRectangle` 剪裁、`RenderPipeline` 顺序和 `TextureSetup` 的哈希码。这些都存储在通过 `GuiRenderState#submitGuiElement` 传递给 `GuiRenderState` 的 `GuiElementRenderState` 上。

一旦元素排序完毕，它们将从 Z 值为 `0` 开始渲染，每个元素比前一个元素向前渲染 `0.01`。

作为警告，由于元素排序顺序，某些自定义配置可能导致屏幕渲染不正确。因此，您必须理解这些方法及其分配的值在排序元素时的工作原理。

#### 层与树

第一种排序方法处理对象渲染的 z 深度。

首先从线性树开始。顾名思义，它基本上是一个双向链接的 `GuiRenderState$Node` 列表。每个节点包含自己的要渲染的元素列表。使用 `GuiRenderState#up` 或 `down` 来导航节点列表，每个方法要么获取下一个节点，要么如果不存在则创建一个新节点。给定树中的节点从底部到顶部渲染，这意味着 `down` 将在当前节点之前渲染任何提交的元素，而 `up` 将在当前节点之后渲染任何提交的元素。

提交元素时，使用其 `ScreenArea` 自动计算元素被添加到哪个节点。`ScreenArea` 定义了要渲染的元素的 `bounds`。本质上，如果元素的边界与当前节点上的任何其他元素相交，则将在 `up` 方向添加一个节点。

然后是层（strata）。一个层本质上是一个线性树。层按照它们被创建的顺序渲染，这意味着调用 `nextStratum` 将在前一层之后渲染所有元素。如果您想将元素分组到特定层中，可以使用此功能。注意：您无法导航到之前的层。

#### 比较器

比较器处理层中线性树内给定节点中的元素排序。

##### 屏幕矩形剪裁

`ScreenRectangle` 就是允许元素绘制的区域，通过 `GuiElementRenderState#scissorArea` 存储。没有指定 `ScreenRectangle` 的元素将首先排序，然后是最小 Y、最大 Y、最小 X 和最大 X。

##### 渲染管线

`RenderPipeline` 定义了用于将某些对象渲染到屏幕的管线，包括其着色器、格式、统一变量等。这通过 `GuiElementRenderState#pipeline` 存储。管线按照它们构建的顺序排序。这意味着，如果在同一层和剪裁矩形上，`RenderPipelines#ENTITY_TRANSLUCENT` 将在 `RenderPipelines#GUI` 之前渲染。由于这是一个依赖于类加载常量的系统，如果您想添加新元素，请确保您的模组加载器支持某种动态管线排序。

##### 纹理哈希码

`TextureSetup` 定义了在渲染管线中使用的 `Sampler0`、`Sampler1` 和 `Sampler2`，通过 `GuiElementRenderState#textureSetup` 存储。没有纹理的元素将首先排序，然后是记录对象的 `getSortKey`。注意，目前这返回 `TextureSetup` 的 `hashCode`，由于 `GpuTextureView` 不实现 `hashCode`，而是依赖于身份对象哈希，这可能是不确定的。

### GuiElementRenderState

现在我们理解了排序，我们一直在使用的 `GuiElementRenderState` 到底是什么？实际上，渲染到屏幕的每个对象都由一个 `GuiElementRenderState` 表示，从库存菜单中看到的玩家到每个单独的物品。一个 `GuiElementRenderState` 定义了四个方法。首先，是用于排序以及如何渲染到屏幕的常用方法（`pipeline`、`scissorArea`、`textureSetup`、`bounds`）。然后是 `buildVertices`，它接受 `VertexConsumer` 来写入顶点和 z 深度。对于 GUI，这通常调用 `VertexConsumer#addVertexWith2DPose`。

原版提供了三种类型的 `GuiElementRenderState`：`BlitRenderState`、`ColoredRectangleRenderState`、`GlyphEffectRenderState` 和 `GlyphRenderState`。`ColoredRectangleRenderState` 和 `GlyphRenderState`/`GlyphEffectRenderState` 分别是处理基本颜色矩形和文本字符的简单情况。`BlitRenderState` 覆盖所有其他情况，因为几乎所有方法最终都会写入一个 `GpuTexture`，然后由它消费。

`GuiElementRenderState` 通过 `GuiRenderState$Node#submitGuiElement` 添加到 `GuiRenderState`。`GuiRenderState` 使 `submitBlitToCurrentLayer` 和 `submitGlyphToCurrentLayer` 可用于添加纹理和字形。例如，这些由 `GuiGraphics#*line`、`fill` 和 `blit*` 方法调用。

#### GuiItemRenderState

`GuiItemRenderState` 是一个特殊情况，用于将物品渲染到屏幕。它接受物品的字符串化名称、当前姿势、其 XY 坐标及其剪裁区域。它持有的 `ItemStackRenderState` 定义了物品的渲染方式。当 `ClientItem$Properties#oversizedInGui` 为 true 时，渲染边界基于物品模型边界框计算；否则，当为 false 时，使用 16x16 的正方形。

就在“渲染”阶段之前，`GuiRenderer` 有效地将 `GuiItemRenderState` 转换为 `GuiElementRenderState`，更具体地说是 `BlitRenderState`。这是通过构造一个物品图集 `GpuTexture` 来完成的，物品被绘制到该纹理上，然后该纹理作为 `BlitRenderState` 提交。所有 `GuiItemRenderState` 都使用 `RenderPipelines#GUI_TEXTURED_PREMULTIPLIED_ALPHA`。

`GuiElementRenderState` 通过 `GuiRenderState#submitItem` 添加到 `GuiRenderState`。这由 `GuiGraphics#render*Item*` 方法调用。

#### GuiTextRenderState

`GuiTextRenderState` 是一个特殊情况，用于将文本渲染到屏幕。它接受 `Font`、`FormattedCharSequence`、当前姿势、其 XY 坐标、颜色、背景颜色、是否有阴影及其渲染边界。

就在“渲染”阶段之前，`GuiRenderer` 将 `GuiTextRenderState` 转换为 `GuiElementRenderState`，更具体地说是 `GlyphRenderState` 或 `GlyphEffectRenderState`，具体取决于通过 `GuiTextRenderState#ensurePrepared` 应渲染的内容。这执行与物品渲染状态类似的过程，其中文本被写入 `GpuTexture` 以供消费。任何背景首先被渲染，然后是背景效果，然后是字符，最后是前景效果。

`GuiElementRenderState` 通过 `GuiRenderState#submitText` 添加到 `GuiRenderState`。这由 `GuiGraphics#draw*String` 和 `render*Tooltip` 方法调用。

#### 画中画

画中画是一个特殊情况，用于将任意对象渲染到 `GpuTexture`，然后传递给 `BlitRenderState`。画中画由两个组件组成：`PictureInPictureRenderState` 和 `PictureInPictureRenderer`。

`PictureInPictureRenderState` 是一个接口，可以存储一些用于将对象渲染到纹理的数据。默认情况下，它必须提供最小和最大 XY 坐标、纹理缩放、其剪裁区域及其渲染边界。您还可以选择通过 `pose` 指定变换矩阵。任何其他数据都可以由实现者添加。

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

`PictureInPictureRenderer` 是将数据写入 `GpuTexture` 的渲染器。它利用这样一个事实：如果 `RenderSystem#output*Override` 纹理不为 null，则它们会被写入 `BufferSource`。一个 `PictureInPictureRenderer` 方法必须实现三个方法。`getRenderStateClass` 返回 `PictureInPictureRenderState` 实现的类。`getTextureLabel` 返回用于调试的纹理标签。`renderToTexture` 是调用渲染逻辑以将数据写入纹理的地方。

```java
public class ExamplePIPRenderer extends PictureInPictureRenderer<ExamplePIPRenderState> {

    // 接受来自 `RenderBuffers` 的缓冲区源
    public ExamplePIPRenderer(MultiBufferSource.BufferSource bufferSource) {
        super(bufferSource);
    }

    @Override
    public Class<ExamplePIPRenderState> getRenderStateClass() {
        // 渲染状态的类
        return ExamplePIPRenderState.class;
    }

    @Override
    protected void renderToTexture(ExamplePIPRenderState renderState, PoseStack pose) {
        // 在此处渲染您想要的任何内容
        // 您可以通过 `this.bufferSource` 使用缓冲区源
    }

    @Override
    protected void blitTexture(ExamplePIPRenderState renderState, GuiRenderState guiState) {
        // 如果您想更改图层提交到渲染状态的方式，可以覆盖此方法
        // 默认情况下，这使用 `BlitRenderState`

        // 如果您想自己处理提交，请删除此项
        super.blitTexture(renderState, guiState);
    }

    @Override
    protected boolean textureIsReadyToBlit(ExamplePIPRenderState renderState) {
        // 当为 true 时，将跳过设置纹理和投影矩阵，并使用当前可用的任何内容
        return false;
    }

    @Override
    protected String getTextureLabel() {
        // 这可以是任何内容，但应该是唯一的
        return "examplemod: example pip";
    }
}
```

要能够使用渲染器，必须将其添加到 `GuiRenderer#pictureInPictureRenderers`。由于构造函数接受一个不可变列表，而渲染器存储一个不可变映射，请使用您的模组加载器提供的任何方法。

```java
// 我们将假设：
// - `GuiRenderer#bufferSource` 是可访问的
// - 映射是可变的
// 对于某个 GuiRenderer renderer

var examplePIP = new ExamplePIPRenderer(renderer.bufferSource);

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

`PictureInPictureRenderState` 通过 `GuiRenderState#submitPicturesInPictureState` 添加到 `GuiRenderState`。这由 `GuiGraphics#submit*RenderState` 方法调用。

### 逻辑变更

`GuiGraphics#drawString` 现在允许 `int` 颜色参数接受 alpha 通道（高八位），从而与其他 `GuiGraphics` 方法保持一致。这意味着任何没有指定 alpha 的颜色字符串将不会被渲染。可以通过将您的 `int` 颜色与 `0xFF000000` 进行 OR 操作，或者将您的颜色传递给 `ARGB#opaque` 来复制以前的行为。

### 上下文栏

屏幕上的许多 HUD 元素会占据经验条渲染的位置。然而，这些元素如何渲染以及哪个元素被优先考虑是通过上下文栏系统处理的。一个上下文栏由两部分组成：`ContextualBarRenderer`，负责将栏渲染到屏幕；以及 `Gui$ContextualInfo`，用作栏的标识符。

一个 `ContextualBarRenderer` 需要实现两个方法：`renderBackground`，用于渲染栏本身；以及 `render`，用于渲染出现在栏顶部的元素。

```java
public class ExampleContextualBarRenderer implements ContextualBarRenderer {

    @Override
    public void renderBackground(GuiGraphics graphics, DeltaTracker delta) {
        // 在此处渲染背景栏精灵
    }

    @Override
    public void render(GuiGraphics graphics, DeltaTracker delta) {
        // 渲染任何可能位于栏顶部的元素
    }
}
```

`Gui$ContextInfo` 是一个枚举，因此您的模组加载器需要允许扩展或某种其他方法来标识栏渲染器。然后，需要将渲染器添加到存储在 `Gui#contextualInfoBarRenderers` 中的渲染器映射中。由于这是一个不可变映射，请使用您的模组加载器提供的任何方法。

```java
// 我们将假设：
// - 创建了一个新的枚举值 `EXAMPLEMOD_EXAMPLE`
// - 映射是可变的
// 对于某个 Gui gui
gui.contextualInfoBarRenderers.put(
    EXAMPLEMOD_EXAMPLE,
    ExampleContextualBarRenderer::new
);
```

最后，为了让您的栏被调用并优先考虑，您需要修改 `Gui#nextContextualInfoState` 以返回您的枚举值，或者使用您的模组加载器提供的任何方法。

### 对话框

为了更通用地处理提供某些基本功能的屏幕——例如确认屏幕、按钮选择或用户输入，原版提供了一个通用的对话框系统。这些对话框可以在数据包中构建，并通过调用 `Player#openDialog` 在客户端上传递。基本的 JSON 描述记录在 [Minecraft Snapshot 25w20a](https://www.minecraft.net/en-us/article/minecraft-snapshot-25w20a) 中。

快速概述，一个基本的 `Dialog` 包含以下组件：一个标题、一个可选的用于导航的外部标题、是否可以通过按“esc”关闭屏幕，以及它的 `DialogBody` 内容。其他所有内容由对话框本身决定，但它具有通过 `InputControl` 进行用户输入的功能。按钮通常通过 `ClickAction` 添加，它包含常见的按钮数据和点击时要执行的事件。如果对话框被取消（例如，关闭），则运行 `onCancel`。

`DialogBody` 和 `InputControl` 只是没有定义结构的通用接口。实现它们，或者任何对话框，都需要在客户端和服务器上向可用类型进行一些注册。

#### 自定义主体

一个 `DialogBody` 就是对话框屏幕的内容。这通常是应该始终显示的不可变信息。每个对话框都持有一个这些 `DialogBody` 的列表，因为每个屏幕都有一些文本来解释它的用途。它只包含一个方法 `mapCodec`，用作主体信息的注册表键和编码器。

```java
// 显然，一个主体会有实际内容，但这只是一个示例实现
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;
    }
}

// 将编解码器注册到注册表
Registry.register(BuiltInRegistries.DIALOG_BODY_TYPE, "examplemod:example_body", ExampleDialogBody.BODY_CODEC);
```

```json5
// 对于某个对话框
{
    // ...
    "body": [
        {
            // 我们的主体
            "type": "examplemod:example_body",
            "val1": true,
            "val2": 0
        },
        // ...
    ]
}
```

那么这个主体实际上是如何渲染的呢？这是通过 `DialogBodyHandler` 完成的。它包含一个单一方法 `createControls`，用于生成给定 `DialogScreen` 和对话框数据的 `LayoutElement` 进行渲染。这个主体处理程序可以通过 `DialogBodyHandlers#register` 链接到 `MapCodec`。

```java
public class ExampleDialogBodyHandler implements DialogBodyHandler<ExampleDialogBody> {

    @Override
    public LayoutElement createControls(DialogScreen<?> screen, ExampleDialogBody body) {
        // 创建元素（小部件、布局等）
        return new StringWidget(...);
    }
}

// 注意 `register` 不是公开的，因此需要访问扩宽
DialogBodyHandlers.register(BODY_CODEC, new ExampleDialogBodyHandler());
```

#### 自定义输入

一个 `InputControl` 表示用户可以提供的某些输入，无论是文本还是按钮提交点击。这通常由可以根据状态接受或提供某些字符串值或标签的组件组成。所有对话框都可以通过 `DialogControlSet` 提供这些输入。它只包含一个方法 `mapCodec`，用作输入控件的注册表键和编码器。

```java
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;
    }
}

// 将编解码器注册到注册表
Registry.register(BuiltInRegistries.INPUT_CONTROL_TYPE, "examplemod:example_input", ExampleInputControl.INPUT_CODEC);
```

```json5
// 对于某个对话框（假设 `minecraft:simple_input_form`）
{
    "inputs": [
        {
            // 我们的输入
            "type": "examplemod:example_input",
            
            // 此输入数据的标识符
            "key": "example_input",

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

与上面一样，输入通过 `InputControlHandler` 渲染。它包含一个单一方法 `addControl`，提供 `Screen` 和输入控件，并通过 `$Output` 创建 `LayoutElement` 及其关联的 `Action$ValueGetter`。这个输入处理程序可以通过 `InputControlHandlers#register` 链接到 `MapCodec`。

```java
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()));

        // 将元素添加到输出
        output.accept(
            // 要渲染的元素
            box,
            // 输入的值输出
            Action.ValueGetter.of(box::getValue)
        );
    }
}

// 注意 `register` 不是公开的，因此需要访问扩宽
InputControlHandlers.register(INPUT_CODEC, new ExampleInputControlHandler());
```

### 自定义动作

如上所示，输入可以提供一些值传递给 `Action`。前者被称为 `$ValueGetter`，它基本上获取一个字符串化或标记的输入以供使用。后者则最终创建发送到服务器的 `ClickEvent`。这些通常通过 `ActionButton` 创建，它定义了一些常见的按钮数据以及要执行的 `Action`。

一个自定义动作包含两个方法：一个返回在编码期间使用的 `MapCodec`（`codec`），另一个根据输入字符串到其 `$ValueGetter` 的映射创建 `ClickEvent`。

```java
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) {
        // 处理如何将键输入映射映射到某个点击事件
        return Optional.empty();
    }
}

// 将编解码器注册到注册表
Registry.register(BuiltInRegistries.DIALOG_ACTION_TYPE, "examplemod:example_action", ExampleAction.ACTION_CODEC);
```

```json5
// 对于某个对话框（假设 `minecraft:notice`）
{
    "action": {
        // 按钮数据
        "label": "示例！",
        "tooltip": "这是一个示例！",
        "width": 80,

        // 要执行的动作
        "action": {
            // 我们的动作类型
            "type": "examplemod:example_action"
        }
    }
}
```

根据您在下面实现 `Dialog` 的方式，动作按钮将自动添加到屏幕，或者您需要通过 `DialogControlSet#createActionButton` 在其中一个方法中添加它：

```java
// 对于某个 DialogScreen 实现，我们假设某个 `SimpleDialog`
@Override
protected void updateHeaderAndFooter(HeaderAndFooterLayout layout, DialogControlSet controls, SimpleDialog dialog, DialogConnectionAccess access) {
    dialog.mainActions().forEach(actionButton -> layout.addToFooter(controls.createActionButton(actionButton).build()));
}
```

#### 自定义对话框

一个 `Dialog` 基本上就是上述所有组件的组合，按需组合。由用户决定如何实现它们。每个 `Dialog` 必须提供其 `CommonDialogData`，它定义了基本标题、主体内容和功能。此外，一个 `Dialog` 可以选择在关闭时通过 `onCancel` 执行一个 `Action`。

```java
// `common` 已由记录实现
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() {
        // 您可以选择在此处返回一些内容，或者如果什么都不做则返回空
        return Optional.empty();
    }
}

// 将编解码器注册到注册表
Registry.register(BuiltInRegistries.DIALOG_TYPE, "examplemod:example_dialog", ExampleDialog.DIALOG_CODEC);
```

```json5
// 对于 `data/examplemod/dialog/example.json` 中的某个对话框
{
    // 我们的对话框类型
    "type": "examplemod:example_dialog",
    
    // 常见按钮数据
    "title": "示例对话框！",
    "can_close_with_escape": true,
    "after_action": "wait_for_response",

    // 我们的自定义参数
    "val1": true,
    "val2": 0
}
```

与其他一样，对话框类型只能通过 `DialogScreen$Factory` 渲染。这个接口构造一个 `DialogScreen`，给定父 `Screen`、`Dialog` 实例和用于与服务器通信的 `DialogConnectionAccess`。然后可以通过 `DialogScreens#register` 将这个对话框屏幕链接到 `MapCodec`。

```java
public class ExampleDialogScreen extends DialogScreen<ExampleDialog> {

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

    // 您可以根据需要选择实现其他方法
    // 有关示例，请参阅现有的对话框屏幕

    @Override
    protected void populateBodyElements(LinearLayout layout, DialogControlSet controls, ExampleDialog dialog, DialogConnectionAccess access) {
        // 将元素和动作添加到屏幕的主体（通常是中心）
    }

    @Override
    protected void updateHeaderAndFooter(HeaderAndFooterLayout layout, DialogControlSet controls, ExampleDialog dialog, DialogConnectionAccess access) {
        // 将元素和动作添加到屏幕的页眉和页脚（顶部和底部）
    }
}

// 注意 `register` 不是公开的，因此需要访问扩宽
DialogScreens.register(DIALOG_CODEC, ExampleDialogScreen::new);
```

- `com.mojang.blaze3d.vertex.VertexConsumer#addVertexWith2DPose` - 添加一个要在 2D 空间中渲染的顶点。
- `net.minecraft.client.gui`
    - `Font`
        - `drawInBatch` 不再返回任何内容
        - `prepareText` - 准备要渲染到屏幕的文本。
        - `splitIgnoringLanguage` - 按提供的顺序拆分文本，而不经过语言处理程序处理。
        - `ALPHA_CUTOFF` 已移除
        - `$GlyphVisitor` - 一个处理要渲染的字形或效果的接口。
        - `$PreparedText` - 一个接口，通过访问每个字形来定义应如何渲染一段文本。
        - `$StringRenderOutput` -> `$PreparedTextBuilder`，不再接受 `MultiBufferSource`、`Matrix4f`、`$DisplayMode`、打包的光照坐标和逆深度布尔值
    - `Gui`
        - `shouldRenderDebugCrosshair` - 如果应渲染调试准星，则返回 true。
        - `$RenderFunction` - 一个接口，定义如何在 GUI 上渲染某个部分或元素。
    - `GuiGraphics` 现在接受一个 `GuiRenderState` 而不是 `MultiBufferSource$BufferSource`
        - `MAX_GUI_Z`、`MIN_GUI_Z` 已移除
        - `pose` 现在返回一个 `Matrix3x2fStack`
        - `flush` 已移除
        - `nextStratum` - 添加另一个层，用于遍历在先前树中的所有节点之后渲染。
        - 所有方法不再接受 `RenderType`、`VertexConsumer` 或 `Function<ResourceLocation, RenderType>`，而是根据调用指定 `RenderPipeline` 和 `TextureSetup`
        - `drawString`、`drawStringWithBackdrop` 不再返回任何内容
        - `draw*String` 方法现在必须传入一个 ARGB 值，其中 A 不能为 0。
        - `renderItem(ItemStack, int, int, int, int)` 已移除
        - `drawSpecial` 已移除，根据特殊情况由单独的 `submit*RenderState` 取代
        - `blurBeforeThisStratum` - 通知渲染状态，模糊效果应在该层和所有先前渲染的层之间渲染。每帧只能应用一次。
        - `render*Tooltip` -> `set*TooltipForNextFrame`，不直接添加到渲染状态，而是在不存在或被覆盖时等待调用 `renderDeferredTooltip`
        - `renderDeferredTooltip` - 添加要在新层上渲染的工具提示信息。
        - `blitSprite` 现在有一个接受浮点 R 色调颜色的重载
        - `$ScissorStack#peek` - 获取堆栈上的最后一个矩形。
    - `LayeredDraw` 类已移除
- `net.minecraft.client.gui.components`
    - `AbstractTextAreaWidget` 现在有一个重载，接受两个额外的布尔值，表示是否显示背景或装饰
    - `AbstractWidget#getTooltip` 已移除
    - `CycleButton$Builder#displayOnlyValue` 现在有一个接受 `boolean` 设置的重载
    - `EditBox`
        - `setCentered` - 设置文本位置是否应居中。
        - `setTextShadow` - 设置文本是否应有阴影效果。
    - `FocusableTextWidget` 现在可以接受一个布尔值，表示是否填充背景
        - `DEFAULT_PADDING` 现在是公开的
    - `ImageWidget#updateResource` - 更新组件上图像的精灵。
    - `ItemDisplayWidget` - 一个显示 `ItemStack` 的小部件。
    - `LogoRenderer#keepLogoThroughFade` - 当为 true 时，即使标题屏幕淡出，也保持徽标可见。
    - `MultiLineEditBox` 现在是包私有的，应通过 `builder` 构造，调用 `$Builder#set*` 方法
        - `setLineLimit` - 设置文本字段的行限制。
        - `setValue` 现在有一个接受 `boolean` 的重载，用于确定是否应强制通过最大行限制
    - `MultiLineLabel`
        - `getStyleAtCentered` - 计算居中文本的组件样式。
        - `getStyleAtLeftAligned` - 计算左对齐文本的组件样式。
    - `MultilineTextField#NO_CHARACTER_LIMIT` -> `NO_LIMIT`
        - `setLineLimit` - 设置文本字段上可以写入的最大行数。
        - `hasLineLimit` - 返回文本字段是否有行限制。
        - `setValue` 现在有一个接受 `boolean` 的重载，用于确定是否应强制通过最大行限制
    - `MultiLineTextWidget#configureStyleHandling` - 设置在悬停组件时是否显示某些内容以及点击时的操作。
    - `ScrollableLayout` - 一个具有某些定义边界并且可以滚动的布局。
    - `SplashRenderer#render` 现在接受一个浮点数作为 R 颜色，而不是 int
    - `WidgetTooltipHolder#refreshTooltipForNextRenderPass` 现在接受 `GuiGraphics` 和 XY 位置
- `net.minecraft.client.gui.components.spectator.SpectatorGui#renderTooltip` -> `renderAction`
- `net.minecraft.client.gui.components.tabs`
    - `LoadingTab` - 一个表示当前正在加载信息的标签页。
    - `Tab#getTabExtraNarration` - 返回标签页的提示旁白。
    - `TabManager` 现在可以接受两个 `Consumer`，用于在选中或取消选中标签页时执行的操作
    - `TabNavigationBar`
        - `getTabs` - 返回导航栏上的标签页列表。
        - `setTabActiveState` - 设置给定标签页索引的活动状态。
        - `setTabTooltip` - 设置给定标签页索引的工具提示信息。
- `net.minecraft.client.gui.components.toasts`
    - `NowPlayingToast` - 一个显示当前正在播放的背景音乐的吐司。
    - `Toast`
        - `xPos`、`yPos` - 获取相对于当前吐司索引的 x 和 y 位置。
        - `onFinishedRendering` - 吐司在屏幕上完成渲染后调用的方法。
    - `ToastManager` 现在接受 `Options`
        - `showNowPlayingToast`、`hideNowPlayingToast`、`createNowPlayingToast`、`removeNowPlayingToast` - 处理“正在播放”音乐吐司。
        - `$ToastInstance#resetToast` - 重置吐司。
- `net.minecraft.client.gui.contextualbar`
    - `ContextualBarRenderer` - 一个接口，定义了一个具有某些要渲染的背景的对象。
    - `ExperienceBarRenderer` - 绘制经验条。
    - `JumpableVehicleBarRenderer` - 绘制跳跃力量条（例如，马跳跃）。
    - `LocatorBarRenderer` - 绘制指向给定路径点的条。
- `net.minecraft.client.gui.font.GlyphRenderTypes` 现在接受一个用于 GUI 渲染的 `RenderPipeline`
- `net.minecraft.client.gui.font.glyphs.BakedGlyph` 现在接受一个 `GpuTextureView`
    - `extractEffect` - 提取一个字形效果（例如阴影）并提交要渲染的元素。
    - `extractBackground` - 提取一个字形效果并提交要在背景 Z 上渲染的元素。
    - `left`、`top`、`right`、`bottom` - 计算字形的边界。
    - `textureView` - 返回构成字形的纹理视图。
    - `guiPipeline` - 返回渲染字形的管线。
    - `renderChar`、`renderEffect` 现在接受一个额外的布尔值，当为 true 时将 Z 偏移设置为 `0`，为 false 时设置为 `0.001`
    - `$Effect#left`、`top`、`right`、`bottom` - 计算字形效果的边界。
    - `$GlyphInstance#left`、`top`、`right`、`bottom` - 计算字形实例的边界。
- `net.minecraft.client.gui.navigation.ScreenRectangle`
    - `transformAxisAligned` 现在接受 `Matrix3x2f` 而不是 `Matrix4f`
    - `intersects` - 返回此矩形是否与另一个矩形重叠。
    - `encompasses` - 返回此矩形是否完全包含另一个矩形。
    - `transformMaxBounds` - 返回一个新矩形，该矩形通过提供的矩阵移动到给定位置。
- `net.minecraft.client.gui.render`
    - `GuiRenderer` - 一个将所有提交的元素渲染到屏幕的类。
    - `TextureSetup` - 一个记录，指定在渲染管线中使用的采样器 0-2。前两个纹理视图是任意的，第三个用于当前的光照图纹理。
- `net.minecraft.client.gui.render.pip`
    - `GuiBannerResultRenderer` - 旗帜结果预览的渲染器。
    - `GuiBookModelRenderer` - 附魔屏幕中书模型的渲染器。
    - `GuiEntityRenderer` - 给定实体的渲染器。
    - `GuiProfilerChartRenderer` - 分析器图表的渲染器。
    - `GuiSignRenderer` - 编辑屏幕中告示牌背景的渲染器。
    - `GuiSkinRenderer` - 具有给定皮肤的玩家的渲染器。
    - `OversizedItemRenderer` - 用于物品模型应渲染得比其物品槽位大时的渲染器。
    - `PictureInPictureRenderer` - 一个抽象类，用于渲染非标准 2D 元素、物品或文本的动态元素。
- `net.minecraft.client.gui.render.state`
    - `BlitRenderState` - 用于基本 2D 纹理 blit 的元素状态。
    - `ColoredRectangleRenderState` - 用于带有色调的简单矩形的元素状态。
    - `GlyphEffectRenderState` - 用于字形效果（例如，字体文本阴影）的元素状态。
    - `GlyphRenderState` - 用于字形（字体文本）的元素状态。
    - `GuiElementRenderState` - 一个表示要渲染的元素状态的接口。
    - `GuiItemRenderState` - 一个表示要渲染的物品状态的记录。
    - `GuiRenderState` - 要渲染到屏幕的 GUI 的状态。
    - `GuiTextRenderState` - 一个表示文本及其渲染位置的记录。
    - `ScreenArea` - 一个定义元素渲染区域的接口。这不会影响剪裁，而是影响层顺序。
- `net.minecraft.client.gui.render.state.pip`
    - `GuiBannerResultRenderState` - 旗帜结果预览的状态。
    - `GuiBookModelRenderState` - 附魔屏幕中书模型的状态。
    - `GuiEntityRenderState` - 给定实体的状态。
    - `GuiProfilerChartRenderState` - 分析器图表的状态。
    - `GuiSignRenderState` - 编辑屏幕中告示牌背景的状态。
    - `GuiSkinRenderState` - 具有给定皮肤的玩家的状态。
    - `OversizedItemRenderState` - 可以以任意大小渲染的物品模型的状态。
    - `PictureInPictureRenderState` - 一个定义将画中画渲染到屏幕所需基本状态的接口。
- `net.minecraft.client.gui.screens`
    - `ConfirmScreen`
        - `layout` - 定义一个由八个单位间隔的垂直元素列表。
        - `yesButton`、`noButton` -> `yesButtonComponent`、`noButtonComponent`
            - `yesButton`、`noButton` 现在表示实际的按钮
        - `addAdditionalText` - 在布局中的按钮之前添加任何附加文本。
        - `addButtons` - 在布局中添加按钮。
    - `PauseScreen`
        - `rendersNowPlayingToast` - 返回是否应渲染“正在播放”吐司。
        - `onDisconnect` -> `disconnectFromWorld`，现在是公开和静态的；不是一对一
    - `Screen`
        - `CUBE_MAP` -> `net.minecraft.client.renderer.GameRenderer#cubeMap`
        - `PANORAMA` -> `net.minecraft.client.renderer.GameRenderer#panorama`
        - `renderBlurredBackground` 现在接受 `GuiGraphics`
        - `*TooltipForNextRenderPass` 方法要么已移除，要么移至 `GuiGraphics`
        - `FADE_IN_TIME` - 表示某个元素淡入需要多少毫秒。
        - `fadeWidgets` - 设置作为屏幕子级添加的 `AbstractWidget` 的 alpha 值。
        - `handleClickEvent` - 处理点击组件时要播放的事件。
        - `defaultHandleClickEvent` - 点击组件时要执行的默认逻辑。
        - `clickUrlAction` - 点击 URL 时要执行的逻辑（具有打开 URL 样式）。
        - `clickCommandAction` - 应执行命令时要执行的逻辑（具有 * 命令样式）。
- `net.minecraft.client.gui.screens.dialog`
    - `ButtonListDialogScreen` - 一个包含一些按钮列表的对话框屏幕。
    - `DialogConnectionAccess` - 一个处理来自对话框的通用交互信息的客户端接口。
    - `DialogControlSet` - 对话框屏幕的输入处理程序。
    - `DialogListDialogScreen` - 一个指向其他对话框的按钮列表的 `DialogListDialog`。
    - `DialogScreen` - 某个对话框模态的屏幕。
    - `DialogScreens` - 对话框模态到其关联屏幕的工厂注册表。
    - `MultiButtonDialogScreen` - 一个 `MultiActionDialog` 的按钮列表。
    - `ServerLinksDialogScreen` - 一个 `ServerLinksDialog` 的按钮列表。
    - `SimpleDialogScreen` - 某个简单对话框的对话框屏幕。
    - `WaitingForResponseScreen` - 处理客户端/服务器之间对话框提交的停机时间的屏幕。
- `net.minecraft.client.gui.screens.dialog.body`
    - `DialogBodyHandler` - 描述标题和动作/输入之间内容的主体元素列表。
    - `DialogBodyHandlers` - `DialogBody` 到其 `DialogBodyHandler` 的注册表。
- `net.minecraft.client.gui.screens.dialog.input`
    - `InputControlHandler` - 用户输入处理程序。
    - `InputControlHandlers`- `InputControl` 到其 `InputControlHandler` 的注册表。
- `net.minecraft.client.gui.screens.inventory`
    - `AbstractContainerScreen`
        - `SLOT_ITEM_BLIT_OFFSET` 已移除
        - `renderContents` - 渲染库存的槽位和标签。
        - `renderCarriedItem` - 渲染持有的物品。
        - `renderSnapbackItem` - 渲染与持有物品交换的物品。
        - `$SnapbackData` - 保存关于拖拽或交换物品从持有位置移动到其槽位位置的信息。
    - `AbstractSignEditScreen#offsetSign` -> `getSignYOffset`，不是一对一
    - `BookEditScreen`
        - `TEXT_*`、`IMAGE_*`、`BACKGROUND_TEXTURE_*` 现在是公开的
    - `BookSignScreen` - 用于签署书的屏幕。
    - `BookViewScreen`
        - `closeScreen` -> `closeContainerOnServer`，不是一对一
        - `$BookAccess#getPage` 现在返回一个 `Component`
    - `EffectsInInventory`
        - `renderEffects` 现在是公开的
        - `renderTooltip` 已被重载为一个公共方法
    - `InventoryScreen#renderEntityInInventory` 不再接受 XY 偏移，而是接受 4 个 `int` 来表示要渲染到的区域
    - `ItemCombinerScreen#renderFg` 已移除
- `net.minecraft.client.gui.screens.inventory.tooltip`
    - `ClientTooltipComponent#renderText` 不再接受姿势和缓冲区，而是接受 `GuiGraphics` 来提交要渲染的文本
    - `TooltipRenderUtil#renderTooltipBackground` 不再接受 Z 偏移
- `net.minecraft.client.gui.screens.multiplayer.ServerLinksScreen` 类已移除，被对话框模态取代
- `net.minecraft.client.gui.screens.social`
    - `PlayerEntry#refreshHasDraftReport` - 设置当前上下文是否具有针对此玩家的报告。
    - `SocialInteractionsPlayerList#refreshHasDraftReport` - 刷新当前上下文是否对所有玩家有报告。
- `net.minecraft.client.gui.screens.worldselection.ExperimentsScreen$ScrollArea` 类已移除，被 `ScrollableLayout` 取代
- `net.minecraft.client.model.geom.ModelPart#getExtentsForGui` - 获取表示已变换到适当空间的部件的向量集。
- `net.minecraft.client.multiplayer.ClientCommonPacketListenerImpl`
    - `showDialog` - 显示当前对话框，动态创建屏幕。
    - `serverLinks` - 返回客户端可以访问的服务器链接条目。
    - `createDialogAccess` - 创建用于通信的客户端对话框处理程序。
    - `clearDialog` - 关闭当前对话框屏幕。
- `net.minecraft.client.player.LocalPlayer#experienceDisplayStartTick` - 表示经验显示应被优先考虑的开始刻。
- `net.minecraft.client.renderer`
    - `GameRenderer` 不再接受 `ResourceManager`
        - `ITEM_ACTIVATION_ANIMATION_LENGTH` 已移除
        - `setRenderHand` 已移除
        - `renderZoomed` 已移除
        - `getPanorama` - 返回全景渲染器。
    - `LightTexture#getTexture` -> `getTextureView`，不是一对一
    - `MapRenderer#WIDTH`、`HEIGHT` 现在是公开的
    - `PanoramaRenderer#registerTextures` - 注册纹理以供立方体贴图使用。
    - `PostPass$Input#texture` 现在返回 `GpuTextureView` 而不是 `GpuTexture`
    - `RenderPipelines`
        - `GUI_OVERLAY`、`GUI_GHOST_RECIPE_OVERLAY`、`GUI_TEXTURED_OVERLAY` 已移除
        - `GUI_TEXTURED_PREMULTIPLIED_ALPHA` - 一个假设纹理在合成阶段已经预乘了透明度的管线。
    - `RenderStateShard`
        - `$Builder#add` 不再接受是否应模糊着色器
        - `$TextureStateShard` 不再接受设置模糊模式的 `TriState`
    - `RenderType`
        - `debugLine` 已移除
        - `gui`、`guiOverlay`、`guiTexturedOverlay`、`guiOpaqueTexturedBackground`、`guiNauseaOverlay`、`guiTextHighlight`、`guiGhostRecipeOverlay`、`guiTextured` 已移除
        - `vignette` 已移除
        - `crosshair` 已移除
        - `mojangLogo` 已移除
    - `ScreenEffectRenderer` 现在是一个实例实现，而不是仅仅一个静态方法
        - 构造函数接受当前的 `Minecraft` 实例和一个 `MultiBufferSource`
        - `renderScreenEffect` 现在是一个实例方法，接受实体是否在睡觉以及部分刻
        - `resetItemActivation`、`displayItemActivation` - 处理物品自动激活时的情况（例如，图腾）。
- `net.minecraft.client.renderer.blockentity`
    - `*Renderer#getExtents` - 将所有模型表示的变换后的向量添加到一个集合中。
    - `HangingSignRenderer`
        - `MODEL_RENDER_SCALE` 现在是公开的
        - `translateBase` 现在是公开的
    - `SignRenderer`
        - `RENDER_SCALE` 现在是公开的
        - `applyInHandTransforms` - 变换堆栈以正确表示所持告示牌的位置。
    - `SkullBlockRenderer#getRenderType(SkullBlock$Type, ResolvableProfile, ResourceLocation)` -> `getSkullRenderType`、`getPlayerSkinRenderType`；不是一对一
- `net.minecraft.client.renderer.entity.ItemRenderer`
    - `GUI_SLOT_CENTER_X`、`GUI_SLOT_CENTER_Y`、`ITEM_DECORATION_BLIT_OFFSET` 已移除
    - `COMPASS_*` -> `SPECIAL_*`
- `net.minecraft.client.renderer.item`
    - `ClientItem$Properties#oversizedInGui` - 当为 true 时，允许物品在 GUI 中渲染到 16x16 框之外；否则，将大小裁剪到框内。
    - `ItemStackRenderState`
        - `setAnimated`、`isAnimated` - 返回物品是否有动画（例如，闪光）。
        - `appendModelIdentityElement`、`getModelIdentity`、`clearModelIdentity` - 处理正在渲染的标识组件。
        - `getModelBoundingBox` - 计算模型的边界框。
        - `setOversizedInGui`、`isOversizedInGui` - 处理物品何时可以根据其属性在 GUI 中过大。
- `net.minecraft.client.renderer.special`
    - `PlayerHeadSpecialRenderer` - 根据其渲染信息渲染玩家头颅。
    - `SkullSpecialRenderer` 现在实现 `NoDataSpecialModelRenderer`，不再接受模型或纹理覆盖，而是接受要使用的 `RenderType`
    - `SpecialModelRenderer#getExtents` - 将表示此渲染器使用的所有模型的变换向量添加到一个集合中。
- `net.minecraft.client.renderer.texture.TextureAtlasSprite#isAnimated` - 返回精灵是否有任何动画。
- `net.minecraft.commands.arguments.ResourceOrIdArgument#dialog`、`getDialog`、`$DialogArgument` - 处理对话框屏幕的命令参数。
- `net.minecraft.core.registries`
    - `BuiltInRegistries#DIALOG_TYPE`、`DIALOG_ACTION_TYPE`、`INPUT_CONTROL_TYPE`、`DIALOG_BODY_TYPE`
    - `Registries#DIALOG_TYPE`、`DIALOG_ACTION_TYPE`、`INPUT_CONTROL_TYPE`、`DIALOG_BODY_TYPE`、`DIALOG`
- `net.minecraft.data.tags.DialogTagsProvider` - 对话框的标签提供者。
- `net.minecraft.network.chat`
    - `ClientEvent`
        - `$Action#SHOW_DIALOG`、`CUSTOM`
            - `valueCodec` - 返回用于编码此动作的映射编解码器。
        - `$Custom` - 一个包含一些要发送到服务器的 nbt 有效负载的事件，目前什么都不做。
        - `$ShowDialog` - 一个显示指定对话框的事件。
    - `CommonComponents`
        - `GUI_RETURN_TO_MENU` - 显示“返回菜单”文本的组件。
        - `disconnectButtonLabel` - 根据服务器是否是本地服务器返回组件。
- `net.minecraft.network.protocol.common`
    - `ClientboundClearDialogPacket` - 关闭当前对话框屏幕。
    - `ClientboundShowDialogPacket` - 打开一个新的对话框屏幕。
    - `ServerboundCustomClickActionPacket` - 向服务器发送一个自定义动作。
- `net.minecraft.server.dialog`
    - `ActionButton` - 一个可以在点击时执行某些 `Action` 的按钮。
    - `ButtonListDialog` - 一个具有若干列可点击按钮的对话框模态。
    - `CommonButtonData` - 与对话框模态中每个按钮关联的数据。
    - `CommonDialogData` - 与每个对话框模态关联的数据。
    - `ConfirmationDialog` - 一个可以选择是或否的对话框模态。
    - `Dialog` - 定义某个对话框模态的基础接口。
    - `DialogAction` - 通常在点击某个动作按钮后执行的动作。
    - `DialogListDialog` - 一个指向其他对话框的按钮的可滚动列表。
    - `Dialogs` - 一个注册 `Dialog` 的数据包引导程序。
    - `DialogTypes` - 用于编码某个对话框模型的映射编解码器注册表。
    - `Input` - 一个将某个键映射到 `InputControl` 的处理程序。
    - `MultiActionDialog` - 一个按列排列的动作的可滚动列表。
    - `NoticeDialog` - 一个在页脚中只有一个动作的简单屏幕。
    - `ServerLinksDialog` - 一个从服务器接收的链接的可滚动列表，按列排列。
    - `SimpleDialog` - 一个定义可以采取的主要动作的对话框。
- `net.minecraft.server.dialog.action`
    - `Action` - 对某些输入执行的通用操作，通常是按钮点击。
    - `ActionTypes` - 用于编码某个动作的映射编解码器注册表。
    - `CustomTemplate` - 构建一个命令并请求服务器运行它。
    - `CustomAll` - 从所有输入构建一个自定义服务器点击动作，并请求服务器运行它。
    - `ParsedTemplate` - 一个编码某些字符串的模板，类似于函数宏的工作方式。
    - `StaticAction` - 一个在激活时触发 `ClickEvent` 的动作。
- `net.minecraft.server.dialog.body`
    - `DialogBody` - 描述标题和动作/输入之间内容的主体元素。
    - `DialogBodyTypes` - 用于编码某个主体的映射编解码器注册表。
    - `ItemBody` - 一个带有可选描述的物品。
    - `PlainMessage` - 一个多行标签。
- `net.minecraft.server.dialog.input`
    - `BooleanInput` - 一个带有标签的普通复选框。
    - `InputControl` - 一个接受用户输入的控制机制。
    - `InputControlTypes` - 用于编码某个输入控件的映射编解码器注册表。
    - `NumberRangeInput` - 一个用于从某个范围内选择数值的滑块。
    - `SingleOptionInput` - 一个在一组选项之间循环的按钮。
    - `TextInput` - 简单的文本输入。
- `net.minecraft.world.entity.player.Player#openDialog` - 打开指定的对话框屏幕。

## 路径点

路径点只是一种跟踪游戏中某些对象位置的方法。底层系统由 `WaypointManager` 处理，负责保存它正在跟踪的路径点，同时允许根据需要更新和移除。服务器通过 `ServerWaypointManager`（通过 `ServerLevel#getWaypointManager` 获得）处理路径点，它持有一个到发射器的活动连接以接收实时更新。客户端通过 `ClientWaypointManager`（通过 `ClientPacketListener#getWaypointManager` 获得）接收这些路径点，它仅保存某些标识符以及精确位置、如果位置不在视野距离内的区块，或者如果距离大于存储的 `Waypoint$Fade#farDist`（默认超过 332 个方块）则保存一个角度。

实体默认跟踪路径点。

### 样式和图标

每个路径点都由某种图标表示，由其 `WaypointStyle` 和图标的颜色定义。`WaypointStyle` 类似于客户端物品或装备模型，它具有一个由 `WaypointStyleAsset` 指向的键，位于 `assets/<modid>/waypoint_style/<path>.json` 中。这包含一个位于 `assets/<modid>/textures/gui/sprites/hud/locator_bar_dot/<path>.png` 中的精灵列表，根据与跟踪器的距离选择。精灵在由近和远距离指定的范围内变化。

```json5
// 对于某个样式 examplemod:example_style
// 它将在 `assets/examplemod/waypoint_style/example_style.json` 中找到
{
    // 表示任何更近的值将在渲染条时使用第一个精灵
    // 未指定时默认为 128
    "near_distance": 100,
    // 表示任何更远的值将在渲染条时使用最后一个精灵
    // 未指定时默认为 332
    // 必须大于近距离
    "far_distance": 400,
    // 一个相对于 `assets/<modid>/textures/gui/sprites/hud/locator_bar_dot/<path>.png` 的非空纹理列表
    // 这是用于在两个距离之间进行插值的内容
    "sprites": [
        // 指向 `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"
    ]
}
```

然后可以使用其构造函数构造图标，并通过服务器上的 `WaypointTransmitter#waypointIcon` 或客户端上的 `TrackedWaypoint#icon` 引用。

```java
// 我们将假设此构造函数被公开以用于更动态的用法
// 目前，它只能通过其 `CompoundTag` 在 `LivingEntity` 上通过 `locator_bar_icon` 设置
public static Waypoint.Icon EXAMPLE_ICON = new Waypoint.Icon(
    // 路径点样式的注册表键
    // 指向 `assets/examplemod/waypoint_style/example_style.json`
    ResourceKey.create(WaypointStyleAssets.ROOT_ID, ResourceLocation.fromNamespaceAndPath("examplemod", "example_style")),
    // 路径点的颜色
    // 当不存在时，使用路径点标识符的哈希码
    Optional.of(0xFFFFFF)
);
```

### 连接

当跟踪路径点时，它们通过 `WaypointTransmitter$Connection` 进行管理。一个连接负责将信息同步到客户端，无论是连接、断开连接还是更新。

```java
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() {
        // 当为 true 时，它将尝试重新建立到此发射器的连接
        // 仅在更新位置时调用
        return ExampleBlockConnection.doesSourceIgnoreReceiver(this.pos, this.receiver);
    }

    @Override
    public void connect() {
        // 这会将跟踪数据包发送到客户端
        this.receiver.connection.send(ClientboundTrackedWaypointPacket.addWaypointPosition(this.state.toString() + ": " + this.pos.toString(), this.icon, this.pos));
    }

    @Override
    public void disconnect() {
        // 这会将移除数据包发送到客户端
        this.receiver.connection.send(ClientboundTrackedWaypointPacket.removeWaypoint(this.state.toString() + ": " + this.pos.toString()));
    }

    @Override
    public void update() {
        // 这会在客户端上更新跟踪值，假设连接没有中断
        // 在我们的例子中，我们可以假设这永远不会改变，因为方块的位置应该是一致的
    }
}
```

### 发射器

一个 `WaypointTransmitter` 负责在其和服务器之间建立连接。为了让您的对象传输位置，它必须实现 `WaypointTransmitter` 及其三个方法。`waypointIcon` 仅返回要显示的图标。`isTransmittingWaypoint` 将确定是否可以从该对象传输路径点。`makeWaypointConnectionWith` 实际处理用于跟踪连接的位置或角度的连接的构造。

```java
public class ExampleWaypointBlock extends BlockEntity implements WaypointTransmitter {

    // ...

    @Override
    public boolean isTransmittingWaypoint() {
        // 如果不应该建立连接，则应返回 false
        return true;
    }

    @Override
    public Optional<WaypointTransmitter.Connection> makeWaypointConnectionWith(ServerPlayer player) {
        // 如果没有被忽略，则创建一个连接
        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;
    }
}
```

然后，您需要做的就是根据需要跟踪、更新或取消跟踪发射器。这可以使用 `ServerWaypointManager` 提供的方法来完成：

```java
// 我们将假设我们可以访问：
// - ServerLevel serverLevel
// - ExampleWaypointBlock be

// 跟踪路径点，例如在某个初始化时
serverLevel.getWaypointManager().trackWaypoint(be);

// 如果位置改变，更新路径点
serverLevel.getWaypointManager().updateWaypoint(be);

// 一旦路径点不再存在，将其移除
serverLevel.getWaypointManager().untrackWaypoint(be);
```

- `net.minecraft.client`
    - `Camera` 现在实现 `TrackedWaypoint$Camera`
    - `Minecraft#getWaypointStyles` - 返回一个键到路径点样式的管理器。
- `net.minecraft.client.data.models.WaypointStyleProvider` - 一个生成路径点样式的数据提供者。
- `net.minecraft.client.multiplayer.ClientPacketListener#getWaypointManager` - 获取用于跟踪路径点的客户端管理器。
- `net.minecraft.client.renderer.GameRenderer` 现在实现 `TrackedWaypoint$Projector`
- `net.minecraft.client.resources`
    - `WaypointStyle` - 定义用于渲染路径点的样式。
    - `WaypointStyleManager` - 将某个键映射到路径点样式的管理器。
- `net.minecraft.client.waypoints.ClientWaypointManager` - 用于跟踪路径点的客户端管理器。
- `net.minecraft.commands.arguments.WaypointArgument` - 一个静态方法持有者，用于从实体获取某个路径点发射器。
- `net.minecraft.network.protocol.game`
    - `ClientboundTrackedWaypointPacket` - 一个向客户端发送某个路径点操作的数据包。
    - `ClientGamePacketListener#handleWaypoint` - 在客户端上处理路径点数据包。
- `net.minecraft.server.ServerScoreboard$Method` 枚举已移除
- `net.minecraft.server.level.ServerLevel#getWaypointManager` - 获取用于跟踪路径点的服务器管理器。
- `net.minecraft.server.level.ServerPlayer#isReceivingWaypoints` - 玩家是否从其他位置或实体接收路径点。
- `net.minecraft.server.waypoints.ServerWaypointManager` - 用于跟踪路径点（例如，玩家和发射器）的服务器端管理器。
- `net.minecraft.world.entity`
    - `Entity#getRequiresPrecisePosition`、`setRequiresPrecisePosition` - 处理何时需要更精确的位置进行跟踪。
    - `LivingEntity` 现在实现 `WaypointTransmitter`
- `net.minecraft.world.waypoints`
    - `TrackedWaypoint` - 一个由某个 UUID 或字符串标识、通过 `Waypoint$Icon` 显示并由 `$Type` 指定的路径点。
    - `TrackedWaypointManager` - 一个用于 `TrackedWaypoint` 的路径点管理器。
    - `Waypoint` - 一个表示某个位置位置的接口。它不保存任何信息，通常在 `TrackedWaypoint` 的上下文中使用。
    - `WaypointManager` - 一个跟踪和更新路径点的接口。
    - `WaypointStyleAsset` - 一个表示样式资源的类。
    - `WaypointStyleAssets` - 一个定义所有原版样式资源的类。
    - `WaypointTransmitter` - 一个传输某个可以连接和跟踪的位置的对象。

## Blaze3d 变更

就像上一次更新一样，Blaze3d 有新的重新设计，改变了渲染的处理方式。

### 缓冲区切片

渲染系统中最重要的是使用 `GpuBufferSlice`。顾名思义，它只是获取 `GpuBuffer` 的某个切片，使用 `offset` 指示起始索引，`length` 指示其大小。在处理任何与渲染相关的事情时，即使传递给着色器，您几乎总是会处理 `GpuBufferSlice`。可以这样理解：缓冲区只是某个对象的任意列表，而切片代表一个特定的对象。

要创建一个切片，只需调用 `GpuBuffer#slice`，可选择提供起始索引和长度。在大多数情况下，您不会直接调用此方法，而是处理为您调用它的其他方法。请注意，由于您通常将数据写入这些切片，它们应该在创建 try-with-resources `RenderPass` 之前构建。

### 统一变量重做

统一变量系统已被完全改造，以至于除非您熟悉特定功能，否则它可能看起来完全陌生。简而言之，统一变量现在存储为接口对象、纹素缓冲区或采样器。这些由 `GpuBuffer` 或 `GpuBufferSlice` 填充。

#### 统一变量类型

一个统一变量目前表示为两种 `UniformType` 之一：`UNIFORM_BUFFER`/接口块，或 `TEXEL_BUFFER`。在设置管道并调用 `withUniform` 时，您必须使用上述类型之一指定您的统一变量。如果您选择使用纹素缓冲区，还必须指定纹理数据的格式。采样器没有变化。

```java
public static final RenderPipeline EXAMPLE_PIPELINE = RenderPipeline.builder(...)
    // 使用名为 'ExampleUniform' 的统一接口块
    .withUniform("ExampleUniform", UniformType.UNIFORM_BUFFER)
    // 使用名为 'ExampleTexel' 的缓冲区，将纹理数据存储为 8 位 R 值
    .withUniform("ExampleTexel", UniformType.TEXEL_BUFFER, TextureFormat.RED8I)
    // 执行其他设置
    .build();
```

#### 接口块

一个 `UNIFORM_BUFFER` 存储为一个 `std140` 接口块。在 GLSL 中，它表示如下：

```glsl
// 在 assets/examplemod/shaders/core/example_shader.json

// ExampleUniform 是块的名称
layout(std140) uniform ExampleUniform {
    // 块内的数据
    // 后处理效果只能使用 int, float, vec2, vec3, ivec3, vec4, 或 mat4
    vec4 Param1;
    float Param2;
};
```

可以在主块内自由使用这些值，如下所示：

```glsl
// 在 assets/examplemod/shaders/core/example_shader.json

out vec4 fragColor;

void main() {
    fragColor = Param1;
}
```

统一块可以位于与主函数相同的文件中，或者如果将被重用，可以作为 `moj_import`，其中统一文件位于 `assets/<modid>/shaders/include/<path>` 内。请注意，在资源包加载之前使用的任何着色器都不能使用 `moj_import`。

后处理效果在 `uniform` 输入中定义其接口块：

```json5
// 在 assets/examplemod/post_effect/example_post_effect.json
// 在 'passes' 对象内部
{
    "vertex_shader": "...",
    // ...
    "uniforms": {
        // 接口块的名称
        "ExampleUniform": [
            // 统一块内的一个参数
            // 有关编解码器格式，请参阅 `UniformValue`
            {
                // 参数的名称
                "name": "Param1",
                // 参数类型，之一：
                // - int
                // - ivec3
                // - float
                // - vec2
                // - vec3
                // - vec4
                // - matrix4x4 (mat4)
                "type": "vec4",
                // 存储在统一变量中的值
                // 不再支持来自代码库的动态值
                "value": [ 0.0, 0.0, 0.0, 0.0 ]
            },
            {
                "name": "Param2",
                "type": "float",
                "value": 0
            }
        ]
    }
}
```

#### 纹素缓冲区

纹素缓冲区通常表示为 `isamplerBuffer` 以供查询，通常使用 `texelFetch`：

```glsl
// 在 assets/examplemod/shaders/core/example_shader.json

uniform isamplerBuffer ExampleTexel;

void main() {
    // 阅读文档以了解 texel fetch 的工作原理
    texelFetch(ExampleTexel, gl_InstanceID);
}
```

#### 编写自定义统一变量

只有当您负责创建 `RenderPass` 时，才能编写自定义统一变量。与之前一样，您在打开 `RenderPass` 之前创建并缓存对象，然后通过调用 `RenderPass#withUniform` 设置统一变量。唯一的区别是，现在您必须提供一个 `GpuBuffer` 或 `GpuBufferSlice`，其中写入了统一数据，而不是提供任意对象。对于纹素缓冲区，这通常是一些所需纹理格式的编码数据（例如网格）。对于接口块，最简单的方法是使用 `Std140Builder` 用正确的值填充缓冲区。

写入 `GpuBuffer` 或 `GpuBufferSlice` 有很多不同的方法，例如使用新创建的 `MappableRingBuffer`。由您决定哪种方法最适合您的场景。以下只是众多解决方案中的一种。

```java
// 用于 'ExampleUniform' 的缓冲区
// 接受缓冲区的名称、其用法和大小
private final MappableRingBuffer ubo = new MappableRingBuffer(
    // 缓冲区名称
    () -> "Example UBO",
    // 缓冲区用法
    // 我们设置 128，因为它用于统一变量，并且设置 2 因为我们正在写入它
    // 其他位可以在 `GpuBuffer` 中作为常量找到
    GpuBuffer.USAGE_UNIFORM | GpuBuffer.USAGE_MAP_WRITE,
    // 缓冲区的大小
    // 最简单的方法是使用 Std140SizeCalculator 正确计算
    new Std140SizeCalculator()
        // Param1
        .putVec4()
        // Param2
        .putFloat()
        .get()
);

// 用于 'ExampleTexel' 的缓冲区
private final MappableRingBuffer utb = new MappableRingBuffer(
    // 缓冲区名称
    () -> "Example UTB",
    // 我们设置 256，因为它用于纹素缓冲区，并且设置 2 因为我们正在写入它
    GpuBuffer.USAGE_UNIFORM_TEXEL_BUFFER | GpuBuffer.USAGE_MAP_WRITE,
    // 缓冲区的大小
    // 对您来说可能会更大
    3
);

// 在某个渲染方法中

// 根据需要填充缓冲区

// 由于我们使用环形缓冲区，这只是使用列表中的下一个可用缓冲区
this.ubo.rotate();
// 将数据写入缓冲区
try (GpuBuffer.MappedView view = RenderSystem.getDevice().createCommandEncoder().mapBuffer(this.ubo.currentBuffer(), false, true)) {
    Std140Builder.intoBuffer(view.data())
        .putVec4(0f, 0f, 0f, 0f)
        .putFloat(0f);
}

// 类似的事情
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);
}

// 创建渲染通道并传入缓冲区作为统一变量的一部分
try (RenderPass pass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(...)) {
    // ..
    pass.setUniform("ExampleUniform", this.ubo.currentBuffer());
    pass.setUniform("ExampleTexel", this.utb.currentBuffer());
    // ...
}
```

### 雾环境

雾系统已被重做为环境/渲染状态式的处理程序。每个环境主要负责设置雾数据和颜色。为各个 `FogType` 和特殊状态效果提供了一些额外的处理。

所有环境都通过 `FogEnvironment` 处理。通过 `setupFog` 方法设置环境，该方法负责将传入的 `FogData` 更改为与该环境关联的值。如果雾对其周围环境着色，则 `providesColor` 应返回 true，并在 `getBaseColor` 中应用基本颜色色调。同样，如果雾使其周围环境变暗，则 `modifiesDarkness` 应返回 true，并通过 `getModifiedDarkness` 返回修改后的暗度。要确定是否应应用环境，会检查 `isApplicable`。如果不可用，则调用 `onNotApplicable`。

所有环境都注册到 `FogRenderer#FOG_ENVIRONMENTS`；然而，使用哪个环境基于 `isApplicable` 和列表顺序。对于颜色和暗度，选择的雾环境是列表中最后一个 `provides*` 方法之一返回 true 的环境。对于实际的雾设置，选择的雾环境是列表中的第一个。

### 渲染通道剪裁现在仅限 OpenGL

剪裁状态已从通用管线代码中移除，现在只能通过 OpenGL 实现访问。通用区域处理已委托给 `CommandEncoder#clearColorAndDepthTextures`。请注意，这不会影响处理面向 blit 的剪裁的现有 `ScreenRectangle` 系统。

- `com.mojang.blaze3d.buffers`
    - `BufferType` 枚举已移除
    - `BufferUsage` 枚举已移除
    - `GpuBuffer` 现在接受两个整数表示大小和用法，不再指定类型
        - `type` 已移除
        - `usage` 现在返回一个 int
        - `slice` - 返回一个表示某个缓冲区切片的记录。实际缓冲区不以任何方式修改。
        - `$ReadView` -> `$MappedView`
    - `GpuBufferSlice` - 一个记录，通过持有对整个缓冲区的引用、起点的偏移索引和切片的长度来表示某个缓冲区的切片。
    - `GpuFence` 现在是一个接口，其 OpenGL 实现已移至 `blaze3d.opengl.GlFence`
    - `Std140Builder` - 一个用于以 `std140` 格式布局的接口块的缓冲区插入器。用于着色器中的统一块。
    - `Std140SizeCalculator` - 一个用于跟踪某个接口块大小的对象。
- `com.mojang.blaze3d.opengl`
    - `AbstractUniform` 已移除，被 `Std140*` 类取代
    - `BufferStorage` - 一个根据其类型创建缓冲区的类。其实现定义了其一般用途。
    - `DirectStateAccess`
        - `createBuffer` - 创建一个缓冲区。
        - `bufferData` - 初始化缓冲区的数据存储。
        - `bufferSubData` - 更新缓冲区数据存储的子集。
        - `bufferStorage` - 创建缓冲区的数据存储。
        - `mapBufferRange` - 映射缓冲区数据存储的一部分。
        - `unmapBuffer` - 释放缓冲区的映射并使指向其数据存储的指针无效。
    - `GlBuffer` 现在接受一个 `DirectStateAccess`、两个整数和一个 `ByteBuffer`，而不是 `GlDebugLabel` 及其 `Buffer*` 枚举
        - `initialized` 已移除
        - `persistentBuffer` - 持有对某个缓冲区不可变部分的引用。
        - `$ReadView` -> `$GlMappedView`
    - `GlCommandEncoder`
        - `executeDrawMultiple` 现在接受一个字符串集合，定义所需统一变量的列表，以及一个表示绘制调用对象的泛型
        - `executeDraw` 现在接受两个 `int`，要渲染的指定索引范围的实例数和基础顶点
    - `GlConst#toGl` 用于 `BufferType` 和 `BufferUsage` -> `bufferUsageToGlFlag`、`bufferUsageToGlEnum`
    - `GlDebugLabel#pushDebugGroup`、`popDebugGroup` - 用于对类似调用进行分组的分析器命令。
    - `GlDevice`
        - `USE_GL_ARB_buffer_storage` - 设置 `GL_ARB_buffer_storage` 的扩展标志。
        - `getBufferStorage` - 返回负责创建缓冲区的存储。
    - `GlProgram`
        - `Uniform` 字段已移除
        - `safeGetUniform`、`setDefaultUniforms` 已移除
        - `bindSampler` 已移除
        - `getSamplerLocations`、`getSamplers`、`getUniforms` -> `getUniforms`，返回名称到其 `Uniform` 对象的映射
    - `GlRenderPass`
        - `uniforms` 现在是一个 `HashMap<String, GpuBufferSlice>`
        - `dirtSamplers` 已移除
        - `samplers` 映射现在持有 `GpuTextureView` 值
        - `pushedDebugGroups` - 返回推送到堆栈上的组数。关闭渲染通道时不得有任何调试组打开。
        - `isScissorEnabled` - 返回是否启用剪裁状态，该状态会裁剪渲染到屏幕的区域。
        - `getScissorX`、`getScissorY`、`getScissorWidth`、`getScissorHeight` - 返回表示剪裁矩形的值。
    - `GlTexture` 现在接受一个额外的整数用于用法和深度/层数
        - `flushModeChanges` 现在接受一个表示纹理目标的 `int`
        - `addViews`、`removeViews` - 管理针对某些 mip 级别的纹理视图。
    - `GlTextureView` - 针对某些 mip 级别的纹理的视图实现。
    - `Uniform` 现在是一个密封接口，实现为缓冲区对象、纹素缓冲区或采样器
- `com.mojang.blaze3d.pipeline`
    - `BlendFunction#PANORAMA` 已移除
    - `CompiledRenderPipeline#containsUniform` 已移除
    - `RenderPipeline`
        - `$Builder#withUniform` 现在有一个可以接受 `TextureFormat` 的重载
        - `$UniformDescription` 现在接受一个可为 null 的 `TextureFormat`
    - `RenderTarget`
        - `colorTextureView`、`depthTextureView`、`getColorTextureView`、`getDepthTextureView` - 当前颜色和深度纹理的视图。
        - `blitAndBlendToTexture` 现在接受 `GpuTextureView` 而不是 `GpuTexture`
- `com.mojang.blaze3d.platform.Lightning` 现在是 `AutoCloseable`
    - `setup*` -> `setupFor`，一个接受 `$Entry` 的实例方法
    - `updateLevel` - 更新光照缓冲区，接受是否使用下界漫射光照。
- `com.mojang.blaze3d.shaders`
    - `FogShape` -> `net.minecraft.client.renderer.fog.FogData`，不是一对一
    - `UniformType` 现在只包含两种类型：`UNIFORM_BUFFER` 或 `TEXEL_BUFFER`，不再接受计数
- `com.mojang.blaze3d.systems`
    - `CommandEncoder`
        - `clearColorAndDepthTextures` 现在有一个接受四个 `int` 的重载，表示要清除纹理信息的区域
        - `writeToBuffer`、`mapBuffer(GpuBuffer, int, int)` 现在接受 `GpuBufferSlice` 而不是 `GpuBuffer`
        - `createFence` - 创建一个新的同步围栏。
        - `createRenderPass` 现在接受一个 `Supplier<String>`，用于确定用作调试组的通道名称，以及 `GpuTextureView` 而不是 `GpuTexture`
        - `writeToTexture` 现在接受一个额外的 `int`，表示要写入的深度或层
        - `presentTexture` 现在接受 `GpuTextureView` 而不是 `GpuTexture`
    - `GpuDevice`
        - `createBuffer` 不再接受 `BufferUsage`，`BufferType` 被 `int` 取代
        - `getUniformOffsetAlignment` - 返回统一缓冲区偏移对齐。
        - `createTexture` 现在接受额外的 `int` 用于用法和深度/层数，请参阅 `GpuTexture` 常量
        - `createTextureView` - 为某个 mip 级别范围创建纹理视图。
    - `RenderPass`
        - `enableScissor` 已移除
        - `bindSampler` 现在可以接受一个可为 null 的 `GpuTextureView`
        - `setUniform` 现在可以接受 `GpuBuffer` 或 `GpuBufferSlice` 而不是原始输入
        - `drawIndexed` 现在接受以下 `int`：基础顶点、起始索引、元素数和原始计数
        - `drawMultipleIndexed` 现在接受一个字符串集合，定义所需统一变量的列表，以及一个表示绘制调用对象的泛型
        - `pushDebugGroup`、`popDebugGroup` - 用于对类似调用进行分组的分析器命令。
        - `$UniformUploader#upload` 现在接受 `GpuBufferSlice` 而不是 `float` 数组
        - `$Draw` 现在有一个泛型，用于将任何统一变量上传到缓冲区
    - `RenderSystem`
        - `SCISSOR_STATE` -> `scissorStateForRenderTypeDraws`，现在是私有的
            - 可通过 `getScissorStateForRenderTypeDraws` 访问
        - `enableScissor`、`disableScissor` -> `enableScissorForRenderTypeDraws`、`disableScissorForRenderTypeDraws`，不是一对一
        - `PROJECTION_MATRIX_UBO_SIZE` - 返回投影矩阵统一变量的大小
        - `setShaderFog`、`getShaderFog` 现在处理 `GpuBufferSlice`
        - `setShaderGlintAlpha`、`getShaderGlintAlpha` 已移除
        - `setShaderLights`、`getShaderLights` 现在处理 `GpuBufferSlice`
        - `setShaderColor`、`getShaderColor`
        - `setup*Lighting` 方法已移除
        - `setProjectionMatrix`、`getProjectionMatrix`（现在为 `getProjectionMatrixBuffer`）现在处理 `GpuBufferSlice`
        - `setShaderGameTime`、`getShaderGameTime` -> `setGlobalSettingsUniform`、`getGlobalSettingsUniform`；不是一对一
        - `getDynamicUniforms` - 返回要为着色器写入的统一变量列表。
        - `bindDefaultUniforms` - 绑定要在 `RenderPass` 内使用的默认统一变量
        - `outputColorTextureOverride`、`outputDepthTextureOverride` 现在是 `GpuTextureView`
        - `setupOverlayColor`、`setShaderTexture`、`getShaderTexture` 现在操作 `GpuTextureView` 而不是 `GpuTexture`
- `com.mojang.blaze3d.textures`
    - `GpuTexture` 现在接受一个表示用法标志和深度/层数的 int
        - `usage` - 定义纹理如何使用的标志。
        - `depthOrLayers`、`getDepthOrLayers` - 定义给定纹理可用的层数或深度。这是作为可用纹理编码的通用计数。目前仅支持立方体贴图（意味着层数必须是 6 的倍数）。
    - `GpuTextureView` - 针对某个 mip 级别范围的纹理视图。
    - `TextureFormat#RED8I` - 处理红色通道的 8 位有符号整数。
- `com.mojang.blaze3d.vertex`
    - `ByteBufferBuilder` 现在接受一个 long 作为最大容量
        - `exactlySized` - 返回一个达到其最大容量的缓冲区。应优先于公共构造函数调用此方法。
    - `DefaultVertexFormat#EMPTY` - 一个没有元素的顶点格式。
- `net.minecraft.client.renderer`
    - `CachedOrthoProjectionMatrixBuffer` - 一个缓存正交投影矩阵的对象，如果屏幕宽度或高度改变，则重新构建。
    - `CachedPerspectiveProjectionMatrixBuffer` - 一个缓存透视投影矩阵的对象，如果宽度、高度或视野改变，则重新构建。
    - `CloudRenderer`
        - `FLAG_INSIDE_FACE`、`FLAG_USE_TOP_COLOR` 现在是私有的
        - `RADIUS_BLOCKS` 已移除
        - `endFrame` - 通过构造围栏结束当前正在渲染的帧。
    - `CubeMap` 现在是 `AutoCloseable`
        - `render` 不再接受部分刻的浮点数。
    - `DynamicUniforms` - 一个将统一接口块写入缓冲区以供着色器使用的类。
    - `DynamicUniformStorage` - 一个将统一变量保存在可映射环形缓冲区切片中的类。
    - `FogParameters` 记录已移除，现在存储在一个通用的 `GpuBufferSlice` 中
    - `FogRenderer` 现在实现 `AutoCloseable` -> `.fog.FogRenderer`
        - `endFrame` - 通过构造围栏结束当前正在渲染的帧。
        - `getBuffer` - 获取持有当前雾模式统一变量的缓冲区切片。
        - `setupFog` 不再接受 `FogMode`，不返回任何内容
        - `$FogData#mode` 已移除，被 `skyEnd`、`cloudEnd` 取代
        - `$FogMode` 枚举已被 `NONE` 和 `WORLD` 取代，不是一对一
    - `GameRenderer`
        - `getGlobalSettingsUniform` - 返回游戏设置的统一变量。
        - `getLighting` - 获取光照渲染器。
        - `setLevel` - 设置渲染器正在渲染的当前等级。
    - `GlobalSettingsUniform` - 一个用于处理持有当前游戏设置的统一变量的对象。
    - `LevelRenderer`
        - `endFrame` - 通过构造围栏结束当前正在渲染的帧。
        - `renderLevel` 现在接受一个 `GpuBufferSlice`、雾向量以及当前位置是否有雾，而不是 `GameRenderer`
    - `MappableRingBuffer` - 一个包含三个缓冲区的对象，根据需要写入，然后在结束时旋转到下一个要使用的缓冲区。这些使用围栏进行同步。
    - `PanoramaRenderer#render` 现在接受一个布尔值，表示是否改变旋转，而不是两个浮点数。
    - `PerspectiveProjectionMatrixBuffer` - 一个持有投影矩阵统一变量的对象。
    - `PostChain`
        - `load` 现在接受 `CachedOrthoProjectionMatrixBuffer`
        - `addToFrame` 不再接受 `Consumer<RenderPass>`
        - `process` 不再接受 `Consumer<RenderPass>`
    - `PostChainConfig`
        - `$FixedSizedTarget` 记录已移除
        - `$FullScreenTarget` 记录已移除
        - `$InternalTarget` 现在是一个记录，可以接受可选的宽度、高度、目标是否持久以及要使用的清除颜色
        - `$Pass#uniforms` 现在是一个 `Map<String, List<UniformValue>>`
        - `$Uniform` 记录已移除
    - `PostPass` 现在是 `AutoCloseable`，接受一个 `Map<String, List<UniformValue>>` 作为统一变量，以及一个 `PostPass$Input` 列表
        - `addToFrame` 不再接受 `Consumer<RenderPass>`，`Matrix4f` 作为 `GpuBufferSlice` 传入
        - `$Input`
            - `bindTo` 已移除
            - `texture` - 根据资源映射为输入构造一个 `GpuTexture`。
            - `samplerName` - 返回采样器的名称。
    - `SkyRenderer#renderSunMoonAndStars` 不再接受 `FogParameters`
    - `UniformValue` - 一个表示存储在接口块内的统一变量的接口。
- `net.minecraft.client.renderer.chunk.SectionRendererDispatcher$RenderSection#setDynamicTransformIndex`、`getDynamicTransformIndex` - 处理用于查询给定部分的正确动态变换的索引。
- `net.minecraft.client.renderer.fog.environment`
    - `AirBasedFogEnvironment` - 一个其颜色源自生物群系空气的环境
    - `AtmosphericFogEnvironment` - 如果没有其他特殊情况匹配，则为默认雾环境。
    - `BlindessFogEnvironment` - 如果实体有失明效果，则激活的环境。
    - `DarknessFogEnvironment` - 如果实体有黑暗效果，则激活的环境。
    - `DimensionOrBossFogEnvrionment` - 根据是否有任何 Boss 或维度特殊效果而激活的环境。
    - `FogEnvironment` - 一个抽象类，确定雾在给定位置应如何为实体渲染。
    - `LavaFogEnvironment` - 如果实体在熔岩中，则激活的环境。
    - `MobEffectFogEnvironment` - 根据实体是否有给定的状态效果而激活的环境。
    - `PowderedSnowFogEnvironment` - 如果实体在细雪中，则激活的环境。
    - `WaterFogEnvironment` - 如果实体在水中，则激活的环境。
- `net.minecraft.client.renderer.texture`
    - `AbstractTexture`
        - `setUseMipmaps` - 设置纹理是否应使用 mipmapping。
        - `textureView`、`getTextureView` - 表示当前的纹理视图。
    - `CubeMapTexture` - 一个兼容立方体贴图的纹理，纹理预期具有后缀 `_0` 到 `_5`。
    - `ReloadableTexture#doLoad` 现在是 protected
- `net.minecraft.world.level.material.FogType`
    - `DIMENSION_OR_BOSS` - 用于维度特殊效果或 Boss 的雾。
    - `ATMOSPHERIC` - 默认雾类型。

## TagAppender 重写

`TagAppender` 已被重写，改变了 `TagsProvider` 的基本实现。

默认情况下，`TagsProvider` 不再提供任何用于向 `TagBuilder` 添加内容的有用方法。您最多可以使用 `TagsProvider#getOrCreateRawBuilder` 构造构建器，并使用可用的 `add*` 方法之一通过其 `ResourceLocation` 添加元素或标签。

```java
// 我们将假设存在某个 TagKey<Item> EXAMPLE_TAG
public class ExampleTagsProvider extends TagsProvider<Item> {

    public ExampleTagsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries, CompletableFuture<TagsProvider.TagLookup<Item>> parentProvider) {
        super(
            // 资源包的输出位置
            output,
            // 要为其生成标签的注册表键
            Registries.ITEM,
            // 注册表的注册表
            registries,
            // 可选：要使用其生成标签的父提供者
            // 通常从 TagsProvider#contentsGetter 获得
            parentProvider
        );
    }

    @Override
    protected void addTags(HolderLookup.Provider registries) {
        // 在此处添加标签
        TagBuilder builder = this.getOrCreateRawBuilder(EXAMPLE_TAG);
        builder
            // 添加单个元素
            .addElement(ResourceLocation.fromNamespaceAndPath("minecraft", "apple"))
            // 将标签添加到构建器
            .addTag(ItemTags.WOOL.location());
    }
}
```

但是，如果我们想通过其 `ResourceKey` 引用标签呢？或者注册表对象？这就是重写的 `TagAppender` 的作用。`TagAppender` 是一个具有两个泛型的接口，`E` 表示要添加的条目的类型，`T` 表示标签内对象的类型。一个 `TagAppender` 有五个常见方法：三个添加条目（`add`、`addAll`、`addOptional`），两个添加标签（`addTag`、`addOptionalTag`）。可以通过 `forBuilder` 创建 `TagAppender`，它接受条目的 `ResourceKey`。

`KeyTagProvider` 通过添加一个 `tag` 方法为您提供此功能，该方法从 `TagKey` 创建追加器。通常，数据包注册表对象使用此提供者生成其标签：

```java
// 我们将假设存在某个 TagKey<Item> EXAMPLE_TAG
public class ExampleTagsProvider extends KeyTagProvider<Item> {

    public ExampleTagsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
        super(
            // 资源包的输出位置
            output,
            // 要为其生成标签的注册表键
            Registries.ITEM,
            // 注册表的注册表
            registries
        );
    }

    @Override
    protected void addTags(HolderLookup.Provider registries) {
        // 在此处添加标签
        TagAppender<ResourceKey<Item>, Item> builder = this.tag(EXAMPLE_TAG);
        builder
            // 添加单个元素
            .add(ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath("minecraft", "apple")))
            // 将标签添加到构建器
            .addTag(ItemTags.WOOL);
    }
}
```

`TagAppender` 也可以使用 `map` 方法来更改其条目类型。这接受一个将新条目类型映射到原始条目类型的函数。`IntrinsicHolderTagsProvider` 通过一个 `tag` 方法为您提供此功能，该方法从 `TagKey` 创建追加器，并使用键提取器进行映射。通常，内置注册表对象使用此提供者生成其标签：

```java
// 我们将假设存在某个 TagKey<Item> EXAMPLE_TAG
public class ExampleTagsProvider extends IntrinsicHolderTagsProvider<Item> {

    public ExampleTagsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
        super(
            // 资源包的输出位置
            output,
            // 要为其生成标签的注册表键
            Registries.ITEM,
            // 注册表的注册表
            registries,
            // 将注册表对象映射到其资源键
            item -> item.builtInRegistryHolder().key()
        );
    }

    @Override
    protected void addTags(HolderLookup.Provider registries) {
        // 在此处添加标签
        TagAppender<Item, Item> builder = this.tag(EXAMPLE_TAG);
        builder
            // 添加单个元素
            .add(Items.APPLE)
            // 将标签添加到构建器
            .addTag(ItemTags.WOOL);
    }
}
```

### 复制标签：方块和物品

复制标签不再以传统意义存在，即遍历现有标签的元素。相反，实现已被缩小到一个通用的 `BlockItemTagsProvider`。此方法通过同时接受方块和物品标签，并在 `Vanilla*TagsProvider` 中适当地转换它们，来提供 `TagAppender<Block, Block>`。因此，与其说是复制，不如说是将方块映射到其关联的物品。

一个缺点是，在其他标签中使用的标签（调用 `addTag`）必须具有相同的名称。例如，添加 `BlockTags#LOGS` 之所以有效，是因为存在一个 `minecraft:logs` 同时用于方块和物品标签。同时，添加 `BlockTags#CEILING_HANGING_SIGNS` 会失败，因为关联的物品标签是 `minecraft:hanging_signs` 而不是 `minecraft:ceiling_hanging_signs`。

```java
// 我们将假设存在某个 TagKey<Block> BLOCK_EXAMPLE_TAG
// 我们将假设存在某个 TagKey<Item> ITEM_EXAMPLE_TAG
public class ExampleBlockItemTagsProvider extends BlockItemTagsProvider {

    @Override
    public void run() {
        // 在此处添加方块物品标签
        // 将根据提供者向方块或物品标签添加条目
        TagAppender<Block, Block> builder = this.tag(BLOCK_EXAMPLE_TAG, ITEM_EXAMPLE_TAG);
        builder
            // 添加单个元素
            .add(Blocks.TERRACOTTA)
            // 将标签添加到构建器
            // 在方块和物品标签中都存在 `minecraft:logs`
            .addTag(BlockTags.LOGS);
    }
}

// 对于某个 IntrinsicHolderTagsProvider<Item> 或 IntrinsicHolderTagsProvider<Block>
@Override
protected void addTags(HolderLookup.Provider registries) {
    // 在此处添加标签
    new ExampleBlockItemTagsProvider() {
        // 或 <Item, Item> 取决于情况
        protected TagAppender<Block, Block> tag(TagKey<Block> blockTag, TagKey<Item> itemTag) {
            // 返回一个 TagAppender
            // 有关物品示例，请参阅 VanillaItemTagsProvider$BlockToItemConverter
            // 有关方块示例，请参阅 VanillaBlockTagsProvider
        }
    }.run();
}
```

- `net.minecraft.data.tags`
    - `BlockItemTagsProvider` - 一个为方块物品生成标签的提供者，使用方块和物品标签等效项作为起点。
    - `IntrinsicHolderTagsProvider`
        - `tag` 现在返回原始的 `TagAppender`
        - `$IntrinsicTagAppender` 类已移除
    - `ItemTagsProvider` 类已移除
    - `KeyTagProvider` - 一个通过其 `ResourceKey` 追加元素的提供者。
    - `TagsProvider`
        - `tag` 已移除
        - `$TagAppender` -> `TagAppender`，不是一对一
    - `VanillaItemTagsProvider` 现在实现 `IntrinsicHolderTagsProvider`
        - `BlockToItemConverter` - 一个将方块添加到物品标签的标签追加器。

## 通用编码与解码：替换直接 NBT 访问

从更高级别的对象（如实体和方块实体）中获取某些 NBT 数据的直接访问已被完全移除。这意味着，通常，在序列化过程中您不能直接接触 `CompoundTag`。相反，通过 `ValueInput` 和 `ValueOutput` 提供了对 nbt 标签的间接访问。顾名思义，它们分别从数据对象读取值和向数据对象写入值。可用的方法类似于 `CompoundTag` 上的方法。对于 `ValueInput`，有通过提供关联键的 `get*` 方法，以及如果不存在则获取或默认的 `get*Or`。还有用于处理 `Codec` 的 `read`。对于 `ValueOutput`，有通过提供关联键和值的 `put*` 方法，以及用于 `Codec` 的 `store`。列表变体在输入/输出访问上单独存在。

因此，大多数接受 `CompoundTag` 的方法现在改为在 `read`/`load` 时接受 `ValueInput`，或在 `write`/`save` 时接受 `ValueOutput`。

```java
// 对于某个带有 ItemStack stack 的 Entity
@Override
protected void readAdditionalSaveData(ValueInput in) {
    super.readAdditionalSaveData(in);
    // 默认情况下，输入使用注册表 ops
    this.stack = in.read("example_stack", ItemStack.CODEC).orElse(ItemStack.EMPTY);
}

@Override
protected void addAdditionalSaveData(ValueOutput out) {
    super.addAdditionalSaveData(out);
    // 默认情况下，输出使用注册表 ops
    in.storeNullable("example_stack", ItemStack.CODEC, this.stack);
}

// 对于某个带有 int value 的 BlockEntity
@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 实现

为了提供对 `CompoundTag` 的间接访问，有分别称为 `TagValueInput` 和 `TagValueOutput` 的 `ValueInput` 和 `ValueOutput` 的实现。

可以使用 `createWithContext` 或 `createWithoutContext` 创建 `TagValueOutput`。“有上下文”意味着输出可以访问注册表对象的 `HolderLookup$Provider`，而“无上下文”则不能。目前，没有位置使用 `createWithoutContext`。内部会创建一个新的 `CompoundTag`。然后，这个输出被传递以填充，最后通过 `buildResult` 返回用于写入的 NBT。

另一方面，`TagValueInput` 可以通过 `create` 创建，接受 `HolderLookup$Provider` 和要读取的 `CompoundTag`。如果数据存储为对象列表而不是单个对象，您可以传入一个 `List<CompoundTag>` 并返回一个 `ValueInputList`。请注意，这不处理索引，只提供可迭代或流关联的实现。

### 问题报告器

除了上述内容之外，`create*` 方法还接受一个 `ProblemReporter`，用于收集在尝试序列化/反序列化数据时遇到的所有问题。由实现决定此报告是导致崩溃还是发出警告。一个 `ProblemReporter` 包含两个方法：`report`，用于报告一个 `$Problem`；以及 `forChild`，用于使用 `$PathElement` 进一步对 `$Problem` 进行分组。问题和路径元素都只是接口对象，分别返回指示问题是什么或分组的字符串。

有两个常用的 `ProblemReporter`：`$Collector`，通常与数据提供者一起使用；以及 `$ScopedCollector`，与磁盘对象（例如，实体、方块实体、区块等）一起使用。`$Collector` 通常使用 `forEach` 逐个报告每个问题，`getReport`/`getTreeReport` 返回字符串化的问题，或 `isEmpty` 列出是否存在任何问题。`$ScopedCollector` 做同样的事情，只是它是 `AutoCloseable`，以防输出没有做任何操作。在这些情况下，报告会写入日志记录器。

每个收集器都接受一个初始的 `$PathElement`。这通常来自对象本身，其中包含某个称为 `problemPath` 的方法，该方法实现了该接口。`HolderLookup$Provider` 以相同的方式提供。

```java
// 对于某个带有 HolderLookup.Provider registries 的对象
// 还有一个 Logger LOGGER

// 我们假设我们的根路径元素实现如下
public record ExamplePathElement(String name) implements ProblemReporter.PathElement {

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

// 对于数据提供者
ProblemReporter.Collector problems = new ProblemReporter.Collector(
    // 对于非指定的根，可以为空
    new ExamplePathElement("data_provider")
);
// 传递提供者

// 对于基于磁盘的对象
try (ProblemReporter.ScopedCollector problems = new ProblemReporter.ScopedCollector(new ExamplePathElement("EXAMPLE TEST"), LOGGER)) {
    TagValueOutput out = TagValueOutput.createWithContext(problems, this.registries);
    // 传递输出以写入数据

    // 对于输入
    // 最后一个参数可以是任何 CompoundTag，以输出为例
    TagValueInput in = TagValueInput.create(problems, this.registries, out.buildResult());
    // 传递输入以读取数据
}
```
- `net.minecraft.nbt.StringTag#escapeWithoutQuotes` - 创建一个转义控制字符、引号、撇号和反斜杠的字符串。
- `net.minecraft.server.level.ServerPlayer`
    - `loadAndSpawnParentVehicle` 现在接受一个 `ValueInput`
    - `loadAndSpawnEnderPearls` 现在接受一个 `ValueInput`
    - `loadGameTypes` 现在接受一个 `ValueInput`
- `net.minecraft.server.players.PlayerList#load` 接受一个 `ProblemReporter`，返回一个可选的 `ValueInput`
- `net.minecraft.util.ProblemReporter`
    - `DISCARDING` - 一个丢弃所有报告的报告器。
    - `forChild` 现在接受一个 `$PathElement`
    - `report` 现在接受一个 `$Problem`
    - `$Collector` 现在有一个接受根 `$PathElement` 的构造函数
        - `isEmpty` - 返回是否没有报告。
        - `forEach` - 遍历所有可用问题。
        - `getReport` 现在返回一个普通的 `String`
        - `getTreeReport` - 使用 DFS 获取报告及其所有子级。
    - `$ElementReferencePathElement` - 一个引用某个 `ResourceKey` 的路径元素。
    - `$FieldPathElement` - 一个引用某个字符串的路径元素。
    - `$IndexedFieldPathElement` - 一个在索引处引用某个字符串的路径元素。
    - `$IndexedPathElement` - 一个引用某个索引的路径元素。
    - `$PathElement` - 一个定义分组或元素的接口。
    - `$Problem` - 一个定义元素问题的接口。
    - `$RootElementPathElement` - 一个引用某个 `ResourceKey` 作为根的路径元素。
    - `$RootFieldPathElement` - 一个引用某个字符串作为根的路径元素。
    - `$ScopedCollector` - 一个在出现问题时记录警告的收集器。
- `net.minecraft.world` 
    - `ContainerHelper`
        - `saveAllItems` 现在接受一个 `ValueOutput` 而不是 `CompoundTag`，不再接受 `HolderLookup$Provider`，不返回任何内容
        - `loadAllItems` 现在接受一个 `ValueInput` 而不是 `CompoundTag`，不再接受 `HolderLookup$Provider`
    - `LockCode#addToTag`、`fromTag` 现在接受 `ValueOutput`/`ValueInput` 而不是 `CompoundTag`，不再接受 `HolderLookup$Provider`
    - `RandomziableContainer#tryLoadLootTable`、`trySaveLootTable` 现在接受 `ValueOutput`/`ValueInput` 而不是 `CompoundTag`
    - `SimpleContainer`
        - `fromTag` -> `fromItemList`，不是一对一
        - `createTag` -> `storeAsItemList`，不是一对一
- `net.minecraft.world.entity`  
    - `Entity`
        - `saveAsPassenger` 现在接受一个 `ValueOutput` 而不是 `CompoundTag`
        - `save` 现在接受一个 `ValueOutput` 而不是 `CompoundTag`
        - `saveWithoutId` 现在接受一个 `ValueOutput` 而不是 `CompoundTag`，不返回任何内容
        - `load` 现在接受一个 `ValueInput` 而不是 `CompoundTag`
        - `readAdditionalSaveData` 现在接受一个 `ValueInput` 而不是 `CompoundTag`
        - `addAdditionalSaveData` 现在接受一个 `ValueOutput` 而不是 `CompoundTag`
        - `problemPath` - 返回报告问题的路径元素。
    - `EntityRenference`
        - `store` 现在接受一个 `ValueOutput` 而不是 `CompoundTag`
        - `read`、`readWithOldOwnerConversion` 现在接受一个 `ValueInput` 而不是 `CompoundTag`
    - `Entity`
        - `UUID_TAG` -> `TAG_UUID`
        - `create`、`by` 现在接受一个 `ValueInput` 而不是 `CompoundTag`
        - `loadEntityRecursive` 现在接受一个 `ValueInput` 而不是 `CompoundTag`
        - `loadEntitiesRecursive` 现在接受一个 `ValueInput$ValueInputList` 而不是 nbt 标签列表
        - `loadStaticEntity` 现在接受一个 `ValueInput` 而不是 `CompoundTag`
    - `EntityReference#store` - 将引用数据写入 `ValueOutput`。
    - `Leashable#readLeashData`、`writeLeashData` 现在接受 `ValueInput`/`ValueOutput` 而不是 `CompoundTag`
    - `LivingEntity#ATTRIBUTES_FIELD` -> `TAG_ATTRIBUTES`
    - `NeutralMob#addPersistentAngerSaveData`、`readPersistentAngerSaveData` 现在接受 `ValueOutput`/`ValueInput` 而不是 `CompoundTag`
- `net.minecraft.world.entity.npc.InventoryCarrier#readInventoryFromTag`、`writeInventoryToTag` 现在接受 `ValueInput`/`ValueOutput` 而不是 `CompoundTag`
- `net.minecraft.world.entity.player.Inventory`
    - `save` 现在接受一个 `ValueOutput$TypedOutputList`，不返回任何内容
    - `load` 现在接受一个 `ValueOutput$TypedInputList`
- `net.minecraft.world.entity.variant.VariantUtils`
    - `writeVariant` 现在接受一个 `ValueOutput` 而不是 `CompoundTag`
    - `readVariant` 现在接受一个 `ValueInput` 而不是 `CompoundTag`，不再接受 `RegistryAccess`
- `net.minecraft.world.entity.vehicle.ContainerEntity#addChestVehicleSaveData`、`readChestVehicleSaveData` 现在接受 `ValueOutput`/`ValueInput` 而不是 `CompoundTag`，不再接受 `HolderLookup$Provider`
- `net.minecraft.world.inventory.PlayerEnderChestContainer`
    - `fromTag` -> `fromSlots`，不是一对一
    - `createTag` -> `storeAsSlots`，不是一对一
- `net.minecraft.world.item`
    - `BlockItem#setBlockEntityData` 现在接受一个 `TagValueOutput` 而不是 `CompoundTag`
    - `ItemStack#parse`、`save` 已移除
- `net.minecraft.world.level`
    - `BaseCommandBlock#save`、`load` 现在接受 `ValueOutput`/`ValueInput` 而不是 `CompoundTag`，不再接受 `HolderLookup$Provider`，不返回任何内容
    - `BaseSpawner#save`、`load` 现在接受 `ValueOutput`/`ValueInput` 而不是 `CompoundTag`，不返回任何内容
- `net.minecraft.world.level.block.SculkSpreader#save`、`load` 现在接受 `ValueOutput`/`ValueInput` 而不是 `CompoundTag`
- `net.minecraft.world.level.block.entity.BlockEntity`
    - `load*` 方法现在接受 `ValueInput` 而不是 `CompoundTag`，不再接受 `HolderLookup$Provider`
    - `save*` 方法现在接受 `ValueOutput` 而不是 `CompoundTag`，不再接受 `HolderLookup$Provider`
    - `removeComponentsFromTag` 现在接受一个 `ValueOutput` 而不是 `CompoundTag`
    - `parseCustomNameSafe` 现在接受一个 `ValueInput` 和键，而不是标签和 `HolderLookup$Provider`
    - `problemPath` - 返回报告问题的路径元素。
- `net.minecraft.world.level.block.entity.trialspawner.TrialSpawner#load`、`store` - 处理写入生成器数据。
- `net.minecraft.world.level.chunk.ChunkAccess#problemPath` - 返回报告问题的路径元素。
- `net.minecraft.world.level.storage`
    - `PlayerDataStorage#load` 现在返回一个 `ValueInput` 而不是 `CompoundTag`，接受一个 `ProblemReporter`
    - `TagValueInput` - 一个复合标签输入。
    - `TagValueOutput` - 一个复合标签输出。
    - `ValueInput` - 一个定义如何从某个对象读取数据的接口。
    - `ValueInputContextHelper` - 一个包含用于读取对象数据的上下文的类。
    - `ValueOutput` - 一个定义如何向某个对象写入数据的接口。
- `net.minecraft.world.level.storage.loot.ValidationContext`
    - `forChild`、`enterElement` 现在接受 `ProblemReporter$PathElement` 而不是 `String`
    - `reportProblem` 现在接受 `ProblemReporter$Problem` 而不是 `String`
    - `$MissingReferenceProblem` - 一个引用对象缺失的问题。
    - `$ParametersNotProvidedProblem` - 一个战利品上下文参数缺失的问题。
    - `$RecursiveReferenceProblem` - 一个引用对象正在引用自身的问题。
    - `$ReferenceNotAllowedProblem` - 一个引用对象不允许被引用的问题。
- `net.minecraft.world.level.storage.loot.entries`
    - `AlternativesEntry#UNREACHABLE_PROBLEM` - 一个替代条目永远无法执行的问题。
    - `CompositeEntryBase#NO_CHILDREN_PROBLEM` - 一个组合体没有条目的问题。
    - `NestedLootTable#INLINE_LOOT_TABLE_PATH_ELEMENT` - 一个表示表是内联的元素。

## 服务端玩家变更

`MinecraftServer` 不再在 `ServerPlayer` 上公开。此外，`serverLevel` 已被移除，现在用重载的 `level` 来返回 `ServerLevel`。

- `net.minecraft.server.level.ServerPlayer`
    - `server` 字段现在是私有的
    - `serverLevel` -> `level`，仍然返回 `ServerLevel`

## 小幅迁移

以下是有用或有趣的增加、变更和移除的列表，它们不值得在入门文档中拥有自己的章节。

### 拴绳

拴绳系统已更新，最多支持四个拴绳同时拴在一个实体上。此外，物理效果已更新，以更恰当地处理某些可拉伸物体的现实弹性。

- `net.minecraft.client.renderer.entity.state.EntityRenderState`
    - `leashState` 现在返回一个 `$LeashState` 列表
    - `$LeashState#slack` - 拴绳是否有松弛。
- `net.minecraft.world.entity`
    - `Entity`
        - `shearOffAllLeashConnections` - 处理使用剪刀移除拴绳时的情况。
        - `dropAllLeashConnections` - 处理应从实体移除所有拴绳时的情况。
        - `getQuadLeashHolderOffsets` - 获取四个拴绳拴在实体上时的偏移量。
        - `supportQuadLeashAsHolder` - 返回实体是否可以被拴最多四次。
        - `notifyLeashHolder`、`notifyLeasheeRemoved` - 处理拴绳在实体上Tick以及被移除时的情况。
        - `setLeashOffset` 已移除
        - `getLeashOffset` -> `Leashable#getLeashOffset`
    - `Leashable`
        - `MAXIMUM_ALLOWED_LEASHED_DIST` - 拴绳可以拴到实体的最大距离。
        - `AXIS_SPECIFIC_ELASTICITY` - 拴绳沿每个轴的阻力。
        - `SPRING_DAMPENING` - 拴绳拉伸时振荡的能量损失。
        - `TORSIONAL_ELASTICITY` - 拴绳在扭矩下的阻力。
        - `STIFFNESS` - 拴绳的刚度。
        - `ENTITY_ATTACHMENT_POINT` - 指定拴绳在实体上的附着点。
        - `LEASHER_ATTACHMENT_POINT` - 指定拴绳在持有者上的附着点。
        - `SHARED_QUAD_ATTACHMENT_POINTS` - 指定拴绳在实体上的附着点。
        - `canHaveALeashAttachedToIt` -> `canHaveALeashAttachedTo`，不是一对一
        - `leashDistanceTo` - 返回拴绳在持有者和被拴者之间经过的距离。
        - `onElasticLeashPull` - 处理拴绳被拉拽时的情况。
        - `leashSnapDistance` - 返回拴绳将尝试从实体上移除的距离。
        - `leashElasticDistance` - 返回拴绳的弹性成为物理因素之前的最大距离。
        - `handleLeashAtDistance` 已移除
        - `angularFriction` - 返回实体在方块上或液体中的角摩擦。
        - `whenLeashedTo` - 通知实体拴绳已附着。
        - `elasticRangeLeashBehaviour`、`legacyElasticRangeLeashBehaviour` -> `checkElasticInteractions`，不是一对一
        - `supportQuadLeash` - 实体是否可以被拴最多四次。
        - `getQuadLeashOffsets` - 返回附着在实体上的每个拴绳的偏移量。
        - `createQuadLeashOffsets` - 为四个可能的拴绳位置中的每一个创建偏移量。
        - `leashableLeashedTo` - 获取所有在 32 格半径内被拴到此持有者的实体。
        - `$LeashData#angularMomentum` - 返回实体被拴时的角动量。
        - `$Wrench` - 一个记录，处理施加在拴绳上的力和扭矩。
- `net.minecraft.world.item.LeadItem#leashableInArea` -> `Leashable#leashableInArea`

### 移除生物效果图集

生物效果图集已被移除，并与 GUI 图集合并。

- `net.minecraft.client.Minecraft#getMobEffectTextures` 已移除
- `net.minecraft.client.gui.Gui#getMobEffectSprite` - 获取状态效果精灵的位置。
- `net.minecraft.client.resources.MobEffectTextureManage` 类已移除
- `AtlasIds#MOB_EFFECTS` 已移除

### 权限来源

命令的权限检查已被抽象到其自己的 `PermissionSource` 接口中。这提供了之前提供的 `hasPermission` 方法，以及一个新方法 `allowsSelectors`，它返回源是否有选择其他实体所需的权限（默认为 2 级权限）。您可以通过在 `ArgumentBuilder#requires` 中使用所需的级别调用 `Commands#hasPermission`，将权限检查合并到您的命令中。

- `net.minecraft.client.multiplayer`
    - `ClientPacketListener`
        - `getCommands` 现在返回一个 `ClientSuggestionProvider` 泛型
        - `sendUnattendedCommand` 现在接受一个 `Screen` 而不是 `boolean`
    - `ClientSuggestionListener` 现在实现 `PermissionSource`，接受一个布尔值表示是否允许受限命令
        - `allowRestrictedCommands` - 返回是否建议受限命令。
- `net.minecraft.commands`
    - `Commands#hasPermission` - 返回给定级别的权限检查。
    - `CommandSourceStack` 现在实现 `PermissionSource`
    - `ExecutionCommandSource` 现在实现 `PermissionSource`
    - `PermissionSource` - 返回运行命令的权限源。
    - `SharedSuggestionProvider`
        - `suggestResgitryElements` 现在接受 `HolderLookup` 而不是 `Registry`
        - `listSuggestions` - 列出某些注册表元素的建议。
        - `hasPermission` 已移除
- `net.minecraft.commands.synchronization.SuggestionProviders`
    - `AVAILABLE_SOUNDS`、`SUMMONABLE_ENTITIES` 现在接受 `SharedSuggestionProvider` 作为其泛型
    - `cast` - 将建议提供者转换为正确的类型。
    - `safelySwap` 已移除
    - `$Wrapper` -> `$RegisteredSuggestion`
- `net.minecraft.world.entity.Entity#getCommandSenderWorld` 已移除

### 动画烘焙

动画现在被烘焙到 `KeyframeAnimation` 中。每个 `KeyframeAnimation` 由将关键帧应用于给定 `ModelPart` 的条目组成。要创建动画，应在模型构造函数中通过 `AnimationDefinition#bake` 烘焙定义，然后在 `EntityModel#setupAnim` 期间根据需要调用 `#apply` 或 `#applyWalk`。

```java
// 对于某个实体模型
// 假设存在某个 AnimationDefinition EXAMPLE_DEFN
// 假设我们的 ExampleEntityState 有一个 AnimationState exampleAnimState
public class ExampleModel extends EntityModel<ExampleEntityState> {

    private final KeyframeAnimation exampleAnim;

    public ExampleModel(ModelPart root) {
        // 我们传入任何可以应用所有动画的 'root'
        this.exampleAnim = EXAMPLE_DEFN.bake(root);
    }

    @Override
    public void setupAnim(ExampleEntityState state) {
        super.setupAnim(state);
        this.exampleAnim.apply(state.exampleAnimState, state.ageInTicks);
    }
}
```

- `net.minecraft.client.animation`
    - `AnimationDefinition#bake` - 烘焙一个已定义的动画，以便在 `Model` 上使用。
    - `KeyframeAnimation` - 一个用于在给定 `Model` 上移动 `ModelPart` 的烘焙动画。
    - `KeyframeAnimations#animate` -> `KeyframeAnimation$Entry#apply`
- `net.minecraft.client.model.Model`
    - `getAnyDescendantWithName` 已移除
    - `animate` -> `KeyframeAnimation#apply`
    - `animateWalk` - `KeyframeAnimation#applyWalk`
    - `applyStatic` -> `KeyframeAnimation#applyStatic`
- `net.minecraft.client.model.geom.ModelPart`
    - `getAllParts` 现在返回一个 `List`
    - `createPartLookup` - 创建一个部件名称到其 `ModelPart` 的查找表，任何重复的名称将被忽略。

### ChunkSectionLayers

用于定义方块或流体应如何渲染的 `RenderType` 现在已被 `ChunkSectionLayer` 取代。它们在功能上与 `RenderType` 相同；然而，它们只指定要使用的 `RenderPipeline` 以及缓冲区信息。这也意味着某些 `RenderType` 被移除，例如 `TRANSLUCENT`，因为它们仅用于区块渲染。

这也意味着添加到 `ItemBlockRenderTypes#TYPE_BY_BLOCK` 必须指定 `ChunkSectionLayer` 而不是关联的 `RenderType`。

- `net.minecraft.client.renderer`
    - `ItemBlockRenderTypes`
        - `getChunkRenderType` 现在返回一个 `ChunkSectionLayer`
        - `getRenderLayer(FluidState)` 现在返回一个 `ChunkSectionLayer`
    - `RenderType`
        - `translucent` 已移除
        - `getRenderTarget`、`getRenderPipeline` 已移除
        - `chunkBufferLayers` 已移除
- `net.minecraft.client.renderer.chunk`
    - `ChunkSectionLayer` - 一个枚举，定义如何渲染单个区块层（例如，实心方块、半透明方块）。
    - `ChunkSectionLayerGroup` - 一个枚举，将层分组以进行渲染。
    - `ChunkSectionsToRender` - 一个记录，包含给定区块的绘制，允许按层组渲染它们。
    - `RenderChunk` -> `SectionCopy`
    - `RenderChunkRegion` -> `RenderSectionRegion`
    - `RenderRegionCache#createRegion` 现在接受一个 `long` 而不是 `SectionPos`
    - `SectionCompiler$Results`
        - `globalBlockEntities` -> - `net.minecraft.client.multiplayer.ClientLevel#getGloballyRenderedBlockEntities`
        - `renderedLayers` 现在接受 `ChunkSectionLayer` 作为键
    - `SectionMesh` - 一个定义区块内给定部分的网格的接口
    - `SectionRenderDispatcher`
        - `getBatchToCount` -> `getCompileQueueSize`
        - `setCamera`、`getCameraPosition` 已移除
        - `blockUntilClear` 已移除
        - `clearBatchQueue` -> `clearCompileQueue`，现在是公开的
        - `$CompiledSection` -> `CompiledSectionMesh`
        - `$RenderSection`
            - `getBuffers` 已移除
            - `uploadSectionLayer(RenderType, MeshData)` -> `upload(Map, CompiledSectionMesh)`，不是一对一
            - `uploadSectionIndexBuffer` 现在接受一个 `CompiledSectionMesh` 和一个 `ChunkSectionLayer` 而不是 `RenderType`
            - `getDistToPlayerSqr` 已移除
            - `getCompiled` -> `getSectionMesh`，不是一对一
            - `rebuildSectionAsync` 不再接受 `SectionRenderDispatcher`
            - `setDynamicTransformIndex`、`getDynamicTransformIndex` 已移除
        - `$SectionBuffers` -> `SectionBuffers`
        - `$TranslucencyPointOfView` -> `TranslucencyPointOfView`
- `net.minecraft.server.level.ChunkMap#getUpdatingChunkIfPresent` 现在是公开的
- `net.minecraft.world.level.TicketStorage`
    - `purgeStaleTickets` 现在接受 `ChunkMap`
    - `removeTicketIf` 现在接受一个 `BiPredicate` 而不是 `Predicate`，接受区块位置和加载票
- `net.minecraft.world.level.chunk.ChunkAccess#isSectionEmpty` 已移除

### 标签变更

- `minecraft:block`
    - `plays_ambient_desert_block_sounds` 拆分为 `triggers_ambient_desert_sand_block_sounds`、`triggers_ambient_desert_dry_vegetation_block_sounds`
    - `happy_ghast_avoids`
    - `triggers_ambient_dried_ghast_block_sounds`
- `minecraft:dialog`
    - `pause_screen_additions`
    - `quick_actions`
- `minecraft:entity_type`
    - `can_equip_harness`
    - `followable_friendly_mobs`
- `minecraft:item`
    - `harnesses`
    - `happy_ghast_food`
    - `happy_ghast_tempt_items`

### 新增列表

- `com.mojang.blaze3d.pipeline`
    - `BlendFunction#TRANSLUCENT_PREMULTIPLIED_ALPHA` - 一个假设目标具有来自合成步骤的预乘 alpha 的混合函数。
    - `RenderPipeline`
        - `getSortKey` - 返回一个表示元素应如何排序以进行渲染的值。用于层排序。
        - `updateSortKeySeed` - 更新排序键的种子，当前未使用。
- `com.mojang.blaze3d.systems.RenderSystem`
    - `outputColorTextureOverride` - 持有一个包含覆盖颜色的纹理，该覆盖颜色将代替 `RenderType` 目标中指定的任何内容使用。
    - `outputDepthTextureOverride` - 持有一个包含覆盖深度的纹理，该覆盖深度将代替 `RenderType` 目标中指定的任何内容使用。
- `com.mojang.blaze3d.textures.GpuTexture#setUseMipmaps` - 设置纹理在不同距离是否应使用 mipmap。
- `net.minecraft`
    - `FileUtil#isPathPartPortable` - 返回提供的字符串是否与任何 Windows 保留文件名不匹配。
    - `WorldVersion$Simple` - 当前世界版本的简单实现。
- `net.minecraft.advancements.critereon`
    - `ItemUsedOnLocationTrigger$TriggerInstance#placedBlockWithProperties` - 创建一个触发器，其中放置了一个具有指定属性的方块。
    - `PlayerInteractTrigger$TriggerInstance#equipmentSheared` - 创建一个条件触发器，作用于玩家从某个实体上取下物品。
- `net.minecraft.client`
    - `GameNarrator#saySystemChatQueued` - 如果启用了系统或聊天消息旁白，则旁白一个组件。
    - `Minecraft#disconnectWithSavingScreen` - 断开当前客户端实例并显示“保存等级”屏幕。
    - `Options`
        - `keyQuickActions` - 用于显示快速操作对话框的按键映射。
        - `cloudRange` - 返回云可以渲染的最大距离。
        - `musicFrequency` - 返回 `MusicManager` 处理的背景音乐应播放的频率。
        - `showNowPlayingToast` - 返回是否显示“正在播放”吐司。
        - `getFinalSoundSourceVolume` - 计算给定声音源的音量，非主声音源由主声音源缩放。
    - `NarratorStatus#shouldNarrateSystemOrChat` - 返回当前旁白状态是否为除 `OFF` 之外的任何状态。
- `net.minecraft.client.color.ColorLerper` - 一个基于部分刻在颜色类型之间进行插值的实用工具类。
- `net.minecraft.client.data.models.BlockModelGenerators#createDriedGhastBlock` - 创建干燥恶魂方块模型定义。
- `net.minecraft.client.data.models.model`
    - `ModelTemplates#DRIED_GHAST` - 一个使用 `minecraft:block/dried_ghast` 父级的模板。
    - `TextureMapping#driedGhast` - 为干燥恶魂模型创建默认纹理映射。
    - `TextureSlot#TENTACLES` - 提供一个纹理键 `tentacles`。
- `net.minecraft.client.model`
    - `GhastModel#animateTentacles` - 动画恶魂的触手。
    - `HappyGhastHarnessModel` - 一个代表恶魂挽具的模型。
    - `HappyGhastModel` - 一个代表“驯服”恶魂的模型。
    - `QuadrupedModel#createBodyMesh` 现在接受两个布尔值，分别用于处理左后腿和右后腿纹理是否镜像。
- `net.minecraft.client.multiplayer.ClientLevel`
    - `DEFAULT_QUIT_MESSAGE` - 持有退出游戏文本的组件。
    - `disconnect(Copmonent)` - 断开与当前等级实例的连接，显示关联的组件。
- `net.minecraft.client.renderer.entity.HappyGhastRenderer` - “驯服”恶魂的渲染器。
- `net.minecraft.client.renderer.entity.layers.RopesLayer` - 用于“驯服”恶魂上的绳索的渲染层。
- `net.mienecraft.client.renderer.entity.state.HappyGhastRenderState` - “驯服”恶魂的状态。
- `net.minecraft.client.resources.model.EquipmentclientInfo$LayerType#HAPPY_GHAST_BODY` - 一个代表快乐恶魂身体的层。
- `net.minecraft.client.resources.sounds.RidingHappyGhastSoundInstance` - 一个在骑乘快乐恶魂时播放的可Tick声音实例。
- `net.minecraft.client.sounds`
    - `MusicManager`
        - `getCurrentMusicTranslationKey` - 返回当前正在播放的音乐的翻译键。
        - `setMinutesBetweenSongs` - 设置背景曲目之间的频率。
        - `showNowPlayingToastIfNeeded` - 如果需要，显示正在播放吐司。
        - `$MusicFrequency` - 正在播放的背景曲目的频率。
    - `SoundEngine$PlayResult` - 尝试播放的声音的起始状态。
- `net.minecraft.commands.arguments`
    - `HexColorArgument` - 一个接受十六进制颜色的整数参数。
    - `ResourceOrIdArgument`
        - `createGrammar` - 创建用于解析参数的语法。
        - `$InlineResult` - 一个返回直接持有者的结果。
        - `$ReferenceResult` - 一个返回引用持有者的结果。
        - `$Result` - 一个表示某个参数解析结果的接口。
- `net.minecraft.data.loot.LootTableProvider$MissingTableProblem` - 一个记录，保存某个缺失的内置表生成器的键。
- `net.minecraft.data.recipes.RecipeProvider`
    - `dryGhast` - 干燥恶魂的配方。
    - `harness` - 染色挽具的配方。
- `net.minecraft.gametest.framework.GameTestTicker#startTicking` - 开始为游戏测试Tick运行器。
- `net.minecraft.nbt.NbtUtils`
    - `addCurrentDataVersion`、`addDataVersion`，将数据版本添加到某个 nbt 标签。
- `net.minecraft.network.FriendlyByteBuf#writeEither`、`readEither` - 使用给定的流编码器/解码器处理 `Either`。
- `net.minecraft.network.codec.ByteBufCodecs`
    - `RGB_COLOR` - 一个使用三个字节写入 RGB 的流编解码器。
    - `lenientJson` - 创建一个以宽松模式解析 json 的流编解码器。
    - `optionalTagCodec` - 创建一个使用提供的 `NbtAccounter` 解析 `Optional` 包装的 `Tag` 的流编解码器。
- `net.minecraft.network.protocol.game`
    - `ServerboundChangeGameModePacket` - 更改当前游戏模式。
    - `ServerboundCustomClickActionPacket` - 在服务器上执行自定义操作，目前什么都不做。
- `net.minecraft.server.MinecraftServer#handleCustomClickAction` - 处理从点击事件发送的自定义操作。
- `net.minecraft.server.level.ServerLevel`
    - `updateNeighboursOnBlockSet` - 更新当前位置的邻居。如果方块不相同（不包括其属性），则调用 `BlockState#affectNeighborsAfterRemoval`。
    - `waitForChunkAndEntities` - 添加一个任务，使服务器等待，直到实体在提供的区块范围内加载。
- `net.minecraft.sources.SoundSource#UI` - 来自某些用户界面的声音。
- `net.minecraft.stats`
    - `RecipeBookSettings#MAP_CODEC`
    - `ServerRecipeBook#pack`、`loadUntrusted`、`$Packed` - 处理编码和解码配方书的数据。
- `net.minecraft.util`
    - `ARGB`
        - `setBrightness` - 使用 0 到 1 之间的浮点数返回某个颜色的亮度。
        - `color` - 从浮点红色和整数 alpha 返回一个 ARGB 颜色。
    - `ExtraCodecs`
        - `VECTOR2F`
        - `VECTOR3I`
        - `NBT`
    - `LenientJsonParser` - 一个使用宽松规则的 json 解析器。
    - `Mth#smallestSquareSide` - 取一个数的平方根的上取整。
    - `StrictJsonParser` - 一个使用严格规则的 json 解析器。
- `net.minecraft.world`
    - `Difficulty#STREAM_CODEC`
    - `ItemStackWithSlot` - 一个记录，包含一个堆栈及其槽位索引。
- `net.minecraft.world.entity`
    - `Entity`
        - `MAX_MOVEMENTS_HANDELED_PER_TICK` - 在给定Tick中可以应用于实体的最大移动数。
        - `isInClouds` - 返回实体的 Y 位置是否在云高度和其上方四个单位之间。
        - `teleportSpectators` - 传送当前从玩家视角观看的旁观者。
        - `isFlyingVehicle` - 返回载具是否可以飞行。
        - `clearMovementThisTick` - 清除实体在本Tick中将进行的所有移动。
    - `EntityAttachments#getAverage` - 返回所有附着点的平均位置。
    - `ExperienceOrb`
        - `awardWithDirection` - 添加一个通过指定向量移动的经验球。
        - `unstuckIfPossible` - 尝试查找并将球移动到空闲位置。
    - `Mob` 
        - `isWithinHome` - 返回该位置是否在实体的限制半径内。
        - `canShearEquipment` - 返回当前玩家是否可以从该生物上剪下装备。
- `net.minecraft.world.entity.ai.control.MoveControl#setWait` - 将操作设置为 `WAIT`。
- `net.minecraft.world.entity.ai.goal.TemptGoal`
    - `stopNavigation`、`navigateTowards` - 处理向玩家的导航。
    - `$ForNonPathfinders` - 一个引诱目标，它导航到想要的位置，而不是立即寻路。
- `net.minecraft.world.entity.ai.navigation.PathNavigation#canNavigateGround` - 返回实体是否可以在陆地上寻路。
- `net.minecraft.world.entity.ai.sensing.AdultSensorAnyType` - 一个忽略实体是否与幼崽相同类型的成年传感器。
- `net.minecraft.world.entity.animal`
    - `HappyGhast` - 一个代表快乐恶魂的实体。
    - `HappyGhastAi` - 快乐恶魂的大脑。
- `net.minecraft.world.entity.decoration.ArmorStand`
    - `setArmorStandPose`、`getArmorStandPose`、`$ArmorStandPose` - 处理盔甲架的姿势。
- `net.minecraft.world.entity.monster.Ghast`
    - `faceMovementDirection` - 旋转实体以面对其当前移动方向。
    - `$RandomFloatAroundGoal#getSuitableFlyToPosition` - 获取恶魂应飞向的位置。
- `net.minecraft.world.entity.player.Inventory#SLOT_BODY_ARMOR`、`SLOT_SADDLE` - 相应槽位的索引。
- `net.minecraft.world.entity.projectile.ProjectileUtil#computeMargin` - 根据其Tick计数计算要检查的给定实体的边界框边距。
- `net.minecraft.world.item.component`
    - `ItemAttributeModifiers`
        - `forEach` - 将消费者应用于槽位组内的所有属性。
        - `$Builder#add` - 添加一个要应用于给定槽位组的属性，并带有显示。
        - `$Display` - 定义属性修改器应如何在其工具提示中显示。
        - `$Default` - 显示默认属性显示。
        - `$Hidden` - 不显示任何属性信息。
        - `$OverrideText` - 用提供的组件覆盖属性文本。
    - `Equippable$Builder`
        - `setCanBeSheared` - 设置装备是否可以从实体上剪下。
        - `setShearingSound` - 设置从实体上剪下一件装备时要播放的声音。
    - `ResolvableProfile#pollResolve` - 返回存储的 id 或名称的配置文件。
- `net.minecraft.world.item.equipment.Equippable#harness` - 表示要装备的挽具。
- `net.minecraft.world.level`
    - `CollisionGetter`
        - `getPreMoveCollisions` - 返回一个包含给定边界框和未来移动方向上的实体和方块碰撞的形状的可迭代对象。
        - `getBlockCollisionsFromContext` - 从给定的碰撞上下文中获取方块形状。
    - `GameType#STREAM_CODEC`
    - `Level`
        - `precipitationAt` - 返回给定位置的降水。
        - `onBlockEntityAdded` - 当方块实体被添加到等级时要运行的逻辑。
- `net.minecraft.world.level.block`
    - `BaseRailBlock#rotate` - 在关联方向上旋转当前的铁轨形状。
    - `DriedGhastBlock` - 一个代表干燥恶魂的方块。
- `net.minecraft.world.level.block.entity.trialspawner.TrialSpawner$FullConfig` - 代表试炼的整个配置。
- `net.minecraft.world.level.dimension.DimensionDefaults`
    - `CLOUD_THICKNESS` - 云的方块厚度。
    - `OVERWORLD_CLOUD_HEIGHT` - 主世界的云高度等级。
- `net.minecraft.world.level.levelgen.flat.FlatLayerInfo#heightLimited` - 返回一个新的层信息，当前高度是否限制为指定值，只要该值不在最大范围内。
- `net.minecraft.world.phys`
    - `AABB`
        - `intersects` - 返回 `BlockPos` 是否与此框相交。
        - `distanceToSqr` - 返回边界框从其最远点的平方距离。
    - `Vec3#rotateClockwise90` - 将向量顺时针旋转 90 度（翻转 x 和 z 并反转新的 x 值）。
- `net.minecraft.world.phys.shapes.CollisionContext`
    - `withPosition` - 返回实体的碰撞上下文及其底部 y 位置。

### 变更列表

- `com.mojang.blaze3d.platform.Window#setGuiScale`、`getGuiScale` 现在处理 `int` 而不是 `double`
- `net.mineraft`
    - `DetectedVersion` 不再实现 `WorldVersion`
    - `WorldVersion` 方法由于使用 `WorldVersion$Simple` 而使用记录命名模式
        - `getDataVersion` -> `dataVersion`
        - `getId` -> `id`
        - `getName` -> `name`
        - `getProtocolVersion` -> `protocolVersion`
        - `getPackVersion` -> `packVersion`
        - `getBuildTime` -> `buildTime`
        - `isStable` -> `stable`
- `net.minecraft.client`
    - `GameNarrator`
        - `sayChat` -> `sayChatQueued`
        - `say` -> `saySystemQueued`
        - `sayNow` -> `saySystemNow`
    - `Minecraft`
        - `grabPanoramixScreenshot` 不再接受要设置的窗口宽度和高度
        - `disconnect()` -> `disconnectWithProgressScreen`
    - `Screenshot#grab`、`takeScreenshot` 现在接受一个表示缩小因子的 `int`
- `net.minecraft.client.main.GameConfig$QuickPlayData` 现在接受一个 `$QuickPlayVariant`
    - `path` -> `logPath`
    - `singleplayer` -> `variant` 带有 `$QuickPlaySinglePlayerData`
    - `multiplayer` -> `variant` 带有 `$QuickPlayMultiplayerData`
    - `realms` -> `variant` 带有 `$QuickPlayRealmsData`
    - 对于 `singleplayer`、`multiplayer`、`realms` 的 null 由带有 `$QuickPlayDisabled` 的 `variant` 表示
- `net.minecraft.client.data.models.ItemModelGenerators#generateWolfArmor` -> `generateTwoLayerDyedItem`
- `net.minecraft.client.gui.components.DebugScreenOverlay#render3dCrosshair` 现在接受当前的 `Camera`
- `net.minecraft.client.gui.components.debugchart.ProfilerPieChart`
    - `RADIUS` 现在是公开的
    - `CHART_Z_OFFSET` -> `PIE_CHART_THICKNESS`，现在是公开的
- `net.minecraft.client.multiplayer`
    - `ClientLevel$ClientLevelData#getClearColorScale` -> `voidDarknessOnsetRange`，不是一对一
    - `MultiPlayerGameMode#createPlayer` 现在接受一个 `Input` 而不是 `boolean`
- `net.minecraft.client.player.LocalPlayer` 现在接受最后发送的 `Input` 而不是 shift 键的 `boolean`
    - `getLastSentInput` - 获取从服务器最后发送的输入。
- `net.minecraft.client.quickplay.QuickPlay#connect` 现在接受 `GameConfig$QuickPlayVariant` 而不是 `GameConfig$QuickPlayData`
- `net.minecraft.client.renderer`
    - `DimensionSpecialEffects` 不再接受当前云级别以及是否有地面
    - `LightTexture#getTarget` -> `getTexture`
- `net.minecraft.client.renderer.blockentity.BlockEntityRenderer#shouldRenderOffscreen` 不再接受 `BlockEntity`
- `net.minecraft.client.resources`
    - `AbstractSoundInstance#sound` 现在是 `Nullable`
    - `SoundInstance#getSound` 现在是 `Nullable`
- `net.minecraft.client.sounds`
    - `SimpleSoundInstance#forMusic` 现在也接受 `float` 音量
    - `SoundEngine` 现在接受 `MusicManager`
        - `pause` -> `pauseAllExcept`，不是一对一
        - `play` 现在返回一个 `$PlayResult`
    - `SoundManager` 现在接受 `MusicManager`
        - `pause` -> `pauseAllExcept`，不是一对一
        - `play` 现在返回一个 `SoundEngine$PlayResult`
- `net.minecraft.commands.arguments`
    - `ResourceOrIdArgument` 现在接受一个任意编解码器，而不是 `Holder` 包装的值
        - `ERROR_INVALID` -> `ERROR_NO_SUCH_ELEMENT`，现在是公开的，不是一对一
        - `VALUE_PARSER` -> `OPS`，现在是公开的，不是一对一
    - `ResourceSelectorArgument#getSelectedResources` 不再接受 `ResourceKey`
- `net.minecraft.commands.functions.StringTemplate`
    - `fromString` 不再接受行号
    - `isValidVariableName` 现在是公开的
- `net.minecraft.data.recipes.RecipeProvider#colorBlockWithDye` -> `colorItemWithDye`，现在接受 `RecipeCategory`
- `net.minecraft.gametest.framework.GameTestInfo#prepareTestStructure` 现在可为 null
- `net.minecraft.network`
    - `Connection#send` 现在接受一个 `ChannelFutureListener` 而不是 `PacketSendListener`
    - `FriendlyByteBuf#readJsonWithCodec` -> `readLenientJsonWithCodec`
    - `PacketSendListener` 现在是一个类，其方法返回 `ChannelFutureListener` 而不是 `PacketSendListener`
        - `onSuccess`、`onFailure` 已移除
- `net.minecraft.network.codec`
    - `ByteBufCodecs#fromCodec` 现在有一个接受某些 ops 和一个编解码器的重载
    - `StreamCodec#composite` 现在有一个接受十个参数的重载
- `net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket` 现在是一个记录
- `net.minecraft.network.protocol.game`
    - `ClientboundChangeDifficultyPacket` 现在是一个记录
    - `ClientboundCommandsPacket` 现在接受一个 `$NodeInspector`
        - `getRoot` 现在是泛型的，接受一个 `$NodeBuilder`
        - `$NodeBuilder` - 一个给定命令的构建器。
        - `$NodeInspector` - 一个检查给定命令节点信息的代理。
    - `ServerboundChangeDifficultyPacket` 现在是一个记录
- `net.minecraft.server.ReloadableServerRegistries$Holder#lookup` 返回一个 `HolderLookup$Provider`
- `net.minecraft.server.network.ServerCommonPacketListenerImpl#send` 现在接受一个 `ChannelFutureListener` 而不是 `PacketSendListener`
- `net.minecraft.sounds.Music` 现在是一个记录
- `net.minecraft.stats.RecipeBookSettings`
    - `getSettings` 现在是公开的
    - `$TypeSettings` 现在是公开的
- `net.minecraft.world.entity`
    - `AreaEffectCloud#setParticle` -> `setCustomParticle`
    - `Entity`
        - `checkSlowFallDistance` -> `checkFallDistanceAccumulation`
        - `collidedWithFluid`、`collidedWithShapeMovingFrom` 现在是公开的
        - `canBeCollidedWith` 现在接受与其碰撞的实体
        - `spawnAtLocation` 现在有一个接受 `Vec3` 作为偏移位置的重载
        - `removeLatestMovementRecordingBatch` -> `removeLatestMovementRecording`
    - `EntityReference` 现在是 final
    - `ExperienceOrb` 现在有一个接受两个向量作为位置和移动的重载
    - `FlyingMob` 被调用 `LivingEntity#travelFlying` 取代
    - `LivingEntity#canBreatheUnderwater` 不再是 `final`
    - `Mob`
        - `restrictTo` -> `setHomeTo`
        - `getRestrictCenter` -> `getHomePosition`
        - `getRestrictRadius` -> `getHomeRadius`
        - `clearRestriction` -> `clearHome`
        - `hasRestriction` -> `hasHome`
- `net.minecraft.world.entity.ai.attributes`
    - `AttributeInstance`
        - `save` -> `pack`、`$Packed`；不是一对一
        - `load` -> `apply`，不是一对一
    - `AttributeMap`
        - `save` -> `pack`；不是一对一
        - `load` -> `apply`，不是一对一
- `net.minecraft.world.entity.ai.behavior`
    - `AnimalPanic` 现在有接受半径或位置获取器的重载
    - `BabyFollowAdult#create` 现在返回一个 `OneShot<LivingEntity>`，并且可以接受一个 `boolean` 表示是否瞄准眼睛位置
    - `EntityTracker` 现在可以接受一个 `boolean` 表示是否瞄准眼睛位置
    - `FollowTemptation` 现在有一个重载，检查实体是否需要跟踪实体的眼睛高度。
- `net.minecraft.world.entity.ai.goal.TemptGoal` 现在有一个接受停止距离的重载
    - `mob` 现在是一个 `Mob`
    - `speedModifier` 现在是 `protected`
- `net.minecraft.world.entity.ai.memory.MemoryModuleType#NEAREST_VISIBLE_ADULT` 现在持有 `LivingEntity`
- `net.minecraft.world.entity.ai.navigation`
    - `FlyingPathNavigation`、`GroundPathNavigation#setCanOpenDoors` -> `PathNavigation#setCanOpenDoors`
- `net.minecraft.world.entity.ai.sensing.AdultSensor` 现在查找 `LivingEntity`
    - `setNearestVisibleAdult` 现在是 `protected`
- `net.minecraft.world.entity.animal.*Variants#selectVariantToSpawn` -> `entity.variant.VariantUtils#selectVariantToSpawn`，不是一对一
- `net.minecraft.world.entity.animal.Fox#isJumping` -> `LivingEntity#isJumping`
- `net.minecraft.world.entity.animal.horse.AbstractHorse`
    - `isJumping` -> `LivingEntity#isJumping`
    - `setStanding` 现在接受一个 `int` 而不是 `boolean` 作为站立计数器
        - `false` 逻辑已移至 `clearStanding`
- `net.minecraft.world.entity.monster`
    - `Ghast` 现在实现 `Mob`
        - `$GhastLookGoal` 现在是公开的，接受一个 `Mob`
        - `$GhastMoveControl` 现在是公开的，接受一个布尔值表示移动时是否应小心，以及一个提供的布尔值表示恶魂是否应停止移动
        - `$RandomFloatAroundGoal` 现在是 `public`，接受一个 `Mob` 和一个方块距离
    - `Phantom` 现在实现 `Mob`
- `net.minecraft.world.entity.player`
    - `Abilities`
        - `addSaveData` -> `pack`、`$Packed`；不是一对一
        - `loadSaveData` -> `apply`，不是一对一
    - `Player` 不再接受 `BlockPos` 和 y 旋转
- `net.minecraft.world.entity.projectile`
    - `AbstractThrownPotion#onHitAsPostion` 现在接受一个 `HitResult` 而不是可为 null 的 `Entity`
    - `EyeOfEnder#signalTo` 现在接受一个 `Vec3` 而不是 `BlockPos`
    - `Projectile`
        - `ownerUUID`、`cachedOwner` -> `owner`，现在是 protected；不是一对一
        - `setOwner` 现在有一个接受 `EntityReference` 的重载
    - `ProjectileUtil`
        - `DEFAULT_ENTITY_HIT_RESULT_MARGIN` 现在是公开的
        - `getEntityHitResult` 现在接受一个 `Projectile` 而不是 `Entity`
- `net.minecraft.world.item.ItemStack`
    - `forEachModifier` 现在接受一个提供修改器显示的 `TriConsumer`
    - `hurtAndBreak` 现在有一个重载，从 `InteractionHand` 获取 `EquipmentSlot`
- `net.minecraft.world.item.equipment.Equippable` 现在接受装备是否可以从实体上剪下以及剪下时要播放的声音
- `net.minecraft.world.level.BlockGetter`
    - `forEachBlockIntersectedBetween` 现在返回一个布尔值，表示在相交区域中访问的每个方块是否可以成功访问
    - `$BlockStepVisitor#visit` 现在返回是否可以成功移动到该位置
- `net.minecraft.world.level.block.AbstractCauldronBlock#SHAPE` 现在是 protected
- `net.minecraft.world.level.block.entity`
    - `BlockEntity#getNameForReporting` 现在是公开的
    - `SignBlockEntity#executeClickCommandsIfPresent` 现在接受一个 `ServerLevel` 而不是 `Level`，参数重新排序
    - `StructureBlockEntity#saveStructure` 现在接受一个要忽略的方块列表
- `net.minecraft.world.level.block.entity.trialspawner`
    - `TrialSpawner` 现在接受一个 `$FullConfig`
        - `getConfig` -> `activeConfig`
        - `get*Config` -> `*config`
        - `getData` -> `getStateData`
    - `TrialSpawnerData` -> `TrialSpawnerStateData`，序列化形式为 `TrialSpawnerStateData$Packed`，不是一对一
- `net.minecraft.world.level.block.sounds.AmbientDesertBlockSoundsPlayer#playAmbientBlockSounds` 已拆分为 `playAmbientSandSounds`、`playAmbientDryGrassSounds`、`playAmbientDeadBushSounds`、`shouldPlayDesertDryVegetationBlockSounds`；不是一对一
- `net.minecraft.world.level.dimension.DimensionType` 现在接受一个可选的整数表示云高度等级
- `net.minecraft.world.level.entity`
    - `PersistentEntitySectionManager#processPendingLoads` 现在是公开的
    - `UUIDLookup#getEntity` 现在可以返回 null
- `net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate#fillFromWorld` 现在接受一个要忽略的方块列表，而不是单个 `Block`
- `net.minecraft.world.level.storage.DataVersion` 现在是一个记录
- `net.minecraft.world.phys.shapes.CollisionContext#placementContext` 现在接受一个 `Player` 而不是 `Entity`

### 移除列表

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