Minecraft 1.21.2/3 -> 1.21.4 模组迁移入门文档
本文档是一个高层次、非详尽的概述,介绍如何将您的模组从 1.21.2/3 迁移到 1.21.4。本文不涉及任何特定的模组加载器,只关注原版类的变更。所有提供的名称均使用官方的 Mojang 映射。
本入门文档采用 知识共享署名 4.0 国际许可协议 授权,因此您可以自由地将其用作参考,并请留下链接以便其他读者查阅。
如果存在任何不正确或缺失的信息,请在本仓库提交 issue,或在 Neoforged Discord 服务器中 @ChampionAsh5357。
资源包变更
原版中有许多面向用户的变更为未在下面讨论,但这些变更可能与模组制作者相关。您可以在 Misode 的版本更新日志 中找到它们的列表。
客户端物品
Minecraft 已将物品应如何渲染的查找和定义移到了自己的数据生成系统中,该系统被称为客户端物品,位于 assets/<namespace>/items/<path>.json。客户端物品类似于方块状态模型定义,但将来有可能包含更多信息。目前,它只是作为一个链接器,链接到用于渲染的模型。
所有客户端物品都包含一个使用 model 字段的 ItemModel$Unbaked。每个未烘焙模型都有一个关联的类型,该类型定义了物品应如何设置渲染,或在特定情况下如何渲染。这些 type 可以在 ItemModels 中找到。本文将介绍除一种类型外的所有类型,因为该未烘焙模型类型专门用于在选择物品时的捆绑包。
物品还包含一个 properties 字段,其中包含一些与元数据相关的参数。目前,它只指定了一个布尔值,当为 false 时,使手部立即交换当前持有的物品,而不是播放手部抬起的动画。
// 对于某个物品 '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。在大多数情况下,客户端物品定义看起来像这样:
// 对于某个物品 '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 来应用。
// 对于某个物品 '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,但该字段默认是私有的,因此需要一些访问更改或反射。
// 物品源类
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
);
// 对于 '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 用于堆栈中的当前物品数量或标准化后的最大堆栈大小百分比。
// 对于某个物品 '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,但该字段默认是私有的,因此需要一些访问更改或反射。
// 范围属性类
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
);
// 对于 '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。
// 对于某个物品 '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,但该字段默认是私有的,因此需要一些访问更改或反射。
// 选择属性类
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
);
// 对于某个物品 '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 用于是否具有给定的数据组件。
// 对于某个物品 '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,但该字段默认是私有的,因此需要一些访问更改或反射。
// 谓词属性类
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
);
// 对于某个物品 '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 定义,本质上是其他模型类型的组合,用于渲染。具体来说,它设置了多个层,在渲染时将一个模型叠加在另一个模型之上。
// 对于某个物品 'examplemod:example_item'
// JSON 位于 'assets/examplemod/items/example_item.json'
{
"model": {
"type": "minecraft:composite",
// 将按照在列表中出现的顺序进行渲染
"models": [
{
// 可以是任何未烘焙模型类型
},
{
// 可以是任何未烘焙模型类型
}
]
}
}
特殊动态模型
特殊动态模型,由 minecraft:special 未烘焙模型类型定义,是用于无等级渲染器的方块实体(例如箱子、旗帜等)的新系统。这些模型不存储烘焙模型,而是提供一个要调用的渲染方法。特殊模型包装器接受一个用于获取基本模型设置(不是元素)的基础模型和一个 SpecialModelRenderer。所有特殊模型渲染器都可以在 net.minecraft.client.renderer.special.* 中找到,并在 SpecialModelRenderers 中注册。
// 对于某个物品 '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 并以某种方式添加到存储的映射中。
// 特殊渲染器
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)
);
// 对于某个物品 '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。
// 在最简单的形式中,假设您没有进行任何变换(您应该根据需要这样做)
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 上设置所有必要的信息。模型本身不进行任何渲染。
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
);
// 对于某个物品 '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.clientClientBootstrap- 注册支持客户端的映射;目前用于物品模型定义。MinecraftgetEquipmentModels已移除,只能在EntityRendererProvider$Context#getEquipmentAssets中直接访问getItemModelResolver- 返回用于解析当前要在ItemStackRenderState$LayerRenderState中渲染的模型的更新器。
KeyMapping#get- 根据其翻译键获取按键映射。
net.minecraft.client.color.itemConstant- 用于对物品纹理进行染色的常量。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.rendererBlockEntityWithoutLevelRenderer类已移除,被NoDataSpecialModelRenderer数据生成系统取代ItemInHandRenderer现在接受ItemModelResolverItemModelShaper已移除,因为这些方法在ModelManager中可用SheetsgetBedMaterial- 根据染料颜色获取床的材质。colorToResourceMaterial- 获取染料颜色的资源位置。createBedMaterial- 根据染料颜色或资源位置创建床的材质。getShulkerBoxMaterial- 根据染料颜色获取潜影盒的材质。colorToShulkerMaterial- 获取潜影盒的染料颜色的资源位置。createShulkerMaterial- 根据染料颜色或资源位置创建潜影盒的材质。chestMaterial- 使用给定的资源位置为箱子创建一个新的材质。
SpecialBlockModelRenderer- 方块到物品变体特殊渲染器的映射。
net.minecraft.client.renderer.block.BlockRenderDispatcher现在接受一个提供的SpecialBlockModelRenderer而不是BlockEntityWithoutLevelRenderernet.minecraft.client.renderer.block.modelBakedOverrides类已移除,被RangeSelectItemModelProperty数据生成系统取代BlockModel现在接受TextureSlots$Data而不是材质映射,并且不再接受ItemOverride列表MISSING_MATERIAL已移除,被minecraft:missingno取代textureMap->textureSlots,现在是私有的,不是一对一parent现在是私有的,不是一对一parentLocation现在是私有的hasAmbientOcclusion->getAmbientOcclusionisResolved已移除getOverrides已移除getParent- 返回未烘焙的父模型。getTextureSlots- 返回模型的纹理数据。getElements现在是包私有的$GuiLight->UnbakedModel$GuiLight
FaceBakerybakeQuad现在是静态的calculateFacing现在是私有的
ItemModelGenerator现在实现UnbakedModelItemOverride类已移除,被RangeSelectItemModelProperty数据生成系统取代ItemTransforms现在是一个记录hasTransform已移除
TextureSlots- 一个处理模型内纹理映射的类。数据从$Data读取,并作为$SlotContents存储,直到在烘焙过程中解析为Material。UnbakedBlockStateModel现在继承ResolvableModel而不是UnbakedModelbake- 将方块状态烘焙到其可选择的模型中。
Variant现在是一个记录
net.minecraft.client.renderer.blockentityBannerRenderer现在有一个接受EntityModelSet的重载构造函数renderInHand- 渲染旗帜的物品模型。
BedRenderer现在有一个接受EntityModelSet的重载构造函数renderInHand- 渲染床的物品模型。
BlockEntityRenderDispatcher(Font, EntityModelSet, Supplier<BlockRenderDispatcher>, Supplier<ItemRenderer>, Supplier<EntityRenderDispatcher>)->BlockEntityRenderDispatcher(Font, Supplier<EntityModelSet>, BlockRenderDispatcher, ItemModelResolver, ItemRenderer, EntityRenderDispatcher)renderItem已移除,在其特定类中实现
BlockEntityRendererProvider现在接受ItemModelResolvergetItemModelResolver- 获取返回物品模型的解析器。
ChestRenderer#xmasTextures- 返回是否应在箱子上渲染圣诞纹理。DecoratedPotRenderer现在有一个接受EntityModelSet的重载构造函数renderInHand- 渲染饰纹陶罐的物品模型。
ShulkerBoxRenderer现在有一个接受EntityModelSet的重载构造函数render- 渲染潜影盒。$ShulkerBoxModel#animate不再接受ShulkerBoxBlockEntity
SkullblockRenderer#createSkullRenderers->createModel,不是一对一
net.minecraft.client.renderer.entityEntityRenderDispatcher现在接受一个IteModelResolver、一个提供的EntityModelSet而不是实例,以及一个EquipmentAssetManager而不是EquipmentModelSetEntityRendererProvider$Context现在接受一个ItemModelResolver而不是ItemRenderer,以及一个EquipmentAssetManager而不是EquipmentModelSetgetItemRenderer->getItemModelResolver,不是一对一getEquipmentModels->getEquipmentAssets
FishingHookRenderer- 返回钓鱼钩的持有手臂。HumanoidMobRenderergetArmPose- 返回实体的手臂姿势。extractHumanoidRenderState现在接受一个ItemModelResolver
ItemEntityRenderergetSeedForItemStack已移除renderMultipleFromCount现在接受ItemClusterRenderState,并移除了ItemRenderer、ItemStack、BakedModel和 3d 布尔值
ItemRenderer不再实现ResourceManagerReloadListener- 构造函数现在只接受
ItemModelResolver render->renderItem,不是一对一renderBundleItem已移除getModel、resolveItemModel已移除
- 构造函数现在只接受
LivingEntityRenderer#itemRenderer->itemModelResolver,不是一对一OminousItemSpawnerRenderer现在使用ItemClusterRenderStateSkeletonRenderer#getArmPose->AbstractSkeletonRenderer#getArmPoseSnowGolemRenderer现在使用SnowGolemRenderState
net.minecraft.client.renderer.entity.layersCrossArmsItemLayer现在使用HoldingEntityRenderStateCustomHeadLayer不再接受ItemRendererDolphinCarryingItemLayer不再接受ItemRendererEquipmentLayerRenderer$TrimSpriteKey现在接受ResourceKey<EquipmentAsset>textureId- 获取纹饰的纹理 id。
FoxHeldItemLayer不再接受ItemRendererItemInHandLayer现在使用ArmedEntityRenderState- 构造函数不再接受
ItemRenderer renderArmWithItem不再接受BakedModel、ItemStack或ItemDisplayContext,而是接受ItemStackRenderState
- 构造函数不再接受
LivingEntityEmissiveLayer现在接受一个布尔值,确定该层是否始终可见PandaHoldsItemLayer不再接受ItemRendererPlayerItemInHandLayer不再接受ItemRendererrenderArmWithItem不再接受BakedModel、ItemStack或ItemDisplayContext,而是接受ItemStackRenderState
SnowGolemHeadLayer现在使用SnowGolemRenderStateWitchItemLayer不再接受ItemRenderer
net.minecraft.client.renderer.entity.player.PlayerRenderer#getArmPose现在是私有的net.minecraft.client.renderer.entity.stateArmedEntityRenderState- 一个用于在右手和左手持有物品的实体的渲染状态。HoldingEntityRenderState- 一个用于持有单个物品的实体的渲染状态。ItemClusterRenderState- 一个用于应多次渲染的物品的渲染状态。ItemDisplayEntityRenderState#itemRenderState、itemModel->item,不是一对一ItemEntityRenderState#itemModel、item->ItemClusterRenderState#item,不是一对一ItemFrameRenderState#itemStack、itemModel->item,不是一对一LivingEntityRenderStateheadItemModel、headItem->headItem,不是一对一- 手臂和手部方法已移至
ArmedEntityRenderState
OminousItemSpawnerRenderState->ItemClusterRenderStatePlayerRenderStatemainHandState、offHandState->ArmedEntityRenderState方法heldOnHead- 表示玩家头上的物品堆栈。
SkeletonRenderState#isHoldingBow- 表示骷髅是否在持弓。SnowGolemRenderState- 雪傀儡的渲染状态。ThrownItemRenderState#item、itemModel->item,不是一对一WitchRenderState#isHoldingPotion- 女巫是否在持药水。
net.minecraft.client.renderer.itemBlockModelWrapper- 包含模型及其关联染色的基本模型定义。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.conditionalBroken- 如果物品只剩下一点耐久。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.numericBundleFullness- 基于捆绑包内容的阈值。CompassAngle- 基于当前角度状态的阈值。CompassAngleState- 基于指南针当前朝向目标角度的阈值。Cooldown- 基于当前冷却百分比的阈值。Count- 基于堆栈数量的阈值。CrossbowPull- 基于弩被拉开的阈值。CustomModelDataProperty- 如果当前索引在DataComponents#CUSTOM_MODEL_DATA中设置了阈值。Damage- 基于剩余耐久百分比的阈值。NeedleDirectionHelper- 一个抽象类,帮助将指针指向正确的方向。RangeSelectItemModelProperties- 包含所有潜在的范围属性类型。RangeSelectItemModelProperty- 表示返回某个浮点数阈值的属性。Time- 基于当前时间的阈值。UseCycle- 基于正在使用的堆栈中归一化到某个周期模数的剩余时间的阈值。UseDuration- 基于正在使用的堆栈中剩余时间的阈值。
net.minecraft.client.renderer.item.properties.selectCharge- 基于弩的充能类型的情况。ContextDimension- 基于物品当前所在维度的情况。ContextEntityType- 基于持有实体类型的情况。CustomModelDataProperty- 如果当前索引在DataComponents#CUSTOM_MODEL_DATA中被设置为字符串。DisplayContext- 基于显示上下文的情况。ItemBlockState- 基于从持有方块状态属性的物品中获取属性值的情况。LocalTime- 基于简单日期格式模式的情况。MainHand- 基于持有物品的手臂的情况。SelectItemModelProperties- 包含所有潜在的选择情况属性类型。SelectItemModelProperty- 表示返回某种选择情况的属性。TrimMaterialProperty- 基于物品上纹饰材料的情况。
net.minecraft.client.renderer.specialBannerSpecialRenderer- 旗帜的物品渲染器。BedSpecialRenderer- 床的物品渲染器。ChestSpecialRenderer- 箱子的物品渲染器。ConduitSpecialRenderer- 潮涌核心的物品渲染器。DecoratedPotSpecialRenderer- 饰纹陶罐的物品渲染器。HangingSignSpecialRenderer- 悬挂式告示牌的物品渲染器。NoDataSpecialModelRenderer- 不需要从堆栈读取任何数据的物品渲染器。ShieldSpecialRenderer- 盾牌的物品渲染器。ShulkerBoxSpecialRenderer- 潜影盒的物品渲染器。SkullSpecialRenderer- 骷髅头的物品渲染器。SpecialModelRenderer- 表示从堆栈读取数据并渲染对象而不需要渲染状态的模型。SpecialModelRenderers- 包含所有潜在的特殊渲染器。StandingSignSpecialRenderer- 站立式告示牌的物品渲染器。TridentSpecialRenderer- 三叉戟的物品渲染器。
net.minecraft.client.resources.modelBakedModelisCustomRenderer已移除,被特殊渲染器系统取代overrides已移除,被属性渲染器系统取代
BlockStateModelLoader不再接受缺失模型definitionLocationToBlockMapper现在是私有的loadBlockStateDefinitionStack现在是私有的loadBlockStates- 获取方块状态的已加载模型。$LoadedBlockModelDefinition现在是包私有的$LoadedModel现在接受UnbakedBlockStateModel而不是UnbakedModel$LoadedModelsforResolving- 返回所有需要解析的模型。plainModels- 返回从模型位置到未烘焙模型的映射。
BuiltInModel类已移除ClientItemInfoLoader- 加载所有物品堆栈的所有模型。EquipmentModelSet->EquipmentAssetManagerItemModel->net.minecraft.client.renderer.item.ItemModelMissingBlockModel#MISSING现在是私有的ModelBakersprites- 返回获取精灵的获取器。rootName- 获取用于调试的模型名称。
ModelBakery(Map<ModelResourceLocation, UnbakedModel>, Map<ResourceLocation, UnbakedModel>, UnbakedModel)->ModelBakery(EntityModelSet, Map<ModelResourceLocation, UnbakedBlockStateModel>, Map<ResourceLocation, ClientItem>, Map<ResourceLocation, UnbakedModel>, UnbakedModel)bakeModels现在返回一个$BakingResultgetBakedTopLevelModels已移除$BakingResult- 包含所有已加载的模型。$TextureGetterget现在接受ModelDebugName而不是ModelResourceLocationreportingMissingReference- 处理当纹理未设置时如何报告。bind- 创建一个绑定到当前模型的独立获取器。
ModelDebugName- 返回用于调试的模型名称。ModelDiscoveryregisterStandardModels已移除registerSpecialModels- 添加系统加载的内部模型。addRoot- 添加一个可以解析的新模型。getUnreferencedModels- 返回已加载模型与已使用模型之间的差异。getTopModels已移除
ModelGroupCollector$GroupKey#create现在接受UnbakedBlockStateModel而不是UnbakedModelModelManagerspecialBlockModelRenderer- 返回特殊方块模型的渲染器。entityModels- 返回实体的模型集。getItemProeprties- 根据其资源位置返回客户端物品的属性。
ModelResourceLocation#inventory已移除ResolvableModel- 基础模型,通常是未烘焙的,具有需要解析的引用。SimpleBakedModel字段现在都是私有的bakeElements- 根据方块元素烘焙模型。$Builder不再有一个接受BlockModel的重载
SpecialModels类已移除SpriteGetter- 用于关联材质的图集精灵的获取器。UnbakedModel现在是一个ResolvableModelbake(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.itemBundleItem不再接受任何ResourceLocationopenFrontModel、openBackModel已移除
CrossbowItem$ChargeType- 弩正在充能的物品。DyeColor#getMixedColor- 返回最接近混合颜色的染料。Item$Properties#overrideModel已移除SpawnEggItem不再接受其染色颜色getColor已移除
net.minecraft.world.item.alchemy.PotionContentsgetColor(*)已移除getColorOr- 获取药水的自定义颜色,如果不存在则获取默认颜色。
net.minecraft.world.item.component.CustomModelData现在接受一个浮点数、标志、字符串和颜色的列表,用于根据提供的索引在自定义模型属性中使用net.minecraft.world.item.equipmentArmorMaterial现在接受ResourceKey<EquipmentAsset>而不是仅仅模型 idEquipmentAsset- 一个表示装备客户端信息键的标记EquipmentAssets- 所有原版装备资源。EquipmentModel->net.minecraft.client.resources.model.EquipmentClientInfoEquipmentModels->net.minecraft.client.data.models.EquipmentAssetProvider,不是一对一Equippable现在接受ResourceKey<EquipmentAsset>而不是仅仅模型 id$Builder#setModel->setAsset
net.minecraft.world.item.equipment.trimArmorTrim#getTexture已移除TrimMaterial不再接受物品模型索引,并且覆盖盔甲材料的键指向ResourceKey<EquipmentAsset>
net.minecraft.world.level.FoliageColorgetEvergreenColor->FOLIAGE_EVERGREENgetBirchColor->FOLIAGE_BIRCHgetDefaultColor->FOLIAGE_DEFAULTgetMangroveColor->FOLIAGE_MANGROVE
net.minecraft.world.level.block.RenderShape#ENTITYBLOCK_ANIMATED已移除net.minecraft.world.level.block.entityBannerBlockEntity#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 中返回该类型。
public static final ParticleRenderType TERRAIN_SHEET_OPAQUE = new ParticleRenderType(
"TERRAIN_SHEET_OPAQUE", // 通常是可识别的内容,例如字段名称
RenderType.opaqueParticle(TextureAtlas.LOCATION_BLOCKS) // 要使用的 RenderType
);
net.minecraft.client.particleCherryParticle->FallingLeavesParticle,不是一对一,因为新类对其泛化有更大的配置ItemPickupParticle不再接受RenderBuffersParticle#renderCustom- 使用ParticleRenderType#CUSTOM渲染类型渲染粒子。ParticleEngine#render(LightTexture, Camera, float)->render(Camera, float, MutliBufferSource$BufferSource)ParticleRenderType现在是一个记录,接受名称和它使用的RenderType。
小幅迁移
以下是有用或有趣的增加、变更和移除的列表,它们不值得在入门文档中拥有自己的章节。
SimpleJsonResourceReloadListener
SimpleJsonResourceReloadListener 现在接受一个转换器,用于将某个键映射到资源位置。已为注册表键提供了一个抽象。这是通过 FileToIdConverter 完成的,它本质上持有一个前缀和扩展名,应用于某个 ResourceLocation。
// 我们假设这是一个服务器重载监听器(意味着在 '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.textureHttpTexture->SkinTextureDownloader,不是一对一,因为新类只是一个返回要存储内容的工具MissingTextureAtlasSpritegetTexture->generateMissingImage,不是一对一getMissingImage(int, int)现在是公开的
SpriteLoader#loadAndStitch现在接受MetadataSectionType的集合而不是MetadataSectionSerializer
net.minecraft.client.resources.SkinManager不再接受TextureManagergetOrLoad现在返回一个Optional<PlayerSkin>的 future,而不仅仅是PlayerSkin
net.minecraft.client.resources.metadata.animationAnimationFrame现在是一个记录AnimationMetadataSection现在是一个记录AnimationMetadataSectionSerializer类已移除VillagerMetaDataSection->VillagerMetadataSectionVillagerMetadataSectionSerializer类已移除
net.minecraft.client.resources.metadata.textureTextureMetadataSection现在是一个记录TextureMetadataSectionSerializer类已移除
net.minecraft.server.packs.PackResources#getMetadataSection现在接受MetadataSectionType而不是MetadataSectionSerializernet.minecraft.server.packs.metadataMetadataSectionSerializer已移除,转而使用部分编解码器MetadataSectionType现在是一个记录,而不是MetadataSectionSerializer的扩展
net.minecraft.server.packs.resources.ResourceMetadatagetSection现在接受MetadataSectionType而不是MetadataSectionSerializercopySections现在接受MetadataSectionType的集合而不是MetadataSectionSerializer
音乐,现在带有音量控制
背景音乐现在通过 MusicInfo 类处理,它还存储音量以及关联的 Music。
net.minecraft.client.Minecraft#getSituationalMusic现在返回MusicInfo而不是Musicnet.minecraft.client.soundsMusicInfo- 一个记录,包含当前正在播放的Music及其音量。MusicManager#startPlaying现在接受MusicInfo而不是MusicSoundEngine#setVolume、SoundManager#setVolume- 设置关联声音实例的音量。
net.minecraft.world.level.biomeBiomegetBackgroundMusic现在返回一个可选的SimpleWeightedRandomList的音乐。getBackgroundMusicVolume- 获取背景音乐的音量。
BiomeSpecialEffects$Builder#silenceAllBackgroundMusic、backgroundMusic(SimpleWeightedRandomList<Music>)- 处理为生物群系设置背景音乐。
标签变更
minecraft:blocktall_flowers->bee_attractive
minecraft:itemtall_flowers、flowers已移除trim_templates已移除skeleton_preferred_weaponsdrowned_preferred_weaponspiglin_preferred_weaponspillager_preferred_weaponswither_skeleton_disliked_weapons
新增列表
com.mojang.blaze3d.platform.Window#isMinimized- 返回应用程序窗口是否最小化。com.mojang.blaze3d.vertex.VertexBufferuploadStatic- 通过使用带有STATIC_WRITEVertexBuffer的Tesselator的Consumer<VertexConsumer>立即上传提供的顶点数据。drawWithRenderType- 使用给定的RenderType将当前缓冲区绘制到屏幕。
com.mojang.math.MatrixUtil#isIdentity- 检查当前Matrix4f是否为单位矩阵。net.minecraftSuppressForbidden- 一个包含某些原因的注解,通常与需要 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.worldselectionExperimentsScreen$ScrollArea- 表示当前可用实验的一个可叙述滚动区域。SwitchGrid#layout- 返回要访问的网格布局。
net.minecraft.client.modelBannerFlagModel、BannerModel- 旗帜和悬挂式旗帜的模型。VillagerLikeModel#translateToArms- 平移姿势堆栈,使当前相对位置位于实体的手臂处。
net.minecraft.client.model.geom.EntityModelSet#vanilla- 创建一个包含所有原版模型的新模型集。net.minecraft.client.multiplayer.PlayerInfo#setShowHat、showHat- 处理在标签页覆盖层中显示玩家的帽子层。net.minecraft.client.renderer.blockentityAbstractSignRenderer- 告示牌如何作为方块实体渲染。HangingSignRenderercreateSignModel- 根据木材和附着位置创建一个告示牌模型。renderInHand- 在实体手中渲染模型。$AttachmentType- 一个枚举,根据其属性表示模型附着的位置。$ModelKey- 模型的键,结合了WoodType及其$AttachmentType。
SignRendererrenderInHand- 在实体手中渲染模型。
net.minecraft.client.renderer.entity.EntityRenderer#getShadowStrength- 返回显示阴影的原始不透明度。net.minecraft.client.renderer.entity.layers.CrossedArmsItemLayer#applyTranslation- 应用平移以在模型的手臂中渲染物品。net.minecraft.client.renderer.textureReloadableTexture- 可以从其关联内容重新加载的纹理。TextureContents- 包含与给定纹理关联的图像和元数据。TextureManagerregisterAndLoad- 使用给定名称注册一个可重新加载的纹理。registerForNextReload- 通过其资源位置注册一个纹理,以便在下一次重载时加载。
net.minecraft.commands.SharedSuggestionProvider#MATCH_SPLITTER- 定义一个匹配句点、下划线或正斜杠的匹配器。net.minecraft.core.BlockPos$TraversalNodeStatus- 一个标记,指示BlockPos是否应被使用、跳过或停止任何进一步的遍历。net.minecraft.core.component.PatchedDataComponentMaptoImmutableMap- 返回不可变的补丁或当前映射的副本。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.ExtraCodecsidResolverCodec- 创建一个将某个键映射到某个值的编解码器。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.entityLivingEntityresolvePlayerResponsibleForDamage- 获取对当前实体造成伤害的玩家。canBeNameTagged- 当为 true 时,实体可以用命名牌设置名称。
Mob#getPreferredWeaponType- 获取表示实体想要拾取的武器的标签。
net.minecraft.world.entity.ai.attributes.AttributeMap#resetBaseValue- 将属性实例重置为其默认值。net.minecraft.world.entity.monster.creakingCreakingactivate、deactivate- 处理嘎枝的大脑逻辑的激活。setTransient、isHeartBound、setHomePos、getHomePos- 处理家的位置。blameSourceForDamage- 找到对伤害负责的玩家。tearDown- 处理嘎枝被摧毁时的情况。creakingDeathEffects- 处理嘎枝的死亡。playerIsStuckInYou- 检查是否有至少四个玩家卡在嘎枝中。setTearingDown、isTearingDown- 处理拆除状态。hasGlowingEyes、checkEyeBlink- 处理眼睛状态。
net.minecraft.world.entity.player.PlayerhasClientLoaded、setClientLoaded- 客户端玩家是否已加载。tickClientLoadTimeout- Tick计时器,用于在客户端玩家未加载时等待多长时间后将其踢出。
net.minecraft.world.itemItem#shouldPrintOpWarning- 是否应根据存储的方块实体数据和管理员权限向玩家打印警告。ItemStackgetCustomName- 返回物品的自定义名称,如果不存在组件则返回null。immutableComponents- 返回不可变的补丁或堆栈组件映射的副本。hasNonDefault- 返回数据组件是否有自定义值而不是仅仅默认值。
net.minecraft.world.item.component.CustomDataparseEntityId- 从组件中读取实体 id。parseEntityType- 从 id 中读取实体类型,并将其映射到其注册表对象。
net.minecraft.world.item.crafting.Ingredient#isEmpty- 返回原料是否没有值。net.minecraft.world.item.trading.Merchant#stillValid- 检查玩家是否仍然可以访问该商人。net.minecraft.world.levelLevel#dragonParts- 返回作为末影龙部件的实体列表。ServerExplosion#getDamageSource- 返回爆炸的伤害来源。
net.minecraft.world.level.blockEyeblossomBlock$Typeblock- 获取当前类型的方块。state- 获取当前类型的方块状态。transform- 返回此类型的相反状态。
FlowerBlock#getBeeInteractionEffect- 返回蜜蜂与花互动时获得的效果。FlowerPotBlock#opposite- 返回方块的反向状态,仅适用于花盆中的 eyeblossom。MultifaceBlock#canAttachTo- 返回此方块是否可以附着到另一个方块。MultifaceSpreadeableBlock- 一个可以自然蔓延的多面方块。
net.minecraft.world.level.block.entity.trialspawnerTrialSpawner#overrideEntityToSpawn- 更改要在试炼中生成的实体。TrialSpawnerConfig#withSpawning- 设置在试炼中生成的实体。
变更列表
com.mojang.blaze3d.platform.NativeImage#upload不再接受三个设置TEXTURE_2D的过滤模式或纹理包裹钳位的布尔值- 这已移至
AbstractTexture#setClamp和#setFilter
- 这已移至
net.minecraft.client.guiGui#clear->clearTitlesGuiGraphics#drawWordWrap有一个新的重载,接受是否应对文本应用阴影- 默认版本启用阴影而不是禁用它
net.minecraft.client.gui.componentsAbstractContainerWidget现在实现AbstractScrollAreaAbstractScrollWidget-> 根据用例使用AbstractScrollArea或AbstractTextAreaWidget,不是一对一AbstractSelectionListsetRenderHeader现在被捆绑到一个带有额外整数的新构造函数中getMaxScroll->AbstractScrollArea#maxScrollAmountgetScrollAmount->AbstractScrollArea#scrollAmountscrollbarVisible->AbstractScrollArea#scrollbarVisiblesetClampedScrollAmount、setScrollAmount->AbstractScrollArea#setScrollAmountclampScrollAmount->refreshScrollAmountupdateScrollingState->AbstractScrollArea#updateScrollinggetScrollbarPosition、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.screensLoadingOverlay#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.modelDonkeyModel#createBodyLayer、createBabyLayer现在接受一个缩放因子VillagerHeadModel->VillagerLikeModel
net.minecraft.client.model.geom.EntityModelSet不再是ResourceManagerReloadListenernet.minecraft.client.multiplayer.MultiPlayerGameMode#handlePickItem->handlePickItemFromBlock或handlePickItemFromEntity,同时提供要同步的实际对象数据和一个关于是否包含被拾取对象数据的booleannet.minecraft.client.particle.CherryParticle->FallingLeavesParticle,不是一对一,因为新类对其泛化有更大的配置net.minecraft.client.player.ClientInput#tick不再接受任何参数net.minecraft.client.rendererCubeMap#preload->registerTextures,不是一对一LevelRendererrenderLevel不再接受LightTextureonChunkLoaded->onChunkReadyToRender
PostChainConfig$Pass#program->programIdprogram现在返回具有给定programId的ShaderProgram
ScreenEffectRenderer#renderScreenEffect现在接受一个MultiBufferSourceSectionOcclusionGraph#onChunkLoaded->onChunkReadyToRenderSheets#createSignMaterial、createHangingSignMaterial现在有一个接受ResourceLocation的重载SkyRendererrenderSunMoonAndStars、renderSunriseAndSunset现在接受一个MultiBufferSource$BufferSource而不是TesselatorrenderEndSky不再接受PoseStack
WeatherEffectRenderer#render现在接受一个MultiBufferSource$BufferSource而不是LightTexture
net.minecraft.client.renderer.blockentityBannerRenderer#createBodyLayer->BannerModel#createBodyLayer,不是一对一HangingSignRenderercreateHangingSignLayer现在接受一个HangingSignRenderer$AttachmentType$HangingSignModel现在被Model$Simple取代,尽管其字段可以从根获取
SkullBlockRenderer#getRenderType现在有一个接受ResourceLocation的重载,用于覆盖表示玩家纹理
net.minecraft.client.renderer.entity.AbstractHorseRenderer、DonkeyRenderer不再接受浮点缩放net.minecraft.client.renderer.entity.layers.CrossedArmsItemLayer现在要求泛型M是VillagerLikeModelnet.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.networkNoOpFrameEncoder被LocalFrameEncoder取代,不是一对一NoOpFrameDecoder被LocalFrameDecoder取代,不是一对一MonitorFrameDecoder被MonitoredLocalFrameDecoder取代,不是一对一
net.minecraft.network.protocol.gameClientboundLevelParticlesPacket现在接受一个布尔值,确定粒子是否应始终渲染ClientboundMoveVehiclePacket现在是一个记录ClientboundPlayerInfoUpdatePacket$Entry现在接受一个布尔值,表示是否应显示帽子ClientboundSetHeldSlotPacket现在是一个记录ServerboundMoveVehiclePacket现在是一个记录ServerboundPickItemPacket->ServerboundPickItemFromBlockPacket、ServerboundPickItemFromEntityPacket;不是一对一
- `net.minecraft.server.level
ServerLevel#sendParticles现在有一个接受覆盖限制距离和粒子是否应始终显示的重载- 其他接受覆盖限制器的重载现在也接受粒子是否应始终显示的布尔值
ServerPlayer#doCheckFallDamage->Entity#doCheckFallDamage,现在是 final
net.minecraft.utilARGB#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.entityEntitysetOnGroundWithMovement有一个重载,将水平碰撞设置为实体当前状态的任何值。awardKillScore不再接受整数makeBoundingBox()现在是 finalmakeBoundingBox(Vec3)现在
onlyOpCanSetNbt->EntityType#onlyOpCanSetNbt
LeashablereadLeashData现在是私有的,被一个不返回任何内容的方法取代dropLeash(boolean, boolean)->dropLeash()、removeLeash、onLeashRemoved;不是一对一,因为它们都在内部调用私有的dropLeash
LivingEntityisLookingAtMe不再接受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现在接受一个移动Vec3net.minecraft.world.entity.playerInventorysetPickedItem->addAndPickItemfindSlotMatchingCraftingIngredient现在接受一个ItemStack进行比较
Player#getPermissionLevel现在是公开的StackedContents$IngredientInfo现在是一个接口,像一个接受某些物品的谓词
net.minecraft.world.entity.projectile.FishingHook不再接受ItemStacknet.minecraft.world.inventory.Slot#getNoItemIcon现在返回单个ResourceLocation而不是一对net.minecraft.world.itemItem$TooltipContext#of现在接受查看物品的PlayerMobBucketItem现在需要一个Mob实体类型 -SpawnEggItem#spawnsEntity、getType现在接受一个HolderLookup$Provider
net.minecraft.world.item.craftingIngredient现在实现StackedContents$IngredientInfo<Holder<Item>>items现在返回一个流而不是一个列表
PlacementInfo#slotInfo->slotsToIngredientIndex,不是一对一
net.minecraft.world.level.Level#addParticle现在接受一个布尔值,表示粒子是否应始终显示net.minecraft.world.level.blockBlock#getCloneItemStack->state.BlockBehaviour#getCloneItemStack,现在是 protectedCherryLeavesBlock->ParticleLeavesBlockCreakingHeartBlock#canSummonCreaking->isNaturalNightMultifaceBlock不再是抽象的,并且实现SimpleWaterloggedBlockgetSpreader->MultifaceSpreadeableBlock#getSpreader
SculkVeinBlock现在是MultifaceSpreadeableBlock的一个实例SnowyDirtBlock#isSnowySetting现在是 protected
net.minecraft.world.level.block.entityAbstractFurnaceBlockEntitylitTime->litTimeRemaininglitDuration->litTotalTimecookingProgress->cookingTimer
BeehiveBlockEntity#addOccupant现在接受一个Bee而不是EntityCreakingHeartBlockEntity#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.configurationsMultifaceGrowthConfiguration现在接受MultifaceSpreadableBlock而不是MultifaceBlockSimpleBlockConfiguration现在接受一个布尔值,表示是否安排Tick更新
net.minecraft.world.level.levelgen.structure.Structure#generate现在接受Structure持有者和Level资源键,仅用于分析
移除列表
com.mojang.blaze3d.systems.RenderSystem#overlayBlendFuncnet.minecraft.client.gui.components.AbstractSelectionListclickedHeaderisValidMouseClick
net.minecraft.client.gui.screens.recipebook.RecipeCollection#hasSingleResultItemnet.minecraft.client.modelDrownedModel#getArmPose,现在是ArmedEntityRenderState的一部分FelineModel#CAT_TRANSFORMERHumanoidModel#getArmPose,现在是ArmedEntityRenderState的一部分PlayerModel#getArmPose,现在是ArmedEntityRenderState的一部分SkeletonModel#getArmPose,现在是ArmedEntityRenderState的一部分VillagerModel#BABY_TRANSFORMER
net.minecraft.client.renderer.textureAbstractTextureloadresetgetDefaultBlur
PreloadedTextureTextureManagergetTexture(ResourceLocation, AbstractTexture)register(String, DynamicTexture)preload
net.minecraft.server.level.TicketType#POST_TELEPORTnet.minecraft.world.entity.LivingEntity#deathScorenet.minecraft.world.entity.ai.navigation.FlyingPathNavigation、GroundPathNavigationcanPassDoors、setCanPassDoorscanOpenDoors
net.minecraft.world.entity.monster.creaking.CreakingTransientnet.minecraft.world.entity.player.StackedItemContents#convertIngredientContentsnet.minecraft.world.itemCompassItem#getSpawnPositionItemStack#clearComponents
net.minecraft.world.item.crafting.PlacementInfoingredientToContentsunpackedIngredients$SlotInfo
net.minecraft.world.level.block.CreakingHeartBlock$CreakingHeartStatenet.minecraft.world.level.block.entity.BlockEntity#onlyOpCanSetNbtnet.minecraft.world.level.block.entity.trialspawner.TrialSpawnerData#setEntityId