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

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

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

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

感谢：

- @TelepathicGrunt 提供的“非常技术性的变更”部分的信息
- @RogueLogix 对“渲染管线重做”部分的审阅和评论
- @Tslat 发现关于 `equipOnInteract` 的错误

## 资源包变更

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

## 正确处理方块实体的移除

以前，`BlockEntity` 会在 `BlockBehaviour#onRemove` 中处理其所有移除逻辑，包括丢弃任何存储的物品和移除方块实体本身。然而，根据方法的使用方式，由于方块实体的可变状态，可能会导致一些奇怪的行为。出于这个原因，构成移除过程的逻辑已被拆分为两个方法：`BlockEntity#preRemoveSideEffects` 和 `BlockBehaviour#affectNeighborsAfterRemoval`。

`BlockEntity#preRemoveSideEffects` 现在负责在方块实体从等级中移除之前从中移除任何东西。默认情况下，如果 `BlockEntity` 是一个 `Container` 实例，它会将容器的内容丢弃到等级中。其他逻辑可以在这里处理，但它通常应避免移除 `BlockEntity` 本身，除非方块实体的位置倾向于动态变化，例如活塞。

然后，`LevelChunk` 逻辑将在调用 `BlockBehaviour#affectNeighborsAfterRemoval` 之前调用 `removeBlockEntity`。这应该只向其他方块发送更新，指示此方块已从等级中移除。对于 `BlockEntity` 持有者，可以通过调用 `Containers#updateNeighboursAfterDestroy` 轻松完成。否则，可能希望根据情况自己调用 `Level#updateNeighborsAt`。

- `net.minecraft.world.Containers`
    - `updateNeighboursAfterDestroy` - 在销毁指定位置的方块后更新邻居状态。
    - `dropContentsOnDestroy` 已移除，对于 `Container` 实例在 `BlockEntity#preRemoveSideEffects` 中处理
- `net.minecraft.world.level.block.entity.BlockEntity#preRemoveSideEffects` - 处理在从等级中移除方块实体之前应发生的逻辑。
- `net.minecraft.world.level.block.state.BlockBehaviour#onRemove`、`$BlockStateBase#onRemove` -> `affectNeighborsAfterRemoval`，应只处理更新周围邻居的逻辑，而不是丢弃容器数据

## 体素形状辅助类

`VoxelShape` 获得了许多辅助方法，用于对其基本状态进行更常见的变换。有用于创建居中（如果需要）盒子的 `Block` 方法，以及用于将 `VoxelShape` 旋转到其适当轴或方向的 `Shapes` 方法。还有一个 `Shapes#rotateAttachFace` 方法，用于旋转附着在另一个方块面上的某个 `VoxelShape`。结果要么存储在某个键到 `VoxelShape` 的 `Map` 中，要么在使用 `Block#getShapeForEachState` 时存储为 `Function<BlockState, VoxelShape>`。

大多数之前有公开或受保护 `VoxelShape` 的 `Block` 子类现在都是私有的，重命名为通常称为 `SHAPE` 或 `SHAPES` 的字段。存储的 `VoxelShape` 也可能在 `Function` 中，而不是直接存储映射本身。

- `com.mojang.math.OctahedralGroup`
    - `permute` - 返回给定轴在指定组内被置换到的轴。
    - `fromAngles` - 使用提供的 X 和 Y 旋转创建一个组。
- `net.minecraft.core.Direction$Axis#choose` 现在有一个接受三个布尔值的重载
- `net.minecraft.world.level.block.Block`
    - `boxes` - 创建比指定数量多一个的盒子，使用索引作为创建 `VoxelShape` 的函数的一部分。
    - `cube` - 创建一个指定大小的居中立方体。
    - `column` - 创建一个指定大小的水平居中柱体。
    - `boxZ` - 创建一个指定大小的垂直居中（围绕 X 轴）的立方体/柱体。
    - `getShapeForEachState` 现在返回一个包装 `ImmutableMap` 的 `Function`，还有一个方法只考虑指定的属性而不是所有可能的状态。
- `net.minecraft.world.phys.shapes`
    - `DiscreteVoxelShape#rotate` - 根据 `OctahedralGroup` 的置换旋转体素形状。
    - `Shapes`
        - `blockOccudes` -> `blockOccludes`
        - `rotate` - 根据 `OctahedralGroup` 的置换围绕提供的向量（如果未指定则围绕方块中心）旋转给定的体素形状。
        - `equal` - 检查两个体素形状是否等效。
        - `rotateHorizontalAxis` - 创建一个轴到 `VoxelShape` 的映射，表示围绕 Y 轴旋转的方块。
        - `rotateAllAxis` - 创建一个轴到 `VoxelShape` 的映射，表示围绕任何轴旋转的方块。
        - `rotateHorizontal` - 创建一个方向到 `VoxelShape` 的映射，表示围绕 Y 轴旋转的方块。
        - `rotateAll` - 创建一个方向到 `VoxelShape` 的映射，表示围绕任何轴旋转的方块。
        - `rotateAttachFace` - 创建一个面到方向到 `VoxelShape` 的映射，表示当附着在其他方块面上时围绕 Y 轴旋转的方块。
    - `VoxelShape#move` 现在有一个接受 `Vec3i` 的重载

## 武器、工具和盔甲：去除冗余

武器、工具和盔甲有很多更新，分别移除了对 `SwordItem`、`DiggerItem` 和 `ArmorItem` 硬编码基类的依赖。这些已被其关联的数据组件取代：`WEAPON` 用于伤害，`TOOL` 用于挖掘，`ARMOR` 用于保护，`BLOCKS_ATTACKS` 用于盾牌。此外，缺失的属性通常通过设置 `ATTRIBUTE_MODIFIERS`、`MAX_DAMAGE`、`MAX_STACK_SIZE`、`DAMAGE`、`REPAIRABLE` 和 `ENCHANTABLE` 来指定。鉴于几乎所有非特定逻辑都已移至数据组件，这些类现在已被完全移除。使用可用的物品属性方法之一或直接调用 `Item$Properties#component` 将每个物品设置为武器、工具、盔甲或三者的某种组合。

为类似盾牌的物品构造一个 `BlockAttacks` 组件：

```java
var blocker = new BlocksAttacks(
    // 使用物品时，在格挡效果应用之前等待的秒数。
    1.2f,
    // 一个标量，用于更改格挡器被禁用的刻数。
    // 如果为负数，则格挡器通常不能被禁用。
    0.5f,
    // 一个减少量列表，说明此格挡器阻挡哪种伤害类型以及阻挡多少。
    List.of(
        new DamageReduction(
            // 应用减少量所需的盾牌水平格挡角度
            90f,
            // 此减少量应应用的伤害类型集合。
            // 当为空时，它适用于所有伤害类型。
            Optional.empty(),
            // 减少攻击的基础伤害。
            1f,
            // 表示被阻挡的伤害分数的标量。
            0.5f
        )
    ),
    // 一个函数，决定要从格挡器中移除多少耐久度。
    new ItemDamageFunction(
        // 指定从格挡器移除耐久度所需的最小伤害量的阈值。
        4f,
        // 从格挡器中移除的基础耐久度。
        1f,
        // 表示要转换为移除耐久度的伤害分数的标量。
        0.5f
    ),
    // 一个标签键，包含可以绕过格挡器并对持有实体直接造成伤害的物品。如果为空，则没有物品可以绕过格挡器。
    Optional.of(DamageTypeTags.BYPASSES_SHIELD),
    // 当格挡器成功减轻一些伤害时播放的声音。
    Optional.of(SoundEvents.SHIELD_BLOCK),
    // 当格挡器被武器禁用时播放的声音。
    Optional.of(SoundEvents.SHIELD_BREAK)
);
```

为类似剑的物品构造一个 `Weapon` 组件：

```java
var weapon = new Weapon(
    // 从物品中移除的耐久度。
    3,
    // 当被此武器击中时，`BlocksAttack`s 组件物品应被禁用的秒数。
    5f
);
```

- `net.minecraft.core.component.DataComponents`
    - `UNBREAKABLE` 现在是一个 `Unit` 实例
    - `HIDE_ADDITIONAL_TOOLTIP`、`HIDE_TOOLTIP` 已被整合到 `TOOLTIP_DISPLAY` 中，接受一个 `TooltipDisplay`
    - `BLOCKS_ATTACKS` - 一个组件，决定持有的物品是否可以阻挡来自某些伤害源的攻击
    - `INSTRUMENT` 现在接受一个 `InstrumentComponent`
    - `PROVIDES_TRIM_MATERIAL`、`PROVIDES_BANNER_PATTERNS` 处理其关联类型的提供者。
    - `BEES` 现在接受一个 `Bees` 组件
    - `BREAK_SOUND` - 物品损坏时播放的声音。
- `net.minecraft.data.recipes`
    - `RecipeProvider#trimSmithing` 现在接受 `TrimPattern` 的键
    - `SmithingTrimRecipeBuilder` 现在接受 `TrimPattern` 的持有者
- `net.minecraft.world.entity.LivingEntity`
    - `blockUsingShield` -> `blockUsingItem`
    - `blockedByShield` -> `blockedByItem`
    - `hurtCurrentlyUsedShield` 已移除
    - `canDisableBlocking` -> `getSecondsToDisableBlocking`，不是一对一
    - `applyItemBlocking` - 应用用物品格挡攻击时所做的伤害减少。
    - `isDamageSourceBlocked` 已移除
- `net.minecraft.world.entity.player.Player#disableShield` -> `net.minecraft.world.item.component.BlocksAttacks#disable`
- `net.minecraft.world.item`
    - `AnimalArmorItem` 类已移除
    - `ArmorItem` 类已移除
    - `AxeItem` 现在继承 `Item`
    - `BannerPatternItem` 类已移除
    - `DiggerItem` 类已移除
    - `FireworkStarItem` 类已移除
    - `HoeItem` 现在继承 `Item`
    - `InstrumentItem` 不再接受标签键
    - `Item`
        - `getBreakingSound` 已移除
        - `$Properties`
            - `tool` - 将物品设置为工具。
            - `pickaxe` - 将物品设置为镐。
            - `sword` - 将物品设置为剑。
            - `axe` - 将物品设置为斧。
            - `hoe` - 将物品设置为锄。
            - `shovel` - 将物品设置为锹。
            - `trimMaterial` - 将物品设置为提供纹饰材料。
    - `ItemStack#getBreakingSound` 已移除
    - `PickaxeItem` 类已移除
    - `ShovelItem` 现在继承 `Item`
    - `SwordItem` 类已移除
    - `ToolMaterial#applyToolProperties` 现在接受一个布尔值，表示武器是否可以禁用格挡器（例如盾牌）
- `net.minecraft.world.item.component`
    - `Bees` - 一个包含蜂巢居住者的组件。
    - `BlocksAttacks` - 用于用持有的物品格挡攻击的组件。
    - `InstrumentComponent` - 一个包含乐器播放声音的组件。
    - `ProvidesTrimMaterial` - 一个为某些盔甲提供要使用的纹饰材料的组件。
    - `Tool` 现在接受一个布尔值，表示该工具是否可以在创造模式下破坏方块
    - `Unbreakable` 类已移除
    - `Weapon` - 一个数据组件，包含物品可以造成多少伤害以及它禁用格挡器（例如盾牌）的时间。
- `net.minecraft.world.item.equipment`
    - `AllowedEntitiesProvider` - 一个函数式接口，用于获取允许处理关联逻辑的实体。
    - `ArmorMaterial`
        - `humanoidProperties` -> `Item$Properties#humanoidArmor`
        - `animalProperties` -> `Item$Properties#wolfArmor`、`horseArmor`
        - `createAttributes` 现在是公开的
    - `Equippable`
        - `equipOnInteract` - 当为 true 时，该物品可以在与另一个实体交互时装备到该实体上。
        - `saddle` - 为马鞍创建一个可装备。
        - `equipOnTarget` - 将物品装备到目标实体上。

### 推断马鞍：装备变更

为马鞍添加了一个新的 `EquipmentSlot`，这带来了用于泛化槽位逻辑的新变化。

首先，现在可以通过一个称为 `SimpleEquipmentLayer` 的附加 `RenderLayer` 来处理实体的装备槽位渲染。这接受实体渲染器、`EquipmentLayerRenderer`、要渲染的层类型、从实体状态获取 `ItemStack` 的函数，以及成年和幼年模型。渲染器将尝试从关联的可装备数据组件中查找客户端信息，并使用该信息在必要时渲染层。

接下来，实体上不再为每个装备槽位设置单独的列表，而是有一个通用的 `EntityEquipment` 对象，它持有一个槽位到 `ItemStack` 的映射委托。这大大简化了存储逻辑。

最后，可装备现在可以通过设置 `equipOnInteract` 来指定物品是否应在交互时（通常是右键单击）装备到生物上。

- `net.minecraft.client.model`
    - `CamelModel`
        - `head` 现在是公开的
        - `createBodyMesh` - 创建骆驼的网格定义。
    - `CamelSaddleModel` - 带有马鞍的骆驼模型。
    - `DonkeyModel#createSaddleLayer` - 为带有马鞍的驴创建层定义。
    - `EquineSaddleModel` - 带有马鞍的马科动物的模型。
    - `PolarBearModel#createBodyLayer` 现在接受一个布尔值，表示实体是否为幼年
- `net.minecraft.client.renderer.entity.layers.HorseArmorLayer`、`SaddleLayer` -> `SimpleEquipmentLayer`
- `net.minecraft.client.renderer.entity.state`
    - `CamelRenderState#isSaddled` -> `saddle`，不是一对一
    - `EquineRenderState#isSaddled` -> `saddle`，不是一对一
    - `PigRenderState#isSaddled` -> `saddle`，不是一对一
    - `SaddleableRenderState` 类已移除
    - `StriderRenderState#isSaddled` -> `saddle`，不是一对一
    - `CamelRenderState#isSaddled` -> `saddle`，不是一对一
- `net.minecraft.client.resources.model.EquipmentClientInfo$LayerType` 现在包含：
    - `PIG_SADDLE`
    - `STRIDER_SADDLE`
    - `CAMEL_SADDLE`
    - `HORSE_SADDLE`
    - `DONKEY_SADDLE`
    - `MULE_SADDLE`
    - `ZOMBIE_HORSE_SADDLE`
    - `SKELETON_HORSE_SADDLE`
    - `trimAssetPrefix` - 返回应用于包含关联类型的盔甲纹饰的纹理的前缀。
- `net.minecraft.world.entity`
    - `EntityEquipment` - 一个槽位到物品堆栈的映射，表示实体的装备。
    - `EquipmentSlot`
        - `SADDLE`、`$Type#SADDLE`
        - `canIncreaseExperience` - 该槽位是否可以在杀死生物时增加获得的经验值数量。
    - `EquipmentSlotGroup` 现在是一个可迭代对象
        - `SADDLE`
        - `slots` - 返回组内的槽位。
    - `LivingEntity`
        - `getEquipSound` - 获取将物品装备到槽位时要播放的声音。
        - `getArmorSlots`、`getHandSlots`、`getArmorAndBodyArmorSlots`、`getAllSlots` 已移除
        - `equipment` - 实体穿戴的装备。
        - `createEquipment` - 设置实体穿戴的默认装备。
        - `drop` - 丢弃指定的堆栈。
        - `getItemBySlot`、`setItemBySlot` 不再是抽象的。
        - `verfiyEquippedItem` 已移除
    - `Mob`
        - `isSaddled` - 检查马鞍槽位中是否有物品。
        - `createEquipmentSlotContainer` - 为装备槽位创建一个单物品容器。
    - `OwnableEntity#getRootOwner` - 获取实体的最高级所有者。
    - `Saddleable` 接口已移除
- `net.minecraft.world.entity.animal.horse.AbstractHorse`
    - `syncSaddletoClients` 已移除
    - `getBodyArmorAccess` 已移除
- `net.minecraft.world.entity.player`
    - `Inventory`
        - `armor`、`offhand` -> `EQUIPMENT_SLOT_MAPPING`，不是一对一
        - `selected` 现在是私有的
        - `setSelectedHotbarSlot` -> `setSelectedSlot`
            - 还存在获取器 `getSelectedSlot`
        - `getSelected` -> `getSelectedItem`
            - 还存在设置器 `setSelectedItem`
        - `getNonEquipmentItems` - 返回库存中的非装备物品列表。
        - `getDestroySpeed` 已移除
        - `getArmor` 已移除
    - `PlayerEquipment` - 玩家穿戴的装备。
- `net.minecraft.world.item`
    - `Item#inventoryTick(ItemStack, Level, Entity, int, boolean)` -> `inventoryTick(ItemStack, ServerLevel, Entity, EquipmentSlot)`
    - `SaddleItem` 类已移除

## 加权列表重做

加权随机列表已被重新设计为一个基本类，用于保存加权条目，以及一个辅助类，可以从对象本身获取权重。

首先是 `WeightedList`。它实际上是 `SimpleWeightedRandomList` 的替代品，通过将 `Weighted`（`WeightedEntry` 的替代品）条目存储在列表本身中，以完全相同的方式工作。在内部，列表要么存储为对象条目的扁平数组，要么在总权重大于 64 时存储为紧凑加权列表。然后，要获取一个随机元素，可以调用 `getRandom` 或 `getRandomOrThrow` 来获取一个条目。如果列表中没有元素，这两个方法都将返回某种形式的空对象或异常。

然后是 `WeightedRandom` 中的静态辅助方法。这些方法接受原始列表和某个 `ToIntFunction`，该函数从列表的对象中获取权重。一些方法还接受一个整数，表示要选择的最大索引或与加权索引关联的条目。

- `net.minecraft.client.resources.model.WeightedBakedModel` 现在接受 `WeightedList` 而不是 `SimpleWeightedRandomList`
- `net.minecraft.util.random`
    - `SimpleWeightedRandomList`、`WeightedRandomList` -> `WeightedList`，现在是 final，不是一对一
        - `contains` - 检查列表是否包含此元素。
    - `Weight` 类已移除
    - `WeightedEntry` -> `Weighted`
    - 所有 `WeightedRandom` 静态方法现在接受一个 `ToIntFunction` 来获取提供的列表中某个条目的权重
- `net.minecraft.util.valueproviders.WeightedListInt` 现在接受 `WeightedList`
- `net.minecraft.world.level.SpawnData#LIST_CODEC` 现在是一个 `WeightedList` 的 `SpawnData`
- `net.minecraft.world.level.biome`
    - `Biome#getBackgroundMusic` 现在是一个 `WeightedList` 的 `Music`
    - `BiomeSpecialEffects#getBackgroundMusic`、`$Builder#backgroundMusic` 现在是一个 `WeightedList` 的 `Music`
    - `MobSpawnSettings#EMPTY_MOB_LIST`、`getMobs` 现在是一个 `WeightedList`
- `net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerConfig#spawnPotentialsDefinition`、`lootTablesToEject` 现在接受 `WeightedList`
- `net.minecraft.world.level.chunk.ChunkGenerator#getMobsAt` 现在返回一个 `WeightedList`
- `net.minecraft.world.level.levelgen.feature.stateproviders.WeightedStateProvider` 现在使用 `WeightedList`
- `net.minecraft.world.level.levelgen.heightproviders.WeightedListHeight` 现在使用 `WeightedList`
- `net.minecraft.world.level.levelgen.structure.StructureSpawnOverride` 现在接受 `WeightedList`
- `net.minecraft.world.level.levelgen.structure.pools.alias`
    - `PoolAliasBinding#random`、`randomGroup` 现在接受 `WeightedList`
    - `Random` 现在接受 `WeightedList`
    - `RandomGroup` 现在接受 `WeightedList`
- `net.minecraft.world.level.levelgen.structure.structures.NetherFortressStructure#FORTRESS_ENEMIES` 现在是一个 `WeightedList`

## 加载票

加载票已被重新实现为一个半类型注册表、半硬编码的系统。使区块在特定时间段内保持加载或模拟的底层逻辑仍然存在；然而，与每个加载票关联的逻辑被硬编码到它们适当的位置，例如强制加载或玩家加载加载票。

加载票从其注册的 `TicketType` 开始，其中包含有关加载票应持续多少刻（如果永久则为 `0`）、是否应将加载票保存到磁盘以及加载票的用途的信息。加载票有两种潜在用途：一种用于加载区块并保持其加载，另一种用于根据加载票创建者的预期移动来模拟区块。大多数加载票指定它们同时用于加载和模拟。

有两种特殊类型具有关联的额外行为。`TicketType#FORCED` 有一些立即加载区块并保持其加载的逻辑。`TicketType#UNKNOWN` 不能自动超时，意味着除非明确指定，否则它们永远不会被移除。

```java
// 您需要将加载票类型注册到 `BuiltInRegistries#TICKET_TYPE`
public static final TicketType EXAMPLE = new TicketType(
    // 加载票被移除前的刻数
    // 如果不应移除，则设置为 0
    0L,
    // 是否应将加载票保存到磁盘
    true,
    // 加载票的用途
    TicketType.TicketUse.LOADING_AND_SIMULATION
);
```

然后是 `Ticket` 类，它实际存储在 `TicketStorage` 中并由其处理。`Ticket` 类接受加载票的类型，并使用它来自动填充它到期的时间。它还接受加载票等级，通常是一个值 31（用于实体Tick和方块Tick）、32（用于方块Tick）或 33（只能访问静态或修改，不能自然更新）减去可以加载的区块半径。然后通过调用 `TicketStorage#addTicketWithRadius` 或其委托 `ServerChunkCache#addTicketWithRadius` 将加载票添加到进程中。如果您希望手动指定加载票而不是根据其半径计算，也可以使用 `addTicket`。

- `net.minecraft.server.level`
    - `ChunkMap` 现在接受 `TicketStorage`
        - `$TrackedEntity#broadcastIgnorePlayers` - 将数据包广播给所有玩家，但 UUID 列表中的玩家除外。
    - `DistanceManager`
        - `chunksToUpdateFutures` 现在是 protected，并接受一个 `TicketStorage`
        - `purgeStaleTickets` -> `net.minecraft.world.level.TicketStorage#purgeStaleTickets`
        - `getTicketDebugString` -> `net.minecraft.world.level.TicketStorage#getTicketDebugString`
        - `getChunkLevel` - 返回当前区块等级，或当提供的布尔值为 true 时返回模拟等级。
        - `getTickingChunks` 已移除
        - `removeTicketsOnClosing` 已移除
        - `$ChunkTicketTracker` -> `LoadingChunkTracker` 或 `SimulationChunkTracker`
    - `ServerChunkCache`
        - `addRegionTicket` -> `addTicketWithRadius` 或 `addTicket`
        - `removeRegionTicket` -> `removeTicketWithRadius`
        - `removeTicketsOnClosing` -> `deactivateTicketsOnClosing`
    - `Ticket` 不再是 final，也不再实现 `Comparable`
        - 构造函数不再接受键
        - `CODEC`
        - `setCreatedTick`、`timedOut` -> `resetTicksLeft`、`decreaseTicksLeft`、`isTimedOut`；不是一对一
    - `TicketType` 现在是一个记录，不再有泛型
        - `getComparator` 已移除
        - `doesLoad`、`doesSimulate` - 检查加载票用途是否用于其特定实例。
        - `$TicketUse` - 加载票可以用于什么。
    - `TickingTracker` -> `SimulationChunkTracker`
- `net.minecraft.world.level.ForcedChunksSavedData` -> `TicketStorage`
- `net.minecraft.world.level.chunk.ChunkSource`
    - `updateChunkForced` 现在返回一个布尔值，指示区块是否已被强制加载
    - `getForceLoadedChunks` - 返回所有已被强制加载的区块。

## 游戏测试大修

游戏测试已被完全改造为一个基于注册表的系统，与之前自动注解驱动的系统完全不同。然而，使用该系统所需的大多数实现必须由您自己完成，而不是由原版提供。因此，此说明将涵盖整个系统，包括哪些部分需要大量工作才能使其类似于先前版本的注解驱动系统。

### 环境

所有游戏测试都在某个环境中发生。大多数情况下，测试可以独立于区域进行，但有时环境需要以某种方式进行管理，例如检查实体或方块在给定时间是否执行了某些操作。为了促进给定测试实例的环境设置和拆除，创建了一个 `TestEnvironmentDefinition`。

`TestEnvironmentDefinition` 的工作方式类似于 `BeforeBatch` 和 `AfterBatch` 注解。环境包含两个方法 `setup` 和 `teardown`，用于管理测试的 `ServerLevel`。环境以基于类型的注册表系统构建，这意味着每个环境将一个 `MapCodec` 注册到内置注册表 `minecraft:test_environment_definition_type`，然后通过数据包注册表 `minecraft:test_environment` 中的 `TestEnvironmentDefinition` 使用。

默认情况下，原版提供了 `minecraft:default` 测试环境，它什么都不做。然而，可以使用可用的测试定义类型创建其他测试环境。

#### 游戏规则

此环境类型设置测试要使用的游戏规则。在拆除期间，游戏规则将恢复为其默认值。

```json5
// examplemod:example_environment
// 在 'data/examplemod/test_environment/example_environment.json'
{
    "type": "minecraft:game_rules",

    // 要设置的具有布尔值的游戏规则列表
    "bool_rules": [
        {
            // 规则的名称
            "rule": "doFireTick",
            "value": false
        }
        // ...
    ],

    // 要设置的具有整数值的游戏规则列表
    "int_rules": [
        {
            "rule": "playersSleepingPercentage",
            "value": 50
        }
        // ...
    ]
}
```

#### 时间

此环境类型将时间设置为某个非负整数，类似于 `/time set <number>` 命令的使用方式。

```json5
// examplemod:example_environment
// 在 'data/examplemod/test_environment/example_environment.json'
{
    "type": "minecraft:time_of_day",

    // 设置世界中的时间
    // 常见值：
    // - 白天      -> 1000
    // - 中午      -> 6000
    // - 夜晚      -> 13000
    // - 午夜      -> 18000
    "time": 13000
}
```

#### 天气

此环境类型设置天气，类似于 `/weather` 命令的使用方式。

```json5
// examplemod:example_environment
// 在 'data/examplemod/test_environment/example_environment.json'
{
    "type": "minecraft:weather",

    // 可以是三个值之一：
    // - clear   （无天气）
    // - rain    （雨）
    // - thunder （雷雨）
    "weather": "thunder"
}
```

#### 函数

此环境类型提供两个 `ResourceLocation` 指向 mcfunctions，分别用于设置和拆除等级。

```json5
// examplemod:example_environment
// 在 'data/examplemod/test_environment/example_environment.json'
{
    "type": "minecraft:function",

    // 要使用的设置 mcfunction
    // 如果未指定，则不会运行任何内容
    // 指向 'data/examplemod/function/example/setup.mcfunction'
    "setup": "examplemod:example/setup",

    // 要使用的拆除 mcfunction
    // 如果未指定，则不会运行任何内容
    // 指向 'data/examplemod/function/example/teardown.mcfunction'
    "teardown": "examplemod:example/teardown"
}
```

#### 复合

如果需要多种组合，则可以使用复合环境类型（恰当地命名为 `all_of`）将上述多个环境类型串联在一起。

```json5
// examplemod:example_environment
// 在 'data/examplemod/test_environment/example_environment.json'
{
    "type": "minecraft:all_of",

    // 要使用的测试环境列表
    // 可以指定注册表名称或环境本身
    "definitions": [
        // 指向 'data/minecraft/test_environment/default.json'
        "minecraft:default",
        {
            // 原始环境定义
            "type": "..."
        }
        // ...
    ]
}
```

### 自定义类型

如果上述类型都不起作用，则可以通过实现 `TestEnvironmentDefinition` 并创建关联的 `MapCodec` 来创建自定义定义：

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

    // 构造要注册的映射编解码器
    public static final MapCodec<ExampleEnvironmentType> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
            Codec.INT.fieldOf("value1").forGetter(ExampleEnvironmentType::value1),
            Codec.BOOL.fieldOf("value2").forGetter(ExampleEnvironmentType::value2)
        ).apply(instance, ExampleEnvironmentType::new)
    );

    @Override
    public void setup(ServerLevel level) {
        // 在此处设置任何必要的内容
    }

    @Override
    public void teardown(ServerLevel level) {
        // 撤消在 setup 方法中更改的任何内容
        // 这应恢复到默认值或之前的值
    }

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

然后使用您的模组加载器所需的任何注册表方法注册 `MapCodec`：

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

最后，您可以在环境定义中使用它：

```json5
// examplemod:example_environment
// 在 'data/examplemod/test_environment/example_environment.json'
{
    "type": "examplemod:example_environment_type",

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

### 测试函数

游戏测试的最初概念是围绕运行 `GameTestHelper` 中的函数来判定测试成功或失败。测试函数是这些函数的注册表驱动表示。本质上，每个测试函数都是一个接受 `GameTestHelper` 的方法。

目前，原版只提供 `minecraft:always_pass`，它只调用 `GameTestHelper#succeed`。测试函数也不是生成的，意味着它只是用提供的任何内容运行该值。因此，一个测试函数通常应代表一个旧的游戏测试：

```java
Registry.register(
    BuiltInRegistries.TEST_FUNCTION,
    ResourceLocation.fromNamespaceAndPath("examplemod", "example_function"),
    (GameTestHelper helper) -> {
        // 运行您想要的任何游戏测试命令
        helper.assertBlockPresent(...);

        // 确保有某种方式成功
        helper.succeedIf(() -> ...);
    }
);
```

### 测试数据

现在我们有了环境和测试函数，就可以开始定义我们的游戏测试了。这是通过 `TestData` 完成的，它相当于 `GameTest` 注解。唯一的变化是，结构现在通过 `structure` 由其 `ResourceLocation` 引用，`GameTest#timeoutTicks` 现在重命名为 `TestData#maxTicks`，并且不再指定 `GameTest#rotationSteps`，而是通过 `TestData#rotation` 提供 `Rotation`。其他所有内容保持不变，只是以不同的格式表示。

### 游戏测试实例

有了 `TestData`，我们现在可以通过 `GameTestInstance` 将所有内容链接在一起。这个实例实际上代表了一个单独的测试。再次，原版只提供默认的 `minecraft:always_pass`，因此我们需要自己构造实例。

#### 原始实例

以前的游戏测试使用 `minecraft:function` 实现，它将测试函数链接到测试数据。

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

    // 指向测试函数注册表中的 'Consumer<GameTestHelper>'
    "function": "examplemod:example_function",

    // 'TestData' 信息

    // 运行测试的环境
    // 指向 'data/examplemod/test_environment/example_environment.json'
    "environment": "examplemod:example_environment",
    // 用于游戏测试的结构
    // 指向 'data/examplemod/structure/example_structure.nbt'
    "structure": "examplemod:example_structure",
    // 游戏测试将运行直到自动失败的刻数
    "max_ticks": 400,
    // 用于设置游戏测试所需所有内容的刻数
    // 这不计入测试可以进行的最大刻数
    // 如果未指定，默认为 0
    "setup_ticks": 50,
    // 测试是否必须成功才能将批次运行标记为成功
    // 如果未指定，默认为 true
    "required": true,
    // 指定结构和所有后续辅助方法应如何为测试旋转
    // 如果未指定，则不旋转任何内容
    "rotation": "clockwise_90",
    // 当为 true 时，测试只能通过 `/test` 命令运行
    // 如果未指定，默认为 false
    "manual_only": true,
    // 指定测试可以重新运行的最大次数
    // 如果未指定，默认为 1
    "max_attempts": 3,
    // 指定测试必须发生的最小成功次数，才能将测试标记为成功
    // 这必须小于或等于允许的最大尝试次数
    // 如果未指定，默认为 1
    "required_successes": 1,
    // 返回结构边界是否应保持顶部为空
    // 这目前仅用于基于方块的测试实例
    // 如果未指定，默认为 false 
    "sky_access": false
}
```

#### 基于方块的实例

原版还通过 `minecraft:block_based` 提供了一个基于方块的测试实例。这是通过结构处理的，测试方块通过 `Level#hasNeighborSignal` 接收信号。要开始，结构必须有一个设置为启动模式的测试方块。然后触发该方块，发送一个持续一刻的十五信号脉冲。然后，结构可以有任意数量的测试方块，设置为日志、接受或失败模式。日志测试方块在激活时也会发送十五信号脉冲。接受和失败测试方块如果其中任何一个被激活，则游戏测试成功或失败（成功优先于失败）。

由于此测试依赖于结构中的测试方块，因此除了测试数据之外，不需要额外的信息：

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

    // 'TestData' 信息

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

#### 自定义测试

如果您需要实现自己的基于测试的逻辑，无论是使用更动态的功能 ~~还是因为您懒得将所有数据逻辑迁移到新系统~~，您可以通过扩展 `GameTestInstance` 并创建关联的 `MapCodec` 来创建自己的自定义测试实例：

```java
public class ExampleTestInstance extends GameTestInstance {

    // 构造要注册的映射编解码器
    public static final MapCodec<ExampleTestInstance> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
            Codec.INT.fieldOf("value1").forGetter(test -> test.value1),
            Codec.BOOL.fieldOf("value2").forGetter(test -> test.value2),
            TestData.CODEC.forGetter(ExampleTestInstance::info)
        ).apply(instance, ExampleTestInstance::new)
    );

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

    @Override
    public void run(GameTestHelper helper) {
        // 运行您想要的任何游戏测试命令
        helper.assertBlockPresent(...);

        // 确保有某种方式成功
        helper.succeedIf(() -> ...);
    }

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

    @Override
    protected MutableComponent typeDescription() {
        // 提供关于此测试应该是什么的描述
        // 应使用可翻译组件
        return Component.literal("Example Test Instance");
    }
}
```

然后使用您的模组加载器所需的任何注册表方法注册 `MapCodec`：

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

最后，您可以在测试实例中使用它：

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

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

    // 'TestData' 信息

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

- `net.minecraft.client.renderer.blockentity`
    - `BeaconRenderer` 现在有一个泛型，接受 `BlockEntity` 和 `BeaconBeamOwner` 的子类型
    - `StructureBlockRenderer` -> `BlockEntityWithBoundingBoxRenderer`，不是一对一
- `net.minecraft.core.registries.Registries#TEST_FUNCTION`、`TEST_ENVIRONMENT_DEFINITION_TYPE`、`TEST_INSTANCE_TYPE`
- `net.minecraft.gametest.Main` - 游戏测试服务器的入口点。
- `net.minecraft.gametest.framework`
    - `AfterBatch`、`BeforeBatch` 注解已移除
    - `BlockBasedTestInstance` - 用于测试测试方块的测试实例。
    - `BuiltinTestFunctions` - 包含所有已注册的测试函数。
    - `FailedTestTracker` - 用于保存所有失败的测试的对象。
    - `FunctionGameTestInstance` - 用于运行测试函数的测试实例。
    - `GameTest` 注解已移除
    - `GameTestAssertException` 现在继承 `GameTestException`
    - `GameTestException` - 游戏测试执行期间抛出的异常。
    - `GameTestBatch` 现在接受索引和环境定义，而不是名称和批次设置
    - `GameTestBatchFactory`
        - `fromTestFunction` -> `divideIntoBatches`，不是一对一
        - `toGameTestInfo` 已移除
        - `toGameTestBatch` 现在接受环境定义和索引
        - `$TestDecorator` - 从测试实例和等级创建测试信息列表。
    - `GameTestEnvironments` - 包含用于批处理游戏测试实例的所有环境。
    - `GameTestGenerator` 注解已移除
    - `GameTestHelper`
        - `tickBlock` - 在特定位置Tick方块。
        - `assertionException` - 返回一个在出错时要抛出的新异常。
        - `getBlockEntity` 现在接受一个 `Class` 来将方块实体转换为
        - `assertBlockTag` - 检查该位置的方块是否在提供的标签内。
        - `assertBlock` 现在接受一个方块 -> 组件函数，用于错误消息。
        - `assertBlockProperty` 现在接受 `Component` 而不是字符串
        - `assertBlockState` 现在接受什么都不接受、一个方块状态 -> 组件函数或一个提供的组件
        - `assertRedstoneSignal` 现在接受一个提供的组件
        - `assertContainerSingle` - 断言容器恰好包含一个指定物品。
        - `assertEntityPosition`、`assertEntityProperty` 现在接受一个组件
        - `fail` 现在接受一个 `Component` 作为错误消息
        - `assertTrue`、`assertValueEqual`、`assertFalse` 现在接受一个组件
    - `GameTestInfo` 现在接受一个持有者包装的 `GameTestInstance` 而不是 `TestFunction`
        - `setStructureBlockPos` -> `setTestBlockPos`
        - `placeStructure` 现在不返回任何内容
        - `getTestName` - `id`，不是一对一
        - `getStructureBlockPos` -> `getTestBlockPos`
        - `getStructureBlockEntity` -> `getTestInstanceBlockEntity`
        - `getStructureName` -> `getStructure`
        - `getTestFunction` -> `getTest`、`getTestHolder`，不是一对一
        - `getOrCalculateNorthwestCorner`、`setNorthwestCorner` 已移除
        - `fail` 现在接受 `Component` 或 `GameTestException` 而不是 `Throwable`
        - `getError` 现在返回 `GameTestException` 而不是 `Throwable`
    - `GameTestInstance` - 定义要运行的测试。
    - `GameTestInstances` - 包含所有已注册的测试。
    - `GameTestMainUtil` - 用于运行游戏测试服务器的工具。
    - `GameTestRegistry` 类已移除
    - `GameTestSequence`
        - `tickAndContinue`、`tickAndFailIfNotComplete` 现在接受一个整数作为刻，而不是 long
        - `thenFail` 现在接受一个提供的 `GameTestException` 而不是 `Throwable`
    - `GameTestServer#create` 现在接受一个可选的字符串和布尔值，而不是测试函数集合和起始位置
    - `GeneratedTest` - 一个包含要在给定环境下运行的测试和要应用的函数的对象
    - `GameTestTicker$State` - 一个枚举，包含游戏测试Tick器当前正在执行的状态。
    - `GameTestTimeoutException` 现在继承 `GameTestException`
    - `ReportGameListener#spawnBeacon` 已移除
    - `StructureBlockPosFinder` -> `TestPosFinder`
    - `StructureUtils`
        - `testStructuresDir` 现在是一个路径
        - `getStructureBounds`、`getStructureBoundingBox`、`getStructureOrigin`、`addCommandBlockAndButtonToStartTest` 已移除
        - `createNewEmptyStructureBlock` -> `createNewEmptyTest`，不是一对一
        - `getStartCorner`、`prepareTestStructure`、`encaseStructure`、`removeBarriers` 已移除
        - `findStructureBlockContainingPos` -> `findTestContainingPos`
        - `findNearestStructureBlock` -> `findNearestTest`
        - `findStructureByTestFunction`、`createStructureBlock` 已移除
        - `findStructureBlocks` -> `findTestBlocks`
        - `lookedAtStructureBlockPos` -> `lookedAtTestPos`
    - `TestClassNameArgument` 已移除
    - `TestEnvironmentDefinition` - 定义测试运行的环境，通过在等级上适当设置数据。
    - `TestFinder` 不再包含上下文的泛型
        - `$Builder#allTests`、`allTestsInClass`、`locateByName` 已移除
        - `$Builder#byArgument` -> `byResourceSelection`
    - `TestFunction` -> `TestData`，不是一对一
    - `TestFunctionArgument` -> `net.minecraft.commands.arguments.ResourceSelectorArgument`
    - `TestFunctionFinder` -> `TestInstanceFinder`
    - `TestFunctionLoader` - 保存要加载和运行的测试函数列表。
    - `UnknownGameTestException` - 当游戏测试的错误未知时抛出的异常。
- `net.minecraft.network.protocol.game`
    - `ClientboundTestInstanceBlockState` - 发送到客户端的数据包，包含测试的状态及其大小。
    - `ServerboundSetTestBlockPacket` - 发送到服务器的数据包，用于设置测试方块中要运行的信息。
    - `ServerboundTestInstanceBlockActionPacket` - 发送到服务器的数据包，用于在测试方块中设置测试实例。
- `net.minecraft.world.entity.player.Player`
    - `openTestBlock` - 打开一个测试方块。
    - `openTestInstanceBlock` - 为游戏测试实例打开一个测试方块。
- `net.minecraft.world.level.block`
    - `TestBlock` - 用于运行游戏测试的方块。
    - `TestInstanceBlock` - 用于管理单个游戏测试的方块。
- `net.minecraft.world.level.block.entity`
    - `BeaconBeamOwner` - 一个接口，表示具有信标光束的方块实体。
    - `BeaconBlockEntity` 现在实现 `BeaconBeamOwner`
        - `BeaconBeamSection` -> `BeaconBeamOwner$Section`
    - `BoundingBoxRenderable` - 一个接口，表示可以渲染任意大小边界框的方块实体。
    - `StructureBlockEntity` 现在实现 `BoundingBoxRenderable`
    - `TestBlockEntity` - 用于运行游戏测试的方块实体。
    - `TestInstanceBlockEntity` - 用于管理单个游戏测试的方块实体。
- `net.minecraft.world.level.block.state.properties.TestBlockMode` - 一个用于表示与测试方块关联的游戏测试当前状态的属性。

## 数据组件获取器

数据组件系统现在可以通过使用 `DataComponentGetter` 在任意对象上表示。顾名思义，获取器负责从关联的类型键获取组件。方块实体和实体都使用 `DataComponentGetter` 来允许查询内部数据，例如变体信息或自定义名称。它们都有从另一个持有者收集数据组件的方法（通过 `applyImplicitComponents` 或 `applyImplicitComponent`）。方块实体还包含通过 `collectImplicitComponents` 收集到另一个持有者的方法。

### 物品

`ItemSubPredicate` 已被完全替换为 `DataComponentPredicate`。每个子谓词在系统中都有其适当的对应项。

- `net.minecraft.advancements.critereon.*` -> `net.minecraft.core.component.predicates.*`
    - `ItemAttributeModifiersPredicate` -> `AttributeModifiersPredicate`
    - `ItemBundlePredicate`  -> `BundlePredicate`
    - `ItemContainerPredicate` -> `ContainerPredicate`
    - `ItemCustomDataPredicate` -> `CustomDataPredicate`
    - `ItemDamagePredicate` -> `DamagePredicate`
    - `ItemEnchantmentsPredicate` -> `EnchantmentsPredicate`
    - `ItemFireworkExplosionPredicate` -> `FireworkExplosionPredicate`
    - `ItemFireworksPredicate` -> `FireworksPredicate`
    - `ItemJukeboxPlayablePredicate` -> `JukeboxPlayablePredicate`
    - `ItemPotionsPredicate` -> `PotionsPredicate`
    - `ItemSubPredicate` -> `DataComponentPredicate`，不是一对一
        - `SINGLE_STREAM_CODEC`
    - `ItemSubPredicates` -> `DataComponentPredicates`，不是一对一
    - `ItemTrimPredicate` -> `TrimPredicate`
    - `ItemWritableBookPredicate` -> `WritableBookPredicate`
    - `ItemWrittenBookPredicate` -> `WrittenBookPredicate`
- `net.minecraft.advancements.critereon`
    - `BlockPredicate` 现在接受一个 `DataComponentMatchers` 用于匹配任何委托的组件数据
    - `DataComponentMatchers` - 一个对 `DataComponentGetter` 进行操作的谓词，匹配提供者上的任何精确和部分组件数据。
    - `EntityPredicate` 现在接受一个 `DataComponentMatchers` 而不是 `Optional<DataComponentExactPredicate>`
    - `ItemPredicate` 现在接受一个 `DataComponentMatchers` 用于匹配任何委托的组件数据
    - `NbtPredicate#matches` 现在接受一个 `DataComponentGetter` 而不是 `ItemStack`
    - `SingleComponentItemPredicate` 现在实现 `DataComponentPredicate` 而不是 `ItemSubPredicate`
        - `matches(ItemStack, T)` -> `matches(T)`
- `net.minecraft.core.component`
    - `DataComponentPatch`
        - `DELIMITED_STREAM_CODEC`
        - `$CodecGetter` - 获取给定组件类型的编解码器。
    - `DataComponentPredicate` -> `DataComponentExactPredicate`
        - `isEmpty` - 检查谓词内的预期组件列表是否为空。
- `net.minecraft.core.registries.Registries#ITEM_SUB_PREDICATE_TYPE` -> `DATA_COMPONENT_PREDICATE_TYPE`，不是一对一
- `net.minecraft.world.item.AdventureModePredicate` 不再接受一个布尔值来显示在工具提示中
- `net.minecraft.world.item`
    - `BannerItem#appendHoverTextFromBannerBlockEntityTag` 已移除
    - `Item#appendHoverText(ItemStack, Item.TooltipContext, List<Component>, TooltipFlag)` -> `appendHoverText(ItemStack, Item.TooltipContext, TooltipDisplay, Consumer<Component>, TooltipFlag)`，现已弃用
    - `ItemStack`
        - `addToTooltip` 现在是公开的
        - `addDetailsToTooltip` - 将物品的组件详细信息附加到工具提示。
    - `JukeboxPlayable#showInTooltip` 已移除
- `net.minecraft.world.item.component`
    - `BlockItemStateProperties` 现在实现 `TooltipProvider`
    - `ChargedProjectiles` 现在实现 `TooltipProvider`
    - `CustomData#itemMatcher` 已移除
    - `DyedItemColor#showInTooltip` 已移除
    - `FireworkExplosion#addShapeNameTooltip` 已移除
    - `ItemAttributeModifiers#showInTooltip` 已移除
    - `ItemContainerContents` 现在实现 `TooltipProvider`
    - `SeededContainerLoot` 现在实现 `TooltipProvider`
    - `TooltipDisplay` - 一个组件，处理物品工具提示中应隐藏的内容。
    - `TooltipProvider#addToTooltip` 现在接受一个 `DataComponentGetter`
- `net.minecraft.world.item.enchantment.ItemEnchantments#showInTooltip` 已移除
- `net.minecraft.world.item.equipment.trim.ArmorTrim#showInTooltip` 已移除
- `net.minecraft.world.item.trading.ItemCost` 现在接受 `DataComponentExactPredicate` 而不是 `DataComponentPredicate`
- `net.minecraft.world.level.block.Block#appendHoverText` 已移除
- `net.minecraft.world.level.block.entity`
    - `BannerPatternLayers` 现在实现 `TooltipProvider`
    - `PotDecorations` 现在实现 `TooltipProvider`
- `net.minecraft.world.level.saveddata.maps.MapId` 现在实现 `TooltipProvider`

### 实体

由于 `EntityPredicate` 现在接受一个 `DataComponentExactPredicate` 来匹配实体上的槽位，一些用于实体变体的 `EntitySubPredicate` 已转换为存储在持有的物品上的数据组件。

- `net.minecraft.advancements.critereon`
    - `EntityPredicate` 现在接受一个 `DataComponentExactPredicate` 来匹配检查的装备槽位
    - `EntitySubPredicate`
        - `AXOLTOL` -> `DataComponents#AXOLOTL_VARIANT`
        - `FOX` -> `DataComponents#FOX_VARIANT`
        - `MOOSHROOM` -> `DataComponents#MOOSHROOM_VARIANT`
        - `RABBIT` -> `DataComponents#RABBIT_VARIANT`
        - `HORSE` -> `DataComponents#HORSE_VARIANT`
        - `LLAMA` -> `DataComponents#LLAMA_VARIANT`
        - `VILLAGER` -> `DataComponents#VILLAGER_VARIANT`
        - `PARROT` -> `DataComponents#PARROT_VARIANT`
        - `SALMON` -> `DataComponents#SALMON_SIZE`
        - `TROPICAL_FISH` -> `DataComponents#TROPICAL_FISH_PATTERN`、`TROPICAL_FISH_BASE_COLOR`、`TROPICAL_FISH_PATTERN_COLOR`
        - `PAINTING` -> `DataComponents#PAINTING_VARIANT`
        - `CAT` -> `DataComponents#CAT_VARIANT`、`CAT_COLLAR`
        - `FROG` -> `DataComponents#FROG_VARIANT`
        - `WOLF` -> `DataComponents#WOLF_VARIANT`、`WOLF_COLLAR`
        - `PIG` -> `DataComponents#PIG_VARIANT`
        - 使用变体子谓词的 `register` 已移除
        - `catVariant`、`frogVariant`、`wolfVariant` 已移除
        - `$EntityHolderVariantPredicateType`、`$EntityVariantPredicateType` 已移除
    - `SheepPredicate` 不再接受 `DyeColor`
- `net.minecraft.client.renderer.entity.state.TropicalFishRenderState#variant` -> `pattern`
- `net.minecraft.core.component`
    - `DataComponentGetter` - 一个从某个对象获取数据组件的获取器。
    - `DataComponentHolder`、`DataComponentMap` 现在继承 `DataComponentGetter`
    - `DataComponentExactPredicate` 现在是一个 `DataComponentGetter` 的谓词
        - `expect` - 一个期望数据组件具有某个值的谓词。
        - `test(DataComponentHolder)` 已移除
    - `DataComponents`
        - `SHEEP_COLOR` - 绵羊的染料颜色。
        - `SHULKER_COLOR` - 潜影贝（盒）的染料颜色。
        - `COW_VARIANT` - 奶牛的变体。
        - `CHICKEN_VARIANT` - 鸡的变体。
        - `WOLF_SOUND_VARIANT` - 狼发出的声音。
- `net.minecraft.world.entity`
    - `Entity` 现在实现 `DataComponentGetter`
        - `applyImplicitComponents` - 将获取器中的组件应用到实体上。这应由模组制作者覆盖。
        - `applyComponentsFromItemStack` - 将堆栈中的组件应用到实体上。
        - `castComponentValue` - 将对象的类型转换为组件类型。
        - `setComponent` - 将组件数据设置到实体上。
        - `applyImplicitComponent` - 将组件数据应用到实体上。这应由模组制作者覆盖。
        - `applyImplicitComponentIfPresent` - 如果获取器中存在该组件，则应用它。
    - `EntityType#appendCustomNameConfig` -> `appendComponentsConfig`
    - `VariantHolder` 接口已移除
        - 因此，相关实体上的所有 `setVariant` 方法都是私有的，而关联的数据也可以从 `DataComponentGetter` 获得
- `net.minecraft.world.entity.animal`
    - `CatVariant#CODEC`
    - `Fox$Variant#STREAM_CODEC`
    - `FrogVariant#CODEC`
    - `MushroomCow$Variant#STREAM_CODEC`
    - `Parrot$Variant#STREAM_CODEC`
    - `Rabbit$Variant#STREAM_CODEC`
    - `Salmon$Variant#STREAM_CODEC`
    - `TropicalFish`
        - `getVariant` -> `getPattern`
        - `$Pattern` 现在实现 `TooltipProvider`
    - `Wolf` -> `.wolf.Wolf`
    - `WolfVariant` -> `.wolf.WolfVariant`，现在是一个记录，接受一个 `$AssetInfo` 和一个 `SpawnPrioritySelectors`
    - `WolfVariants` -> `.wolf.WolfVariants`
- `net.minecraft.world.entity.animal.axolotl.Axolotl$Variant#STREAM_CODEC`
- `net.minecraft.world.entity.animal.horse`
    - `Llama$Variant#STREAM_CODEC`
    - `Variant#STREAM_CODEC`
- `net.minecraft.world.entity.animal.wolf`
    - `WolfSoundVariant` - 狼发出的声音。
    - `WolfSoundVariants` - 所有原版狼声音变体。
- `net.minecraft.world.entity.decoration.Painting`
    - `VARIANT_MAP_CODEC` 已移除
    - `VARIANT_CODEC` 现在是私有的
- `net.minecraft.world.entity.npc.VillagerDataHolder#getVariant`、`setVariant` 已移除
- `net.minecraft.world.entity.variant.VariantUtils`- 用于获取实体变体信息的工具。
- `net.minecraft.world.item`
    - `ItemStack#copyFrom` - 从获取器复制组件。
    - `MobBucketItem#VARIANT_FIELD_CODEC` -> `TropicalFish$Pattern#STREAM_CODEC`
- `net.minecraft.world.level.block.entity.BlockEntity#applyImplicitComponents` 现在接受一个 `DataComponentGetter`
    - `$DataComponentInput` -> `DataComponentGetter`
- `net.minecraft.world.level.Spawner` 方法现在接受 `CustomData` 而不是 `ItemStack` 本身

#### 生成条件

为了允许实体在给定条件下随机生成变体，添加了一个名为 `SPAWN_CONDITION_TYPE` 的新注册表。这些接受 `SpawnCondition`：一个选择器，像一个谓词，接受上下文以查看给定的变体是否可以在那里生成。所有变体都被放入一个列表中，然后根据存储在 `SpawnProritySelectors` 中的选定优先级进行排序。优先级较高的将首先被检查，相同优先级的多个将按提供的顺序选择。然后，在相同优先级级别上，所有满足条件的变体将被随机选择。

```json5
// 对于某个存在生成条件的对象
[
    {
        // 正在检查的生成条件
        "condition": {
            "type": "minecraft:biome",
            // 将检查变体尝试生成的生物群系是否在森林中
            "biomes": "#minecraft:is_forest"
        },
        // 将首先检查此条件
        "priority": 1
    },
    {
        // 表示条件始终为真
        "priority": 0
    }
]
```

- `net.minecraft.core.registries.Registries#SPAWN_CONDITION_TYPE`
- `net.minecraft.world.entity.variant`
    - `BiomeCheck` - 一个生成条件，检查实体是否在给定的生物群系之一中。
    - `MoonBrightnessCheck` - 一个生成条件，检查月亮的亮度。
    - `PriorityProvider` - 一个基于某个优先级整数对条件选择器进行排序的接口。
    - `SpawnCondition` - 检查实体是否可以在该位置生成。
    - `SpawnConditions` - 可供选择的生成条件。
    - `SpawnContext` - 一个包含实体生成所在的当前位置、等级和生物群系的对象。
    - `SpawnPrioritySelectors` - 要针对实体检查的生成条件列表。用于在给定位置随机选择一个变体生成。
    - `StructureCheck` - 一个生成条件，检查实体是否在结构内。

#### 变体数据包注册表

青蛙、猫、奶牛、鸡、猪、狼和狼的声音变体是数据包注册表对象，意味着现在大多数引用需要通过 `RegistryAccess` 或 `HolderLookup$Provider` 实例来引用。

对于青蛙、猫或狼：

```json5
// 文件位于：
// - `data/examplemod/frog_variant/example_frog.json`
// - `data/examplemod/cat_variant/example_cat.json`
// - `data/examplemod/wolf_variant/example_wolf.json`
{
    // 指向 `assets/examplemod/textures/entity/cat/example_cat.png` 的纹理
    "asset_id": "examplemod:entity/cat/example_cat",
    "spawn_conditions": [
        // 此变体生成的条件
        {
            "priority": 0
        }
    ]
}
```

对于猪、奶牛或鸡：
```json5
// 文件位于：
// - `data/examplemod/pig_variant/example_pig.json`
// - `data/examplemod/cow_variant/example_cow.json`
// - `data/examplemod/chicken_variant/example_chicken.json`
{
    // 指向 `assets/examplemod/textures/entity/pig/example_pig.png` 的纹理
    "asset_id": "examplemod:entity/pig/example_pig",
    // 定义用于选择渲染猪变体的实体模型的 `PigVariant$ModelType`
    "model": "cold",
    "spawn_conditions": [
        // 此变体生成的条件
        {
            "priority": 0
        }
    ]
}
```

对于狼的声音变体：
```json5
// 文件位于：
// - `data/examplemod/wolf_sound_variant/example_wolf_sound.json``
{
    // 空闲时随机播放的声音事件的注册表名称
    "ambient_sound": "minecraft:entity.wolf.ambient",
    // 死亡时播放的声音事件的注册表名称
    "death_sound": "minecraft:entity.wolf.death",
    // 生气时空闲时随机播放的声音事件的注册表名称
    "growl_sound": "minecraft:entity.wolf.growl",
    // 受伤时播放的声音事件的注册表名称
    "hurt_sound": "minecraft:entity.wolf.hurt",
    // 空闲时在生命值满的情况下，随机播放（1/3 的概率）的声音事件的注册表名称
    "pant_sound": "minecraft:entity.wolf.pant",
    // 空闲时在生命值未满的情况下，随机播放（1/3 的概率）的声音事件的注册表名称
    "whine_sound": "minecraft:entity.wolf.whine"
}
```

#### 客户端资源

客户端文件中的原始 `ResourceLocation`（用于标识符或纹理）正在被定义标识符以及潜在纹理路径的对象所取代。有三个主要对象需要了解：`ClientAsset`、`ModelAndTexture` 和 `MaterialAssetGroup`。

`ClientAsset` 是一个 id/纹理对，用于指向纹理位置。默认情况下，纹理路径由 id 构造，路径以 `textures` 为前缀，并以 PNG 扩展名为后缀。

`ModelAndTexture` 是一个对象/客户端资源对，当渲染器应在多个模型之间选择时使用。通常，渲染器会创建一个对象类型到模型的映射，并提供给 `ModelAndTexture` 的对象用作映射中的查找键。

`MaterialAssetGroup` 是一个处理用某些纹饰材料渲染装备资源的处理器。它接受用于叠加到盔甲上的基础纹理，以及针对给定装备资源的任何覆盖。

- `net.minecraft.advancements.DisplayInfo` 现在接受一个 `ClientAsset` 而不是仅一个 `ResourceLocation` 作为背景纹理
- `net.minecraft.client.model`
    - `AdultAndBabyModelPair` - 保存两个 `Model` 实例，表示某个实体的成年和幼年形态。
    - `ChickenModel#createBaseChickenModel` - 创建默认的鸡模型。
    - `ColdChickenModel` - 寒冷温度下鸡的变体模型。
    - `ColdCowModel` - 寒冷温度下奶牛的变体模型。
    - `ColdPigModel` - 寒冷温度下猪的变体模型。
    - `CowModel#createBaseCowModel` - 创建奶牛的基础模型。
    - `PigModel#createBasePigModel` - 创建默认的猪模型。
    - `WarmCowModel` - 温暖温度下奶牛的变体模型。
- `net.minecraft.client.renderer.entity`
    - `ChickenRenderer` 现在继承 `MobRenderer` 而不是 `AgeableMobRenderer`
    - `CowRenderer` 现在继承 `MobRenderer` 而不是 `AgeableMobRenderer`
    - `PigRenderer` 现在继承 `MobRenderer` 而不是 `AgeableMobRenderer`
- `net.minecraft.client.renderer.entity.layers.SheepWoolUndercoatLayer` - 一个渲染绵羊羊毛底层的层。
- `net.minecraft.client.renderer.entity.state`
    - `CowRenderState` - 奶牛实体的渲染状态。
    - `SheepRenderState`
        - `getWoolColor` - 返回绵羊羊毛的整数颜色。
        - `isJebSheep` - 返回绵羊的名称是否包含 `jeb_` 前缀。
- `net.minecraft.core.ClientAsset` - 一个包含标识符和指向某个纹理的路径的对象。
- `net.minecraft.data.loot.EntityLootSubProvider#killedByFrogVariant` 现在接受 `FrogVariant` 的 `HolderGetter`
- `net.minecraft.data.tags.CatVariantTagsProvider` 类已移除
- `net.minecraft.tags.CatVariantTags` 类已移除
- `net.minecraft.world.entity.animal`
    - `AbstractCow` - 一个代表奶牛（牛）的抽象动物。
    - `Chicken#setVariant`、`getVariant` - 处理鸡的变体信息。
    - `ChickenVariant` - 一个定义给定鸡的通用可渲染信息和生物群系生成的类。
    - `ChickenVariants` - 保存所有原版鸡变体的键。
    - `Cow` 现在继承 `AbstractCow`。
    - `CowVariant` - 一个定义给定奶牛的通用可渲染信息和生物群系生成的类。
    - `CowVariants` - 保存所有原版奶牛变体的键。
    - `CatVariant(ResourceLocation)` -> `CatVariant(ClientAsset, SpawnPrioritySelectors)`
    - `CatVariants` - 保存所有原版猫变体的键。
    - `FrogVariant` -> `.frog.FrogVariant`
        - `FrogVariant(ResourceLocation)` -> `FrogVariant(ClientAsset, SpawnPrioritySelectors)`
    - `MushroomCow` 现在继承 `AbstractCow`
    - `PigVariant` - 一个定义给定猪的通用可渲染信息和生物群系生成的类。
    - `TemperatureVariants` - 一个接口，保存指示不同温度下实体的 `ResourceLocation`。
- `net.minecraft.world.entity.variant.ModelAndTexture` - 定义带有其关联纹理的模型。
- `net.minecraft.world.item.equipment.trim`
    - `MaterialAssetGroup` - 一个资源定义了一些基础以及基于所穿戴装备的排列。
    - `TrimMaterial` 现在接受 `MaterialAssetGroup` 而不是原始基础和覆盖

## 标签与解析

标签已被重写，移除了任何对类型的直接引用，同时密封并最终确定了相关类。从标签获取值现在返回一个 `Optional` 包装的条目，除非您调用 `get*Or` 方法之一，在其中指定默认值。另一方面，对象不接受默认值，而是返回所需标签的空变体。

```java
// 对于某个 `CompoundTag` tag

// 读取一个值
Optional<Integer> value1 = tag.getInt("value1");
int value1Raw = tag.getIntOr("value1", 0);

// 读取另一个对象
Optional<CompoundTag> childTag = tag.getCompound("childTag");
CompoundTag childTagRaw = tag.getCopmoundOrEmpty("childTag");
```

### 使用编解码器写入

`CompoundTag` 现在有使用 `Codec` 或 `MapCodec` 进行写入和读取的方法。对于 `Codec`，它将序列化的数据存储在指定的键内。对于 `MapCodec`，它将字段合并到顶层标签上。

```java
// 对于某个 Codec<ExampleObject> CODEC 和 MapCodec<ExampleObject> MAP_CODEC
// 我们还有一个 ExampleObject example
CompoundTag tag = new CompoundTag();

// 对于编解码器
tag.store("example_key", CODEC, example);
Optional<ExampleObject> fromCodec = tag.read("example_key", CODEC);

// 对于映射编解码器
tag.store(MAP_CODEC, example);
Optional<ExampleObject> fromMapCodec = tag.read(MAP_CODEC);
```

### 命令解析器

packrat 解析器已更新了新的规则和系统，允许命令具有基于解析器的参数。这来自于 `CommandArgumentParser`，它解析某些语法以返回所需的对象。然后解析器被 `ParserBasedArgument` 使用，它尝试解析字符串并根据您当前键入的内容构建任何建议。这些都由 `Grammar` 类处理，它实现了 `CommandArgumentParser`，使用原子、字典、规则和术语的组合构建。

- `net.minecraft.commands.ParserUtils#parseJson`
- `net.minecraft.commands.arguments`
    - `ComponentArgument` 现在继承 `ParserBasedArgument`
    - `NbtTagArgument` 现在继承 `ParserBasedArgument`
    - `StyleArgument` 现在继承 `ParserBasedArgument`
- `net.minecraft.commands.arguments.item.ItemPredicateArgument` 现在继承 `ParserBasedArgument`
- `net.minecraft.nbt`
    - `ByteArrayTag`，现在是 final，不再接受列表对象
    - `ByteTag` 现在是一个记录
    - `CollectionTag` 现在是一个密封接口，不再继承 `AbstractList` 或具有泛型
        - `set`、`add` 已移除
        - `remove` 现在返回一个 `Tag`
        - `get` - 返回指定索引处的标签。
        - `getElementType` 已移除
        - `size` - 返回集合的大小。
        - `isEmpty` - 返回集合是否没有元素。
        - `stream` - 流式传输集合的元素。
    - `CompoundTag` 现在是 final
        - `store` - 将编解码器或映射编解码器写入标签。
        - `read` - 从标签中读取编解码器或映射编解码器编码的值。
        - `getFloatOrDefault`、`getIntOrDefault`、`getLongOrDefault` - 获取具有关联键的值，如果不存在或抛出异常则返回默认值。
        - `storeNullable` - 当不为 null 时，使用编解码器将值写入标签。
        - `putUUID`、`getUUID`、`hasUUID` 已移除
        - `getAllKeys` -> `keySet`
        - `values`、`forEach` - 实现标准的映射操作。
        - 接受列表对象的 `putByteArray`、`putIntArray` 已移除
        - `getTagType` 已移除
        - `contains` 已移除
        - `get*`、`get*Or` - 返回键的可选包装对象，如果使用 `Or` 方法，则返回指定的默认值。
    - `DoubleTag` 现在是一个记录
    - `EndTag` 现在是一个记录
    - `FloatTag` 现在是一个记录
    - `IntArrayTag`，现在是 final，不再接受列表对象
    - `IntTag` 现在是一个记录
    - `ListTag`，现在是 final，继承 `AbstractList`
        - `addAndUnwrap` - 将标签添加到列表中，如果是一个包含单个元素的复合标签，则改为添加内部标签。
        - `get*`、`get*Or` - 返回键的可选包装对象，如果使用 `Or` 方法，则返回指定的默认值。
        - `compoundStream` - 返回列表中所有 `CompoundTag` 的扁平映射。
    - `LongArrayTag`，现在是 final，不再接受列表对象
    - `LongTag` 现在是一个记录
    - `NbtIo#readUnnamedTag` 现在是公开的，用于测试
    - `NbtOps` 现在有一个私有构造函数
    - `NbtUtils`
        - `getDataVersion` 现在有一个接受 `Dynamic` 的重载
        - `createUUID`、`loadUUID` 已移除
        - `readBlockPos`、`writeBlockPos` 已移除
    - `NumericTag` 现在是一个实现 `PrimitiveTag` 的密封接口
        - `getAsLong` -> `longValue`
        - `getAsInt` -> `intValue`
        - `getAsShort` -> `shortValue`
        - `getAsByte` -> `byteValue`
        - `getAsDouble` -> `doubleValue`
        - `getAsFloat` -> `floatValue`
        - `getAsNumber` -> `box`
        - `as*` - 返回数值的可选包装。
    - `PrimitiveTag` - 一个密封接口，表示标签数据是一个原始对象。
    - `ShortTag` 现在是一个记录
    - `SnbtGrammar` - 用于字符串化 NBT 的解析器创建器。
    - `SnbtOperations` - 一个包含用于解析某些值的内置操作的辅助工具。
    - `StringTag` 现在是一个记录
    - `StringTagVisitor`
        - `visit` -> `build`，不是一对一
        - `handleEscape` -> `handleKeyEscape`，现在是私有的
    - `Tag` 现在是一个密封接口
        - `as*` -> 尝试将标签转换为其子类型之一，失败时返回空 optional。
        - `getAsString` -> `asString`，不是一对一
    - `TagParser` 现在持有一个泛型，引用要解析到的中间对象的类型
        - 构造函数现在接受一个语法，或者 `create` 从 `DynamicOps` 构造语法
        - `AS_CODEC` -> `FLATTENED_CODEC`
        - `parseTag` -> `parseCompoundFully` 或 `parseCompoundAsArgument`
            - 其他方法如 `parseFully`、`parseAsArgument` 解析到某个中间对象
            - 这些都是实例方法
        - `readKey`、`readTypedValue` 已移除
    - `TagType#isValue` 已移除
- `net.minecraft.util.parsing.packrat`
    - `CachedParseState` - 一个缓存已解析位置并在读取时控制的解析状态。
    - `Control#hasCut` - 返回语法的控制流对于读取对象是否有 cut。
    - `DelayedException` - 一个创建要抛出的异常的接口。
    - `Dictionary`
        - `put` 现在返回一个 `NamedRule`
        - `put(Atom<T>, Term<S>, Rule.RuleAction<S, T>)` -> `putComplex`
        - `get` -> `getOtThrow`，不是一对一
        - `forward` - 获取或写入术语到字典。
        - `namedWithAlias` - 创建一个对命名原子或其别名的新引用。
    - `ErrorCollector$Nop` - 一个什么都不做的错误收集器。
    - `NamedRule` - 一个具有关联名称的规则。
    - `ParseState` 现在是一个接口
        - 缓存逻辑已移至 `CachedParseState`
        - `scope` - 返回解析对象内当前正在分析的范围。
        - `parse` 现在接受 `NamedRule` 而不是 `Atom`
        - `acquireControl`、`releaseControl` - 处理获取解析期间使用的 `Control`。
        - `silent` - 返回一个不收集任何错误的 `ParseState`。
    - `Rule`
        - `parse`、`$RuleAction#run` 现在返回一个可为 null 的值，而不是 optional
        - `SimpleRuleAction` 现在实现 `$RuleAction`
    - `Scope#pushFrame`、`popFrame`、`splitFrame`、`clearFrameValues`、`mergeFrame` - 处理将解析术语管理到称为帧的部分中。
    - `Term`
        - `named` -> `Dictionary#named`，不是一对一
        - `repeated`、`repeatedWithTrailingSeparator`、`repeatedWithoutTrailingSeparator` - 处理类似于 varargs 的重复术语，并将它们放入列表中。
        - `positiveLookahead`、`negativeLookahead` - 处理基于后续内容匹配信息的术语。
        - `fail` - 将术语标记为解析期间失败。
- `net.minecraft.util.parsing.packrat.commands`
    - `CommandArgumentParser` - 将字符串解析为与命令一起使用的参数。
    - `Grammar` 现在接受顶部的 `NamedRule` 而不是 `Atom`
    - `GreedyPatternParseRule` - 一个尝试贪婪匹配提供的模式的规则，假设如果某个区域匹配，则可以获得匹配的组。
    - `GreedyPredicateParseRule` - 一个尝试贪婪匹配接受的字符的规则，确保字符串达到最小大小。
    - `NumberRunParseRule` - 一个尝试从字符串解析数字的规则。
    - `ParserBasedArgument` - 一个使用解析器提取值的命令参数。
    - `ResourceLookupRule` 现在接受 id 解析器的 `NamedRule` 而不是 `Atom`
    - `StringReaderParserState` 现在继承 `CachedParsedState`
        - 不再接受 `Dictoionary`
    - `StringReaderTerms#characters` - 匹配字符串中的多个字符，通常用于捕获小写和大写变体。
    - `UnquotedStringParseRule` - 一个将序列的一部分作为未引用字符串读取的规则，确保它达到最小大小。

## 保存数据，现在带有类型

`SavedData` 已被重写，将其大部分保存和加载逻辑抽象到单独的 `SavedDataType` 中。这意味着 `save` 覆盖以及额外的 `load` 和 `factory` 方法现在都在 `SavedDataType` 本身内部处理。

要构造一个 `SavedDataType`，您需要传入四个参数。首先是字符串标识符，用于解析保存您信息的 `.dat` 文件。这必须是一个有效的路径。然后是构造函数，当没有信息存在时，它接受 `SavedData$Context` 来返回您的数据对象的实例。接下来是编解码器，它接受 `SavedData$Context` 并返回一个用于读取和写入您的保存数据的 `Codec`。最后是用于数据修复器的 `DataFixTypes`。由于这是一个静态枚举，如果您计划使用原版数据修复器，您将需要注入到枚举本身中，或者修补 `DimensionDataStorage#readTagFromDisk` 中的 `update` 调用以传入 null 值。

```java
// 我们的保存数据实例
public class ExampleSavedData extends SavedData {

    // 保存数据类型
    public static final SavedDataType<ExampleSavedData> TYPE = new SavedDataType<>(
        // 最好用您的模组 id 后跟下划线作为标识符的前缀
        // 斜杠会抛出错误，因为文件夹不存在
        // 将解析为 `saves/<world_name>/data/examplemod_example.dat`
        "examplemod_example",
        // 新实例的构造函数
        ExampleSavedData::new,
        // 用于编码和解码数据的编解码器工厂
        ctx -> RecordCodecBuilder.create(instance -> instance.group(
            RecordCodecBuilder.point(ctx.levelOrThrow()),
            Codec.INT.fieldOf("value1").forGetter(data -> data.value1),
            Codec.BOOL.fieldOf("value2").forGetter(data -> data.value2)
        ).apply(instance, ExampleSavedData::new));
    );

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


    // 用于新实例
    private ExampleSavedData(ServerLevel.Context ctx) {
        this(ctx.levelOrThrow(), 0, false);
    }

    // 用于编解码器
    // 如果不使用 `DimensionDataStorage#set`，构造函数不需要是公开的
    private ExampleSavedData(ServerLevel level, int value1, boolean value2) {
        this.level = level;
        this.value1 = value1;
        this.value2 = value2;
    }

    // 其他方法在此处
}

// 在可以访问 DimensionDataStorage storage 的地方
ExampleSavedData data = storage.computeIfAbsent(ExampleSavedData.TYPE);
```

- `net.minecraft.server.ServerScoreboard`
    - `dataFactory` 已移除
    - `createData` 现在接受一个 `$Packed` 实例
- `net.minecraft.world.RandomSequences`
    - `factory`、`load` 已移除
    - `codec` - 根据当前世界种子为随机序列构造一个编解码器。
- `net.minecraft.world.entity.raid.Raids` 不再接受任何参数
    - `getType` - 根据当前维度返回保存数据类型。
    - `factory` 已移除
    - `tick` 现在接受 `ServerLevel`
    - `getId` - 获取突袭实例的标识符。
    - `canJoinRaid` 不再接受突袭实例
    - `load` 不再接受 `ServerLevel`
- `net.minecraft.world.level.levelgen.structure.structures.StructureFeatureIndexSavedData`
    - `factory`、`load` 已移除
    - `type` - 返回具有指定 id 的要素保存数据类型。
- `net.minecraft.world.level.saveddata`
    - `SavedData`
        - `save` 已移除
        - `$Factory` 记录已移除
        - `$Context` - 保存保存数据正在写入的当前上下文。
    - `SavedDataType` - 一个表示保存数据类型的记录，包括关于如何构造、保存和加载数据的信息。
- `net.minecraft.world.level.saveddata.maps`
    - `MapIndex` 现在有一个接受最后一个地图 id 的构造函数
        - `factory`、`load` 已移除
        - `getFreeAuxValueForMap` -> `getNextMapId`
    - `MapItemSavedData`
        - `factory`、`load` 已移除
        - `type` - 使用地图 id 的键返回保存数据类型。
- `net.minecraft.world.level.storage.DimensionDataStorage` 现在接受一个 `SavedData$Context`
    - `computeIfAbsent`、`get` 现在只接受 `SavedDataType`
    - `set` 现在接受 `SavedDataType` 以及数据实例
- `net.minecraft.world.scores.ScoreboardSaveData`
    - `load` -> `loadFrom`
    - `pack` - 将数据打包到其保存数据格式中。
    - `$Packed` - 表示可序列化的打包数据。

## 渲染管线重做

无论您之前使用的是着色器还是 `RenderType`，将对象渲染到屏幕的方式都已完全或部分重做。因此，很多事情需要重新解释，下面将进行更深入的探讨。然而，对于不关心细节的人，这里是 TL;DR。

首先，着色器 JSON 不再存在。这被 `RenderPipeline` 取代，它实际上是一个代码中的替代品。其次，`RenderPipeline` 强制将大多数任意值转换为对象。例如，您不再存储混合函数模式 id，而是存储一个 `BlendFunction` 对象。同样，您不再存储或设置直接的纹理对象，而是通过 `GpuTexture` 进行管理。最后，`VertexBuffer` 可以通过直接传入 `RenderPipeline` 并更新消费者中任何必要的统一变量来绘制到帧缓冲区，或者通过传入 `RenderType` 来绘制。

现在，对于需要细节的人，让我们深入探讨。

### 抽象化 Open GL

众所周知，Minecraft 一直在抽象化其 OpenGL 调用和常量，此版本也不例外。除 `BufferUsage` 外，所有对 GL 代码的调用都已移出对象引用，通常通过调用 `GlConst$toGl` 来获得。然而，随着所有其他渲染重做，有许多变化和复杂性需要学习一个全新的系统，假设您不使用 `RenderType`。

从头开始，对底层渲染系统的所有调用都通过 `GpuDevice`，这是一个像 OpenGL 或 Vulkan 这样的渲染库的通用实现的接口。该设备负责创建缓冲区和纹理，执行任何所需的命令。可以通过 `RenderSystem` 通过 `getDevice` 获取当前的 `GpuDevice`，如下所示：

```java
GpuDevice device = RenderSystem.getDevice();
```

然后，`GpuDevice` 可以分别使用 `createBuffer` 和 `createTexture` 创建带有所需数据的缓冲区或包含要渲染信息的纹理。为冗余起见，缓冲区保存顶点数据，而纹理保存纹理（颜色和深度）数据。您通常应缓存缓冲区或纹理对象以供以后使用，并根据需要更新任何附加数据。作为参考，缓冲区通常通过使用 `BufferBuilder` 和 `ByteBufferBuilder` 首先构建 `MeshData`，然后再将其传递给 `createBuffer` 来创建。

设置好所需的缓冲区和纹理后，我们如何实际修改将它们渲染到屏幕？这由 `CommandEncoder` 处理，它也可以通过 `GpuDevice#createCommandEncoder` 从设备获得。编码器包含熟悉的读写方法，以及一些额外的将纹理清除为给定颜色或直接将纹理 blit 到屏幕（`presentTexture`）的方法。然而，这里最重要的方法是 `createRenderPass`。它接受要绘制到屏幕的 `GpuTexture` 以及背景的默认 ARGB 颜色。此外，它还可以接受深度纹理。这应该使用 try-with-resources 块来创建，如下所示：

```java
// 我们假设您已经构造了一个用于颜色数据的 `GpuTexture` texture
try (RenderPass pass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(this.texture, OptionalInt.of(0xFFFFFFFF))) {
    // 在此处设置内容

}
```

在 `RenderPass` 内部，您可以设置要使用的 `RenderPipeline`，它定义了关联的着色器，绑定来自其他目标的任何采样器或设置统一变量，剪切屏幕的一部分以进行渲染，以及设置用于定义要渲染的顶点的顶点和索引缓冲区。最后，可以使用 `draw` 方法之一将所有内容绘制到屏幕上，提供起始索引和顶点计数。

```java
// 如果缓冲区/纹理尚未创建或缓存，请在此处创建它们
// 在渲染通道打开时，不能运行来自 `CommandEncoder` 的任何方法
RenderSystem.AutoStorageIndexBuffer indices = RenderSystem.getSequentialBuffer(VertexFormat.Mode.QUADS);
GpuBuffer vertexBuffer = RenderSystem.getQuadVertexBuffer();
GpuBuffer indexBuffer = indices.getBuffer(6);

// 我们假设您已经构造了一个用于颜色数据的 `GpuTexture` texture
try (RenderPass pass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(this.texture, OptionalInt.of(0xFFFFFFFF))) {

    // 设置管道信息以及任何采样器和统一变量
    pass.setPipeline(EXAMPLE_PIPELINE);
    pass.setVertexBuffer(0, vertexBuffer);
    pass.setIndexBuffer(indexBuffer, indices.type());
    pass.bindSampler("Sampler0", RenderSystem.getShaderTexture(0));

    // 然后，将所有内容绘制到屏幕
    // 在此示例中，缓冲区只包含一个四边形
    // 对于那些不知道的人来说，顶点计数为 6，因为四边形由 2 个三角形组成，所以有 2 个顶点重叠
    pass.drawIndexed(0, 6);
}
```

然而，除非您需要如此精细的控制，否则建议在必要时使用带有 `MultiBufferSource` 的 `RenderType`，因为它会为您设置大部分内容。

### 对象引用

大多数用于确定模式和处理纹理的 GL 代码的原始引用已被对象取代。正如 TL;DR 之前提到的，这些通常存储为某种枚举或对象，然后可以解析为其 GL 对应项。一些对象直接包含其引用标识符，例如 `BlendFunction`。其他对象只是占位符，在适当的位置解析，例如 `DepthTestFunction`，其枚举值通过 `RenderPipeline#toGl` 转换。

然而，最大的变化是增加了 `GpuTexture`。它负责管理与创建、写入和释放写入到某个缓冲区的纹理相关的任何事情。在初始化时，纹理被创建和绑定，并设置任何必要的参数用于 mipmap 和纹理格式。这些 `GpuTexture` 被存储和引用在任何地方，从 `RenderTarget` 的深度和颜色目标到支持 `TextureAtlas` 的纹理。然后，一旦不再需要，纹理通过调用 `#close` 释放。请注意，尽管技术上可以再次调用 `#bind`，但纹理已被视为删除，不应再使用。

如果由于某种原因，您需要使用 `GpuTexture`，实际上使用起来非常简单。首先，您只需通过 `GpuDevice#createTexture` 构造 `GpuTexture`。然后，如果您需要更改任何寻址或纹理 mipmap 过滤器，您可以在写入之前随时应用它们。

```java
public class MyTextureManager {
    
    private final GpuTexture texture;

    public MyTextureManager() {
        this.texture = RenderSystem.getDevice().createTexture(
            // 纹理名称，用于日志记录和调试
            "Example Texture",
            // 纹理像素的格式，可以是三个值之一：
            // 值：   (纹理内部格式， 纹素数据格式，   纹素数据类型，     像素大小)
            // - RGBA8   (GL_RGBA8,                GL_RGBA,            GL_UNSIGNED_BYTE, 4)
            // - RED8    (GL_R8,                   GL_RED,             GL_UNSIGNED_BYTE, 1)
            // - DEPTH32 (GL_DEPTH_COMPONENT32,    GL_DEPTH_COMPONENT, GL_FLOAT,         4)
            TextureFormat.RGBA8,
            // 纹理宽度
            16,
            // 纹理高度
            16,
            // mipmap 级别和最大细节级别（最小为 1）
            1
        );

        // 设置 UV 分量的纹理模式
        // 值：
        // - REPEAT        (GL_REPEAT)
        // - CLAMP_TO_EDGE (GL_CLAMP_TO_EDGE)
        this.texture.setAddressMode(
            // 用于 U 分量的模式 (GL_TEXTURE_WRAP_S)
            AddressMode.CLAMP_TO_EDGE,
            // 用于 V 分量的模式 (GL_TEXTURE_WRAP_R)
            AddressMode.REPEAT
        );

        // 设置用于在屏幕上缩放纹理的过滤函数
        // 值    (默认，    用于 mipmap)：
        // - NEAREST (GL_NEAREST, GL_NEAREST_MIPMAP_LINEAR)
        // - LINEAR  (GL_LINEAR,  GL_LINEAR_MIPMAP_LINEAR)
        this.texture.setTextureFilter(
            // 用于纹理缩小函数的模式 (GL_TEXTURE_MIN_FILTER)
            FilterMode.LINEAR,
            // 用于纹理放大函数的模式 (GL_TEXTURE_MAG_FILTER)
            FilterMode.NEAREST,
            // 是否应为缩小函数使用 mipmap（当为 true 时，应具有高于 1 的 mipmap 级别）
            false
        );
    }
}
```

然后，每当您想要将某些内容上传到纹理时，您可以调用 `CommandEncoder#writeToTexture` 或 `CommandEncoder#copyTextureToTexture`。这要么接受要写入的 `NativeImage`，要么接受带有纹理数据和要使用的 `NativeImage$Format` 的 `IntBuffer`。

```java
// 像其他缓冲区/纹理修改方法一样，这必须在渲染通道之外完成
// 我们假设您有一些要加载到纹理中的 `NativeImage` image
RenderSystem.getDevice().createCommandEncoder().writeToTexture(
    // 正在写入的纹理（目标）
    this.texture,
    // 正在读取的图像（源）
    image,
    // mipmap 级别
    0,
    // 起始目标 x 偏移
    0,
    // 起始目标 y 偏移
    0,
    // 目标宽度（x 大小）
    16,
    // 目标高度（y 大小）
    16,
    // 起始源 x 偏移
    0,
    // 起始源 y 偏移
    0
)
```

最后，当您使用完纹理后，如果它没有被自动处理，不要忘记通过 `#close` 释放它。

### 渲染管线

以前，管道是使用 JSON 构造的，其中包含从顶点和片段着色器到其定义的值、采样器和统一变量的所有元数据。然而，这已被一个代码内解决方案取代，该方案将 JSON 的某些部分和原本归入 `RenderType` 的部分更加本地化。这被称为 `RenderPipeline`。

可以使用其构建器通过 `RenderPipeline#builder` 构造 `RenderPipeline`。然后可以通过调用 `build` 来构建管道。如果您希望着色器无需任何额外工作即可预编译，则可以将最终的管道传递给 `RenderPipeline#register`。但是，如果您希望更优雅地处理失败状态，也可以自己处理编译。如果您有跨多个管道使用的代码片段，则可以构建一个部分管道（通过 `$Builder#buildSnippet`），然后在 `builder` 方法中将其传递给构造管道。

> 示例中描述的以下枚举已提供其 GL 代码，因为它们已被抽象化。

```java
// 这假设 RenderPipeline#register 已通过某种形式变为公开
public static final RenderPipeline EXAMPLE_PIPELINE = RenderPipelines.register(
    RenderPipeline.builder()
    // 管道的名称（必需）
    .withLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "pipeline/example"))
    // 顶点着色器的位置，相对于 'shaders'（必需）
    // 指向 'assets/examplemod/shaders/example.vsh'
    .withVertexShader(ResourceLocation.fromNamespaceAndPath("examplemod", "example"))
    // 片段着色器的位置，相对于 'shaders'（必需）
    // 指向 'assets/examplemod/shaders/example.fsh'
    .withFragmentShader(ResourceLocation.fromNamespaceAndPath("examplemod", "example"))
    // 着色器内顶点的格式（必需）
    .withVertexFormat(
        // 顶点格式
        DefaultVertexFormat.POSITION_TEX_COLOR,
        // 格式的模式
        VertexFormat.Mode.QUADS
    )
    // 添加可以在着色器中引用的常量
    // 可以指定名称以及一个 int / float 来表示其值
    // 如果未指定值，则应使用 #ifdef / #endif 块进行门控
    .withShaderDefines("ALPHA_CUTOUT", 0.5)
    // 添加可以在着色器中引用的纹理 sampler2D
    // 通常，存储在 `RenderSystem` 中的着色器纹理通过 `Sampler0` - `Sampler11` 引用
    // - `Sampler0` 通常总是存在，但这些应该事先设置好
    // 此外，对于渲染目标，`InSampler` 通常存在，以及在后处理通道中定义的任何采样器
    .withSampler("Sampler0")
    // 添加可以在着色器中引用的统一变量
    // 这些只是定义，然后根据情况由调用者填充或默认填充
    // 默认值可以在 `CompiledShaderProgram#setupUniforms` 中找到
    .withUniform("ModelOffset", UniformType.VEC3)
    // 自定义统一变量必须手动设置，因为原版批处理系统不支持这样的操作
    .withUniform("CustomUniform", UniformType.INT)
    // 设置用于在离相机不同距离处渲染对象的深度测试函数
    // 值：
    // - NO_DEPTH_TEST      (GL_ALWAYS)
    // - EQUAL_DEPTH_TEST   (GL_EQUAL)
    // - LEQUAL_DEPTH_TEST  (GL_LEQUAL)
    // - LESS_DEPTH_TEST    (GL_LESS)
    // - GREATER_DEPTH_TEST (GL_GREATER)
    .withDepthTestFunction(DepthTestFunction.LEQUAL_DEPTH_TEST)
    // 设置多边形应如何渲染
    // 值：
    // - FILL      (GL_FILL)
    // - WIREFRAME (GL_LINE)
    .withPolygonMode(PolygonMode.FILL)
    // 当为 true 时，可以剔除正面或背面的多边形
    .withCull(false)
    // 指定将两个带有 alpha 的颜色混合在一起时要使用的函数
    // 由 `GlStateManager$SourceFactor` 和 `GlStateManager$DestFactor` 组成
    // 前两个用于 RGB，后两个用于 alpha
    // 如果未指定任何内容，则禁用混合
    .withBlend(BlendFunction.TRANSLUCENT)
    // 决定是否屏蔽写入颜色和 alpha 到绘制缓冲区
    .withColorWrite(
        // 屏蔽 RGB
        false,
        // 屏蔽 alpha
        false
    )
    // 决定是否屏蔽写入值到深度缓冲区
    .withDepthWrite(false)
    // 决定将 RGBA 颜色应用到帧缓冲区时要应用的逻辑操作
    .withColorLogic(LogicOp.NONE)
    // 设置用于计算多边形深度值的比例和单位。
    // 这取代了多边形偏移。
    .withDepthBias(0f, 0f)
    .build()
);
```

从那里，管道可以直接使用，也可以通过某些 `RenderType` 使用：

```java
// 这将假设 RenderType#create 是公开的
public static final RenderType EXAMPLE_RENDER_TYPE = RenderType.create(
    // 渲染类型的名称
    "examplemod:example",
    // 缓冲区的大小
    // 或 4MB
    4194304,
    // 是否影响应用于方块实体的破碎效果
    false,
    // 顶点在上传前是否应排序
    true,
    // 要使用的管道
    EXAMPLE_PIPIELINE,
    // 要应用的任何其他复合状态设置
    RenderType.CompositeState.builder().createCompositeState(RenderType.OutlineProperty.NONE)
);
```

然后可以通过创建 `RenderPass` 并将 `RenderPipeline` 设置为使用您的管道来绘制管道。对于 `RenderType`，可以使用 `MultiBufferSource#getBuffer` 获得关联的缓冲区。请注意，不应在 `RenderType` 中使用自定义统一变量，因为它们不容易设置。

```java
// 由于我们使用的是自定义统一变量，我们必须自己处理
// 我们假设我们有某个 `GpuTexture` texture 要写入

// 创建要使用的渲染通道
try (RenderPass pass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(
        // 要写入的 GPU 颜色纹理
        this.texture,
        // ARGB 格式的清除颜色
        OptionalInt.of(0xFFFFFFFF),
        // 深度纹理和清除深度值也可以在此处构造
    )
) {
    // 添加管道和我们的统一变量
    pass.setPipeline(EXAMPLE_PIPELINE);
    pass.setUniform("CustomUniform", 1);
    
    // 设置任何其他采样器和要使用的顶点/索引缓冲区

    // 最后，调用 draw 函数之一
    // 接受要绘制的顶点的第一个索引和索引计数
    pass.draw(...);
}
```

### 后处理效果

鉴于管道 JSON 已被剥离，这也影响了后处理效果。`program` 被直接指定 `vertex_shader` 和 `fragment_shader` 所取代。此外，统一变量必须指定其 `type`。

```json5
// 1.21.5 之前（对于 'passes' 中的某个 pass）
{
    // 与之前相同
    "inputs": [ /*...*/ ],
    "output": "swap",

    // 被 'vertex_shader', 'fragment_shader' 取代
    "program": "minecraft:post/box_blur",

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

// 1.21.5（对于 'passes' 中的某个 pass）
{
    // 与之前相同
    "inputs": [ /*...*/ ],
    "output": "swap",

    // 相对于 'shaders'
    // 指向 'assets/minecraft/shaders/post/blur.vsh'
    "vertex_shader": "minecraft:post/blur",
    // 指向 'assets/minecraft/shaders/post/box_blur.fsh'
    "fragment_shader": "minecraft:post/box_blur",


    "uniforms": [
        {
            "name": "BlurDir",
            // 指定为此统一变量使用的类型
            // `Uniform$Type` 之一：
            // - int
            // - ivec3
            // - float
            // - vec2
            // - vec3
            // - vec4
            // - matrix4x4
            "type": "vec2",
            "values": [ 1.0, 0.0 ]
        },
        {
            "name": "Radius",
            "type": "float"
            // values 不再是必需的
        }
    ]
}
```

请注意，如果您没有为统一变量定义值，则必须在处理 `PostChain` 之前在 `PostChain#process` 的 `RenderPass` 消费者中通过调用 `#setUniform` 来指定它们。

```java
// 假设我们已经得到了 `PostChain` post
post.process(Minecraft.getInstance().getMainRenderTarget(), GraphicsResourceAllocator.UNPOOLED, pass -> {
    pass.setUniform("Radius", 0.4f);
});
```

- `com.mojang.blaze3d.GpuOutOfMemoryException` - 当无法在 GPU 上分配纹理时抛出的异常。
- `com.mojang.blaze3d.buffers`
    - `BufferType` 不再存储 GL 代码，现在在 `GlConst#toGl` 中
    - `BufferUsage` 不再存储 GL 代码，现在在 `GlConst#toGl` 中
        - `isReadable`、`isWritable` - 返回缓冲区是否可读或可写。
    - `GpuBuffer` 现在是抽象的
        - 带有 `ByteBuffer` 的构造函数已移除
        - `size` - 返回缓冲区的大小。
        - `type` - 返回缓冲区的类型。
        - `resize`、`write`、`read`、`bind` 已移除
        - `usage` - 返回缓冲区的用途。
        - `close` 现在是抽象的
        - `isClosed` - 返回缓冲区是否已关闭。
        - `$ReadView` 现在是一个接口，定义了缓冲区数据以及如何关闭视图
- `com.mojang.blaze3d.font.SheetGlyphInfo#upload` 现在接受一个 `GpuTexture`
- `com.mojang.blaze3d.opengl`
    - `DirectStateAccess` - 一个创建数据并将其绑定到某个帧缓冲区的接口。
        - `$Core` - 一种修改帧缓冲区而不将其绑定到上下文的 DSA 实现。
        - `$Emulated` - 一种仍然绑定上下文的 DSA 抽象。
    - `GlBuffer` - 用于 OpenGL 的 `GpuBuffer` 实现。
    - `GlCommandEncoder` - 用于 OpenGL 的 `CommandEncoder` 实现。
    - `GlDebugLabel` - 用于处理对 GL 指定数据结构的调试引用的标签器。
    - `GlDevice` - 用于 OpenGL 的 `GpuDevice` 实现。
    - `GlRenderPass` - 用于 OpenGL 的 `RenderPass` 实现。
    - `GlRenderPipeline` - 用于 OpenGL 的 `CompiledRenderPipeline` 实现。
    - `GlTexture` - 用于 OpenGL 的 `GpuTexture` 实现。
    - `VertexArrayCache` - 用于绑定顶点数组并将其上传到 OpenGL 管道的缓存。
- `com.mojang.blaze3d.pipeline`
    - `BlendFunction` - 一个类，包含在目标中叠加像素时要应用的源和目标颜色及 alpha。这也包含所有原版混合函数。
    - `CompiledRenderPipeline` - 一个接口，包含具有渲染到屏幕所需所有信息的管道。
    - `RenderPipeline` - 一个类，包含将某个对象渲染到屏幕所需的一切。它在应用之前类似于渲染状态。
    - `RenderTarget` 现在接受一个表示目标名称的字符串
        - `colorTextureId` -> `colorTexture`，现在是一个 `GpuTexture`
            - 同样 `getColorTextureId` -> `getColorTexture`
        - `depthBufferId` -> `depthTexture`，现在是一个 `GpuTexture`
            - 同样 `getDepthTextureId` -> `getDepthTexture`
        - `filterMode` 现在是一个 `FilterMode`
            - 同样 `setFilterMode` 用于 int 参数
        - `blitAndBlendToScreen` 不再接受视口大小参数
        - `framebufferId` 已移除
        - `checkStatus` 已移除
        - `bindWrite`、`unbindWrite`、`setClearColor` 已移除
        - `blitToScreen` 不再接受任何参数
        - `blitAndBlendToScreen` -> `blitAndBlendToTexture`，不是一对一
        - `clear` 已移除
        - `unbindRead` 已移除
- `com.mojang.blaze3d.platform`
    - `DepthTestFunction` - 一个枚举，表示在将样本渲染到帧缓冲区时要应用的受支持深度测试。
    - `DisplayData` 现在是一个记录
        - `withSize` - 创建一个具有指定宽度/高度的新实例。
        - `withFullscreen` - 创建一个具有指定全屏标志的新实例。
    - `FramerateLimitTracker`
        - `getThrottleReason` - 返回游戏帧率被限制的原因。
        - `isHeavilyThrottled` - 返回当前限制是否显著影响游戏速度。
        - `$FramerateThrottleReason` - 帧率被限制的原因。
    - `GlConst` -> `com.mojang.blaze3d.opengl.GlConst`
        - `#toGl` - 将某个引用对象映射到其关联的 OpenGL 代码。
    - `GlDebug` -> `com.mojang.blaze3d.opengl.GlDebug`
        - `enableDebugCallback` 现在接受一组启用的扩展。
    - `GlStateManager` -> `com.mojang.blaze3d.opengl.GlStateManager`
        - `_blendFunc`、`_blendEquation` 已移除
        - `_glUniform2(int, IntBuffer)`、`_glUniform4(int, IntBuffer)` 已移除
        - `_glUniformMatrix2(int, boolean, FloatBuffer)`、`_glUniformMatrix3(int, boolean, FloatBuffer)` 已移除
        - `_glUniformMatrix4(int, boolean, FloatBuffer)` -> `_glUniformMatrix4(int, FloatBuffer)`，transpose 现在始终为 false
        - `_glGetAttribLocation` 已移除
        - `_glMapBuffer` 已移除
        - `_glCopyTexSubImage2D` 已移除
        - `_glBindRenderbuffer`、`_glDeleteRenderbuffers` 已移除
        - `glGenRenderbuffers`、`_glRenderbufferStorage`、`_glFramebufferRenderbuffer` 已移除
        - `_texParameter(int, int, float)` 已移除
        - `_genTextures`、`_deleteTextures` 已移除
        - `_texSubImage2D` 现在有一个接受 `IntBuffer` 而不是 `long` 作为像素数据的重载
        - `upload` 已移除
        - `_stencilFunc`、`_stencilMask`、`_stencilOp`、`_clearStencil` 已移除
        - `_getTexImage` 已移除
        - `_glDrawPixels`、`_readPixels` 已移除
        - `$CullState#mode` 已移除
        - `$DestFactor` -> `DestFactor`，代码已移除，通过 `GlConst#toGl` 调用
        - `$FramebufferState` 枚举已移除
        - `$LogicOp` -> `LogicOp`，代码已移除，通过 `GlConst#toGl` 调用
            - 除 `OR_REVERSE` 外，所有都已移除
            - `NONE` - 不执行逻辑操作。
        - `$PolygonOffsetState#line` 已移除
        - `$SourceFactor` -> `SourceFactor`，代码已移除，通过 `GlConst#toGl` 调用
        - `$StencilFunc`、`$StencilState` 类已移除
        - `$Viewport` 枚举已移除
    - `GlUtil` 类已移除
        - `getVendor`、`getRenderer`、`getOpenGlVersion`（现在为 `getVersion`）已移至 `GpuDevice` 上的实例抽象方法
        - `getCpuInfo` -> `GLX#_getCpuInfo`
    - `GLX`
        - `getOpenGLVersionString` 已移除
        - `_init` -> `_getCpuInfo`，不是一对一
        - `_renderCrosshair`、`com.mojang.blaze3d.systems.RenderSystem#renderCrosshair` -> `net.minecraft.client.gui.components.DebugScreenOverlay#render3dCrosshair`，不是一对一
    - `PolygonMode` - 一个枚举，定义多边形在缓冲区中将如何渲染。
    - `NativeImage` 构造函数现在是公开的
        - `upload` 已移除
        - `getPointer` - 返回指向图像数据的指针。
        - `setPixelABGR` 现在是公开的
        - `applyToAllPixels` 已移除
        - `downloadTexture`、`downloadDepthBuffer` 已移除
        - `flipY` 已移除
        - `setPackPixelStoreState`、`setUnpackPixelStoreState` 已移除
        - `$InternalGlFormat` 枚举已移除
        - `$Format` 不再包含 GL 代码，现在在 `GlConst#toGl` 中
    - `TextureUtil`
        - `generateTextureId`、`releaseTextureId` 已移除
        - `prepareImage` 已移除
        - `writeAsPNG` 现在接受一个 `GpuTexture` 而不是直接的三个整数
            - 没有 `IntUnaryOperator` 的重载已移除
- `com.mojang.blaze3d.resource`
    - `RenderTargetDescriptor` 现在接受一个表示要清除到的颜色的整数
    - `ResourceDescriptor`
        - `prepare` - 在分配后准备资源以供使用。
        - `canUsePhysicalResource` - 通常返回一个描述符是否已经分配了相同的信息。
- `com.mojang.blaze3d.shaders`
    - `AbstractUniform` -> `com.mojang.blaze3d.opengl.AbstractUniform`
        - `setSafe` 方法已移除
        - `setMat*` 方法已移除
        - `set(Matrix3f)` 已移除
    - `CompiledShader` -> `com.mojang.blaze3d.opengl.GlShaderModule`
        - `$Type` -> `com.mojang.blaze3d.shaders.ShaderType`
    - `Uniform` -> `com.mojang.blaze3d.opengl.Uniform`
        - 构造函数现在接受一个 `$Type` 而不是计数和一个表示类型的整数
        - `UT_*` 字段已移除
        - `setFromConfig(ShaderProgramConfig.Uniform)` 已移除
        - `getTypeFromString` 已移除
        - `getType` 现在返回一个 `$Type`
        - `set(int, float)` 已移除
        - `setSafe` 现在是私有的
        - `$Type` - 保存类型名称以及它包含多少个值。
        - `getLocation` 已移除
        - `getCount` -> `$Type#count`
        - `getIntBuffer`、`getFloatBuffer` 已移除
        - `$Type` -> `com.mojang.blaze3d.shaders.UniformType`
- `com.mojang.blaze3d.systems`
    - `CommandEncoder` - 一个接口，定义如何将各种命令编码到底层渲染系统，例如创建通道、清除和写入纹理，或从缓冲区读取。
    - `GpuDevice` - 一个接口，定义用于绘制到屏幕的设备或底层渲染系统。它负责创建缓冲区和纹理，同时编译任何管道。
    - `RenderPass` - 一个接口，定义如何使用底层渲染系统将给定的通道渲染到某个缓冲区。这允许绑定任何采样器并设置所需的统一变量。
    - `RenderSystem`
        - `isOnRenderThreadOrInit`、`assertOnRenderThreadOrInit` 已移除
        - `recordRenderCall`、`replayQueue` 已移除
        - `blendFunc`、`blendFuncSeparate`、`blendEquation` 已移除
        - `texParameter`、`deleteTexture`、`bindTextureForSetup` 已移除
        - `stencilFunc`、`stencilMask`、`stencilOp` 已移除
        - `clearDepth` 已移除
        - `glBindBuffer`、`glBindVertexArray`、`glBufferData`、`glDeleteBuffers` 已移除
        - `glUniform1i` 已移除
        - `glUniform1`、`glUniform2`、`glUniform3`、`glUniform4` 已移除
        - `glUniformMatrix2`、`glUniformMatrix3`、`glUniformMatrix4` 已移除
        - `setupOverlayColor` 现在接受一个 `GpuTexture` 而不是两个 int
        - `beginInitialization`、`finishInitialization` 已移除
        - `renderThreadTesselator` 已移除
        - `setShader`、`clearShader`、`getShader` 已移除
        - `setShaderTexture` 现在接受一个 `GpuTexture` 而不是一个绑定地址
        - `getShaderTexture` 现在返回一个 `GpuTexture`，如果不存在则返回 null
        - `pixelStore`、`readPixels` 已移除
        - `queueFencedTask`、`executePendingTasks` - 处理发送在 GPU 上异步运行的任务。
        - `SCISSOR_STATE` - 保存主要的剪裁状态。
        - `disableDepthTest`、`enableDepthTest` 已移除
        - `depthFunc`、`depthMask` 已移除
        - `enableBlend`、`disableBlend` 已移除
        - `neableCull`、`disableCull` 已移除
        - `polygonMode`、`enablePolygonOffset`、`disablePolygonOffset`、`polygonOffset` 已移除
        - `enableColorLogicOp`、`disableColorLogicOp`、`logicOp` 已移除
        - `bindTexture`、`viewport` 已移除
        - `colorMask`、`clearColor`、`clear` 已移除
        - `setupShaderLights(CompiledShaderProgram)` 已移除
        - `getShaderLights` - 返回表示块光和天空光的向量。
        - `drawElements`、`getString` 已移除
        - `initRenderer` 现在接受窗口指针、默认着色器源以及一个是否使用调试标签的布尔值
        - `setupDefaultState` 不再接受任何参数
        - `maxSupportTextureSize` 已移除
        - `glDeleteVertexArrays` 已移除
        - `defaultBlendFunc` 已移除
        - `setShaderTexture` 已移除
        - `getQuadVertexBuffer` - 返回一个绑定了一个四边形的顶点缓冲区。
        - `getDevice`、`tryGetDevice` - 返回表示要使用的底层渲染系统的 `GpuDevice`。
        - `getCapsString` 已移除
        - `activeTexture` 已移除
        - `setModelOffset`、`resetModelOffset`、`getModelOffset` - 处理在渲染模型时应用于 `ModelOffset` 统一变量的偏移量。通常用于云和世界边界。
        - `$AutoStorageIndexBuffer#bind` -> `getBuffer`，不是一对一
        - `$GpuAsyncTask` - 一个保存回调和围栏对象的记录，用于将信息同步到 GPU。
    - `ScissorState` - 一个类，保存要渲染的屏幕部分。
- `com.mojang.blaze3d.textures`
    - `AddressMode` - 设置为如何将纹理渲染到特定位置的模式。
    - `FilterMode` - 设置为当细节级别函数确定纹理应如何最大化或最小化时如何渲染纹理的模式。
    - `GpuTexture` - 根据需要绑定和写入 GPU 的纹理。
    - `TextureFormat` - 指定纹理应分配的格式。
- `com.mojang.blaze3d.vertex`
    - `PoseStack`
        - `mulPose(Quaternionf)`、`rotateAround` 现在接受 `Quaternionfc` 而不是 `Quaternionf`
        - `clear` -> `isEmpty`
        - `mulPose(Matrix4f)` -> `mulPose(Matrix4fc)`
        - `$Pose`
            - `computeNormalMatrix` 现在是私有的
            - `transformNormal` 现在接受 `Vector3fc` 作为其第一个参数
            - `translate`、`scale`、`rotate`、`rotateAround`、`setIdentity`、`mulPose` 现在除了在堆栈上之外，在姿势本身上也可用
    - `VertexBuffer` -> `com.mojang.blaze3d.buffers.GpuBuffer`，不是一对一
        - 一些逻辑也移至 `VertexFormat`
    - `VertexFormat`
        - `bindAttributes` 已移除
        - `setupBufferState`、`clearBufferState`、`getImmediateDrawVertexBuffer` -> `uploadImmediateVertexBuffer`、`uploadImmediateIndexBuffer`；不是一对一
        - `$IndexType` 不再存储 GL 代码，现在在 `GlConst#toGl` 中
        - `$Mode` 不再存储 GL 代码，现在在 `GlConst#toGl` 中
    - `VertexFormatElement`
        - `setupBufferState` 已移除
        - `$Type` 不再存储 GL 代码，现在在 `GlConst#toGl` 中
        - `$Usage` 不再存储 GL 函数调用，现在在 `VertexArrayCache#setupCombinedAttributes` 中
- `com.mojang.math`
    - `MatrixUtil`
        - `isIdentity`、`isPureTranslation`、`isOrthonormal` 现在接受一个 `Matrix4fc`
        - `checkProperty` - 检查提供的属性是否在矩阵中表示。
    - `OctahedralGroup`
        - `transformation` 现在返回一个 `Matrix3fc`
        - `fromAnges` -> `fromXYAngles`，不是一对一
    - `Quadrant` - 一个包含 90 度增量旋转的枚举。
    - `SymmetricGroup3#transformation` 现在返回一个 `Matrix3fc`
    - `Transformation` 现在接受一个 `Matrix4fc`
        - `getMatrix` 现在返回一个 `Matrix4fc`
        - `getMatrixCopy` - 返回当前矩阵的深拷贝。
- `net.minecraft.client.gui.font.FontTexture` 现在接受一个提供的标签字符串
- `net.minecraft.client.main.GameConfig` 现在接受一个布尔值，表示是否渲染调试标签
- `net.minecraft.client.renderer`
    - `CloudRenderer#render` 不再接受用于投影或姿势的 `Matrix4f`
    - `CompiledShaderProgram` -> `com.mojang.blaze3d.opengl.GlProgram`
        - `link` 现在接受一个字符串作为着色器名称
        - `setupUniforms` 现在接受 `$UniformDescription` 列表以及采样器使用的名称列表
        - `getUniformConfig` 已移除
        - `bindSampler` 现在接受一个 `GpuTexture` 而不是整数绑定标识符
        - `parseUniformNode` 已移除
    - `CoreShaders` -> `RenderPipelines`，不是一对一
    - `LightTexture#getTarget` - 返回包含基于玩家的当前等级的光照纹理的 `GpuTexture`。
    - `PostChain`
        - `load` 不再接受 `ShaderManager`，现在接受一个表示链名称的 `ResourceLocation`
        - `addToFrame`、`process` 现在接受一个 `RenderPass` 消费者，用于将任何其他设置应用于要渲染的通道
        - `setUniform` 已移除
        - `setOnRenderPass` - 在 `RenderPass` 上的后处理链中设置统一变量，以供着色器使用。
    - `PostChainConfig`
        - `$Pass` 现在接受顶点和片段着色器的 id，而不是程序 id
            - `referencedTargets` - 返回通道中引用的要应用的目标。
            - `program` 已移除
        - `$Uniform` 现在接受统一变量的类型以及一个可选的浮点数列表（如果值不需要被覆盖）
    - `PostPass` 不再接受 `CompiledShaderProgram`，现在接受 `RenderPipeline` 而不是表示通道名称的字符串
         - `addToFrame` 现在接受一个 `RenderPass` 消费者，用于将任何其他设置应用于要渲染的通道
         - `getShader` 已移除
         - `$Input#bindTo` 现在接受 `RenderPass` 而不是 `CompiledShaderProgram`
    - `RenderStateShard`
        - 使用多边形偏移的 `$LayerStateShard` 已移除
        - `getName` - 返回着色器的名称。
        - `$TransparencyStateShard` 类已移除
            - 现在通过 `BlendFunction` 处理
        - `$ShaderStateShard` 类已移除
            - 由 `VertexBuffer` 直接引用
        - `$CullStateShard` 类已移除
            - 现在作为 `RenderPipeline` 上的设置处理
        - `$DepthTestStateShard` 类已移除
            - 现在通过 `DepthTestFunction` 处理
        - `$WriteMaskStateShard` 类已移除
            - 现在作为 `RenderPipeline` 上的设置处理
        - `$ColorLogicStateShard` 类已移除
            - 现在作为 `RenderPipeline` 上的设置处理
        - `$OutputStateShard` 现在接受一个提供的 `RenderTarget` 而不是用于启动和拆除状态的 runnable
    - `RenderType` 不再接受 `VertexFormat` 或 `VertexFormat$Mode`
        - `SKY`、`END_SKY`、`sky`、`endSky`、`stars` 已移除
        - `ENTITY_OUTLINE_BLIT`、`entityOutlineBlit` 已移除
        - `PANORAMA`、`panorama` 已移除
        - `CREATE_LIGHTMAP`、`createLightmap` 已移除
        - `createClouds`、`flatClouds`、`clouds`、`cloudsDepthOnly` 已移除
        - `worldBorder` 已移除
        - `debugLine` - 返回与调试线关联的 `RenderType`。
        - `entityOutlineBlit` - 返回用于渲染实体轮廓的 `RenderType`。
        - `panorama` - 返回用于渲染全景模式的 `RenderType`。
        - `createLightmap` - 返回用于渲染光照图纹理的 `RenderType`。
        - `create` 不再接受 `VertexFormat` 或 `VertexFormat$Mode`，而是接受 `RenderPipeline`
        - `getRenderTarget`、`getRenderPipeline` - 返回用于渲染的目标和管道。
        - `format`、`mode`、`draw` 现在是抽象的
        - `$CompositeStateBuilder` 方法现在是 protected
        - `$OutlineProperty` 现在是 protected
    - `ShaderDefines$Builder#define` 现在有一个接受整数的重载
    - `ShaderManager`
        - `SHADER_INCLUDE_PATH` 现在是私有的
        - `MAX_LOG_LENGTH` 已移除
        - `preloadForStartup` 已移除，被 `GpuDevice#precompilePipeline` 取代
        - `getProgram`、`getProgramForLoading` -> `getShader`，不是一对一
        - `linkProgram` 现在接受 `RenderPipeline` 而不是 `ShaderProgram` 和 `ShaderProgramConfig`
        - `$CompilationCache#getOrCompileProgram`、`getOrCompileShader` -> `getShaderSource`，不是一对一
        - `$Configs` 不再接受程序映射
        - `$ShaderCompilationKey` 记录已移除
    - `ShaderProgram`、`ShaderProgramConfig` -> `RenderPipeline`，不是一对一
    - `SkyRenderer#renderDarkDisc` 不再接受 `PoseStack`
- `net.minecraft.client.renderer.chunk.SectionRenderDispatcher`
    - `uploadSectionLayer`、`uploadSectionIndexBuffer` -> `$RenderSection#uploadSectionLayer`、`uploadSectionIndexBuffer`
    - `$SectionBuffers` - 一个保存用于渲染部分的缓冲区的类。
- `net.minecraft.client.renderer.texture`
    - `AbstractTexture`
        - `NOT_ASSIGNED` 已移除
        - `texture`、`getTexture` - 保存要渲染的纹理的引用。
        - `getId`、`releaseId` 已移除
        - `bind` 已移除
    - `DynamicTexture` 现在接受纹理的标签
    - `SpriteContents#uploadFirstFrame`、`$AnimatedTexture#uploadFirstFrame` 现在接受一个 `GpuTexture`
    - `SpriteTicker#tickAndUpload` 现在接受 `GpuTexture`
    - `TextureAtlasSprite#uploadFirstFrame`、`$Ticker#tickAndUpload` 现在接受 `GpuTexture`

## 模型重做

模型系统已进一步分离为用于方块状态、方块和物品的模型。因此，统一的 `BakedModel` 已被完全移除，并分离到它们自己的部分中，分三步加载：从 JSON 加载、解析依赖关系，然后烘焙以供关联的方块状态模型或物品模型使用。作为参考，下面讨论的所有内容都是在 `ModelManager#reload` 中并行发生的。

首先，让我们从方块和物品之间使用的基础模型 JSON 开始。这些被加载到 `UnbakedModel`（具体来说是 `BlockModel`）中，其中包含熟悉的属性，例如 gui 光照和纹理槽位。然而，一个变化是将元素与其渲染设置分离。这些持有渲染四边形的元素存储在 `UnbakedGeometry` 中。`UnbakedGeometry` 负责将模型烘焙成 `QuadCollection`，它实际上保存了要渲染的 `BakedQuad` 列表。目前，原版只有 `SimpleUnbakedGeometry`，它保存了熟悉的 `BlockElement` 列表。这些 `UnbakedModel` 一旦加载，就会被传递给 `ModelDiscovery` 以解析方块状态和物品模型。

接下来是 `ResolvableModel`，它是方块状态和物品模型的基础。这些模型本质上作为标记，请求它们将使用的 `UnbakedModel`。然后，我们有它们的子类型 `BlockStateModel$UnbakedRoot`（用于方块状态 JSON）和 `ItemModel$Unbaked`（用于客户端物品 JSON 中引用的模型）。每个都以某种方式实现 `resolveDependencies`，以调用 `ResolvableModel$Resolver#markDependency`，传入它们想要使用的模型位置。

> 从技术上讲，`BlockStateModel` 更复杂一些，因为变体在加载期间使用 `BlockStateModel$Unbaked`，然后在初始化期间转换为 `$UnbakedRoot`。

现在我们知道了应该加载哪些模型，它们必须被放入一个可用于烘焙的状态。这是 `ModelDiscovery` 的工作，它接受一个 `ResolvableModel`，并在第一次引用时将 `UnbakedModel` 加载到 `ResolvedModel` 中。顾名思义，`ResolvedModel` 是围绕 `UnbakedModel` 的功能包装器，用于解析所有依赖链。

从那里，为 `BlockState` 构建模型组，并加载纹理，从而进入实际烘焙 `BlockStateModel` 和 `ItemModel` 的最后一步。这通过 `$UnbakedRoot`（或 `$Unbaked`）和 `ModelBakery` 上提供的 `bake` 方法处理。简而言之，`bake` 构建 `BakedQuad` 列表，其中包含方块状态或物品模型本身所需的任何其他信息。`ResolvedModel` 从烘焙器中获得，然后调用其实例方法。对于 `BlockStateModel`，这通过 `SimpleModelWrapper#bake` 解析，从中从 `Variant` 数据获得 `ModelState`。它们将烘焙的四边形存储在 `BlockModelPart` 中。对于 `ItemModel`，它直接使用 `BakedQuad` 列表以及由 `ModelRenderProperties#fromResolvedModel` 提供的信息。这确实意味着每个 `BlockStateModel` 和 `ItemModel` 如果同一个模型在多个位置被引用，则可能包含重复（但唯一）的 `BakedQuad`。

### 方块生成器：变体修改器

鉴于所有分离出方块状态 JSON 加载的变化，`BlockModelGenerators` 也有许多变化。虽然其中大部分只是重命名（例如，`BlockStateGenerator` -> `BlockModelDefinitionGenerator`），但主要变化是增加了 `VariantMutator`。`VariantMutator` 在功能上是 `Variant` 上的一元运算符，用于设置某些设置。这一增加简化了（或者说更像是编解码器构造）`PropertyDispatch` 的使用，以便更快速地根据其属性分派具有变体的方块。

```java
// 在水平朝向属性上创建一个属性分派
// 应用关联的变体，但如果需要，也可以提供一个函数式接口
public static final PropertyDispatch<VariantMutator> ROTATION_HORIZONTAL_FACING = PropertyDispatch.modify(BlockStateProperties.HORIZONTAL_FACING)
    .select(Direction.EAST, BlockModelGenerators.Y_ROT_90)
    .select(Direction.SOUTH, BlockModelGenerators.Y_ROT_180)
    .select(Direction.WEST, BlockModelGenerators.Y_ROT_270)
    .select(Direction.NORTH, BlockModelGenerators.NOP);

// 然后，在可以访问 `Consumer<BlockModelDefinitionGenerator>` blockStateOutput 的地方
this.blockStateOutput.accept(
    MultiVariantGenerator.dispatch(EXAMPLE_BLOCK).with(ROTATION_HORIZONTAL_FACING)
);
```

- `net.minecraft.client.data.models`
    - `BlockModelGenerators`
        - `nonOrientableTrapdoor` -> `NON_ORIENTABLE_TRAPDOOR`，现在是静态的
        - 常量现在可用于常见的 `VariantMutator`，例如将方块模型旋转一定角度
        - `texturedModels` -> `TEXTURED_MODELS`，现在是静态的
        - `MULTIFACE_GENERATOR` 现在是私有的
        - `plainModel` - 从模型位置创建一个变体。
        - `variant`、`variants` - 从一些 `Variant` 创建一个常规的 `MultiVariant`
        - `plainVariant` - 从其位置创建一个只有一个模型的 `MultiVariant`。
        - `condition` - 为多部分模型创建一个新的条件构建器
        - `or` - 对多个条件进行 OR 操作。
        - 大多数生成器方法现在返回 `BlockModelDefinitionGenerator`、`Variant` 或 `MultiVariant`，并接受一个 `Variant` 或 `MultiVariant` 而不是指向所需模型的 `ResourceLocation`
            - `VariantProperties` 已被 `VariantMutator` 取代
            - `Condition$TerminalCondition` 被 `Condition` 取代
        - `createHorizontalFacingDispatch`、`createHorizontalFacingDispatchAlt`、`createTorchHorizontalDispatch` 已移除
        - `createFacingDispatch` 已移除
        - `createRotatedVariant(Block, ResourceLocation)` 已移除
        - `selectMultifaceProperties` - 基于提供的 `BlockState` 和方向到属性函数，创建一个属性到 `VariantMutator` 的映射。
        - `applyRotation` 不再接受 `Variant`，并返回一个 `VariantMutator`
    - `ItemModelGenerators#generateSpawnEgg` 已移除
    - `ModelProvider#saveAll` 已移除
- `net.minecraft.client.data.models.blockstates`
    - `BlockStateGenerator` -> `BlockModelDefinitionGenerator`，不是一对一
    - `Condition` -> `net.minecraft.client.renderer.block.model.multipart.Condition`，不是一对一
        - `validate` -> `instantiate`，不是一对一
    - `ConditionBuilder` - 使用属性值构建一个条件
    - `MultiPartGenerator` 现在实现 `BlockModelDefinitionGenerator`
        - `with(List<Variant>)` -> `with(MultiVariant)`
        - `with(Variant)` 已移除
        - `with(Condition, ...)` -> `with(Condition, MultiVariant)`
            - 接受 `ConditionBuilder` 的重载
        - `$ConditionalEntry`、`$Entry` 已移除
    - `MultiVariantGenerator` 现在实现 `BlockModelDefinitionGenerator`
        - `multiVariant` -> `dispatch`
        - `multiVariant(Block, ...)` -> `dispatch(Block, MultiVariant)`
        - `$Empty` - 一个匹配每个方块状态的多变体条目。
    - `PropertyDispatch` 有一个包含分派值的泛型
        - 泛型 `V` 替换了所有 `List<Variant>` 的值
        - `property`、`properties` -> `initial` 或 `modify`
        - `$C*#generateList` 方法已移除
        - `$*Function` 已移除
    - `Selector` -> `PropertyValueList`，不是一对一
    - `Variant` -> `net.minecraft.client.renderer.block.model.Variant`，不是一对一
    - `VariantProperties` -> `net.minecraft.client.renderer.block.model.VariantMutator`，不是一对一
    - `VariantProperty` -> `net.minecraft.client.renderer.block.model.VariantMutator$VariantProperty`，不是一对一
- `net.minecraft.client.renderer.ItemInHandRenderer#renderItem` 不再接受表示物品是否在左手中的布尔值
- `net.minecraft.client.renderer.block`
    - `BlockModelShaper#stateToModelLocation`、`statePropertiesToString` 已移除
    - `BlockRenderDispatcher#renderBatched` 现在接受一个 `BlockModelPart` 列表而不是 `RandomSource`
    - `ModelBlockRenderer`
        - `tesselateBlock`、`tesselateWithAO`、`tesselateWithoutAO` 不再接受 `RandomSource`，并将 `BlockStateModel` 替换为 `BlockModelPart` 列表
        - `renderModel` 现在是静态的，不再接受 `BlockState`
        - `$AmbientOcclusionFace` -> `$AmbientOcclusionRenderStorage`
        - `$CommonRenderStorage` - 一个类，保存用于在其给定位置渲染方块的一些元数据。
        - `$SizeInfo` 现在接受直接索引，而不是从其方向和翻转布尔值计算信息
- `net.minecraft.client.renderer.block.model`
    - `BakedQuad` 现在是一个记录
    - `BlockElement` 现在是一个记录
        - `from`、`to` 现在是 `Vector3fc`
    - `BlockElementFace` 现在接受一个 `Quadrant` 作为面旋转
        - `getU`、`getV` - 返回旋转后的纹理坐标。
        - `$Deserializer#getTintIndex` 现在是私有的和静态的
    - `BlockFaceUV` -> `BlockElementFace$UVs`，不是一对一
    - `BlockModel` 现在是一个记录，接受一个 `UnbakedGeometry` 而不是直接的 `BlockElement` 列表
        - `$Deserializer#getElements` 现在返回一个 `UnbakedGeometry`
    - `BlockModelDefinition` 现在是一个记录，接受 `$SimpleModelSelectors` 和 `$MultiPartDefinition`
        - `GSON`、`fromStream`、`fromJsonElement` -> `CODEC`，不是一对一
        - `instantiate` 现在接受一个提供的字符串而不是直接的字符串
        - `$Deserializer` 已移除
        - `$MultiPartDefinition` - 一个记录，保存用于获取多部分模型的选择器列表。
        - `$SimpleModelSelectors` - 一个记录，保存变体到其未烘焙模型实例的映射。
    - `BlockModelPart` - 方块的烘焙模型表示。
    - `BlockStateModel` - 方块状态的烘焙表示。
        - `collectParts` - 获取用于渲染此状态的烘焙模型列表。
        - `$SimpleCachedUnbakedRoot` - 一个类，表示某个 `$Unbaked` 模型的委托。
        - `$Unbaked` - 一个可以创建 `$SimpleCachedUnbakedRoot` 的 `$UnbakedRoot` 的扩展
    - `FaceBakery`
        - `bakeQuad` 现在接受 `Vector3fc` 而不是 `Vector3f`
        - `recomputeUVs` 已移除
        - `extractPositions` - 提取面的位置并将它们传递给一个消费者以供使用。
    - `ItemTransform` 现在是一个记录，向量是 `Vector3fc`
    - `MultiVariant` -> `net.minecraft.client.data.models.MultiVariant`
        - `CODEC`
        - `with` - 创建一个带有指定修改器的 `MultiVariant`。
        - `$Deserializer` 类已移除
    - `SimpleModelWrapper` 现在实现 `BlockModelPart`
    - `SimpleUnbakedGeometry` - 一个保存要烘焙的 `BlockElement` 列表的未烘焙几何体。
    - `SingleVariant` - 一个 `BlockStateModel` 实现，其状态只有一个模型。
    - `UnbakedBlockStateModel` -> `BlockStateModel$UnbakedRoot`
    - `Variant` 不再实现 `ModelState`，现在接受 `$SimpleModelState` 而不是直接的旋转和 uv 锁定
        - 构造函数现在有一个只提供 `ResourceLocation` 的重载，不再接受权重，将其留给 `MultiVariant`
        - `CODEC`
        - `withXRot`、`withYRot`、`withUvLock`、`withModel`、`withState`、`with` - 将变体变异为一个应用了给定设置的新对象。
        - `$Deserializer` 类已移除
        - `$SimpleModelState` - 一个记录，保存 x/y 旋转和 uv 锁定。
    - `VariantMutator` - 一个变体上的一元运算符，将指定设置应用于变体。在状态生成期间使用。
- `net.minecraft.client.renderer.block.model.multipart`
    - `AndCondition`、`OrCondition` -> `CombinedCondition`，不是一对一
    - `KeyValueCondition` 现在是一个记录，接受一个要测试的键到术语的映射
    - `MultiPart` -> `MultiPartModel$Unbaked`
        - `$Definition`
            - `CODEC`
            - `getMultiVariants` 已移除
        - `$Deserializer` 类已移除
    - `Selector` 现在是一个记录，接受一个 `BlockStateModel$Unbaked` 而不是 `MultiVariant`
        - `$Deserializer` 类已移除
- `net.minecraft.client.renderer.entity.ItemRenderer`
    - `renderItem` 现在接受一个 `List<BakedQuad>` 而不是 `BakedModel`
    - `renderStatic` 不再接受一个表示物品握在哪只手中的布尔值
- `net.minecraft.client.renderer.item`
    - `BlockModelWrapper` 现在有一个公共构造函数，接受染色源列表、四边形列表和 `ModelRenderProperties`
        - 四边形列表和 `ModelRenderProperties` 取代了直接的 `BakedModel`，或者现在的 `BlockStateModel`
        - `computeExtents` - 将烘焙四边形的顶点提取到一个数组中。
    - `ItemModel$BakingContext#bake` 已移除
    - `ItemModelResolver#updateForLiving`、`updateForTopItem` 不再接受表示物品是否在左手中的布尔值
    - `ItemStackReenderState`
        - `isGui3d` 已移除
        - `transform` 已移除
        - `visitExtents` - 访问模型要渲染的所有顶点，并将它们传递给提供的消费者。
        - `$LayerRenderState`
            - `NO_EXTENTS_SUPPLIER` - 一个空的顶点列表。
            - `setupBlockModel` 已被拆分为 `prepareQuadList`、`setRenderType`、`setUsesBlockLight`、`setExtents`、`setParticleIcon`、`setTransform`
            - `setupSpecialModel` 不再接受基础 `BakedModel`
    - `MissingItemModel` 现在接受一个 `BakedQuad` 列表和 `ModelRenderProperties`，而不是直接的 `BakedModel`
    - `ModelRenderProperties` - 用于渲染模型的属性，通常从 `ResolvedModel` 检索。
    - `SpecialModelRenderer` 现在接受 `ModelRenderProperties` 而不是基础 `BakedModel`
- `net.minecraft.client.resources.model`
    - `BakedModel` -> `net.minecraft.client.resources.model.QuadCollection`，不是一对一
    - `BlockModelRotation`
        - `by` 现在接受 `Quadrant` 而不是整数
        - `withUvLock` - 返回带有旋转和声明锁定 UV 用于旋转的模型状态。
    - `BlockStateDefinitions` - 一个用于创建方块名称到其状态定义映射的管理器。
    - `BlockStateModelLoader`
        - `ModelResourceLocation` 字段已移除
        - `loadBlockState` 不再接受缺失模型
        - `$LoadedModel` 类已移除
        - `$LoadedModels` 现在接受一个 `BlockStateModel$UnbakedRoot` 而不是 `$Unbaked`
            - `forResolving`、`plainModels` 已移除
    - `DelegateBakedModel` -> `net.minecraft.client.renderer.block.model.SimpleModelWrapper`，不是一对一
    - `MissingBlockModel#VARIANT` 已移除
    - `ModelBaker`
        - `bake` -> `getModel`，不是一对一
            - 烘焙器只是检索 `ResolvedModel`
        - `rootName` 已移除
        - `compute` - 计算包含 `ModelBaker` 的提供的键。通常用于烘焙 `BlockStateModel`
        - `$SharedOperationKey` - 一个接口，通常计算未烘焙模型的某个烘焙过程。
    - `ModelBakery` 现在接受一个 `Map<BlockState, BlockStateModel$UnbakedRoot>` 用于未烘焙的方块状态模型，一个 `Map<ResourceLocation, ResolvedModel>` 用于加载的模型，以及一个 `ResolvedModel` 用于缺失模型
        - `bakeModels` 现在接受一个 `SpriteGetter` 和一个 `Executor`，同时返回一个 `CompletableFuture` 用于并行加载和烘焙
        - `$BakingResult` 现在接受一个 `$MissingModels` 用于缺失的方块状态和物品模型，以及一个 `Map<BlockState, BlockStateModel>` 用于烘焙的方块状态模型；缺失的物品模型存储在 `$MissingModels` 中
        - `$MissingModels` - 保存方块状态和物品的缺失模型。
        - `$TextureGetter` 接口已移除
    - `ModelDebugName` 不再继承 `Supplier<String>`，而是使用 `debugName`
    - `ModelDiscovery`
        - `registerSpecialModels` 已移除
        - `discoverDependencies` 现在是私有的
        - `getReferencedModels`、`getUnreferencedModels` 已移除
        - `addSpecialModel` - 将一个根模型添加到任意加载的模型列表中。
        - `missingModel` - 返回缺失模型
        - `resolve` - 解析所有模型依赖关系，返回模型名称到其模型的映射。
    - `ModelGroupCollector$GroupKey#create` 现在接受一个 `BlockStateModel$UnbakedRoot` 而不是 `$Unbaked`
    - `ModelManager`
        - `getModel` 已移除
        - `getMissingModel` -> `getMissingBlockStateModel`
        - `$ResolvedModels` - 一个包含已解析依赖关系的模型的映射。
    - `ModelResourceLocation` 记录已移除
    - `ModelState`
        - `getRotation` -> `transformation`
        - `isUvLocked` 已移除
        - `faceTransfomration`、`inverseFaceTransformation` - 处理返回用于烘焙面顶点的变换后的 `Matrix4fc`。
    - `MultiPartBakedModel` -> `net.minecraft.client.renderer.block.model.multipart.MultiPartModel`
        - 现在实现 `BlockStateModel` 而不是继承 `DelegateBakedModel`
        - `$SharedBlockState` - 一个持有者，包含映射到其 `$Selector` 的 `BlockStateModel`。
    - `QuadCollection` - 一个包含要基于关联方向和剔除渲染的四边形列表的数据对象。
    - `ResolvableModel$Resolver#resolve` -> `markDependency`，不是一对一
        - 不再直接解析，而是标记依赖关系以供后续后处理步骤使用
    - `ResolvedModel` - 一个 `UnbakedModel`，其模型和纹理依赖关系已被完全解析。
    - `SimpleBakedModel` -> `net.minecraft.client.renderer.block.model.SimpleModelWrapper` 或 `net.minecraft.client.renderer.block.model.SimpleUnbakedGeometry`，不是一对一
    - `SpriteGetter`
        - `get`、`reportMissingReference` 现在接受 `ModelDebugName`
        - `resolveSlot` - 将 `TextureSlot` 中的键解析为其 `TextureAtlasSprite`。
    - `UnbakedGeometry` - 一个接口，构造在烘焙时要渲染的四边形集合。
    - `UnbakedModel` 不再实现 `ResolvableModel`
        - `DEFAULT_AMBIENT_OCCLUSION`、`DEFAULT_GUI_LIGHT` 已移除
        - `PARTICLE_TEXTURE_REFERENCE` - 保存表示粒子纹理的键。
        - `bake` 已移除
        - `getAmbientOcclusion` -> `ambientOcclusion`
        - `getGuiLight` -> `guiLight`
        - `getTransforms` - `transforms`
        - `getTextureSlots` - `textureSlots`
        - `geometry` - 保存表示模型元素的未烘焙几何体。
        - `getParent` -> `parent`，不是一对一
        - `bakeWithTopModelValues` 已移除
        - `getTopTextureSlots`、`getTopAmbientOcclusion`、`getTopGuiLight`、`getTopTransform`、`getTopTransforms` 已移除
    - `WeightedBakedModel` -> `WeightedVariants`
        - 现在实现 `BlockStateModel` 而不是继承 `DelegateBakedModel`
- `net.minecraft.world.item.ItemDisplayContext#leftHand` - 返回显示上下文是否正在使用实体的左手渲染。

## 小幅迁移

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

### 实体引用

通常，存储另一个实体的 UUID 是为了稍后获取该实体以执行某些逻辑。然而，如果实体在某个时间点被移除，存储原始实体可能会导致问题。因此，添加了 `EntityReference` 来处理从 UUID 解析实体，同时确保在查询时它仍然存在。

`EntityReference` 只是一个包装的 `Either`，要么持有实体实例，要么持有 UUID。当通过 `getEntity` 解析时，它将尝试验证存储的实体（如果存在）是否未被移除。如果被移除，它将获取 UUID 以再次查找实体本身。如果该实体确实存在，则返回它，否则返回 null。

实体中对 UUID 的大多数引用已被替换为 `EntityReference` 以促进此更改。

- `net.minecraft.network.syncher.EntityDataSerializers#OPTIONAL_UUID` -> `OPTIONAL_LIVING_ENTITY_REFERENCE`，不是一对一，因为它可以持有实体引用
- `net.minecraft.server.level.ServerLevel#getEntity(UUID)` -> `Level#getEntity(UUID)`
- `net.minecraft.world.entity`
    - `EntityReference` - 一个对实体的引用，要么通过其在世界中的实体实例，要么通过 UUID。
    - `LivingEntity#lastHurtByPlayer`、`lastHurtByMob` 现在是 `EntityReference`
    - `OwnableEntity`
        - `getOwnerUUID` -> `getOwnerReference`，不是一对一
        - `level` 现在返回一个 `Level` 而不是 `EntityGetter`
    - `TamableAnimal#setOwnerUUID` -> `setOwner` 或 `setOwnerReference`；不是一对一
- `net.minecraft.world.entity.animal.horse.AbstractHorse#setOwnerUUID` -> `setOwner`，不是一对一
- `net.minecraft.world.level.Level` 现在实现 `UUIDLookup<Entity>`
- `net.minecraft.world.level.entity`
    - `EntityAccess` 现在实现 `UniquelyIdentifyable`
    - `UniquelyIdentifyable` - 一个声称对象具有 UUID 并跟踪对象是否被移除的接口。
    - `UUIDLookup` - 一个通过 UUID 查找类型的接口。

### 解作用域玩家参数

许多接受 `Player` 的方法已被解作用域，根据用例接受 `LivingEntity` 或 `Entity`。以下方法是此情况的非详尽列表。

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

### 组件交互事件

`MutableComponent` 上的点击和悬停事件已被重做为类似 `MapCodec` 注册表的系统。它们现在都是接口，将其编解码器注册到一个 `$Action` 枚举。然后，该实现创建一个引用 `$Action` 类型的编解码器，并存储逻辑应用所需的任何必要信息。然而，没有与组件交互关联的直接“动作”逻辑。相反，它们被硬编码到它们的使用位置。对于点击事件，是在 `Screen#handleComponentClicked` 中。对于悬停事件，是在 `GuiGraphics#renderComponentHoverEffect` 中。因此，任何添加的额外事件都需要注入到枚举以及这两个位置之一或两者中。

- `net.minecraft.network.chat`
    - `ClickEvent` 现在是一个接口
        - `getAction` -> `action`
        - `getValue` 现在根据需要在其子类上，用于其各自的类型
    - `HoverEvent` 现在是一个接口
        - `getAction` -> `action`
        - `$EntityTooltipInfo`
            - `CODEC` 现在是一个 `MapCodec`
            - `legacyCreate` 已移除
        - `$ItemStackInfo` 已移除，被 `$ShowItem` 取代
        - `$LegacyConverter` 接口已移除

### 纹理图集重做

纹理图集逻辑已最终确定为一个注册表编解码器系统；然而，图集数据的查询方式已更改。首先，所有图集标识符存储在 `AtlasIds` 中，而相应的纹理位置存储在 `Sheets` 中。要从图集中获取材质，使用 `MaterialMapper` 作为纹理位置和要附加到材质的关联前缀的包装器。然后可以通过 `apply` 传入您想要使用的材质的 id 来获得 `Material`。

例如：

```java
// 在 sheets 中找到
public static final MaterialMapper ITEMS_MAPPER = new MaterialMapper(TextureAtlas.LOCATION_BLOCKS, "item");
public static final MaterialMapper BLOCKS_MAPPER = new MaterialMapper(TextureAtlas.LOCATION_BLOCKS, "block");

// 查找位于 `assets/examplemod/textures/item/example_item.png` 的纹理的材质
public static final Material EXAMPLE_ITEM = ITEMS_MAPPER.apply(ResourceLocation.fromNamespaceAndPath("examplemod", "example_item"));

// 查找位于 `assets/examplemod/textures/block/example/block.png` 的纹理的材质
public static final Material EXAMPLE_BLOCK = ITEMS_MAPPER.apply(ResourceLocation.fromNamespaceAndPath("examplemod", "example/block"));
```

- `net.minecraft.client.data.AtlasProvider` - 用于生成纹理图集提供者的数据提供者。
- `net.minecraft.client.data.models.ItemModelGenerators`
    - `SLOT_*` -> `TRIM_PREFIX_*`，现在是公开的，并且是 `ResourceLocation`
    - `TRIM_MATERIAL_MODELS` 现在是公开的
    - `generateTrimmableItem` 现在接受 `ResourceLocation` 而不是 `String`
    - `$TrimMaterialData` 现在是公开的，接受 `MaterialAssetGroup` 而不是名称和覆盖材质
- `net.minecraft.client.renderer`
    - `MaterialMapper` - 一个存储图集纹理位置和应用于纹理中 id 的前缀的对象。
    - `Sheets`
        - `*_MAPPER` - 每个纹理图集纹理的 `MaterialMapper`。
        - `createBedMaterial(ResourceLocation)` 已移除
        - `createShulkerMaterial(ResourceLocation)` 已移除
        - `createSignMaterial(ResourceLocation)` 已移除
        - `chestMaterial(String)`、`chestMaterial(ResourceLocation)` 已移除
        - `createDecoratedPotMaterial(ResourceLocation)` 已移除
- `net.minecraft.client.renderer.blockentity.ConduitRenderer#MAPPER` - 一个从方块图集获取潮涌核心纹理的映射器。
- `net.minecraft.client.renderer.texture.atlas`
    - `SpriteSource#type` -> `codec`，不是一对一
    - `SpriteSources` 现在包含类似于客户端注册表的逻辑，通过其 id 映射器
    - `SpriteSourceType` 记录已移除
- `net.minecraft.client.renderer.texture.atlas.sources`
    - `DirectoryLister` 现在是一个记录
    - `PalettedPermutations` 现在是一个记录
    - `SingleFile` 现在是一个记录
    - `SourceFilter` 现在是一个记录
    - `Unstitcher` 现在是一个记录
        - `$Region` 现在是公开的
- `net.minecraft.client.resources.model.AtlasIds` - 一个保存所有原版纹理图集的 `ResourceLocation` 的类。

### 注册表上下文交换器

客户端物品现在存储一个 `RegistryContextSwapper`，用于正确检查访问注册表对象的客户端物品信息。在等级加载之前，它会获得一个占位符以避免崩溃，并在渲染期间用正确的值填充。

- `net.minecraft.client.multiplayer`
    - `CacheSlot` - 一个包含从某个上下文计算出的值的对象。更新时，先前的值被覆盖，上下文注册该槽位以进行清理。
    - `ClientLevel` 现在实现 `CacheSlot$Cleaner`
- `net.minecraft.client.renderer.item`
    - `ClientItem` 现在可以接受一个可为 null 的 `RegistryContextSwapper`
        - `withRegistrySwapper` - 在 `ClientItem` 中设置 `RegistryContextSwapper`
    - `ItemModel$BakingContext` 现在接受一个 `RegistryContextSwapper`
- `net.minecraft.util`
    - `PlaceholderLookupProvider` - 一个包含引用对象的占位符的提供者。在客户端物品中使用，因为它们将在 `RegistyAccess` 填充之前加载。
    - `RegistryContextSwapper` - 一个用于将某个对象换成另一个不同对象的接口。由客户端物品用于将占位符换成加载的 `RegistryAccess`。

### 重载实例创建

重载实例已被稍微重新排列。`SimpleReloadInstance` 基础现在只接受 `List<PreparableReloadListener>`，其他字段被传入 `of` 函数，以便可以立即调用 `#startTasks`。

- `net.minecraft.server.packs.resources`
    - `ProfiledReloadInstance` 构造函数现在是私有的，通过 `of` 访问
    - `SimpleReloadInstance` 只接受 `List<PreparableReloadListener>`
        - `of` 现在返回一个 `ReloadInstance`，不是一对一
        - `allPreparations` 现在是包私有的
        - `allDone` 现在是私有的
        - `startTasks` - 开始重载监听器。
        - `prepareTasks` - 运行执行器并设置读取和加载所有所需数据所需的 future。
        - `StateFactory$SIMPLE` - 一个调用 `PreparableReloadListener#reload` 的工厂

### 方块效果应用器

当实体在方块内部时应用于实体的效果现在通过 `InsideBlockEffectApplier` 和 `InsideBlockEffectType` 处理。`InsideBlockEffectType` 是一个枚举，包含一个消费者，用于在调用时应用到实体上。另一方面，`InsideBlockEffectApplier` 存储在实体上，作为一种基于枚举序数以有序方式应用效果的方法。

要调用其中一种效果类型，您必须覆盖 `BlockBehaviour#entityInside` 或 `Fluid#entityInside` 并调用 `InsideBlockEffectApplier#apply`。如果某些内容应在效果类型之前应用，例如在细雪中冻结之前灭火，则应在 `apply` 之前调用 `InsideBlockEffectApplier#runBefore`。类似地，如果某些内容应在之后运行，例如在被放入熔岩后伤害敌人，则应调用 `runAfter`。

```java
// 在某个方块或流体子类中
@Override
protected void entityInside(Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier applier) {
    applier.runBefore(InsideBlockEffectType.EXTINGUISH, entity -> {
        // 在此处修改实体。
    });

    // 执行存储在类型上的基本应用逻辑
    applier.apply(InsideBlockEffectType.FIRE_IGNITE);

    applier.runAfter(InsideBlockEffectType.FIRE_IGNITE, entity -> {
        // 执行由于效果应用而产生的任何最终检查
        entity.hurt(...);
    });
}
```

- `net.minecraft.world.entity`
    - `InsideBlockEffectApplier` - 一个接口，定义实体在给定方块内时应如何交互。
    - `InsideBlockEffectType` - 一个枚举，定义当在引用该类型的特定方块内部时要执行的行为。
- `net.minecraft.world.level.block.state.BlockBehaviour#entityInside`、`$BlockStateBase#entityInside` 现在接受一个 `InsideBlockEffectApplier`
- `net.minecraft.world.level.material.Fluid#entityInside`、`FluidState#entityInside` - 每当实体被认为在流体的边界框内时调用的方法。

### 定时器回调，加入编解码器俱乐部！

用于在服务器计划中执行事件的 `TimerCallback`，通常是数据包中的 mcfunctions，现在已被重做为编解码器形式。这意味着可以通过将 `MapCodec` 传递给 `TimerCallbacks#register`（通过 `TimerCallbacks#SERVER_CALLBACKS`）而不是序列化器，将回调注册到可用回调列表中。

- `net.minecraft.world.level.timers`
    - `FunctionCallback` 现在是一个记录
    - `FunctionTagCallback` 现在是一个记录
    - `TimerCallback`
        - `codec` - 返回用于序列化的编解码器。
        - `$Serializer` 类已移除
    - `TimerCallbacks`
        - `serialize`、`deserialize` -> `codec`，不是一对一

### JOML 后端接口

Mojang 选择通过传递其逻辑对象的实现接口（通常附加一个 `c`）来减少对 JOML 对象的限制。例如，`Vector3f` 变成 `Vector3fc`，`Matrix4f` 变成 `Matrix4fc`。这不会改变任何逻辑本身，因为 `c` 接口由类组件实现。

### 标签变更

- `minecraft:worldgen/biome`
    - `spawns_cold_variant_farm_animals`
    - `spawns_warm_variant_farm_animals`
- `minecraft:block`
    - `sword_instantly_mines`
    - `replaceable_by_mushrooms`
    - `plays_ambient_desert_block_sounds`
    - `edible_for_sheep`
    - `dead_bush_may_place_on` -> `dry_vegetation_may_place_on`
    - `camels_spawnable_on`
- `minecraft:cat_variant` 已移除
- `minecraft:entity_type`
    - `can_equip_saddle`
    - `can_wear_horse_armor`
- `minecraft:item`
    - `book_cloning_target`
    - `eggs`
    - `flowers`

### 状态效果字段重命名

一些状态效果已重命名为其游戏内名称，而不是某些内部描述符。

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

### 非常技术性的变更

这是一个技术变更列表，根据您的具体设置可能导致高度特定的错误。

- `minecraft:patch_sugar_cane` 功能和 `minecraft:patch_pumpkin` 功能的顺序已交换（先南瓜，后甘蔗），这意味着生成这两个功能的模组生物群系需要将其 JSON 更新为新顺序。

- 几个原版橡树和树选择器功能现在末尾附加了 `_leaf_litter`。
    - 例如：`trees_birch_and_oak` -> `trees_birch_and_oak_leaf_litter`

### 新增列表

- `net.minecraft`
    - `ChatFormatting#COLOR_CODEC`
    - `CrashReportCategory#populateBlockLocationDetails` - 将方块位置详细信息添加到崩溃报告。
- `net.minecraft.advancements.critereon.MinMaxBounds#createStreamCodec` - 为 `MinMaxBounds` 实现构造一个流编解码器。
- `net.minecraft.client.Options#startedCleanly` - 设置游戏上次启动时是否干净启动。
- `net.minecraft.client.data.models`
    - `BlockModelGenerators#createSegmentedBlock` - 生成一个具有水平旋转的多部分方块状态定义，根据某个整数属性显示最多四个模型。
    - `ItemModelGenerators#prefixForSlotTrim` - 为某个槽位中的纹饰生成一个原版 `ResourceLocation`。
- `net.minecraft.client.MouseHandler`
    - `fillMousePositionDetails` - 将有关当前鼠标位置和屏幕大小的详细信息添加到崩溃报告。
    - `getScaledXPos` - 获取由 GUI 缩放选项缩放的当前 x 位置。
    - `getScaledYPos` - 获取由 GUI 缩放选项缩放的当前 y 位置。
    - `drawDebugMouseInfo` - 将有关鼠标缩放位置的信息绘制到屏幕。
- `net.minecraft.client.gui.components.toasts.Toast#getSoundEvent` - 返回显示吐司时要播放的声音。
- `net.minecraft.client.gui.screens.options.VideoSettingsScreen#updateFullscreenButton` - 将全屏选项设置为指定的布尔值。
- `net.minecraft.client.model.geom.builders`
    - `MeshDefinition#apply` - 在返回新实例之前将给定的变换器应用于网格。
    - `MeshTransformer#IDENTITY`- 执行恒等变换。
- `net.minecraft.client.multiplayer.ClientPacketListener#decoratedHashOpsGenenerator` - 返回用于创建数据组件及其值的哈希值的生成器。
- `net.minecraft.client.particle`
    - `FallingLeavesParticle$TintedLeavesProvider` - 一个 `FallingLeavesParticle` 的提供者，使用粒子生成位置上方的方块指定的颜色。
    - `FireflyParticle` - 一个在给定的非空气方块位置周围生成萤火虫的粒子。
- `net.minecraft.client.renderer`
    - `BiomeColors#getAverageDryFoliageColor` - 返回干燥生物群系的平均树叶颜色。
    - `LevelRenderer$BrightnessGetter` - 一个在给定方块位置获取打包亮度的接口。
    - `WorldBorderRenderer#invalidate` - 使世界边界的当前渲染无效，以便重新渲染。
- `net.minecraft.client.renderer.entity`
    - `EntityRenderDispatcher#getRenderer` - 从渲染状态上存储的数据中获取要使用的渲染器。
    - `EntityRenderer#extractAdditionalHitboxes` - 当启用“显示碰撞箱”调试状态时，获取要渲染的任何其他碰撞箱。
- `net.minecraft.client.renderer.entity.state`
    - `EntityRenderState`
        - `entityType` - 实体的类型。
        - `hitboxesRenderState` - 相对于实体位置的实体的碰撞箱信息。
        - `serverHitboxesRenderState` - 从服务器同步的实体的碰撞箱信息。
        - `fillCrashReportCategory` - 设置与渲染状态相关的任何崩溃的详细信息。
    - `HitboxesRenderState` - 相对于实体位置的实体碰撞箱的渲染状态。
    - `HitboxRenderState` - 要渲染的单个碰撞箱的渲染状态及其颜色，例如实体的眼睛高度。
    - `ServerHitboxesRenderState` - 包含来自相关服务器实体的最后同步信息的渲染状态。
    - `PigRenderState#variant` - 猪的变体。
- `net.minecraft.client.renderer.item.SelectItemModel$ModelSelector` - 一个函数式接口，根据开关情况和级别选择物品模型。
- `net.minecraft.client.renderer.item.properties.conditional.ComponentMatches` - 一个条件属性，检查给定的谓词是否匹配组件数据。
- `net.minecraft.client.renderer.item.properties.select`
    - `ComponentContents` - 一个开关情况属性，作用于数据组件内的内容。
    - `SelectItemModelProperty#valueCodec` - 返回属性类型的 `Codec`。
- `net.minecraft.client.resources.DryFoliageColorReloadListener` - 一个加载干燥树叶颜色图的重新加载监听器。
- `net.minecraft.commands.arguments.ComponentArgument#getResolvedComponent` - 构造一个包含其内容已解析信息的组件。
- `net.minecraft.core`
    - `Direction#getUnitVec3f` - 返回方向的浮点单位向量。
    - `HolderGetter$Provider#getOrThrow` - 从资源键获取一个持有者引用。
    - `SectionPos#sectionToChunk` - 将压缩的部分位置转换为压缩的区块位置。
    - `Vec3i#STREAM_CODEC`
- `net.minecraft.network`
    - `HashedPatchMap` - 一个记录，包含组件到其哈希类型/值的映射，以及一组已移除的组件。
    - `HashedStack` - 一个 `ItemStack` 表示，对存储的组件进行哈希处理。
    - `ProtocolInfo$DetailsProvider` - 为给定的协议提供详细信息。
    - `SkipPacketDecoderException` - 当解码期间发生错误时抛出的异常，其数据被忽略。
    - `SkipPacketEncoderException` - 当编码期间发生错误时抛出的异常，其数据被忽略。
- `net.minecraft.network.chat`
    - `LastSeenMessages`
        - `computeChecksum` - 计算表示所有消息签名的合并校验和的字节。
        - `$Update#verifyChecksum` - 验证更新校验和是否与最后看到的消息中的校验和匹配。
    - `LastSeenMessagesValidator$ValidationException` - 如果无法验证消息则抛出的异常。
    - `MessageSignature`
        - `describe` - 返回消息签名的字符串化版本。
        - `checksum` - 将签名中的字节哈希为单个整数。
    - `PlayerChatMessage#describeSigned` - 返回聊天消息的字符串化版本。
- `net.minecraft.network.codec`
    - `ByteBufCodecs`
        - `LONG_ARRAY`
        - `lengthPrefixed` - 返回一个将缓冲区大小限制为给定大小的操作。
    - `IdDispatchCodec$DontDecorateException` - 一个接口，告诉异常处理程序重新抛出原始异常，而不是将其包装在 `EncoderException` 中。
- `net.minecraft.network.protocol`
    - `CodecModifier` - 一个使用给定对象修改某个编解码器的函数。
    - `ProtocolInfoBuilder#context*Protocol` - 使用给定的上下文构建一个 `UnboundProtocol`，用于修改要发送的编解码器。
- `net.minecraft.network.protocol.game.GameProtocols`
    - `HAS_INFINITE_MATERIALS` - 一个修饰符，检查 `ServerboundSetCreativeModeSlotPacket` 中玩家是否具有必要的设置。如果没有，则丢弃数据包。
    - `$Context` - 返回数据包用于修改传入编解码器的上下文。
- `net.minecraft.resources.DelegatingOps`
    - `$DelegateListBuilder` - 一个列表构建器，如果需要可以被子类化。
    - `$DelegateRecordBuilder` - 一个记录构建器，如果需要可以被子类化。
- `net.minecraft.server.bossevents.CustomBossEvent$Packed` - 一个记录，支持用于序列化的事件信息。
- `net.minecraft.server.commands.InCommandFunction` - 一个接受某些输入并返回结果的命令函数。
- `net.minecraft.server.level`
    - `DistanceManager#forEachBlockTickingChucnks` - 为每个启用了方块Tick的区块应用提供的消费者。
    - `ServerLevel`
        - `areEntitiesActuallyLoadedAndTicking` - 返回实体管理器是否实际上正在Tick并加载给定区块中的实体。
        - `tickThunder` - 在给定等级内Tick雷声逻辑。
        - `anyPlayerCloseEnoughForSpawning` - 如果玩家足够接近以在给定位置生成实体，则返回。
    - `ServerPlayer$RespawnConfig` - 一个包含玩家重生信息的记录。
- `net.minecraft.util`
    - `AbstractListBuilder` - 一个 ops 列表构建器，将实现简化为三个方法：初始化、追加和构建最终列表。
    - `Brightness`
        - `block` - 从打包值中返回块光。
        - `sky` - 从打包值中返回天空光。
    - `HashOps` - 一个为数据生成哈希码的动态 ops。
    - `ExtraCodecs`
        - `UNTRUSTED_URI` - 一个不受游戏信任的 URI 的编解码器。
        - `CHAT_STRING` - 聊天消息中字符串的编解码器。
        - `legacyEnum` - 一个将枚举映射到其在 `Enum#toString` 中的输出的编解码器。
    - `FileSystemUtil` - 一个用于与文件系统交互的工具。
    - `GsonHelper#encodesLongerThan` - 返回提供的元素是否可以用指定数量的字符写入。
    - `Unit#STREAM_CODEC` - 一个用于单位实例的流编解码器。
    - `Util`
        - `mapValues` - 使用给定的函数更新映射的值。
        - `mapValuesLazy` - 使用给定的函数更新映射的值，但每个值在首次访问时解析。
        - `growByHalf` - 返回一个整数乘以 1.5，向下取整，将值钳制到某个最小值和最大整数大小。
- `net.minecraft.util.random.Weighted#map`、`WeightedList#map` - 将存储的对象转换为新类型。
- `net.minecraft.util.thread.ParallelMapTransform` - 一个辅助工具，用于并行处理和批处理任务。
- `net.minecraft.world.effect.MobEffectInstance#withScaledDuration` - 构造一个新的实例，其持续时间按某个浮点值缩放。
- `net.minecraft.world.entity`
    - `AreaEffectCloud#setPotionDurationScale` - 设置药水应应用的持续时间比例。
    - `DropChances` - 一个槽位到概率的映射，表示实体掉落该装备的可能性。
    - `Entity`
        - `isInterpolating` - 返回实体是否在两个步骤之间插值。
        - `sendBubbleColumnParticles` - 从服务器生成气泡柱粒子。
        - `canSimulateMovement` - 实体的移动是否可以模拟，通常来自玩家。
        - `propagateFallToPassengers` - 将载具的坠落伤害传播给其乘客。
        - `lavaIgnite` - 如果实体不免疫，则点燃实体 15 秒。
        - `clearFreeze` - 将实体被冻结的刻数设置为 0。
        - `removeLatestMovementRecordingBatch` - 从本Tick执行的所有移动中删除最后一个元素。
    - `InterpolationHandler` - 一个旨在根据需要轻松处理给定实体的位置和旋转插值的类。
    - `LivingEntity`
        - `getLuck` - 返回实体在随机事件中的运气。
        - `getLastHurtByPlayer`、`setLastHurtByPlayer` - 处理最后伤害此实体的玩家。
        - `getEffectBlendFactor` - 获取已应用状态效果的混合因子。
        - `applyInput` - 应用实体的输入作为其 AI，通常用于本地玩家。
        - `INPUT_FRICTION` - 应用于实体移动的标量。
- `net.minecraft.world.entity.animal.camel.Camel#checkCamelSpawnRules` - 检查骆驼是否可以在特定位置生成。
- `net.minecraft.world.entity.animal.sheep.SheepColorSpawnRules` - 一个包含绵羊在给定气候下生成时羊毛的颜色生成配置的类。
- `net.minecraft.world.entity.npc.Villager#createDefaultVillagerData` - 返回在未设置数据时要使用的村民的默认类型和职业。
- `net.minecraft.world.entity.player.Player`
    - `preventsBlockDrops` - 玩家是否不能掉落任何被破坏的方块。
    - `gameMode` - 返回玩家的当前游戏模式。
    - `debugInfo` - 将关于玩家的常见信息作为单个字符串返回。
- `net.minecraft.world.inventory`
    - `ContainerSynchronizer#createSlot` - 创建一个表示对侧槽位的 `RemoteSlot`。
    - `RemoteSlot` - 一个表示对侧数据的槽位，当数据不一致时进行同步。
- `net.minecraft.world.item`
    - `EitherHolder#key` - 返回持有的注册表对象的资源键。
    - `Item#STREAM_CODEC`
    - `ItemStack`
        - `OPTIONAL_UNTRUSTED_STREAM_CODEC`
        - `MAP_CODEC`
        - `canDestroyBlock` - 返回此物品是否可以破坏提供的方块状态。
- `net.minecraft.world.item.alchemy.PotionContents#getPotionDescription` - 返回带有某些放大器的状态效果的描述。
- `net.minecraft.world.item.crafting`
    - `Recipe#KEY_CODEC`
    - `TransmuteResult` - 一个配方结果对象，表示一个物品、数量和应用到的组件。
- `net.minecraft.world.item.equipment.trim.ArmorTrim#layerAssetId` - 返回纹饰资源的位置。
- `net.minecraft.world.level`
    - `BlockGetter$BlockStepVisitor` - 一个消费者，接受当前位置以及期望行进路径内的碰撞次数。
    - `ColorMapColorUtil` - 一个辅助工具，根据生物群系的温度、降水、颜色映射和默认颜色从地图中获取颜色。
    - `DryFoliageColor` - 用于具有干燥树叶的生物群系的颜色解析器。
    - `GameRules`
        - `getType` - 从其键获取游戏规则类型。
        - `keyCodec` - 为游戏规则类型的键创建编解码器。
    - `Level`
        - `isMoonVisible` - 返回月亮当前是否在天空中可见。
        - `getPushableEntities` - 获取指定目标之外的在提供的边界框内的所有实体。
        - `getClientLeafTintColor` - 返回指定位置的树叶染色颜色。
        - `playPlayerSound` - 在客户端向当前玩家播放声音。
    - `LevelReader#getHeight` - 返回地图在给定位置的高度。
    - `NaturalSpawner#INSCRIBED_SQUARE_SPAWN_DISTANCE_CHUNK` - 提供玩家足够接近以进行生成的最小距离。
- `net.minecraft.world.level.biome`
    - `Biome`   
        - `getDryFoliageColor`、`getDryFoliageColorFromTexture` - 获取生物群系的干燥树叶颜色，要么从效果中获取，要么从气候设置中获取。
    - `BiomeSpecialEffects#getDryFoliageColorOverride`、`$Builder#dryFoliageColorOverride` - 当不从颜色映射纹理中提取时，返回默认的干燥树叶颜色。
- `net.minecraft.world.level.block`
    - `BaseFireBlock#fireIgnite` - 点燃一个实体。
    - `Block`
        - `UPDATE_SKIP_BLOCK_ENTITY_SIDEEFFECTS` - 一个标志，在更新方块实体时跳过所有潜在的副作用。
        - `UPDATE_SKIP_ALL_SIDEEFFECTS` - 一个标志，通过跳过某些方块实体逻辑、抑制掉落和更新已知形状来跳过所有副作用。
        - `UPDATE_SKIP_ON_PLACE` - 一个标志，在设置时跳过调用 `BlockState#onPlace`。
    - `BonemealableBlock#hasSpreadableNeighbourPos`、`findSpreadableNeighbourPos` - 处理在施骨粉时植被可以传播到的其他位置。
    - `CactusFlowerBlock` - 生长在仙人掌上的花。
    - `FireflyBushBlock` - 一个在其周围生成萤火虫粒子的灌木。
    - `SandBlock` - 一个可以播放环境声音的彩色沙子方块。
    - `SegmentableBlock` - 一个通常可以分解成具有独特大小和位置的部分的方块。
    - `ShortDryGrassBlock` - 一个已经干枯的单个草方块。
    - `TallDryGrassBlock` - 一个已经干枯的双高草方块。
    - `TerracottaBlock` - 一个可以播放环境声音的陶瓦方块。
    - `TintParticleLeavesBlock` - 一个其粒子被染色的树叶方块。
    - `UntintedParticleLeavesBlock` - 一个其粒子未被染色的树叶方块。
    - `VegetationBlock` - 一个表示某种植被的方块，可以传播光线，并需要某种耕地或泥土才能生存。
- `net.minecraft.world.level.block.entity.StructureBlockEntity#isStrict`、`setStrict` - 在生成结构时设置严格模式。
- `net.minecraft.world.level.block.sounds.AmbientDesertBlockSoundsPlayer` - 一个辅助工具，用于为给定的方块播放声音，通常在 `animateTick` 期间。
- `net.minecraft.world.level.block.state.BlockBehaviour#getEntityInsideCollisionShape` - 获取实体在其内部时方块的碰撞形状。
- `net.minecraft.world.level.border.WorldBorder`
    - `closestBorder` - 根据玩家的水平方向返回离玩家最近的边界列表。
    - `$DistancePerDirection` - 一个记录，包含给定方向上世界边界到实体的距离。
- `net.minecraft.world.level.chunk.status.ChunkStatus#CODEC`
- `net.minecraft.world.level.entity.PersistentEntitySectionManager#isTicking` - 返回指定的区块当前是否正在Tick。
- `net.minecraft.world.level.levelgen.Heightmap$Types#STREAM_CODEC`
- `net.minecraft.world.level.levelgen.feature`
    - `AbstractHugeMushroomFeature#placeMushroomBlock` - 在指定位置放置一个蘑菇方块，如果可以则替换方块。
    - `FallenTreeFeature` - 一个生成带有给定长度树桩的倒伏树木的功能。
    - `TreeFeature#getLowestTrunkOrRootOfTree` - 返回树装饰器的最低树干位置。
- `net.minecraft.world.level.levelgen.feature.configurations.FallenTreeConfiguration` - 用于带有树桩的倒伏树的配置。
- `net.minecraft.world.level.levelgen.feature.treedecorators`
    - `AttachedToLogsDecorator` - 一个装饰器，以一定的概率将随机方块附加到原木的给定方向。
    - `PlaceOnGroundDecorator` - 一个装饰器，将树放置在有效的方块位置上。
- `net.minecraft.world.level.levelgen.structure.pools`
    - `ListPoolElement#getElements` - 返回结构池的元素。
    - `SinglePoolElement#getTemplateLocation` - 返回元素使用的模板的位置。
    - `StructureTemplatePool#getTemplates` - 返回一个带有权重的元素列表。
- `net.minecraft.world.level.levelgen.structure.structures.JigsawStructure`
    - `getStartPool` - 返回要生成的拼图的起始池。
    - `getPoolAliases` - 返回拼图使用的所有池。
- `net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate#getDefaultJointType` - 如果未指定或加载期间发生错误，返回两个拼图块之间的默认连接类型。
- `net.minecraft.world.level.material.Fluid#getAABB`、`FluidState#getAABB` - 返回流体的边界框。
- `net.minecraft.world.scores`
    - `Objective#pack`、`$Packed` - 处理目标数据的可序列化形式。
    - `PlayerTeam#pack`、`$Packed` - 处理玩家队伍数据的可序列化形式。
    - `Scoreboard`
        - `loadPlayerTeam`、`loadObjective` - 从打包对象加载数据。
        - `$PackedScore` - 处理记分板数据的可序列化形式。
- `net.minecraft.world.level.storage.loot.LootTable#KEY_CODEC`
- `net.minecraft.world.phys`
    - `AABB$Builder` - 一个用于通过提供内部向量来构造边界框的构建器。
    - `Vec2#CODEC`
- `net.minecraft.world.phys.shapes.CollisionContext`
    - `placementContext` - 当从其物品放置方块时构造上下文。
    - `isPlacement` - 返回上下文是否用于放置方块。
- `net.minecraft.world.ticks.TickPriority#CODEC`

### 变更列表

- `net.minecraft.client.Screenshot` 现在是一个实用程序而不是实例类，意味着所有实例方法都已移除
    - `takeScreenshot(RenderTarget)` -> `takeScreenshot(RenderTarget, Consumer<NativeImage>)`，不返回任何内容
- `net.minecraft.client.multiplayer`
    - `ClientChunkCache#replaceWithPacketData` 现在接受一个 `Map<Heightmap$Types, long[]>` 而不是 `CompoundTag`
    - `MultiPlayerGameMode#hasInfiniteItems` -> `net.minecraft.world.entity.LivingEntity#hasInfiniteMaterials`
    - `ClientPacketListener#markMessageAsProcessed` 现在接受一个 `MessageSignature` 而不是 `PlayerChatMessage`
- `net.minecraft.client.multiplayer.chat.ChatListener#handleChatMessageError` 现在接受一个可为 null 的 `MessageSignature`
- `net.minecraft.client.player`
    - `ClientInput#leftImpulse`、`forwardImpulse` -> `moveVector`，现在是 protected
    - `LocalPlayer#spinningEffectIntensity`、`oSpinningEffectIntensity` -> `portalEffectIntensity`、`oPortalEffectIntensity`
- `net.minecraft.client.renderer.LevelRenderer#getLightColor(BlockAndTintGetter, BlockState, BlockPos)` -> `getLightColor(LevelRenderer$BrightnessGetter, BlockAndTintGetter, BlockState, BlockPos)`
- `net.minecraft.client.renderer.blockentity.BlockEntityRenderer#render` 现在接受一个 `Vec3` 表示相机的位置
- `net.minecraft.client.renderer.chunk.SectionRenderDispatcher`
    - `$RenderSection`
        - `getOrigin` -> `getRenderOrigin`
        - `reset` 现在是公开的
        - `releaseBuffers` 已移除
    - `$CompileTask#getOrigin` -> `getRenderOrigin`
- `net.minecraft.client.renderer.entity`
    - `DonkeyRenderer` 现在接受一个 `DonekyRenderer$Type`，包含纹理、模型层和装备信息
    - `ItemEntityRenderer#renderMultipleFromCount` 现在有一个接受模型边界框的重载
    - `UndeadHorseRenderer` 现在接受一个 `UndeadHorseRenderer$Type`，包含纹理、模型层和装备信息
- `net.minecraft.client.renderer.entity.layers`
    - `EquipmentLayerRenderer$TrimSpriteKey#textureId` -> `spriteId`
    - `VillagerProfessionLayer#getHatData` 现在接受一个资源键到元数据部分的映射，并将注册表和值交换为一个持有者实例
- `net.minecraft.client.renderer.item`
    - `ConditionalItemModel` 现在接受一个 `ItemModelPropertyTest` 而不是 `ConditionalItemModelProperty`
    - `SelectItemModel` 现在接受一个 `$ModelSelector` 而不是一个对象映射
- `net.minecraft.client.renderer.item.properties.conditional.ConditionalItemModelProperty` 现在实现 `ItemModelPropertyTest`
    - `ItemModelPropertyTest` 持有之前在 `ConditionalItemModelProperty` 中的 `get` 方法
- `net.minecraft.commands.arguments`
    - `ComponentArgument`
        - `ERROR_INVALID_JSON` -> `ERROR_INVALID_COMPONENT`
        - `getComponent` -> `getRawComponent`
    - `ResourceKeyArgument#getRegistryKey` 现在是公开的
    - `StyleArgument#ERROR_INVALID_JSON` -> `ERROR_INVALID_STYLE`
- `net.minecraft.commands.arguments.item`
    - `ComponentPredicateParser$Context#createComponentTest`、`createPredicateTest` 现在接受一个 `Dynamic` 而不是 `Tag`
    - `ItemPredicateArgument`
        - `$ComponentWrapper#decode` 现在接受一个 `Dynamic` 而不是 `RegistryOps`、`Tag` 对
        - `$PredicateWrapper#decode` 现在接受一个 `Dynamic` 而不是 `RegistryOps`、`Tag` 对
- `net.minecraft.core`
    - `BlockMath`
        - `VANILLA_UV_TRANSFORM_LOCAL_TO_GLOBAL`、`VANILLA_UV_TRANSFORM_GLOBAL_TO_LOCAL` 现在是私有的
        - `getUVLockTransform` -> `getFaceTransformation`
    - `Direction#rotate` 现在接受一个 `Matrix4fc` 而不是 `Matrix4f`
    - `Rotations` 现在是一个记录
- `net.minecraft.data.loot.BlockLootSubProvider#createPetalDrops` -> `createSegmentedBlockDrops`
- `net.minecraft.network`
    - `FriendlyByteBuf`
        - `writeLongArray`、`readLongArray` 现在有静态委托，接受 `ByteBuf`，并且 `*Fixed*` 版本用于固定大小的数组
    - `ProtocolInfo$Unbound` -> `$Details`、`net.minecraft.network.protocol.SimpleUnboundProtocol`、`net.minecraft.network.protocol.UnboundProtocol`；不是一对一
        - `#bind` -> `net.minecraft.network.protocol.SimpleUnboundProtocol#bind`、`UnboundProtocol#bind`；不是一对一
    - `SkipPacketException` 现在是一个接口，而不是 `EncoderException` 的子类
- `net.minecraft.network.chat`
    - `ComponentSerialization#flatCodec` -> `flatRestrictedCodec`
    - `LastSeenMessages$Update` 现在接受一个表示校验和值的字节
    - `LastSeenMessagesValidator`
        - `applyOffset` 现在不返回任何内容，并且可以抛出 `$ValidationException`
        - `applyUpdate` 现在返回原始消息，并且可以抛出 `$ValidationException`
- `net.minecraft.network.codec.StreamCodec#composite` 现在有一个九个参数的重载
- `net.minecraft.network.protocol.ProtocolInfoBuilder` 现在接受第三个泛型，表示如何修改提供的编解码器。
    - `addPacket` 现在有一个接受 `CodecModifier` 的重载
    - `build` -> `buildUnbound`，不是一对一
    - `protocol`、`serverboundProtocol`、`clientboundProtocol` 现在返回一个 `SimpleUnboundProtocol`
- `net.minecraft.network.protocol.ConfigurationProtocols` 现在包含 `SimpleUnboundProtocol` 常量
- `net.minecraft.network.protocol.game`
    - `ClientboundContainerSetContentPacket` 现在是一个记录
    - `ClientboundMoveEntityPacket#getyRot`、`getxRot` -> `getYRot`、`getXRot`
    - `ClientboundPlayerChatPacket` 现在接受一个聊天消息的全局索引
    - `ClientboundLevelChunkPacketdata#getHeightmaps` 现在返回一个 `Map<Heightmap.Types, long[]>`
    - `ClientboundUpdateAdvancementsPacket` 现在接受一个布尔值，表示是否将进度显示为吐司
    - `GameProtocols` 常量现在是 `SimpleUnboundProtocol` 或 `UnboundProtocol`
    - `ServerboundContainerClickPacket` 现在是一个记录
    - `ServerboundMovePlayerPacket$Pos`、`$PosRot` 现在有一个接受 `Vec3` 作为位置的重载
    - `ServerboundSetStructureBlockPacket` 现在接受一个额外的布尔值，表示是否应在严格模式下生成结构
- `net.minecraft.network.protocol.handshake.HandshakeProtocols#SERVERBOUND_TEMPLATE` 现在是一个 `SimpleUnboundProtocol`
- `net.minecraft.network.protocol.login.LoginProtocols#SERVERBOUND_TEMPLATE` 常量现在是 `SimpleUnboundProtocol`
- `net.minecraft.network.protocol.status.StatusProtocols#SERVERBOUND_TEMPLATE` 常量现在是 `SimpleUnboundProtocol`
- `net.minecraft.server.PlayerAdvancements#flushDirty` 现在接受一个布尔值，表示进度是否显示为吐司
- `net.minecraft.server.bossevents.CustomBossEvent`
    - `save` -> `pack`，不是一对一
    - `load` 现在接受 id 和打包变体以解包
- `net.minecraft.server.level`
    - `DistanceManager`
        - `hasPlayersNearby` 现在返回一个 `TriState`
        - `forEachBlockTickingChunks` -> `forEachEntityTickingChunk`，不是一对一
    - `ServerEntity` 现在接受一个消费者，用于向所有玩家广播数据包，但忽略列表中的玩家除外
    - `ServerLevel`
        - `getForcedChunks` -> `getForceLoadedChunks`
        - `isPositionTickingWithEntitiesLoaded` 现在是公开的
        - `isNaturalSpawningAllowed` -> `canSpawnEntitiesInChunk`，`BlockPos` 变体已移除
    - `ServerPlayer`
        - `getRespawnPosition`、`getRespawnAngle`、`getRespawnDimension`、`isRespawnForced` -> `getRespawnConfig`，不是一对一
        - `setRespawnPosition` 现在接受一个 `$RespawnConfig` 而不是单独的重生信息
        - `loadAndSpawnParentVehicle`、`loadAndSpawnEnderpearls` 现在接受一个 `CompoundTag`，没有可选的包装
- `net.minecraft.server.network.ServerGamePacketListenerImpl` 现在实现 `GameProtocols$Context`
- `net.minecraft.sounds.SoundEvents` 有以下声音现在是 `Holder` 包装的：
    - `ITEM_BREAK`
    - `SHIELD_BLOCK`、`SHIELD_BREAK`、
    - `WOLF_ARMOR_BREAK`
- `net.minecraft.util`
    - `Brightness`
        - `FULL_BRIGHT` 现在是 final
        - `pack` 现在有一个静态重载，接受块光和天空光。
    - `ExtraCodecs#MATRIX4f` 现在是一个 `Codec<Matrix4fc>`
    - `Util#makeEnumMap` 返回 `Map` 超实例而不是具体的 `EnumMap`
- `net.minecraft.util.parsing.packrat.commands.TagParseRule` 现在接受一个标签类型的泛型
    - 构造函数现在是公开的，接受一个 `DynamicOps`
- `net.minecraft.util.profiling`
    - `ActiveProfiler` 现在接受一个 `BooleanSupplier` 而不是一个布尔值
    - `ContinuousProfiler` 现在接受一个 `BooleanSupplier` 而不是一个布尔值
- `net.minecraft.util.worldupdate.WorldUpgrader` 现在接受当前的 `WorldData`
- `net.minecraft.world`
    - `BossEvent$BossBarColor`、`$BossBarOverlay` 现在实现 `StringRepresentable`
    - `Container` 现在实现 `Iterable<ItemStack>`
- `net.minecraft.world.effect`
    - `MobEffect`
        - `getBlendDurationTicks` -> `getBlendInDurationTicks`、`getBlendOutDurationTicks`、`getBlendOutAdvanceTicks`；不是一对一
        - `setBlendDuration` 现在有一个接受三个整数来设置淡入、淡出和淡出提前刻的重载
    - `MobEffectInstance#tick` -> `tickServer`、`tickClient`；不是一对一
- `net.minecraft.world.entity`
    - `Entity`
        - `cancelLerp` -> `InterpolationHandler#cancel`
        - `lerpTo` -> `moveOrInterpolateTo`
        - `lerpTargetX`、`lerpTargetY`、`lerpTargetZ`、`lerpTargetXRot`、`lerpTargetYRot` -> `getInterpolation`
        - `onAboveBubbleCol` -> `onAboveBubbleColumn` 现在接受一个 `BlockPos` 作为气泡柱粒子的生成位置
            - 逻辑委托给受保护的静态 `handleOnAboveBubbleColumn`
        - `isControlledByOrIsLocalPlayer` -> `isLocalInstanceAuthoritative`，现在是 final
        - `isControlledByLocalInstance` -> `isLocalClientAuthoritative`，现在是 protected
        - `isControlledByClient` -> `isClientAuthoritative`
        - `fallDistance`、`causeFallDamage` 现在是 double
        - `absMoveto` -> `absSnapTo`
        - `absRotateTo` -> `asbSnapRotationTo`
        - `moveTo` -> `snapTo`
        - `sendBubbleColumnParticles` 现在是静态的，接受 `Level`
        - `onInsideBubbleColumn` 逻辑委托给受保护的静态 `handleOnInsideBubbleColumn`
    - `EntityType`
        - `POTION` -> `SPLASH_POTION`、`LINGERING_POTION`，不是一对一
        - `$EntityFactory#create` 现在可以返回一个 null 实例
    - `ExperienceOrb#value` -> `DATA_VALUE`
    - `ItemBasedSteering` 不再接受用于判断是否有马鞍的访问器
    - `LivingEntity`
        - `lastHurtByPlayerTime` -> `lastHurtByPlayerMemoryTime`
        - `lerpSteps`、`lerpX`、`lerpY`、`lerpZ`、`lerpYRot`、`lerpXRot` -> `interpolation`，不是一对一
        - `isAffectedByFluids` 现在是公开的
        - `removeEffectNoUpdate` 现在是 final
        - `tickHeadTurn` 现在不返回任何内容
        - `canDisableShield` -> `canDisableBlocking`，现在通过 `WEAPON` 数据组件设置
        - `calculateFallDamage` 现在接受 double 而不是 float
    - `Mob`
        - `handDropChances`、`armorDropChances`、`bodyArmorDropChance` -> `dropChances`，不是一对一
        - `getEquipmentDropChance` -> `getDropChances`，不是一对一
- `net.minecraft.world.entity.ai.Brain#addActivityWithConditions` 现在有一个接受整数表示起始优先级的重载
- `net.minecraft.world.entity.ai.behavior`
    - `LongJumpToRandomPos$PossibleJump` 现在是一个记录
    - `VillagerGoalPackages#get*Package` 现在接受一个持有者包装的职业
- `net.minecraft.world.entity.ai.gossip.GossipContainer#store`、`update` -> `clear`、`putAll`、`copy`；不是一对一
- `net.minecraft.world.entity.animal`
    - `Pig` 现在是一个 `VariantHolder`
    - `Sheep` -> `.sheep.Sheep`
    - `WaterAnimal#handleAirSupply` 现在接受一个 `ServerLevel`
- `net.minecraft.world.entity.animal.axolotl.Axolotl#handleAirSupply` 现在接受一个 `ServerLevel`
- `net.minecraft.world.entity.monster.ZombieVillager#setGossips` 现在接受一个 `GossipContainer`
- `net.minecraft.world.entity.monster.warden.WardenSpawnTracker` 现在有一个重载，将初始参数设置为零
- `net.minecraft.world.entity.npc`
    - `Villager` 现在接受一个键或一个 `VillagerType` 的持有者
        - `setGossips` 现在接受一个 `GossipContainer`
    - `VillagerData` 现在是一个记录
        - `set*` -> `with*`
    - `VillagerProfession` 现在接受一个 `Component` 作为名称
    - `VillagerTrades`
        - `TRADES` 现在接受一个资源键作为映射的键
            - 这对于所有其他特定类型的交易类似
        - `$FailureItemListing` 现在是私有的
- `net.minecraft.world.entity.player.Player`
    - `stopFallFlying` -> `LivingEntity#stopFallFlying`
    - `isSpectator`、`isCreative` 在 `Player` 类中不再是抽象的
- `net.minecraft.world.entity.projectile.ThrownPotion` -> `AbstractThrownPotion`，在 `ThrownLingeringPotion` 和 `ThrownSplashPotion` 中实现
- `net.minecraft.world.entity.raid.Raid(int, ServerLevel, BlockPos)` -> `Raid(BlockPos, Difficulty)`
    - `tick`、`addWaveMob` 现在接受 `ServerLevel`
- `net.minecraft.world.entity.vehicle`
    - `AbstractMinecart#setDisplayBlockState` -> `setCustomDisplayBlockState`
    - `MinecartBehavior` 
        - `cancelLerp` -> `InterpolationHandler#cancel`
        - `lerpTargetX`、`lerpTargetY`、`lerpTargetZ`、`lerpTargetXRot`、`lerpTargetYRot` -> `getInterpolation`
    - `MinecartTNT#primeFuse` 现在接受 `DamageSource` 原因
- `net.minecraft.world.inventory`
    - `AbstractContainerMenu`
        - `setRemoteSlotNoCopy` -> `setRemoteSlotUnsafe`，不是一对一
        - `setRemoteCarried` 现在接受一个 `HashedStack`
    - `ClickType` 现在接受一个表示其表示的 id
    - `ContainerSynchronizer#sendInitialData` 现在接受一个堆栈列表而不是 `NonNullList`
- `net.minecraft.world.item`
    - `EitherHolder` 现在接受一个 `Either` 实例而不是仅仅一个可选的持有者和 `ResourceKey`
    - `Item`
        - `canAttackBlock` -> `canDestroyBlock`
        - `hurtEnemy` 不再返回任何内容
        - `onCraftedBy` 不再接受一个单独的 `Level` 实例，现在依赖于 `Player` 提供的实例
    - `ItemStack`
        - `validateStrict` 现在是公开的
        - `onCraftedBy` 不再接受一个单独的 `Level` 实例，现在依赖于 `Player` 提供的实例
    - `MapItem`
        - `create` 现在接受一个 `ServerLevel` 而不是 `Level`
        - `lockMap` 现在是私有的
    - `ThrowablePotionItem` 现在是抽象的，包含两个创建 `AbstractThrownPotion` 实体的方法
    - `WrittenBookItem#resolveBookComponents` -> `WrittenBookContent#resolveForItem`
- `net.minecraft.world.item.alchemy.PotionContents` 现在实现 `TooltipProvider`
    - `forEachEffect`、`applyToLivingEntity` 现在接受一个 float 表示持续时间的标量
- `net.minecraft.world.item.component.WrittenBookContent` 现在实现 `TooltipProvider`
- `net.minecraft.world.item.crafting`
    - `SmithingRecipe#baseIngredient` 现在返回一个 `Ingredient`
    - `SmithingTransformRecipe` 现在接受一个 `TransmuteResult` 而不是一个 `ItemStack` 和一个 `Ingredient` 作为基础
    - `SmithingTrimRecipe` 现在接受 `Ingredient` 而不是 `Optional` 包装的条目，以及一个 `TrimPattern` 持有者
    - `TransmuteRecipe` 现在接受一个 `TransmuteResult` 而不是一个 `Item` 持有者
- `net.minecraft.world.item.crafting.display.SlotDisplay$SmithingTrimDemoSlotDisplay` 现在接受一个 `TrimPattern` 持有者
- `net.minecraft.world.item.enchantment.EnchantmentInstance` 现在是一个记录
- `net.minecraft.world.level`
    - `BlockGetter#boxTraverseBlocks` -> `forEachBlockIntersectedBetween`，不是一对一
    - `CustomSpawner#tick` 不再返回任何内容
    - `GameRules$Type` 现在接受一个值类
    - `Level`
        - `onBlockStateChange` -> `updatePOIOnBlockStateChange`
        - `isDay` -> `isBrightOutside`
        - `isNight` -> `isDarkOutside`
        - `setMapData` -> `net.minecraft.server.level.ServerLevel#setMapData`
        - `getFreeMapId` -> `net.minecraft.server.level.ServerLevel#getFreeMapId`
    - `LevelAccessor#blockUpdated` -> `updateNeighborsAt`
- `net.minecraft.world.level.biome.MobSpawnSettings$SpawnerData` 现在是一个记录
- `net.minecraft.world.level.block`
    - `AttachedStemBlock` 现在继承 `VegetationBlock`
    - `AzaleaBlock` 现在继承 `VegetationBlock`
    - `Block#fallOn` 现在接受一个 double 作为坠落伤害，而不是 float
    - `BushBlock` 现在继承 `VegetationBlock` 并实现 `BonemealableBlock`
    - `ColoredFallingBlock#dustColor` 现在是 protected
    - `CropBlock` 现在继承 `VegetationBlock`
    - `DeadBushBlock` -> `DryVegetationBlock`
    - `DoublePlantBlock` 现在继承 `VegetationBlock`
    - `FallingBlock#getDustColor` 现在是抽象的
    - `FlowerBedBlock` 现在继承 `VegetationBlock`
    - `FlowerBlock` 现在继承 `VegetationBlock`
    - `FungusBlock` 现在继承 `VegetationBlock`
    - `LeafLitterBlock` 现在继承 `VegetationBlock`
    - `LeavesBlock` 现在是抽象的，接受粒子生成的概率
        - 粒子通过 `spawnFallingLeavesParticle` 生成
    - `MangroveLeavesBlock` 现在继承 `TintedParticleLeavesBlock`
    - `MushroomBlock` 现在继承 `VegetationBlock`
    - `NetherSproutsBlock` 现在继承 `VegetationBlock`
    - `NetherWartBlock` 现在继承 `VegetationBlock`
    - `ParticleLeavesBlock` -> `LeafLitterBlock`
    - `PinkPetalsBlock` -> `FlowerBedBlock`
    - `RootsBlock` 现在继承 `VegetationBlock`
    - `Rotation` 现在有一个用于网络同步的索引
    - `SaplingBlock` 现在继承 `VegetationBlock`
    - `SeagrassBlock` 现在继承 `VegetationBlock`
    - `SeaPickleBlock` 现在继承 `VegetationBlock`
    - `StemBlock` 现在继承 `VegetationBlock`
    - `SweetBerryBushBlock` 现在继承 `VegetationBlock`
    - `TallGrassBlock` 现在继承 `VegetationBlock`
    - `TntBlock#prime` 现在返回是否生成了点燃的 TNT。
    - `WaterlilyBlock` 现在继承 `VegetationBlock`
- `net.minecraft.world.level.block.entity`
    - `BlockEntity`
        - `parseCustomNameSafe` 现在接受一个可为 null 的 `Tag` 而不是字符串
        - `getPosFromTag` 现在接受 `ChunkPos`
        - `$ComponentHolder#COMPONENTS_CODEC` 现在是一个 `MapCodec`
    - `BLockEntityType#create` 不再是可为 null 的
- `net.minecraft.world.level.block.entity.trialspawner.TrialSpawner#codec` 现在返回一个 `MapCodec`
- `net.minecraft.world.level.block.state.StateHolder`
    - `getNullableValue` 现在是私有的
    - `hasProperty` 不再包含泛型
- `net.minecraft.world.level.chunk`
    - `ChunkAccess#setBlockState` 现在接受块标志而不是布尔值，并有一个重载来更新所有设置
    - `LevelChunk#replaceWithPacketData` 现在接受一个 `Map<Heightmap$Types, long[]>` 而不是 `CompoundTag`
- `net.minecraft.world.level.chunk.storage.SerializableChunkData#getChunkTypeFromTag` -> `getChunkStatusFromTag`，不是一对一
- `net.minecraft.world.level.gameevent.vibrations.VibrationSystem#DEFAULT_VIBRATION_FREQUENCY` -> `NO_VIBRATION_FREQUENCY`
- `net.minecraft.world.level.levelgen.feature.TreeFeature#isVine` 现在是公开的
- `net.minecraft.world.level.levelgen.structure.pools.alias`
    - `Direct` -> `DirectPoolAlias`
    - `Random` -> `RandomPoolAlias`
    - `RandomGroup` -> `RandomGroupPoolAlias`
- `net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate$JigsawBlockInfo` 现在接受 `StructureTemplatePool` 的 `ResourceKey` 而不是原始 `ResourceLocation`
- `net.minecraft.world.level.saveddata.maps.MapFrame` 现在是一个记录
    - `save`、`load` -> `CODEC`，不是一对一
- `net.minecraft.world.level.storage.loot.functions.SetWrittenBookPagesFunction#PAGE_CODEC` -> `WrittenBookContent#PAGES_CODEC`
- `net.minecraft.world.scores`
    - `Score#write` -> `CODEC`，不是一对一
    - `Scoreboard`
        - `savePlayerScores` -> `packPlayerScores`，不是一对一
        - `loadPlayerScores` -> `loadPlayerScore`，不是一对一
    - `Team$CollisionRule`、`$Visibility` 现在是 `StringRepresentable`
- `net.minecraft.world.phys.shapes.EntityCollisionContext` 现在接受一个布尔值，表示是否用于放置方块
- `net.minecraft.world.ticks.SavedTick`
    - `loadTick`、`saveTick`、`save` -> `codec`，不是一对一
    - `loadTickList` -> `filterTickListForChunk`，不是一对一

### 移除列表

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