Server crashes because a train has an invalid position
JXSnack opened this issue · 19 comments
Context
This is an issue I have pretty often, but the fix I made (CreateTrainFix) usually works. This time it did not. It occurred when a player entered the nether dimension, promptly loading a train with invalid data and crashing the server. I have no idea which train is causing this.
Crash Report
@JXSnack That's wild. Could I possibly have a world download and a list of all current addons/mods you have installed on the server? I would like to do some testing.
Whilst digging for some context, I found out that the error is not because the position is null
, but rather because it's too high.
// class net.minecraft.entity.Entity
// Yarn Mappings
// Line 2272
if (!Double.isFinite(this.getX()) || !Double.isFinite(this.getY()) || !Double.isFinite(this.getZ())) {
throw new IllegalStateException("Entity has invalid position");
The issue arises in Create here:
// class com.simibubi.create.content.trains.entity.Carriage.DimensionalCarriageEntity
// Line 794
private void createEntity(World level, boolean loadPassengers) {
Entity entity = EntityType.getEntityFromNbt(serialisedEntity, level)
.orElse(null);
Edit:
I might be wrong here though, I checked all train positions and could not find anything remotely close to the maximum double size
I added two mixin injections. One at createEntity
(from create) and readNbt
(from 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());
}
}
}
This is what's being logged, after which it inevitably crashes. The coordinates are somehow invalid, while still being normal in the createEntity
method.
[18:18:15] [Server thread/INFO]: (225.5, 58.0, -165.8600004762411)
[18:18:15] [Server thread/INFO]: INFINITE location (NaN, NaN, NaN)
After more thorough checking the NBT already comes as NaN, while the create_tracks.dat
file doesn't contain anything like that. create_tracks.dat check see line 123 (heh, funny number)
Sorry if I'm being a little stupid here, as I have no knowledge in coding, but why does it say in the first line 'loadPassengers' when it's not really possible for passengers to be inside the train unless you force villagers or something inside of train cars. In my opinion that's a little bit odd.
Sorry if I'm being a little stupid here, as I have no knowledge in coding, but why does it say in the first line 'loadPassengers' when it's not really possible for passengers to be inside the train unless you force villagers or something inside of train cars. In my opinion that's a little bit odd.
You can see the arguments the method is expecting. A boolean is a true or false statement. When the method is called it expects an argument of the type World
and of the type boolean
. The boolean determines whether passengers should be loaded if that makes sense.
Found the location of the entity that is crashing the server. (nether dimension)
[18:06:52] [Server thread/INFO]: (225.5, 58.0, -165.8600004762411)
[18:06:53] [Server thread/ERROR]: Encountered an unexpected exception
net.minecraft.class_148: Loading entity NBT
at net.minecraft.server.MinecraftServer.method_3813(MinecraftServer.java:901) ~[server-intermediary.jar:?]
at net.minecraft.class_3176.method_3813(class_3176.java:283) ~[server-intermediary.jar:?]
at net.minecraft.server.MinecraftServer.method_3748(MinecraftServer.java:824) ~[server-intermediary.jar:?]
at net.minecraft.server.MinecraftServer.method_29741(MinecraftServer.java:671) ~[server-intermediary.jar:?]
at net.minecraft.server.MinecraftServer.method_29739(MinecraftServer.java:265) ~[server-intermediary.jar:?]
at java.lang.Thread.run(Thread.java:840) ~[?:?]
Caused by: java.lang.IllegalStateException: Entity has invalid position
at net.minecraft.class_1297.method_5651(class_1297.java:1897) ~[server-intermediary.jar:?]
at net.minecraft.class_1299.method_17839(class_1299.java:549) ~[server-intermediary.jar:?]
at net.minecraft.class_156.method_17974(class_156.java:513) ~[server-intermediary.jar:?]
at net.minecraft.class_1299.method_5892(class_1299.java:548) ~[server-intermediary.jar:?]
at com.simibubi.create.content.trains.entity.Carriage$DimensionalCarriageEntity.createEntity(Carriage.java:795) ~[create-fabric-0.5.1-f-build.1417+mc1.20.1.jar:?]
at com.simibubi.create.content.trains.entity.Carriage.manageEntities(Carriage.java:275) ~[create-fabric-0.5.1-f-build.1417+mc1.20.1.jar:?]
at com.simibubi.create.content.trains.entity.Carriage.travel(Carriage.java:201) ~[create-fabric-0.5.1-f-build.1417+mc1.20.1.jar:?]
at com.simibubi.create.content.trains.entity.Train.tick(Train.java:372) ~[create-fabric-0.5.1-f-build.1417+mc1.20.1.jar:?]
at com.simibubi.create.content.trains.GlobalRailwayManager.tickTrains(GlobalRailwayManager.java:226) ~[create-fabric-0.5.1-f-build.1417+mc1.20.1.jar:?]
at com.simibubi.create.content.trains.GlobalRailwayManager.tick(GlobalRailwayManager.java:201) ~[create-fabric-0.5.1-f-build.1417+mc1.20.1.jar:?]
at com.simibubi.create.foundation.events.CommonEvents.onServerWorldTick(CommonEvents.java:126) ~[create-fabric-0.5.1-f-build.1417+mc1.20.1.jar:?]
at net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents.lambda$static$6(ServerTickEvents.java:63) ~[fabric-lifecycle-events-v1-2.2.2+1802ada577-64bb13225b65065c.jar:?]
at net.minecraft.class_3218.handler$bic000$fabric-lifecycle-events-v1$endWorldTick(class_3218.java:4740) ~[server-intermediary.jar:?]
at net.minecraft.class_3218.method_18765(class_3218.java:396) ~[server-intermediary.jar:?]
at net.minecraft.server.MinecraftServer.method_3813(MinecraftServer.java:897) ~[server-intermediary.jar:?]
... 5 more
It's becoming a pretty big problem right now as six players have been affected by it and a large portion of the nether dimension is impossible to visit
Unfortunate :( Have you tried removing any create addon mods if you have any for the server? Try to find the offending one if there are addons.
I've once had a similar issue with a train crash at a nether portal. While you would disconnect on the server when getting nearby the crashed trains. It was completely fine to load the world in singleplayer, get the trains back on track and move the world back to the server.
Worth a shot to load the world in singleplayer if it's possible?
That’s a nice idea, but we have no idea where exactly those trains are located at and we’d need a minimum 18GB ram computer to load the world (at least that’s what the server uses when loading the world)
World size is 32GB
not sure if its related but I get the positional errors on trains with obscene Y values and noticed at the same time elevators with positions completely off the map as well, the elevators can be called back up/down but the trains cannot
The bug with elevators has been fixed on 0.5.1h
not sure if its related but I get the positional errors on trains with obscene Y values and noticed at the same time elevators with positions completely off the map as well, the elevators can be called back up/down but the trains cannot
I'm unable to reproduce this reliably so would you be able to in createEntity inject the following at HEAD and see if it still occurs?
serialisedEntity.remove("Pos");
serialisedEntity.put("Pos", newDoubleList(positionAnchor.x(), positionAnchor.y(), positionAnchor.z()));
Hello! Sorry for not responding earlier I've been busy with some irl stuff. Anyhow, thanks a lot for this idea! I've made an addon which fixes this using your method.
@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.");
}
}
I'll publish this to Modrinth for anyone else who might be encountering this issue.
Link: (not approved yet)
your patch should look like this instead, using reflection there isn't needed, https://github.com/Layers-of-Railways/RailwaysTweaks/blob/main/src/main/java/dev/ithundxr/railwaystweaks/mixin/compat/create/Carriage$DimensionalCarriageEntityMixin.java