Create

Create

101M Downloads

Server crashes because a train has an invalid position

JXSnack opened this issue · 19 comments

commented

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.

create_tracks_backup.dat

Crash Report

https://mclo.gs/ZjzsCKV

commented

@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.

commented

Triage note: occurs on forge aswell

commented

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

commented

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)

commented

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.

commented

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
commented

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

commented

It has now infected the overworld. (29 players affected)

commented

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.

commented

The issue lies within base create

commented

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?

commented

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

commented

Yikes.

commented

sadly cannot test since the world is on fabric

commented

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

commented

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

commented

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()));
commented

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)