Lithium (Fabric)

Lithium (Fabric)

22M Downloads

Conflict With EnergonRelics Structure Generation

TheBrokenRail opened this issue ยท 8 comments

commented

Expected Behavior

The EnergonRelics structure generates.

Actual Behavior

java.util.ConcurrentModificationException
	at java.base/java.util.HashMap.computeIfAbsent(Unknown Source)
	at me.jellysquid.mods.lithium.common.world.scheduler.LithiumServerTickScheduler.addScheduledTick(LithiumServerTickScheduler.java:293)
	at me.jellysquid.mods.lithium.common.world.scheduler.LithiumServerTickScheduler.method_8675(LithiumServerTickScheduler.java:124)
	at net.minecraft.class_1951.method_8676(class_1951.java:9)
	at com.thebrokenrail.energonrelics.block.structure.StructureGeneratorBlock.schedule(StructureGeneratorBlock.java:108)
	at com.thebrokenrail.energonrelics.block.structure.StructureGeneratorPiece.method_14931(StructureGeneratorPiece.java:53)
	at net.minecraft.class_3449.method_14974(class_3449.java:76)
	at net.minecraft.class_1959.method_28401(class_1959.java:356)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(Unknown Source)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(Unknown Source)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
	at java.base/java.util.PrimitiveIterator$OfLong.forEachRemaining(Unknown Source)
	at it.unimi.dsi.fastutil.longs.LongIterator.forEachRemaining(LongIterator.java:53)
	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Unknown Source)
	at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
	at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
	at java.base/java.util.stream.ReferencePipeline.forEach(Unknown Source)
	at net.minecraft.class_1959.method_8702(class_1959.java:355)
	at net.minecraft.class_2794.method_12102(class_2794.java:220)
	at net.minecraft.class_2806.method_12151(class_2806.java:89)
	at net.minecraft.class_2806.method_12154(class_2806.java:219)
	at net.minecraft.class_3898.method_17225(class_3898.java:568)
	at com.mojang.datafixers.util.Either$Left.map(Either.java:38)
	at net.minecraft.class_3898.method_17224(class_3898.java:562)
	at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(Unknown Source)
	at java.base/java.util.concurrent.CompletableFuture$Completion.run(Unknown Source)
	at net.minecraft.class_3900.method_17634(class_3900.java:58)
	at net.minecraft.class_3846.method_16907(class_3846.java:94)
	at net.minecraft.class_3846.method_16900(class_3846.java:137)
	at net.minecraft.class_3846.run(class_3846.java:105)
	at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(Unknown Source)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(Unknown Source)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(Unknown Source)
	at java.base/java.util.concurrent.ForkJoinPool.scan(Unknown Source)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(Unknown Source)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(Unknown Source)

Reproduction Steps

Start a server with EnergonRelics and Lithium.

Why

EnergonRelics generates structures by generating a generator block, the scheduling it for next tick. The next tick the generator block, generates the structure. This makes sure the structure can generate properly. It seems scheduling a block with the blockTickScheduler is causing an error with Lithium.

commented

I think the problem is that your mod is unlike vanilla modifying the scheduled ticks of the world (not those of the generating chunk) on a worldgen thread. The vanilla tick scheduler is not threadsafe either, so this is a problem with your mod. Please refer to this issue I commented on your repo earlier https://gitea.thebrokenrail.com/TheBrokenRail/EnergonRelics/issues/2

If you think I am wrong about the above, please explain why

commented

Hmm, sorry I didn't see that issue yet!

commented

Do you know if there is any supported way of scheduling a block to tick after the chunk is generated?

commented

Yes. Just schedule any tick. For example the NetherFortressGenerator.CorridorExit does structureWorldAccess.getFluidTickScheduler().schedule(blockPos2, Fluids.LAVA, 0);
I believe you can do something similar. It is important that you don't use the toServerWorld()

commented

Will the scheduled tick be ran on the main server thread after chunk generation?

commented

you have to replace your schedule call block.schedule(world.toServerWorld(), pos);
with block.schedule(world, pos)

and change the schedule method:

    public void schedule(StructureworldAccess structureWorldAccess, BlockPos pos) {
        structureWorldAccess.getBlockTickScheduler().schedule(pos, this, 0); //parameters of schedule here might have to be changed
    }

commented

The scheduled tick should be run when the chunk is becoming loaded, and it will be run on the main thread
I am not 100% sure this works, but that is how I believe vanilla does it.

commented

It worked! Thanks for the help!