# Minecraft 1.21.8 -> 1.21.9 模组迁移入门文档

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

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

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

感谢：

- @Soaryn 指出了一些不推荐的渲染用法
- @Deximus-Maximus 修正了一些拼写错误

## 资源包变更

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

## 调试大修

整个调试系统已被彻底改造，从暴露内部调试工具到调试屏幕。本文档旨在为处理您自己的调试屏幕和渲染器添加提供一个高层次概述。

### 调试渲染器

原版现在允许用户通过 JVM 属性启用 `-DMC_DEBUG_ENABLED` 以及其他所需标志来查看内部 API 提供的调试渲染器。用户可以利用这些暴露的功能，通过原版提供的管道来处理自己的渲染器。本概述将通过修补现有渲染器和订阅者（根据需要）进行说明，但这些通常可以在任何需要的地方设置。原版提供的好处是将其集成到现有对象（例如，实体、方块实体）以及跨网络的通用同步中。当然，您始终可以使用简单的 `boolean` 代替。毕竟，尽管 `SharedConstants` 中的标志是 final 的，但它们仍然每刻都会被检查。

#### 订阅调试器

在大多数情况下，您想要渲染和调试的信息存储在服务器端。有时，相关信息会在客户端同步，但大多数情况下，它通常是某种仅用于渲染的部分状态。

```java
// 服务器上的示例对象
public record ExampleObject(Block held, int count) {}

// 客户端上的示例
// Count 不用于渲染，仅用于服务器逻辑
public class ExampleRenderState {
    Block held;
}
```

因此，如果我们想查看来自服务器的额外数据，我们需要一种方法不仅能将其同步到客户端，还能在值发生变化时更新它。为此，原版提供了 `DebugSubscription`：一个类，用于存储同步对象所需的信息（如果它已更改）。构造函数包含两个字段：用于跨网络同步对象的 `StreamCodec`，以及一个可选的 `int`，当大于零时，如果在指定时间内没有更多更新，将从客户端清除同步的值。

为了处理与同步相关的逻辑，服务器使用 `TrackingDebugSynchronizer` 来处理玩家监听器并在必要时同步对象，并使用 `LevelDebugSynchronizers` 来处理同步器的通用跟踪和Tick。然后，这些数据被发送到 `ClientDebugSubscriber` 进行存储，并发送到 `DebugRenderer` 进行渲染。请注意，客户端只有在他们是单机世界的拥有者或服务器管理员时才能看到调试信息。此外，客户端只能请求添加到 `ClientDebugSubscriber#requestedSubscriptions` 提供的集合中的订阅。

`DebugSubscription` 必须注册到 `BuiltInRegistries#DEBUG_SUBSCRIPTION`：

```java
public static final DebugSubscription<ExampleObject> EXAMPLE_OBJECt = Registry.register(
    BuiltInRegistries.DEBUG_SUBSCRIPTION
    ResourceLocation.withNamespaceAndPath("examplemod", "example_object"),
    new DebugSubscription<>(
        // 用于同步示例对象的流编解码器
        StreamCodec.composite(
            ByteBufCodecs.registry(Registries.BLOCK), ExampleObject::block,
            ByteBufCodecs.VAR_INT, ExampleObject::count,
            ExampleObject::new
        ),
        // 更新之间的最大刻数
        //   在此之后数据将从客户端清除
        // 如果永不过期则设置为零
        0
    )
);
```

为了能够正确检查更新，所使用的对象必须正确实现 `hashCode` 和 `equals`，而不是依赖对象标识。

#### 调试源

那么，我们如何告诉同步器跟踪和更新我们的 `DebugSubscription`？您可以扩展 `TrackingDebugSynchronizer` 或其子类，并通过修补 `LevelDebugSynchronizers` 或创建自己的类来实现跟踪和同步逻辑。但是，如果您要跟踪的数据直接附加到 `LevelChunk`、`Entity` 或 `BlockEntity`，并且可以从其关联的服务器对象更新，则可以使用 `DebugValueSource`。

`DebugValueSource` 是一种将 `DebugSubscription` 注册为 `TrackingDebugSynchronizer$SourceSynchronizer` 的方法。这将每刻轮询并向每个启用订阅的跟踪源玩家发送更新。注册 `DebugSubscription` 通过 `DebugValueSource#registerDebugValues` 完成，它接受服务器等级和 `$Registration` 接口。然后通过 `$Registration#register` 传入订阅和构造订阅值的供应商来处理注册。

```java
// 假设我们在下面的类中有某个 ExampleObject exampleObject

// 对于某个 BlockEntity、Entity 或 LevelChunk 子类
@Override
public void registerDebugValues(ServerLevel level, DebugValueSource.Registration registrar) {
    super.registerDebugValues(level, registrar);
    // 注册我们的订阅
    registrar.register(
        // 订阅
        EXAMPLE_OBJECT,
        // 提供的订阅对象
        () -> this.exampleObject
    );
}
```

#### 渲染调试信息

一旦信息同步到客户端并存储在 `ClientDebugSubscriber` 中（假设您使用上述方法），我们现在需要将该信息渲染到屏幕上。这通常通过 `DebugRenderer#render` 处理，它在运行关联的渲染器之前通过 `refreshRendererList` 检查启用的调试渲染器。从技术上讲，数据在渲染过程中的任何点都可以获得，所以位置并不特别重要，但本文将假设您修补 `refreshRendererList` 以将您自己的渲染器添加到不透明或半透明渲染器中。

所有渲染器都实现 `DebugRenderer$SimpleDebugRenderer` 来调用 `render`，它提供当前的 `PoseStack`、缓冲区源、相机 XYZ 和 `Frustum`。此外，原版通过 `Connection#createDebugValueAccess` 传入一个 `DebugValueAccess`，以从 `ClientDebugSubscriber` 获取同步的调试信息。`DebugRenderer` 提供了使用 `render*` 在特定位置渲染文本或框的简单方法。

`DebugValueAccess` 包含两种类型的方法：`get*Value` 用于获取特定源（例如，位置、实体）的调试对象；以及 `forEach*`，用于遍历所有发送调试对象的源。您使用哪个取决于您将 `DebugSubscription` 注册到哪个源。

```java
// 我们将假设我们的示例对象已注册到一个实体
public class ExampleObjectRenderer implements DebugRenderer.SimpleDebugRenderer {

    @Override
    public void render(PoseStack poseStack, MultiBufferSource bufferSource, double x, double y, double z, DebugValueAccess access, Frustum frustum) {
        // 遍历所有带有我们示例对象的块
        access.forEachEntity(EXAMPLE_OBJECT, (entity, exampleObject) -> {
            // 渲染调试信息
            DebugRenderer.renderTextOverMob(
                poseStack, bufferSource, entity,
                // 文本 Y 偏移（实体显示很多信息）
                100,
                // 要渲染的文本
                "持有计数: " + exampleObject.count(),
                // 文本颜色
                0xFFFFFFFF,
                // 文本缩放
                1f
            );
        });
    }
}
```

## 调试屏幕

调试屏幕允许用户启用、禁用或仅在 F3 中显示特定组件。这个模块化系统允许模组制作者将自己的调试条目添加到屏幕中。并非本文说明的所有部分都可以在没有更多模组工作的情况下访问，因此这些区域将被特别指出。

#### `DebugScreenEntry`

每个调试选项都有自己的条目，要么定义显示的内容（例如，fps、内存），要么是无操作，由单独的实现处理（例如，实体碰撞箱、区块边界）。这被称为 `DebugScreenEntry`，它定义了三个方法。

首先是 `category`。在原版中，这几乎总是 `DebugEntryCategory#SCREEN_TEXT`，因为所有调试条目所做的就是在屏幕上绘制文本。另一个可用选项 `RENDERER` 仅用于无操作，因为渲染选项总是独立于调试屏幕渲染。`DebugEntryCategory` 只是一个带有标签和某种排序键值的记录，因此可以通过调用构造函数添加更多。该类别仅用于在调试选项屏幕中搜索。

接下来是 `isAllowed`。此方法决定调试选项是否应独立于条目状态在屏幕上渲染。默认情况下，仅当 `Minecraft#showOnlyReducedInfo` 辅助功能选项为 false 时才为 true。一些调试条目覆盖此方法以始终返回 true，或者如果某个其他检查通过。

最后是 `display` 方法。它负责使用 `DebugScreenDisplayer` 将文本绘制到屏幕。它还接受当前的 `Level`、客户端区块和服务器区块。`DebugScreenDisplayer` 有四个方法，每个方法都将文本绘制到屏幕。首先，有标准的 `addLine` 方法，它只是将字符串添加到左侧或右侧，具体取决于其渲染的元素。这些将一个接一个地出现。然后，有 `addPriorityLine`，它将始终添加到左侧或右侧的顶部。最后，有 `addToGroup`，它接受一个额外的键，将行渲染为一个单独的组，并在末尾添加一个额外的换行符。

```java
public class ExampleDebugEntry implements DebugScreenEntry {

    public static final ResourceLocation GROUP_ONE = ResourceLocation.fromNamespaceAndPath("examplemod", "group_one");
    public static final ResourceLocation GROUP_TWO = ResourceLocation.fromNamespaceAndPath("examplemod", "group_two");


    @Override
    public void display(DebugScreenDisplayer displayer, @Nullable Level level, @Nullable LevelChunk clientChunk, @Nullable LevelChunk serverChunk) {
        // 如果它是屏幕上唯一的条目，以下将显示如下：
        // 左侧第一！                                                右侧第一！
        // 
        // 世界你好！                                                随机文本！
        // 洛雷姆·伊普苏姆。
        //                                                            我是另一个组！
        // 我是一个组                                                这将出现在没有换行符之后！
        // 全部排成一行
        // 以列表形式提供。
        //

        displayer.addLine("世界你好！");
        displayer.addLine("洛雷姆·伊普苏姆。");
        displayer.addLine("随机文本！");

        // 这些将首先显示
        displayer.addPriorityLine("左侧第一！");
        displayer.addPriorityLine("右侧第一！");

        // 这些将根据键单独分组
        displayer.addToGroup(GROUP_ONE, List.of(
            "我是一个组",
            "全部排成一行",
            "以列表形式提供。"
        ));

        displayer.addToGroup(GROUP_TWO, "我是另一个组！");
        displayer.addToGroup(GROUP_TWO, "这将出现在没有换行符之后！");
    }

    @Override
    public boolean isAllowed(boolean reducedDebugInfo) {
        // 无论辅助功能选项如何，始终显示
        return true;
    }
}
```

然后，只需将您的条目注册到 `DebugScreenEntries` 即可显示。可以通过调试菜单使用提供的键进行切换。

```java
// 此方法是私有的，因此需要扩宽其访问权限
DebugScreenEntries.register(
    // id，这将显示在选项屏幕上
    ResourceLocation.fromNamespaceAndPath("examplemod", "example_entry"),
    // 屏幕条目
    new ExampleScreenEntry();
);
```

#### 外部切换和检查

如果您想从选项菜单单独切换活动状态怎么办？如果您想检查条目是否已启用以在游戏中显示调试数据怎么办？这可以通过 `Minecraft` 实例访问 `DebugScreenEntryList` 来完成。

切换当前状态可以通过 `DebugScreenEntryList#toggleStatus` 完成。其行为取决于当前活动的屏幕。基本上，调用 toggle 将始终翻转调试条目的开关：如果它当前不在屏幕上，它将在屏幕上渲染，反之亦然。如果在 F3 中，那么 toggle on 将仅在 F3 打开时渲染该调试条目。

然后可以使用 `DebugScreenEntryList#isCurrentlyEnabled` 检查条目的状态。这将仅检查调试屏幕是否在当前打开的列表中，而不检查 `DebugScreenEntry#isAllowed`。

```java
// 让我们创建另一个条目
public static final ResourceLocation EXAMPLE_TOGGLE = DebugScreenEntries.register(
    ResourceLocation.fromNamespaceAndPath("examplemod", "example_toggle"),
    // 我们使用无操作，因为没有文本显示
    new DebugEntryNoop();
);

// 切换：
Minecraft.getInstance().debugEntries.toggleStatus(EXAMPLE_TOGGLE);

// 检查是否启用：
if (Minecraft.getInstance().debugEntries.isCurrentlyEnabled(EXAMPLE_TOGGLE)) {
    // ...
}
```

#### 配置文件

配置文件是根据用户意愿配置的预定义预设。目前，配置文件被硬编码为默认或性能。要扩展系统，您需要能够动态地向 `DebugScreenProfile` 枚举添加条目，使 `DebugScreenEntries#PROFILES` 映射可变以添加您的配置文件和预设，并使用您的配置文件按钮修改调试选项屏幕。

- `net.minecraft.SharedConstants`
    - `DEBUG_SHUFFLE_MODELS` - 一个可能打乱模型加载顺序的标志。
    - `DEBUG_FLAG_PREFIX` - 放在每个调试标志前面的前缀。
    - `USE_DEBUG_FEATURES` -> `DEBUG_ENABLED`
    - `DEBUG_RENDER` 已移除
    - `DEBUG_WORLDGENATTEMPT` 已移除
    - `debugGenerateStripedTerrainWithoutNoise` 已移除
    - `DEBUG_RESOURCE_GENERATION_OVERRIDE` 已移除
    - `DEBUG_POI` - 启用 POI 调试渲染器。
    - `DEBUG_PANORAMA_SCREENSHOT` - 启用时，允许用户拍摄全景截图。
    - `DEBUG_CHASE_COMMAND` - 启用时，添加 chase 命令。
    - `FAKE_MS_LATENCY` -> `DEBUG_FAKE_LATENCY_MS`
    - `FAKE_MS_JITTER` -> `DEBUG_FAKE_JITTER_MS`
    - `DEBUG_VERBOSE_COMMAND_ERRORS` - 启用时，通过聊天框输出详细错误。
    - `DEBUG_DEV_COMMANDS` - 启用时，添加用于调试游戏的命令。
- `net.minecraft.client.Minecraft`
    - `debugEntries` - 返回一个调试功能列表以及应在屏幕上显示的内容。
    - `fpsString`、`sectionPath`、`sectionVisibility` 已移除
    - `debugRenderer` -> `LevelRenderer#debugRenderer`
- `net.minecraft.client.gui.Gui`
    - `renderDebugOverlay` 现在是公开的
    - `shouldRenderDebugCrosshair` 已移除
- `net.minecraft.client.gui.components.DebugScreenOverlay`
    - `drawGameInformation`、`drawSystemInformation` 已移除
    - `getGameInformation`、`getSystemInformation` 已移除
    - `toggleOverlay` 已移除
- `net.minecraft.client.gui.components.debug`
    - `DebugEntryBiome` - 一个显示相机实体所在生物群系的调试条目。
    - `DebugEntryCategory` - 一个描述调试条目如何显示的类别。
    - `DebugEntryChunkGeneration` - 一个显示当前区块生成信息的调试条目。
    - `DebugEntryChunkRenderStats` - 一个显示当前区块统计信息的调试条目。
    - `DebugEntryChunkSourceStats` - 一个显示区块源通用元数据的调试条目。
    - `DebugEntryEntityRenderStats` - 一个显示实体存储通用元数据的调试条目。
    - `DebugEntryFps` - 一个显示每秒帧数和垂直同步信息的调试条目。
    - `DebugEntryGpuUtilization` - 一个显示 GPU 利用率的调试条目。
    - `DebugEntryHeightmap` - 一个显示当前位置高度图的调试条目。
    - `DebugEntryLight` - 一个显示客户端光照信息的调试条目。
    - `DebugEntryLocalDifficulty` - 一个显示当前世界难度和时间的调试条目。
    - `DebugEntryLookingAtBlock` - 一个显示相机当前正在查看的方块的调试条目。
    - `DebugEntryLookingAtEntity` - 一个显示相机当前正在查看的实体的调试条目。
    - `DebugEntryLookingAtFluid` - 一个显示相机当前正在查看的流体的调试条目。
    - `DebugEntryMemory` - 一个显示游戏分配和使用的内存的调试条目。
    - `DebugEntryNoop` - 一个不显示任何内容的调试条目。
    - `DebugEntryParticleRenderState` - 一个显示正在渲染的粒子数量的调试条目。
    - `DebugEntryPosition` - 一个显示相机实体的当前位置和旋转的调试条目。
    - `DebugEntryPostEffect` - 一个显示当前应用的后处理效果的调试条目。
    - `DebugEntrySectionPosition` - 一个显示当前部分位置的调试条目。
    - `DebugEntrySimplePerformanceImpactors` - 一个显示图形模式、云状态和生物群系混合半径的调试条目。
    - `DebugEntrySoundMood` - 一个显示当前播放的声音和玩家情绪的调试条目。
    - `DebugEntrySpawnCounts` - 一个显示每个生物类别的实体生成数量的调试条目。
    - `DebugEntrySystemSpecs` - 一个显示运行机器规格的调试条目。
    - `DebugEntryTps` - 一个显示通用每秒刻数的调试条目。
    - `DebugEntryVersion` - 一个显示当前 Minecraft 版本的调试条目。
    - `DebugScreenDisplayer` - 一个接口，调试条目使用它来将元素显示到屏幕。
    - `DebugScreenEntries` - Minecraft 注册的调试条目。
    - `DebugScreenEntry` - 一个元素，如果启用，则在调试覆盖层启用时显示。
    - `DebugScreenEntryList` - 有关在屏幕上显示哪些调试元素的选项信息。
    - `DebugScreenEntryStatus` - 调试条目应显示的状态。
    - `DebugScreenProfile` - 一个枚举，表示调试屏幕在决定显示哪些条目时可以设置的配置文件。
- `net.minecraft.client.gui.screen.debug.DebugOptionsScreen` - 一个允许用户更改配置文件的显示调试条目的屏幕。
- `net.minecraft.client.renderer.LevelRenderer`
    - `getSectionStatistics` 现在可为 null
    - `getEntityStatistics` 现在可为 null
    - `gameTestBlockHighlightRenderer` - 游戏测试中方块高亮的渲染器。
- `net.minecraft.client.renderer.debug.DebugRenderer`
    - `switchRenderChunkborder` -> `DebugScreenEntries#CHUNK_BORDERS`，不是一对一
    - `toggleRenderOctree` -> `DebugScreenEntries#CHUNK_SECTION_OCTREE`，不是一对一
- `net.minecraft.client.multiplayer`
    - `DebugSampleSubscriber` -> `ClientDebugSubscriber`，不是一对一
    - `ClientPacketListener#createDebugValueAccess` - 创建用于获取当前调试值的访问器。
- `net.minecraft.client.renderer.debug`
    - `BeeDebugRenderer#addOrUpdateHiveInfo`、`addOrUpdateBeeInfo`、`removeBeeInfo` 已移除
    - `BrainDebugRenderer`
        - `addPoi`、`removePoi`、`$PoiInfo` 已移除
        - `setFreeTicketCount` 已移除
        - `addOrUpdateBrainDump`、`removeBrainDump` 已移除
    - `BreezeDebugRenderer` 现在实现 `DebugRenderer$SimpleDebugRenderer`
        - `render` 现在接受一个 `DebugValueAccess`
        - `clear`、`add` 已移除
    - `DebugRenderer` 不再接受 `Minecraft` 实例
        - 所有字段渲染器已从公共访问中移除，而是存储在某个 `*Renderers` 列表中
        - `worldGenAttemptRenderer` 已移除
        - `renderTextOverBlock` - 在提供的方块位置上方渲染给定的流。
        - `renderTextOverMob` - 在提供的实体上方渲染给定的字符串。
        - `refreshRendererList` - 使用启用的调试渲染器填充渲染器列表。
        - `render`、`renderAfterTranslucents` 已合并到 `render` 中，其中 `boolean` 决定是渲染半透明还是不透明的渲染器
        - `$SimpleDebugRenderer`
            - `render` 现在接受一个 `DebugValueAccess` 和 `Frustum`
            - `clear` 已移除
    - `EntityBlockIntersectionDebugRenderer` - 一个用于显示实体相交的方块的调试渲染器。
    - `GameEventListenerRenderer` 不再接受 `Minecraft` 实例
        - `trackGameEvent`、`trackListener` 已移除
    - `GameTestDebugRenderer` -> `GameTestBlockHighlightRenderer`，不是一对一
        - `addMarker` -> `highlightPos`，不是一对一
    - `GoalSelectorDebugRenderer#addGoalSelector`、`removeGoalSelector` 已移除
    - `NeighborsUpdateRenderer` 不再接受 `Minecraft` 实例
        - `addUpdate` 已移除
    - `OctreeDebugRenderer` 现在实现 `DebugRenderer$SimpleDebugRenderer`
    - `PathfindingRenderer#addPath` 已移除
    - `PoiDebugRenderer` - 一个用于显示兴趣点的调试渲染器。
    - `RaidDebugRenderer#setRaidCenters` 已移除
    - `RedstoneWireOrientationsRenderer` 不再接受 `Minecraft` 实例
        - `addWireOrientation` 已移除
    - `StructureRenderer` 不再接受 `Minecraft` 实例
        - `addBoundingBox` 已移除
    - `VillagerSectionsDebugRenderer#setVillageSection`、`setNotVillageSection` 已移除
    - `WorldGenAttemptRenderer` 类已移除
- `net.minecraft.core.registries.BuiltInRegistries`、`Registries#DEBUG_SUBSCRIPTION` - 调试处理程序订阅的注册表。
- `net.minecraft.gametest.framework`
    - `GameTestAssertPosException#getMessageToShowAtBlock` 现在返回一个 `Component`
    - `GameTestRunner#clearMarkers` 已移除
- `net.minecraft.network.protocol.common.custom`
    - 所有类已移至 `net.minecraft.util.debug`
    - 它们不再是有效负载，而是仅包含对象信息和关联流编解码器的记录
    - 如果有效负载类有一个关联的内部对象类，则该类被移动，有效负载类被移除
    - 否则，有效负载类被添加，没有 `*Payload` 后缀，大多数情况下带有 `*Info` 后缀
- `net.minecraft.network.protocol.game`
    - `ClientboundDebugBlockValuePacket` - 发送到客户端的数据包，关于方块位置上的调试值更改。
    - `ClientboundDebugChunkValuePacket` - 发送到客户端的数据包，关于区块位置上的调试值更改。
    - `ClientboundDebugEntityValuePacket` - 发送到客户端的数据包，关于实体上的调试值更改。
    - `ClientboundDebugEventPacket` - 发送到客户端的数据包，关于触发的调试事件。
    - `ClientboundGameTestHighlightPosPacket` - 发送到客户端的数据包，关于要高亮的游戏测试位置。
    - `ClientGamePacketListener`
        - `handleDebugChunkValue` - 处理调试区块位置数据包。
        - `handleDebugBlockValue` - 处理调试方块位置数据包。
        - `handleDebugEntityValue` - 处理调试实体数据包。
        - `handleDebugEvent` - 处理触发的调试事件。
        - `handleGameTestHighlightPos` - 处理提供的高亮位置。
    - `DebugPackets` 类已移除
    - `ServerboundDebugSampleSubscriptionPacket` -> `ServerboundDebugSubscriptionRequestPacket`，不是一对一
    - `ServerGamePacketListener#handleDebugSampleSubscription` -> `handleDebugSubscriptionRequest`，不是一对一
- `net.minecraft.server.MinecraftServer`
    - `subscribeToDebugSample` 已移除
    - `debugSubscribers` - 返回已跟踪订阅到已启用它的玩家列表的映射。
- `net.minecraft.server.level`
    - `ChunkMap`
        - `isChunkTracked` 现在是公开的
        - `getChunks` 已移除
    - `ServerLevel#debugSynchronizers` - 返回等级的调试器处理程序和同步器。
    - `ServerPlayer`
        - `requestDebugSubscriptions` - 设置玩家正在监听的调试器。
        - `debugSubscriptions` - 返回玩家正在监听的调试器。
- `net.minecraft.util.debug`
    - `DebugSubscription` - 一个可以监听或订阅的跟踪数据点。
    - `DebugSubscriptions` - 原版调试订阅。
    - `DebugValueAccess` - 访问调试订阅跟踪的值，在客户端上用于调试渲染器。
    - `DebugValueSource` - 定义一个提供要跟踪的调试值的源对象，例如一个实体。
    - `LevelDebugSynchronizers` - 处理将订阅数据通过网络发送到跟踪客户端。
    - `ServerDebugSubscribers` - 处理订阅了当前启用订阅的玩家的全局状态。
    - `TrackingDebugSynchronizer` - 处理订阅了某个订阅的玩家列表。
- `net.minecraft.util.debugchart`
    - `DebugSampleSubscriptionTracker` 类已移除
    - `RemoteDebugSampleType` 现在接受一个 `DebugSubscription`
        - `subscription` - 返回样本类型报告的订阅。
    - `RemoteSampleLogger` 现在接受 `ServerDebugSubscribers` 而不是 `DebugSampleSubscriptionTracker`
- `net.minecraft.world.entity`
    - `Entity` 现在实现 `DebugValueSource`
    - `Mob#sendDebugPackets` 已移除
- `net.minecraft.world.entity.ai.village.poi`
    - `PoiManager#getFreeTickets` -> `getDebugPoiInfo`，不是一对一
    - `PoiSection#getDebugPoiInfo` - 返回给定位置的调试 POI 信息。
- `net.minecraft.world.level.block.entity`
    - `BlockEntity` 现在实现 `DebugValueSource`
    - `TestInstanceBlockEntity#markError`、`clearErrorMarkers`、`getErrorMarkers`、`$ErrorMarker` - 处理测试实例设置的错误标记。
- `net.minecraft.world.level.chunk.LevelChunk` 现在实现 `DebugValueSource`
- `net.minecraft.world.level.pathfinder.PathFinder#setCaptureDebug` - 设置是否应捕获路径以进行调试。
- `net.minecraft.world.level.redstone.CollectingNeighborUpdater#setDebugListener` - 设置用于调试的方块位置更改的监听器。

## 功能提交：电影版

整个渲染管线，从实体到方块实体再到粒子，已被重做为称为“功能”的提交/渲染阶段系统。本指南将介绍功能系统的基础知识，然后介绍如何使用它实现每种主要类型。

### 提交与渲染

功能系统，就像 GUI 一样，分为两个阶段：提交和渲染。提交阶段由 `SubmitNodeCollector` 处理，它基本上收集将对象抽象渲染到屏幕所需的数据。这一切都是通过 `submit*` 方法完成的，这些方法通常接受一个 `PoseStack` 来将对象放置在 3D 空间中，以及任何其他所需的数据，如模型、状态、渲染类型等。

以下是每个方法接受的参数的快速概述：

方法                 | 参数
:---------------------:|:----------
`submitHitbox`         | 一个姿势堆栈、实体的渲染状态和碰撞箱渲染状态
`submitShadow`         | 一个姿势堆栈、阴影半径和阴影碎片
`submitNameTag`        | 一个姿势堆栈、一个可选位置、Y 偏移、文本组件、文本是否应透明（如潜行时）、光照坐标和相机渲染状态
`submitText`           | 一个姿势堆栈、XY 偏移、文本序列、是否添加阴影、字体显示模式、光照坐标、颜色、背景颜色和轮廓颜色
`submitFlame`          | 一个姿势堆栈、实体的渲染状态和一个旋转四元数
`submitLeash`          | 一个姿势堆栈和拴绳状态
`submitModel`          | 一个姿势堆栈、实体模型、渲染状态、渲染类型、光照坐标、覆盖坐标、色调颜色、一个可选纹理、轮廓颜色和一个可选的破碎覆盖
`submitModelPart`      | 一个姿势堆栈、模型部件、渲染类型、光照坐标、覆盖坐标、一个可选纹理、如果渲染类型不透明则是否对物品使用闪光而非实体闪光、是否渲染闪光覆盖、色调颜色、一个可选的破碎覆盖和轮廓颜色
`submitBlock`          | 一个姿势堆栈、方块状态、光照坐标、覆盖坐标和轮廓颜色
`submitMovingBlock`    | 一个姿势堆栈和移动方块的渲染状态
`submitBlockModel`     | 一个姿势堆栈、渲染类型、方块状态模型、RGB 浮点数、光照坐标、覆盖坐标和轮廓颜色
`submitItem`           | 一个姿势堆栈、物品显示上下文、光照坐标、覆盖坐标、轮廓颜色、色调层、四边形、渲染类型和闪光类型
`submitCustomGeometry` | 一个姿势堆栈、渲染类型和一个接受当前姿势和 `VertexConsumer` 以创建网格的函数
`submitParticleGroup`  | 一个 `SubmitNodeCollector$ParticleGroupRenderer`

从技术上讲，`submit*` 方法由 `OrderedSubmitNodeCollector` 提供，`SubmitNodeCollector` 扩展了它。这是因为功能可以提交到不同的顺序，其功能类似于 GUI 中的层（strata）。默认情况下，所有提交调用都被推送到顺序 0。使用 `SubmitNodeCollector#order` 加上某个整数，然后调用 `submit*` 方法，您可以让一个对象在给定顺序上的所有功能之前或之后渲染。这存储为一个 AVL 树，其中每个顺序的数据存储在一个 `SubmitNodeCollection` 中。使用当前的默认功能渲染顺序，这仅在非常特定的情况下使用，例如渲染史莱姆的外层身体或装备层。

```java
// 假设我们可以访问 `SubmitNodeCollector` collector

// 这将在顺序 0 中渲染
collector.submitModel(...);

// 这将在 `submitModel` 调用之前渲染
collector.order(-1).submitShadow(...);

// 这将在 `submitModel` 调用之后渲染
collector.order(1).submitNameTag(...);
```

渲染阶段由 `FeatureRenderDispatcher` 处理，它使用其提交的功能渲染器渲染对象。什么是功能渲染器？实际上就是一个任意方法，它遍历它将推送到缓冲区的节点内容。目前，对于给定的顺序，功能按如下方式推送其顶点：阴影、模型、模型部件、火焰动画、实体名称标签、任意文本、碰撞箱、拴绳、物品、方块、自定义渲染管线，最后是粒子。每个顺序，从最小数字到最大数字，将重新运行所有功能渲染，直到到达树的末尾。然后所有提交将被清除以供下次使用。

大多数功能分派器只是对其集合运行一个循环。那些存储渲染类型的会将渲染调用批处理到一个缓冲区。同时，`ModelFeatureRenderer` 更进一步，将其半透明模型按距离相机的距离排序，并在所有不透明模型之后将它们发送到缓冲区。

### 实体模型

那么，这如何影响实体？让我们从构成所有实体模型的根 `Model` 开始。`Model` 现在有一个泛型，用于将支持对象的状态传递给 `setupAnim`，该方法也已移至 `Model`。这意味着基本模型类很少被传递，而是选择某个子类型，例如用于告示牌的 `Model$Simple`。鉴于大多数 `EntityModel` 已经需要 `EntityRenderState` 的泛型，这不会影响任何东西。

主要变化来自模型部件可见性的工作方式，例如盔甲和披风。每一个单独的部件（例如，头盔、胸甲）现在都有自己独立的模型，这意味着通用的部件可见性系统已被完全移除。您仍然可以在 `setupAnim` 中通过可变的模型部件提供可见性，但通常的做法是简单地将应该分开的模型部件作为单独的模型。

为了促进这一点，`PartDefinition` 现在有一些方法可以选择性地保留模型的某些部分并移除其他部分。这是通过 `clear*` 和 `retain*` 方法完成的。基本上，所有这些方法所做的就是保留部件姿势，同时移除与子查询关联的任何立方体。`retain*` 允许某些部分和可能的子部分保留它们的立方体。这一增加提供了双重好处：模型层可以确定性地使用 `setupAnim` 以与基础模型类似的方式设置部件，并且模型纹理将只需要包含保留的元素。

以下是为苦力怕创建盔甲模型的示例：

```java
// 人形盔甲的变形
private static final CubeDeformation OUTER_ARMOR_DEFORMATION = new CubeDeformation(1.0F);
private static final CubeDeformation INNER_ARMOR_DEFORMATION = new CubeDeformation(0.5F);

// 苦力怕有以下部分：
// - head
// - body
// - right_hind_leg, left_hind_leg
// - right_front_leg, left_front_leg

// 我们使用单独的网格，因为我们基本上要隔离我们想要保留在每一个中的部分

public static ArmorModelSet<MeshDefinition> createCreeperArmor() {
    // 头盔

    // 创建网格
    MeshDefinition helmetMesh = CreeperModel.createBodyLayer(OUTER_ARMOR_DEFORMATION);
    // 仅保留所需部分
    // 注意 body 和腿仍然存在，它们只是没有立方体
    helmetMesh.getRoot().retainExactParts(Set.of("head"));

    // 胸甲

    // 创建网格
    var chestplateMesh = CreeperModel.createBodyLayer(OUTER_ARMOR_DEFORMATION);
    // 仅保留所需部分
    chestplateMesh.getRoot().retainExactParts(Set.of("body"));

    // 护腿

    // 创建网格
    var leggingsMesh = CreeperModel.createBodyLayer(INNER_ARMOR_DEFORMATION);
    // 仅保留所需部分
    leggingsMesh.getRoot().retainExactParts(Set.of("right_hind_leg", "left_hind_leg", "right_front_leg", "left_front_leg"));

    // 靴子

    // 创建网格
    var bootsMesh = CreeperModel.createBodyLayer(OUTER_ARMOR_DEFORMATION);
    // 仅保留所需部分
    bootsMesh.getRoot().retainExactParts(Set.of("right_hind_leg", "left_hind_leg", "right_front_leg", "left_front_leg"));

    // 将所有内容存储在 ArmorModelSet 中，基本上只是一个对象持有者和映射器
    return new ArmorModelSet<>(
        helmetMesh,
        chestplateMesh,
        leggingsMesh,
        bootsMesh
    );
}

// 要注册层定义，基本上使用 ArmorModelSet 的相同过程
public static final ArmorModelSet<ModelLayerLocation> CREEPER_ARMOR = new ArmorModelSet<>(
    new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "creeper"), "helmet"),
    new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "creeper"), "chestplate"),
    new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "creeper"), "leggings"),
    new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "creeper"), "boots")
);

// 在某个可以访问 Map<ModelLayerLocation, LayerDefinition> builder 的方法中
ArmorModelSet<LayerDefinition> creeperArmorLayers = createCreeperArmor().map(mesh -> LayerDefinition.create(mesh, 64, 32));
CREEPER_ARMOR.putFrom(creeperArmorLayers, builder);
```

### 实体渲染器

随着提交的更改，`EntityRenderer` 及其关联的 `RenderLayer` 也发生了变化。基本上，您可以假设几乎所有带有 `render` 一词的方法都已更改为 `submit`，并且 `MultiBufferSource` 和光照坐标整数通常已被 `SubmitNodeCollector` 和关联的实体渲染状态取代。

在 `EntityRenderer` 中替换 `render` 的新 `submit` 方法现在接受实体的渲染状态、`PoseStack`、`SubmitNodeCollector` 和 `CameraRenderState`。提交任何元素时，3D 空间中的位置通过获取 `PoseStack` 上的最后一个姿势并将其存储以供将来使用。

```java
// 一个基本的实体渲染器

// 我们将假设所有列出的类都存在
public class ExampleEntityRenderer extends MobRenderer<ExampleEntity, ExampleEntityRenderState, ExampleModel> {

    public ExampleEntityRenderer(EntityRendererProvider.Context ctx) {
        super(ctx, ctx.bakeLayer(EXAMPLE_MODEL_LAYER), 0.5f);
    }

    @Override
    public void submit(ExampleEntityRenderState renderState, PoseStack poseStack, SubmitNodeCollector collector, CameraRenderState cameraState) {
        super.submit(renderState, poseStack, collector, cameraState);

        // 提交某些内容的示例
        collector.submitCustomGeometry(
            poseStack, // 当前姿势
            RenderType.solid(), // 要使用的渲染类型
            ExampleEntityRenderer::addVertices // 写入几何数据的方法
        );
    }

    private static void addVertices(PoseStack.Pose pose, VertexConsumer consumer) {
        // 添加自定义几何体
    }
}

// 一个渲染层

public class CreeperArmorLayer extends RenderLayer<CreeperRenderState, CreeperModel> {

    private final ArmorModelSet<CreeperModel> modelSet;
    private final EquipmentLayerRenderer equipment;

    public CreeperArmorLayer(RenderLayerParent<CreeperRenderState, CreeperModel> parent, ArmorModelSet<CreeperModel> modelSet, EquipmentLayerRenderer equipment) {
        super(parent);
        this.modelSet = modelSet;
        this.equipment = equipment;
    }

    // 我们将假设我们以某种方式向 CreeperRenderState 添加了 headEquipment、chestEquipment、legsEquipment、feetEquipment
    @Override
    public void submit(PoseStack poseStack, SubmitNodeCollector collector, int lightCoords, CreeperRenderState renderState, float yRot, float xRot) {
        this.renderArmorPiece(poseStack, collector, renderState.chestEquipment, EquipmentSlot.CHEST, lightCoords, renderState);
        this.renderArmorPiece(poseStack, collector, renderState.legsEquipment,  EquipmentSlot.LEGS,  lightCoords, renderState);
        this.renderArmorPiece(poseStack, collector, renderState.feetEquipment,  EquipmentSlot.FEET,  lightCoords, renderState);
        this.renderArmorPiece(poseStack, collector, renderState.headEquipment,  EquipmentSlot.HEAD,  lightCoords, renderState);
    }

    // 取自人形盔甲层
    private void renderArmorPiece(PoseStack poseStack, SubmitNodeCollector collector, ItemStack stack, EquipmentSlot slot, int lightCoords, CreeperRenderState renderState) {
        Equippable equippable = stack.get(DataComponents.EQUIPPABLE);
        if (equippable != null && equippable.assetId().isPresent() && equippable.slot() == slot) {
            CreeperModel model = this.modelSet.get(slot);
            EquipmentClientInfo.LayerType layer = slot == EquipmentSlot.LEGS
                ? EquipmentClientInfo.LayerType.HUMANOID_LEGGINGS
                : EquipmentClientInfo.LayerType.HUMANOID;
            this.equipmentRenderer.renderLayers(
                layer, // 要使用的装备层
                equippable.assetId().orElseThrow(), // 要拉取的装备资源
                model, // 盔甲模型
                renderState, // 实体渲染状态
                stack, // 盔甲堆栈
                poseStack, // 姿势堆栈
                collector, // 用于添加模型数据的收集器
                lightCoords, // 光照坐标
                renderState.outlineColor // 实体的轮廓颜色
            );
        }
    }
}

// 然后，将其添加到苦力怕渲染器的构造函数中
public CreeperRenderer(EntityRendererProvider.Context ctx) {
    // ...
    this.addLayer(new CreeperArmorLayer(
        this, // 父级是渲染器本身
        ArmorModelSet.bake( // 烘焙模型集
            CREEPER_ARMOR, // 模型层位置
            ctx.getModelSet(), // 用于从层位置映射模型的模型集
            CreeperModel::new // 根部件到模型的映射器
        ),
        ctx.getEquipmentRenderer() // 装备的渲染器
    ));
}
```

### 方块实体渲染器

`BlockEntityRenderer` 也使用新的提交方法，几乎将所有 `render*` 替换为 `submit`。它们借鉴了实体的做法，现在有自己的 `BlockEntityRenderState`，从 `BlockEntity` 中提取。因此，`BlockEntityRenderer` 现在有一个新的泛型 `S`，表示 `BlockEntityRenderState`。

默认情况下，`BlockEntityRenderState` 包含关于其位置、方块状态、类型、光照坐标以及作为 `ModelFeatureRenderer$CrumblingOverlay` 的当前破坏进度的信息。这些信息都通过 `BlockEntityRenderState#extractBase` 填充，该方法在 `BlockEntityRenderer#extractRenderState` 中调用。与实体一样，渲染状态首先通过 `BlockEntityRenderer#createRenderState` 构造，然后从方块实体中提取值。`extractRenderState` 确实包含部分刻和相机位置，但默认情况下不会传递给 `BlockEntityRenderState`。

因此，接管 `render` 方法的 `submit` 方法接受渲染状态、用于 3D 空间位置的 `PoseStack`、用于推送要渲染的元素的 `SubmitNodeCollector` 以及 `CameraRenderState`。

```java
// 我们将假设所有未在此处指定的类都存在

// 一个简单的渲染状态
public class ExampleRenderState extends BlockEntityRenderState {
    public float partialTick;
}

// 一个基本的方块实体渲染器
public class ExampleBlockEntityRenderer implements BlockEntityRenderer<ExampleBlockEntity, ExampleRenderState> {

    public ExampleBlockEntityRenderer(BlockEntityRendererProvider.Context ctx) {
        // 从上下文中获取任何需要的内容
    }

    @Override
    public ExampleRenderState createRenderState() {
        // 创建用于将方块实体提交到功能渲染器的渲染状态
        return new ExampleRenderState();
    }

    @Override
    public void extractRenderState(ExampleBlockEntity blockEntity, ExampleRenderState renderState, float partialTick, Vec3 cameraPos, @Nullable ModelFeatureRenderer.CrumblingOverlay crumblingOverlay) {
        // 从方块实体中提取必要的渲染值到渲染状态
        // 始终调用 super 或 BlockEntityRenderState#extractBase
        super.extractRenderState(blockEntity, renderState, partialTick, cameraPos, crumblingOverlay);

        // 填充任何所需的值
        renderState.partialTick = partialTick;
    }


    @Override
    public void submit(ExampleRenderState renderState, PoseStack poseStack, SubmitNodeCollector collector, CameraRenderState cameraState) {
        // 提交某些内容的示例
        collector.submitModel(..., renderState.breakProgress);
    }
}
```

### 特殊物品模型

由于特殊物品模型也使用自定义渲染，它们已更新为 `submit` 更改，仅将 `MultiBufferSource` 替换为 `SubmitNodeCollector`。

```java
// 一个基本的特殊物品模型

// 我们将假设所有列出的类都存在
public class ExampleSpecialModelRenderer implements NoDataSpecialModelRenderer {

    public ExampleSpecialModelRenderer() {}

    @Override
    public void submit(ItemDisplayContext displayContext, PoseStack poseStack, SubmitNodeCollector collector, int lightCoords, int overlayCoords, boolean hasFoil, int outlineColor) {
        // 提交某些内容的示例
        collector.submitModelPart(...);
    }

    @Override
    public void getExtents(Set<Vector3f> extents) {}
}
```

### 粒子

粒子已被添加到提交过程中；然而，根据粒子的复杂程度，有多条路径。一些类和通用名称也被重用于额外的目的，有时使理解每个部分的工作原理变得困难。因此，本文档将介绍两种创建粒子的方法：一种更熟悉旧系统，另一种从头开始解释底层细微差别。

#### 引擎和资源的分离

在我们讨论这两种方法之前，首先，让我们了解总体变化。`ParticleEngine` 在功能上被拆分为两个类：`ParticleEngine`，负责处理实际的Tick和提取（而不是提交）渲染状态；以及 `ParticleResources`，它是注册 `ParticleProvider` 和可选的 `ParticleResources$SpriteParticleRegistration` 并从其 `ParticleDescription` 重新加载 `SpriteSet` 的重载监听器。这种底层行为没有改变（除了整个提取和提交过程），方法只是被移动了。

`ParticleProvider#createParticle` 现在也提供了一个 `RandomSource`，可以根据需要使用。

至于实际的提交和渲染过程，这由 `ParticleEngine` 之外处理。更具体地说，`LevelRenderer` 通过 `ParticleEngine#extract` 将所有粒子提取到 `ParticlesRenderState` 中。然后，在 `LevelRenderer#addParticlesPass` 中，资源句柄被设置到粒子的 `FramePass`，在执行时，粒子通过 `ParticlesRenderState#submit` 提交，然后通过 `ParticleFeatureRenderer` 通过功能分派器渲染。

#### 单个四边形

旧系统中的许多粒子仅仅是由一个带有纹理的单个四边形组成。这些粒子是 `SingleQuadParticle`，它将之前的 `SingleQuadParticle` 和 `TextureSheetParticle` 合并为一个。`SingleQuadParticle` 现在接受一个初始的 `TextureAtlasSprite` 来设置第一个纹理，然后可以通过覆盖 `Particle#tick` 并调用 `SingleQuadParticle#setSpriteFromAge` 来更新 `SpriteSet`，或者直接使用 `setSprite` 来更新。色调也可以在Tick中使用 `setColor` 和 `setAlpha` 修改。有些也在 `SingleQuadParticle#extract` 中直接设置，但使用哪个取决于您是否需要覆盖整个Tick。

要确定用于渲染四边形的 `RenderType`，必须将 `SingleQuadParticle#getLayer` 设置为所需的 `$Layer`。`$Layer` 基本上是一个记录，定义四边形是否可以具有半透明、它从哪个纹理图集拉取以及要使用的渲染管线。原版提供了类似于旧 `Particle#getRenderType` 的 `TERRAIN`、`OPAQUE` 和 `TRANSLUCENT`，它取代了这些。`TERRAIN` 和 `TRANSLUCENT` 都允许透明度，`OPAQUE` 和 `TRANSLUCENT` 从粒子图集拉取，而 `TERRAIN` 使用方块图集。可以使用构造函数创建自定义的 `$Layer`。

```java
public static final SingleQuadParticle.Layer EXAMPLE_LAYER = new SingleQuadParticle.Layer(true, TextureAtlas.LOCATION_PARTICLES, RenderPipelines.WEATHER_DEPTH_WRITE);
```

除此之外，您还可以通过覆盖 `SingleQuadParticle#getFacingCameraMode` 来设置粒子的旋转方式。`$FacingCameraMode` 是一个函数式接口，在提取粒子时设置粒子的旋转。默认情况下，这意味着纹理将始终面向相机。任何其他方法的更改和添加都在下面的列表中。

从那里开始，创建 `ParticleProvider` 并注册它的所有其他内容都是相同的。

```java
// 我们将假设我们的粒子有某个 SimpleParticleType EXAMPLE_QUAD
// 此外，我们将假设有某个粒子描述，其中包含要使用的纹理
public class ExampleQuadParticle extends SingleQuadParticle {

    private final SpriteSet spriteSet;

    // 这可以是包私有、受保护或公开的
    // 如果粒子将在提供者之外构造，则应使用公开
    ExampleQuadParticle(ClientLevel level, double x, double y, double z, SpriteSet spriteSet) {
        // 我们使用 first 来设置初始粒子纹理
        super(level, x, y, z, spriteSet.first());
    }

    @Override
    public void tick() {
        super.tick();
        // 更新粒子图像
        this.setSpriteFromAge(spriteSet);
    }

    @Override
    public SingleQuadParticle.Layer getLayer() {
        return EXAMPLE_LAYER;
    }

    // 创建提供者
    public static class Provider implements ParticleProvider<SimpleParticleType> {

        private final SpriteSet spriteSet;

        public Provider(SpriteSet spriteSet) {
            this.spriteSet = spriteSet;
        }

        @Override
        public Particle createParticle(SimpleParticleType options, ClientLevel level, double x, double y, double z, double xd, double yd, double zd, RandomSource random) {
            // 创建粒子
            return new ExampleQuadParticle(level, x, y, z, this.spriteSet);
        }
    }
}

// 将提供者注册到 `ParticleResources#register`
// 假设可以访问 ParticleResources resources 并且 register 已设为公开
resources.register(EXAMPLE_QUAD, ExampleQuadParticle.Provider::new);
```

#### 从头开始

如果要渲染更复杂或自定义的内容呢？在这些情况下，我们需要更深入地了解 `ParticleEngine` 如何提取粒子。`Particle` 类本身实际上不进行任何提取、提交或渲染。它只是每刻处理物理更新。实际的提取逻辑由 `ParticleGroup` 处理，而提交由 `ParticleGroupRenderState` 处理。

那么，什么是 `ParticleGroup`？顾名思义，一个粒子组持有一组粒子，并负责跟踪、Tick和提取其粒子的渲染状态。泛型表示它可以跟踪的 `Particle` 类型，每个组最多 16,384 个（尽管单个粒子可以通过 `Particle#getParticleLimit` 设置自己的子组限制）。所有 `SingleQuadParticle` 都是 `QuadParticleGroup` 的一部分。为了提取渲染状态，`ParticleEngine` 调用 `ParticleGroup#extractRenderState`，它接受当前的平截头体、相机和部分刻，并返回一个 `ParticleGroupRenderState`。

`ParticleGroupRenderState` 有点像渲染状态、提交处理器和缓存的混合体。它包含两个方法：`submit`，接受 `SubmitNodeCollector` 并提交组；以及 `clear`，清除所有先前缓存的粒子状态。从技术上讲，任何东西都可以使用收集器提交，但粒子有 `SubmitNodeCollector$ParticleGroupRenderer`：一个有助于缓存和渲染的附加实用程序。组渲染器包含两个方法：`prepare`，将网格数据写入环形缓冲区；以及 `render`，通常使用缓存的缓冲区，使用提供的 `RenderPass` 将数据写入共享的顺序缓冲区，并将其绘制到屏幕。只有 `QuadParticleRenderState` 使用缓存和 `ParticleGroupRenderer`，因为渲染状态在渲染后立即被清除。

要将 `ParticleGroup` 链接到 `Particle` 以供使用，我们必须使用 `Particle#getGroup` 设置 `ParticleRenderType`。与之前的版本不同，`ParticleRenderType` 只是 `ParticleGroup` 的一个键。此键通过 `ParticleEngine#createParticleGroup` 映射到组，提交/渲染顺序由 `ParticleEngine#RENDER_ORDER` 确定。必须修补该方法和列表，才能使您的组正确管理粒子并提取以进行提交。

```java
// 我们将假设我们的粒子有某个 SimpleParticleType EXAMPLE_ONE, EXAMPLE_TWO
// 此示例将构造两个具有相同基础类型的粒子，以展示组的工作原理

// 创建粒子类型
public static final ParticleRenderType EXAMPLE_TYPE = new ParticleRenderType("examplemod:example_type");

// 创建我们的粒子
public abstract class ExampleParticle extends Particle {

    // 您可以以任何方式处理传递给粒子组
    // 使字段可访问或拥有专用方法
    public final Model<Unit> model;

    protected ExampleParticle(ClientLevel level, double x, double y, double z, Function<EntityModelSet, Model<Unit>> modelFactory) {
        super(level, x, y, z);
        this.model = modelFactory.apply(Minecraft.getInstance().getEntityModels());
    }

    @Override
    public ParticleRenderType getGroup() {
        // 将粒子类型设置为我们的组
        return EXAMPLE_TYPE;
    }

    @FunctionalInterface
    public interface ExampleParticleFactory<P extends ExampleParticle> {
        
        P create(ClientLevel level, double x, double y, double z);
    }

    protected static <P extends ExampleParticle> ParticleProvider<SimpleParticleType> createProvider(ExampleParticleFactory<P> factory) {
        return (options, level, x, y, z, xd, yd, zd, random) -> factory.create(level, x, y, z);
    }
}

public class ExampleOneParticle extends ExampleParticle {

    ExampleOneParticle(ClientLevel level, double x, double y, double z) {
        super(level, x, y, z, modelSet -> new Model.Simple(new ModelPart(Collections.emptyList(), Collections.emptyMap()), RenderType::entityCutoutNoCull));
    }

    public static ParticleProvider<SimpleParticleType> provider() {
        return ExampleParticle.createProvider(ExampleOneParticle::new);
    }
}

public class ExampleTwoParticle extends ExampleParticle {

    private static final ParticleLimit LIMIT = new ParticleLimit(5);

    ExampleTwoParticle(ClientLevel level, double x, double y, double z) {
        super(level, x, y, z, modelSet -> new Model.Simple(new ModelPart(Collections.emptyList(), Collections.emptyMap()), RenderType::entityCutoutNoCull));
    }

    @Override
    public Optional<ParticleLimit> getParticleLimit() {
        // 将使用 LIMIT 子组的粒子数量限制为 5
        // 注意，由于 ParticleLimit 是一个记录，任何具有相同限制的都将被视为相同的键
        return Optional.of(LIMIT);
    }

    public static ParticleProvider<SimpleParticleType> provider() {
        return ExampleParticle.createProvider(ExampleTwoParticle::new);
    }
}

// 将提供者注册到 `ParticleResources#register`
// 假设可以访问 ParticleResources resources 并且 register 已设为公开
resources.register(EXAMPLE_ONE, ExampleOneParticle.provider());
resources.register(EXAMPLE_TWO, ExampleTwoParticle.provider());

// 创建渲染状态以提交组中的所有粒子
// 存储您需要提交到节点收集器的任何内容
public record ExampleGroupRenderState(List<Model<Unit>> models) implements ParticleGroupRenderState {

    @Override
    public void submit(SubmitNodeCollector collector) {
        // 提交每个粒子 
        for (var model : this.models) {
            collector.submitModel(model, ...);
        }
    }
}

// 创建粒子组以跟踪粒子并创建渲染状态
// EXAMPLE_ONE 和 EXAMPLE_TWO 都将被添加到此组
public class ExampleParticleGroup extends ParticleGroup<ExampleParticle> {

    public ExampleParticleGroup(ParticleEngine engine) {
        super(engine);
    }

    @Override
    public ParticleGroupRenderState extractRenderState(Frustum frustum, Camera camera, float partialTick) {
        // 创建要提交粒子的粒子组
        return new ExampleGroupRenderState(
            this.particles.stream().map(particle -> particle.model).toList()
        );
    }
}

// 将 ParticleRenderType 链接到其 ParticleGroup
// 假设我们可以访问 ParticleEngine engine
// 假设 ParticleEngine#RENDER_ORDER 是可变的并且是公开的
// 假设我们可以修补 ParticleEngine#createParticleGroup
engine.RENDER_ORDER.add(EXAMPLE_TYPE);

// 在 ParticleEngine 中
private ParticleGroup<?> createParticleGroup(ParticleRenderType renderType) {
    if (renderType == EXAMPLE_TYPE) {
        // this 指的是 ParticleEngine
        return new ExampleParticleGroup(this);
    }
    // ...
}
```

### 图集处理器整合

图集处理器已修改了一些逻辑，以整合其他精灵并更改获取 `TextureAtlasSprite` 的方式。

首先，地图装饰、绘画和 GUI 精灵现在是带有自己图集的适当图集：分别是 `Sheets#MAP_DECORATIONS_SHEET`、`PAINTINGS_SHEET` 和 `GUI_SHEET`。

从这些图集中获取 `TextureAtlasSprite` 现在完全通过 `MaterialSet` 路由：一个函数式接口，接受一个 `Material`（基本上是图集位置和纹理位置），并返回关联的 `TextureAtlasSprite`。`MaterialSet` 处理物品模型、方块实体渲染器和实体渲染器的纹理获取：

```java
// 这是一个从适当图集中获取苹果纹理的材质示例
public static final Material APPLE = new Material(
    TextureAtlas.LOCATION_BLOCKS, // 存储物品纹理的图集
    ResourceLocation.fromNamespaceAndPath("minecraft", "item/apple") // 根据精灵内容的纹理名称
);
// 您也可以使用 Sheets.ITEMS_MAPPER.defaultNamespaceApply("apple") 做同样的事情

// 对于某个物品模型
public class ExampleUnbakedItemModel implements ItemModel.Unbaked {
    
    // ...

    @Override
    public ItemModel bake(ItemModel.BakingContext ctx) {
        TextureAtlasSprite appleTexture = ctx.materials().get(APPLE);
        // ...
    }
}

// 对于某个特殊物品模型
public class ExampleUnbakedSpecialModel implements SpecialModelRenderer.Unbaked {
    
    // ...

    @Override
    @Nullable
    public SpecialModelRenderer<?> bake(SpecialModelRenderer.BakingContext ctx) {
        TextureAtlasSprite appleTexture = ctx.materials().get(APPLE);
        // ...
    }
}

// 对于某个方块实体渲染器
public class ExampleBlockEntityRenderer implements BlockEntityRenderer<ExampleBlockEntity> {

    public ExampleBlockEntityRenderer(BlockEntityRendererProvider.Context ctx) {
        TextureAtlasSprite appleTexture = ctx.materials().get(APPLE);
        // ...
    }

    // ...
}


// 对于某个实体渲染器
public class ExampleEntityRenderer implements EntityRenderer<ExampleEntity, ExampleEntityState> {

    public ExampleEntityRenderer(EntityRendererProvider.Context ctx) {
        TextureAtlasSprite appleTexture = ctx.getMaterials().get(APPLE);
        // ...
    }

    // ...
}
```

- `assets/minecraft/shaders/core`
    - `blit_screen.json` -> `screenquad.json`，使用无格式三角形而不是定位四边形
    - `position_color_lightmap.*` 已移除
    - `position_color_tex_lightmap.*` 已移除
- `com.mojang.blaze3d.vertex`
    - `CompactVectorArray` - 一个将浮点向量列表压缩到单个顺序数组中的持有者。
    - `MeshData$SortState#centroids` 现在返回一个 `CompactVectorArray`
    - `VertexSorting`
        - `byDistance` 现在接受一个 `Vector3fc` 而不是 `Vector3f`
        - `sort` 现在接受一个 `CompactVectorArray` 而不是 `Vector3f[]`
- `net.minecraft.client.Minecraft`
    - `getTextureAtlas` -> `AtlasManager#getAtlasOrThrow`，不是一对一
    - `getPaintingTextures`、`getMapDecorationTextures`、`getGuiSprites` -> `getAtlasManager`，不是一对一
- `net.minecraft.client.animation.Keyframe` 现在有一个重载，接受 `preTarget` 和 `postTarget` 而不是一个简单的 `target`，接受 `Vector3fc` 而不是 `Vector3f`
- `net.minecraft.client.entity`
    - `ClientAvatarEntity` - 化身实体的客户端数据。
    - `ClientAvatarState` - 化身的移动状态。
    - `ClientMannequin` - `Mannequin` 实体的客户端版本。
- `net.minecraft.client.gui`
    - `GuiGraphics`
        - `renderOutline` -> `submitOutline`
        - `renderDeferredTooltip` -> `renderDeferredElements`，不是一对一
        - `submitBannerPatternRenderState` 现在接受 `BannerFlagModel` 而不是 `ModelPart`
    `GuiSpriteManager` 类已移除
- `net.minecraft.client.gui.render.GuiRenderer` 现在接受 `SubmitNodeCollector` 和 `FeatureRenderDispatcher`
    - `MIN_GUI_Z` 现在是公开的
- `net.minecraft.client.gui.render.pip`
    - `GuiBannerResultRenderer` 现在接受一个 `MaterialSet`
    - `GuiSignRenderer` 现在接受一个 `MaterialSet`
- `net.minecraft.client.gui.render.state.TiledBlitRenderState` - 一个用于使用平铺构建精灵的渲染状态，通常用于平铺或九切片纹理。
- `net.minecraft.client.gui.render.state.pip.GuiBannerResultRenderState` 现在接受 `BannerFlagModel` 而不是 `ModelPart`
- `net.minecraft.client.model`
    - `AbstractPiglinModel#createArmorMeshSet` - 为每个人形盔甲槽位创建模型网格。
    - `ArmedModel` 现在有一个 `EntityRenderState` 的泛型
        - `translateToHand` 现在接受实体渲染状态
    - `ArmorStandArmorModel#createBodyLayer` -> `createArmorLayerSet`，不是一对一
    - `BellModel$State` - 表示支持对象的状态。
    - `BookModel$State` - 表示支持对象的状态。
    - `BreezeModel`
        - `createBodyLayer` -> `createBaseMesh`，现在是私有的
            - 被 `createBodyLayer`、`createWindLayer`、`createEyesLayer` 取代
    - `CopperGolemModel` - 铜傀儡实体的模型。
    - `CopperGolemStatueModel` - 铜傀儡雕像的模型。
    - `CreakingModel`
        - `NO_PARTS`、`getHeadModelParts` 已移除
        - `createEyesLayer` - 创建模型的眼睛。
    - `EntityModel#setupAnim` -> `Model#setupAnim`
    - `GuardianParticleModel` - 从守卫者生成的粒子。
    - `HeadedModel#translateToHead` - 将姿势堆栈变换到头部的位置和旋转。
    - `HumanoidArmorModel` -> `HumanoidModel#createArmorMeshSet`，不是一对一
    - `HumanoidModel#copyPropertiesTo` 已移除
    - `Model` 现在接受一个表示渲染状态的泛型
    - `PlayerCapeModel` 现在继承 `PlayerModel`
    - `PlayerEarsModel` 现在继承 `PlayerModel`
    - `PlayerModel` 渲染状态已拓宽到 `AvatarRenderState`
        - 静态字段现在是 `protected`
        - `createArmorMeshSet` - 为每个人形盔甲槽位创建模型网格。
    - `SkullModelBase$State` - 表示支持对象的状态。
    - `SpinAttackEffectModel` 泛型已拓宽到 `AvatarRenderState`
    - `VillagerLikeModel` 现在接受渲染状态的泛型
        - `hatVisible` 已移除
            - 被 `VillagerModel#createNoHatModel` 取代
        - `translateToArms` 现在接受渲染状态
    - `WardenModel`
        - `createTendrilsLayer`、`createHeartLayer`、`createBioluminescentLayer`、`createPulsatingSpotsLayer` - 创建监守者的 `RenderLayer` 使用的层。
        - `getTendrilsLayerModelParts`、`getHeartLayerModelParts`、`getBioluminescentLayerModelParts`、`getPulsatingSpotsLayerModelParts` 已移除
    - `ZombieVillagerModel`
        - `createArmorLayer` -> `createArmorLayerSet`，不是一对一
        - `createNoHatLayer` - 创建没有帽子层的模型。
- `net.minecraft.client.model.geom.ModelPart`
    - `copyFrom` 已移除
    - `$Polygon#normal` 现在是 `Vector3fc` 而不是 `Vector3f`
    - `$Vertex`
        - `pos` -> `x`、`y`、`z`
        - `worldX`、`worldY`、`worldZ` - 返回坐标缩小 16 倍后的值。
- `net.minecraft.client.model.geom.builders.PartDefinition`
    - `clearRecursively` - 清除所有子部件及其子子部件。
    - `retainPartsAndChildren` - 从其根和任何子子部件中保留指定的部件。
    - `retainExactParts` - 仅保留顶级部件，清除所有其他部件和子子部件。
- `net.minecraft.client.particle`
    - `AttackSweepParticle` 现在继承 `SingleQuadParticle`
    - `BaseAshSmokeParticle` 现在继承 `SingleQuadParticle` 并且是 `abstract`
    - `BlockMarker` 现在继承 `SingleQuadParticle`
    - `BreakingItemParticle` 现在继承 `SingleQuadParticle`
        - 构造函数接受 `TextureAtlasSprite` 而不是 `ItemStackRenderState`
        - `$ItemParticleProvider#calculateState` -> `getSprite`，不是一对一
    - `BubbleColumnUpParticle` 现在继承 `SingleQuadParticle`
    - `BubbleParticle` 现在继承 `SingleQuadParticle`
    - `BubblePopParticle` 现在继承 `SingleQuadParticle`
    - `CampfireSmokeParticle` 现在继承 `SingleQuadParticle`
    - `CritParticle` 现在继承 `SingleQuadParticle`
    - `DragonBreathParticle` 现在继承 `SingleQuadParticle`
        - `$Provider` 泛型现在使用 `PowerParticleOption`
    - `DripParticle` 现在继承 `SingleQuadParticle` 并接受一个 `TextureAtlasSprite`
        - `create*Particle` 方法 -> `$*Provider` 类
    - `DustParticleBase` 现在继承 `SingleQuadParticle`
    - `ElderGuardianParticleGroup` - 负责设置和提交远古守卫者粒子的粒子组。
    - `ExplodeParticle` 现在继承 `SingleQuadParticle`
    - `FallingDustParticle` 现在继承 `SingleQuadParticle`
    - `FallingLeavesParticle` 现在继承 `SingleQuadParticle` 并接受 `TextureAtlasSprite` 而不是 `SpriteSet`
    - `FireflyParticle` 现在继承 `SingleQuadParticle` 并接受一个 `TextureAtlasSprite`
    - `FireworkParticles`
        - `$FlashProvider` 泛型现在使用 `ColorParticleOption`
        - `$OverlayParticle` 现在继承 `SingleQuadParticle` 并接受一个 `TextureAtlasSprite`
    - `FlameParticle` 现在接受一个 `TextureAtlasSprite`
    - `FlyStraightTowardsParticle` 现在继承 `SingleQuadParticle` 并接受一个 `TextureAtlasSprite`
    - `FlyTowardsPositionParticle` 现在继承 `SingleQuadParticle` 并接受一个 `TextureAtlasSprite`
    - `GlowParticle` 现在继承 `SingleQuadParticle`
    - `GustParticle` 现在继承 `SingleQuadParticle`
    - `HeartParticle` 现在继承 `SingleQuadParticle` 并接受一个 `TextureAtlasSprite`
    - `HugeExplosionParticle` 现在继承 `SingleQuadParticle`
    - `ItemPickupParticle` 现在接受 `EntityRenderState` 而不是 `EntityRenderDispatcher`
        - 除目标实体外，所有字段现在都是 `protected`
    - `ItemPickupParticleGroup` - 负责设置和提交物品拾取粒子的粒子组。
    - `LavaParticle` 现在继承 `SingleQuadParticle`
    - `MobAppearanceParticle` -> `ElderGuardianParticle`
    - `NoRenderParticleGroup` - 什么都不做的粒子组。
    - `NoteParticle` 现在继承 `SingleQuadParticle` 并接受一个 `TextureAtlasSprite`
    - `Particle`
        - `rCol`、`gCol`、`bCol`、`alpha` -> `SingleQuadParticle#rCol`、`gCol`、`bCol`、`alpha`
        - `roll`、`oRoll` -> `SingleQuadParticle#roll`、`oRoll`
        - `setColor`、`setAlpha` -> `SingleQuadParticle#setColor`、`setAlpha`
        - `render`、`renderCustom` -> `ParticleGroupRenderState#submit`，不是一对一
        - `getRenderType` -> `getGroup`
            - 此方法的原始用途已移至 `SingleQuadParticle#getLayer`
        - `getParticleGroup` -> `getParticleLimit`，不是一对一
    - `ParticleEngine` 不再实现 `PreparableReloadListener`
        - 构造函数现在接受 `ParticleResources` 而不是 `TextureManager`
        - `close` 已移除
        - `updateCount` 现在是 `protected`
        - `render` -> `extract`，不是一对一
        - `destroy` -> `ClientLevel#addDestroyBlockEffect`
        - `crack` -> `ClientLevel#addBreakingBlockEffect`
        - `clearParticles` 现在是 `public`
        - `$MutableSpriteSet` -> `ParticleResources$MutableSpriteSet`
        - `$SpriteParticleRegistration` -> `ParticleResources$SpriteParticleRegistration`
    - `ParticleGroup` - 特定 `ParticleRenderType` 的粒子持有者，负责Tick和提取通用渲染状态。
    - `ParticleProvider`
        - `createParticle` 现在接受 `RandomSource`
        - `$Sprite#createParticle` 现在接受 `RandomSource` 并返回 `SingleQuadParticle` 而不是 `TextureSheetParticle`
    - `ParticleRenderType` 不再接受 `RenderType`
        - 此记录已被重新用于表示粒子组的键
        - `TERRAIN_SHEET` -> `SingleQuadParticle$Layer#TERRAIN`
        - `PARTICLE_SHEET_OPAQUE` -> `SingleQuadParticle$Layer#OPAQUE`
        - `PARTICLE_SHEET_TRANSLUCENT` -> `SingleQuadParticle$Layer#TRANSLUCENT`
        - `CUSTOM` 被一个不是为 `ParticleRenderType#SINGLE_QUADS` 的粒子组取代
    - `ParticleResources` - 加载粒子提供者、任何必要的描述，并将它们计算到所需的精灵集中。
    - `PlayerCloudParticle` 现在继承 `SingleQuadParticle`
    - `PortalParticle` 现在继承 `SingleQuadParticle` 并接受一个 `TextureAtlasSprite`
    - `QuadParticleGroup` - 负责设置和提交单个四边形粒子的粒子组。
    - `ReversePortalParticle` 现在接受一个 `TextureAtlasSprite`
    - `RisingParticle` 现在继承 `SingleQuadParticle`
    - `SculkChargeParticle` 现在继承 `SingleQuadParticle`
    - `SculkChargePopParticle` 现在继承 `SingleQuadParticle`
    - `SculkChargePopParticle` 现在继承 `SingleQuadParticle`
    - `ShriekParticle` 现在继承 `SingleQuadParticle` 并接受一个 `TextureAtlasSprite`
    - `SimpleAnimatedParticle` 现在继承 `SingleQuadParticle` 并且是 `abstract`
    - `SingleQuadParticle` 现在接受一个 `TextureAtlasSprite`
        - `sprite` - 粒子的纹理。
        - `render` -> `extract`，不是一对一，现在接受 `QuadParticleRenderState` 而不是 `VertexConsumer`
        - `renderRotatedQuad` -> `extractRotatedQuad`，不是一对一，现在接受 `QuadParticleRenderState` 而不是 `VertexConsumer`
        - `getU0`、`getU1`、`getV0`、`getV1` 不再是抽象的
        - `getLayer` - 设置单个四边形的渲染层。
        - `$Layer` - 单个四边形应渲染的层。
    - `SnowflakeParticle` 现在继承 `SingleQuadParticle`
    - `SpellParticle` 现在继承 `SingleQuadParticle`
        - `InstantProvider` 泛型现在使用 `SpellParticleOption`
    - `SplashParticle` 现在接受一个 `TextureAtlasSprite`
    - `SpriteSet#first` - 返回精灵集中的第一个纹理。
    - `SuspendedParticle` 现在继承 `SingleQuadParticle` 并接受一个 `TextureAtlasSprite`
    - `SuspendedTownParticle` 现在继承 `SingleQuadParticle` 并接受一个 `TextureAtlasSprite`
    - `TerrainParticle` 现在继承 `SingleQuadParticle`
    - `TextureSheetParticle` 类已移除，请改用 `SingleQuadParticle`
    - `TrailParticle` 现在继承 `SingleQuadParticle` 并接受一个 `TextureAtlasSprite`
    - `TrialSpawnerDetectionParticle` 现在继承 `SingleQuadParticle`
    - `VibrationSignalParticle` 现在继承 `SingleQuadParticle` 并接受一个 `TextureAtlasSprite`
    - `WakeParticle` 现在继承 `SingleQuadParticle`
    - `WaterCurrentDownParticle` 现在继承 `SingleQuadParticle` 并接受一个 `TextureAtlasSprite`
    - `WaterDropParticle` 现在继承 `SingleQuadParticle` 并接受一个 `TextureAtlasSprite`
- `net.minecraft.client.player.AbstractClientPlayer` 字段现在存储在 `ClientAvatarState` 中
    - `elytraRot*` -> `*Cloak`
    - `clientLevel` 已移除
    - `getDeltaMovementLerped` -> `addWalkedDistance`，不是一对一
    - `updateBob` - 更新相机的摆动运动。
- `net.minecraft.client.renderer`
    - `EndFlashState` - 末地闪光的渲染状态。
    - `GameRenderer` 现在接受 `BlockRenderDispatcher`
        - `getSubmitNodeStorage` - 获取用于功能类对象的节点提交。
        - `getFeatureRenderDispatcher` - 获取用于渲染功能类对象的分派器。
        - `getLevelRenderState` - 获取等级中动态功能的渲染状态。
    - `ItemInHandRenderer`
        - `renderItem` 现在接受 `SubmitNodeCollector` 而不是 `MultiBufferSource`
        - `renderHandsWithItems` 现在接受 `SubmitNodeCollector` 而不是 `MultiBufferSource$BufferSource`
    - `LevelRenderer` 现在接受 `LevelRenderState` 和 `FeatureRenderDispatcher`
        - `getSectionRenderDispatcher` 现在可为 null
        - `tickParticles` 已移除
        - `addParticle` 已移除
    - `MapRenderer` 现在接受 `AtlasManager` 而不是 `MapDecorationTextureManager`
        - `render` 现在接受 `SubmitNodeCollector` 而不是 `MultiBufferSource`
    - `OrderedSubmitNodeCollector` - 一个提交处理器，用于在功能被分派时以给定顺序将元素绘制到屏幕。
    - `OutlineBufferSource` 不再接受任何参数
        - `setColor` 现在接受一个整数
    - `ParticleGroupRenderState` - 一组粒子的渲染状态。
    - `ParticlesRenderState` - 所有粒子的渲染状态。
    - `QuadParticleRenderState` - 所有单个四边形粒子的渲染组状态。
    - `RenderPipelines`
        - `GUI_TEXT` - GUI 中文本的管线。
        - `GUI_TEXT_INTENSITY` - GUI 中未着色文本的强度管线。
    - `RenderStateShard#TRANSLUCENT_TARGET`、`PARTICLES_TARGET` 已移除
    - `RenderType`
        - `pipeline` - 该类型使用的 `RenderPipeline`。
        - `opaqueParticle`、`translucentParticle` 已移除
        - `sunriseSunset`、`celestial` 已移除
    - `ScreenEffectRenderer` 现在接受一个 `MaterialSet`
        - `renderScreenEffect` 现在接受一个 `SubmitNodeCollector`
    - `ShapeRenderer`
        - `renderLineBox` 现在接受 `PoseStack$Pose` 而不是 `PoseStack`
        - `renderFace` 现在接受 `Matrix4f` 而不是 `PoseStack`
    - `Sheets`
        - `GUI_SHEET`、`MAP_DECORATIONS_SHEET`、`PAINTINGS_SHEET` - 图集纹理。
        - `BLOCK_ENTITIES_MAPPER` - 将方块纹理映射到方块实体的映射器。
        - `*COPPER*` - 铜箱子的材质。
        - `chooseMaterial` 现在接受 `ChestRenderState$ChestMaterialType` 而不是 `BlockEntity` 和 `boolean`
    - `SkyRenderer`
        - `END_SKY_LOCATION` 现在是私有的
        - `renderSunMoonAndStars` 不再接受缓冲区源
        - `renderEndFlash` 不再接受缓冲区源
        - `renderSunriseAndSunset` 不再接受缓冲区源
    - `SpecialBlockModelRenderer`
        - `vanilla` 现在接受 `SpecialModelRenderer$BakingContext` 而不是 `EntityModelSet`
        - `renderByBlock` 现在接受 `SubmitNodeCollector` 而不是 `MultiBufferSource`，以及一个轮廓颜色
    - `SubmitNodeCollection` - `OrderedSubmitNodeCollector` 的一个实现，将提交的功能保存在单独的列表中。
    - `SubmitNodeCollector` - 一个 `OrderedSubmitNodeCollector`，提供更改元素将渲染的当前顺序的方法。
    - `SubmitNodeStorage` - 由某个顺序持有的集合的存储。
    - `SkyRenderer`
        - `renderEndFlash` - 渲染末地闪光。
        - `initTextures` - 获取所用元素的纹理。
        - `extractRenderState` - 从当前等级提取 `SkyRenderState`。
    - `WeatherEffectRenderer`
        - `render` 现在接受 `WeatherRenderState` 而不是 `int`、`float` 和 `Level`
            - 这些字段已移至 `extractRenderState`
        - `extractRenderState` - 从当前等级提取 `WeatherRenderState`。
        - `$ColumnInstance` 现在是公开的
    - `WorldBorderRenderer`
        - `render` 现在接受 `WorldBorderRenderState` 而不是 `WorldBorder`
        - `extract` - 从当前世界边界提取 `WorldBorderRenderState`。
- `net.minecraft.client.renderer.block`
    - `BlockRenderDispatcher` 现在接受一个 `MaterialSet`
    - `MovingBlockRenderState` - 一个实现 `BlockAndTintGetter` 的移动方块的渲染状态。
    - `LiquidBlockRenderer#setupSprites` 现在接受 `BlockModelShaper` 和 `MaterialSet`
- `net.minecraft.client.renderer.blockentity`
    - 这里的大多数接受 `MultiBufferSource` 的方法已被 `SubmitNodeCollector` 取代，如果该方法不用于物品渲染，则还有 `ModelFeatureRenderer$CrumblingOverlay`
    - 大多数方法从 `render*` 更名为 `submit*`，主要的 submit 方法现在使用 `BlockEntityRenderState`
    - 所有 `BlockEntityRenderer` 现在都有一个 `BlockEntityRenderState` 泛型
    - `AbstractEndPortalRenderer` - 末地传送门的方块实体渲染器。
    - `AbstractSignRenderer`
        - `getSignModel` 现在返回一个 `Model$Simple`
        - `renderSign` -> `submitSign`，现在接受一个 `Model$Simple` 并且不再接受色调颜色
    - `BannerRenderer` 有一个接受 `SpecialModelRenderer$BakingContext` 的重载
        - `EntityModelSet` 构造函数现在接受 `MaterialSet`
        - `renderPatterns` -> `submitPatterns` 现在接受 `MaterialSet` 和 `ModelFeatureRenderer$CrumblingOverlay`，`ModelPart` 已被 `Model` 及其渲染状态取代，一个 `boolean` 表示是否使用实体闪光，以及一个轮廓颜色
            - 带有两个额外 `boolean` 的重载已移除
        - `renderSpecial` -> `submitSpecial`，现在接受轮廓颜色
    - `BeaconRenderer#renderBeaconBeam` -> `submitBeaconBeam`，不再接受游戏时间 `long`
    - `BedRenderer` 有一个接受 `SpecialModelRenderer$BakingContext` 的重载
        - `EntityModelSet` 构造函数现在接受 `MaterialSet`
        - `renderSpecial` -> `submitSpecial`，现在接受轮廓颜色
    - `BlockEntityRenderDispatcher` 现在接受 `MaterialSet` 和 `PlayerSkinRenderCache`
        - `render` -> `submit`，现在接受 `BlockEntityRenderState` 而不是 `BlockEntity`，不再接受部分刻 `float`，并接受 `CameraRenderState`
        - `getRenderer` 现在有一个重载，可以从其 `BlockEntityRenderState` 获取渲染器
        - `tryExtractRenderState` - 从 `BlockEntity` 获取 `BlockEntityRenderState`
        - `level`、`camera`、`cameraHitResult` 已移除
        - `prepare` 现在只接受 `Camera`
        - `setLevel` 已移除
    - `BlockEntityRenderer` 现在有另一个泛型 `S` 表示 `BlockEntityRenderState`
        - `render` -> `submit`，接受 `BlockEntityRenderState`、`PoseStack`、`SubmitNodeCollector` 和 `CameraRenderState`
        - `createRenderState` - 创建渲染状态对象。
        - `extractRenderState` - 从方块实体中提取渲染状态。
    - `BlockEntityRendererProvider$Context` 现在是一个记录，接受 `MaterialSet` 和 `PlayerSkinRenderCache`
        - 它现在有另一个泛型 `S` 表示 `BlockEntityRenderState`
    - `CopperGolemStatueBlockRenderer` - 铜傀儡雕像的方块实体渲染器。
    - `DecoratedPotRenderer` 有一个接受 `SpecialModelRenderer$BakingContext` 的重载
        - `EntityModelSet` 构造函数现在接受 `MaterialSet`
        - `render` 重载 -> `submit`，现在接受轮廓颜色
    - `HangingSignRenderer`
        - `createSignModel` 现在返回一个 `Model$Simple`
        - `renderInHand` 现在接受一个 `MaterialSet`
    - `ShelfRenderer` - 架子的方块实体渲染器。
    - `ShulkerBoxRenderer` 有一个接受 `SpecialModelRenderer$BakingContext` 的重载
        - `EntityModelSet` 构造函数现在接受 `MaterialSet`
        - `render` 重载 -> `submit`，现在接受轮廓颜色
    - `SignRenderer`
        - `createSignModel` 现在返回一个 `Model$Simple`
        - `renderInHand` 现在接受一个 `MaterialSet`
    - `SkullBlockRenderer#submitSkull` - 将骷髅头模型提交给收集器。
    - `SpawnerRenderer#renderEntityInSpawner` -> `submitEntityInSpawner`，现在接受 `CameraRenderState`
    - `TestInstanceREnderer` 现在接受 `BlockEntityRendererProvider$Context`
- `net.minecraft.client.renderer.blockentity.state`
    - `BannerRenderState` - 旗帜方块实体的渲染状态。
    - `BeaconRenderState` - 信标方块实体的渲染状态。
    - `BedRenderState` - 床方块实体的渲染状态。
    - `BellRenderState` - 钟方块实体的渲染状态。
    - `BlockEntityRenderState` - 所有方块实体的基础渲染状态。
    - `BlockEntityWithBoundingBoxRenderState` - 具有自定义边界框的方块实体的渲染状态。
    - `BrushableBlockRenderState` - 可刷扫方块实体的渲染状态。
    - `CampfireRenderState` - 营火方块实体的渲染状态。
    - `ChestRenderState` - 箱子方块实体的渲染状态。
    - `CondiutRenderState` - 潮涌核心方块实体的渲染状态。
    - `CopperGolemStatueRenderState` - 铜傀儡方块实体的渲染状态。
    - `DecoratedPotRenderState` - 饰纹陶罐方块实体的渲染状态。
    - `EnchantTableRenderState` - 附魔台方块实体的渲染状态。
    - `EndGatewayRenderState` - 末地折跃门方块实体的渲染状态。
    - `EndPortalRenderState` - 末地传送门方块实体的渲染状态。
    - `LecternRenderState` - 讲台方块实体的渲染状态。
    - `PistonHeadRenderState` - 活塞头方块实体的渲染状态。
    - `ShelfRenderState` - 架子方块实体的渲染状态。
    - `ShulkerBoxRenderState` - 潜影盒方块实体的渲染状态。
    - `SignRenderState` - 告示牌方块实体的渲染状态。
    - `SkullBlockRenderState` - 骷髅头方块实体的渲染状态。
    - `SpawnerRenderState` - 刷怪笼方块实体的渲染状态。
    - `TestInstanceRenderState` - 测试实例方块实体的渲染状态。
    - `VaultRenderState` -  vault 方块实体的渲染状态。
- `net.minecraft.client.renderer.culling.Frustum`
    - `offset` - 偏移位置。
    - `pointInFrustum` - 检查提供的坐标是否在平截头体内。
- `net.minecraft.client.renderer.entity`
    - 这里的大多数接受 `MultiBufferSource` 和光照坐标整数的方法已被 `SubmitNodeCollector` 和渲染状态参数取代
    - 大多数方法从 `render*` 更名为 `submit*`
    - `AbstractBoatRenderer#renderTypeAdditions` -> `submitTypeAdditions`
    - `AbstractMinecartRenderer#renderMinecartContents` -> `submitMinecartContents`
    - `AbstractSkeletonRenderer` 接受 `ArmorModelSet` 而不是 `ModelLayerLocation`
    - `AbstractZombieRenderer` 接受 `ArmorModelSet` 而不是模型
    - `ArmorModelSet` - 一个将某个对象映射到每个人形盔甲槽位的持有者。通常保存层定义，然后将其烘焙到关联的模型中。
    - `BreezeRenderer#enable` 已移除
    - `CopperGolemRenderer` - 铜傀儡实体的渲染器。
    - `DisplayRenderer#renderInner` -> `submitInner`
    - `EnderDragonRenderer#renderCrystalBeams` -> `submitCrystalBeams`
    - `EntityRenderDispatcher` 现在接受 `AtlasManager`
        - `prepare` 不再接受 `Level`
        - `setRenderShadow`、`setRenderHitBoxes`、`shouldRenderHitBoxes` 已移除
        - `extractEntity` - 从实体和部分刻创建渲染状态。
        - `render` -> `submit`，现在接受 `CameraRenderState`
        - `setLevel` -> `resetCamera`，不是一对一
        - `getPlayerRenderer` - 从给定的客户端玩家获取 `AvatarRenderer`。
        - `overrideCameraOrientation`、`distanceToSqr`、`cameraOrientation` 已移除
    - `EntityRenderer`
        - `NAMETAG_SCALE` 现在是公开的
        - `render(S, PoseStack, MultiBufferSource, int)` -> `submit(S, PoseStack, SubmitNodeCollector, CameraRenderState)`
        - `renderNameTag` -> `submitNameTag`，现在接受 `CameraRenderState`
        - `finalizeRenderState` - 在 `extractRenderState` 之后作为最后一步提取渲染状态的信息，例如阴影。
    - `EntityRendererProvider$Context` 现在接受 `PlayerSkinRenderCache` 和 `AtlasManager`
        - `getModelManager` 已移除
        - `getMaterials` - 返回材质到图集精灵的映射器。
        - `getPlayerSkinRenderCache` - 获取玩家皮肤的渲染缓存。
        - `getAtlas` - 返回该位置的图集。
    - `EntityRenderers#createPlayerRenderers` 现在返回一个 `PlayerModelType` 到 `AvatarRenderer` 的映射
    - `ItemEntityRenderer`
        - `renderMultipleFromCount` -> `submitMultipleFromCount`
        - `renderMultipleFromCount(PoseStack, MultiBufferSource, int, ItemClusterRenderState, RandomSource)` -> `renderMultipleFromCount(PoseStack, SubmitNodeCollector, int, ItemClusterRenderState, RandomSource)`
    - `ItemRenderer` 不再接受 `ItemModelResolver`
        - `getArmorFoilBuffer` -> `getFoilRenderTypes`，不是一对一
        - `renderStatic` 方法已移除
    - `MobRenderer#checkMagicName` - 返回自定义名称是否与给定字符串匹配。
    - `PiglinRenderer` 接受 `ArmorModelSet` 而不是 `ModelLayerLocation`
    - `TntMinecartRenderer#renderWhiteSolidBlock` -> `submitWhiteSolidBlock`，现在接受一个轮廓颜色
    - `ZombieRenderer` 接受 `ArmorModelSet` 而不是 `ModelLayerLocation`
    - `ZombifiedPiglinPiglinRenderer` 接受 `ArmorModelSet` 而不是 `ModelLayerLocation`
- `net.minecraft.client.renderer.entity.layers`
    - `ArrowLayer` 现在处理 `AvatarRenderState` 而不是 `PlayerRenderState`
    - `BeeStingerLayer` 现在处理 `AvatarRenderState` 而不是 `PlayerRenderState`
    - `BlockDecorationLayer` - 一个处理由实体变换的方块模型的层。
    - `BreezeWindLayer` 现在接受 `EntityModelSet` 而不是 `EntityRendererProvider$Context`
    - `CapeLayer` 现在处理 `AvatarRenderState` 而不是 `PlayerRenderState`
    - `CustomHeadLayer` 现在接受 `PlayerSkinRenderCache`
    - `Deadmau5EarsLayer` 现在处理 `AvatarRenderState` 而不是 `PlayerRenderState`
    - `EquipmentLayerRenderer#renderLayers` 现在接受渲染状态、`SubmitNodeCollector`、轮廓颜色和一个初始顺序，而不是 `MultiBufferSource`
    - `HumanoidArmorLayer` 现在接受 `ArmorModelSet` 而不是模型
        - `setPartVisibility` 已移除
    - `ItemInHandLayer#renderArmWithItem` -> `submitArmWithItem`
    - `LivingEntityEmissiveLayer` 现在接受一个用于纹理的函数而不是 `ResourceLocation`，以及一个模型而不是 `$DrawSelector`
        - `$DrawSelector` 已移除
    - `ParrotOnShoulderLayer` 现在处理 `AvatarRenderState` 而不是 `PlayerRenderState`
    - `PlayerItemInHandLayer` 现在处理 `AvatarRenderState` 而不是 `PlayerRenderState`
    - `RenderLayer`
        - `renderColoredCutoutModel`、`coloredCutoutModelCopyLayerRender` 现在接受 `Model` 而不是 `EntityModel`，接受 `SubmitNodeCollector` 而不是 `MultiBufferSource`，以及一个表示渲染顺序的整数
        - `render` -> `submit`，接受 `SubmitNodeCollector` 而不是 `MultiBufferSource`
    - `SimpleEquipmentLayer` 现在接受一个顺序整数
    - `SpinAttackEffectLayer` 现在处理 `AvatarRenderState` 而不是 `PlayerRenderState`
    - `StuckInBodyLayer` 现在有一个用于渲染状态的额外泛型，在构造函数中也接受渲染状态
        - `numStuck` 现在接受 `AvatarRenderState` 而不是 `PlayerRenderState`
    - `VillagerProfessionLayer` 现在接受两个模型
- `net.minecraft.client.renderer.entity.player.PlayerRenderer` -> `AvatarRenderer`
    - `render*Hand` 现在接受 `SubmitNodeCollector` 而不是 `MultiBufferSource`
- `net.minecraft.client.renderer.entity.state`
    - `CopperGolemRenderState` - 铜傀儡实体的渲染状态。
    - `DisplayEntityRenderState#cameraYRot`、`cameraXRot` - 相机的旋转。
    - `EntityRenderState`
        - `NO_OUTLINE` - 一个表示无轮廓颜色的常量。
        - `outlineColor` - 实体的轮廓颜色。
        - `lightCoords` - 用于照亮实体的打包光照坐标。
        - `shadowPieces`、`$ShadowPiece` - 表示实体投射的阴影的相对坐标。
    - `FallingBlockRenderState` 字段和实现已全部移至 `MovingBlockRenderState`
    - `LivingEntityRenderState`
        - `appearsGlowing` -> `EntityRenderState#appearsGlowing`，现在是一个方法
        - `customName` 已移除
    - `PaintingRenderState#lightCoords` -> `lightCoordsPerBlock`
    - `PlayerRenderState` -> `AvatarRenderState`
        - `useItemRemainingTicks`、`swinging` 已移除
        - `showDeadMouseEars` -> `showExtraEars`
    - `SheepRenderState`
        - `id` 已移除
        - `isJebSheep` 现在是一个字段而不是方法
    - `WitherSkullRenderState#xRot`、`yRot` -> `modeState`，不是一对一
- `net.minecraft.client.renderer.feature`
    - `BlockFeatureRenderer` - 渲染提交的方块、方块模型或下落中的方块。
    - `CustomFeatureRenderer` - 通过传递的函数渲染提交的几何体。
    - `FeatureRenderDispatcher` - 分派所有功能以从提交的节点收集器对象渲染。
    - `FlameFeatureRenderer` - 渲染提交的着火的实体动画。
    - `HitboxFeatureRenderer` - 渲染提交的实体碰撞箱。
    - `ItemFeatureRenderer` - 渲染提交的物品。
    - `LeashFeatureRenderer` - 渲染提交的附着在实体上的拴绳。
    - `ModelFeatureRenderer` - 渲染提交的 `Model`。
    - `ModelPartFeatureRenderer` - 渲染提交的 `ModelPart`。
    - `NameTagFeatureRenderer` - 渲染提交的名称标签。
    - `ParticleFeatureRenderer` - 渲染提交的粒子。
    - `ShadowFeatureRenderer` - 渲染提交的实体阴影。
    - `TextFeatureRenderer` - 渲染提交的文本。
- `net.minecraft.client.renderer.item`
    - `ItemModel$BakingContext` 现在接受 `MaterialSet` 和 `PlayerSkinRenderCache`，并实现 `SpecialModelRenderer$BakingContext`
    - `ItemStackRenderState#render` -> `submit`，接受 `SubmitNodeCollector` 而不是 `MultiBufferSource` 以及一个轮廓颜色
- `net.minecraft.client.renderer.special`
    - 这里的大多数接受 `MultiBufferSource` 的方法已被 `SubmitNodeCollector` 取代
    - `ChestSpecialRenderer` 现在接受一个 `MaterialSet`
        - `*COPPER*` - 铜箱子的纹理。
    - `ConduitSpecialRenderer` 现在接受一个 `MaterialSet`
    - `CopperGolemStatueSpecialRenderer` - 铜傀儡雕像作为物品的特殊渲染器。
    - `HangingSignSpecialRenderer` 现在接受一个 `MaterialSet` 和一个 `Model$Simple` 而不是 `Model`
    - `NoDataSpecialModelRenderer#render` -> `submit`，现在接受一个轮廓颜色
    - `PlayerHeadSpecialRenderer` 现在接受 `PlayerSkinRenderCache`
    - `ShieldSpecialRenderer` 现在接受一个 `MaterialSet`
    - `SpecialModelRenderer`
        - `render` -> `submit`，现在接受一个轮廓颜色
        - `$BakingContext` - 用于烘焙特殊物品模型的上下文。
        - `$Unbaked#bake` 现在接受 `SpecialModelRenderer$BakingContext` 而不是 `EntityModelSet`
    - `SpecialModelRenderers#createBlockRenderers` 现在接受 `SpecialModelRenderer$BakingContext` 而不是 `EntityModelSet`
    - `StandingSignSpecialRenderer` 现在接受一个 `MaterialSet` 和一个 `Model$Simple` 而不是 `Model`
- `net.minecraft.client.renderer.state`
    - `BlockBreakingRenderState` - 当前方块被破坏进度的渲染状态。
    - `BlockOutlineRenderState` - 通过其 `VoxelShape` 的方块轮廓的渲染状态。
    - `CameraRenderState` - 相机的渲染状态。
    - `LevelRenderState` - 等级中动态功能的渲染状态。
    - `ParticleGroupRenderState` - 一组粒子的渲染状态。
    - `ParticlesRenderState` - 所有粒子的渲染状态。
    - `QuadParticleRenderState` - 所有单个四边形粒子的渲染组状态。
    - `SkyRenderState` - 天空的渲染状态，包括月亮和星星。
    - `WeatherRenderState` - 当前天气的渲染状态。
    - `WorldBorderRenderState` - 世界边界的渲染状态。
- `net.minecraft.client.renderer.texture`
    - `SkinTextureDownloader` 现在是一个实例类而不是静态方法持有者，接受 `Proxy`、`TextureManager` 和主线程 `Executor`
        - 以前是静态的大多数方法现在是实例方法
    - `SpriteContents` 现在接受一个可选的 `AnimationMetadataSection` 和 `MetadataSectionType$WithValue` 列表，而不是 `ResourceMetadata`
        - `metadata` -> `getAdditionalMetadata`，不是一对一
    - `SpriteLoader`
        - `DEFAULT_METADATA_SECTIONS` 已移除
        - `stitch` 现在是私有的
        - `runSpriteSuppliers` 现在是私有的
        - `loadAndStitch(ResourceManager, ResourceLocation, int, Executor)` 已移除
        - `loadAndStitch` 现在接受一组 `MetadataSectionType` 而不是一个集合
        - `$Preparations`
            - `waitForUpload` 已移除
            - `getSprite` - 返回给定资源位置的图集精灵。
    - `TextureAtlasSprite#isAnimated` -> `SpriteContents#isAnimated`
- `net.minecraft.client.renderer.texture.atlas.SpriteResourceLoader#create` 现在接受一组 `MetadataSectionType` 而不是一个集合
- `net.minecraft.client.resources`
    - `MapDecorationTextureManager` 类已移除
    - `PaintingTextureManager` 类已移除
    - `PlayerSkin$Model` -> `PlayerModelType`，不是一对一
        - 构造函数现在接受遗留服务名称
        - `byName` -> `byLegacyServicesName`
    - `SkinManager` 现在接受 `Services` 而不是 `MinecraftSessionService`，以及一个 `SkinTextureDownloader`
        - `lookupInsecure` -> `createLookup`，现在接受一个布尔值表示是否检查不安全的皮肤
        - `getOrLoad` -> `get`
    - `TextureAtlasHolder` 类已移除
- `net.minecraft.client.resources.model`
    - `AtlasIds` -> `net.minecraft.data.AtlasIds`
    - `AtlasSet` -> `AtlasManager`，不是一对一
        - `forEach` - 遍历每个图集图版。
    - `Material`
        - `sprite` -> `MaterialSet#get`
        - `buffer` 现在接受一个 `MaterialSet`
    - `MaterialSet` - 材质到其图集精灵的映射。
    - `ModelBakery` 现在接受 `MaterialSet` 和 `PlayerSkinRenderCache`
    - `ModelManager` 不再是 `AutoCloseable`
        - 构造函数接受 `PlayerSkinRenderCache`、`AtlasManager` 而不是 `TextureManager`，以及最大 mipmap 级别整数
        - `getAtlas` -> `MaterialSet#get`
        - `updateMaxMipLevel` -> `AtlasManager#updateMaxMipLevel`
- `net.minecraft.core.particles`
    - `ParticleGroup` -> `ParticleLimit`
    - `ParticleTypes`
        - `DRAGON_BREATH` 现在使用 `PowerParticleOption`
        - `EFFECT` 现在使用 `SpellParticleOption`
        - `FLASH` 现在使用 `ColorParticleOption`
        - `INSTANT_EFFECT` 现在使用 `SpellParticleOption`
    - `PowerParticleOption` - 龙息粒子的粒子选项。
    - `SpellParticleOption` - 药水效果的粒子选项。

## 字体 字形 管线

字形的后端已被部分重做，以将字符及其效果统一到一个可渲染的对象，并添加烘焙流程（尽管是延迟的）。本文将简要概述这个新流程。

让我们从资源重新加载时开始，导致 `FontManager` 运行。字体定义被加载并传递到它们适当的 `GlyphProviderDefinition`，对于这个例子，它将立即解包到 `GlyphProvider$Loader` 中。加载器读取它需要的任何信息（很可能是纹理），并将其映射到关联的码点作为 `UnbakedGlyph`。一个 `UnbakedGlyph` 表示一个包含其 `GlyphInfo`（带有位置元数据）的单个字符，以及一个将其写入纹理的 `bake` 方法。`bake` 接受一个 `UnbakedGlyph$Stitcher`，它本身接受一个 `GlyphBitmap` 以正确定位和上传字形，以及用于任何偏移调整的 `GlyphInfo`。然后，在解析和最终确定之后，使用 `FontSet#reload` 创建 `FontSet`。这会重置纹理和缓存，并调用 `FontSet#selectProviders` 来存储活动的 `GlyphProvider` 列表，并通过将字符宽度映射到匹配的码点列表来填充 `glyphsByWidth`。此时，所有加载都已完成。虽然字形以未烘焙的格式存储，但它们直到该特定字符被渲染时才被烘焙和缓存。

现在，让我们转到 `FontDescription`。`FontDescription` 提供了与 `GlyphSource` 的一对一映射，后者负责获取字形。原版提供了三种 `FontDescription`：`$Resource` 用于映射到如上所述的 `FontSet`（字体 JSON 名称），`$AtlasSprite` 用于将图集解释为一组字形，以及 `$PlayerSprite` 用于渲染玩家头部和帽子。对于给定的 `Component`，可以通过 `Style#withFont` 将使用的 `FontDescription` 设置为其 `Style`。

因此，假设您使用 `FontDescription#DEFAULT` 将文本绘制到屏幕，它使用定义的 `assets/minecraft/font/default.json`。最终，这将调用 `Font#drawInBatch` 或 `drawInBatch8xOutline`。然后，无论是通过 `StringSplitter` 还是直接，`GlyphSource` 都是从 `FontDescription` 获得的。然后，调用 `GlyphSource#getGlyph`。对于 `FontDescription$AtlasSprite` 和 `$PlayerSprite`，这仅返回相关纹理的包装器。对于 `$Resource`，这内部调用 `FontSet#getGlyph`，它将 `UnbakedGlyph` 存储为 `FontSet$DelayedBake` 的一部分，然后通过调用 `UnbakedGlyph#bake` 将字形写入某个纹理，立即将其解析为 `BakedGlyph`。

`BakedGlyph` 包含两个方法：如前所述的用于位置元数据的 `GlyphInfo`，以及一个称为 `createGlyph` 的方法，它返回一个 `TextRenderable`：一个用于将字形绘制到屏幕的渲染器。`TextRenderable` 还有一个子接口，称为 `PlainTextRenderable`，用于帮助处理纹理精灵。在内部，所有资源 `BakedGlyph` 都是 `BakedSheetGlyph`，因为 `UnbakedGlyph$Stitcher#stitch` 调用只是包装了 `GlyphStitcher#stitch`。您可以将 `BakedSheetGlyph` 视为 256x256 `FontTexture` 上的一个视图，如果一张 `FontTexture` 上没有足够的空间，则会创建一个新的 `FontTexture`。

`BakedSheetGlyph` 还实现了 `EffectGlyph`，它可能应该在文本上渲染某种效果。这个功能，虽然目前仅作为另一个对象实现，但仅用于白色字形，而白色字形未被使用。

### 对象信息

`ObjectInfo` 是服务器端的实现，用于构造通过字形管线渲染任意对象所使用的 `FontDescription`。每个 info 接受 `FontDescription` 和一个常规的 `String` 来显示简单的描述。此外，它接受一个 `MapCodec` 来从对象内容进行编码和解码。

请注意，要使自定义 `FontDescription` 正确映射到源，您需要以某种方式修改 `FontManager$CachedFontProvider#getGlyphSource` 或实现自定义的 `Font$Provider`。

```java
// 一个基本的字体描述
public static record BlockDescription(Block block) implements FontDescription {}

// 一个简单的对象信息
public record BlockInfo(Block block) implements ObjectInfo {
    // 用于通过网络发送信息的编解码器
    public static final MapCodec<BlockInfo> MAP_CODEC = BuiltInRegistries.BLOCK.byNameCodec().fieldOf("block");

    @Override
    public FontDescription fontDescription() {
        // 要渲染的字体描述
        return new BlockDescription(this.block);
    }

    @Override
    public String description() {
        // 只是对象的文本描述
        return Objects.toString(BuiltInRegistries.BLOCK.getKey(this.block));
    }

    @Override
    public MapCodec<? extends ObjectInfo> codec() {
        return MAP_CODEC;
    }
}

// 创建用于渲染对象的 `GlyphSource` 和 `PlainTextRenderable`
public record BlockRenderable(...) implements PlainTextRenderable {
    // ...
}

public static GlyphSource create(Block block) {
    return new SingleSpriteSource(...);
}
```

`ObjectInfo` 也需要渲染到 `ObjectInfos#ID_MAPPER`：

```java
// 假设映射器已设为公开
ObjectInfos.ID_MAPPER.put("examplemod:block", BlockInfo.MAP_CODEC);
```

### 组件内容

组件内容现在也使用 id 映射器，而不是在类型上持有 id。这意味着创建自定义组件是通过以某种方式挂钩到 `ComponentSerialization#bootstrap` 并将您的 `ComponentContents` 实现的映射编解码器注册到映射器来完成的。

### 数据源

数据源也获得了与组件内容类似的处理，现在使用 id 映射器而不是在类型上持有 id。然后通过将您的 `DataSource` 的映射编解码器注册到 `DataSources#ID_MAPPER` 来注册数据源。请注意，映射器字段是私有的，因此您可能需要使用可用的解决方法。

- `com.mojang.blaze3d.font`
    - `GlyphInfo`
        - `bake` -> `UnbakedGlyph#bake`，现在接受 `UnbakedGlyph$Stitcher` 而不是函数
            - 函数行为被 `UnbakedGlyph$Stitcher#stitch` 取代
        - `$SpaceGlyphInfo` -> `GlyphInfo#simple` 和 `EmptyGlyph`，不是一对一
        - `$Stitched` -> `UnbakedGlyph`，不是一对一
    - `GlyphProvider#getGlyph` 现在返回一个 `UnbakedGlyph`
    - `SheetGlyphInfo` -> `GlyphBitmap`
- `net.minecraft.client.gui`
    - `Font` 不再接受函数和布尔值，而是接受 `Font$Provider`
        - `random` 现在是私有的
        - `$GlyphVisitor`
            - `acceptGlyph` 现在接受 `TextRenderable` 而不是 `BakedGlyph$GlyphInstance`
            - `acceptEffect` 现在只接受一个 `TextRenderable`
        - `$PreparedTextBuilder#accept` 现在有一个接受 `BakedGlyph` 而不是其码点的重载
        - `$Provider` - 一个简单的接口，用于根据其描述提供字形源，以及空字形。
    - `GlyphSource` - 一个接口，根据其码点持有烘焙的字形。
- `net.minecraft.client.gui.font`
    - `AtlasGlyphProvider` - 基于纹理图集的字形提供者。
    - `FontManager` 现在接受 `AtlasManager` 和 `PlayerSkinRenderCache`
    - `FontSet` 现在接受 `GlyphStitcher` 而不是 `TextureManager`，并且不再接受名称
        - `name` 已移除
        - `source` - 根据是否只应看到非可疑字形，返回字形源。
        - `getGlyphInfo`、`getGlyph` -> `getGlyph`，现在是包私有的，不是一对一
        - `getRandomGlyph` 现在接受 `RandomSource` 和一个码点而不是 `GlyphInfo`，返回一个 `BakedGlyph`
        - `whiteGlyph` 现在返回一个 `EffectGlyph`
        - `$GlyphSource` - 一个可以获取要烘焙的字形的源。
    - `FontTexture#add` 现在接受 `GlyphInfo` 和 `GlyphBitmap`，返回一个 `BakedSheetGlyph`
    - `GlyphStitcher` - 一个从其字形信息创建 `BakedGlyph` 的类。
    - `PlainTextRenderable` - `TextRenderable` 的一个实现，确定如何渲染精灵。
    - `PlayerGlyphProvider` - 用于渲染玩家头部和帽子的字形提供者。
    - `SingleSpriteSource` - 一个只包含一个字形的字形源，例如一个纹理。
    - `TextRenderable` - 表示文本表示（如字体中的字形）如何渲染。
- `net.minecraft.client.gui.font.glyphs`
    - `BakedGlyph` 现在是一个创建可渲染对象的接口
        - 其原始用途已移至 `BakedSheetGlyph`
    - `EffectGlyph` - 一个创建某个字形效果的可渲染对象的接口。
    - `EmptyGlyph` 现在实现 `UnbakedGlyph` 而不是继承 `BakedGlyph`
        - 构造函数接受字形的文本宽度。
    - `SpecialGlyphs#bake` 现在返回一个 `BakedSheetGlyph`
        - 此方法在技术上是新的。
- `net.minecraft.client.gui.font.providers`
    - `BitmapProvider$Glyph` 现在实现 `UnbakedGlyph` 而不是 `GlyphInfo$Stitched`
    - `UnihexProvider$Glyph` 现在实现 `UnbakedGlyph` 而不是 `GlyphInfo$Stitched`
- `net.minecraft.client.gui.render.state`
    - `GlyphEffectRenderState` 已移除
        - 使用 `GlyphRenderState`
    - `GlyphRenderState` 现在接受 `TextRenderable` 而不是 `BakedGlyph$Instance`
- `net.minecraft.network.chat`
    - `Component#object` - 创建一个带有对象内容的可变组件。
    - `ComponentContents#type` -> `codec`，丢弃字符串 id
        - `$Type` 已移除
    - `ComponentSerialization`
        - `createLegacyComponentMatcher` 不再需要 `StringRepresentable` 泛型，而是使用带有 `String` 键的 id 映射器
        - `$FuzzyCodec` 现在接受一组映射编解码器而不是一个列表
    - `FontDescription` - 一个描述字体的标识符，通常作为位置或精灵。
    - `Style` 现在是 final
        - `getFont` 现在返回一个 `FontDescription`
        - `withFont` 现在接受 `FontDescription` 而不是 `ResourceLocation`
        - `DEFAULT_FONT` 已移除
- `net.minecraft.network.chat.contents`
    - `BlockDataSource` -> `.data.BlockDataSource`
    - `DataSource` -> `.data.DataSource`
        - `type` -> `codec`，丢弃字符串 id
    - `EntityDataSource` -> `.data.EntityDataSource`
    - `*Contents`
        - `CODEC` -> `MAP_CODEC`
        - `TYPE` 已移除
    - `ObjectContents` - 可以作为组件一部分写入的任意内容，例如精灵。
    - `StorageDataSource` -> `.data.StorageDataSource`
- `net.minecraft.network.chat.contents.data.DataSources` - 所有原版注册的数据源。
- `net.minecraft.network.chat.contents.objects`
    - `AtlasSprite` - 纹理图集中精灵的对象信息。
    - `ObjectInfo` - 通过字形管线传递任意对象的引用相关信息。
    - `ObjectInfos` - 所有原版对象信息。
    - `PlayerSprite` - 玩家头部和帽子纹理的对象信息。

## JSON-RPC 管理服务器

Minecraft 引入了通过 JSON-RPC websocket 远程管理专用服务器的支持。这可以通过 `management-server-enabled` 属性启用，默认情况下它在 `localhost:25585` 上监听服务器。整个系统不仅处理通过 `JsonElement` 发送的网络请求的构造，还处理每个请求使用的模式。然后可以通过 `JsonRpcApiSchema` 数据提供者生成这些模式。

系统支持两种类型的 RPC 方法：来自管理服务器的请求的 `IncomingRpcMethod`，以及通知或向管理服务器请求信息的 `OutgoingRpcMethod`。这两者都是静态注册表对象，但通常通过其关联的构建器构造和注册，而不是实现接口。

### 模式

顾名思义，`Schema` 是 JSON 对象的规范。它们以类似于 `JsonElement` 的方式构造。大多数构造为 `Schema#record`，其字段和类型通过 `withField` 填充，然后存储在 `SchemaComponent` 中，该组件将引用名称映射到模式。然后可以通过 `asRef` 或 `asArray` 分别获取对象或数组实现。`SchemaComponent` 本身被注册到列表 `Schema#SCHEMA_REGISTRY` 以进行引用解析。

```json5
// 一个更改天气的 JSON 示例：
{
    "weather": "clear|rain|thunder",
    "duration": -1,
}
```

关联的模式组件如下所示：

```java
public static final SchemaComponent WEATHER_SCHEMA = new SchemaComponent(
    // 引用名称
    // 虽然我们可以使用冒号，但需要按照 RFC 3986 定义的百分号编码
    "examplemod_weather",
    // 要使用的模式
    Schema.record()
        .withField("weather", Schema.ofEnum(List.of("clear", "rain", "thunder")))
        .withField("duration", Schema.INT_SCHEMA)
);

// 将模式注册到注册表
Schema.getSchemaRegistry().add(WEATHER_SCHEMA);
```

请注意，模式目前无法指定单个属性是否可选。

### `IncomingRpcMethod`

`IncomingRpcMethod` 通过 `method` 构建器构造和注册。这些方法接受更新 Minecraft 服务器的处理函数、结果的编解码器，以及一个来自管理服务器的参数的可选编解码器。从那里，构建器包含用于发现服务以及如何执行方法的方法。`$IncomingRpcMethodBuilder#response` 和 `param` 定义管理服务器发送的参数和响应。`description` 由发现服务用于模式。`undiscoverable` 默认隐藏路由。最后，`notOnMainThread` 告诉该方法它可以在主线程之外运行。一旦调用了所需的方法，就可以使用 `build` 或 `register` 来构造对象，接受路由端点的命名空间和路径。

传入的方法接受 `MinecraftApi` 用于通过指定的“服务”与专用服务器通信，以及当前的 `ClientInfo` 连接。如果存在参数对象，它也接受该参数对象。

```java
// 构造 dto 对象
public record WeatherDto(String weather, int duration) {
    public static final Codec<WeatherDto> CODEC = RecordCodecBuilder.create(
        instance -> instance.group(
            Codec.STRING.fieldOf("weather").forGetter(WeatherDto::weather),
            Codec.INT.fieldOf("duration").forGetter(WeatherDto::duration),
        )
        .apply(instance, WeatherDto::new)
    );

    // 创建传入方法处理程序
    public static WeatherDto handleWeather(MinecraftApi api, WeatherDto params, ClientInfo info) {
        // 注意，api 使服务器私有，因为它期望逻辑通过其中一个中间层服务处理。
        // 我们将假设 `server` 字段以某种方式被设为公开。
        if (params.weather().equals("clear")) {
            api.server.overworld().setWeatherParameters(params.duration(), 0, false, false);
        } else if (params.weather().equals("rain")) {
            api.server.overworld().setWeatherParameters(0, params.duration(), true, false);
        } else if (params.weather().equals("thunder")) {
            api.server.overworld().setWeatherParameters(0, params.duration(), true, true);
        }

        return params;
    }
}

// 构造并注册方法端点
IncomingRpcMethod.method(
    // 处理程序方法
    WeatherDto::handleWeather,
    // 参数的编解码器
    WeatherDto.CODEC,
    // 结果的编解码器
    WeatherDto.CODEC
)
    // 设置路由的描述
    .description("设置天气")
    // 参数
    .param(new ParamInfo(
        // 对象的名称
        "weather",
        // 模式
        WEATHER_SCHEMA.asRef()
    ))
    // 响应
    .response(new ResultInfo(
        // 对象的名称
        "weather",
        // 模式
        WEATHER_SCHEMA.asRef()
    ))
    // 构建并注册路由
    .register(
        BuiltInRegistries.INCOMING_RPC_METHOD,
        // 端点命名空间
        "examplemod",
        // 端点路径
        "weather/update"
    );
```

### `OutgoingRpcMethod`

`OutgoingRpcMethod` 通过 `notification` 或 `request` 构建器构造和注册。通知通常只发送参数而不返回结果，而请求也提供结果。在任何一种情况下，它们都只接受参数或结果（如果存在）的编解码器。`$OutgoingRpcMethod#response` 和 `param` 定义 Minecraft 服务器发送的参数和响应。`description` 由发现服务用于模式。一旦调用了所需的方法，就可以使用 `register` 来构造对象，接受路由端点的命名空间和路径，并将其包装在 `Holder$Reference` 中。

目前，原版仅通过 `NotificationService` 广播通知：一个用于特定方法操作（如玩家加入或更改游戏规则）的远程日志记录器。虽然有结果，但必须通过 `Connection#sendRequest` 读取并异步处理。

```java
// 构造传出方法
// 由于 Minecraft 服务器将发送这些，我们需要持有该对象
public static final Holder.Reference<OutgoingRpcMethod.ParmeterlessNotification> SOMETHING_HAPPENED = OutgoingRpcMethod.notification()
        .description("某件事发生了！")
        .register("examplemod", "something");

// 发送通知，假设我们可以访问 `ManagementServer` managementServer
managementServer.forEachConnection(connection -> connection.sendNotification(SOMETHING_HAPPENED));
```

- `net.minecraft.SharedConstants#RPC_MANAGEMENT_SERVER_API_VERSION` - JSON RPC 服务器管理的 API 版本。
- `net.minecraft.core.registries`
    - `BuiltInRegistries`、`Registries`
        - `INCOMING_RPC_METHOD` - 对 RPC 服务的查询的注册表。
        - `OUTGOING_RPC_METHOD` - 来自 RPC 服务的广播的注册表。
- `net.minecraft.server`
    - `MinecraftServer`
        - `notificationManager` - 返回当前通知管理器。
        - `onGameRuleChanged` - 处理当前服务器的游戏规则更改时的情况。
        - `getOperatorUserPermissionLevel` -> `operatorUserPermissionLevel`
        - `isLevelEnabled` -> `isAllowedToEnterPortal`，不是一对一
        - `setPvpAllowed` 被 `GameRules#RULE_PVP` 取代
        - `setFlightAllowed` 被 `DedicatedServerProperties#allowFlight` 取代
        - `isCommandBlockEnabled` 不再是抽象的
        - `isSpawnerBlockEnabled` - 返回刷怪笼方块是否可以生成实体。
        - `getPlayerIdleTimeout` -> `playerIdleTimeout`
        - `kickUnlistedPlayers` 不再接受 `CommandSourceStack`
        - `pauseWhileEmptySeconds` -> `pauseWhenEmptySeconds`
        - `getSpawnProtectionRadius` -> `DedicatedServer#spawnProtectionRadius`
        - `isUsingWhiteList` - 处理为服务器启用白名单用户。
        - `setAutoSave`、`isAutoSave` - 处理服务器是否应每隔一段时间自动保存。
- `net.minecraft.server.dedicated`
    - `DedicatedServer` 现在接受 `LevelLoadListener` 而不是 `ChunkProgressListenerFactory`
        - `setAllowFlight` - 设置玩家是否可以在服务器中飞行。
        - `setDifficulty` - 设置服务器的游戏难度。
        - `viewDistance`、`setViewDistance` - 处理服务器的视距（可渲染区块）。
        - `simulationDistance`、`setSimulationDistance` - 处理服务器的模拟距离（逻辑运行区块）。
        - `setMaxPlayers` - 设置可以加入服务器的最大玩家数。
        - `setSpawnProtectionRadius` - 设置应受重生保护保护的区块半径。
        - `setRepliesToStatus` - 设置游戏是否使用旧式查询处理程序。
        - `setHidesOnlinePlayers` - 设置是否应隐藏在线玩家不被其他玩家看到。
        - `setOperatorUserPermissionLevel` - 设置操作员的权限级别。
        - `statusHeartbeatInterval`、`setStatusHeartbeatInterval` - 处理管理服务器将检查 Minecraft 服务器是否仍然存活的心跳间隔。
        - `entityBroadcastRangePercentage`、`setEntityBroadcastRangePercentage` - 处理实体跟踪的广播范围标量。
        - `forceGameMode`、`setForceGameMode` - 处理强制所有用户的游戏模式。
        - `gameMode`、`setGameMode` - 设置服务器的默认游戏模式。
        - `setAcceptsTransfers` - 设置服务器是否接受来自其他服务器的客户端转移。
        - `setPauseWhenEmptySeconds` - 设置当没有玩家时服务器应等待多少秒才停止Tick。
    - `DedicatedServerProperties`
        - `pvp` 被 `GameRules#RULE_PVP` 取代
        - `allowFlight`、`motd`、`forceGameMode`、`enforceWhitelist`、`difficulty`、`gameMode`、`spawnProtection`、`opPermissionLevel`、`viewDistance`、`simulationDistance`、`enableStatus`、`hideOnlinePlayers`、`entityBroadcastRangePercentage`、`pauseWhenEmptySeconds`、`acceptsTransfers` 现在是可变属性
        - `allowNether` 被 `GameRules#RULE_ALLOW_NETHER` 取代
        - `spawnMonsters` 被 `GameRules#RULE_SPAWN_MONSTERS` 取代
        - `enabledCommandBlock` 被 `GameRules#RULE_COMMAND_BLOCKS_ENABLED` 取代
        - `managementServerEnabled` - 返回是否启用了管理服务器。
        - `managementServerHost` - 返回管理服务器通信的主机。
        - `managementServerPort` - 返回管理服务器通信的端口。
        - `statusHeartbeatInterval` - 返回管理服务器发送以确保 Minecraft 服务器仍然存活的心跳间隔。
        - `MANAGEMENT_SERVER_TLS_ENABLED_KEY`、`MANAGEMENT_SERVER_TLS_KEYSTORE_KEY`、`MANAGEMENT_SERVER_TLS_KEYSTORE_PASSWORD_KEY` - 用于与管理服务器通信的 TLS 密钥库设置。
        - `managementServerSecret` - 授权令牌密钥。
        - `managementServerTlsEnabled` - 是否应使用 TLS 作为通信协议。
        - `managementServerTlsKeystore` - 指定用于 TLS 密钥库的文件路径。
        - `managementServerTlsKeystorePassword` - 指定密钥库文件的密码。
    - `Settings#getMutable` - 获取设置键和默认值的可变属性。
- `net.minecraft.server.jsonrpc`
    - `Connection` - 管理服务器发送的 json 元素的入站处理程序。
    - `IncomingRpcMethod` - 管理服务器发送的传入消息的定义和处理程序。
    - `IncomingRpcMethods` - 所有原版传入 RPC 处理程序。
    - `JsonRPCErrors` - 一个枚举，包含尝试读取、解析或执行方法时可能抛出的错误。
    - `JsonRpcLogger` - 一个用于 Minecraft 服务器执行的操作（无论是通信还是逻辑）的通用日志记录器。
    - `JsonRpcNotificationService` - 一个向所有连接的 Minecraft 服务器广播的通知服务。
    - `JsonRPCUtils` - 用于请求对象和错误的实用工具。
    - `ManagementServer` - 一个用于 Minecraft 服务器与管理服务器通信的基本 websocket 通信。
    - `OutgoingRpcMethod` - 对管理服务器的传出请求的定义和处理程序。
    - `OutgoingRpcMethods` - 所有原版传出 RPC 处理程序。
    - `PendingRpcRequest` - Minecraft 服务器向管理服务器发出的待处理请求。
- `net.minecraft.server.jsonrpc.api`
    - `MethodInfo` - 定义由管理服务器处理的方法，无论是入站还是出站。
    - `ParamInfo` - 定义特定方法接受的参数。
    - `PlayerDto` - 表示玩家的数据传输对象。
    - `ReferenceUtil` - 用于创建本地引用 URI 的实用工具。
    - `ResultInfo` - 定义特定方法返回的响应。
    - `Schema` - 用于发现服务、参数和结果的 JSON 模式的实现。
    - `SchemaComponent` - 模式中某个组件的引用定义。
- `net.minecraft.server.jsonrpc.dataprovider.JsonRpcApiSchema` - 一个从发现服务生成 JSON 模式的数据提供者。
- `net.minecraft.server.jsonrpc.internalapi`
    - `GameRules` - 一个获取当前游戏规则值的 API。
    - `MinecraftAllowListService` - 一个处理来自管理服务器的关于允许列表的通信的 Minecraft 中间层。
    - `MinecraftAllowListServiceImpl` - 允许列表实现。
    - `MinecraftApi` - 一个处理所有与管理服务器通信的服务的 Minecraft API。
    - `MinecraftBanListService` - 一个处理来自管理服务器的关于禁令列表的通信的 Minecraft 中间层。
    - `MinecraftBanListServiceImpl` - 禁令列表实现。
    - `MinecraftExecutorService` - 一个提交任意 runnable 或 supplier 以在服务器上执行的 Minecraft 中间层。
    - `MinecraftExecutorServiceImpl` - 执行器实现。
    - `MinecraftGameRuleService` - 一个处理来自管理服务器的关于游戏规则的通信的 Minecraft 中间层。
    - `MinecraftExecutorServiceImpl` - 执行器实现。
    - `MinecraftOperatorListService` - 一个处理来自管理服务器的关于操作员命令的通信的 Minecraft 中间层。
    - `MinecraftOperatorListServiceImpl` - 操作员列表实现。
    - `MinecraftPlayerListService` - 一个处理来自管理服务器的关于玩家列表的通信的 Minecraft 中间层。
    - `MinecraftPlayerListServiceImpl` - 玩家列表实现。
    - `MinecraftServerSettingsService` - 一个处理来自管理服务器的关于服务器设置的通信的 Minecraft 中间层。
    - `MinecraftServerSettingsServiceImpl` - 服务器设置实现。
    - `MinecraftServerStateService` - 一个处理来自管理服务器的关于当前服务器状态和发送消息的通信的 Minecraft 中间层。
    - `MinecraftServerStateServiceImpl` - 服务器状态实现。
- `net.minecraft.server.jsonrpc.methods`
    - `AllowlistService` - 一个处理来自管理服务器的关于允许列表的通信的服务。
    - `BanlistService` - 一个处理来自管理服务器的关于玩家禁令列表的通信的服务。
    - `ClientInfo` - 当前 Minecraft 服务器连接到管理服务器的标识符。
    - `DiscoveryService` - 一个显示管理服务器支持的所有服务的模式的服务。
    - `EncodeJsonRpcException` - 尝试编码 JSON 数据包时抛出的异常。
    - `GameRulesService` - 一个处理来自管理服务器的关于游戏规则的通信的服务。
    - `IllegalMethodDefinitionException` - 当提供的方法定义非法时抛出的异常。
    - `InvalidParameterJsonRpcException` - 当方法的参数无效时抛出的异常。
    - `InvalidRequestJsonRpcException` - 当请求无效时抛出的异常。
    - `IpBanlistService` - 一个处理来自管理服务器的关于 IP 禁令列表的通信的服务。
    - `Message` - 表示字面量或可翻译组件的数据传输对象。
    - `MethodNotFoundJsonRpcException` - 当发生 404 错误时抛出的异常，表示方法不存在。
    - `OperatorService` - 一个处理来自管理服务器的关于操作员命令的通信的服务。
    - `PlayerService` - 一个处理来自管理服务器的关于玩家列表的通信的服务。
    - `RemoteRpcErrorException` - 当管理服务器上出现问题时抛出的异常。
    - `ServerSettingsService` - 一个处理来自管理服务器的关于服务器设置的通信的服务。
    - `ServerStateService` - 一个处理来自管理服务器的关于当前服务器状态和发送消息的通信的服务。
- `net.minecraft.server.jsonrpc.security`
    - `AuthenticationHandler` - 处理请求中认证令牌持有者的验证。
    - `JsonRpcSslContextProvider` - 为 TLS 通信提供密钥库上下文。
    - `SecurityConfig` - 处理密钥，从检查基本有效性到生成新密钥。
- `net.minecraft.server.jsonrpc.websocket`
    - `JsonToWebSocketEncoder` - 一个用于 JSON 的消息到消息编码器。
    - `WebSocketToJsonCodec` - 一个用于 JSON 的消息到消息解码器。
- `net.minecraft.server.notifications`
    - `EmptyNotificationService` - 一个什么都不做的通知服务。
    - `NotificationManager` - 一个用于处理多个通知服务的管理器。
    - `NotificationService` - 一个定义由监听器（如管理服务器）采取的预期操作的服务。
- `net.minecraft.server.players`
    - `BanListEntry`
        - `getReason` 现在可以为 `null`
        - `getReasonMessage` - 返回禁令原因的可翻译组件。
    - `IpBanList` 现在接受 `NotificationService`
        - `add`、`remove` - 处理列表中的条目。
    - `PlayerList` 现在接受 `NotificationService` 而不是最大玩家数
        - `maxPlayers` 已移除
        - `op` 现在有一个用于权限级别和绕过限制布尔值的重载
        - `setUsingWhiteList` -> `MinecraftServer#setUsingWhiteList`
        - `getPlayer` - 通过名称获取玩家。
    - `ServerOpList` 现在接受 `NotificationService`
        - `add`、`remove` - 处理列表中的条目。
    - `StoredUserEntry#getUser` 现在是公开的
    - `StoredUserList` 现在接受 `NotificationService`
        - `add`、`remove` 现在返回一个布尔值表示是否成功
        - `remove(StoredUserEntry<K>)` 已移除
        - `clear` - 清除所有存储的用户。
    - `UserBanList` 现在接受 `NotificationService`
        - `add`、`remove` - 处理列表中的条目。
    - `UserWhiteList` 现在接受 `NotificationService`
        - `add`、`remove` - 处理列表中的条目。

## 输入处理整合

输入处理以前传递原始值，每个值都在自己单独的参数中，由 GLFW 提供。然而，相当多的处理逻辑是冗余的，因为特定的键通常被检查，或者所有值都在从一个方法到下一个方法的烫手山芋游戏中传递。考虑到这一点，`GuiEventListener` 和其他调用中的输入处理程序现在通过事件对象处理。这些对象仍然包含 GLFW 传递的信息；然而，现在它们通过超类 `InputWithModifiers` 接口进行了许多常见检查。

有两种类型的事件：用于按键的 `KeyEvent` 和用于鼠标按下的 `MouseButtonEvent`。键、扫描码和修饰符被包装到 `KeyEvent` 中。按钮、修饰符和 XY 屏幕位置被包装到 `MouseButtonEvent` 中。因此，这通常是一个拖放替换，只需删除上述任何参数并用它们适当的事件替换。

### 按键映射类别

按键映射略有变化，不再接受原始字符串作为其类别，而是使用 `KeyMapping$Category` 记录，它本质上是一个命名空间的字符串。可以使用 `KeyMapping$Category#register` 创建类别；否则，每当映射作为比较器的一部分使用时，都会抛出错误。

```java
public static final KeyMapping.Category EXAMPLE = KeyMapping.Category.register(ResourceLocation.withNamespaceAndPath("examplemod", "example"));
```

### 双击扩展

`GuiEventListener#mouseClicked` 现在接受一个布尔值，表示该点击是否实际上是双击。

```java
// 对于某个 Screen 子类（或 AbstractWidget 或任何 GUI 对象渲染）

@Override
public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) {
    // ...
    return false;
}
```

- `com.mojang.blaze3d.platform.InputConstants`
    - `MOD_SHIFT`、`MOD_ALT`、`MOD_SUPER`、`MOD_CAPS_LOCK`、`MOD_NUM_LOCK` - 用于转换键输入的修饰键。
    - `KEY_LWIN`、`KEY_RWIN` -> `KEY_LSUPER`、`KEY_RSUPER`
    - `getKey` 现在接受 `KeyEvent` 而不是键和扫描码 `int`
    - `isKeyDown`、`setupKeyboardCallbacks`、`setupMouseCallbacks`、`grabOrReleaseMouse`、`updateRawMouseInput` 现在接受 `Window` 而不是 `long` 句柄
- `net.minecraft.client`
    - `KeyboardHandler`
        - `keyPress` 现在是私有的
        - `setup` 现在接受 `Window` 而不是 `long` 句柄
    - `KeyMapping` 现在接受 `$Category` 而不是 `String`
        - `shouldSetOnIngameFocus` - 返回键是否映射到键盘上的某个值。
        - `restoreToggleStatesOnScreenClosed` - 将切换键恢复到游戏内操作期间的状态。
        - `key` 现在是 protected
        - `release` 现在是 protected
        - `CATEGORY_*` -> `$Category#*`
            - 可以通过 `$Category#id` 获取键
            - 组件可通过 `$Category#label` 获得
        - `getCategory` 现在返回 `$Category` 而不是 `String`
        - `matches` 现在接受 `KeyEvent` 而不是键和扫描码 `int`
        - `matchesMouse` 现在接受 `MouseButtonEvent` 而不是按钮 `int`
    - `Minecraft#ON_OSX` -> `InputQuirks#ON_OSX`
    - `MouseHandler#setup` 现在接受 `Window` 而不是 `long` 句柄
    - `ToggleKeyMapping` 现在有一个接受输入类型的重载
        - 构造函数现在接受 `KeyMapping$Category` 而不是 `String`，以及一个 `boolean` 表示是否应恢复按键绑定的先前状态
- `net.minecraft.client.gui.components`
    - `AbstractButton#onPress` 现在接受 `InputWithModifiers`
    - `AbstractScrollArea#updateScrolling` 现在接受 `MouseButtonEvent` 而不是按钮信息和 XY 位置
    - `AbstractWidget`
        - `onClick` 现在接受 `MouseButtonEvent` 而不是 XY 位置以及按钮是否被双击
        - `onRelease` 现在接受 `MouseButtonEvent` 而不是 XY 位置
        - `onDrag` 现在接受 `MouseButtonEvent` 而不是 XY 位置
        - `isValidClickButton` 现在接受 `MouseButtonInfo` 而不是按钮 `int`
    - `CommandSuggestions`
        - `keyPressed` 现在接受 `KeyEvent` 而不是键、扫描码、修饰符 `int`
        - `mouseClicked` 现在接受 `MouseButtonEvent` 而不是按钮信息和 XY 位置
        - `$SuggestionsList`
            - `mouseClicked` 不再接受按钮 `int`
            - `keyPressed` 现在接受 `KeyEvent` 而不是键、扫描码、修饰符 `int`
    - `MultilineTextField#keyPressed` 现在接受 `KeyEvent` 而不是键 `int`
- `net.minecraft.client.gui.components.events.GuiEventListener`
    - `DOUBLE_CLICK_THRESHOLD_MS` -> `MouseHandler#DOUBLE_CLICK_THRESHOLD_MS`
    - `mouseClicked` 现在接受 `MouseButtonEvent` 而不是按钮信息和 XY 位置，以及按钮是否被双击
    - `mouseReleased` 现在接受 `MouseButtonEvent` 而不是按钮信息和 XY 位置
    - `mouseDragged` 现在接受 `MouseButtonEvent` 而不是按钮信息和 XY 位置
    - `keyPressed` 现在接受 `KeyEvent` 而不是键、扫描码、修饰符 `int`
    - `keyReleased` 现在接受 `KeyEvent` 而不是键、扫描码、修饰符 `int`
    - `charTyped` 现在接受 `CharacterEvent` 而不是码点 `char` 和修饰符 `int`
- `net.minecraft.client.gui.font.TextFieldHelper`
    - `charTyped` 现在接受 `CharacterEvent` 而不是码点 `char`
    - `keyPressed` 现在接受 `KeyEvent` 而不是键 `int`
- `net.minecraft.client.gui.navigation.CommonInputs` 类已移除
    - `selected` -> `InputWithModifiers#isSelection`
    - `confirm` -> `InputWithModifiers#isConfirmation`
- `net.minecraft.client.gui.screens.Screen`
    - `hasControlDown` -> `Minecraft#hasControlDown`、`InputWithModifiers#hasControlDown`
    - `hasShiftDown` -> `Minecraft#hasShiftDown`、`InputWithModifiers#hasShiftDown`
    - `hasAltDown` -> `Minecraft#hasAltDown`、`InputWithModifiers#hasAltDown`
    - `isCut` -> `InputWithModifiers#isCut`
    - `isPaste` -> `InputWithModifiers#isPaste`
    - `isCopy` -> `InputWithModifiers#isCopy`
    - `isSelectAll` -> `InputWithModifiers#isSelectAll`
- `net.minecraft.client.gui.screens.inventory.AbstractContainerScreen`
    - `hasClickedOutside` 不再接受按钮 `int`
    - `checkHotbarKeyPressed` 现在接受 `KeyEvent` 而不是键和修饰符 `int` 
- `net.minecraft.client.gui.screens.options.controls.KeyBindsList$CategoryEntry` 现在接受 `KeyMapping$Category` 而不是 `Component`
- `net.minecraft.client.gui.screens.recipebook`
    - `hasClickedOutside` 不再接受按钮 `int`
    - `RecipeBookPage#mouseClicked` 现在接受 `MouseButtonEvent` 而不是按钮信息和 XY 位置，以及按钮是否被双击
- `net.minecraft.client.input`
    - `CharacterEvent` - 某种输入交互生成一个码点，带有当前活动的修饰符。
    - `InputQuirks` - 处理输入时操作系统之间差异的实用工具。
    - `InputWithModifiers` - 定义一个带有当前活动修饰符的输入，以及一些常见的输入检查。
    - `KeyEvent` - 某种输入交互通过扫描码生成一个键，带有当前活动的修饰符。
    - `MouseButtonEvent` - 某种输入交互在 XY 位置生成一个按钮。
    - `MouseButtonInfo` - 某种输入交互生成一个带有当前活动修饰符的按钮。

## `Level#isClientSide` 现在为 private

`Level#isClientSide` 字段现在是私有的，因此所有查询都必须使用方法版本：

```java
// 对于某个 Level level
level.isClientSide();
```

- `net.minecraft.world.level.Level#isClientSide` 字段现在是私有的

## 小幅迁移

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

### 物品拥有者

Minecraft 进一步将物品模型中的物品持有者抽象为其自己的接口：`ItemOwner`。一个 `ItemOwner` 由三件事定义：持有者所在的 `level`、持有者的 `position`，以及持有者表示朝向的 Y 旋转（以度为单位）。`ItemOwner` 在每个 `Entity` 上实现；然而，它们的位置可以通过使用 `ItemOwner#offsetFromOwner` 或创建 `ItemOwner$OffsetFromOwner` 来偏移。

目前，只有新的架子方块使用偏移拥有者，以便指南针在放置时不会随机旋转。

- `net.minecraft.client.renderer.entity.ItemRenderer#renderStatic` 现在接受一个可选的 `ItemOwner` 而不是 `LivingEntity`
- `net.minecraft.client.renderer.item`
    - `ItemModel#update` 现在接受 `ItemOwner` 而不是 `LivingEntity`
    - `ItemModelResolver#updateForTopItem`、`appendItemLayers` 现在接受 `ItemOwner` 而不是 `LivingEntity`
- `net.minecraft.client.renderer.item.properties.numeric`
    - `NeedleDirectionHelper#get`、`calculate` 现在接受 `ItemOwner` 而不是 `LivingEntity`
    - `RangeSelectItemModelProperty#get` 现在接受 `ItemOwner` 而不是 `LivingEntity`
    - `Time$TimeSource#get` 现在接受 `ItemOwner` 而不是 `Entity`
- `net.minecraft.world.entity`
    - `Entity` 现在实现 `ItemOwner`
    - `ItemOwner` - 表示正在渲染的物品的拥有者。

### 容器使用者

由于 Minecraft 的这个新版本引入了铜傀儡（一种可以与库存交互的原版生物），可以使用容器的实体的概念已被抽象为其自己的接口：`ContainerUser`。`ContainerUser` 预计将在某个 `LivingEntity` 子类上实现。由于实际的库存逻辑在其他地方处理，`ContainerUser` 只有两个方法：`hasContainerOpen`，检查活体实体当前是否正在打开某个容器（例如，桶、箱子）；以及 `getContainerInteractionRange`，确定实体可以与某个容器交互的半径（以方块为单位）。

- `net.minecraft.world.Container`
    - `startOpen`、`stopOpen` 现在接受 `ContainerUser` 而不是 `Player`
    - `getEntitiesWithContainerOpen` - 返回正在与此容器交互的 `ContainerUser` 列表。
- `net.minecraft.world.entity.ContainerUser` - 通常是可以与容器交互并打开容器的实体。
- `net.minecraft.world.entity.player.Player` 现在实现 `ContainerUser`
- `net.minecraft.world.level.block.entity.EnderChestBlockEntity#startOpen`、`stopOpen` 现在接受 `ContainerUser` 而不是 `Player`

### 名称和 ID

除非需要 `GameProfile`，否则 Minecraft 现在为每个玩家传递一个 `NameAndId`。顾名思义，`NameAndId` 包含玩家的 UUID 和名称，因为对于涉及玩家实体的大多数逻辑来说，这通常就是全部所需。

- `net.minecraft.commands.arguments.GameProfileArgument`
    - `getGameProfiles` 现在返回 `NameAndId` 的集合
    - `$Result#getNames` 现在返回 `NameAndId` 的集合
- `net.minecraft.network.codec.ByteBufCodecs#PLAYER_NAME` - 玩家名称的 16 字节字符串流编解码器。
- `net.minecraft.network.protocol.status.ServerStatus$Players#Sample` 现在是一个 `NameAndId` 列表，而不是 `GameProfile`
- `net.minecraft.server`
    - `MinecraftServer`
        - `getProfilePermissions` 现在接受 `NameAndId` 而不是 `GameProfile`
        - `isSingleplayerOwner` 现在接受 `NameAndId` 而不是 `GameProfile`
        - `ANONYMOUS_PLAYER_PROFILE` 现在是一个 `NameAndId`
    - `Services` 现在接受 `UserNameToIdResolver` 而不是 `GameProfileCache`，以及一个 `ProfileResolver`
- `net.minecraft.server.players`
    - `GameProfileCache` -> `UserNameToIdResolver`、`CachedUserNameToIdResolver`；不是一对一
        - `getAsync` 已移除
        - `add(GameProfile)` 已移除
    - `NameAndId` - 一个包含配置文件的 UUID 和名称的对象。
    - `PlayerList`
        - `load` -> `loadPlayerData`，不是一对一
        - `canPlayerLogin` 现在接受 `NameAndId` 而不是 `GameProfile`
        - `disconnectAllPlayersWithProfile` 现在接受 `UUID` 而不是 `GameProfile`
        - `op`、`deop` 现在接受 `NameAndId` 而不是 `GameProfile`
        - `isWhiteListed`、`isOp` 现在接受 `NameAndId` 而不是 `GameProfile`
        - `canBypassPlayerLimit` 现在接受 `NameAndId` 而不是 `GameProfile`
    - `ServerOpList` 现在接受 `NameAndId` 作为其第一个泛型
        - `canBypassPlayerLimit` 现在接受 `NameAndId` 而不是 `GameProfile`
    - `ServerOpListEntry` 现在接受 `NameAndId` 作为其泛型和构造函数
    - `UserBanList` 现在接受 `NameAndId` 作为其第一个泛型
        - `isBanned` 现在接受 `NameAndId` 而不是 `GameProfile`
    - `UserBanListEntry` 现在接受 `NameAndId` 作为其泛型和构造函数
    - `UserWhiteList` 现在接受 `NameAndId` 作为其第一个泛型
        - `isWhiteListed` 现在接受 `NameAndId` 而不是 `GameProfile`
    - `UserWhiteListEntry` 现在接受 `NameAndId` 作为其泛型和构造函数
- `net.minecraft.world.entity.player.Player#nameAndId` - 返回玩家的名称和 ID。
- `net.minecraft.world.level.storage.PlayerDataStorage#load(Player, ProblemReporter)` -> `load(NameAndId)`，返回一个 `Optional<CompoundTag>`

### 类型化实体数据

用于存储方块和实体数据的数据组件已从使用 `CustomData` 更改为类型安全的变体 `TypedEntityData`。`TypedEntityData` 与 `CustomData` 几乎相同，存储一个 `CompoundTag`，不同之处在于它由某个 `IdType` 泛型（如 `EntityType` 或 `BlockEntityType`）表示。`CustomData` 中与方块实体和实体相关的所有方法都已移至 `TypedEntityData`。

刷怪蛋使用 `TypedEntityData` 来存储它将生成的 `EntityType`。生成的逻辑仍然与 `SpawnEggItem` 子类绑定。

- `net.minecraft.core.component.DataComponents#ENTITY_DATA`、`BLOCK_ENTITY_DATA` 现在是带有 `EntityType` 和 `BlockEntityType` id 的 `TypeEntityData`
- `net.minecraft.world.entity.EntityType#updateCustomEntityTag` 现在接受 `TypedEntityData` 而不是 `CustomData`
- `net.minecraft.world.item.Item$Properties#spawnEgg` - 添加带有实体类型的 `ENTITY_DATA` 组件。
- `net.minecraft.world.item.component`
    - `CustomData`
        - `CODEC_WITH_ID` 已移除
        - `COMPOUND_TAG_CODEC` - 用于扁平复合标签的编解码器。
        - `parseEntityId`、`parseEntityType` 已移除
        - `loadInto` -> `TypedEntityData#loadInto`
        - `update`、`read`、`size` 已移除
        - `contains` -> `TypedEntityData#contains`
        - `getUnsafe` -> `TypedEntityData#getUnsafe`
    - `TypedEntityData` - 一个提供类型安全标识符的自定义数据。
- `net.minecraft.world.level.Spawner#appendHoverText`、`getSpawnEntityDisplayName` 现在接受 `TypedEntityData` 而不是 `CustomData`
- `net.minecraft.world.level.block.entity.BeehiveBlockEntity$Occupant#entityData` 现在是一个 `TypedEntityData`

### 重载监听器共享状态

`PreparableReloadListener` 现在可以选择通过使用 `PreparableReloadListener#prepareSharedState` 在其他重载监听器之间共享数据。`prepareSharedState` 在调用 `reload` 之前在主线程上运行，可以将任意值存储到某个 `$SharedKey`，基本上作为一个字典查找。然后，一旦调用 `reload`，就可以通过键获取并使用存储的数据。通常，使用的共享值是某种 `CompletableFuture` 并在内部连接。

```java
public class FirstExampleListener implements PreparableReloadListener {

    // 创建要写入共享数据的键
    public static final PreparableReloadListener.StateKey<CompletableFuture<Void>> EXAMPLE = new PreparableReloadListener.StateKey<>();

    @Override
    public void prepareSharedState(PreparableReloadListener.SharedState state) {
        // 将数据添加到共享状态
        state.set(EXAMPLE, CompletableFuture.allOf());
    }

    @Override
    public CompletableFuture<Void> reload(PreparableReloadListener.SharedState state, Executor tasksExecutor, PreparableReloadListener.PreparationBarrier barrier, Executor reloadExecutor) {
        // 使用共享状态
        var example = state.get(EXAMPLE);
    }
}


public class SecondExampleListener implements PreparableReloadListener {

    @Override
    public CompletableFuture<Void> reload(PreparableReloadListener.SharedState state, Executor tasksExecutor, PreparableReloadListener.PreparationBarrier barrier, Executor reloadExecutor) {
        // 在不同的监听器中使用共享状态
        var example = state.get(FirstExampleListener.EXAMPLE);
    }
}
```

- `net.minecraft.server.packs.resources`
    - `PreparableReloadListener`
        - `reload` 现在接受 `PreparableReloadListener$SharedState` 而不是 `ResourceManager`
        - `prepareSharedState` - 在重载监听器重新加载之前调用的方法，用于在重载监听器之间共享数据。
        - `$SharedState` - 一个通用字典，可以在重载监听器之间提供资源，尽管它们通常应采用 `CompletableFuture` 的形式。
        - `$StateKey` - 共享状态的一个键。
    - `SimpleReloadInstance$StateFactory#create` 现在接受 `PreparableReloadListener$SharedState` 而不是 `ResourceManager`

### 加载票标志

`TicketType` 已更新为接受一个表示加载票属性位掩码的标志，而不是布尔值和枚举。

```java
// 这需要注册到 BuiltInRegistries#TICKET_TYPE
public static final TicketType EXAMPLE = new TicketType(
    20L, // 加载票超时并被移除前的刻数，如果加载票永不过时则设置为 0
    // 要设置的位标志，请参阅下面的新标志的替换和说明
    TicketType.FLAG_SIMULATION | TicketType.FLAG_LOADING
);
```

- `net.minecraft.server.level.TicketType` 现在接受一个标志位掩码，而不是布尔值和加载票用途
    - `FLAG_PERSIST`、`persist` 取代了布尔值
    - `FLAG_LOADING` 取代了 `$TicketUse#LOADING`
    - `FLAG_SIMULATION` 取代了 `$TicketUse#SIMULATION`
    - `FLAG_KEEP_DIMENSION_ACTIVE`、`shouldKeepDimensionActive` - 设置后，防止等级卸载。
    - `FLAG_CAN_EXPIRE_IF_UNLOADED`、`canExpireIfUnloaded` - 设置后，如果区块被卸载，加载票将过期。
    - `START` -> `PLAYER_SPAWN`、`SPAWN_SEARCH`
    - `$TicketUse` 类已移除
- `net.minecraft.world.level.TicketStorage`
    - `shouldKeepDimensionActive` - 检查存储中是否有任何加载票设置了维度活动标志。
    - `removeTicketIf` 现在接受 `$TicketPredicate` 而不是 `BiPredicate`
    - `$TicketPredicate` - 测试给定区块位置的加载票。

### 重生数据

重生逻辑已被整合到一个称为 `LevelData$RespawnData` 的单一对象中。重生数据保存全局位置（等级键和方块位置）以及实体的旋转。所有对原始角度和位置方法的调用已被 `Level#setRespawnData` 或 `getRespawnData` 取代，后者委托给 `MinecraftServer` 并最终委托给等级数据。

- `net.minecraft.client.multiplayer.ClientLevel#setDefaultSpawnPos` -> `Level#setRespawnData`
- `net.minecraft.network.protocol.game.ClientboundSetDefaultSpawnPositionPacket` 现在是一个记录
    - 参数已被一个 `LevelData$RespawnData` 对象取代
- `net.minecraft.server.MinecraftServer`
    - `findRespawnDimension` - 获取玩家应重生的默认 `ServerLevel`。
    - `setRespawnData` - 设置默认重生位置。
    - `getRespawnData` - 获取默认重生位置。
- `net.minecraft.server.level`
    - `ServerLevel#setDefaultSpawnPos` -> `Level#setRespawnData`
    - `ServerPlayer$RespawnConfig` 现在接受 `LevelData$RespawnData` 而不是维度、位置和角度
        - 字段仍然可以从重生数据访问
- `net.minecraft.world.level.Level#getSharedSpawnPos`、`getSharedSpawnAngle` -> `getRespawnData`、`getWorldBorderAdjustedRespawnData`，不是一对一
- `net.minecraft.world.level.storage`
    - `LevelData`
        - `getSpawnPos`、`getSpawnAngle` -> `getRespawnData`，不是一对一
        - `$RespawnData` - 定义默认重生玩家的全局位置、偏航角和俯仰角。
    - `WritableLevelData#setSpawn` 现在只接受 `LevelData$RespawnData`

### “在架子上”变换

模型现在有一个新的变换，用于确定物品如何放置在架子上，称为 `on_shelf`。

- `net.minecraft.client.renderer.block.model.ItemTransforms#fixedFromBottom` - 一个期望物品放置在某个固定底部（如架子）上的变换。
- `net.minecraft.world.item.ItemDisplayContext#ON_SHELF` - 当物品被放置在架子上时。

### 客户端资源拆分

`ClientAsset` 已被重写，以更好地指定资源引用的内容。目前，原版添加了 `ClientAsset$Texture` 来指定资源是一个纹理，它进一步子类化为用于从互联网下载的纹理的 `$DownloadedTexture`，以及用于从磁盘上某些现有资源访问的纹理的 `$ResourceTexture`。

- `net.minecraft.advancements.DisplayInfo` 现在接受一个可选的 `ClientAsset$ResourceTexture` 作为背景，而不是 `ClientAsset`
- `net.miencraft.client.renderer.texture.SkinTextureDownloader#downloadAndRegisterSkin` 现在返回 `ClientAsset$Texture` 的 future，而不是 `ResourceLocation`
- `net.minecraft.client.resources`
    - `PlayerSkin` -> `net.minecraft.world.entity.player.PlayerSkin`
        - 构造函数现在接受 `ClientAsset$Texture` 而不是 `ResourceLocation` 和 `String`
        - `texture`、`textureUrl` -> `body`
        - `capeTexture` -> `cape`
        - `elytraTexture` -> `elytra`
        - `insecure` - 构造一个 `insecure` 设置为 false 的 `PlayerSkin`。
        - `with` - 从其 `$Patch` 构建 `PlayerSkin`。
        - `$Patch` - 一个打包对象，表示在其他文件或通过网络发送时的皮肤。
    - `SkinManager$TextureCache#getOrLoad` 现在返回 `ClientAsset$Texture` 的 future，而不是 `ResourceLocation`
- `net.minecraft.core.ClientAsset` 现在是一个接口而不是记录
    - 原始实现移至 `$ResourceTexture`
    - `id` 仍然作为一个方法存在
    - `texturePath` -> `$Texture#texturePath`
    - `CODEC`、`DEFAULT_FIELD_CODEC`、`STREAM_CODEC` -> `$ResourceTexture#*`
    - `$DownloadedTexture` - 从互联网下载的纹理。
    - `$Texture` - 定义一个纹理的客户端资源。
- `net.minecraft.world.entity.animal.CatVariant#assetInfo` 现在接受 `ClientAsset$ResourceTexture` 而不是 `ClientAsset`
- `net.minecraft.world.entity.animal.frog.FrogVariant#assetInfo` 现在接受 `ClientAsset$ResourceTexture` 而不是 `ClientAsset`
- `net.minecraft.world.entity.animal.wolf.WolfVariant$AssetInfo#*` 现在接受 `ClientAsset$ResourceTexture` 而不是 `ClientAsset`
- `net.minecraft.world.entity.variant.ModelAndTexture#asset` 现在接受 `ClientAsset$ResourceTexture` 而不是 `ClientAsset`

### 光标类型

屏幕上的当前光标现在可以通过 GUI 中的 `GuiGraphics#requestCursor` 或任何其他地方的 `Window#selectCursor` 更改为本机 `CursorType`，通过 `GLFW#glfwCreateStandardCursor`。注意 `Window#setAllowCursorChanges` 必须为 true，这可以通过选项菜单设置。

- `com.mojang.blaze3d.platform.Window`
    - `setAllowCursorChanges` - 设置光标是否可以更改为不同的标准形状。
    - `selectCursor` - 将当前光标设置为指定类型。
- `com.mojang.blaze3d.platform.cursor`
    - `CursorType` - GLFW 标准光标形状的定义。
        - `createStandardCursor` - 从其形状、名称和后备创建标准光标。
    - `CursorTypes` - Blaze3d 的光标类型。
- `net.minecraft.client.Options#allowCursorChanges` - 设置光标是否可以更改为不同的标准形状。
- `net.minecraft.client.gui.GuiGraphics`
    - `requestCursor` - 请求光标提交以进行渲染。
    - `applyCursor` - 应用光标更改以进行渲染。

### 新标签

- `minecraft:block`
    - `wooden_shelves`
    - `copper_chests`
    - `lightning_rods`
    - `copper`
    - `copper_golem_statues`
    - `incorrect_for_copper_tool`
    - `chains`
    - `lanterns`
    - `bars`
- `minecraft:entity_types`
    - `cannot_be_pushed_onto_boats`
    - `accepts_iron_golem_gift`
    - `candidate_for_iron_golem_gift`
- `minecraft:item`
    - `wooden_shelves`
    - `copper_chests`
    - `lightning_rods`
    - `copper`
    - `copper_golem_statues`
    - `copper_tool_materials`
    - `repairs_copper_armor`
    - `chains`
    - `lanterns`
    - `bars`
    - `shearable_from_copper_golem`

### 新增列表

- `com.mojang.blaze3d.GraphicsWorkarounds#isGlOnDx12` - 返回渲染器是否使用 DirectX 12。
- `com.mojang.blaze3d.opengl.GlStateManager#incrementTrackedBuffers` - 增加游戏使用的缓冲区数量。
- `com.mojang.blaze3d.systems.TimerQuery#isRecording` - 返回是否有当前活动的查询。
- `net.minecraft.SharedConstants#RESOURCE_PACK_FORMAT_MINOR`、`DATA_PACK_FORMAT_MINOR` - 资源包版本的次要组件。
- `net.minecraft.advancements.critereon.MinMaxBounds`
    - `bounds` - 返回值的边界。
    - `$FloatDegrees` - 表示某个角度的浮点数的边界。
- `net.minecraft.client`
    - `Minecraft`
        - `isOfflineDevelopedMode` - 返回游戏是否处于离线开发者模式。
        - `canSwitchGameMode` - 玩家实体是否存在并具有游戏模式。
        - `playerSkinRenderCache` - 返回持有玩家渲染纹理的缓存。
        - `canInterruptScreen` - 当前屏幕是否可以被另一个屏幕关闭。
        - `packetProcessor` - 返回调度和处理数据包的处理器。
    - `Options`
        - `invertMouseX` - 当为 true 时，反转 X 轴鼠标移动。
        - `toggleAttack` - 当为 true 时，将攻击键设置为可切换。
        - `toggleUse` - 当为 true 时，将使用键设置为可切换。
        - `sprintWindow` - 双击前进键激活疾跑的时间窗口（以刻为单位）。
        - `saveChatDrafts` - 返回如果输入框关闭，正在聊天中键入的消息是否应保留。
        - `keySpectatorHotbar` - 调出旁观者快捷栏菜单的键。
    - `ToggleKeyMapping#shouldRestoreStateOnScreenClosed` - 屏幕关闭后是否应恢复先前的切换状态。
- `net.minecraft.client.animation.definitions.CopperGolemAnimation` - 铜傀儡的动画。
- `net.minecraft.client.data.models.BlockModelGenerators`
    - `and` - 将给定的条件进行 AND 运算。
    - `createShelf` - 从基础纹理和粒子纹理创建一个架子方块状态。
    - `addShelfPart` - 为架子的所有状态添加一个模型的变体。
    - `forEachHorizontalDirection` - 对一对方向和旋转执行操作。
    - `shelfCondition` - 基于架子的状态构造一个条件。
    - `createCopperGolemStatues` - 创建所有铜傀儡雕像。
    - `createCopperGolemStatue` - 为提供的方块、铜块和锈蚀状态创建一个铜傀儡雕像。
    - `createCopperChests` - 创建所有铜箱子。
    - `createCopperLantern` - 创建一个灯笼和悬挂式灯笼。
    - `createCopperChain` - 创建一个链。
    - `createCopperChainItem` - 创建一个链物品模型。
- `net.minecraft.client.data.models.model`
    - `ModelTemplate`
        - `SHELF_*` - 用于将架子构建为多部分的模型模板。
        - `LIGHTNING_ROD` - 避雷针的模型模板。
        - `CHAIN` - 链的模型模板。
        - `BARS_*` - 用于构建类似栏杆方块的模型模板。
    - `TexturedModel#CHAIN` - 链的模型提供者。
    - `TextureMapping#bars` - 类似栏杆方块的纹理映射。
    - `TextureSlot#BARS` - 对 `#bars` 纹理的引用。
- `net.minecraft.client.gui`
    - `Gui#renderDeferredSubtitles` - 在屏幕上渲染字幕。
    - `GuiGraphics#getSprite` - 从其材质获取 `TextureAtlasSprite`。
- `net.minecraft.client.gui.components`
    - `AbstractScrollArea#isOverScrollbar` - 返回当前光标位置是否在滚动条上。
    - `AbstractSelectionList`
        - `sort` - 对列表中的条目进行排序。
        - `swap` - 交换列表中两个条目的位置
        - `clearEntriesExcept` - 移除所有与提供的元素不匹配的条目。
        - `getNextY` - 返回渲染滚动组件的 Y 分量。
        - `entriesCanBeSelected` - 列表中的条目是否可以被选择。
        - `scrollToEntry` - 滚动条，使选中的条目显示在屏幕上。
        - `removeEntries` - 移除提供的列表中的所有条目。
        - `$Entry`
            - `set*` - 设置组件大小。
            - `getContent*` - 获取内容大小和位置。
    - `ChatComponent`
        - `saveAsDraft`、`discardDraft` - 处理聊天框中的草稿消息。
        - `createScreen`、`openScreen`、`preserveCurrentChatScreen`、`restoreChatScreen` - 根据草稿聊天选项处理屏幕行为。
        - `$ChatMethod` - 定义聊天的消息类型。
        - `$Draft` - 定义聊天框中的草稿消息。
    - `EditBox`
        - `DEFAULT_HINT_STYLE` - 默认提示的样式。
        - `SEARCH_HINT_STYLE` - 可搜索提示的样式，例如配方书中的提示。
        - `$TextFormatter` - 用于格式化框中字符串的接口。
    - `FittingMultiLineTextWidget#minimizeHeight` - 将小部件的高度设置为内部高度和内边距。
    - `FocusableTextWidget$BackgroundFill` - 一个枚举，表示何时应填充背景。
    - `ItemDisplayWidget#renderTooltip` - 提交要渲染的工具提示。
    - `MultiLineLabel$Align` - 处理标签的对齐方式。
    - `MultilineTextField#selectWordAtCursor` - 选择光标当前所在的单词。
    - `SpriteIconButton$Builder#withTooltip` - 设置显示消息的工具提示。
    - `StringWidget`
        - `setMaxWidth` - 设置字符串的最大宽度以及如何处理多余的宽度。
        - `$TextOverflow` - 如果文本长于最大宽度，则采取的操作。
- `net.minecraft.client.gui.components.events.GuiEventListener#shouldTakeFocusAfterInteraction` - 当为 true 时，在点击时将元素设置为焦点。
- `net.minecraft.client.gui.screens`
    - `ChatScreen`
        - `isDraft` - 框中是否有未发送的消息。
        - `exitReason` - 聊天屏幕被关闭的原因。
        - `shouldDiscardDraft` - 是否应丢弃当前的草稿消息。
        - `$ChatConstructor` - 基于草稿状态的聊天屏幕的构造函数。
        - `$ExitReason` - 聊天屏幕被关闭的原因。
    - `FaviconTexture#isClosed` - 返回纹理是否已关闭。
    - `LevelLoadingScreen`
        - `update` - 更新当前加载跟踪器和原因。
        - `$Reason` - 更改等级加载屏幕的原因。
    - `Overlay#tick` - Tick覆盖层。
    - `Screen`
        - `panoramaShouldSpin` - 返回渲染的全景图是否应旋转其相机。
        - `setNarrationSuppressTime` - 设置旁白应被抑制到什么时间。
        - `isInGameUi` - 返回屏幕是否在游戏进行中（而不是暂停菜单）打开。
        - `isAllowedInPortal` - 此屏幕是否可以在传送门过渡效果期间打开。
        - `canInterruptWithAnotherScreen` - 此屏幕是否可以被另一个屏幕关闭，默认为“按 Esc 关闭”屏幕。
- `net.minecraft.client.gui.screens.inventory.AbstractCommandBlockScreen#addExtraControls` - 向命令方块屏幕添加任何额外的小部件。
- `net.minecraft.client.gui.screens.multiplayer`
    - `CodeOfConductScreen` - 一个显示服务器的行为准则文本的屏幕。
    - `ServerSelectionList$Entry`
        - `matches` - 返回提供的条目是否与此条目匹配。
        - `join` - 处理客户端如何加入服务器条目。
- `net.minecraft.client.gui.screens.reporting.ChatSelectionScreen$ChatSelectionList#ITEM_HEIGHT` - 列表中每个条目的高度。
- `net.minecraft.client.gui.screens.worldselection.WorldSelectionList`
    - `returnToScreen` - 重新加载世界列表后返回上一个屏幕。
    - `$Builder` - 创建一个新的 `WorldSelectionList`。
    - `$Entry#getLevelSummary` - 返回所选世界的摘要。
    - `$EntryType` - 一个枚举，表示条目的世界类型。
    - `$NoWorldsEntry` - 一个没有世界可供选择的条目。
- `net.minecraft.client.main.GameConfig$GameData#offlineDeveloperMode` - 游戏是否离线并用于开发。
- `net.minecraft.client.multiplayer`
    - `ClientCommonPacketListenerImpl`
        - `seenPlayers` - 该玩家看到的所有玩家，无论他们当前是否在线。
        - `seenInsecureChatWarning` - 玩家是否已看到不安全聊天警告。
        - `$CommonDialogAccess` - 客户端网络使用的对话框访问。
    - `ClientConfigurationPacketListenerImpl#DISCONNECTED_MESSAGE` - 因不接受行为准则而断开连接时显示的消息。
    - `ClientExplosionTracker` - 跟踪客户端上发生的爆炸，专门用于处理粒子。
    - `ClientLevel`
        - `endFlashState` - 处理末地中出现的闪光状态。
        - `trackExplosionEffects` - 跟踪爆炸以处理其粒子。
    - `ClientPacketListener`
        - `getSeenPlayers` - 返回该玩家看到的所有玩家。
        - `getPlayerInfoIgnoreCase` - 获取提供的配置文件名称的玩家信息。
- `net.minecraft.client.player.LocalPlayerResolver` - 本地玩家的配置文件解析器。
- `net.minecraft.client.resources.WaypointStyle#ICON_LOCATION_PREFIX` - 路径点图标的前缀。
- `net.minecraft.client.server.IntegratedServer#MAX_PLAYERS` - 本地托管服务器允许的最大玩家数。
- `net.minecraft.client.sounds`
    - `DirectionalSoundInstance` - 一个根据相机方向改变位置的声音。
    - `SoundEngineExecutor#startUp` - 创建运行引擎的线程。
    - `SoundPreviewHandler` - 一个用于预览某个事件在给定设置下听起来如何的实用工具。
- `net.minecraft.core`
    - `BlockPos#betweenCornersInDirection` - 一个可迭代对象，按向量提供的方向遍历提供的边界。
    - `Direction#axisStepOrder` - 返回应检查给定向量的方向列表。
- `net.minecraft.core.particles.ExplosionParticleInfo` - 用作爆炸一部分的粒子。
- `net.minecraft.data.loot.BlockLootSubProvider#createCopperGolemStatueBlock` - 铜傀儡雕像的战利品表。
- `net.minecraft.data.loot.packs`
    - `VanillaBlockInteractLoot` - 来自实体交互的原版方块战利品的子提供者。
    - `VanillaChargedCreeperExplosionLoot` - 来自闪电苦力怕爆炸的原版实体战利品的子提供者。
    - `VanillaEntityInteractLoot` - 来自实体交互的原版实体战利品的子提供者。
- `net.minecraft.data.recipes.RecipeProvider#shelf` - 从一个物品构造一个架子配方。
- `net.minecraft.data.worldgen.BiomeDefaultFeatures#addNearWaterVegetation` - 在水体附近添加植被。
- `net.minecraft.gametest.framework.GameTestHelper#getTestDirection` - 获取测试面向的方向。
- `net.minecraft.network`
    - `FriendlyByteBuf#readLpVec3`、`writeLpVec3` - 处理同步压缩的 `Vec3`。
    - `LpVec3` - 一个 vec3 网络处理程序，将向量压缩和解压缩为最多两个字节和两个整数。
    - `PacketProcessor` - 用于调度和处理数据包的处理器。
- `net.minecraft.network.chat.CommonComponents#GUI_COPY_TO_CLIPBOARD` - 将聊天复制到剪贴板时显示的消息。
- `net.minecraft.network.protocol.configuration`
    - `ClientboundCodeOfConductPacket` - 一个将服务器的行为准则发送给加入客户端的数据包。
    - `ClientConfigurationPacketListener#handleCodeOfConduct` - 处理从服务器发送的行为准则。
    - `ServerboundAcceptCodeOfConductPacket` - 一个发送客户端从服务器读取行为准则的接受响应的数据包。
    - `ServerConfigurationPacketListener#handleAcceptCodeOfConduct` - 处理来自客户端的行为准则接受。
- `net.minecraft.network.syncher.EntityDataSerializers`
    - `WEATHERING_COPPER_STATE` - 傀儡上铜的风化状态。
    - `COPPER_GOLEM_STATE` - 铜傀儡的逻辑状态。
    - `RESOLVABLE_PROFILE` - 实体的可解析配置文件。
- `net.minecraft.server.MinecraftServer`
    - `selectLevelLoadFocusPos` - 返回服务器的加载中心位置，通常是共享重生位置。
    - `getLevelLoadListener` - 返回用于跟踪等级加载的监听器。
    - `getCodeOfConducts` - 返回文件名到其行为准则文本的映射。
    - `enforceGameTypeForPlayers` - 设置所有玩家的游戏类型。
    - `packetProcessor` - 返回服务器的数据包处理器。
- `net.minecraft.server.commands.FetchProfileCommand` - 获取给定用户的配置文件。
- `net.minecraft.server.dedicated.DedicatedServerProperties#codeOfConduct` - 服务器是否有行为准则。
- `net.minecraft.server.level`
    - `ChunkLoadCounter` - 在等级加载或玩家生成时跟踪区块加载。
    - `ChunkMap`
        - `getLatestStatus` - 返回给定区块位置的最新状态。
        - `isTrackedByAnyPlayer` - 检查实体是否被任何玩家跟踪。
        - `forEachEntityTrackedBy` - 遍历给定玩家跟踪的每个实体。
        - `forEachReadyToSendChunk` - 遍历每个准备好发送给客户端的区块。
    - `ServerChunkCache`
        - `hasActiveTickets` - 检查当前等级是否有任何保持其加载的活动加载票。
        - `addTicketAndLoadWithRadius` - 向某个位置添加加载票，并加载该位置及其半径内的区块。
    - `ServerEntity$Synchronizer` - 处理向跟踪实体发送数据包。
    - `ServerLevel#isSpawningMonsters` - 返回服务器是否可以生成怪物。
    - `ServerPlayer$SavedPosition` - 保存玩家在磁盘上的当前位置。
- `net.minecraft.server.level.progress.ChunkLoadStatusView` - 加载区块的状态视图。
- `net.minecraft.server.network.ConfigurationTask#tick` - 每刻调用该任务，直到返回 true，然后完成任务。
- `net.minecraft.server.network.config`
    - `PrepareSpawnTask` - 一个查找玩家生成点的配置任务。
    - `ServerCodeOfConductConfigurationTask` - 一个将行为准则发送给客户端的配置任务。
- `net.minecraft.server.packs.OverlayMetadataSection`
    - `codecForPackType` - 根据资源包类型为部分构造一个编解码器。
    - `forPackType` - 从资源包类型获取元数据部分类型。
- `net.minecraft.server.packs.metadata.MetadataSectionType#withValue`、`$WithValue` - 持有元数据部分及其提供的值。
- `net.minecraft.server.packs.metadata.pack`
    - `PackFormat` - 表示资源包的主要和次要修订版本。
    - `PackMetadataSection#forPackType` - 从资源包类型获取元数据部分类型。
- `net.minecraft.server.packs.repository.PackCompatibility#UNKNOWN` - 资源包与游戏的兼容性未知，因为主要版本设置为最大整数值。
- `net.minecraft.server.packs.resources.ResourceMetadata#getTypedSection`、`getTypedSections` - 获取提供的类型的元数据部分。
- `net.minecraft.server.players.ProfileResolver` - 从其名称或 UUID 解析游戏配置文件。
- `net.minecraft.util`
    - `ExtraCodecs`
        - `gameProfileCodec` - 给定 UUID 编解码器，为 `GameProfile` 创建一个编解码器。
        - `$LateBoundIdMapper#values` - 返回映射器内的值集合。
    - `InclusiveRange#map` - 将一个泛型的范围映射到另一个泛型。
    - `Mth#ceilLong` - 返回向上取整到最近长整型的双精度值。
- `net.minecraft.util.random`
    - `Weighted#streamCodec` - 为加权条目构造一个流编解码器。
    - `WeightedList#streamCodec` - 为加权列表构造一个流编解码器。
- `net.minecraft.util.thread.BlockableEventLoop#shouldRunAllTasks` - 返回是否有任何阻塞的任务。
- `net.minecraft.world.Nameable#getPlainTextName` - 返回名称组件的字符串。
- `net.minecraft.world.entity`
    - `Avatar` - 一个构成玩家基础的实体。
    - `EntityReference`
        - `getEntity` - 根据类型类和等级返回实体。
        - 静态 `getEntity`、`getLivingEntity`、`getPlayer` - 根据其 `EntityReference` 和等级返回实体。
    - `EntityType`
        - `MANNEQUIN` - 人体模型实体类型。
        - `STREAM_CODEC` - 实体类型的流编解码器。
        - `$Builder#notInPeaceful` - 设置实体不在和平模式下生成。
    - `Entity`
        - `canInteractWithLevel` - 实体是否可以与当前等级交互。
        - `isInShallowWater` - 返回玩家是否在水中但未在水下。
        - `getAvailableSpaceBelow` - 返回实体与碰撞体之间在 Y 方向上的空间量，按给定值偏移。
        - `collectAllColliders` - 返回所有实体碰撞。
    - `InsideBlockEffectType#CLEAR_FREEZE` - 一个清除冰冻刻数的方块内效果。
    - `LivingEntity`
        - `dropFromEntityInteractLootTable` - 从实体交互的战利品表中掉落战利品。
        - `shouldTakeDrowningDamage` - 实体是否应受到溺水伤害。
    - `Mob#WEARING_ARMOR_UPGRADE_MATERIAL_CHANCE`、`WEARING_ARMOR_UPGRADE_MATERIAL_ATTEMPTS` - 盔甲材料升级的常量。
    - `PositionMoveRotation#withRotation` - 使用提供的 XY 旋转创建一个新对象。
    - `Relative`
        - `rotation` - 从 XY 布尔值获取相对旋转的集合。
        - `position` - 从 XYZ 布尔值获取相对位置的集合。
        - `direction` - 从 XYZ 布尔值获取相对增量的集合。
- `net.minecraft.world.entity.ai.Brain#isBrainDead` - 返回大脑是否没有任何记忆、传感器或行为。
- `net.minecraft.world.entity.ai.behavior.TransportItemsBetweenContainers` - 一个实体将在访问过的容器之间移动物品的行为。
- `net.minecraft.world.entity.ai.memory.MemoryModuleType`
    - `VISITED_BLOCK_POSITIONS` - 访问过的重要方块位置。
    - `TRANSPORT_ITEMS_COOLDOWN_TICKS` - 在运输物品之前等待多少刻。
    - `UNREACHABLE_TRANSPORT_BLOCK_POSITIONS` - 保存一个无法到达的位置列表。
- `net.minecraft.world.entity.ai.navigation.GroundPathNavigation#setCanPathToTargetsBelowSurface` - 设置实体是否可以将起始位置下方非空气方块下方的其他实体作为目标。
- `net.minecraft.world.entity.animal.coppergolem`
    - `CopperGolem` - 铜傀儡实体。
    - `CopperGolemAi` - 铜傀儡的大脑逻辑。
    - `CopperGolemOxidationLevel` - 一个记录，保存给定氧化等级的源事件和纹理。
    - `CopperGolemOxidationLevels` - 所有原版氧化等级。
    - `CopperGolemState` - 铜傀儡所处的当前逻辑状态。
- `net.minecraft.world.entity.decoration`
    - `HangingEntity#canCoexist` - 是否有任何其他悬挂实体与此实体位于同一位置。默认情况下，确保实体不是相同的实体类型且不面向相同的方向。
    - `Mannequin` - 一个没有连接玩家的人体模型。
- `net.minecraft.world.entity.player`
    - `Player`
        - `isMobilityRestricted` - 返回玩家是否有失明效果。
        - `handleShoulderEntities` - 处理玩家肩膀上的实体。
        - `extractParrotVariant`、`convertParrotVariant`、`*ShoulderParrot*` - 处理玩家肩膀上的鹦鹉。
    - `PlayerModelPart#CODEC` - 模型部件的编解码器。
- `net.minecraft.world.entity.raid.Raids#getRaidCentersInChunk` - 返回给定区块中的袭击中心数量。
- `net.minecraft.world.entity.vehicle.MinecartFurnace#addFuel` - 向熔炉添加燃料以推动实体。
- `net.minecraft.world.item`
    - `BucketItem#getContent` - 返回桶中持有的流体。
    - `Item$TooltipContext#isPeaceful` - 如果难度设置为和平，则返回 true。
    - `ToolMaterial#COPPER` - 铜工具材料。
    - `WeatheringCopperItems` - 一个记录，表示每个风化铜状态的物品。
- `net.minecraft.world.item.equipment`
    - `ArmorMaterials#COPPER` - 铜盔甲材料。
    - `EquipmentAssets#COPPER` - 铜装备资源的键引用。
    - `ResolvableProfile`
        - `skinPatch` - 返回玩家皮肤引用。
        - `$Static` - 使用已解析的游戏配置文件。
        - `$Dynamic` - 在使用时动态解析游戏配置文件。
        - `$Partial` - 根据提供给组件的任何信息表示游戏配置文件的一部分。
- `net.minecraft.world.level`
    - `BaseCommandBlock$CloseableCommandBlockSource` - 通常用于命令方块的命令源。
    - `ChunkPos#contains` - 给定的方块位置是否在区块中。
    - `GameRules#RULE_SPAWNER_BLOCKS_ENABLED` - 刷怪笼方块是否应生成实体。
    - `Level`
        - `getEntityInAnyDimension` - 通过 UUID 获取实体。
        - `getPlayerInAnyDimension` - 通过 UUID 获取玩家。
        - `hasEntities` - 返回提供的边界是否具有匹配类型和谓词的实体。
        - `palettedContainerFactory` - 返回用于创建调色板容器的工厂。
- `net.minecraft.world.level.border.WorldBorder$Settings#toWorldBorder` - 从设置构造世界边界。
- `net.minecraft.world.level.block`
    - `Block#dropFromBlockInteractLootTable` - 与方块交互时掉落战利品。
    - `ChestBlock`
        - `chestCanConnectTo` - 返回箱子是否可以与另一个方块合并。
        - `getConnectedBlockPos` - 获取箱子的连接方块位置。
        - `getOpenChestSound`、`getCloseChestSound` - 返回箱子打开/关闭时播放的声音。
        - `getChestType` - 根据周围的箱子返回箱子的类型。
    - `ChiseledBookShelfBlock#FACING`、`SLOT_*_OCCUPIED` - 雕纹书架
