Conflict With EnergonRelics Structure Generation
TheBrokenRail opened this issue ยท 8 comments
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.
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
Do you know if there is any supported way of scheduling a block to tick after the chunk is generated?
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()
Will the scheduled tick be ran on the main server thread after chunk generation?
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
}
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.