Minecraft 1.21.5 -> 1.21.6 模组迁移入门文档
本文档是一个高层次、非详尽的概述,介绍如何将您的模组从 1.21.5 迁移到 1.21.6。本文不涉及任何特定的模组加载器,只关注原版类的变更。所有提供的名称均使用官方的 Mojang 映射。
本入门文档采用 知识共享署名 4.0 国际许可协议 授权,因此您可以自由地将其用作参考,并请留下链接以便其他读者查阅。
如果存在任何不正确或缺失的信息,请在本仓库提交 issue,或在 Neoforged Discord 服务器中 @ChampionAsh5357。
感谢:
- @Soaryn 提供了一些
ItemStack最佳实践和拼写修复 - @earthcomputer 提供了绘制字符串时的颜色更改
资源包变更
原版中有许多面向用户的变更为未在下面讨论,但这些变更可能与模组制作者相关。您可以在 Misode 的版本更新日志 中找到它们的列表。
GUI 变更
GUI 渲染系统与之前的版本相比发生了重大变化。虽然表面上看起来有些相似,但实际的实现细节要复杂得多且迂回。本文将以高层次概述新系统,并提供一些基本示例。
准备与渲染
渲染 GUI 已分为两个阶段:“准备”和“渲染”。
准备阶段是我们通常认为的 GUI 渲染方法(例如,Gui#render、AbstractContainerScreen#renderBg 等)。这些方法现在不再实际渲染组件,而是将它们提交给 GuiRenderState 以存储在“渲染”阶段使用。GuiRenderState 存储在 GameRenderer 上,并传递给 GuiGraphics,后者使用前述方法将所需对象添加到渲染状态。
渲染阶段实际处理所有对象的渲染。这是通过 GuiRenderer 处理的,它从 GuiRenderState 读取数据,并在经过一些委托的准备和排序后,将对象渲染到屏幕上。GuiRenderer 也存储在 GameRenderer 上。
元素排序
现在,元素是如何渲染到屏幕上的?在之前的版本中,这主要基于渲染调用的顺序。然而,新系统使用两种不同的排序方法。第一种方法使用层和线性树来处理深度。第二种方法基于三个因素(按优先级顺序)使用比较器:ScreenRectangle 剪裁、RenderPipeline 顺序和 TextureSetup 的哈希码。这些都存储在通过 GuiRenderState#submitGuiElement 传递给 GuiRenderState 的 GuiElementRenderState 上。
一旦元素排序完毕,它们将从 Z 值为 0 开始渲染,每个元素比前一个元素向前渲染 0.01。
作为警告,由于元素排序顺序,某些自定义配置可能导致屏幕渲染不正确。因此,您必须理解这些方法及其分配的值在排序元素时的工作原理。
层与树
第一种排序方法处理对象渲染的 z 深度。
首先从线性树开始。顾名思义,它基本上是一个双向链接的 GuiRenderState$Node 列表。每个节点包含自己的要渲染的元素列表。使用 GuiRenderState#up 或 down 来导航节点列表,每个方法要么获取下一个节点,要么如果不存在则创建一个新节点。给定树中的节点从底部到顶部渲染,这意味着 down 将在当前节点之前渲染任何提交的元素,而 up 将在当前节点之后渲染任何提交的元素。
提交元素时,使用其 ScreenArea 自动计算元素被添加到哪个节点。ScreenArea 定义了要渲染的元素的 bounds。本质上,如果元素的边界与当前节点上的任何其他元素相交,则将在 up 方向添加一个节点。
然后是层(strata)。一个层本质上是一个线性树。层按照它们被创建的顺序渲染,这意味着调用 nextStratum 将在前一层之后渲染所有元素。如果您想将元素分组到特定层中,可以使用此功能。注意:您无法导航到之前的层。
比较器
比较器处理层中线性树内给定节点中的元素排序。
屏幕矩形剪裁
ScreenRectangle 就是允许元素绘制的区域,通过 GuiElementRenderState#scissorArea 存储。没有指定 ScreenRectangle 的元素将首先排序,然后是最小 Y、最大 Y、最小 X 和最大 X。
渲染管线
RenderPipeline 定义了用于将某些对象渲染到屏幕的管线,包括其着色器、格式、统一变量等。这通过 GuiElementRenderState#pipeline 存储。管线按照它们构建的顺序排序。这意味着,如果在同一层和剪裁矩形上,RenderPipelines#ENTITY_TRANSLUCENT 将在 RenderPipelines#GUI 之前渲染。由于这是一个依赖于类加载常量的系统,如果您想添加新元素,请确保您的模组加载器支持某种动态管线排序。
纹理哈希码
TextureSetup 定义了在渲染管线中使用的 Sampler0、Sampler1 和 Sampler2,通过 GuiElementRenderState#textureSetup 存储。没有纹理的元素将首先排序,然后是记录对象的 getSortKey。注意,目前这返回 TextureSetup 的 hashCode,由于 GpuTextureView 不实现 hashCode,而是依赖于身份对象哈希,这可能是不确定的。
GuiElementRenderState
现在我们理解了排序,我们一直在使用的 GuiElementRenderState 到底是什么?实际上,渲染到屏幕的每个对象都由一个 GuiElementRenderState 表示,从库存菜单中看到的玩家到每个单独的物品。一个 GuiElementRenderState 定义了四个方法。首先,是用于排序以及如何渲染到屏幕的常用方法(pipeline、scissorArea、textureSetup、bounds)。然后是 buildVertices,它接受 VertexConsumer 来写入顶点和 z 深度。对于 GUI,这通常调用 VertexConsumer#addVertexWith2DPose。
原版提供了三种类型的 GuiElementRenderState:BlitRenderState、ColoredRectangleRenderState、GlyphEffectRenderState 和 GlyphRenderState。ColoredRectangleRenderState 和 GlyphRenderState/GlyphEffectRenderState 分别是处理基本颜色矩形和文本字符的简单情况。BlitRenderState 覆盖所有其他情况,因为几乎所有方法最终都会写入一个 GpuTexture,然后由它消费。
GuiElementRenderState 通过 GuiRenderState$Node#submitGuiElement 添加到 GuiRenderState。GuiRenderState 使 submitBlitToCurrentLayer 和 submitGlyphToCurrentLayer 可用于添加纹理和字形。例如,这些由 GuiGraphics#*line、fill 和 blit* 方法调用。
GuiItemRenderState
GuiItemRenderState 是一个特殊情况,用于将物品渲染到屏幕。它接受物品的字符串化名称、当前姿势、其 XY 坐标及其剪裁区域。它持有的 ItemStackRenderState 定义了物品的渲染方式。当 ClientItem$Properties#oversizedInGui 为 true 时,渲染边界基于物品模型边界框计算;否则,当为 false 时,使用 16x16 的正方形。
就在“渲染”阶段之前,GuiRenderer 有效地将 GuiItemRenderState 转换为 GuiElementRenderState,更具体地说是 BlitRenderState。这是通过构造一个物品图集 GpuTexture 来完成的,物品被绘制到该纹理上,然后该纹理作为 BlitRenderState 提交。所有 GuiItemRenderState 都使用 RenderPipelines#GUI_TEXTURED_PREMULTIPLIED_ALPHA。
GuiElementRenderState 通过 GuiRenderState#submitItem 添加到 GuiRenderState。这由 GuiGraphics#render*Item* 方法调用。
GuiTextRenderState
GuiTextRenderState 是一个特殊情况,用于将文本渲染到屏幕。它接受 Font、FormattedCharSequence、当前姿势、其 XY 坐标、颜色、背景颜色、是否有阴影及其渲染边界。
就在“渲染”阶段之前,GuiRenderer 将 GuiTextRenderState 转换为 GuiElementRenderState,更具体地说是 GlyphRenderState 或 GlyphEffectRenderState,具体取决于通过 GuiTextRenderState#ensurePrepared 应渲染的内容。这执行与物品渲染状态类似的过程,其中文本被写入 GpuTexture 以供消费。任何背景首先被渲染,然后是背景效果,然后是字符,最后是前景效果。
GuiElementRenderState 通过 GuiRenderState#submitText 添加到 GuiRenderState。这由 GuiGraphics#draw*String 和 render*Tooltip 方法调用。
画中画
画中画是一个特殊情况,用于将任意对象渲染到 GpuTexture,然后传递给 BlitRenderState。画中画由两个组件组成:PictureInPictureRenderState 和 PictureInPictureRenderer。
PictureInPictureRenderState 是一个接口,可以存储一些用于将对象渲染到纹理的数据。默认情况下,它必须提供最小和最大 XY 坐标、纹理缩放、其剪裁区域及其渲染边界。您还可以选择通过 pose 指定变换矩阵。任何其他数据都可以由实现者添加。
public record ExamplePIPRenderState(boolean data, int x0, int x1, int y0, int y1, float scale, @Nullable ScreenRectangle scissorArea, @Nullable ScreenRectangle bounds)
implements PictureInPictureRenderState {}
PictureInPictureRenderer 是将数据写入 GpuTexture 的渲染器。它利用这样一个事实:如果 RenderSystem#output*Override 纹理不为 null,则它们会被写入 BufferSource。一个 PictureInPictureRenderer 方法必须实现三个方法。getRenderStateClass 返回 PictureInPictureRenderState 实现的类。getTextureLabel 返回用于调试的纹理标签。renderToTexture 是调用渲染逻辑以将数据写入纹理的地方。
public class ExamplePIPRenderer extends PictureInPictureRenderer<ExamplePIPRenderState> {
// 接受来自 `RenderBuffers` 的缓冲区源
public ExamplePIPRenderer(MultiBufferSource.BufferSource bufferSource) {
super(bufferSource);
}
@Override
public Class<ExamplePIPRenderState> getRenderStateClass() {
// 渲染状态的类
return ExamplePIPRenderState.class;
}
@Override
protected void renderToTexture(ExamplePIPRenderState renderState, PoseStack pose) {
// 在此处渲染您想要的任何内容
// 您可以通过 `this.bufferSource` 使用缓冲区源
}
@Override
protected void blitTexture(ExamplePIPRenderState renderState, GuiRenderState guiState) {
// 如果您想更改图层提交到渲染状态的方式,可以覆盖此方法
// 默认情况下,这使用 `BlitRenderState`
// 如果您想自己处理提交,请删除此项
super.blitTexture(renderState, guiState);
}
@Override
protected boolean textureIsReadyToBlit(ExamplePIPRenderState renderState) {
// 当为 true 时,将跳过设置纹理和投影矩阵,并使用当前可用的任何内容
return false;
}
@Override
protected String getTextureLabel() {
// 这可以是任何内容,但应该是唯一的
return "examplemod: example pip";
}
}
要能够使用渲染器,必须将其添加到 GuiRenderer#pictureInPictureRenderers。由于构造函数接受一个不可变列表,而渲染器存储一个不可变映射,请使用您的模组加载器提供的任何方法。
// 我们将假设:
// - `GuiRenderer#bufferSource` 是可访问的
// - 映射是可变的
// 对于某个 GuiRenderer renderer
var examplePIP = new ExamplePIPRenderer(renderer.bufferSource);
renderer.pictureInPictureRenderers.put(
examplePIP.getRenderStateClass(),
examplePIP
);
PictureInPictureRenderState 通过 GuiRenderState#submitPicturesInPictureState 添加到 GuiRenderState。这由 GuiGraphics#submit*RenderState 方法调用。
逻辑变更
GuiGraphics#drawString 现在允许 int 颜色参数接受 alpha 通道(高八位),从而与其他 GuiGraphics 方法保持一致。这意味着任何没有指定 alpha 的颜色字符串将不会被渲染。可以通过将您的 int 颜色与 0xFF000000 进行 OR 操作,或者将您的颜色传递给 ARGB#opaque 来复制以前的行为。
上下文栏
屏幕上的许多 HUD 元素会占据经验条渲染的位置。然而,这些元素如何渲染以及哪个元素被优先考虑是通过上下文栏系统处理的。一个上下文栏由两部分组成:ContextualBarRenderer,负责将栏渲染到屏幕;以及 Gui$ContextualInfo,用作栏的标识符。
一个 ContextualBarRenderer 需要实现两个方法:renderBackground,用于渲染栏本身;以及 render,用于渲染出现在栏顶部的元素。
public class ExampleContextualBarRenderer implements ContextualBarRenderer {
@Override
public void renderBackground(GuiGraphics graphics, DeltaTracker delta) {
// 在此处渲染背景栏精灵
}
@Override
public void render(GuiGraphics graphics, DeltaTracker delta) {
// 渲染任何可能位于栏顶部的元素
}
}
Gui$ContextInfo 是一个枚举,因此您的模组加载器需要允许扩展或某种其他方法来标识栏渲染器。然后,需要将渲染器添加到存储在 Gui#contextualInfoBarRenderers 中的渲染器映射中。由于这是一个不可变映射,请使用您的模组加载器提供的任何方法。
// 我们将假设:
// - 创建了一个新的枚举值 `EXAMPLEMOD_EXAMPLE`
// - 映射是可变的
// 对于某个 Gui gui
gui.contextualInfoBarRenderers.put(
EXAMPLEMOD_EXAMPLE,
ExampleContextualBarRenderer::new
);
最后,为了让您的栏被调用并优先考虑,您需要修改 Gui#nextContextualInfoState 以返回您的枚举值,或者使用您的模组加载器提供的任何方法。
对话框
为了更通用地处理提供某些基本功能的屏幕——例如确认屏幕、按钮选择或用户输入,原版提供了一个通用的对话框系统。这些对话框可以在数据包中构建,并通过调用 Player#openDialog 在客户端上传递。基本的 JSON 描述记录在 Minecraft Snapshot 25w20a 中。
快速概述,一个基本的 Dialog 包含以下组件:一个标题、一个可选的用于导航的外部标题、是否可以通过按“esc”关闭屏幕,以及它的 DialogBody 内容。其他所有内容由对话框本身决定,但它具有通过 InputControl 进行用户输入的功能。按钮通常通过 ClickAction 添加,它包含常见的按钮数据和点击时要执行的事件。如果对话框被取消(例如,关闭),则运行 onCancel。
DialogBody 和 InputControl 只是没有定义结构的通用接口。实现它们,或者任何对话框,都需要在客户端和服务器上向可用类型进行一些注册。
自定义主体
一个 DialogBody 就是对话框屏幕的内容。这通常是应该始终显示的不可变信息。每个对话框都持有一个这些 DialogBody 的列表,因为每个屏幕都有一些文本来解释它的用途。它只包含一个方法 mapCodec,用作主体信息的注册表键和编码器。
// 显然,一个主体会有实际内容,但这只是一个示例实现
public record ExampleDialogBody(boolean val1, int val2) implements DialogBody {
public static final MapCodec<ExampleDialogBody> BODY_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
Codec.BOOL.fieldOf("val1").forGetter(ExampleDialogBody::val1),
Codec.INT.fieldOf("val2").forGetter(ExampleDialogBody::val2)
).apply(ExampleDialogBody::new));
@Override
public MapCodec<? extends DialogBody> mapCodec() {
return BODY_CODEC;
}
}
// 将编解码器注册到注册表
Registry.register(BuiltInRegistries.DIALOG_BODY_TYPE, "examplemod:example_body", ExampleDialogBody.BODY_CODEC);
// 对于某个对话框
{
// ...
"body": [
{
// 我们的主体
"type": "examplemod:example_body",
"val1": true,
"val2": 0
},
// ...
]
}
那么这个主体实际上是如何渲染的呢?这是通过 DialogBodyHandler 完成的。它包含一个单一方法 createControls,用于生成给定 DialogScreen 和对话框数据的 LayoutElement 进行渲染。这个主体处理程序可以通过 DialogBodyHandlers#register 链接到 MapCodec。
public class ExampleDialogBodyHandler implements DialogBodyHandler<ExampleDialogBody> {
@Override
public LayoutElement createControls(DialogScreen<?> screen, ExampleDialogBody body) {
// 创建元素(小部件、布局等)
return new StringWidget(...);
}
}
// 注意 `register` 不是公开的,因此需要访问扩宽
DialogBodyHandlers.register(BODY_CODEC, new ExampleDialogBodyHandler());
自定义输入
一个 InputControl 表示用户可以提供的某些输入,无论是文本还是按钮提交点击。这通常由可以根据状态接受或提供某些字符串值或标签的组件组成。所有对话框都可以通过 DialogControlSet 提供这些输入。它只包含一个方法 mapCodec,用作输入控件的注册表键和编码器。
public record ExampleInputControl(int value) implements InputControl {
public static final MapCodec<ExampleInputControl> INPUT_CODEC = Codec.INT.fieldOf("value").xmap(
ExampleInputControl::new, ExampleInputControl::value
);
@Override
public MapCodec<? extends InputControl> mapCodec() {
return INPUT_CODEC;
}
}
// 将编解码器注册到注册表
Registry.register(BuiltInRegistries.INPUT_CONTROL_TYPE, "examplemod:example_input", ExampleInputControl.INPUT_CODEC);
// 对于某个对话框(假设 `minecraft:simple_input_form`)
{
"inputs": [
{
// 我们的输入
"type": "examplemod:example_input",
// 此输入数据的标识符
"key": "example_input",
"value": 0
},
// ...
]
}
与上面一样,输入通过 InputControlHandler 渲染。它包含一个单一方法 addControl,提供 Screen 和输入控件,并通过 $Output 创建 LayoutElement 及其关联的 Action$ValueGetter。这个输入处理程序可以通过 InputControlHandlers#register 链接到 MapCodec。
public class ExampleInputControlHandler implements InputControlHandler<ExampleInputControl> {
@Override
public void addControl(ExampleInputControl control, Screen screen, InputControlHandler.Output output) {
EditBox box = new EditBox(...);
box.setValue(String.valueOf(control.value()));
// 将元素添加到输出
output.accept(
// 要渲染的元素
box,
// 输入的值输出
Action.ValueGetter.of(box::getValue)
);
}
}
// 注意 `register` 不是公开的,因此需要访问扩宽
InputControlHandlers.register(INPUT_CODEC, new ExampleInputControlHandler());
自定义动作
如上所示,输入可以提供一些值传递给 Action。前者被称为 $ValueGetter,它基本上获取一个字符串化或标记的输入以供使用。后者则最终创建发送到服务器的 ClickEvent。这些通常通过 ActionButton 创建,它定义了一些常见的按钮数据以及要执行的 Action。
一个自定义动作包含两个方法:一个返回在编码期间使用的 MapCodec(codec),另一个根据输入字符串到其 $ValueGetter 的映射创建 ClickEvent。
public record ExampleAction() implements Action {
public static final MapCodec<ExampleAction> ACTION_CODEC = MapCodec.unit(new ExampleAction());
@Override
public MapCodec<? extends Action> codec() {
return ACTION_CODEC;
}
@Override
public Optional<ClickEvent> createAction(Map<String, Action.ValueGetter> keysToGetters) {
// 处理如何将键输入映射映射到某个点击事件
return Optional.empty();
}
}
// 将编解码器注册到注册表
Registry.register(BuiltInRegistries.DIALOG_ACTION_TYPE, "examplemod:example_action", ExampleAction.ACTION_CODEC);
// 对于某个对话框(假设 `minecraft:notice`)
{
"action": {
// 按钮数据
"label": "示例!",
"tooltip": "这是一个示例!",
"width": 80,
// 要执行的动作
"action": {
// 我们的动作类型
"type": "examplemod:example_action"
}
}
}
根据您在下面实现 Dialog 的方式,动作按钮将自动添加到屏幕,或者您需要通过 DialogControlSet#createActionButton 在其中一个方法中添加它:
// 对于某个 DialogScreen 实现,我们假设某个 `SimpleDialog`
@Override
protected void updateHeaderAndFooter(HeaderAndFooterLayout layout, DialogControlSet controls, SimpleDialog dialog, DialogConnectionAccess access) {
dialog.mainActions().forEach(actionButton -> layout.addToFooter(controls.createActionButton(actionButton).build()));
}
自定义对话框
一个 Dialog 基本上就是上述所有组件的组合,按需组合。由用户决定如何实现它们。每个 Dialog 必须提供其 CommonDialogData,它定义了基本标题、主体内容和功能。此外,一个 Dialog 可以选择在关闭时通过 onCancel 执行一个 Action。
// `common` 已由记录实现
public record ExampleDialog(CommonDialogData common, boolean val1, int val2) implements Dialog {
public static final MapCodec<ExampleDialog> DIALOG_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
CommonDialogData.MAP_CODEC.forGetter(ExampleDialog::common),
Codec.BOOL.fieldOf("val1").forGetter(ExampleDialog::val1),
Codec.INT.fieldOf("val2").forGetter(ExampleDialog::val2)
).apply(ExampleDialog::new));
@Override
public MapCodec<? extends Dialog> codec() {
return DIALOG_CODEC;
}
@Override
public Optional<Action> onCancel() {
// 您可以选择在此处返回一些内容,或者如果什么都不做则返回空
return Optional.empty();
}
}
// 将编解码器注册到注册表
Registry.register(BuiltInRegistries.DIALOG_TYPE, "examplemod:example_dialog", ExampleDialog.DIALOG_CODEC);
// 对于 `data/examplemod/dialog/example.json` 中的某个对话框
{
// 我们的对话框类型
"type": "examplemod:example_dialog",
// 常见按钮数据
"title": "示例对话框!",
"can_close_with_escape": true,
"after_action": "wait_for_response",
// 我们的自定义参数
"val1": true,
"val2": 0
}
与其他一样,对话框类型只能通过 DialogScreen$Factory 渲染。这个接口构造一个 DialogScreen,给定父 Screen、Dialog 实例和用于与服务器通信的 DialogConnectionAccess。然后可以通过 DialogScreens#register 将这个对话框屏幕链接到 MapCodec。
public class ExampleDialogScreen extends DialogScreen<ExampleDialog> {
public ExampleDialogScreen(@Nullable Screen previousScreen, ExampleDialog dialog, DialogConnectionAccess connectionAccess) {
super(previousScreen, dialog, connectionAccess);
}
// 您可以根据需要选择实现其他方法
// 有关示例,请参阅现有的对话框屏幕
@Override
protected void populateBodyElements(LinearLayout layout, DialogControlSet controls, ExampleDialog dialog, DialogConnectionAccess access) {
// 将元素和动作添加到屏幕的主体(通常是中心)
}
@Override
protected void updateHeaderAndFooter(HeaderAndFooterLayout layout, DialogControlSet controls, ExampleDialog dialog, DialogConnectionAccess access) {
// 将元素和动作添加到屏幕的页眉和页脚(顶部和底部)
}
}
// 注意 `register` 不是公开的,因此需要访问扩宽
DialogScreens.register(DIALOG_CODEC, ExampleDialogScreen::new);
com.mojang.blaze3d.vertex.VertexConsumer#addVertexWith2DPose- 添加一个要在 2D 空间中渲染的顶点。net.minecraft.client.guiFontdrawInBatch不再返回任何内容prepareText- 准备要渲染到屏幕的文本。splitIgnoringLanguage- 按提供的顺序拆分文本,而不经过语言处理程序处理。ALPHA_CUTOFF已移除$GlyphVisitor- 一个处理要渲染的字形或效果的接口。$PreparedText- 一个接口,通过访问每个字形来定义应如何渲染一段文本。$StringRenderOutput->$PreparedTextBuilder,不再接受MultiBufferSource、Matrix4f、$DisplayMode、打包的光照坐标和逆深度布尔值
GuishouldRenderDebugCrosshair- 如果应渲染调试准星,则返回 true。$RenderFunction- 一个接口,定义如何在 GUI 上渲染某个部分或元素。
GuiGraphics现在接受一个GuiRenderState而不是MultiBufferSource$BufferSourceMAX_GUI_Z、MIN_GUI_Z已移除pose现在返回一个Matrix3x2fStackflush已移除nextStratum- 添加另一个层,用于遍历在先前树中的所有节点之后渲染。- 所有方法不再接受
RenderType、VertexConsumer或Function<ResourceLocation, RenderType>,而是根据调用指定RenderPipeline和TextureSetup drawString、drawStringWithBackdrop不再返回任何内容draw*String方法现在必须传入一个 ARGB 值,其中 A 不能为 0。renderItem(ItemStack, int, int, int, int)已移除drawSpecial已移除,根据特殊情况由单独的submit*RenderState取代blurBeforeThisStratum- 通知渲染状态,模糊效果应在该层和所有先前渲染的层之间渲染。每帧只能应用一次。render*Tooltip->set*TooltipForNextFrame,不直接添加到渲染状态,而是在不存在或被覆盖时等待调用renderDeferredTooltiprenderDeferredTooltip- 添加要在新层上渲染的工具提示信息。blitSprite现在有一个接受浮点 R 色调颜色的重载$ScissorStack#peek- 获取堆栈上的最后一个矩形。
LayeredDraw类已移除
net.minecraft.client.gui.componentsAbstractTextAreaWidget现在有一个重载,接受两个额外的布尔值,表示是否显示背景或装饰AbstractWidget#getTooltip已移除CycleButton$Builder#displayOnlyValue现在有一个接受boolean设置的重载EditBoxsetCentered- 设置文本位置是否应居中。setTextShadow- 设置文本是否应有阴影效果。
FocusableTextWidget现在可以接受一个布尔值,表示是否填充背景DEFAULT_PADDING现在是公开的
ImageWidget#updateResource- 更新组件上图像的精灵。ItemDisplayWidget- 一个显示ItemStack的小部件。LogoRenderer#keepLogoThroughFade- 当为 true 时,即使标题屏幕淡出,也保持徽标可见。MultiLineEditBox现在是包私有的,应通过builder构造,调用$Builder#set*方法setLineLimit- 设置文本字段的行限制。setValue现在有一个接受boolean的重载,用于确定是否应强制通过最大行限制
MultiLineLabelgetStyleAtCentered- 计算居中文本的组件样式。getStyleAtLeftAligned- 计算左对齐文本的组件样式。
MultilineTextField#NO_CHARACTER_LIMIT->NO_LIMITsetLineLimit- 设置文本字段上可以写入的最大行数。hasLineLimit- 返回文本字段是否有行限制。setValue现在有一个接受boolean的重载,用于确定是否应强制通过最大行限制
MultiLineTextWidget#configureStyleHandling- 设置在悬停组件时是否显示某些内容以及点击时的操作。ScrollableLayout- 一个具有某些定义边界并且可以滚动的布局。SplashRenderer#render现在接受一个浮点数作为 R 颜色,而不是 intWidgetTooltipHolder#refreshTooltipForNextRenderPass现在接受GuiGraphics和 XY 位置
net.minecraft.client.gui.components.spectator.SpectatorGui#renderTooltip->renderActionnet.minecraft.client.gui.components.tabsLoadingTab- 一个表示当前正在加载信息的标签页。Tab#getTabExtraNarration- 返回标签页的提示旁白。TabManager现在可以接受两个Consumer,用于在选中或取消选中标签页时执行的操作TabNavigationBargetTabs- 返回导航栏上的标签页列表。setTabActiveState- 设置给定标签页索引的活动状态。setTabTooltip- 设置给定标签页索引的工具提示信息。
net.minecraft.client.gui.components.toastsNowPlayingToast- 一个显示当前正在播放的背景音乐的吐司。ToastxPos、yPos- 获取相对于当前吐司索引的 x 和 y 位置。onFinishedRendering- 吐司在屏幕上完成渲染后调用的方法。
ToastManager现在接受OptionsshowNowPlayingToast、hideNowPlayingToast、createNowPlayingToast、removeNowPlayingToast- 处理“正在播放”音乐吐司。$ToastInstance#resetToast- 重置吐司。
net.minecraft.client.gui.contextualbarContextualBarRenderer- 一个接口,定义了一个具有某些要渲染的背景的对象。ExperienceBarRenderer- 绘制经验条。JumpableVehicleBarRenderer- 绘制跳跃力量条(例如,马跳跃)。LocatorBarRenderer- 绘制指向给定路径点的条。
net.minecraft.client.gui.font.GlyphRenderTypes现在接受一个用于 GUI 渲染的RenderPipelinenet.minecraft.client.gui.font.glyphs.BakedGlyph现在接受一个GpuTextureViewextractEffect- 提取一个字形效果(例如阴影)并提交要渲染的元素。extractBackground- 提取一个字形效果并提交要在背景 Z 上渲染的元素。left、top、right、bottom- 计算字形的边界。textureView- 返回构成字形的纹理视图。guiPipeline- 返回渲染字形的管线。renderChar、renderEffect现在接受一个额外的布尔值,当为 true 时将 Z 偏移设置为0,为 false 时设置为0.001$Effect#left、top、right、bottom- 计算字形效果的边界。$GlyphInstance#left、top、right、bottom- 计算字形实例的边界。
net.minecraft.client.gui.navigation.ScreenRectangletransformAxisAligned现在接受Matrix3x2f而不是Matrix4fintersects- 返回此矩形是否与另一个矩形重叠。encompasses- 返回此矩形是否完全包含另一个矩形。transformMaxBounds- 返回一个新矩形,该矩形通过提供的矩阵移动到给定位置。
net.minecraft.client.gui.renderGuiRenderer- 一个将所有提交的元素渲染到屏幕的类。TextureSetup- 一个记录,指定在渲染管线中使用的采样器 0-2。前两个纹理视图是任意的,第三个用于当前的光照图纹理。
net.minecraft.client.gui.render.pipGuiBannerResultRenderer- 旗帜结果预览的渲染器。GuiBookModelRenderer- 附魔屏幕中书模型的渲染器。GuiEntityRenderer- 给定实体的渲染器。GuiProfilerChartRenderer- 分析器图表的渲染器。GuiSignRenderer- 编辑屏幕中告示牌背景的渲染器。GuiSkinRenderer- 具有给定皮肤的玩家的渲染器。OversizedItemRenderer- 用于物品模型应渲染得比其物品槽位大时的渲染器。PictureInPictureRenderer- 一个抽象类,用于渲染非标准 2D 元素、物品或文本的动态元素。
net.minecraft.client.gui.render.stateBlitRenderState- 用于基本 2D 纹理 blit 的元素状态。ColoredRectangleRenderState- 用于带有色调的简单矩形的元素状态。GlyphEffectRenderState- 用于字形效果(例如,字体文本阴影)的元素状态。GlyphRenderState- 用于字形(字体文本)的元素状态。GuiElementRenderState- 一个表示要渲染的元素状态的接口。GuiItemRenderState- 一个表示要渲染的物品状态的记录。GuiRenderState- 要渲染到屏幕的 GUI 的状态。GuiTextRenderState- 一个表示文本及其渲染位置的记录。ScreenArea- 一个定义元素渲染区域的接口。这不会影响剪裁,而是影响层顺序。
net.minecraft.client.gui.render.state.pipGuiBannerResultRenderState- 旗帜结果预览的状态。GuiBookModelRenderState- 附魔屏幕中书模型的状态。GuiEntityRenderState- 给定实体的状态。GuiProfilerChartRenderState- 分析器图表的状态。GuiSignRenderState- 编辑屏幕中告示牌背景的状态。GuiSkinRenderState- 具有给定皮肤的玩家的状态。OversizedItemRenderState- 可以以任意大小渲染的物品模型的状态。PictureInPictureRenderState- 一个定义将画中画渲染到屏幕所需基本状态的接口。
net.minecraft.client.gui.screensConfirmScreenlayout- 定义一个由八个单位间隔的垂直元素列表。yesButton、noButton->yesButtonComponent、noButtonComponentyesButton、noButton现在表示实际的按钮
addAdditionalText- 在布局中的按钮之前添加任何附加文本。addButtons- 在布局中添加按钮。
PauseScreenrendersNowPlayingToast- 返回是否应渲染“正在播放”吐司。onDisconnect->disconnectFromWorld,现在是公开和静态的;不是一对一
ScreenCUBE_MAP->net.minecraft.client.renderer.GameRenderer#cubeMapPANORAMA->net.minecraft.client.renderer.GameRenderer#panoramarenderBlurredBackground现在接受GuiGraphics*TooltipForNextRenderPass方法要么已移除,要么移至GuiGraphicsFADE_IN_TIME- 表示某个元素淡入需要多少毫秒。fadeWidgets- 设置作为屏幕子级添加的AbstractWidget的 alpha 值。handleClickEvent- 处理点击组件时要播放的事件。defaultHandleClickEvent- 点击组件时要执行的默认逻辑。clickUrlAction- 点击 URL 时要执行的逻辑(具有打开 URL 样式)。clickCommandAction- 应执行命令时要执行的逻辑(具有 * 命令样式)。
net.minecraft.client.gui.screens.dialogButtonListDialogScreen- 一个包含一些按钮列表的对话框屏幕。DialogConnectionAccess- 一个处理来自对话框的通用交互信息的客户端接口。DialogControlSet- 对话框屏幕的输入处理程序。DialogListDialogScreen- 一个指向其他对话框的按钮列表的DialogListDialog。DialogScreen- 某个对话框模态的屏幕。DialogScreens- 对话框模态到其关联屏幕的工厂注册表。MultiButtonDialogScreen- 一个MultiActionDialog的按钮列表。ServerLinksDialogScreen- 一个ServerLinksDialog的按钮列表。SimpleDialogScreen- 某个简单对话框的对话框屏幕。WaitingForResponseScreen- 处理客户端/服务器之间对话框提交的停机时间的屏幕。
net.minecraft.client.gui.screens.dialog.bodyDialogBodyHandler- 描述标题和动作/输入之间内容的主体元素列表。DialogBodyHandlers-DialogBody到其DialogBodyHandler的注册表。
net.minecraft.client.gui.screens.dialog.inputInputControlHandler- 用户输入处理程序。InputControlHandlers-InputControl到其InputControlHandler的注册表。
net.minecraft.client.gui.screens.inventoryAbstractContainerScreenSLOT_ITEM_BLIT_OFFSET已移除renderContents- 渲染库存的槽位和标签。renderCarriedItem- 渲染持有的物品。renderSnapbackItem- 渲染与持有物品交换的物品。$SnapbackData- 保存关于拖拽或交换物品从持有位置移动到其槽位位置的信息。
AbstractSignEditScreen#offsetSign->getSignYOffset,不是一对一BookEditScreenTEXT_*、IMAGE_*、BACKGROUND_TEXTURE_*现在是公开的
BookSignScreen- 用于签署书的屏幕。BookViewScreencloseScreen->closeContainerOnServer,不是一对一$BookAccess#getPage现在返回一个Component
EffectsInInventoryrenderEffects现在是公开的renderTooltip已被重载为一个公共方法
InventoryScreen#renderEntityInInventory不再接受 XY 偏移,而是接受 4 个int来表示要渲染到的区域ItemCombinerScreen#renderFg已移除
net.minecraft.client.gui.screens.inventory.tooltipClientTooltipComponent#renderText不再接受姿势和缓冲区,而是接受GuiGraphics来提交要渲染的文本TooltipRenderUtil#renderTooltipBackground不再接受 Z 偏移
net.minecraft.client.gui.screens.multiplayer.ServerLinksScreen类已移除,被对话框模态取代net.minecraft.client.gui.screens.socialPlayerEntry#refreshHasDraftReport- 设置当前上下文是否具有针对此玩家的报告。SocialInteractionsPlayerList#refreshHasDraftReport- 刷新当前上下文是否对所有玩家有报告。
net.minecraft.client.gui.screens.worldselection.ExperimentsScreen$ScrollArea类已移除,被ScrollableLayout取代net.minecraft.client.model.geom.ModelPart#getExtentsForGui- 获取表示已变换到适当空间的部件的向量集。net.minecraft.client.multiplayer.ClientCommonPacketListenerImplshowDialog- 显示当前对话框,动态创建屏幕。serverLinks- 返回客户端可以访问的服务器链接条目。createDialogAccess- 创建用于通信的客户端对话框处理程序。clearDialog- 关闭当前对话框屏幕。
net.minecraft.client.player.LocalPlayer#experienceDisplayStartTick- 表示经验显示应被优先考虑的开始刻。net.minecraft.client.rendererGameRenderer不再接受ResourceManagerITEM_ACTIVATION_ANIMATION_LENGTH已移除setRenderHand已移除renderZoomed已移除getPanorama- 返回全景渲染器。
LightTexture#getTexture->getTextureView,不是一对一MapRenderer#WIDTH、HEIGHT现在是公开的PanoramaRenderer#registerTextures- 注册纹理以供立方体贴图使用。PostPass$Input#texture现在返回GpuTextureView而不是GpuTextureRenderPipelinesGUI_OVERLAY、GUI_GHOST_RECIPE_OVERLAY、GUI_TEXTURED_OVERLAY已移除GUI_TEXTURED_PREMULTIPLIED_ALPHA- 一个假设纹理在合成阶段已经预乘了透明度的管线。
RenderStateShard$Builder#add不再接受是否应模糊着色器$TextureStateShard不再接受设置模糊模式的TriState
RenderTypedebugLine已移除gui、guiOverlay、guiTexturedOverlay、guiOpaqueTexturedBackground、guiNauseaOverlay、guiTextHighlight、guiGhostRecipeOverlay、guiTextured已移除vignette已移除crosshair已移除mojangLogo已移除
ScreenEffectRenderer现在是一个实例实现,而不是仅仅一个静态方法- 构造函数接受当前的
Minecraft实例和一个MultiBufferSource renderScreenEffect现在是一个实例方法,接受实体是否在睡觉以及部分刻resetItemActivation、displayItemActivation- 处理物品自动激活时的情况(例如,图腾)。
- 构造函数接受当前的
net.minecraft.client.renderer.blockentity*Renderer#getExtents- 将所有模型表示的变换后的向量添加到一个集合中。HangingSignRendererMODEL_RENDER_SCALE现在是公开的translateBase现在是公开的
SignRendererRENDER_SCALE现在是公开的applyInHandTransforms- 变换堆栈以正确表示所持告示牌的位置。
SkullBlockRenderer#getRenderType(SkullBlock$Type, ResolvableProfile, ResourceLocation)->getSkullRenderType、getPlayerSkinRenderType;不是一对一
net.minecraft.client.renderer.entity.ItemRendererGUI_SLOT_CENTER_X、GUI_SLOT_CENTER_Y、ITEM_DECORATION_BLIT_OFFSET已移除COMPASS_*->SPECIAL_*
net.minecraft.client.renderer.itemClientItem$Properties#oversizedInGui- 当为 true 时,允许物品在 GUI 中渲染到 16x16 框之外;否则,将大小裁剪到框内。ItemStackRenderStatesetAnimated、isAnimated- 返回物品是否有动画(例如,闪光)。appendModelIdentityElement、getModelIdentity、clearModelIdentity- 处理正在渲染的标识组件。getModelBoundingBox- 计算模型的边界框。setOversizedInGui、isOversizedInGui- 处理物品何时可以根据其属性在 GUI 中过大。
net.minecraft.client.renderer.specialPlayerHeadSpecialRenderer- 根据其渲染信息渲染玩家头颅。SkullSpecialRenderer现在实现NoDataSpecialModelRenderer,不再接受模型或纹理覆盖,而是接受要使用的RenderTypeSpecialModelRenderer#getExtents- 将表示此渲染器使用的所有模型的变换向量添加到一个集合中。
net.minecraft.client.renderer.texture.TextureAtlasSprite#isAnimated- 返回精灵是否有任何动画。net.minecraft.commands.arguments.ResourceOrIdArgument#dialog、getDialog、$DialogArgument- 处理对话框屏幕的命令参数。net.minecraft.core.registriesBuiltInRegistries#DIALOG_TYPE、DIALOG_ACTION_TYPE、INPUT_CONTROL_TYPE、DIALOG_BODY_TYPERegistries#DIALOG_TYPE、DIALOG_ACTION_TYPE、INPUT_CONTROL_TYPE、DIALOG_BODY_TYPE、DIALOG
net.minecraft.data.tags.DialogTagsProvider- 对话框的标签提供者。net.minecraft.network.chatClientEvent$Action#SHOW_DIALOG、CUSTOMvalueCodec- 返回用于编码此动作的映射编解码器。
$Custom- 一个包含一些要发送到服务器的 nbt 有效负载的事件,目前什么都不做。$ShowDialog- 一个显示指定对话框的事件。
CommonComponentsGUI_RETURN_TO_MENU- 显示“返回菜单”文本的组件。disconnectButtonLabel- 根据服务器是否是本地服务器返回组件。
net.minecraft.network.protocol.commonClientboundClearDialogPacket- 关闭当前对话框屏幕。ClientboundShowDialogPacket- 打开一个新的对话框屏幕。ServerboundCustomClickActionPacket- 向服务器发送一个自定义动作。
net.minecraft.server.dialogActionButton- 一个可以在点击时执行某些Action的按钮。ButtonListDialog- 一个具有若干列可点击按钮的对话框模态。CommonButtonData- 与对话框模态中每个按钮关联的数据。CommonDialogData- 与每个对话框模态关联的数据。ConfirmationDialog- 一个可以选择是或否的对话框模态。Dialog- 定义某个对话框模态的基础接口。DialogAction- 通常在点击某个动作按钮后执行的动作。DialogListDialog- 一个指向其他对话框的按钮的可滚动列表。Dialogs- 一个注册Dialog的数据包引导程序。DialogTypes- 用于编码某个对话框模型的映射编解码器注册表。Input- 一个将某个键映射到InputControl的处理程序。MultiActionDialog- 一个按列排列的动作的可滚动列表。NoticeDialog- 一个在页脚中只有一个动作的简单屏幕。ServerLinksDialog- 一个从服务器接收的链接的可滚动列表,按列排列。SimpleDialog- 一个定义可以采取的主要动作的对话框。
net.minecraft.server.dialog.actionAction- 对某些输入执行的通用操作,通常是按钮点击。ActionTypes- 用于编码某个动作的映射编解码器注册表。CustomTemplate- 构建一个命令并请求服务器运行它。CustomAll- 从所有输入构建一个自定义服务器点击动作,并请求服务器运行它。ParsedTemplate- 一个编码某些字符串的模板,类似于函数宏的工作方式。StaticAction- 一个在激活时触发ClickEvent的动作。
net.minecraft.server.dialog.bodyDialogBody- 描述标题和动作/输入之间内容的主体元素。DialogBodyTypes- 用于编码某个主体的映射编解码器注册表。ItemBody- 一个带有可选描述的物品。PlainMessage- 一个多行标签。
net.minecraft.server.dialog.inputBooleanInput- 一个带有标签的普通复选框。InputControl- 一个接受用户输入的控制机制。InputControlTypes- 用于编码某个输入控件的映射编解码器注册表。NumberRangeInput- 一个用于从某个范围内选择数值的滑块。SingleOptionInput- 一个在一组选项之间循环的按钮。TextInput- 简单的文本输入。
net.minecraft.world.entity.player.Player#openDialog- 打开指定的对话框屏幕。
路径点
路径点只是一种跟踪游戏中某些对象位置的方法。底层系统由 WaypointManager 处理,负责保存它正在跟踪的路径点,同时允许根据需要更新和移除。服务器通过 ServerWaypointManager(通过 ServerLevel#getWaypointManager 获得)处理路径点,它持有一个到发射器的活动连接以接收实时更新。客户端通过 ClientWaypointManager(通过 ClientPacketListener#getWaypointManager 获得)接收这些路径点,它仅保存某些标识符以及精确位置、如果位置不在视野距离内的区块,或者如果距离大于存储的 Waypoint$Fade#farDist(默认超过 332 个方块)则保存一个角度。
实体默认跟踪路径点。
样式和图标
每个路径点都由某种图标表示,由其 WaypointStyle 和图标的颜色定义。WaypointStyle 类似于客户端物品或装备模型,它具有一个由 WaypointStyleAsset 指向的键,位于 assets/<modid>/waypoint_style/<path>.json 中。这包含一个位于 assets/<modid>/textures/gui/sprites/hud/locator_bar_dot/<path>.png 中的精灵列表,根据与跟踪器的距离选择。精灵在由近和远距离指定的范围内变化。
// 对于某个样式 examplemod:example_style
// 它将在 `assets/examplemod/waypoint_style/example_style.json` 中找到
{
// 表示任何更近的值将在渲染条时使用第一个精灵
// 未指定时默认为 128
"near_distance": 100,
// 表示任何更远的值将在渲染条时使用最后一个精灵
// 未指定时默认为 332
// 必须大于近距离
"far_distance": 400,
// 一个相对于 `assets/<modid>/textures/gui/sprites/hud/locator_bar_dot/<path>.png` 的非空纹理列表
// 这是用于在两个距离之间进行插值的内容
"sprites": [
// 指向 `assets/examplemod/textures/gui/sprites/hud/locator_bar_dot/example_style_0.png`
"examplemod:example_style_0",
"examplemod:example_style_1",
"examplemod:example_style_2"
]
}
然后可以使用其构造函数构造图标,并通过服务器上的 WaypointTransmitter#waypointIcon 或客户端上的 TrackedWaypoint#icon 引用。
// 我们将假设此构造函数被公开以用于更动态的用法
// 目前,它只能通过其 `CompoundTag` 在 `LivingEntity` 上通过 `locator_bar_icon` 设置
public static Waypoint.Icon EXAMPLE_ICON = new Waypoint.Icon(
// 路径点样式的注册表键
// 指向 `assets/examplemod/waypoint_style/example_style.json`
ResourceKey.create(WaypointStyleAssets.ROOT_ID, ResourceLocation.fromNamespaceAndPath("examplemod", "example_style")),
// 路径点的颜色
// 当不存在时,使用路径点标识符的哈希码
Optional.of(0xFFFFFF)
);
连接
当跟踪路径点时,它们通过 WaypointTransmitter$Connection 进行管理。一个连接负责将信息同步到客户端,无论是连接、断开连接还是更新。
public class ExampleBlockConnection implements WaypointTransmitter.Connection {
private final BlockState state;
private final BlockPos pos;
private final Waypoint.Icon icon;
private final ServerPlayer receiver;
public ExampleBlockConnection(BlockState state, BlockPos pos, Waypoint.Icon icon, ServerPlayer receiver) {
this.state = state;
this.pos = pos;
this.icon = icon;
this.recevier = receiver;
}
public static boolean doesSourceIgnoreReceiver(BlockPos pos, ServerPlayer player) {
double receiveRange = player.getAttributeValue(Attributes.WAYPOINT_RECEIVE_RANGE);
return pos.distSqr(player.blockPosition()) >= receiveRange * receiveRange;
}
@Override
public boolean isBroken() {
// 当为 true 时,它将尝试重新建立到此发射器的连接
// 仅在更新位置时调用
return ExampleBlockConnection.doesSourceIgnoreReceiver(this.pos, this.receiver);
}
@Override
public void connect() {
// 这会将跟踪数据包发送到客户端
this.receiver.connection.send(ClientboundTrackedWaypointPacket.addWaypointPosition(this.state.toString() + ": " + this.pos.toString(), this.icon, this.pos));
}
@Override
public void disconnect() {
// 这会将移除数据包发送到客户端
this.receiver.connection.send(ClientboundTrackedWaypointPacket.removeWaypoint(this.state.toString() + ": " + this.pos.toString()));
}
@Override
public void update() {
// 这会在客户端上更新跟踪值,假设连接没有中断
// 在我们的例子中,我们可以假设这永远不会改变,因为方块的位置应该是一致的
}
}
发射器
一个 WaypointTransmitter 负责在其和服务器之间建立连接。为了让您的对象传输位置,它必须实现 WaypointTransmitter 及其三个方法。waypointIcon 仅返回要显示的图标。isTransmittingWaypoint 将确定是否可以从该对象传输路径点。makeWaypointConnectionWith 实际处理用于跟踪连接的位置或角度的连接的构造。
public class ExampleWaypointBlock extends BlockEntity implements WaypointTransmitter {
// ...
@Override
public boolean isTransmittingWaypoint() {
// 如果不应该建立连接,则应返回 false
return true;
}
@Override
public Optional<WaypointTransmitter.Connection> makeWaypointConnectionWith(ServerPlayer player) {
// 如果没有被忽略,则创建一个连接
return ExampleBlockConnection.doesSourceIgnoreReceiver(this.getBlockPos(), player)
? Optional.empty()
: Optional.of(new ExampleBlockConnection(this.getBlockState(), this.getBlockPos(), this.waypointIcon(), player));
}
@Override
public Waypoint.Icon waypointIcon() {
return EXAMPLE_ICON;
}
}
然后,您需要做的就是根据需要跟踪、更新或取消跟踪发射器。这可以使用 ServerWaypointManager 提供的方法来完成:
// 我们将假设我们可以访问:
// - ServerLevel serverLevel
// - ExampleWaypointBlock be
// 跟踪路径点,例如在某个初始化时
serverLevel.getWaypointManager().trackWaypoint(be);
// 如果位置改变,更新路径点
serverLevel.getWaypointManager().updateWaypoint(be);
// 一旦路径点不再存在,将其移除
serverLevel.getWaypointManager().untrackWaypoint(be);
net.minecraft.clientCamera现在实现TrackedWaypoint$CameraMinecraft#getWaypointStyles- 返回一个键到路径点样式的管理器。
net.minecraft.client.data.models.WaypointStyleProvider- 一个生成路径点样式的数据提供者。net.minecraft.client.multiplayer.ClientPacketListener#getWaypointManager- 获取用于跟踪路径点的客户端管理器。net.minecraft.client.renderer.GameRenderer现在实现TrackedWaypoint$Projectornet.minecraft.client.resourcesWaypointStyle- 定义用于渲染路径点的样式。WaypointStyleManager- 将某个键映射到路径点样式的管理器。
net.minecraft.client.waypoints.ClientWaypointManager- 用于跟踪路径点的客户端管理器。net.minecraft.commands.arguments.WaypointArgument- 一个静态方法持有者,用于从实体获取某个路径点发射器。net.minecraft.network.protocol.gameClientboundTrackedWaypointPacket- 一个向客户端发送某个路径点操作的数据包。ClientGamePacketListener#handleWaypoint- 在客户端上处理路径点数据包。
net.minecraft.server.ServerScoreboard$Method枚举已移除net.minecraft.server.level.ServerLevel#getWaypointManager- 获取用于跟踪路径点的服务器管理器。net.minecraft.server.level.ServerPlayer#isReceivingWaypoints- 玩家是否从其他位置或实体接收路径点。net.minecraft.server.waypoints.ServerWaypointManager- 用于跟踪路径点(例如,玩家和发射器)的服务器端管理器。net.minecraft.world.entityEntity#getRequiresPrecisePosition、setRequiresPrecisePosition- 处理何时需要更精确的位置进行跟踪。LivingEntity现在实现WaypointTransmitter
net.minecraft.world.waypointsTrackedWaypoint- 一个由某个 UUID 或字符串标识、通过Waypoint$Icon显示并由$Type指定的路径点。TrackedWaypointManager- 一个用于TrackedWaypoint的路径点管理器。Waypoint- 一个表示某个位置位置的接口。它不保存任何信息,通常在TrackedWaypoint的上下文中使用。WaypointManager- 一个跟踪和更新路径点的接口。WaypointStyleAsset- 一个表示样式资源的类。WaypointStyleAssets- 一个定义所有原版样式资源的类。WaypointTransmitter- 一个传输某个可以连接和跟踪的位置的对象。
Blaze3d 变更
就像上一次更新一样,Blaze3d 有新的重新设计,改变了渲染的处理方式。
缓冲区切片
渲染系统中最重要的是使用 GpuBufferSlice。顾名思义,它只是获取 GpuBuffer 的某个切片,使用 offset 指示起始索引,length 指示其大小。在处理任何与渲染相关的事情时,即使传递给着色器,您几乎总是会处理 GpuBufferSlice。可以这样理解:缓冲区只是某个对象的任意列表,而切片代表一个特定的对象。
要创建一个切片,只需调用 GpuBuffer#slice,可选择提供起始索引和长度。在大多数情况下,您不会直接调用此方法,而是处理为您调用它的其他方法。请注意,由于您通常将数据写入这些切片,它们应该在创建 try-with-resources RenderPass 之前构建。
统一变量重做
统一变量系统已被完全改造,以至于除非您熟悉特定功能,否则它可能看起来完全陌生。简而言之,统一变量现在存储为接口对象、纹素缓冲区或采样器。这些由 GpuBuffer 或 GpuBufferSlice 填充。
统一变量类型
一个统一变量目前表示为两种 UniformType 之一:UNIFORM_BUFFER/接口块,或 TEXEL_BUFFER。在设置管道并调用 withUniform 时,您必须使用上述类型之一指定您的统一变量。如果您选择使用纹素缓冲区,还必须指定纹理数据的格式。采样器没有变化。
public static final RenderPipeline EXAMPLE_PIPELINE = RenderPipeline.builder(...)
// 使用名为 'ExampleUniform' 的统一接口块
.withUniform("ExampleUniform", UniformType.UNIFORM_BUFFER)
// 使用名为 'ExampleTexel' 的缓冲区,将纹理数据存储为 8 位 R 值
.withUniform("ExampleTexel", UniformType.TEXEL_BUFFER, TextureFormat.RED8I)
// 执行其他设置
.build();
接口块
一个 UNIFORM_BUFFER 存储为一个 std140 接口块。在 GLSL 中,它表示如下:
// 在 assets/examplemod/shaders/core/example_shader.json
// ExampleUniform 是块的名称
layout(std140) uniform ExampleUniform {
// 块内的数据
// 后处理效果只能使用 int, float, vec2, vec3, ivec3, vec4, 或 mat4
vec4 Param1;
float Param2;
};
可以在主块内自由使用这些值,如下所示:
// 在 assets/examplemod/shaders/core/example_shader.json
out vec4 fragColor;
void main() {
fragColor = Param1;
}
统一块可以位于与主函数相同的文件中,或者如果将被重用,可以作为 moj_import,其中统一文件位于 assets/<modid>/shaders/include/<path> 内。请注意,在资源包加载之前使用的任何着色器都不能使用 moj_import。
后处理效果在 uniform 输入中定义其接口块:
// 在 assets/examplemod/post_effect/example_post_effect.json
// 在 'passes' 对象内部
{
"vertex_shader": "...",
// ...
"uniforms": {
// 接口块的名称
"ExampleUniform": [
// 统一块内的一个参数
// 有关编解码器格式,请参阅 `UniformValue`
{
// 参数的名称
"name": "Param1",
// 参数类型,之一:
// - int
// - ivec3
// - float
// - vec2
// - vec3
// - vec4
// - matrix4x4 (mat4)
"type": "vec4",
// 存储在统一变量中的值
// 不再支持来自代码库的动态值
"value": [ 0.0, 0.0, 0.0, 0.0 ]
},
{
"name": "Param2",
"type": "float",
"value": 0
}
]
}
}
纹素缓冲区
纹素缓冲区通常表示为 isamplerBuffer 以供查询,通常使用 texelFetch:
// 在 assets/examplemod/shaders/core/example_shader.json
uniform isamplerBuffer ExampleTexel;
void main() {
// 阅读文档以了解 texel fetch 的工作原理
texelFetch(ExampleTexel, gl_InstanceID);
}
编写自定义统一变量
只有当您负责创建 RenderPass 时,才能编写自定义统一变量。与之前一样,您在打开 RenderPass 之前创建并缓存对象,然后通过调用 RenderPass#withUniform 设置统一变量。唯一的区别是,现在您必须提供一个 GpuBuffer 或 GpuBufferSlice,其中写入了统一数据,而不是提供任意对象。对于纹素缓冲区,这通常是一些所需纹理格式的编码数据(例如网格)。对于接口块,最简单的方法是使用 Std140Builder 用正确的值填充缓冲区。
写入 GpuBuffer 或 GpuBufferSlice 有很多不同的方法,例如使用新创建的 MappableRingBuffer。由您决定哪种方法最适合您的场景。以下只是众多解决方案中的一种。
// 用于 'ExampleUniform' 的缓冲区
// 接受缓冲区的名称、其用法和大小
private final MappableRingBuffer ubo = new MappableRingBuffer(
// 缓冲区名称
() -> "Example UBO",
// 缓冲区用法
// 我们设置 128,因为它用于统一变量,并且设置 2 因为我们正在写入它
// 其他位可以在 `GpuBuffer` 中作为常量找到
GpuBuffer.USAGE_UNIFORM | GpuBuffer.USAGE_MAP_WRITE,
// 缓冲区的大小
// 最简单的方法是使用 Std140SizeCalculator 正确计算
new Std140SizeCalculator()
// Param1
.putVec4()
// Param2
.putFloat()
.get()
);
// 用于 'ExampleTexel' 的缓冲区
private final MappableRingBuffer utb = new MappableRingBuffer(
// 缓冲区名称
() -> "Example UTB",
// 我们设置 256,因为它用于纹素缓冲区,并且设置 2 因为我们正在写入它
GpuBuffer.USAGE_UNIFORM_TEXEL_BUFFER | GpuBuffer.USAGE_MAP_WRITE,
// 缓冲区的大小
// 对您来说可能会更大
3
);
// 在某个渲染方法中
// 根据需要填充缓冲区
// 由于我们使用环形缓冲区,这只是使用列表中的下一个可用缓冲区
this.ubo.rotate();
// 将数据写入缓冲区
try (GpuBuffer.MappedView view = RenderSystem.getDevice().createCommandEncoder().mapBuffer(this.ubo.currentBuffer(), false, true)) {
Std140Builder.intoBuffer(view.data())
.putVec4(0f, 0f, 0f, 0f)
.putFloat(0f);
}
// 类似的事情
this.utb.rotate();
try (GpuBuffer.MappedView view = RenderSystem.getDevice().createCommandEncoder().mapBuffer(this.utb.currentBuffer(), false, true)) {
view.data()
.put((byte) 0)
.put((byte) 0)
.put((byte) 0);
}
// 创建渲染通道并传入缓冲区作为统一变量的一部分
try (RenderPass pass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(...)) {
// ..
pass.setUniform("ExampleUniform", this.ubo.currentBuffer());
pass.setUniform("ExampleTexel", this.utb.currentBuffer());
// ...
}
雾环境
雾系统已被重做为环境/渲染状态式的处理程序。每个环境主要负责设置雾数据和颜色。为各个 FogType 和特殊状态效果提供了一些额外的处理。
所有环境都通过 FogEnvironment 处理。通过 setupFog 方法设置环境,该方法负责将传入的 FogData 更改为与该环境关联的值。如果雾对其周围环境着色,则 providesColor 应返回 true,并在 getBaseColor 中应用基本颜色色调。同样,如果雾使其周围环境变暗,则 modifiesDarkness 应返回 true,并通过 getModifiedDarkness 返回修改后的暗度。要确定是否应应用环境,会检查 isApplicable。如果不可用,则调用 onNotApplicable。
所有环境都注册到 FogRenderer#FOG_ENVIRONMENTS;然而,使用哪个环境基于 isApplicable 和列表顺序。对于颜色和暗度,选择的雾环境是列表中最后一个 provides* 方法之一返回 true 的环境。对于实际的雾设置,选择的雾环境是列表中的第一个。
渲染通道剪裁现在仅限 OpenGL
剪裁状态已从通用管线代码中移除,现在只能通过 OpenGL 实现访问。通用区域处理已委托给 CommandEncoder#clearColorAndDepthTextures。请注意,这不会影响处理面向 blit 的剪裁的现有 ScreenRectangle 系统。
com.mojang.blaze3d.buffersBufferType枚举已移除BufferUsage枚举已移除GpuBuffer现在接受两个整数表示大小和用法,不再指定类型type已移除usage现在返回一个 intslice- 返回一个表示某个缓冲区切片的记录。实际缓冲区不以任何方式修改。$ReadView->$MappedView
GpuBufferSlice- 一个记录,通过持有对整个缓冲区的引用、起点的偏移索引和切片的长度来表示某个缓冲区的切片。GpuFence现在是一个接口,其 OpenGL 实现已移至blaze3d.opengl.GlFenceStd140Builder- 一个用于以std140格式布局的接口块的缓冲区插入器。用于着色器中的统一块。Std140SizeCalculator- 一个用于跟踪某个接口块大小的对象。
com.mojang.blaze3d.openglAbstractUniform已移除,被Std140*类取代BufferStorage- 一个根据其类型创建缓冲区的类。其实现定义了其一般用途。DirectStateAccesscreateBuffer- 创建一个缓冲区。bufferData- 初始化缓冲区的数据存储。bufferSubData- 更新缓冲区数据存储的子集。bufferStorage- 创建缓冲区的数据存储。mapBufferRange- 映射缓冲区数据存储的一部分。unmapBuffer- 释放缓冲区的映射并使指向其数据存储的指针无效。
GlBuffer现在接受一个DirectStateAccess、两个整数和一个ByteBuffer,而不是GlDebugLabel及其Buffer*枚举initialized已移除persistentBuffer- 持有对某个缓冲区不可变部分的引用。$ReadView->$GlMappedView
GlCommandEncoderexecuteDrawMultiple现在接受一个字符串集合,定义所需统一变量的列表,以及一个表示绘制调用对象的泛型executeDraw现在接受两个int,要渲染的指定索引范围的实例数和基础顶点
GlConst#toGl用于BufferType和BufferUsage->bufferUsageToGlFlag、bufferUsageToGlEnumGlDebugLabel#pushDebugGroup、popDebugGroup- 用于对类似调用进行分组的分析器命令。GlDeviceUSE_GL_ARB_buffer_storage- 设置GL_ARB_buffer_storage的扩展标志。getBufferStorage- 返回负责创建缓冲区的存储。
GlProgramUniform字段已移除safeGetUniform、setDefaultUniforms已移除bindSampler已移除getSamplerLocations、getSamplers、getUniforms->getUniforms,返回名称到其Uniform对象的映射
GlRenderPassuniforms现在是一个HashMap<String, GpuBufferSlice>dirtSamplers已移除samplers映射现在持有GpuTextureView值pushedDebugGroups- 返回推送到堆栈上的组数。关闭渲染通道时不得有任何调试组打开。isScissorEnabled- 返回是否启用剪裁状态,该状态会裁剪渲染到屏幕的区域。getScissorX、getScissorY、getScissorWidth、getScissorHeight- 返回表示剪裁矩形的值。
GlTexture现在接受一个额外的整数用于用法和深度/层数flushModeChanges现在接受一个表示纹理目标的intaddViews、removeViews- 管理针对某些 mip 级别的纹理视图。
GlTextureView- 针对某些 mip 级别的纹理的视图实现。Uniform现在是一个密封接口,实现为缓冲区对象、纹素缓冲区或采样器
com.mojang.blaze3d.pipelineBlendFunction#PANORAMA已移除CompiledRenderPipeline#containsUniform已移除RenderPipeline$Builder#withUniform现在有一个可以接受TextureFormat的重载$UniformDescription现在接受一个可为 null 的TextureFormat
RenderTargetcolorTextureView、depthTextureView、getColorTextureView、getDepthTextureView- 当前颜色和深度纹理的视图。blitAndBlendToTexture现在接受GpuTextureView而不是GpuTexture
com.mojang.blaze3d.platform.Lightning现在是AutoCloseablesetup*->setupFor,一个接受$Entry的实例方法updateLevel- 更新光照缓冲区,接受是否使用下界漫射光照。
com.mojang.blaze3d.shadersFogShape->net.minecraft.client.renderer.fog.FogData,不是一对一UniformType现在只包含两种类型:UNIFORM_BUFFER或TEXEL_BUFFER,不再接受计数
com.mojang.blaze3d.systemsCommandEncoderclearColorAndDepthTextures现在有一个接受四个int的重载,表示要清除纹理信息的区域writeToBuffer、mapBuffer(GpuBuffer, int, int)现在接受GpuBufferSlice而不是GpuBuffercreateFence- 创建一个新的同步围栏。createRenderPass现在接受一个Supplier<String>,用于确定用作调试组的通道名称,以及GpuTextureView而不是GpuTexturewriteToTexture现在接受一个额外的int,表示要写入的深度或层presentTexture现在接受GpuTextureView而不是GpuTexture
GpuDevicecreateBuffer不再接受BufferUsage,BufferType被int取代getUniformOffsetAlignment- 返回统一缓冲区偏移对齐。createTexture现在接受额外的int用于用法和深度/层数,请参阅GpuTexture常量createTextureView- 为某个 mip 级别范围创建纹理视图。
RenderPassenableScissor已移除bindSampler现在可以接受一个可为 null 的GpuTextureViewsetUniform现在可以接受GpuBuffer或GpuBufferSlice而不是原始输入drawIndexed现在接受以下int:基础顶点、起始索引、元素数和原始计数drawMultipleIndexed现在接受一个字符串集合,定义所需统一变量的列表,以及一个表示绘制调用对象的泛型pushDebugGroup、popDebugGroup- 用于对类似调用进行分组的分析器命令。$UniformUploader#upload现在接受GpuBufferSlice而不是float数组$Draw现在有一个泛型,用于将任何统一变量上传到缓冲区
RenderSystemSCISSOR_STATE->scissorStateForRenderTypeDraws,现在是私有的- 可通过
getScissorStateForRenderTypeDraws访问
- 可通过
enableScissor、disableScissor->enableScissorForRenderTypeDraws、disableScissorForRenderTypeDraws,不是一对一PROJECTION_MATRIX_UBO_SIZE- 返回投影矩阵统一变量的大小setShaderFog、getShaderFog现在处理GpuBufferSlicesetShaderGlintAlpha、getShaderGlintAlpha已移除setShaderLights、getShaderLights现在处理GpuBufferSlicesetShaderColor、getShaderColorsetup*Lighting方法已移除setProjectionMatrix、getProjectionMatrix(现在为getProjectionMatrixBuffer)现在处理GpuBufferSlicesetShaderGameTime、getShaderGameTime->setGlobalSettingsUniform、getGlobalSettingsUniform;不是一对一getDynamicUniforms- 返回要为着色器写入的统一变量列表。bindDefaultUniforms- 绑定要在RenderPass内使用的默认统一变量outputColorTextureOverride、outputDepthTextureOverride现在是GpuTextureViewsetupOverlayColor、setShaderTexture、getShaderTexture现在操作GpuTextureView而不是GpuTexture
com.mojang.blaze3d.texturesGpuTexture现在接受一个表示用法标志和深度/层数的 intusage- 定义纹理如何使用的标志。depthOrLayers、getDepthOrLayers- 定义给定纹理可用的层数或深度。这是作为可用纹理编码的通用计数。目前仅支持立方体贴图(意味着层数必须是 6 的倍数)。
GpuTextureView- 针对某个 mip 级别范围的纹理视图。TextureFormat#RED8I- 处理红色通道的 8 位有符号整数。
com.mojang.blaze3d.vertexByteBufferBuilder现在接受一个 long 作为最大容量exactlySized- 返回一个达到其最大容量的缓冲区。应优先于公共构造函数调用此方法。
DefaultVertexFormat#EMPTY- 一个没有元素的顶点格式。
net.minecraft.client.rendererCachedOrthoProjectionMatrixBuffer- 一个缓存正交投影矩阵的对象,如果屏幕宽度或高度改变,则重新构建。CachedPerspectiveProjectionMatrixBuffer- 一个缓存透视投影矩阵的对象,如果宽度、高度或视野改变,则重新构建。CloudRendererFLAG_INSIDE_FACE、FLAG_USE_TOP_COLOR现在是私有的RADIUS_BLOCKS已移除endFrame- 通过构造围栏结束当前正在渲染的帧。
CubeMap现在是AutoCloseablerender不再接受部分刻的浮点数。
DynamicUniforms- 一个将统一接口块写入缓冲区以供着色器使用的类。DynamicUniformStorage- 一个将统一变量保存在可映射环形缓冲区切片中的类。FogParameters记录已移除,现在存储在一个通用的GpuBufferSlice中FogRenderer现在实现AutoCloseable->.fog.FogRendererendFrame- 通过构造围栏结束当前正在渲染的帧。getBuffer- 获取持有当前雾模式统一变量的缓冲区切片。setupFog不再接受FogMode,不返回任何内容$FogData#mode已移除,被skyEnd、cloudEnd取代$FogMode枚举已被NONE和WORLD取代,不是一对一
GameRenderergetGlobalSettingsUniform- 返回游戏设置的统一变量。getLighting- 获取光照渲染器。setLevel- 设置渲染器正在渲染的当前等级。
GlobalSettingsUniform- 一个用于处理持有当前游戏设置的统一变量的对象。LevelRendererendFrame- 通过构造围栏结束当前正在渲染的帧。renderLevel现在接受一个GpuBufferSlice、雾向量以及当前位置是否有雾,而不是GameRenderer
MappableRingBuffer- 一个包含三个缓冲区的对象,根据需要写入,然后在结束时旋转到下一个要使用的缓冲区。这些使用围栏进行同步。PanoramaRenderer#render现在接受一个布尔值,表示是否改变旋转,而不是两个浮点数。PerspectiveProjectionMatrixBuffer- 一个持有投影矩阵统一变量的对象。PostChainload现在接受CachedOrthoProjectionMatrixBufferaddToFrame不再接受Consumer<RenderPass>process不再接受Consumer<RenderPass>
PostChainConfig$FixedSizedTarget记录已移除$FullScreenTarget记录已移除$InternalTarget现在是一个记录,可以接受可选的宽度、高度、目标是否持久以及要使用的清除颜色$Pass#uniforms现在是一个Map<String, List<UniformValue>>$Uniform记录已移除
PostPass现在是AutoCloseable,接受一个Map<String, List<UniformValue>>作为统一变量,以及一个PostPass$Input列表addToFrame不再接受Consumer<RenderPass>,Matrix4f作为GpuBufferSlice传入$InputbindTo已移除texture- 根据资源映射为输入构造一个GpuTexture。samplerName- 返回采样器的名称。
SkyRenderer#renderSunMoonAndStars不再接受FogParametersUniformValue- 一个表示存储在接口块内的统一变量的接口。
net.minecraft.client.renderer.chunk.SectionRendererDispatcher$RenderSection#setDynamicTransformIndex、getDynamicTransformIndex- 处理用于查询给定部分的正确动态变换的索引。net.minecraft.client.renderer.fog.environmentAirBasedFogEnvironment- 一个其颜色源自生物群系空气的环境AtmosphericFogEnvironment- 如果没有其他特殊情况匹配,则为默认雾环境。BlindessFogEnvironment- 如果实体有失明效果,则激活的环境。DarknessFogEnvironment- 如果实体有黑暗效果,则激活的环境。DimensionOrBossFogEnvrionment- 根据是否有任何 Boss 或维度特殊效果而激活的环境。FogEnvironment- 一个抽象类,确定雾在给定位置应如何为实体渲染。LavaFogEnvironment- 如果实体在熔岩中,则激活的环境。MobEffectFogEnvironment- 根据实体是否有给定的状态效果而激活的环境。PowderedSnowFogEnvironment- 如果实体在细雪中,则激活的环境。WaterFogEnvironment- 如果实体在水中,则激活的环境。
net.minecraft.client.renderer.textureAbstractTexturesetUseMipmaps- 设置纹理是否应使用 mipmapping。textureView、getTextureView- 表示当前的纹理视图。
CubeMapTexture- 一个兼容立方体贴图的纹理,纹理预期具有后缀_0到_5。ReloadableTexture#doLoad现在是 protected
net.minecraft.world.level.material.FogTypeDIMENSION_OR_BOSS- 用于维度特殊效果或 Boss 的雾。ATMOSPHERIC- 默认雾类型。
TagAppender 重写
TagAppender 已被重写,改变了 TagsProvider 的基本实现。
默认情况下,TagsProvider 不再提供任何用于向 TagBuilder 添加内容的有用方法。您最多可以使用 TagsProvider#getOrCreateRawBuilder 构造构建器,并使用可用的 add* 方法之一通过其 ResourceLocation 添加元素或标签。
// 我们将假设存在某个 TagKey<Item> EXAMPLE_TAG
public class ExampleTagsProvider extends TagsProvider<Item> {
public ExampleTagsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries, CompletableFuture<TagsProvider.TagLookup<Item>> parentProvider) {
super(
// 资源包的输出位置
output,
// 要为其生成标签的注册表键
Registries.ITEM,
// 注册表的注册表
registries,
// 可选:要使用其生成标签的父提供者
// 通常从 TagsProvider#contentsGetter 获得
parentProvider
);
}
@Override
protected void addTags(HolderLookup.Provider registries) {
// 在此处添加标签
TagBuilder builder = this.getOrCreateRawBuilder(EXAMPLE_TAG);
builder
// 添加单个元素
.addElement(ResourceLocation.fromNamespaceAndPath("minecraft", "apple"))
// 将标签添加到构建器
.addTag(ItemTags.WOOL.location());
}
}
但是,如果我们想通过其 ResourceKey 引用标签呢?或者注册表对象?这就是重写的 TagAppender 的作用。TagAppender 是一个具有两个泛型的接口,E 表示要添加的条目的类型,T 表示标签内对象的类型。一个 TagAppender 有五个常见方法:三个添加条目(add、addAll、addOptional),两个添加标签(addTag、addOptionalTag)。可以通过 forBuilder 创建 TagAppender,它接受条目的 ResourceKey。
KeyTagProvider 通过添加一个 tag 方法为您提供此功能,该方法从 TagKey 创建追加器。通常,数据包注册表对象使用此提供者生成其标签:
// 我们将假设存在某个 TagKey<Item> EXAMPLE_TAG
public class ExampleTagsProvider extends KeyTagProvider<Item> {
public ExampleTagsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
super(
// 资源包的输出位置
output,
// 要为其生成标签的注册表键
Registries.ITEM,
// 注册表的注册表
registries
);
}
@Override
protected void addTags(HolderLookup.Provider registries) {
// 在此处添加标签
TagAppender<ResourceKey<Item>, Item> builder = this.tag(EXAMPLE_TAG);
builder
// 添加单个元素
.add(ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath("minecraft", "apple")))
// 将标签添加到构建器
.addTag(ItemTags.WOOL);
}
}
TagAppender 也可以使用 map 方法来更改其条目类型。这接受一个将新条目类型映射到原始条目类型的函数。IntrinsicHolderTagsProvider 通过一个 tag 方法为您提供此功能,该方法从 TagKey 创建追加器,并使用键提取器进行映射。通常,内置注册表对象使用此提供者生成其标签:
// 我们将假设存在某个 TagKey<Item> EXAMPLE_TAG
public class ExampleTagsProvider extends IntrinsicHolderTagsProvider<Item> {
public ExampleTagsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
super(
// 资源包的输出位置
output,
// 要为其生成标签的注册表键
Registries.ITEM,
// 注册表的注册表
registries,
// 将注册表对象映射到其资源键
item -> item.builtInRegistryHolder().key()
);
}
@Override
protected void addTags(HolderLookup.Provider registries) {
// 在此处添加标签
TagAppender<Item, Item> builder = this.tag(EXAMPLE_TAG);
builder
// 添加单个元素
.add(Items.APPLE)
// 将标签添加到构建器
.addTag(ItemTags.WOOL);
}
}
复制标签:方块和物品
复制标签不再以传统意义存在,即遍历现有标签的元素。相反,实现已被缩小到一个通用的 BlockItemTagsProvider。此方法通过同时接受方块和物品标签,并在 Vanilla*TagsProvider 中适当地转换它们,来提供 TagAppender<Block, Block>。因此,与其说是复制,不如说是将方块映射到其关联的物品。
一个缺点是,在其他标签中使用的标签(调用 addTag)必须具有相同的名称。例如,添加 BlockTags#LOGS 之所以有效,是因为存在一个 minecraft:logs 同时用于方块和物品标签。同时,添加 BlockTags#CEILING_HANGING_SIGNS 会失败,因为关联的物品标签是 minecraft:hanging_signs 而不是 minecraft:ceiling_hanging_signs。
// 我们将假设存在某个 TagKey<Block> BLOCK_EXAMPLE_TAG
// 我们将假设存在某个 TagKey<Item> ITEM_EXAMPLE_TAG
public class ExampleBlockItemTagsProvider extends BlockItemTagsProvider {
@Override
public void run() {
// 在此处添加方块物品标签
// 将根据提供者向方块或物品标签添加条目
TagAppender<Block, Block> builder = this.tag(BLOCK_EXAMPLE_TAG, ITEM_EXAMPLE_TAG);
builder
// 添加单个元素
.add(Blocks.TERRACOTTA)
// 将标签添加到构建器
// 在方块和物品标签中都存在 `minecraft:logs`
.addTag(BlockTags.LOGS);
}
}
// 对于某个 IntrinsicHolderTagsProvider<Item> 或 IntrinsicHolderTagsProvider<Block>
@Override
protected void addTags(HolderLookup.Provider registries) {
// 在此处添加标签
new ExampleBlockItemTagsProvider() {
// 或 <Item, Item> 取决于情况
protected TagAppender<Block, Block> tag(TagKey<Block> blockTag, TagKey<Item> itemTag) {
// 返回一个 TagAppender
// 有关物品示例,请参阅 VanillaItemTagsProvider$BlockToItemConverter
// 有关方块示例,请参阅 VanillaBlockTagsProvider
}
}.run();
}
net.minecraft.data.tagsBlockItemTagsProvider- 一个为方块物品生成标签的提供者,使用方块和物品标签等效项作为起点。IntrinsicHolderTagsProvidertag现在返回原始的TagAppender$IntrinsicTagAppender类已移除
ItemTagsProvider类已移除KeyTagProvider- 一个通过其ResourceKey追加元素的提供者。TagsProvidertag已移除$TagAppender->TagAppender,不是一对一
VanillaItemTagsProvider现在实现IntrinsicHolderTagsProviderBlockToItemConverter- 一个将方块添加到物品标签的标签追加器。
通用编码与解码:替换直接 NBT 访问
从更高级别的对象(如实体和方块实体)中获取某些 NBT 数据的直接访问已被完全移除。这意味着,通常,在序列化过程中您不能直接接触 CompoundTag。相反,通过 ValueInput 和 ValueOutput 提供了对 nbt 标签的间接访问。顾名思义,它们分别从数据对象读取值和向数据对象写入值。可用的方法类似于 CompoundTag 上的方法。对于 ValueInput,有通过提供关联键的 get* 方法,以及如果不存在则获取或默认的 get*Or。还有用于处理 Codec 的 read。对于 ValueOutput,有通过提供关联键和值的 put* 方法,以及用于 Codec 的 store。列表变体在输入/输出访问上单独存在。
因此,大多数接受 CompoundTag 的方法现在改为在 read/load 时接受 ValueInput,或在 write/save 时接受 ValueOutput。
// 对于某个带有 ItemStack stack 的 Entity
@Override
protected void readAdditionalSaveData(ValueInput in) {
super.readAdditionalSaveData(in);
// 默认情况下,输入使用注册表 ops
this.stack = in.read("example_stack", ItemStack.CODEC).orElse(ItemStack.EMPTY);
}
@Override
protected void addAdditionalSaveData(ValueOutput out) {
super.addAdditionalSaveData(out);
// 默认情况下,输出使用注册表 ops
in.storeNullable("example_stack", ItemStack.CODEC, this.stack);
}
// 对于某个带有 int value 的 BlockEntity
@Override
protected void loadAdditional(ValueInput in) {
super.loadAdditional(in);
this.value = in.getIntOr("value", 0);
}
@Override
protected void saveAdditional(ValueOutput out) {
super.saveAdditional(out);
out.putInt("value", this.value);
}
NBT 实现
为了提供对 CompoundTag 的间接访问,有分别称为 TagValueInput 和 TagValueOutput 的 ValueInput 和 ValueOutput 的实现。
可以使用 createWithContext 或 createWithoutContext 创建 TagValueOutput。“有上下文”意味着输出可以访问注册表对象的 HolderLookup$Provider,而“无上下文”则不能。目前,没有位置使用 createWithoutContext。内部会创建一个新的 CompoundTag。然后,这个输出被传递以填充,最后通过 buildResult 返回用于写入的 NBT。
另一方面,TagValueInput 可以通过 create 创建,接受 HolderLookup$Provider 和要读取的 CompoundTag。如果数据存储为对象列表而不是单个对象,您可以传入一个 List<CompoundTag> 并返回一个 ValueInputList。请注意,这不处理索引,只提供可迭代或流关联的实现。
问题报告器
除了上述内容之外,create* 方法还接受一个 ProblemReporter,用于收集在尝试序列化/反序列化数据时遇到的所有问题。由实现决定此报告是导致崩溃还是发出警告。一个 ProblemReporter 包含两个方法:report,用于报告一个 $Problem;以及 forChild,用于使用 $PathElement 进一步对 $Problem 进行分组。问题和路径元素都只是接口对象,分别返回指示问题是什么或分组的字符串。
有两个常用的 ProblemReporter:$Collector,通常与数据提供者一起使用;以及 $ScopedCollector,与磁盘对象(例如,实体、方块实体、区块等)一起使用。$Collector 通常使用 forEach 逐个报告每个问题,getReport/getTreeReport 返回字符串化的问题,或 isEmpty 列出是否存在任何问题。$ScopedCollector 做同样的事情,只是它是 AutoCloseable,以防输出没有做任何操作。在这些情况下,报告会写入日志记录器。
每个收集器都接受一个初始的 $PathElement。这通常来自对象本身,其中包含某个称为 problemPath 的方法,该方法实现了该接口。HolderLookup$Provider 以相同的方式提供。
// 对于某个带有 HolderLookup.Provider registries 的对象
// 还有一个 Logger LOGGER
// 我们假设我们的根路径元素实现如下
public record ExamplePathElement(String name) implements ProblemReporter.PathElement {
@Override
public String get() {
return "Example: " + this.name();
}
}
// 对于数据提供者
ProblemReporter.Collector problems = new ProblemReporter.Collector(
// 对于非指定的根,可以为空
new ExamplePathElement("data_provider")
);
// 传递提供者
// 对于基于磁盘的对象
try (ProblemReporter.ScopedCollector problems = new ProblemReporter.ScopedCollector(new ExamplePathElement("EXAMPLE TEST"), LOGGER)) {
TagValueOutput out = TagValueOutput.createWithContext(problems, this.registries);
// 传递输出以写入数据
// 对于输入
// 最后一个参数可以是任何 CompoundTag,以输出为例
TagValueInput in = TagValueInput.create(problems, this.registries, out.buildResult());
// 传递输入以读取数据
}
net.minecraft.nbt.StringTag#escapeWithoutQuotes- 创建一个转义控制字符、引号、撇号和反斜杠的字符串。net.minecraft.server.level.ServerPlayerloadAndSpawnParentVehicle现在接受一个ValueInputloadAndSpawnEnderPearls现在接受一个ValueInputloadGameTypes现在接受一个ValueInput
net.minecraft.server.players.PlayerList#load接受一个ProblemReporter,返回一个可选的ValueInputnet.minecraft.util.ProblemReporterDISCARDING- 一个丢弃所有报告的报告器。forChild现在接受一个$PathElementreport现在接受一个$Problem$Collector现在有一个接受根$PathElement的构造函数isEmpty- 返回是否没有报告。forEach- 遍历所有可用问题。getReport现在返回一个普通的StringgetTreeReport- 使用 DFS 获取报告及其所有子级。
$ElementReferencePathElement- 一个引用某个ResourceKey的路径元素。$FieldPathElement- 一个引用某个字符串的路径元素。$IndexedFieldPathElement- 一个在索引处引用某个字符串的路径元素。$IndexedPathElement- 一个引用某个索引的路径元素。$PathElement- 一个定义分组或元素的接口。$Problem- 一个定义元素问题的接口。$RootElementPathElement- 一个引用某个ResourceKey作为根的路径元素。$RootFieldPathElement- 一个引用某个字符串作为根的路径元素。$ScopedCollector- 一个在出现问题时记录警告的收集器。
net.minecraft.worldContainerHelpersaveAllItems现在接受一个ValueOutput而不是CompoundTag,不再接受HolderLookup$Provider,不返回任何内容loadAllItems现在接受一个ValueInput而不是CompoundTag,不再接受HolderLookup$Provider
LockCode#addToTag、fromTag现在接受ValueOutput/ValueInput而不是CompoundTag,不再接受HolderLookup$ProviderRandomziableContainer#tryLoadLootTable、trySaveLootTable现在接受ValueOutput/ValueInput而不是CompoundTagSimpleContainerfromTag->fromItemList,不是一对一createTag->storeAsItemList,不是一对一
net.minecraft.world.entityEntitysaveAsPassenger现在接受一个ValueOutput而不是CompoundTagsave现在接受一个ValueOutput而不是CompoundTagsaveWithoutId现在接受一个ValueOutput而不是CompoundTag,不返回任何内容load现在接受一个ValueInput而不是CompoundTagreadAdditionalSaveData现在接受一个ValueInput而不是CompoundTagaddAdditionalSaveData现在接受一个ValueOutput而不是CompoundTagproblemPath- 返回报告问题的路径元素。
EntityRenferencestore现在接受一个ValueOutput而不是CompoundTagread、readWithOldOwnerConversion现在接受一个ValueInput而不是CompoundTag
EntityUUID_TAG->TAG_UUIDcreate、by现在接受一个ValueInput而不是CompoundTagloadEntityRecursive现在接受一个ValueInput而不是CompoundTagloadEntitiesRecursive现在接受一个ValueInput$ValueInputList而不是 nbt 标签列表loadStaticEntity现在接受一个ValueInput而不是CompoundTag
EntityReference#store- 将引用数据写入ValueOutput。Leashable#readLeashData、writeLeashData现在接受ValueInput/ValueOutput而不是CompoundTagLivingEntity#ATTRIBUTES_FIELD->TAG_ATTRIBUTESNeutralMob#addPersistentAngerSaveData、readPersistentAngerSaveData现在接受ValueOutput/ValueInput而不是CompoundTag
net.minecraft.world.entity.npc.InventoryCarrier#readInventoryFromTag、writeInventoryToTag现在接受ValueInput/ValueOutput而不是CompoundTagnet.minecraft.world.entity.player.Inventorysave现在接受一个ValueOutput$TypedOutputList,不返回任何内容load现在接受一个ValueOutput$TypedInputList
net.minecraft.world.entity.variant.VariantUtilswriteVariant现在接受一个ValueOutput而不是CompoundTagreadVariant现在接受一个ValueInput而不是CompoundTag,不再接受RegistryAccess
net.minecraft.world.entity.vehicle.ContainerEntity#addChestVehicleSaveData、readChestVehicleSaveData现在接受ValueOutput/ValueInput而不是CompoundTag,不再接受HolderLookup$Providernet.minecraft.world.inventory.PlayerEnderChestContainerfromTag->fromSlots,不是一对一createTag->storeAsSlots,不是一对一
net.minecraft.world.itemBlockItem#setBlockEntityData现在接受一个TagValueOutput而不是CompoundTagItemStack#parse、save已移除
net.minecraft.world.levelBaseCommandBlock#save、load现在接受ValueOutput/ValueInput而不是CompoundTag,不再接受HolderLookup$Provider,不返回任何内容BaseSpawner#save、load现在接受ValueOutput/ValueInput而不是CompoundTag,不返回任何内容
net.minecraft.world.level.block.SculkSpreader#save、load现在接受ValueOutput/ValueInput而不是CompoundTagnet.minecraft.world.level.block.entity.BlockEntityload*方法现在接受ValueInput而不是CompoundTag,不再接受HolderLookup$Providersave*方法现在接受ValueOutput而不是CompoundTag,不再接受HolderLookup$ProviderremoveComponentsFromTag现在接受一个ValueOutput而不是CompoundTagparseCustomNameSafe现在接受一个ValueInput和键,而不是标签和HolderLookup$ProviderproblemPath- 返回报告问题的路径元素。
net.minecraft.world.level.block.entity.trialspawner.TrialSpawner#load、store- 处理写入生成器数据。net.minecraft.world.level.chunk.ChunkAccess#problemPath- 返回报告问题的路径元素。net.minecraft.world.level.storagePlayerDataStorage#load现在返回一个ValueInput而不是CompoundTag,接受一个ProblemReporterTagValueInput- 一个复合标签输入。TagValueOutput- 一个复合标签输出。ValueInput- 一个定义如何从某个对象读取数据的接口。ValueInputContextHelper- 一个包含用于读取对象数据的上下文的类。ValueOutput- 一个定义如何向某个对象写入数据的接口。
net.minecraft.world.level.storage.loot.ValidationContextforChild、enterElement现在接受ProblemReporter$PathElement而不是StringreportProblem现在接受ProblemReporter$Problem而不是String$MissingReferenceProblem- 一个引用对象缺失的问题。$ParametersNotProvidedProblem- 一个战利品上下文参数缺失的问题。$RecursiveReferenceProblem- 一个引用对象正在引用自身的问题。$ReferenceNotAllowedProblem- 一个引用对象不允许被引用的问题。
net.minecraft.world.level.storage.loot.entriesAlternativesEntry#UNREACHABLE_PROBLEM- 一个替代条目永远无法执行的问题。CompositeEntryBase#NO_CHILDREN_PROBLEM- 一个组合体没有条目的问题。NestedLootTable#INLINE_LOOT_TABLE_PATH_ELEMENT- 一个表示表是内联的元素。
服务端玩家变更
MinecraftServer 不再在 ServerPlayer 上公开。此外,serverLevel 已被移除,现在用重载的 level 来返回 ServerLevel。
net.minecraft.server.level.ServerPlayerserver字段现在是私有的serverLevel->level,仍然返回ServerLevel
小幅迁移
以下是有用或有趣的增加、变更和移除的列表,它们不值得在入门文档中拥有自己的章节。
拴绳
拴绳系统已更新,最多支持四个拴绳同时拴在一个实体上。此外,物理效果已更新,以更恰当地处理某些可拉伸物体的现实弹性。
net.minecraft.client.renderer.entity.state.EntityRenderStateleashState现在返回一个$LeashState列表$LeashState#slack- 拴绳是否有松弛。
net.minecraft.world.entityEntityshearOffAllLeashConnections- 处理使用剪刀移除拴绳时的情况。dropAllLeashConnections- 处理应从实体移除所有拴绳时的情况。getQuadLeashHolderOffsets- 获取四个拴绳拴在实体上时的偏移量。supportQuadLeashAsHolder- 返回实体是否可以被拴最多四次。notifyLeashHolder、notifyLeasheeRemoved- 处理拴绳在实体上Tick以及被移除时的情况。setLeashOffset已移除getLeashOffset->Leashable#getLeashOffset
LeashableMAXIMUM_ALLOWED_LEASHED_DIST- 拴绳可以拴到实体的最大距离。AXIS_SPECIFIC_ELASTICITY- 拴绳沿每个轴的阻力。SPRING_DAMPENING- 拴绳拉伸时振荡的能量损失。TORSIONAL_ELASTICITY- 拴绳在扭矩下的阻力。STIFFNESS- 拴绳的刚度。ENTITY_ATTACHMENT_POINT- 指定拴绳在实体上的附着点。LEASHER_ATTACHMENT_POINT- 指定拴绳在持有者上的附着点。SHARED_QUAD_ATTACHMENT_POINTS- 指定拴绳在实体上的附着点。canHaveALeashAttachedToIt->canHaveALeashAttachedTo,不是一对一leashDistanceTo- 返回拴绳在持有者和被拴者之间经过的距离。onElasticLeashPull- 处理拴绳被拉拽时的情况。leashSnapDistance- 返回拴绳将尝试从实体上移除的距离。leashElasticDistance- 返回拴绳的弹性成为物理因素之前的最大距离。handleLeashAtDistance已移除angularFriction- 返回实体在方块上或液体中的角摩擦。whenLeashedTo- 通知实体拴绳已附着。elasticRangeLeashBehaviour、legacyElasticRangeLeashBehaviour->checkElasticInteractions,不是一对一supportQuadLeash- 实体是否可以被拴最多四次。getQuadLeashOffsets- 返回附着在实体上的每个拴绳的偏移量。createQuadLeashOffsets- 为四个可能的拴绳位置中的每一个创建偏移量。leashableLeashedTo- 获取所有在 32 格半径内被拴到此持有者的实体。$LeashData#angularMomentum- 返回实体被拴时的角动量。$Wrench- 一个记录,处理施加在拴绳上的力和扭矩。
net.minecraft.world.item.LeadItem#leashableInArea->Leashable#leashableInArea
移除生物效果图集
生物效果图集已被移除,并与 GUI 图集合并。
net.minecraft.client.Minecraft#getMobEffectTextures已移除net.minecraft.client.gui.Gui#getMobEffectSprite- 获取状态效果精灵的位置。net.minecraft.client.resources.MobEffectTextureManage类已移除AtlasIds#MOB_EFFECTS已移除
权限来源
命令的权限检查已被抽象到其自己的 PermissionSource 接口中。这提供了之前提供的 hasPermission 方法,以及一个新方法 allowsSelectors,它返回源是否有选择其他实体所需的权限(默认为 2 级权限)。您可以通过在 ArgumentBuilder#requires 中使用所需的级别调用 Commands#hasPermission,将权限检查合并到您的命令中。
net.minecraft.client.multiplayerClientPacketListenergetCommands现在返回一个ClientSuggestionProvider泛型sendUnattendedCommand现在接受一个Screen而不是boolean
ClientSuggestionListener现在实现PermissionSource,接受一个布尔值表示是否允许受限命令allowRestrictedCommands- 返回是否建议受限命令。
net.minecraft.commandsCommands#hasPermission- 返回给定级别的权限检查。CommandSourceStack现在实现PermissionSourceExecutionCommandSource现在实现PermissionSourcePermissionSource- 返回运行命令的权限源。SharedSuggestionProvidersuggestResgitryElements现在接受HolderLookup而不是RegistrylistSuggestions- 列出某些注册表元素的建议。hasPermission已移除
net.minecraft.commands.synchronization.SuggestionProvidersAVAILABLE_SOUNDS、SUMMONABLE_ENTITIES现在接受SharedSuggestionProvider作为其泛型cast- 将建议提供者转换为正确的类型。safelySwap已移除$Wrapper->$RegisteredSuggestion
net.minecraft.world.entity.Entity#getCommandSenderWorld已移除
动画烘焙
动画现在被烘焙到 KeyframeAnimation 中。每个 KeyframeAnimation 由将关键帧应用于给定 ModelPart 的条目组成。要创建动画,应在模型构造函数中通过 AnimationDefinition#bake 烘焙定义,然后在 EntityModel#setupAnim 期间根据需要调用 #apply 或 #applyWalk。
// 对于某个实体模型
// 假设存在某个 AnimationDefinition EXAMPLE_DEFN
// 假设我们的 ExampleEntityState 有一个 AnimationState exampleAnimState
public class ExampleModel extends EntityModel<ExampleEntityState> {
private final KeyframeAnimation exampleAnim;
public ExampleModel(ModelPart root) {
// 我们传入任何可以应用所有动画的 'root'
this.exampleAnim = EXAMPLE_DEFN.bake(root);
}
@Override
public void setupAnim(ExampleEntityState state) {
super.setupAnim(state);
this.exampleAnim.apply(state.exampleAnimState, state.ageInTicks);
}
}
net.minecraft.client.animationAnimationDefinition#bake- 烘焙一个已定义的动画,以便在Model上使用。KeyframeAnimation- 一个用于在给定Model上移动ModelPart的烘焙动画。KeyframeAnimations#animate->KeyframeAnimation$Entry#apply
net.minecraft.client.model.ModelgetAnyDescendantWithName已移除animate->KeyframeAnimation#applyanimateWalk-KeyframeAnimation#applyWalkapplyStatic->KeyframeAnimation#applyStatic
net.minecraft.client.model.geom.ModelPartgetAllParts现在返回一个ListcreatePartLookup- 创建一个部件名称到其ModelPart的查找表,任何重复的名称将被忽略。
ChunkSectionLayers
用于定义方块或流体应如何渲染的 RenderType 现在已被 ChunkSectionLayer 取代。它们在功能上与 RenderType 相同;然而,它们只指定要使用的 RenderPipeline 以及缓冲区信息。这也意味着某些 RenderType 被移除,例如 TRANSLUCENT,因为它们仅用于区块渲染。
这也意味着添加到 ItemBlockRenderTypes#TYPE_BY_BLOCK 必须指定 ChunkSectionLayer 而不是关联的 RenderType。
net.minecraft.client.rendererItemBlockRenderTypesgetChunkRenderType现在返回一个ChunkSectionLayergetRenderLayer(FluidState)现在返回一个ChunkSectionLayer
RenderTypetranslucent已移除getRenderTarget、getRenderPipeline已移除chunkBufferLayers已移除
net.minecraft.client.renderer.chunkChunkSectionLayer- 一个枚举,定义如何渲染单个区块层(例如,实心方块、半透明方块)。ChunkSectionLayerGroup- 一个枚举,将层分组以进行渲染。ChunkSectionsToRender- 一个记录,包含给定区块的绘制,允许按层组渲染它们。RenderChunk->SectionCopyRenderChunkRegion->RenderSectionRegionRenderRegionCache#createRegion现在接受一个long而不是SectionPosSectionCompiler$ResultsglobalBlockEntities-> -net.minecraft.client.multiplayer.ClientLevel#getGloballyRenderedBlockEntitiesrenderedLayers现在接受ChunkSectionLayer作为键
SectionMesh- 一个定义区块内给定部分的网格的接口SectionRenderDispatchergetBatchToCount->getCompileQueueSizesetCamera、getCameraPosition已移除blockUntilClear已移除clearBatchQueue->clearCompileQueue,现在是公开的$CompiledSection->CompiledSectionMesh$RenderSectiongetBuffers已移除uploadSectionLayer(RenderType, MeshData)->upload(Map, CompiledSectionMesh),不是一对一uploadSectionIndexBuffer现在接受一个CompiledSectionMesh和一个ChunkSectionLayer而不是RenderTypegetDistToPlayerSqr已移除getCompiled->getSectionMesh,不是一对一rebuildSectionAsync不再接受SectionRenderDispatchersetDynamicTransformIndex、getDynamicTransformIndex已移除
$SectionBuffers->SectionBuffers$TranslucencyPointOfView->TranslucencyPointOfView
net.minecraft.server.level.ChunkMap#getUpdatingChunkIfPresent现在是公开的net.minecraft.world.level.TicketStoragepurgeStaleTickets现在接受ChunkMapremoveTicketIf现在接受一个BiPredicate而不是Predicate,接受区块位置和加载票
net.minecraft.world.level.chunk.ChunkAccess#isSectionEmpty已移除
标签变更
minecraft:blockplays_ambient_desert_block_sounds拆分为triggers_ambient_desert_sand_block_sounds、triggers_ambient_desert_dry_vegetation_block_soundshappy_ghast_avoidstriggers_ambient_dried_ghast_block_sounds
minecraft:dialogpause_screen_additionsquick_actions
minecraft:entity_typecan_equip_harnessfollowable_friendly_mobs
minecraft:itemharnesseshappy_ghast_foodhappy_ghast_tempt_items
新增列表
com.mojang.blaze3d.pipelineBlendFunction#TRANSLUCENT_PREMULTIPLIED_ALPHA- 一个假设目标具有来自合成步骤的预乘 alpha 的混合函数。RenderPipelinegetSortKey- 返回一个表示元素应如何排序以进行渲染的值。用于层排序。updateSortKeySeed- 更新排序键的种子,当前未使用。
com.mojang.blaze3d.systems.RenderSystemoutputColorTextureOverride- 持有一个包含覆盖颜色的纹理,该覆盖颜色将代替RenderType目标中指定的任何内容使用。outputDepthTextureOverride- 持有一个包含覆盖深度的纹理,该覆盖深度将代替RenderType目标中指定的任何内容使用。
com.mojang.blaze3d.textures.GpuTexture#setUseMipmaps- 设置纹理在不同距离是否应使用 mipmap。net.minecraftFileUtil#isPathPartPortable- 返回提供的字符串是否与任何 Windows 保留文件名不匹配。WorldVersion$Simple- 当前世界版本的简单实现。
net.minecraft.advancements.critereonItemUsedOnLocationTrigger$TriggerInstance#placedBlockWithProperties- 创建一个触发器,其中放置了一个具有指定属性的方块。PlayerInteractTrigger$TriggerInstance#equipmentSheared- 创建一个条件触发器,作用于玩家从某个实体上取下物品。
net.minecraft.clientGameNarrator#saySystemChatQueued- 如果启用了系统或聊天消息旁白,则旁白一个组件。Minecraft#disconnectWithSavingScreen- 断开当前客户端实例并显示“保存等级”屏幕。OptionskeyQuickActions- 用于显示快速操作对话框的按键映射。cloudRange- 返回云可以渲染的最大距离。musicFrequency- 返回MusicManager处理的背景音乐应播放的频率。showNowPlayingToast- 返回是否显示“正在播放”吐司。getFinalSoundSourceVolume- 计算给定声音源的音量,非主声音源由主声音源缩放。
NarratorStatus#shouldNarrateSystemOrChat- 返回当前旁白状态是否为除OFF之外的任何状态。
net.minecraft.client.color.ColorLerper- 一个基于部分刻在颜色类型之间进行插值的实用工具类。net.minecraft.client.data.models.BlockModelGenerators#createDriedGhastBlock- 创建干燥恶魂方块模型定义。net.minecraft.client.data.models.modelModelTemplates#DRIED_GHAST- 一个使用minecraft:block/dried_ghast父级的模板。TextureMapping#driedGhast- 为干燥恶魂模型创建默认纹理映射。TextureSlot#TENTACLES- 提供一个纹理键tentacles。
net.minecraft.client.modelGhastModel#animateTentacles- 动画恶魂的触手。HappyGhastHarnessModel- 一个代表恶魂挽具的模型。HappyGhastModel- 一个代表“驯服”恶魂的模型。QuadrupedModel#createBodyMesh现在接受两个布尔值,分别用于处理左后腿和右后腿纹理是否镜像。
net.minecraft.client.multiplayer.ClientLevelDEFAULT_QUIT_MESSAGE- 持有退出游戏文本的组件。disconnect(Copmonent)- 断开与当前等级实例的连接,显示关联的组件。
net.minecraft.client.renderer.entity.HappyGhastRenderer- “驯服”恶魂的渲染器。net.minecraft.client.renderer.entity.layers.RopesLayer- 用于“驯服”恶魂上的绳索的渲染层。net.mienecraft.client.renderer.entity.state.HappyGhastRenderState- “驯服”恶魂的状态。net.minecraft.client.resources.model.EquipmentclientInfo$LayerType#HAPPY_GHAST_BODY- 一个代表快乐恶魂身体的层。net.minecraft.client.resources.sounds.RidingHappyGhastSoundInstance- 一个在骑乘快乐恶魂时播放的可Tick声音实例。net.minecraft.client.soundsMusicManagergetCurrentMusicTranslationKey- 返回当前正在播放的音乐的翻译键。setMinutesBetweenSongs- 设置背景曲目之间的频率。showNowPlayingToastIfNeeded- 如果需要,显示正在播放吐司。$MusicFrequency- 正在播放的背景曲目的频率。
SoundEngine$PlayResult- 尝试播放的声音的起始状态。
net.minecraft.commands.argumentsHexColorArgument- 一个接受十六进制颜色的整数参数。ResourceOrIdArgumentcreateGrammar- 创建用于解析参数的语法。$InlineResult- 一个返回直接持有者的结果。$ReferenceResult- 一个返回引用持有者的结果。$Result- 一个表示某个参数解析结果的接口。
net.minecraft.data.loot.LootTableProvider$MissingTableProblem- 一个记录,保存某个缺失的内置表生成器的键。net.minecraft.data.recipes.RecipeProviderdryGhast- 干燥恶魂的配方。harness- 染色挽具的配方。
net.minecraft.gametest.framework.GameTestTicker#startTicking- 开始为游戏测试Tick运行器。net.minecraft.nbt.NbtUtilsaddCurrentDataVersion、addDataVersion,将数据版本添加到某个 nbt 标签。
net.minecraft.network.FriendlyByteBuf#writeEither、readEither- 使用给定的流编码器/解码器处理Either。net.minecraft.network.codec.ByteBufCodecsRGB_COLOR- 一个使用三个字节写入 RGB 的流编解码器。lenientJson- 创建一个以宽松模式解析 json 的流编解码器。optionalTagCodec- 创建一个使用提供的NbtAccounter解析Optional包装的Tag的流编解码器。
net.minecraft.network.protocol.gameServerboundChangeGameModePacket- 更改当前游戏模式。ServerboundCustomClickActionPacket- 在服务器上执行自定义操作,目前什么都不做。
net.minecraft.server.MinecraftServer#handleCustomClickAction- 处理从点击事件发送的自定义操作。net.minecraft.server.level.ServerLevelupdateNeighboursOnBlockSet- 更新当前位置的邻居。如果方块不相同(不包括其属性),则调用BlockState#affectNeighborsAfterRemoval。waitForChunkAndEntities- 添加一个任务,使服务器等待,直到实体在提供的区块范围内加载。
net.minecraft.sources.SoundSource#UI- 来自某些用户界面的声音。net.minecraft.statsRecipeBookSettings#MAP_CODECServerRecipeBook#pack、loadUntrusted、$Packed- 处理编码和解码配方书的数据。
net.minecraft.utilARGBsetBrightness- 使用 0 到 1 之间的浮点数返回某个颜色的亮度。color- 从浮点红色和整数 alpha 返回一个 ARGB 颜色。
ExtraCodecsVECTOR2FVECTOR3INBT
LenientJsonParser- 一个使用宽松规则的 json 解析器。Mth#smallestSquareSide- 取一个数的平方根的上取整。StrictJsonParser- 一个使用严格规则的 json 解析器。
net.minecraft.worldDifficulty#STREAM_CODECItemStackWithSlot- 一个记录,包含一个堆栈及其槽位索引。
net.minecraft.world.entityEntityMAX_MOVEMENTS_HANDELED_PER_TICK- 在给定Tick中可以应用于实体的最大移动数。isInClouds- 返回实体的 Y 位置是否在云高度和其上方四个单位之间。teleportSpectators- 传送当前从玩家视角观看的旁观者。isFlyingVehicle- 返回载具是否可以飞行。clearMovementThisTick- 清除实体在本Tick中将进行的所有移动。
EntityAttachments#getAverage- 返回所有附着点的平均位置。ExperienceOrbawardWithDirection- 添加一个通过指定向量移动的经验球。unstuckIfPossible- 尝试查找并将球移动到空闲位置。
MobisWithinHome- 返回该位置是否在实体的限制半径内。canShearEquipment- 返回当前玩家是否可以从该生物上剪下装备。
net.minecraft.world.entity.ai.control.MoveControl#setWait- 将操作设置为WAIT。net.minecraft.world.entity.ai.goal.TemptGoalstopNavigation、navigateTowards- 处理向玩家的导航。$ForNonPathfinders- 一个引诱目标,它导航到想要的位置,而不是立即寻路。
net.minecraft.world.entity.ai.navigation.PathNavigation#canNavigateGround- 返回实体是否可以在陆地上寻路。net.minecraft.world.entity.ai.sensing.AdultSensorAnyType- 一个忽略实体是否与幼崽相同类型的成年传感器。net.minecraft.world.entity.animalHappyGhast- 一个代表快乐恶魂的实体。HappyGhastAi- 快乐恶魂的大脑。
net.minecraft.world.entity.decoration.ArmorStandsetArmorStandPose、getArmorStandPose、$ArmorStandPose- 处理盔甲架的姿势。
net.minecraft.world.entity.monster.GhastfaceMovementDirection- 旋转实体以面对其当前移动方向。$RandomFloatAroundGoal#getSuitableFlyToPosition- 获取恶魂应飞向的位置。
net.minecraft.world.entity.player.Inventory#SLOT_BODY_ARMOR、SLOT_SADDLE- 相应槽位的索引。net.minecraft.world.entity.projectile.ProjectileUtil#computeMargin- 根据其Tick计数计算要检查的给定实体的边界框边距。net.minecraft.world.item.componentItemAttributeModifiersforEach- 将消费者应用于槽位组内的所有属性。$Builder#add- 添加一个要应用于给定槽位组的属性,并带有显示。$Display- 定义属性修改器应如何在其工具提示中显示。$Default- 显示默认属性显示。$Hidden- 不显示任何属性信息。$OverrideText- 用提供的组件覆盖属性文本。
Equippable$BuildersetCanBeSheared- 设置装备是否可以从实体上剪下。setShearingSound- 设置从实体上剪下一件装备时要播放的声音。
ResolvableProfile#pollResolve- 返回存储的 id 或名称的配置文件。
net.minecraft.world.item.equipment.Equippable#harness- 表示要装备的挽具。net.minecraft.world.levelCollisionGettergetPreMoveCollisions- 返回一个包含给定边界框和未来移动方向上的实体和方块碰撞的形状的可迭代对象。getBlockCollisionsFromContext- 从给定的碰撞上下文中获取方块形状。
GameType#STREAM_CODECLevelprecipitationAt- 返回给定位置的降水。onBlockEntityAdded- 当方块实体被添加到等级时要运行的逻辑。
net.minecraft.world.level.blockBaseRailBlock#rotate- 在关联方向上旋转当前的铁轨形状。DriedGhastBlock- 一个代表干燥恶魂的方块。
net.minecraft.world.level.block.entity.trialspawner.TrialSpawner$FullConfig- 代表试炼的整个配置。net.minecraft.world.level.dimension.DimensionDefaultsCLOUD_THICKNESS- 云的方块厚度。OVERWORLD_CLOUD_HEIGHT- 主世界的云高度等级。
net.minecraft.world.level.levelgen.flat.FlatLayerInfo#heightLimited- 返回一个新的层信息,当前高度是否限制为指定值,只要该值不在最大范围内。net.minecraft.world.physAABBintersects- 返回BlockPos是否与此框相交。distanceToSqr- 返回边界框从其最远点的平方距离。
Vec3#rotateClockwise90- 将向量顺时针旋转 90 度(翻转 x 和 z 并反转新的 x 值)。
net.minecraft.world.phys.shapes.CollisionContextwithPosition- 返回实体的碰撞上下文及其底部 y 位置。
变更列表
com.mojang.blaze3d.platform.Window#setGuiScale、getGuiScale现在处理int而不是doublenet.mineraftDetectedVersion不再实现WorldVersionWorldVersion方法由于使用WorldVersion$Simple而使用记录命名模式getDataVersion->dataVersiongetId->idgetName->namegetProtocolVersion->protocolVersiongetPackVersion->packVersiongetBuildTime->buildTimeisStable->stable
net.minecraft.clientGameNarratorsayChat->sayChatQueuedsay->saySystemQueuedsayNow->saySystemNow
MinecraftgrabPanoramixScreenshot不再接受要设置的窗口宽度和高度disconnect()->disconnectWithProgressScreen
Screenshot#grab、takeScreenshot现在接受一个表示缩小因子的int
net.minecraft.client.main.GameConfig$QuickPlayData现在接受一个$QuickPlayVariantpath->logPathsingleplayer->variant带有$QuickPlaySinglePlayerDatamultiplayer->variant带有$QuickPlayMultiplayerDatarealms->variant带有$QuickPlayRealmsData- 对于
singleplayer、multiplayer、realms的 null 由带有$QuickPlayDisabled的variant表示
net.minecraft.client.data.models.ItemModelGenerators#generateWolfArmor->generateTwoLayerDyedItemnet.minecraft.client.gui.components.DebugScreenOverlay#render3dCrosshair现在接受当前的Cameranet.minecraft.client.gui.components.debugchart.ProfilerPieChartRADIUS现在是公开的CHART_Z_OFFSET->PIE_CHART_THICKNESS,现在是公开的
net.minecraft.client.multiplayerClientLevel$ClientLevelData#getClearColorScale->voidDarknessOnsetRange,不是一对一MultiPlayerGameMode#createPlayer现在接受一个Input而不是boolean
net.minecraft.client.player.LocalPlayer现在接受最后发送的Input而不是 shift 键的booleangetLastSentInput- 获取从服务器最后发送的输入。
net.minecraft.client.quickplay.QuickPlay#connect现在接受GameConfig$QuickPlayVariant而不是GameConfig$QuickPlayDatanet.minecraft.client.rendererDimensionSpecialEffects不再接受当前云级别以及是否有地面LightTexture#getTarget->getTexture
net.minecraft.client.renderer.blockentity.BlockEntityRenderer#shouldRenderOffscreen不再接受BlockEntitynet.minecraft.client.resourcesAbstractSoundInstance#sound现在是NullableSoundInstance#getSound现在是Nullable
net.minecraft.client.soundsSimpleSoundInstance#forMusic现在也接受float音量SoundEngine现在接受MusicManagerpause->pauseAllExcept,不是一对一play现在返回一个$PlayResult
SoundManager现在接受MusicManagerpause->pauseAllExcept,不是一对一play现在返回一个SoundEngine$PlayResult
net.minecraft.commands.argumentsResourceOrIdArgument现在接受一个任意编解码器,而不是Holder包装的值ERROR_INVALID->ERROR_NO_SUCH_ELEMENT,现在是公开的,不是一对一VALUE_PARSER->OPS,现在是公开的,不是一对一
ResourceSelectorArgument#getSelectedResources不再接受ResourceKey
net.minecraft.commands.functions.StringTemplatefromString不再接受行号isValidVariableName现在是公开的
net.minecraft.data.recipes.RecipeProvider#colorBlockWithDye->colorItemWithDye,现在接受RecipeCategorynet.minecraft.gametest.framework.GameTestInfo#prepareTestStructure现在可为 nullnet.minecraft.networkConnection#send现在接受一个ChannelFutureListener而不是PacketSendListenerFriendlyByteBuf#readJsonWithCodec->readLenientJsonWithCodecPacketSendListener现在是一个类,其方法返回ChannelFutureListener而不是PacketSendListeneronSuccess、onFailure已移除
net.minecraft.network.codecByteBufCodecs#fromCodec现在有一个接受某些 ops 和一个编解码器的重载StreamCodec#composite现在有一个接受十个参数的重载
net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket现在是一个记录net.minecraft.network.protocol.gameClientboundChangeDifficultyPacket现在是一个记录ClientboundCommandsPacket现在接受一个$NodeInspectorgetRoot现在是泛型的,接受一个$NodeBuilder$NodeBuilder- 一个给定命令的构建器。$NodeInspector- 一个检查给定命令节点信息的代理。
ServerboundChangeDifficultyPacket现在是一个记录
net.minecraft.server.ReloadableServerRegistries$Holder#lookup返回一个HolderLookup$Providernet.minecraft.server.network.ServerCommonPacketListenerImpl#send现在接受一个ChannelFutureListener而不是PacketSendListenernet.minecraft.sounds.Music现在是一个记录net.minecraft.stats.RecipeBookSettingsgetSettings现在是公开的$TypeSettings现在是公开的
net.minecraft.world.entityAreaEffectCloud#setParticle->setCustomParticleEntitycheckSlowFallDistance->checkFallDistanceAccumulationcollidedWithFluid、collidedWithShapeMovingFrom现在是公开的canBeCollidedWith现在接受与其碰撞的实体spawnAtLocation现在有一个接受Vec3作为偏移位置的重载removeLatestMovementRecordingBatch->removeLatestMovementRecording
EntityReference现在是 finalExperienceOrb现在有一个接受两个向量作为位置和移动的重载FlyingMob被调用LivingEntity#travelFlying取代LivingEntity#canBreatheUnderwater不再是finalMobrestrictTo->setHomeTogetRestrictCenter->getHomePositiongetRestrictRadius->getHomeRadiusclearRestriction->clearHomehasRestriction->hasHome
net.minecraft.world.entity.ai.attributesAttributeInstancesave->pack、$Packed;不是一对一load->apply,不是一对一
AttributeMapsave->pack;不是一对一load->apply,不是一对一
net.minecraft.world.entity.ai.behaviorAnimalPanic现在有接受半径或位置获取器的重载BabyFollowAdult#create现在返回一个OneShot<LivingEntity>,并且可以接受一个boolean表示是否瞄准眼睛位置EntityTracker现在可以接受一个boolean表示是否瞄准眼睛位置FollowTemptation现在有一个重载,检查实体是否需要跟踪实体的眼睛高度。
net.minecraft.world.entity.ai.goal.TemptGoal现在有一个接受停止距离的重载mob现在是一个MobspeedModifier现在是protected
net.minecraft.world.entity.ai.memory.MemoryModuleType#NEAREST_VISIBLE_ADULT现在持有LivingEntitynet.minecraft.world.entity.ai.navigationFlyingPathNavigation、GroundPathNavigation#setCanOpenDoors->PathNavigation#setCanOpenDoors
net.minecraft.world.entity.ai.sensing.AdultSensor现在查找LivingEntitysetNearestVisibleAdult现在是protected
net.minecraft.world.entity.animal.*Variants#selectVariantToSpawn->entity.variant.VariantUtils#selectVariantToSpawn,不是一对一net.minecraft.world.entity.animal.Fox#isJumping->LivingEntity#isJumpingnet.minecraft.world.entity.animal.horse.AbstractHorseisJumping->LivingEntity#isJumpingsetStanding现在接受一个int而不是boolean作为站立计数器false逻辑已移至clearStanding
net.minecraft.world.entity.monsterGhast现在实现Mob$GhastLookGoal现在是公开的,接受一个Mob$GhastMoveControl现在是公开的,接受一个布尔值表示移动时是否应小心,以及一个提供的布尔值表示恶魂是否应停止移动$RandomFloatAroundGoal现在是public,接受一个Mob和一个方块距离
Phantom现在实现Mob
net.minecraft.world.entity.playerAbilitiesaddSaveData->pack、$Packed;不是一对一loadSaveData->apply,不是一对一
Player不再接受BlockPos和 y 旋转
net.minecraft.world.entity.projectileAbstractThrownPotion#onHitAsPostion现在接受一个HitResult而不是可为 null 的EntityEyeOfEnder#signalTo现在接受一个Vec3而不是BlockPosProjectileownerUUID、cachedOwner->owner,现在是 protected;不是一对一setOwner现在有一个接受EntityReference的重载
ProjectileUtilDEFAULT_ENTITY_HIT_RESULT_MARGIN现在是公开的getEntityHitResult现在接受一个Projectile而不是Entity
net.minecraft.world.item.ItemStackforEachModifier现在接受一个提供修改器显示的TriConsumerhurtAndBreak现在有一个重载,从InteractionHand获取EquipmentSlot
net.minecraft.world.item.equipment.Equippable现在接受装备是否可以从实体上剪下以及剪下时要播放的声音net.minecraft.world.level.BlockGetterforEachBlockIntersectedBetween现在返回一个布尔值,表示在相交区域中访问的每个方块是否可以成功访问$BlockStepVisitor#visit现在返回是否可以成功移动到该位置
net.minecraft.world.level.block.AbstractCauldronBlock#SHAPE现在是 protectednet.minecraft.world.level.block.entityBlockEntity#getNameForReporting现在是公开的SignBlockEntity#executeClickCommandsIfPresent现在接受一个ServerLevel而不是Level,参数重新排序StructureBlockEntity#saveStructure现在接受一个要忽略的方块列表
net.minecraft.world.level.block.entity.trialspawnerTrialSpawner现在接受一个$FullConfiggetConfig->activeConfigget*Config->*configgetData->getStateData
TrialSpawnerData->TrialSpawnerStateData,序列化形式为TrialSpawnerStateData$Packed,不是一对一
net.minecraft.world.level.block.sounds.AmbientDesertBlockSoundsPlayer#playAmbientBlockSounds已拆分为playAmbientSandSounds、playAmbientDryGrassSounds、playAmbientDeadBushSounds、shouldPlayDesertDryVegetationBlockSounds;不是一对一net.minecraft.world.level.dimension.DimensionType现在接受一个可选的整数表示云高度等级net.minecraft.world.level.entityPersistentEntitySectionManager#processPendingLoads现在是公开的UUIDLookup#getEntity现在可以返回 null
net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate#fillFromWorld现在接受一个要忽略的方块列表,而不是单个Blocknet.minecraft.world.level.storage.DataVersion现在是一个记录net.minecraft.world.phys.shapes.CollisionContext#placementContext现在接受一个Player而不是Entity
移除列表
net.minecraft.client.Minecraft#disconnect(Screen)net.minecraft.client.rendererDimensionSpecialEffects#getCloudHeight、hasGroundLevelRenderer#updateGlobalBlockEntities
net.minecraft.client.renderer.texture.AbstractTexturedefaultBlursetFilter
net.minecraft.network.chat.Component$Serializer、$SerializerAdapternet.minecraft.network.protocol.game.ServerboundPlayerCommandPacket$Action#*_SHIFT_KEYnet.minecraft.server.ReloadableServerRegistries$Holder#getKeysnet.minecraft.server.players.PlayerList#getPlayerForLoginnet.minecraft.statsRecipeBookSettings#read、writeServerRecipeBook#toNbt、fromNbt
net.minecraft.utilGsonHelper#fromNullableJson(..., boolean)、fromJson(..., boolean)LowerCaseEnumTypeAdapterFactory
net.minecraft.world.entity.ai.attributes.AttributeInstance#ID_FIELD、TYPE_CODECnet.minecraft.world.entity.animal.horse.AbstractHorse#setIsJumpingnet.minecraft.world.entity.animal.sheep.Sheep#getColornet.minecraft.world.entity.monster.Drowned#waterNavigation、groundNavigationnet.minecraft.world.entity.projectile.Projectile#findOwner、setOwnerThroughUUIDnet.minecraft.world.level.Level#disconnect()net.minecraft.world.level.blockAbstractCauldronBlock#isEntityInsideContentTerracottaBlock
net.minecraft.world.level.block.entity.trialspawner.TrialSpawner*_CONFIG_TAG_NAMEcodec
net.minecraft.world.level.dimension.DimensionType#parseLegacy