1449 lines
80 KiB
Markdown
1449 lines
80 KiB
Markdown
# Minecraft 1.21.2/3 -> 1.21.4 模组迁移入门文档
|
||
|
||
本文档是一个高层次、非详尽的概述,介绍如何将您的模组从 1.21.2/3 迁移到 1.21.4。本文不涉及任何特定的模组加载器,只关注原版类的变更。所有提供的名称均使用官方的 Mojang 映射。
|
||
|
||
本入门文档采用 [知识共享署名 4.0 国际许可协议](http://creativecommons.org/licenses/by/4.0/) 授权,因此您可以自由地将其用作参考,并请留下链接以便其他读者查阅。
|
||
|
||
如果存在任何不正确或缺失的信息,请在本仓库提交 issue,或在 Neoforged Discord 服务器中 @ChampionAsh5357。
|
||
|
||
## 资源包变更
|
||
|
||
原版中有许多面向用户的变更为未在下面讨论,但这些变更可能与模组制作者相关。您可以在 [Misode 的版本更新日志](https://misode.github.io/versions/?id=1.21.4&tab=changelog) 中找到它们的列表。
|
||
|
||
## 客户端物品
|
||
|
||
Minecraft 已将物品应如何渲染的查找和定义移到了自己的数据生成系统中,该系统被称为**客户端物品**,位于 `assets/<namespace>/items/<path>.json`。客户端物品类似于方块状态模型定义,但将来有可能包含更多信息。目前,它只是作为一个链接器,链接到用于渲染的模型。
|
||
|
||
所有客户端物品都包含一个使用 `model` 字段的 `ItemModel$Unbaked`。每个未烘焙模型都有一个关联的类型,该类型定义了物品应如何设置渲染,或在特定情况下如何渲染。这些 `type` 可以在 `ItemModels` 中找到。本文将介绍除一种类型外的所有类型,因为该未烘焙模型类型专门用于在选择物品时的捆绑包。
|
||
|
||
物品还包含一个 `properties` 字段,其中包含一些与元数据相关的参数。目前,它只指定了一个布尔值,当为 false 时,使手部立即交换当前持有的物品,而不是播放手部抬起的动画。
|
||
|
||
```json5
|
||
// 对于某个物品 'examplemod:example_item'
|
||
// JSON 位于 'assets/examplemod/items/example_item.json'
|
||
{
|
||
"model": {
|
||
"type": "" // 在此处设置类型
|
||
// 添加其他参数
|
||
},
|
||
"properties": {
|
||
// 当为 false 时,禁用将此物品交换到手中时的动画
|
||
"hand_animation_on_swap": false
|
||
}
|
||
}
|
||
```
|
||
|
||
### 基本模型
|
||
|
||
基本模型定义由 `minecraft:model` 类型处理。它包含两个字段:`model`,用于定义模型 JSON 的相对位置;以及一个可选的 `tints` 列表,用于定义如何对每个索引进行染色。
|
||
|
||
`model` 指向模型 JSON,相对于 `assets/<namespace>/models/<path>.json`。在大多数情况下,客户端物品定义看起来像这样:
|
||
|
||
```json5
|
||
// 对于某个物品 'examplemod:example_item'
|
||
// JSON 位于 'assets/examplemod/items/example_item.json'
|
||
{
|
||
"model": {
|
||
"type": "minecraft:model",
|
||
// 指向 'assets/examplemod/models/item/example_item.json'
|
||
"model": "examplemod:item/example_item"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 染色源
|
||
|
||
在模型 JSON 中,一些元素面会有一个 `tintindex` 字段,它引用 `minecraft:model` 未烘焙模型类型中 `tints` 列表的某个索引。tints 列表是 `ItemTintSource`,它们都在 `net.minecraft.client.color.item.*` 中定义。所有定义的染色源都可以在 `ItemTintSources` 中找到,例如 `minecraft:constant` 用于常量颜色,或 `minecraft:dye` 用于使用 `DataComponents#DYED_COLOR` 的颜色,如果不存在则使用默认值。所有染色源都必须返回一个不透明的颜色,不过所有源通常通过调用 `ARGB#opaque` 来应用。
|
||
|
||
```json5
|
||
// 对于某个物品 'examplemod:example_item'
|
||
// JSON 位于 'assets/examplemod/items/example_item.json'
|
||
{
|
||
"model": {
|
||
"type": "minecraft:model",
|
||
// 指向 'assets/examplemod/models/item/example_item.json'
|
||
"model": "examplemod:item/example_item",
|
||
// 要应用的 tints 列表
|
||
"tints": [
|
||
{
|
||
// 当 tintindex: 0 时
|
||
"type": "minecraft:constant",
|
||
// 0x00FF00(或纯绿色)
|
||
"value": 65280
|
||
},
|
||
{
|
||
// 当 tintindex: 1 时
|
||
"type": "minecraft:dye",
|
||
// 0x0000FF(或纯蓝色)
|
||
// 仅在未设置 `DataComponents#DYED_COLOR` 时调用
|
||
"default": 255
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
要创建自己的 `ItemTintSource`,需要实现 `calculate` 方法,并注册与 `type` 字段关联的 `MapCodec`。`calculate` 接受当前的 `ItemStack`、等级和持有实体,并返回一个带有不透明 alpha 的 RGB 整数,定义层应如何染色。
|
||
|
||
然后,需要将 `MapCodec` 注册到 `ItemTintSources#ID_MAPPER`,但该字段默认是私有的,因此需要一些访问更改或反射。
|
||
|
||
```java
|
||
// 物品源类
|
||
public record FromDamage(int defaultColor) implements ItemTintSource {
|
||
|
||
public static final MapCodec<FromDamage> MAP_CODEC = RecordCodecBuilder.mapCodec(instance ->
|
||
instance.group(
|
||
ExtraCodecs.RGB_COLOR_CODEC.fieldOf("default").forGetter(FromDamage::defaultColor)
|
||
).apply(instance, FromDamage::new)
|
||
);
|
||
|
||
public FromDamage(int defaultColor) {
|
||
this.defaultColor = ARGB.opaque(defaultColor);
|
||
}
|
||
|
||
@Override
|
||
public int calculate(ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity) {
|
||
return stack.isDamaged() ? ARGB.opaque(stack.getBarColor()) : defaultColor;
|
||
}
|
||
|
||
@Override
|
||
public MapCodec<FromDamage> type() {
|
||
return MAP_CODEC;
|
||
}
|
||
}
|
||
|
||
// 然后,在某个暴露 ItemTintSources#ID_MAPPER 的初始化位置
|
||
ItemTintSources.ID_MAPPER.put(
|
||
// 注册表名称
|
||
ResourceLocation.fromNamespaceAndPath("examplemod", "from_damage"),
|
||
// 映射编解码器
|
||
FromDamage.MAP_CODEC
|
||
);
|
||
```
|
||
|
||
```json5
|
||
// 对于 'tints' 数组中的某个对象
|
||
{
|
||
"type": "examplemod:from_damage",
|
||
// 0x0000FF(或纯蓝色)
|
||
// 仅在物品尚未损坏时调用
|
||
"default": 255
|
||
}
|
||
```
|
||
|
||
### 范围属性模型
|
||
|
||
范围属性模型,由 `minecraft:range_dispatch` 未烘焙模型类型定义,与之前的物品覆盖系统最为相似。本质上,该类型定义了一些可以缩放的物品属性,以及一系列阈值和关联的模型。选择的模型是具有最接近且不超过属性值的阈值的模型(例如,如果属性值为 `4`,我们有阈值 `3` 和 `5`,则会选择 `3`,因为它是最接近且不超过的)。物品属性通过 `RangeSelectItemModelProperty` 定义,它接受堆栈、等级、实体和一些种子值,返回一个浮点数,通常根据实现缩放在 0 和 1 之间。所有属性都可以在 `net.minecraft.client.renderer.item.properties.numeric.*` 中找到,并在 `RangeSelectItemModelProperties` 中注册,例如 `minecraft:cooldown` 用于冷却时间百分比,或 `minecraft:count` 用于堆栈中的当前物品数量或标准化后的最大堆栈大小百分比。
|
||
|
||
```json5
|
||
// 对于某个物品 'examplemod:example_item'
|
||
// JSON 位于 'assets/examplemod/items/example_item.json'
|
||
{
|
||
"model": {
|
||
"type": "minecraft:range_dispatch",
|
||
|
||
// 要使用的 `RangeSelectItemModelProperty`
|
||
"property": "minecraft:count",
|
||
// 乘以计算出的属性值的标量
|
||
// 如果 count 为 0.3,scale 为 0.2,则检查的阈值为 0.3*0.2=0.06
|
||
"scale": 1,
|
||
"fallback": {
|
||
// 如果没有匹配的阈值,则使用的后备模型
|
||
// 可以是任何未烘焙模型类型
|
||
"type": "minecraft:model",
|
||
"model": "examplemod:item/example_item"
|
||
},
|
||
|
||
// ~~ 由 `Count` 定义的属性 ~~
|
||
// 当为 true 时,使用其最大堆栈大小对计数进行归一化
|
||
"normalize": true,
|
||
|
||
// ~~ 包含阈值信息的条目 ~~
|
||
"entries": [
|
||
{
|
||
// 当计数为其当前最大堆栈大小的三分之一时
|
||
"threshold": 0.33,
|
||
"model": {
|
||
// 可以是任何未烘焙模型类型
|
||
}
|
||
},
|
||
{
|
||
// 当计数为其当前最大堆栈大小的三分之二时
|
||
"threshold": 0.66,
|
||
"model": {
|
||
// 可以是任何未烘焙模型类型
|
||
}
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
要创建自己的 `RangeSelectItemModelProperty`,需要实现 `get` 方法,并注册与 `type` 字段关联的 `MapCodec`。`get` 接受堆栈、等级、实体和种子值,并返回一个任意浮点数,供范围分发模型解释。
|
||
|
||
然后,需要将 `MapCodec` 注册到 `RangeSelectItemModelProperties#ID_MAPPER`,但该字段默认是私有的,因此需要一些访问更改或反射。
|
||
|
||
```java
|
||
// 范围属性类
|
||
public record AppliedEnchantments() implements RangeSelectItemModelProperty {
|
||
|
||
public static final MapCodec<AppliedEnchantments> MAP_CODEC = MapCodec.unit(new AppliedEnchantments());
|
||
|
||
@Override
|
||
public float get(ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed) {
|
||
return (float) stack.getEnchantments().size();
|
||
}
|
||
|
||
@Override
|
||
public MapCodec<AppliedEnchantments> type() {
|
||
return MAP_CODEC;
|
||
}
|
||
}
|
||
|
||
// 然后,在某个暴露 RangeSelectItemModelProperties#ID_MAPPER 的初始化位置
|
||
RangeSelectItemModelProperties.ID_MAPPER.put(
|
||
// 注册表名称
|
||
ResourceLocation.fromNamespaceAndPath("examplemod", "applied_enchantments"),
|
||
// 映射编解码器
|
||
AppliedEnchantments.MAP_CODEC
|
||
);
|
||
```
|
||
|
||
```json5
|
||
// 对于 'model' 中的某个客户端物品
|
||
{
|
||
"type": "minecraft:range_dispatch",
|
||
|
||
// 要使用的 `RangeSelectItemModelProperty`
|
||
"property": "examplemod:applied_enchantments",
|
||
// 乘以计算出的属性值的标量
|
||
"scale": 0.5,
|
||
"fallback": {
|
||
// 如果没有匹配的阈值,则使用的后备模型
|
||
// 可以是任何未烘焙模型类型
|
||
"type": "minecraft:model",
|
||
"model": "examplemod:item/example_item"
|
||
},
|
||
|
||
// ~~ 由 `AppliedEnchantments` 定义的属性 ~~
|
||
// 无(构造函数无参数)
|
||
|
||
// ~~ 包含阈值信息的条目 ~~
|
||
"entries": [
|
||
{
|
||
// 当存在一个附魔时
|
||
// 因为 1 * 标量 0.5 = 0.5
|
||
"threshold": 0.5,
|
||
"model": {
|
||
// 可以是任何未烘焙模型类型
|
||
}
|
||
},
|
||
{
|
||
// 当存在两个附魔时
|
||
"threshold": 1,
|
||
"model": {
|
||
// 可以是任何未烘焙模型类型
|
||
}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 选择属性模型
|
||
|
||
选择属性模型,由 `minecraft:select` 未烘焙模型类型定义,在功能上类似于范围属性模型,但现在它根据某个属性(通常是枚举)进行切换。物品属性通过 `SelectItemModelProperty` 定义,它接受堆栈、等级、实体、一些种子值和当前显示上下文,以获取其中一个属性值。所有属性都可以在 `net.minecraft.client.renderer.item.properties.select.*` 中找到,并在 `SelectItemModelProperties` 中注册,例如 `minecraft:block_state` 用于指定方块状态属性的字符串值,或 `minecraft:display_context` 用于当前的 `ItemDisplayContext`。
|
||
|
||
```json5
|
||
// 对于某个物品 'examplemod:example_item'
|
||
// JSON 位于 'assets/examplemod/items/example_item.json'
|
||
{
|
||
"model": {
|
||
"type": "minecraft:select",
|
||
|
||
// 要使用的 `SelectItemModelProperty`
|
||
"property": "minecraft:display_context",
|
||
"fallback": {
|
||
// 如果没有匹配的阈值,则使用的后备模型
|
||
// 可以是任何未烘焙模型类型
|
||
"type": "minecraft:model",
|
||
"model": "examplemod:item/example_item"
|
||
},
|
||
|
||
// ~~ 由 `DisplayContext` 定义的属性 ~~
|
||
// 无(构造函数无参数)
|
||
|
||
// ~~ 基于可选择的属性的开关情况 ~~
|
||
"cases": [
|
||
{
|
||
// 当显示上下文为 `ItemDisplayContext#GUI` 时
|
||
"when": "gui",
|
||
"model": {
|
||
// 可以是任何未烘焙模型类型
|
||
}
|
||
},
|
||
{
|
||
// 当显示上下文为 `ItemDisplayContext#FIRST_PERSON_RIGHT_HAND` 时
|
||
"when": "firstperson_righthand",
|
||
"model": {
|
||
// 可以是任何未烘焙模型类型
|
||
}
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
要创建自己的 `SelectItemModelProperty`,需要实现 `get` 方法,并注册与 `type` 字段关联的 `SelectItemModelProperty$Type`。`get` 接受堆栈、等级、实体、种子值和显示上下文,并返回一个可编码的对象,供选择模型解释。
|
||
|
||
然后,需要将 `MapCodec` 注册到 `SelectItemModelProperties#ID_MAPPER`,但该字段默认是私有的,因此需要一些访问更改或反射。
|
||
|
||
```java
|
||
// 选择属性类
|
||
public record StackRarity() implements SelectItemModelProperty<Rarity> {
|
||
|
||
public static final SelectItemModelProperty.Type<StackRarity, Rarity> TYPE = SelectItemModelProperty.Type.create(
|
||
// 此属性的映射编解码器
|
||
MapCodec.unit(new StackRarity()),
|
||
// 被选择对象的编解码器
|
||
Rarity.CODEC
|
||
);
|
||
|
||
@Nullable
|
||
@Override
|
||
public Rarity get(ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed, ItemDisplayContext displayContext) {
|
||
// 当为 null 时,使用后备模型
|
||
return stack.get(DataComponents.RARITY);
|
||
}
|
||
|
||
@Override
|
||
public SelectItemModelProperty.Type<StackRarity, Rarity> type() {
|
||
return TYPE;
|
||
}
|
||
}
|
||
|
||
// 然后,在某个暴露 SelectItemModelProperties#ID_MAPPER 的初始化位置
|
||
SelectItemModelProperties.ID_MAPPER.put(
|
||
// 注册表名称
|
||
ResourceLocation.fromNamespaceAndPath("examplemod", "rarity"),
|
||
// 属性类型
|
||
StackRarity.TYPE
|
||
);
|
||
```
|
||
|
||
```json5
|
||
// 对于某个物品 'examplemod:example_item'
|
||
// JSON 位于 'assets/examplemod/items/example_item.json'
|
||
{
|
||
"model": {
|
||
"type": "minecraft:select",
|
||
|
||
// 要使用的 `SelectItemModelProperty`
|
||
"property": "examplemod:rarity",
|
||
"fallback": {
|
||
// 如果没有匹配的阈值,则使用的后备模型
|
||
// 可以是任何未烘焙模型类型
|
||
"type": "minecraft:model",
|
||
"model": "examplemod:item/example_item"
|
||
},
|
||
|
||
// ~~ 由 `StackRarity` 定义的属性 ~~
|
||
// 无(构造函数无参数)
|
||
|
||
// ~~ 基于可选择的属性的开关情况 ~~
|
||
"cases": [
|
||
{
|
||
// 当稀有度为 `Rarity#UNCOMMON` 时
|
||
"when": "uncommon",
|
||
"model": {
|
||
// 可以是任何未烘焙模型类型
|
||
}
|
||
},
|
||
{
|
||
// 当稀有度为 `Rarity#RARE` 时
|
||
"when": "rare",
|
||
"model": {
|
||
// 可以是任何未烘焙模型类型
|
||
}
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 条件属性模型
|
||
|
||
条件属性模型,由 `minecraft:condition` 未烘焙模型类型定义,在功能上类似于范围属性模型,但现在它根据布尔值进行切换。这些通常与范围分发结合使用,例如拉弓时。物品属性通过 `ConditionalItemModelProperty` 定义,它接受堆栈、等级、实体、一些种子值和当前显示上下文,以获取一个 true 或 false 语句。所有属性都可以在 `net.minecraft.client.renderer.item.properties.conditional.*` 中找到,并在 `ConditionalItemModelProperties` 中注册,例如 `minecraft:damaged` 用于物品是否损坏,或 `minecraft:has_component` 用于是否具有给定的数据组件。
|
||
|
||
```json5
|
||
// 对于某个物品 'examplemod:example_item'
|
||
// JSON 位于 'assets/examplemod/items/example_item.json'
|
||
{
|
||
"model": {
|
||
"type": "minecraft:condition",
|
||
|
||
// 要使用的 `SelectItemModelProperty`
|
||
"property": "minecraft:damaged",
|
||
|
||
// ~~ 由 `Damaged` 定义的属性 ~~
|
||
// 无(构造函数无参数)
|
||
|
||
// ~~ 布尔结果的含义 ~~
|
||
"on_true": {
|
||
// 可以是任何未烘焙模型类型
|
||
},
|
||
"on_false": {
|
||
// 可以是任何未烘焙模型类型
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
要创建自己的 `ConditionalItemModelProperty`,需要实现 `get` 方法,并注册与 `type` 字段关联的 `MapCodec`。`get` 接受堆栈、等级、实体、种子值和显示上下文,并返回一个布尔值,分别由 `on_true` 和 `on_false` 解释。
|
||
|
||
然后,需要将 `MapCodec` 注册到 `ConditionalItemModelProperties#ID_MAPPER`,但该字段默认是私有的,因此需要一些访问更改或反射。
|
||
|
||
```java
|
||
// 谓词属性类
|
||
public record TimePeriod(int month, MinMaxBounds.Ints dates, boolean enabled) implements ConditionalItemModelProperty {
|
||
|
||
public static final MapCodec<TimePeriod> MAP_CODEC = RecordCodecBuilder.mapCodec(instance ->
|
||
instance.group(
|
||
Codec.intRange(1, 12).fieldOf("month").forGetter(TimePeriod::month),
|
||
MinMaxBounds.Ints.CODEC.fieldOf("dates").forGetter(TimePeriod::dates)
|
||
).apply(instance, TimePeriod::new)
|
||
);
|
||
|
||
public TimePeriod(int month, MinMaxBounds.Ints dates) {
|
||
this.month = month;
|
||
this.dates = dates;
|
||
|
||
Calendar cal = Calendar.getInstance();
|
||
this.enabled = cal.get(Calendar.MONTH) + 1 == this.month
|
||
&& this.dates.matches(cal.get(Calendar.DATE));
|
||
}
|
||
|
||
@Override
|
||
public boolean get(ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed, ItemDisplayContext context) {
|
||
return this.enabled;
|
||
}
|
||
|
||
@Override
|
||
public MapCodec<TimePeriod> type() {
|
||
return MAP_CODEC;
|
||
}
|
||
}
|
||
|
||
// 然后,在某个暴露 ConditionalItemModelProperties#ID_MAPPER 的初始化位置
|
||
ConditionalItemModelProperties.ID_MAPPER.put(
|
||
// 注册表名称
|
||
ResourceLocation.fromNamespaceAndPath("examplemod", "time_period"),
|
||
// 映射编解码器
|
||
TimePeriod.MAP_CODEC
|
||
);
|
||
```
|
||
|
||
```json5
|
||
// 对于某个物品 'examplemod:example_item'
|
||
// JSON 位于 'assets/examplemod/items/example_item.json'
|
||
{
|
||
"model": {
|
||
"type": "minecraft:condition",
|
||
|
||
// 要使用的 `SelectItemModelProperty`
|
||
"property": "examplemod:time_period",
|
||
|
||
// ~~ 由 `TimePeriod` 定义的属性 ~~
|
||
// 七月
|
||
"month": 7,
|
||
"dates": {
|
||
// 7 月 1 日至 14 日之间
|
||
"min": 1,
|
||
"max": 14
|
||
},
|
||
|
||
// ~~ 布尔结果的含义 ~~
|
||
"on_true": {
|
||
// 可以是任何未烘焙模型类型
|
||
},
|
||
"on_false": {
|
||
// 可以是任何未烘焙模型类型
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 复合模型
|
||
|
||
复合模型,由 `minecraft:composite` 定义,本质上是其他模型类型的组合,用于渲染。具体来说,它设置了多个层,在渲染时将一个模型叠加在另一个模型之上。
|
||
|
||
```json5
|
||
// 对于某个物品 'examplemod:example_item'
|
||
// JSON 位于 'assets/examplemod/items/example_item.json'
|
||
{
|
||
"model": {
|
||
"type": "minecraft:composite",
|
||
|
||
// 将按照在列表中出现的顺序进行渲染
|
||
"models": [
|
||
{
|
||
// 可以是任何未烘焙模型类型
|
||
},
|
||
{
|
||
// 可以是任何未烘焙模型类型
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 特殊动态模型
|
||
|
||
特殊动态模型,由 `minecraft:special` 未烘焙模型类型定义,是用于无等级渲染器的方块实体(例如箱子、旗帜等)的新系统。这些模型不存储烘焙模型,而是提供一个要调用的渲染方法。特殊模型包装器接受一个用于获取基本模型设置(不是元素)的基础模型和一个 `SpecialModelRenderer`。所有特殊模型渲染器都可以在 `net.minecraft.client.renderer.special.*` 中找到,并在 `SpecialModelRenderers` 中注册。
|
||
|
||
```json5
|
||
// 对于某个物品 'examplemod:example_item'
|
||
// JSON 位于 'assets/examplemod/items/example_item.json'
|
||
{
|
||
"model": {
|
||
"type": "minecraft:special",
|
||
|
||
// 从中读取粒子纹理和显示变换的模型
|
||
"base": "minecraft:item/template_skull",
|
||
"model": {
|
||
// 要使用的特殊模型渲染器
|
||
"type": "minecraft:head",
|
||
|
||
// ~~ 由 `SkullSpecialRenderer.Unbaked` 定义的属性 ~~
|
||
// 骷髅头的类型
|
||
"kind": "wither_skeleton"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
要创建自己的 `SpecialModelRenderer`,需要同时实现渲染器和 `$Unbaked` 模型,以便从 JSON 读取数据。`$Unbaked` 模型通过 `bake` 创建 `SpecialModelRenderer`,并使用其 `type` 的 `MapCodec` 进行注册。然后,`SpecialModelRenderer` 通过 `extractArgument` 从堆栈中提取渲染所需的数据,并将其传递给 `render` 方法。如果不需要从堆栈中获取任何信息,可以实现 `NoDataSpecialModelRenderer`。
|
||
|
||
然后,需要将 `MapCodec` 注册到 `SpecialModelRenderers#ID_MAPPER`,但该字段默认是私有的,因此需要一些访问更改或反射。
|
||
|
||
如果您的物品是一个持有的方块,还需要将其添加到 `SpecialModelRenderers#STATIC_BLOCK_MAPPING` 中,以便在特定渲染场景下(例如在矿车中,或被末影人捡起)通过 `BlockRenderDispatcher#renderSingleBLock` 进行渲染。默认模型渲染器和特殊模型渲染器都会在此方法中被调用;允许同时渲染静态方块模型和动态特殊模型。由于此映射是不可变的,您需要替换它或挂钩到 `SpecialBlockModelRenderer` 并以某种方式添加到存储的映射中。
|
||
|
||
```java
|
||
// 特殊渲染器
|
||
public record SignSpecialRenderer(WoodType defaultType, Model model) implements SpecialModelRenderer<WoodType> {
|
||
|
||
// 渲染模型
|
||
@Override
|
||
public void render(@Nullable WoodType type, ItemDisplayContext displayContext, PoseStack pose, MultiBufferSource bufferSource, int light, int overlay, boolean hasFoil) {
|
||
VertexConsumer consumer = Sheets.getSignMaterial(type).buffer(bufferSource, this.model::renderType);
|
||
this.model.renderToBuffer(pose, consumer, light, overlay);
|
||
}
|
||
|
||
// 从堆栈中获取木材类型
|
||
@Nullable
|
||
@Override
|
||
public WoodType extractArgument(ItemStack stack) {
|
||
return (stack.getItem() instanceof BlockItem item && item.getBlock() instanceof SignBlock sign)
|
||
? sign.type() : this.defaultType;
|
||
}
|
||
|
||
// 从中读取 JSON 的模型
|
||
public static record Unbaked(WoodType defaultType) implements SpecialModelRenderer.Unbaked {
|
||
|
||
public static final MapCodec<SignSpecialRenderer.Unbaked> MAP_CODEC = RecordCodecBuilder.mapCodec(instance ->
|
||
instance.group(
|
||
WoodType.CODEC.fieldOf("default").forGetter(SignSpecialRenderer.Unbaked::defaultType)
|
||
).apply(instance, SignSpecialRenderer.Unbaked::new)
|
||
);
|
||
|
||
// 创建特殊模型渲染器,如果失败则返回 null
|
||
@Nullable
|
||
@Override
|
||
public SpecialModelRenderer<?> bake(EntityModelSet modelSet) {
|
||
return new SignSpecialRenderer(
|
||
this.defaultType,
|
||
SignRenderer.createSignModel(modelSet, defaultType, true)
|
||
)
|
||
}
|
||
|
||
@Overrides
|
||
public MapCodec<SignSpecialRenderer.Unbaked> type() {
|
||
return MAP_CODEC;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 然后,在某个暴露 SpecialModelRenderers#ID_MAPPER 的初始化位置
|
||
SpecialModelRenderers.ID_MAPPER.put(
|
||
// 注册表名称
|
||
ResourceLocation.fromNamespaceAndPath("examplemod", "sign"),
|
||
// 映射编解码器
|
||
SignSpecialRenderer.Unbaked.MAP_CODEC
|
||
);
|
||
// 假设我们也可以直接添加到 SpecialModelRenderers#STATIC_BLOCK_MAPPING
|
||
// 我们有一个方块 EXAMPLE_SIGN
|
||
SpecialModelRenderers.STATIC_BLOCK_MAPPING.put(
|
||
// 作为物品具有特殊渲染的方块
|
||
EXAMPLE_SIGN,
|
||
// 要使用的未烘焙渲染器
|
||
new SignSpecialRenderer.Unbaked(WoodType.BAMBOO)
|
||
);
|
||
```
|
||
|
||
```json5
|
||
// 对于某个物品 'examplemod:example_item'
|
||
// JSON 位于 'assets/examplemod/items/example_item.json'
|
||
{
|
||
"model": {
|
||
"type": "minecraft:special",
|
||
|
||
// 从中读取粒子纹理和显示变换的模型
|
||
"base": "minecraft:item/bamboo_sign",
|
||
"model": {
|
||
// 要使用的特殊模型渲染器
|
||
"type": "examplemod:sign",
|
||
|
||
// ~~ 由 `SignSpecialRenderer.Unbaked` 定义的属性 ~~
|
||
// 如果找不到,则使用的默认木材类型
|
||
"default": "bamboo"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 渲染物品
|
||
|
||
现在,通过 `ItemModelResolver` 和 `ItemStackRenderState` 来渲染物品。这与 `EntityRenderState` 的工作方式类似:首先,`ItemModelResolver` 设置 `ItemStackRenderState`,然后通过 `ItemStackRenderState#render` 渲染状态。
|
||
|
||
让我们从 `ItemStackRenderState` 开始。对于渲染,我们只关心以下方法:`isEmpty`、`isGui3d`、`usesBlockLight`、`transform` 和 `render`。`isEmpty` 用于确定堆栈是否应该被渲染。然后,`isGui3d`、`usesBlockLight` 和 `transform` 在其关联的上下文中用于正确定位要渲染的堆栈。最后,`render` 接受姿势堆栈、缓冲区源、打包光照和覆盖纹理,以在适当的位置渲染物品。
|
||
|
||
`ItemModelResolver` 负责设置渲染所需的 `ItemStackRenderState` 上的信息。这是通过 `updateForLiving`(用于活体实体持有的物品)、`updateForNonLiving`(用于其他类型的实体持有的物品)和 `updateforTopItem`(用于所有其他情况)完成的。`updateForItem`(前两个方法委托给它)接受渲染状态、堆栈、显示上下文、堆栈是否在左手、等级、实体和一些种子值。这将通过 `ItemStackRenderState#clear` 清除先前状态,然后通过委托给 `ItemModel#update` 来设置新状态。如果您不在渲染器上下文中(例如,方块实体、实体),则始终可以通过 `Minecraft#getItemModelResolver` 获取 `ItemModelResolver`。
|
||
|
||
```java
|
||
// 在最简单的形式中,假设您没有进行任何变换(您应该根据需要这样做)
|
||
public class ExampleRenderer {
|
||
private final ItemStackRenderState state = new ItemStackRenderState();
|
||
|
||
public void render(ItemStack stack, Level level, PoseStack pose, MultiBufferSource bufferSource) {
|
||
// 首先更新渲染状态
|
||
Minecraft.getInstance().getItemModelResolver().updateForTopItem(
|
||
// 渲染状态
|
||
this.state,
|
||
// 用于更新状态的堆栈
|
||
stack,
|
||
// 要在其中渲染的显示上下文
|
||
ItemDisplayContext.NONE,
|
||
// 是否在实体的左手中(当未知时使用 false)
|
||
false,
|
||
// 当前等级(可以为 null)
|
||
level,
|
||
// 持有实体(可以为 null)
|
||
null,
|
||
// 任意种子值
|
||
0
|
||
);
|
||
|
||
// 在此处执行任何所需的变换
|
||
|
||
// 然后渲染状态
|
||
this.state.render(
|
||
// 带有所需变换的姿势堆栈
|
||
pose,
|
||
// 缓冲区源
|
||
bufferSource,
|
||
// 打包的光照值
|
||
LightTexture.FULL_BRIGHT,
|
||
// 覆盖纹理值
|
||
OverlayTexture.NO_OVERLAY
|
||
);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 自定义物品模型定义
|
||
|
||
要制作自定义物品模型定义,我们需要查看 `ItemStackRenderState` 中的更多方法,虽然您通常不会使用它们,但了解它们很有用:`ensureCapacity` 和 `newLayer`。这两个方法负责确保有足够的 `ItemStackRenderState$LayerRenderState`,如果您碰巧同时叠加多个模型的话。实际上,每次您计划在未烘焙模型中渲染某些东西时,都应该调用 `newLayer`。如果您计划将多个东西叠加在一起渲染,那么应该在调用 `newLayer` 之前使用计划渲染的层数设置 `ensureCapacity`。
|
||
|
||
一个物品模型定义由 `ItemModel` 组成,它在功能上定义了一个“烘焙模型”及其用于序列化的 `ItemModel$Unbaked`。
|
||
|
||
未烘焙变体有两个方法:`bake`,用于创建 `ItemModel`;以及 `type`,它引用要注册到 `ItemModels#ID_MAPPER` 的 `MapCodec`,但该字段默认是私有的,因此需要一些访问更改或反射。`bake` 接受 `$BakingContext`,其中包含用于获取 `BakedModel` 的 `ModelBaker`、用于实体模型的 `EntityModelSet` 以及缺失的 `ItemModel`。
|
||
|
||
烘焙变体只有一个方法 `update`,负责在 `ItemStackRenderState` 上设置所有必要的信息。模型本身不进行任何渲染。
|
||
|
||
```java
|
||
public record RenderTypeModelWrapper(BakedModel model, RenderType type) implements ItemModel {
|
||
|
||
// 更新渲染状态
|
||
@Override
|
||
public void update(ItemStackRenderState state, ItemStack stack, ItemModelResolver resolver, ItemDisplayContext displayContext, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed) {
|
||
ItemStackRenderState.LayerRenderState layerState = state.newLayer();
|
||
if (stack.hasFoil()) {
|
||
layerState.setFoilType(ItemStackRenderState.FoilType.STANDARD);
|
||
}
|
||
layerState.setupBlockModel(this.model, this.type);
|
||
}
|
||
|
||
public static record Unbaked(ResourceLocation model, RenderType type) implements ItemModel.Unbaked {
|
||
// 为编解码器创建渲染类型映射
|
||
private static final BiMap<String, RenderType> RENDER_TYPES = Util.make(HashBiMap.create(), map -> {
|
||
map.put("translucent_item", Sheets.translucentItemSheet());
|
||
map.put("cutout_block", Sheets.cutoutBlockSheet());
|
||
});
|
||
private static final Codec<RenderType> RENDER_TYPE_CODEC = ExtraCodecs.idResolverCodec(Codec.STRING, RENDER_TYPES::get, RENDER_TYPES.inverse()::get);
|
||
|
||
// 要注册的映射编解码器
|
||
public static final MapCodec<RenderTypeModelWrapper.Unbaked> MAP_CODEC = RecordCodecBuilder.mapCodec(instance ->
|
||
instance.group(
|
||
ResourceLocation.CODEC.fieldOf("model").forGetter(RenderTypeModelWrapper.Unbaked::model),
|
||
RENDER_TYPE_CODEC.fieldOf("render_type").forGetter(RenderTypeModelWrapper.Unbaked::type)
|
||
)
|
||
.apply(instance, RenderTypeModelWrapper.Unbaked::new)
|
||
);
|
||
|
||
@Override
|
||
public void resolveDependencies(ResolvableModel.Resolver resolver) {
|
||
// 解析模型依赖项,因此传入所有已知的资源位置
|
||
resolver.resolve(this.model);
|
||
}
|
||
|
||
@Override
|
||
public ItemModel bake(ItemModel.BakingContext context) {
|
||
// 获取烘焙模型并返回
|
||
BakedModel baked = context.bake(this.model);
|
||
return new RenderTypeModelWrapper(baked, this.type);
|
||
}
|
||
|
||
@Override
|
||
public MapCodec<RenderTypeModelWrapper.Unbaked> type() {
|
||
return MAP_CODEC;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 然后,在某个暴露 ItemModels#ID_MAPPER 的初始化位置
|
||
ItemModels.ID_MAPPER.put(
|
||
// 注册表名称
|
||
ResourceLocation.fromNamespaceAndPath("examplemod", "render_type"),
|
||
// 映射编解码器
|
||
RenderTypeModelWrapper.Unbaked.MAP_CODEC
|
||
);
|
||
```
|
||
|
||
```json5
|
||
// 对于某个物品 'examplemod:example_item'
|
||
// JSON 位于 'assets/examplemod/items/example_item.json'
|
||
{
|
||
"model": {
|
||
"type": "examplemod:render_type",
|
||
// 指向 'assets/examplemod/models/item/example_item.json'
|
||
"model": "examplemod:item/example_item",
|
||
// 设置渲染时使用的渲染类型
|
||
"render_type": "cutout_block"
|
||
}
|
||
}
|
||
```
|
||
|
||
- `net.minecraft.client`
|
||
- `ClientBootstrap` - 注册支持客户端的映射;目前用于物品模型定义。
|
||
- `Minecraft`
|
||
- `getEquipmentModels` 已移除,只能在 `EntityRendererProvider$Context#getEquipmentAssets` 中直接访问
|
||
- `getItemModelResolver` - 返回用于解析当前要在 `ItemStackRenderState$LayerRenderState` 中渲染的模型的更新器。
|
||
- `KeyMapping#get` - 根据其翻译键获取按键映射。
|
||
- `net.minecraft.client.color.item`
|
||
- `Constant` - 用于对物品纹理进行染色的常量。
|
||
- `CustomModelDataSource` - 根据 `DataComponent#CUSTOM_MODEL_DATA` 数据组件中的索引获取要染色的颜色。如果未找到索引或超出范围,则使用默认颜色。
|
||
- `Dye` - 使用 `DataComponent#DYED_COLOR` 数据组件获取要染色的颜色。
|
||
- `Firework` - 使用 `DataComponent#FIRE_EXPLOSION` 数据组件获取要染色的颜色。
|
||
- `GrassColorSource` - 根据提供的温度和降水值获取要染色的颜色。
|
||
- `ItemColor` -> `ItemTintSource`,不是一对一,因为通过在模型列表中提供多个 `ItemTintSource` 来设置索引。
|
||
- `ItemColors` 类已移除,现在作为 `ItemTintSource` 进行数据生成
|
||
- `ItemTintSources` - 用于在模型中对物品纹理进行染色的源的注册表。
|
||
- `MapColor` - 使用 `DataComponent#MAP_COLOR` 数据组件获取要染色的颜色。
|
||
- `Potion` - 使用 `DataComponent#POTION_CONTENTS` 数据组件获取要染色的颜色。
|
||
- `TeamColor` - 根据持有实体的队伍颜色获取颜色。
|
||
- `net.minecraft.client.data.Main` - 客户端数据生成的入口点。
|
||
- `net.minecraft.client.particle.BreakingItemParticle` 现在接受 `ItemStackRenderState` 而不是 `ItemStack`
|
||
- `$ItemParticleProvider` - 一个抽象的粒子提供者,提供一个计算 `ItemStackRenderState` 的简单方法。
|
||
- `net.minecraft.client.renderer`
|
||
- `BlockEntityWithoutLevelRenderer` 类已移除,被 `NoDataSpecialModelRenderer` 数据生成系统取代
|
||
- `ItemInHandRenderer` 现在接受 `ItemModelResolver`
|
||
- `ItemModelShaper` 已移除,因为这些方法在 `ModelManager` 中可用
|
||
- `Sheets`
|
||
- `getBedMaterial` - 根据染料颜色获取床的材质。
|
||
- `colorToResourceMaterial` - 获取染料颜色的资源位置。
|
||
- `createBedMaterial` - 根据染料颜色或资源位置创建床的材质。
|
||
- `getShulkerBoxMaterial` - 根据染料颜色获取潜影盒的材质。
|
||
- `colorToShulkerMaterial` - 获取潜影盒的染料颜色的资源位置。
|
||
- `createShulkerMaterial` - 根据染料颜色或资源位置创建潜影盒的材质。
|
||
- `chestMaterial` - 使用给定的资源位置为箱子创建一个新的材质。
|
||
- `SpecialBlockModelRenderer` - 方块到物品变体特殊渲染器的映射。
|
||
- `net.minecraft.client.renderer.block.BlockRenderDispatcher` 现在接受一个提供的 `SpecialBlockModelRenderer` 而不是 `BlockEntityWithoutLevelRenderer`
|
||
- `net.minecraft.client.renderer.block.model`
|
||
- `BakedOverrides` 类已移除,被 `RangeSelectItemModelProperty` 数据生成系统取代
|
||
- `BlockModel` 现在接受 `TextureSlots$Data` 而不是材质映射,并且不再接受 `ItemOverride` 列表
|
||
- `MISSING_MATERIAL` 已移除,被 `minecraft:missingno` 取代
|
||
- `textureMap` -> `textureSlots`,现在是私有的,不是一对一
|
||
- `parent` 现在是私有的,不是一对一
|
||
- `parentLocation` 现在是私有的
|
||
- `hasAmbientOcclusion` -> `getAmbientOcclusion`
|
||
- `isResolved` 已移除
|
||
- `getOverrides` 已移除
|
||
- `getParent` - 返回未烘焙的父模型。
|
||
- `getTextureSlots` - 返回模型的纹理数据。
|
||
- `getElements` 现在是包私有的
|
||
- `$GuiLight` -> `UnbakedModel$GuiLight`
|
||
- `FaceBakery`
|
||
- `bakeQuad` 现在是静态的
|
||
- `calculateFacing` 现在是私有的
|
||
- `ItemModelGenerator` 现在实现 `UnbakedModel`
|
||
- `ItemOverride` 类已移除,被 `RangeSelectItemModelProperty` 数据生成系统取代
|
||
- `ItemTransforms` 现在是一个记录
|
||
- `hasTransform` 已移除
|
||
- `TextureSlots` - 一个处理模型内纹理映射的类。数据从 `$Data` 读取,并作为 `$SlotContents` 存储,直到在烘焙过程中解析为 `Material`。
|
||
- `UnbakedBlockStateModel` 现在继承 `ResolvableModel` 而不是 `UnbakedModel`
|
||
- `bake` - 将方块状态烘焙到其可选择的模型中。
|
||
- `Variant` 现在是一个记录
|
||
- `net.minecraft.client.renderer.blockentity`
|
||
- `BannerRenderer` 现在有一个接受 `EntityModelSet` 的重载构造函数
|
||
- `renderInHand` - 渲染旗帜的物品模型。
|
||
- `BedRenderer` 现在有一个接受 `EntityModelSet` 的重载构造函数
|
||
- `renderInHand` - 渲染床的物品模型。
|
||
- `BlockEntityRenderDispatcher(Font, EntityModelSet, Supplier<BlockRenderDispatcher>, Supplier<ItemRenderer>, Supplier<EntityRenderDispatcher>)` -> `BlockEntityRenderDispatcher(Font, Supplier<EntityModelSet>, BlockRenderDispatcher, ItemModelResolver, ItemRenderer, EntityRenderDispatcher)`
|
||
- `renderItem` 已移除,在其特定类中实现
|
||
- `BlockEntityRendererProvider` 现在接受 `ItemModelResolver`
|
||
- `getItemModelResolver` - 获取返回物品模型的解析器。
|
||
- `ChestRenderer#xmasTextures` - 返回是否应在箱子上渲染圣诞纹理。
|
||
- `DecoratedPotRenderer` 现在有一个接受 `EntityModelSet` 的重载构造函数
|
||
- `renderInHand` - 渲染饰纹陶罐的物品模型。
|
||
- `ShulkerBoxRenderer` 现在有一个接受 `EntityModelSet` 的重载构造函数
|
||
- `render` - 渲染潜影盒。
|
||
- `$ShulkerBoxModel#animate` 不再接受 `ShulkerBoxBlockEntity`
|
||
- `SkullblockRenderer#createSkullRenderers` -> `createModel`,不是一对一
|
||
- `net.minecraft.client.renderer.entity`
|
||
- `EntityRenderDispatcher` 现在接受一个 `IteModelResolver`、一个提供的 `EntityModelSet` 而不是实例,以及一个 `EquipmentAssetManager` 而不是 `EquipmentModelSet`
|
||
- `EntityRendererProvider$Context` 现在接受一个 `ItemModelResolver` 而不是 `ItemRenderer`,以及一个 `EquipmentAssetManager` 而不是 `EquipmentModelSet`
|
||
- `getItemRenderer` -> `getItemModelResolver`,不是一对一
|
||
- `getEquipmentModels` -> `getEquipmentAssets`
|
||
- `FishingHookRenderer` - 返回钓鱼钩的持有手臂。
|
||
- `HumanoidMobRenderer`
|
||
- `getArmPose` - 返回实体的手臂姿势。
|
||
- `extractHumanoidRenderState` 现在接受一个 `ItemModelResolver`
|
||
- `ItemEntityRenderer`
|
||
- `getSeedForItemStack` 已移除
|
||
- `renderMultipleFromCount` 现在接受 `ItemClusterRenderState`,并移除了 `ItemRenderer`、`ItemStack`、`BakedModel` 和 3d 布尔值
|
||
- `ItemRenderer` 不再实现 `ResourceManagerReloadListener`
|
||
- 构造函数现在只接受 `ItemModelResolver`
|
||
- `render` -> `renderItem`,不是一对一
|
||
- `renderBundleItem` 已移除
|
||
- `getModel`、`resolveItemModel` 已移除
|
||
- `LivingEntityRenderer#itemRenderer` -> `itemModelResolver`,不是一对一
|
||
- `OminousItemSpawnerRenderer` 现在使用 `ItemClusterRenderState`
|
||
- `SkeletonRenderer#getArmPose` -> `AbstractSkeletonRenderer#getArmPose`
|
||
- `SnowGolemRenderer` 现在使用 `SnowGolemRenderState`
|
||
- `net.minecraft.client.renderer.entity.layers`
|
||
- `CrossArmsItemLayer` 现在使用 `HoldingEntityRenderState`
|
||
- `CustomHeadLayer` 不再接受 `ItemRenderer`
|
||
- `DolphinCarryingItemLayer` 不再接受 `ItemRenderer`
|
||
- `EquipmentLayerRenderer$TrimSpriteKey` 现在接受 `ResourceKey<EquipmentAsset>`
|
||
- `textureId` - 获取纹饰的纹理 id。
|
||
- `FoxHeldItemLayer` 不再接受 `ItemRenderer`
|
||
- `ItemInHandLayer` 现在使用 `ArmedEntityRenderState`
|
||
- 构造函数不再接受 `ItemRenderer`
|
||
- `renderArmWithItem` 不再接受 `BakedModel`、`ItemStack` 或 `ItemDisplayContext`,而是接受 `ItemStackRenderState`
|
||
- `LivingEntityEmissiveLayer` 现在接受一个布尔值,确定该层是否始终可见
|
||
- `PandaHoldsItemLayer` 不再接受 `ItemRenderer`
|
||
- `PlayerItemInHandLayer` 不再接受 `ItemRenderer`
|
||
- `renderArmWithItem` 不再接受 `BakedModel`、`ItemStack` 或 `ItemDisplayContext`,而是接受 `ItemStackRenderState`
|
||
- `SnowGolemHeadLayer` 现在使用 `SnowGolemRenderState`
|
||
- `WitchItemLayer` 不再接受 `ItemRenderer`
|
||
- `net.minecraft.client.renderer.entity.player.PlayerRenderer#getArmPose` 现在是私有的
|
||
- `net.minecraft.client.renderer.entity.state`
|
||
- `ArmedEntityRenderState` - 一个用于在右手和左手持有物品的实体的渲染状态。
|
||
- `HoldingEntityRenderState` - 一个用于持有单个物品的实体的渲染状态。
|
||
- `ItemClusterRenderState` - 一个用于应多次渲染的物品的渲染状态。
|
||
- `ItemDisplayEntityRenderState#itemRenderState`、`itemModel` -> `item`,不是一对一
|
||
- `ItemEntityRenderState#itemModel`、`item` -> `ItemClusterRenderState#item`,不是一对一
|
||
- `ItemFrameRenderState#itemStack`、`itemModel` -> `item`,不是一对一
|
||
- `LivingEntityRenderState`
|
||
- `headItemModel`、`headItem` -> `headItem`,不是一对一
|
||
- 手臂和手部方法已移至 `ArmedEntityRenderState`
|
||
- `OminousItemSpawnerRenderState` -> `ItemClusterRenderState`
|
||
- `PlayerRenderState`
|
||
- `mainHandState`、`offHandState` -> `ArmedEntityRenderState` 方法
|
||
- `heldOnHead` - 表示玩家头上的物品堆栈。
|
||
- `SkeletonRenderState#isHoldingBow` - 表示骷髅是否在持弓。
|
||
- `SnowGolemRenderState` - 雪傀儡的渲染状态。
|
||
- `ThrownItemRenderState#item`、`itemModel` -> `item`,不是一对一
|
||
- `WitchRenderState#isHoldingPotion` - 女巫是否在持药水。
|
||
- `net.minecraft.client.renderer.item`
|
||
- `BlockModelWrapper` - 包含模型及其关联染色的基本模型定义。
|
||
- `BundleSelectedItemSpecialRenderer` - 用于捆绑包选择的堆栈的特殊渲染器。
|
||
- `ClampedItemPropertyFunction`、`ItemPropertyFunction` -> 根据情况和属性,使用 `.properties.numeric.*` 类
|
||
- `ClientItem` - 表示 `assets/<modid>/items` 中模型定义的基础物品。
|
||
- `CompositeModel` - 将多个模型叠加在一起。
|
||
- `ConditionalItemModel` - 根据布尔值显示不同模型的模型。
|
||
- `EmptyModel` - 不渲染任何内容的模型。
|
||
- `ItemModel` - 根据需要更新堆栈渲染状态的基础物品模型。
|
||
- `ItemModelResolver` - 更新堆栈渲染状态的解析器。
|
||
- `ItemModels` - 包含 `ClientItem` 的所有潜在物品模型。
|
||
- `ItemProperties` 类已移除
|
||
- `ItemStackRenderState` - 表示要渲染的堆栈的渲染状态。
|
||
- `MissingItemModel` - 表示缺失模型的模型。
|
||
- `RangeSelectItemModel` - 包含一定范围值的模型,应用满足阈值的关联模型。
|
||
- `SelectItemModel` - 根据提供的属性进行切换的物品模型。
|
||
- `SpecialModelWrapper` - 用于动态渲染的模型(例如箱子)的物品模型。
|
||
- `net.minecraft.client.renderer.item.properties.conditional`
|
||
- `Broken` - 如果物品只剩下一点耐久。
|
||
- `BundleHasSelectedItem` - 如果捆绑包持有选中的物品。
|
||
- `ConditionalItemModelProperties` - 包含所有潜在的条件属性类型。
|
||
- `ConditionalItemModelProperty` - 表示返回某个布尔值的属性。
|
||
- `CustomModelDataProperty` - 如果当前索引在 `DataComponents#CUSTOM_MODEL_DATA` 中被设置为 true。
|
||
- `Damaged` - 如果物品已损坏。
|
||
- `ExtendedView` - 如果显示上下文是 GUI 并且按下了 shift 键。
|
||
- `FishingRodCast` - 如果鱼竿正在使用。
|
||
- `HasComponent` - 是否具有关联的数据组件。
|
||
- `IsCarried` - 如果物品正在当前菜单中被携带。
|
||
- `IsKeybindDown` - 如果按键映射正在被按下。
|
||
- `IsSelected` - 如果物品在快捷栏中被选中。
|
||
- `IsUsingItem` - 如果物品正在被使用。
|
||
- `IsViewEntity` - 持有实体是否是当前的相机实体。
|
||
- `net.minecraft.client.renderer.item.properties.numeric`
|
||
- `BundleFullness` - 基于捆绑包内容的阈值。
|
||
- `CompassAngle` - 基于当前角度状态的阈值。
|
||
- `CompassAngleState` - 基于指南针当前朝向目标角度的阈值。
|
||
- `Cooldown` - 基于当前冷却百分比的阈值。
|
||
- `Count` - 基于堆栈数量的阈值。
|
||
- `CrossbowPull` - 基于弩被拉开的阈值。
|
||
- `CustomModelDataProperty` - 如果当前索引在 `DataComponents#CUSTOM_MODEL_DATA` 中设置了阈值。
|
||
- `Damage` - 基于剩余耐久百分比的阈值。
|
||
- `NeedleDirectionHelper` - 一个抽象类,帮助将指针指向正确的方向。
|
||
- `RangeSelectItemModelProperties` - 包含所有潜在的范围属性类型。
|
||
- `RangeSelectItemModelProperty` - 表示返回某个浮点数阈值的属性。
|
||
- `Time` - 基于当前时间的阈值。
|
||
- `UseCycle` - 基于正在使用的堆栈中归一化到某个周期模数的剩余时间的阈值。
|
||
- `UseDuration` - 基于正在使用的堆栈中剩余时间的阈值。
|
||
- `net.minecraft.client.renderer.item.properties.select`
|
||
- `Charge` - 基于弩的充能类型的情况。
|
||
- `ContextDimension` - 基于物品当前所在维度的情况。
|
||
- `ContextEntityType` - 基于持有实体类型的情况。
|
||
- `CustomModelDataProperty` - 如果当前索引在 `DataComponents#CUSTOM_MODEL_DATA` 中被设置为字符串。
|
||
- `DisplayContext` - 基于显示上下文的情况。
|
||
- `ItemBlockState` - 基于从持有方块状态属性的物品中获取属性值的情况。
|
||
- `LocalTime` - 基于简单日期格式模式的情况。
|
||
- `MainHand` - 基于持有物品的手臂的情况。
|
||
- `SelectItemModelProperties` - 包含所有潜在的选择情况属性类型。
|
||
- `SelectItemModelProperty` - 表示返回某种选择情况的属性。
|
||
- `TrimMaterialProperty` - 基于物品上纹饰材料的情况。
|
||
- `net.minecraft.client.renderer.special`
|
||
- `BannerSpecialRenderer` - 旗帜的物品渲染器。
|
||
- `BedSpecialRenderer` - 床的物品渲染器。
|
||
- `ChestSpecialRenderer` - 箱子的物品渲染器。
|
||
- `ConduitSpecialRenderer` - 潮涌核心的物品渲染器。
|
||
- `DecoratedPotSpecialRenderer` - 饰纹陶罐的物品渲染器。
|
||
- `HangingSignSpecialRenderer` - 悬挂式告示牌的物品渲染器。
|
||
- `NoDataSpecialModelRenderer` - 不需要从堆栈读取任何数据的物品渲染器。
|
||
- `ShieldSpecialRenderer` - 盾牌的物品渲染器。
|
||
- `ShulkerBoxSpecialRenderer` - 潜影盒的物品渲染器。
|
||
- `SkullSpecialRenderer` - 骷髅头的物品渲染器。
|
||
- `SpecialModelRenderer` - 表示从堆栈读取数据并渲染对象而不需要渲染状态的模型。
|
||
- `SpecialModelRenderers` - 包含所有潜在的特殊渲染器。
|
||
- `StandingSignSpecialRenderer` - 站立式告示牌的物品渲染器。
|
||
- `TridentSpecialRenderer` - 三叉戟的物品渲染器。
|
||
- `net.minecraft.client.resources.model`
|
||
- `BakedModel`
|
||
- `isCustomRenderer` 已移除,被特殊渲染器系统取代
|
||
- `overrides` 已移除,被属性渲染器系统取代
|
||
- `BlockStateModelLoader` 不再接受缺失模型
|
||
- `definitionLocationToBlockMapper` 现在是私有的
|
||
- `loadBlockStateDefinitionStack` 现在是私有的
|
||
- `loadBlockStates` - 获取方块状态的已加载模型。
|
||
- `$LoadedBlockModelDefinition` 现在是包私有的
|
||
- `$LoadedModel` 现在接受 `UnbakedBlockStateModel` 而不是 `UnbakedModel`
|
||
- `$LoadedModels`
|
||
- `forResolving` - 返回所有需要解析的模型。
|
||
- `plainModels` - 返回从模型位置到未烘焙模型的映射。
|
||
- `BuiltInModel` 类已移除
|
||
- `ClientItemInfoLoader` - 加载所有物品堆栈的所有模型。
|
||
- `EquipmentModelSet` -> `EquipmentAssetManager`
|
||
- `ItemModel` -> `net.minecraft.client.renderer.item.ItemModel`
|
||
- `MissingBlockModel#MISSING` 现在是私有的
|
||
- `ModelBaker`
|
||
- `sprites` - 返回获取精灵的获取器。
|
||
- `rootName` - 获取用于调试的模型名称。
|
||
- `ModelBakery(Map<ModelResourceLocation, UnbakedModel>, Map<ResourceLocation, UnbakedModel>, UnbakedModel)` -> `ModelBakery(EntityModelSet, Map<ModelResourceLocation, UnbakedBlockStateModel>, Map<ResourceLocation, ClientItem>, Map<ResourceLocation, UnbakedModel>, UnbakedModel)`
|
||
- `bakeModels` 现在返回一个 `$BakingResult`
|
||
- `getBakedTopLevelModels` 已移除
|
||
- `$BakingResult` - 包含所有已加载的模型。
|
||
- `$TextureGetter`
|
||
- `get` 现在接受 `ModelDebugName` 而不是 `ModelResourceLocation`
|
||
- `reportingMissingReference` - 处理当纹理未设置时如何报告。
|
||
- `bind` - 创建一个绑定到当前模型的独立获取器。
|
||
- `ModelDebugName` - 返回用于调试的模型名称。
|
||
- `ModelDiscovery`
|
||
- `registerStandardModels` 已移除
|
||
- `registerSpecialModels` - 添加系统加载的内部模型。
|
||
- `addRoot` - 添加一个可以解析的新模型。
|
||
- `getUnreferencedModels` - 返回已加载模型与已使用模型之间的差异。
|
||
- `getTopModels` 已移除
|
||
- `ModelGroupCollector$GroupKey#create` 现在接受 `UnbakedBlockStateModel` 而不是 `UnbakedModel`
|
||
- `ModelManager`
|
||
- `specialBlockModelRenderer` - 返回特殊方块模型的渲染器。
|
||
- `entityModels` - 返回实体的模型集。
|
||
- `getItemProeprties` - 根据其资源位置返回客户端物品的属性。
|
||
- `ModelResourceLocation#inventory` 已移除
|
||
- `ResolvableModel` - 基础模型,通常是未烘焙的,具有需要解析的引用。
|
||
- `SimpleBakedModel` 字段现在都是私有的
|
||
- `bakeElements` - 根据方块元素烘焙模型。
|
||
- `$Builder` 不再有一个接受 `BlockModel` 的重载
|
||
- `SpecialModels` 类已移除
|
||
- `SpriteGetter` - 用于关联材质的图集精灵的获取器。
|
||
- `UnbakedModel` 现在是一个 `ResolvableModel`
|
||
- `bake(ModelBaker, Function<Material, TextureAtlasSprite>, ModelState)` -> `bake(TextureSlots, ModelBaker, ModelState, boolean, boolean, ItemTransforms)`
|
||
- `getAmbientOcclusion`、`getTopAmbientOcclusion` - 返回是否应在物品上启用环境光遮蔽。
|
||
- `getGuiLight`、`getTopGuiLight` - 返回 GUI 内的光照面。
|
||
- `getTransforms`、`getTopTransform`、`getTopTransforms` - 返回基于显示上下文要应用的变换。
|
||
- `getTextureSlots`、`getTopTextureSlots` - 返回模型的纹理数据。
|
||
- `getParent` - 返回此模型的父模型。
|
||
- `bakeWithTopModelValues` - 烘焙模型。
|
||
- `net.minecraft.data.models.*` -> `net.minecraft.client.data.models.*`
|
||
- `net.minecraft.world.item`
|
||
- `BundleItem` 不再接受任何 `ResourceLocation`
|
||
- `openFrontModel`、`openBackModel` 已移除
|
||
- `CrossbowItem$ChargeType` - 弩正在充能的物品。
|
||
- `DyeColor#getMixedColor` - 返回最接近混合颜色的染料。
|
||
- `Item$Properties#overrideModel` 已移除
|
||
- `SpawnEggItem` 不再接受其染色颜色
|
||
- `getColor` 已移除
|
||
- `net.minecraft.world.item.alchemy.PotionContents`
|
||
- `getColor(*)` 已移除
|
||
- `getColorOr` - 获取药水的自定义颜色,如果不存在则获取默认颜色。
|
||
- `net.minecraft.world.item.component.CustomModelData` 现在接受一个浮点数、标志、字符串和颜色的列表,用于根据提供的索引在自定义模型属性中使用
|
||
- `net.minecraft.world.item.equipment`
|
||
- `ArmorMaterial` 现在接受 `ResourceKey<EquipmentAsset>` 而不是仅仅模型 id
|
||
- `EquipmentAsset` - 一个表示装备客户端信息键的标记
|
||
- `EquipmentAssets` - 所有原版装备资源。
|
||
- `EquipmentModel` -> `net.minecraft.client.resources.model.EquipmentClientInfo`
|
||
- `EquipmentModels` -> `net.minecraft.client.data.models.EquipmentAssetProvider`,不是一对一
|
||
- `Equippable` 现在接受 `ResourceKey<EquipmentAsset>` 而不是仅仅模型 id
|
||
- `$Builder#setModel` -> `setAsset`
|
||
- `net.minecraft.world.item.equipment.trim`
|
||
- `ArmorTrim#getTexture` 已移除
|
||
- `TrimMaterial` 不再接受物品模型索引,并且覆盖盔甲材料的键指向 `ResourceKey<EquipmentAsset>`
|
||
- `net.minecraft.world.level.FoliageColor`
|
||
- `getEvergreenColor` -> `FOLIAGE_EVERGREEN`
|
||
- `getBirchColor` -> `FOLIAGE_BIRCH`
|
||
- `getDefaultColor` -> `FOLIAGE_DEFAULT`
|
||
- `getMangroveColor` -> `FOLIAGE_MANGROVE`
|
||
- `net.minecraft.world.level.block.RenderShape#ENTITYBLOCK_ANIMATED` 已移除
|
||
- `net.minecraft.world.level.block.entity`
|
||
- `BannerBlockEntity#fromItem` 已移除
|
||
- `BedBlockEntitty#setColor` 已移除
|
||
- `BlockEntity#saveToItem` 已移除
|
||
- `DecoratedPotBlockEntity#setFromItem`、`getPotAsItem` 已移除
|
||
- `net.minecraft.world.level.storage.loot.functions.SetCustomModelDataFunction` 现在接受一个浮点数、标志、字符串和颜色的列表,用于根据提供的索引在自定义模型属性中使用
|
||
|
||
## 生物 替换当前物品
|
||
|
||
与工具和盔甲分别是 `DiggerItem` 和 `ArmorItem` 子类型相关的最后一个硬编码实例已被重做:`Mob#canReplaceCurrentItem`。现在,它从 `DataComponents#EQUIPPABLE` 数据组件中读取堆栈的 `EquipmentSlot`。然后,根据情况使用不同的逻辑。
|
||
|
||
对于盔甲槽位,如果盔甲附有 `EnchantmentEffectComponents#PREVENT_ARMOR_CHANGE` 效果组件,则无法更换。否则,它将首先尝试比较盔甲属性,如果相等则比较盔甲韧性。
|
||
|
||
对于武器(通过手部槽位),它将首先检查生物是否有偏好的武器类型标签。如果有,它将把物品切换到标签中的武器,前提是标签中有一个物品而另一个没有。否则,它将尝试比较攻击伤害属性。
|
||
|
||
如果所有属性都相等,则它们都将默认采用以下逻辑。首先,它会尝试选择附魔最多的物品。然后,它会尝试选择剩余耐久度最多的物品(原始值,而不是百分比)。最后,它会检查其中一个物品是否通过 `DataComponents#CUSTOM_NAME` 具有自定义名称。
|
||
|
||
> 一个小问题是,`BambooSaplingBlock` 和 `BambooStalkBLock` 仍然硬编码检查主手物品是否为 `SwordItem`,尽管这将来可能会被替换为对 `ToolMaterial#applySwordProperties` 的更改。
|
||
|
||
## 粒子,通过渲染类型渲染
|
||
|
||
粒子现在使用 `RenderType` 进行渲染,而不是自己设置缓冲区构建器。唯一的特殊情况是 `ParticleRenderType#CUSTOM`,它允许模组制作者通过 `Particle#renderCustom` 实现自己的渲染;以及 `ParticleRenderType#NO_RENDER`,它不渲染任何内容。
|
||
|
||
要创建新的 `ParticleRenderType`,可以通过传入其名称(用于日志记录)和要使用的 `RenderType` 来创建。然后,在 `Particle#getRenderType` 中返回该类型。
|
||
|
||
```java
|
||
public static final ParticleRenderType TERRAIN_SHEET_OPAQUE = new ParticleRenderType(
|
||
"TERRAIN_SHEET_OPAQUE", // 通常是可识别的内容,例如字段名称
|
||
RenderType.opaqueParticle(TextureAtlas.LOCATION_BLOCKS) // 要使用的 RenderType
|
||
);
|
||
```
|
||
|
||
- `net.minecraft.client.particle`
|
||
- `CherryParticle` -> `FallingLeavesParticle`,不是一对一,因为新类对其泛化有更大的配置
|
||
- `ItemPickupParticle` 不再接受 `RenderBuffers`
|
||
- `Particle#renderCustom` - 使用 `ParticleRenderType#CUSTOM` 渲染类型渲染粒子。
|
||
- `ParticleEngine#render(LightTexture, Camera, float)` -> `render(Camera, float, MutliBufferSource$BufferSource)`
|
||
- `ParticleRenderType` 现在是一个记录,接受名称和它使用的 `RenderType`。
|
||
|
||
## 小幅迁移
|
||
|
||
以下是有用或有趣的增加、变更和移除的列表,它们不值得在入门文档中拥有自己的章节。
|
||
|
||
### `SimpleJsonResourceReloadListener`
|
||
|
||
`SimpleJsonResourceReloadListener` 现在接受一个转换器,用于将某个键映射到资源位置。已为注册表键提供了一个抽象。这是通过 `FileToIdConverter` 完成的,它本质上持有一个前缀和扩展名,应用于某个 `ResourceLocation`。
|
||
|
||
```java
|
||
// 我们假设这是一个服务器重载监听器(意味着在 'data' 文件夹中)
|
||
public class MyLoader extends SimpleJsonResourceReloadListener<ExampleObject> {
|
||
|
||
public MyLoader() {
|
||
super(
|
||
// 用于编码/解码对象的编解码器
|
||
ExampleObject.CODEC,
|
||
// 文件转换器
|
||
// 会将文件放置在 data/<namespace>/example/object/<path>.json
|
||
FileToIdConverter.json(
|
||
// 前缀
|
||
"example/object"
|
||
)
|
||
);
|
||
}
|
||
|
||
// 下面相同
|
||
}
|
||
```
|
||
|
||
- `net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener` 现在接受一个注册表的资源键,或者一个文件到 id 的转换器,而不仅仅是一个字符串
|
||
- `scanDirectory` 现在接受一个注册表的资源键,或者一个文件到 id 的转换器,而不仅仅是一个字符串
|
||
|
||
### MetadataSectionSerializer,被 Codec 取代
|
||
|
||
`MetadataSectionSerializer` 已被移除,转而使用 `Codec` 来序列化元数据部分。因此,所有 `MetadataSectionSerializer` 都已被其 `MetadataSectionType` 取代,它包含部分的名称和该元数据部分的编解码器。
|
||
|
||
- `net.minecraft.client.renderer.texture`
|
||
- `HttpTexture` -> `SkinTextureDownloader`,不是一对一,因为新类只是一个返回要存储内容的工具
|
||
- `MissingTextureAtlasSprite`
|
||
- `getTexture` -> `generateMissingImage`,不是一对一
|
||
- `getMissingImage(int, int)` 现在是公开的
|
||
- `SpriteLoader#loadAndStitch` 现在接受 `MetadataSectionType` 的集合而不是 `MetadataSectionSerializer`
|
||
- `net.minecraft.client.resources.SkinManager` 不再接受 `TextureManager`
|
||
- `getOrLoad` 现在返回一个 `Optional<PlayerSkin>` 的 future,而不仅仅是 `PlayerSkin`
|
||
- `net.minecraft.client.resources.metadata.animation`
|
||
- `AnimationFrame` 现在是一个记录
|
||
- `AnimationMetadataSection` 现在是一个记录
|
||
- `AnimationMetadataSectionSerializer` 类已移除
|
||
- `VillagerMetaDataSection` -> `VillagerMetadataSection`
|
||
- `VillagerMetadataSectionSerializer` 类已移除
|
||
- `net.minecraft.client.resources.metadata.texture`
|
||
- `TextureMetadataSection` 现在是一个记录
|
||
- `TextureMetadataSectionSerializer` 类已移除
|
||
- `net.minecraft.server.packs.PackResources#getMetadataSection` 现在接受 `MetadataSectionType` 而不是 `MetadataSectionSerializer`
|
||
- `net.minecraft.server.packs.metadata`
|
||
- `MetadataSectionSerializer` 已移除,转而使用部分编解码器
|
||
- `MetadataSectionType` 现在是一个记录,而不是 `MetadataSectionSerializer` 的扩展
|
||
- `net.minecraft.server.packs.resources.ResourceMetadata`
|
||
- `getSection` 现在接受 `MetadataSectionType` 而不是 `MetadataSectionSerializer`
|
||
- `copySections` 现在接受 `MetadataSectionType` 的集合而不是 `MetadataSectionSerializer`
|
||
|
||
### 音乐,现在带有音量控制
|
||
|
||
背景音乐现在通过 `MusicInfo` 类处理,它还存储音量以及关联的 `Music`。
|
||
|
||
- `net.minecraft.client.Minecraft#getSituationalMusic` 现在返回 `MusicInfo` 而不是 `Music`
|
||
- `net.minecraft.client.sounds`
|
||
- `MusicInfo` - 一个记录,包含当前正在播放的 `Music` 及其音量。
|
||
- `MusicManager#startPlaying` 现在接受 `MusicInfo` 而不是 `Music`
|
||
- `SoundEngine#setVolume`、`SoundManager#setVolume` - 设置关联声音实例的音量。
|
||
- `net.minecraft.world.level.biome`
|
||
- `Biome`
|
||
- `getBackgroundMusic` 现在返回一个可选的 `SimpleWeightedRandomList` 的音乐。
|
||
- `getBackgroundMusicVolume` - 获取背景音乐的音量。
|
||
- `BiomeSpecialEffects$Builder#silenceAllBackgroundMusic`、`backgroundMusic(SimpleWeightedRandomList<Music>)` - 处理为生物群系设置背景音乐。
|
||
|
||
### 标签变更
|
||
|
||
- `minecraft:block`
|
||
- `tall_flowers` -> `bee_attractive`
|
||
- `minecraft:item`
|
||
- `tall_flowers`、`flowers` 已移除
|
||
- `trim_templates` 已移除
|
||
- `skeleton_preferred_weapons`
|
||
- `drowned_preferred_weapons`
|
||
- `piglin_preferred_weapons`
|
||
- `pillager_preferred_weapons`
|
||
- `wither_skeleton_disliked_weapons`
|
||
|
||
### 新增列表
|
||
|
||
- `com.mojang.blaze3d.platform.Window#isMinimized` - 返回应用程序窗口是否最小化。
|
||
- `com.mojang.blaze3d.vertex.VertexBuffer`
|
||
- `uploadStatic` - 通过使用带有 `STATIC_WRITE` `VertexBuffer` 的 `Tesselator` 的 `Consumer<VertexConsumer>` 立即上传提供的顶点数据。
|
||
- `drawWithRenderType` - 使用给定的 `RenderType` 将当前缓冲区绘制到屏幕。
|
||
- `com.mojang.math.MatrixUtil#isIdentity` - 检查当前 `Matrix4f` 是否为单位矩阵。
|
||
- `net.minecraft`
|
||
- `SuppressForbidden` - 一个包含某些原因的注解,通常与需要 sysout 流有关。
|
||
- `Util#maxAllowedExecutorThreads` - 返回在 1 和最大线程数之间钳制的可用处理器数量。
|
||
- `net.minecraft.client.gui.components.events.GuiEventListener#getBorderForArrowNavigation` - 返回绑定到当前方向的 `ScreenRectangle`。
|
||
- `net.minecraft.client.gui.navigation.ScreenRectangle#transformAxisAligned` - 通过使用提供的 `Matrix4f` 变换位置来创建一个新的 `ScreenRectangle`。
|
||
- `net.minecraft.client.gui.narration.NarratableEntry#getNarratables` - 返回当前对象内可叙述对象的列表。
|
||
- `net.minecraft.client.gui.screens.recipebook.RecipeCollection#EMPTY` - 一个空的配方集合。
|
||
- `net.minecraft.client.gui.screens.worldselection`
|
||
- `ExperimentsScreen$ScrollArea` - 表示当前可用实验的一个可叙述滚动区域。
|
||
- `SwitchGrid#layout` - 返回要访问的网格布局。
|
||
- `net.minecraft.client.model`
|
||
- `BannerFlagModel`、`BannerModel` - 旗帜和悬挂式旗帜的模型。
|
||
- `VillagerLikeModel#translateToArms` - 平移姿势堆栈,使当前相对位置位于实体的手臂处。
|
||
- `net.minecraft.client.model.geom.EntityModelSet#vanilla` - 创建一个包含所有原版模型的新模型集。
|
||
- `net.minecraft.client.multiplayer.PlayerInfo#setShowHat`、`showHat` - 处理在标签页覆盖层中显示玩家的帽子层。
|
||
- `net.minecraft.client.renderer.blockentity`
|
||
- `AbstractSignRenderer` - 告示牌如何作为方块实体渲染。
|
||
- `HangingSignRenderer`
|
||
- `createSignModel` - 根据木材和附着位置创建一个告示牌模型。
|
||
- `renderInHand` - 在实体手中渲染模型。
|
||
- `$AttachmentType` - 一个枚举,根据其属性表示模型附着的位置。
|
||
- `$ModelKey` - 模型的键,结合了 `WoodType` 及其 `$AttachmentType`。
|
||
- `SignRenderer`
|
||
- `renderInHand` - 在实体手中渲染模型。
|
||
- `net.minecraft.client.renderer.entity.EntityRenderer#getShadowStrength` - 返回显示阴影的原始不透明度。
|
||
- `net.minecraft.client.renderer.entity.layers.CrossedArmsItemLayer#applyTranslation` - 应用平移以在模型的手臂中渲染物品。
|
||
- `net.minecraft.client.renderer.texture`
|
||
- `ReloadableTexture` - 可以从其关联内容重新加载的纹理。
|
||
- `TextureContents` - 包含与给定纹理关联的图像和元数据。
|
||
- `TextureManager`
|
||
- `registerAndLoad` - 使用给定名称注册一个可重新加载的纹理。
|
||
- `registerForNextReload` - 通过其资源位置注册一个纹理,以便在下一次重载时加载。
|
||
- `net.minecraft.commands.SharedSuggestionProvider#MATCH_SPLITTER` - 定义一个匹配句点、下划线或正斜杠的匹配器。
|
||
- `net.minecraft.core.BlockPos$TraversalNodeStatus` - 一个标记,指示 `BlockPos` 是否应被使用、跳过或停止任何进一步的遍历。
|
||
- `net.minecraft.core.component.PatchedDataComponentMap`
|
||
- `toImmutableMap` - 返回不可变的补丁或当前映射的副本。
|
||
- `hasNonDefault` - 返回数据组件是否有自定义值而不是仅仅默认值。
|
||
- `net.minecraft.data.PackOutput$PathProvider#json` - 从资源键获取 JSON 路径。
|
||
- `net.minecraft.data.loot.BlockLootSubProvider#createMultifaceBlockDrops` - 根据挖掘的方块面掉落方块。
|
||
- `net.minecraft.data.worldgen.placement.PlacementUtils#HEIGHTMAP_NO_LEAVES` - 使用 `Heightmap$Types#MOTION_BLOCKING_NO_LEAVES` 高度图创建一个 Y 轴放置。
|
||
- `net.minecraft.network.chat.Style#getShadowColor`、`withShadowColor` - 处理组件阴影颜色的方法。
|
||
- `net.minecraft.network.protocol.game.ServerboundPlayerLoadedPacket` - 当客户端玩家加载到客户端世界时发送的数据包。
|
||
- `net.minecraft.resources.FileToIdConverter#registry` - 从注册表键获取文件转换器。
|
||
- `net.minecraft.util.ExtraCodecs`
|
||
- `idResolverCodec` - 创建一个将某个键映射到某个值的编解码器。
|
||
- `compactListCodec` - 创建一个可以是元素或元素列表的编解码器。
|
||
- `floatRange` - 创建一个必须在两个浮点值之间的编解码器。
|
||
- `$LateBoundIdMapper` - 一个在功能上类似于具有关联编解码器的注册表的映射器。
|
||
- `net.minecraft.util.profiling.jfr.JvmProfiler#onStructureGenerate` - 返回当结构尝试在世界中生成时的分析持续时间。
|
||
- `net.minecraft.util.profiling.jfr.event.StructureGenerationEvent` - 当结构正在生成时的分析器事件。
|
||
- `net.minecraft.util.profiling.jfr.stats.StructureGenStat` - 分析的结构生成的结果。
|
||
- `net.minecraft.world.entity`
|
||
- `LivingEntity`
|
||
- `resolvePlayerResponsibleForDamage` - 获取对当前实体造成伤害的玩家。
|
||
- `canBeNameTagged` - 当为 true 时,实体可以用命名牌设置名称。
|
||
- `Mob#getPreferredWeaponType` - 获取表示实体想要拾取的武器的标签。
|
||
- `net.minecraft.world.entity.ai.attributes.AttributeMap#resetBaseValue` - 将属性实例重置为其默认值。
|
||
- `net.minecraft.world.entity.monster.creaking`
|
||
- `Creaking`
|
||
- `activate`、`deactivate` - 处理嘎枝的大脑逻辑的激活。
|
||
- `setTransient`、`isHeartBound`、`setHomePos`、`getHomePos` - 处理家的位置。
|
||
- `blameSourceForDamage` - 找到对伤害负责的玩家。
|
||
- `tearDown` - 处理嘎枝被摧毁时的情况。
|
||
- `creakingDeathEffects` - 处理嘎枝的死亡。
|
||
- `playerIsStuckInYou` - 检查是否有至少四个玩家卡在嘎枝中。
|
||
- `setTearingDown`、`isTearingDown` - 处理拆除状态。
|
||
- `hasGlowingEyes`、`checkEyeBlink` - 处理眼睛状态。
|
||
- `net.minecraft.world.entity.player.Player`
|
||
- `hasClientLoaded`、`setClientLoaded` - 客户端玩家是否已加载。
|
||
- `tickClientLoadTimeout` - Tick计时器,用于在客户端玩家未加载时等待多长时间后将其踢出。
|
||
- `net.minecraft.world.item`
|
||
- `Item#shouldPrintOpWarning` - 是否应根据存储的方块实体数据和管理员权限向玩家打印警告。
|
||
- `ItemStack`
|
||
- `getCustomName` - 返回物品的自定义名称,如果不存在组件则返回 `null`。
|
||
- `immutableComponents` - 返回不可变的补丁或堆栈组件映射的副本。
|
||
- `hasNonDefault` - 返回数据组件是否有自定义值而不是仅仅默认值。
|
||
- `net.minecraft.world.item.component.CustomData`
|
||
- `parseEntityId` - 从组件中读取实体 id。
|
||
- `parseEntityType` - 从 id 中读取实体类型,并将其映射到其注册表对象。
|
||
- `net.minecraft.world.item.crafting.Ingredient#isEmpty` - 返回原料是否没有值。
|
||
- `net.minecraft.world.item.trading.Merchant#stillValid` - 检查玩家是否仍然可以访问该商人。
|
||
- `net.minecraft.world.level`
|
||
- `Level#dragonParts` - 返回作为末影龙部件的实体列表。
|
||
- `ServerExplosion#getDamageSource` - 返回爆炸的伤害来源。
|
||
- `net.minecraft.world.level.block`
|
||
- `EyeblossomBlock$Type`
|
||
- `block` - 获取当前类型的方块。
|
||
- `state` - 获取当前类型的方块状态。
|
||
- `transform` - 返回此类型的相反状态。
|
||
- `FlowerBlock#getBeeInteractionEffect` - 返回蜜蜂与花互动时获得的效果。
|
||
- `FlowerPotBlock#opposite` - 返回方块的反向状态,仅适用于花盆中的 eyeblossom。
|
||
- `MultifaceBlock#canAttachTo` - 返回此方块是否可以附着到另一个方块。
|
||
- `MultifaceSpreadeableBlock` - 一个可以自然蔓延的多面方块。
|
||
- `net.minecraft.world.level.block.entity.trialspawner`
|
||
- `TrialSpawner#overrideEntityToSpawn` - 更改要在试炼中生成的实体。
|
||
- `TrialSpawnerConfig#withSpawning` - 设置在试炼中生成的实体。
|
||
|
||
### 变更列表
|
||
|
||
- `com.mojang.blaze3d.platform.NativeImage#upload` 不再接受三个设置 `TEXTURE_2D` 的过滤模式或纹理包裹钳位的布尔值
|
||
- 这已移至 `AbstractTexture#setClamp` 和 `#setFilter`
|
||
- `net.minecraft.client.gui`
|
||
- `Gui#clear` -> `clearTitles`
|
||
- `GuiGraphics#drawWordWrap` 有一个新的重载,接受是否应对文本应用阴影
|
||
- 默认版本启用阴影而不是禁用它
|
||
- `net.minecraft.client.gui.components`
|
||
- `AbstractContainerWidget` 现在实现 `AbstractScrollArea`
|
||
- `AbstractScrollWidget` -> 根据用例使用 `AbstractScrollArea` 或 `AbstractTextAreaWidget`,不是一对一
|
||
- `AbstractSelectionList`
|
||
- `setRenderHeader` 现在被捆绑到一个带有额外整数的新构造函数中
|
||
- `getMaxScroll` -> `AbstractScrollArea#maxScrollAmount`
|
||
- `getScrollAmount` -> `AbstractScrollArea#scrollAmount`
|
||
- `scrollbarVisible` -> `AbstractScrollArea#scrollbarVisible`
|
||
- `setClampedScrollAmount`、`setScrollAmount` -> `AbstractScrollArea#setScrollAmount`
|
||
- `clampScrollAmount` -> `refreshScrollAmount`
|
||
- `updateScrollingState` -> `AbstractScrollArea#updateScrolling`
|
||
- `getScrollbarPosition`、`getDefaultScrollbarPosition` -> `scrollBarY`,不是一对一
|
||
- `AbstractWidget#clicked` -> `isMouseOver`,已经存在
|
||
- `net.minecraft.client.gui.components.toasts.TutorialToast` 现在在其构造函数中需要 `Font` 作为第一个参数
|
||
- `net.minecraft.client.gui.font.glyphs.BakedGlyph$Effect` 和 `$GlyphInstance` 现在接受文本阴影的颜色和偏移
|
||
- `net.minecraft.client.gui.screens`
|
||
- `LoadingOverlay#registerTextures` 现在接受 `TextureManager` 而不是 `Minecraft` 实例
|
||
- `TitleScreen#preloadResources` -> `registerTextures`,不是一对一
|
||
- `net.minecraft.client.gui.screens.debug.GameModeSwitcherScreen$GameModeSlot` 现在是一个静态内部类
|
||
- `net.minecraft.client.gui.screens.reporting.ChatSelectionScreen$Entry`、`$PaddingEntry` 现在是静态内部类
|
||
- `net.minecraft.client.gui.screens.worldselection.SwitchGrid$Builder#build` 不再接受 `Consumer<LayoutElement>`
|
||
- `net.minecraft.client.model`
|
||
- `DonkeyModel#createBodyLayer`、`createBabyLayer` 现在接受一个缩放因子
|
||
- `VillagerHeadModel` -> `VillagerLikeModel`
|
||
- `net.minecraft.client.model.geom.EntityModelSet` 不再是 `ResourceManagerReloadListener`
|
||
- `net.minecraft.client.multiplayer.MultiPlayerGameMode#handlePickItem` -> `handlePickItemFromBlock` 或 `handlePickItemFromEntity`,同时提供要同步的实际对象数据和一个关于是否包含被拾取对象数据的 `boolean`
|
||
- `net.minecraft.client.particle.CherryParticle` -> `FallingLeavesParticle`,不是一对一,因为新类对其泛化有更大的配置
|
||
- `net.minecraft.client.player.ClientInput#tick` 不再接受任何参数
|
||
- `net.minecraft.client.renderer`
|
||
- `CubeMap#preload` -> `registerTextures`,不是一对一
|
||
- `LevelRenderer`
|
||
- `renderLevel` 不再接受 `LightTexture`
|
||
- `onChunkLoaded` -> `onChunkReadyToRender`
|
||
- `PostChainConfig$Pass#program` -> `programId`
|
||
- `program` 现在返回具有给定 `programId` 的 `ShaderProgram`
|
||
- `ScreenEffectRenderer#renderScreenEffect` 现在接受一个 `MultiBufferSource`
|
||
- `SectionOcclusionGraph#onChunkLoaded` -> `onChunkReadyToRender`
|
||
- `Sheets#createSignMaterial`、`createHangingSignMaterial` 现在有一个接受 `ResourceLocation` 的重载
|
||
- `SkyRenderer`
|
||
- `renderSunMoonAndStars`、`renderSunriseAndSunset` 现在接受一个 `MultiBufferSource$BufferSource` 而不是 `Tesselator`
|
||
- `renderEndSky` 不再接受 `PoseStack`
|
||
- `WeatherEffectRenderer#render` 现在接受一个 `MultiBufferSource$BufferSource` 而不是 `LightTexture`
|
||
- `net.minecraft.client.renderer.blockentity`
|
||
- `BannerRenderer#createBodyLayer` -> `BannerModel#createBodyLayer`,不是一对一
|
||
- `HangingSignRenderer`
|
||
- `createHangingSignLayer` 现在接受一个 `HangingSignRenderer$AttachmentType`
|
||
- `$HangingSignModel` 现在被 `Model$Simple` 取代,尽管其字段可以从根获取
|
||
- `SkullBlockRenderer#getRenderType` 现在有一个接受 `ResourceLocation` 的重载,用于覆盖表示玩家纹理
|
||
- `net.minecraft.client.renderer.entity.AbstractHorseRenderer`、`DonkeyRenderer` 不再接受浮点缩放
|
||
- `net.minecraft.client.renderer.entity.layers.CrossedArmsItemLayer` 现在要求泛型 `M` 是 `VillagerLikeModel`
|
||
- `net.minecraft.client.renderer.entity.state.CreakingRenderState#isActive` -> `eyesGlowing`
|
||
- 原始参数仍然存在于 `Creaking` 上,但对于渲染不是必需的
|
||
- `net.minecraft.core.BlockPos#breadthFirstTraversal` 现在接受一个返回 `$TraversalNodeStatus` 的函数,而不是一个简单的谓词,以允许跳过某些位置
|
||
- `net.minecraft.core.particles.TargetColorParticleOption` -> `TrailParticleOption`,不是一对一
|
||
- `net.minecraft.data.DataProvider#savelAll` 现在有接受带有键函数的映射的重载,以获取关联的路径
|
||
- `net.minecraft.network`
|
||
- `NoOpFrameEncoder` 被 `LocalFrameEncoder` 取代,不是一对一
|
||
- `NoOpFrameDecoder` 被 `LocalFrameDecoder` 取代,不是一对一
|
||
- `MonitorFrameDecoder` 被 `MonitoredLocalFrameDecoder` 取代,不是一对一
|
||
- `net.minecraft.network.protocol.game`
|
||
- `ClientboundLevelParticlesPacket` 现在接受一个布尔值,确定粒子是否应始终渲染
|
||
- `ClientboundMoveVehiclePacket` 现在是一个记录
|
||
- `ClientboundPlayerInfoUpdatePacket$Entry` 现在接受一个布尔值,表示是否应显示帽子
|
||
- `ClientboundSetHeldSlotPacket` 现在是一个记录
|
||
- `ServerboundMoveVehiclePacket` 现在是一个记录
|
||
- `ServerboundPickItemPacket` -> `ServerboundPickItemFromBlockPacket`、`ServerboundPickItemFromEntityPacket`;不是一对一
|
||
- `net.minecraft.server.level
|
||
- `ServerLevel#sendParticles` 现在有一个接受覆盖限制距离和粒子是否应始终显示的重载
|
||
- 其他接受覆盖限制器的重载现在也接受粒子是否应始终显示的布尔值
|
||
- `ServerPlayer#doCheckFallDamage` -> `Entity#doCheckFallDamage`,现在是 final
|
||
- `net.minecraft.util`
|
||
- `ARGB#from8BitChannel` 现在是私有的,单个浮点分量可以通过 `alphaFloat`、`redFloat`、`greenFloat` 和 `blueFloat` 获得
|
||
- `SpawnUtil#trySpawnMob` 现在接受一个布尔值,当为 false 时,允许实体无论与周围区域的碰撞状态如何都可以生成
|
||
- `net.minecraft.util.profiling.jfr.callback.ProfiledDuration#finish` 现在接受一个布尔值,表示分析的事件是否成功
|
||
- `net.minecraft.util.profiling.jfr.parse.JfrStatsResults` 现在接受一个结构生成统计信息的列表
|
||
- `net.minecraft.world.effect.PoisonMobEffect`、`WitherMobEffect` 现在是公开的
|
||
- `net.minecraft.world.entity`
|
||
- `Entity`
|
||
- `setOnGroundWithMovement` 有一个重载,将水平碰撞设置为实体当前状态的任何值。
|
||
- `awardKillScore` 不再接受整数
|
||
- `makeBoundingBox()` 现在是 final
|
||
- `makeBoundingBox(Vec3)` 现在
|
||
- `onlyOpCanSetNbt` -> `EntityType#onlyOpCanSetNbt`
|
||
- `Leashable`
|
||
- `readLeashData` 现在是私有的,被一个不返回任何内容的方法取代
|
||
- `dropLeash(boolean, boolean)` -> `dropLeash()`、`removeLeash`、`onLeashRemoved`;不是一对一,因为它们都在内部调用私有的 `dropLeash`
|
||
- `LivingEntity`
|
||
- `isLookingAtMe` 不再接受 `Predicate<LivingEntity>`,并且 `DoubleSupplier` 数组现在是一个 `double` 数组
|
||
- `hasLineOfSight` 接受一个 double 而不是 `DoubleSupplier`
|
||
- `net.minecraft.world.entity.ai.behavior.AcquirePoi#create` 现在有接受 `BiPredicate<ServerLevel, BlockPos>` 用于过滤 POI 位置的重载
|
||
- `net.minecraft.world.entity.animal.Bee#attractsBees` 现在是公开的
|
||
- `net.minecraft.world.entity.monster.Shulker#getProgressAabb`、`getProgressDeltaAabb` 现在接受一个移动 `Vec3`
|
||
- `net.minecraft.world.entity.player`
|
||
- `Inventory`
|
||
- `setPickedItem` -> `addAndPickItem`
|
||
- `findSlotMatchingCraftingIngredient` 现在接受一个 `ItemStack` 进行比较
|
||
- `Player#getPermissionLevel` 现在是公开的
|
||
- `StackedContents$IngredientInfo` 现在是一个接口,像一个接受某些物品的谓词
|
||
- `net.minecraft.world.entity.projectile.FishingHook` 不再接受 `ItemStack`
|
||
- `net.minecraft.world.inventory.Slot#getNoItemIcon` 现在返回单个 `ResourceLocation` 而不是一对
|
||
- `net.minecraft.world.item`
|
||
- `Item$TooltipContext#of` 现在接受查看物品的 `Player`
|
||
- `MobBucketItem` 现在需要一个 `Mob` 实体类型
|
||
-` SpawnEggItem#spawnsEntity`、`getType` 现在接受一个 `HolderLookup$Provider`
|
||
- `net.minecraft.world.item.crafting`
|
||
- `Ingredient` 现在实现 `StackedContents$IngredientInfo<Holder<Item>>`
|
||
- `items` 现在返回一个流而不是一个列表
|
||
- `PlacementInfo#slotInfo` -> `slotsToIngredientIndex`,不是一对一
|
||
- `net.minecraft.world.level.Level#addParticle` 现在接受一个布尔值,表示粒子是否应始终显示
|
||
- `net.minecraft.world.level.block`
|
||
- `Block#getCloneItemStack` -> `state.BlockBehaviour#getCloneItemStack`,现在是 protected
|
||
- `CherryLeavesBlock` -> `ParticleLeavesBlock`
|
||
- `CreakingHeartBlock#canSummonCreaking` -> `isNaturalNight`
|
||
- `MultifaceBlock` 不再是抽象的,并且实现 `SimpleWaterloggedBlock`
|
||
- `getSpreader` -> `MultifaceSpreadeableBlock#getSpreader`
|
||
- `SculkVeinBlock` 现在是 `MultifaceSpreadeableBlock` 的一个实例
|
||
- `SnowyDirtBlock#isSnowySetting` 现在是 protected
|
||
- `net.minecraft.world.level.block.entity`
|
||
- `AbstractFurnaceBlockEntity`
|
||
- `litTime` -> `litTimeRemaining`
|
||
- `litDuration` -> `litTotalTime`
|
||
- `cookingProgress` -> `cookingTimer`
|
||
- `BeehiveBlockEntity#addOccupant` 现在接受一个 `Bee` 而不是 `Entity`
|
||
- `CreakingHeartBlockEntity#setCreakingInfo` - 设置方块实体所附着的嘎枝。
|
||
- `net.minecraft.world.level.block.state.BlockBehaviour#getCloneItemStack`、`$BlockStateBase#getCloneItemStack` 现在接受一个布尔值,表示是否有无限材料以及是否应保存当前方块数据。
|
||
- `net.minecraft.world.level.chunk.ChunkGenerator#createStructures` 现在接受 `Level` 资源键,仅用于分析
|
||
- `net.minecraft.world.level.levelgen.feature.configurations`
|
||
- `MultifaceGrowthConfiguration` 现在接受 `MultifaceSpreadableBlock` 而不是 `MultifaceBlock`
|
||
- `SimpleBlockConfiguration` 现在接受一个布尔值,表示是否安排Tick更新
|
||
- `net.minecraft.world.level.levelgen.structure.Structure#generate` 现在接受 `Structure` 持有者和 `Level` 资源键,仅用于分析
|
||
|
||
### 移除列表
|
||
|
||
- `com.mojang.blaze3d.systems.RenderSystem#overlayBlendFunc`
|
||
- `net.minecraft.client.gui.components.AbstractSelectionList`
|
||
- `clickedHeader`
|
||
- `isValidMouseClick`
|
||
- `net.minecraft.client.gui.screens.recipebook.RecipeCollection#hasSingleResultItem`
|
||
- `net.minecraft.client.model`
|
||
- `DrownedModel#getArmPose`,现在是 `ArmedEntityRenderState` 的一部分
|
||
- `FelineModel#CAT_TRANSFORMER`
|
||
- `HumanoidModel#getArmPose`,现在是 `ArmedEntityRenderState` 的一部分
|
||
- `PlayerModel#getArmPose`,现在是 `ArmedEntityRenderState` 的一部分
|
||
- `SkeletonModel#getArmPose`,现在是 `ArmedEntityRenderState` 的一部分
|
||
- `VillagerModel#BABY_TRANSFORMER`
|
||
- `net.minecraft.client.renderer.texture`
|
||
- `AbstractTexture`
|
||
- `load`
|
||
- `reset`
|
||
- `getDefaultBlur`
|
||
- `PreloadedTexture`
|
||
- `TextureManager`
|
||
- `getTexture(ResourceLocation, AbstractTexture)`
|
||
- `register(String, DynamicTexture)`
|
||
- `preload`
|
||
- `net.minecraft.server.level.TicketType#POST_TELEPORT`
|
||
- `net.minecraft.world.entity.LivingEntity#deathScore`
|
||
- `net.minecraft.world.entity.ai.navigation.FlyingPathNavigation`、`GroundPathNavigation`
|
||
- `canPassDoors`、`setCanPassDoors`
|
||
- `canOpenDoors`
|
||
- `net.minecraft.world.entity.monster.creaking.CreakingTransient`
|
||
- `net.minecraft.world.entity.player.StackedItemContents#convertIngredientContents`
|
||
- `net.minecraft.world.item`
|
||
- `CompassItem#getSpawnPosition`
|
||
- `ItemStack#clearComponents`
|
||
- `net.minecraft.world.item.crafting.PlacementInfo`
|
||
- `ingredientToContents`
|
||
- `unpackedIngredients`
|
||
- `$SlotInfo`
|
||
- `net.minecraft.world.level.block.CreakingHeartBlock$CreakingHeartState`
|
||
- `net.minecraft.world.level.block.entity.BlockEntity#onlyOpCanSetNbt`
|
||
- `net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerData#setEntityId`
|