创建火车碰撞修复
修复了机械动力模组的列车因无限位置可能导致服务器崩溃的问题。
Create Train Crash Fix
修复当列车具有无限坐标时可能发生的崩溃(即使列车数据文件中并未显示为无限)
一个非常简单的模组
给极客的信息(如何修复的)
首先我们得看一下问题所在:列车在列车数据文件中并没有无效的坐标。这意味着问题一定出在序列化过程中的某个地方。问题 #6795 的创建
2024年8月7日
我添加了两个 mixin 注入。一个在 createEntity(来自 create)上,另一个在 readNbt(来自 minecraft)上。
@Mixin(Carriage.DimensionalCarriageEntity.class)
public abstract class DimensionalCarriageMixin {
@Shadow public Vec3d positionAnchor;
@Inject(at = @At("HEAD"), method = "createEntity")
private void sendEntityInfo(World level, boolean loadPassengers, CallbackInfo ci) {
CreateTrainFix.LOGGER.info(positionAnchor.toString());
if (!Double.isFinite(positionAnchor.getX()) || !Double.isFinite(positionAnchor.getY()) || !Double.isFinite(positionAnchor.getZ())) {
CreateTrainFix.LOGGER.info("Train failed to be created, because of infinity checks.");
}
}
}
@Mixin(Entity.class)
public abstract class EntityMixin {
@Shadow public abstract double getX();
@Shadow public abstract double getY();
@Shadow public abstract double getZ();
@Shadow public abstract Vec3d getPos();
@Inject(method = "readNbt", at = @At(value = "INVOKE", target = "Ljava/lang/Double;isFinite(D)Z"))
private void checkFiniteDebug(NbtCompound nbt, CallbackInfo ci) {
if (!Double.isFinite(getX()) || !Double.isFinite(getY()) || !Double.isFinite(getZ())) {
CreateTrainFix.LOGGER.info("INFINITE location " + getPos());
}
}
}
这是记录下来的日志,之后它不可避免地崩溃了。坐标不知为何是无效的,而在 createEntity 方法中却仍然是正常的。
[18:18:15] [Server thread/INFO]: (225.5, 58.0, -165.8600004762411)
[18:18:15] [Server thread/INFO]: INFINITE location (NaN, NaN, NaN)
经过更彻底的检查后发现,NBT 传入时已经是 NaN,而 create_tracks.dat 文件中却不包含任何类似的内容。create_tracks.dat 检查 见第 123 行(嘿,有趣的数字)
~2.5 个月后 IThundxr 提出了在代码中添加类似以下内容的方案:
serialisedEntity.remove("Pos");
serialisedEntity.put("Pos", newDoubleList(positionAnchor.x(), positionAnchor.y(), positionAnchor.z()));
这就是最终的概念,并且它生效了!
这是所添加内容的最终版本
@Inject(at = @At("HEAD"), method = "createEntity")
private void createTrainFix$fixEntity(World level, boolean loadPassengers, CallbackInfo ci) {
try {
// RefUtil is a class with a few methods to access private fields from the superclass.
NbtCompound serialisedEntity = (NbtCompound) RefUtil.getPrivateFieldValue(this$0, "serialisedEntity");
serialisedEntity.remove("Pos");
serialisedEntity.put("Pos", newDoubleList(positionAnchor.x, positionAnchor.y, positionAnchor.z));
// Set the value again
RefUtil.setFieldValue(this$0, "serialisedEntity", serialisedEntity);
} catch (NoSuchFieldException | IllegalAccessException e) {
// If this all didn't work, throw an error
CreateTrainFix.LOGGER.error("(CreateTrainFix) Failed to fix train position");
throw new RuntimeException(e);
}
// Final check
if (!Double.isFinite(positionAnchor.getX()) || !Double.isFinite(positionAnchor.getY()) || !Double.isFinite(positionAnchor.getZ())) {
CreateTrainFix.LOGGER.info("Train failed to be created, because of infinity checks.");
}
}
正在加载版本记录…
正在加载评论…
评论在新手盒子客户端中发表,这里同步展示。