Creators-of-Create / Create

[Forge Mod] Building Tools and Aesthetic Technology
MIT License
2.69k stars 867 forks source link

(Game Crashed) NullPointer onto render error #3423

Open FacrGetr opened 1 year ago

FacrGetr commented 1 year ago

Describe the Bug

I built a flying machine (also now its a world eater) some day when I done mineing i close the game while machine's unloading cargos after that every time I open that savefile it crashs immediately

BUT, cuz crash said its render error, I manage to sort it out and save my save I shorten my render distence and luckly machine's just barely outside of it after stop it from keep unloading cargos, no crashs anymore

and also, later, my friend join my server while machine's unloading his game crashed with the same render error, yet I have no problems at all

Reproduction Steps

  1. have a flying machine (world eater)
  2. machine is now unloading cargos
  3. one player (including yourself) tries load in that savefile
  4. machine itself is within player's render range

Expected Result

NullPointer: entity "c" is null → Render Error → Game crashed

(but won't crash if you already loaded in the game before starts unloading cargos)

Screenshots and Videos

my child, I mean, my machine image

unloading image

Crash Report or Log

https://pastebin.com/8XCEjVsP

Operating System

Windows 10

Mod Version

0.5.0c

Minecraft Version

1.18.2

Forge Version

40.1.14

Other Mods

only [✔️] create-mc1.18.2_v0.5.0c [✔️] flywheel-forge-1.18-0.6.4

Additional Context

if needed, I can provide my savefiles, both before and after escaped this crash situation

FacrGetr commented 1 year ago

NEW DISCOVERY!

image

after removing upper layer's drills no crashes any more, this bug is fixed (kind of?)

hypermx commented 1 year ago

I also got the same issue, but instead, it's with a contraption (drills) on a mechanical bearing that's already started, so I am unable to log in without an instant crash.

My contraption worked fine, with 1024 chests (purely coincidental), but as soon as I added another row and started the contraption, it started the crash cycle.

If you want the world download, let me know as it can be arranged.

Crashlog: https://bytebin.lucko.me/pvVh3nEo2C

Zivodor commented 1 year ago

I looked into the code surrounding this area and please correct me if I am wrong, but I think this might be a race condition with the renderer and the assembly of the offending contraption. Consider the following:

The code that is erroring out is this line in the ContraptionRenderingWorld.java file:

ContraptionHandler.loadedContraptions.get(world)
                .values()
                .stream()
                .map(Reference::get)
                .filter(Objects::nonNull)
                .map(AbstractContraptionEntity::getContraption)
                .forEach(this::getRenderInfo);

when we call getRenderInfo() it performs this action which results in a null reference exception:

int entityId = c.entity.getId();

Specifically, We can conclude that the entity is getting initialized and added to the world because if it was null then the filter(Objects::nonNull) code would filter it out, but the contraption is not or has not been yet assigned. The major difference for why this doesn't happen every time for every contraption, as far as I can tell, is the size of the contraption being assembled. Tracking back to the CartAssemblerTileEntity.java and the assemble() method we see the contraption gets created on line 128

MountedContraption contraption = new MountedContraption(mode);

Then on line 130 it gets assembled.

if (!contraption.assemble(world, pos))
    return;

Finally, after it is assembled, some more actions are performed finally, on line 161 the entity is created.

OrientedContraptionEntity entity = OrientedContraptionEntity.create(world, contraption, initialOrientation);

When the OrientedContraptionEntity.create() call is executed, the entity.setContraption() method is called almost immediately and inside that the onEntityCreated() call is executed if the contraption is not null, which we know it is initialized and therefore not null, and if the level is not clientside, which I cannot confirm.

If we assume that the level is not client side, then the onEntityCreated() method is called and the contraption should be successfully assigned to the entity and there should be no null reference exception, but this is not what is happening.

The gap in my knowledge right now, is that I am unsure how the entity gets registered within the world. If it works how I suspect, being that as soon as an entity is created it is registered in the world, it would mean that if the render tick is happening too fast then its possible to get an entity with no related contraption because it is still being constructed/assigned.

To verify this, I created a fresh world with no contraptions, created a large contraption and then put it into a minecart, the world crashed immediately. To slow down that render thread to give the entity enough time to initialize, I created dozens of contraptions of varying sizes and then tried to put the large one into a cart, there was no crash. I am fairly confident that this is a race condition with the render thread and whatever process registers an entity within the world.

I am not a Minecraft mod developer though, nor a java developer, but I have spent the last 10 years debugging code and fixing difficult bugs including race conditions and this has all the tell tale signs of a race condition.

As a fix, I suggest someone who is set up to debug and test this simply adds a filter before the forEach loop that filters out entities with null contraptions as they have not yet been initialized and therefore are not ready to render.

Again though, I am not a Minecraft mod developer, and my experience solely comes from my time as a software developer and I made a whole bunch of assumption here. Feel free to correct me, I just really want to build my giant-ass world eater without my world crashing and forcing me to go into the NBT data to delete the offending entity so I thought I would lend an external view to the problem as it seems this has been going on for a while.