
创建碰撞 修复崩溃
修复了 Create 6.0.10 服务器崩溃问题,该问题是由于移动装置(滑轮/钻机采石场)抛出空指针异常"mf.axis"为null
Create Collision Crashfix
一个微小的单 Mixin 热修复补丁,用于解决 Minecraft 1.21.1(NeoForge)下 Create 6.0.10 中导致服务器崩溃的致命错误。
问题
移动的 Create 机械装置可能会硬崩溃服务器 tick 循环:
java.lang.NullPointerException: Cannot read field "x" because "mf.axis" is null
at com.simibubi.create.foundation.collision.ContinuousOBBCollider.collideMany(ContinuousOBBCollider.java:153)
at com.simibubi.create.content.contraptions.ContraptionCollider.collideEntities(ContraptionCollider.java:166)
at com.simibubi.create.content.contraptions.ContraptionHandler.tick(ContraptionHandler.java:54)
Description: Exception in server tick loop
一旦发生,世界通常会在加载时崩溃循环,因为违规的机械装置每次 tick 都会触发同样的崩溃。
触发条件: 移动机械装置的碰撞检测遇到一种退化、零距离的情况——实体边界框的中心在所有轴上都恰好位于机械装置方块的中心。最常触发此问题的现实场景是绳索滑轮 + 钻头采石场(例如,滑轮在中心列,周围是钻头阵列),但旋转轴承、带有锯子的树场以及其他类似设置也可能触发。
这是 Create 上游的一个漏洞,仅出现在 6.0.10 中(6.0.9 不受影响)。官方的修复方案是 Create PR #10301,计划在 6.0.11 中发布,目前尚未发布。对于大多数整合包来说,降级到 6.0.9 并不可行,因为许多 Create 附属模组需要 create >= 6.0.10。
相关的上游报告
- Issue #10218(追踪)— https://github.com/Creators-of-Create/Create/issues/10218
- Issue #10278 — 当实体 AABB 中心与机械装置方块中心重合时
mf.axis为空 — https://github.com/Creators-of-Create/Create/issues/10278 - Issue #10344 — https://github.com/Creators-of-Create/Create/issues/10344
- Issue #10353 — https://github.com/Creators-of-Create/Create/issues/10353
- Issue #10378 — 机械装置碰撞 NPE 边缘情况 — https://github.com/Creators-of-Create/Create/issues/10378
- Issue #10479 — 树场加载时导致服务器崩溃 — https://github.com/Creators-of-Create/Create/issues/10479
- 上游修复:PR #10301 — https://github.com/Creators-of-Create/Create/pull/10301
修复内容——更改了什么以及为什么有效
在 Create 的 ContinuousSeparationManifold#separate 方法内部,分离轴 axis(以及 normalAxis)仅在测试距离非零时被记录:
if (distance != 0.0 && -diff <= Math.abs(this.separation)) {
this.axis = axis; // 在完美重合、中心对齐的情况下永远不会执行
this.separation = separation;
}
在完美重合的重叠情况下,每次分离测试都使用 distance == 0,因此 axis/normalAxis 保持为 null。collideMany 随后会解引用它们(mf.axis.x),导致服务器崩溃。
本模组在 collideMany 中为这两个字段读取添加了空值保护(使用 MixinExtras 的 @WrapOperation)。当记录的轴为 null 时,它返回 Vec3.ZERO,因此退化碰撞在该 tick 中贡献零推力而不是崩溃。下一个 tick 中实体已经移动了亚体素级距离,会存在有效的分离轴,碰撞会正常解析——没有实体卡住,没有穿模。
@WrapOperation(
method = "collideMany",
at = @At(value = "FIELD",
target = "L.../ContinuousOBBCollider$ContinuousSeparationManifold;axis:Lnet/minecraft/world/phys/Vec3;",
opcode = Opcodes.GETFIELD),
remap = false)
private static Vec3 guardAxis(@Coerce Object manifold, Operation<Vec3> original) {
Vec3 value = original.call(manifold);
return value == null ? Vec3.ZERO : value; // 对 normalAxis 同样处理
}
为什么特别使用 Vec3.ZERO,以及为什么它是安全的:
- 当
axis为 null 时,配对的separation标量是Double.MAX_VALUE。如果使用非零的 fallback 轴,计算axis * MAX_VALUE会将实体弹射到无穷远。0 * MAX_VALUE == 0干净地中和了它——不产生 NaN,不产生瞬移。 axis和normalAxis是collideMany中唯一可为 null 的Vec3读取(stepSeparationAxis是final且非 null;collision*字段是原生double类型),因此这覆盖了该方法中所有空指针解引用的位置。- 该保护仅在 null/退化路径上激活。所有正常碰撞在字节码层面上完全不变。
此修复反映了上游 PR #10301 的意图;它故意设计得非常精准,因此不会影响非退化的物理行为。
兼容性
- Minecraft 1.21.1 · NeoForge 21.1.x
- 仅限 Create 6.0.10。 此模组硬性绑定到
create [6.0.10]。在任何其他 Create 版本上,它会拒绝加载,并显示清晰的requires create [6.0.10]消息——这也是在提醒你在 Create 6.0.11(包含官方修复)发布后移除本模组。 - 客户端和服务器端都需要安装(版本必须匹配)。
- 不对任何附属模组的类进行 Mixin——它仅保护 Create 核心内部的两个字段读取,因此与那些对
ContraptionCollider进行 Mixin 的附属模组(如 Create Big Cannons、Aeronautics、Sable 等)共存。
许可证
MIT。不包含任何 Create 代码——仅包含一个 Mixin 和元数据。
正在加载版本记录…
正在加载评论…
评论在新手盒子客户端中发表,这里同步展示。