Download Create Train Crash Fix — Minecraft Mods — ModStock

Create Train Crash Fix

Active

Downloads

1

Last update

7 months ago

Versions

1.20.1
Server
Fabric
Quilt
Technological

Create Train Crash Fix

Fixes the crash that may occur when a train has infinite positions (even if the train data file doesn't show an infinite)

a very simple mod

Info for nerds (how it was fixed) First we've got to take a look at the issue: the train does not have an invalid position in the train data file. That means it has to be somewhere in the serialisation. --- Creation of issue [#6795](https://github.com/Creators-of-Create/Create/issues/6795)\ August 7th, 2024 I added two mixin injections. One at `createEntity` (from create) and `readNbt` (from minecraft). ```java @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](https://gist.github.com/JXSnack/e63a53cad8c1886db637cbcb82f716de) see line 123 (heh, funny number) --- ~2.5 months later IThundxr proposes the idea of adding something similar to the following into the code: ```java serialisedEntity.remove("Pos"); serialisedEntity.put("Pos", newDoubleList(positionAnchor.x(), positionAnchor.y(), positionAnchor.z())); ``` This is the final concept and it works! --- This is the final version of what has been added ```java @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."); } } ```
Project members
JXSnack

JXSnack

Developer