McJtyMods / InControl

Be In Control of Mob Spawns and others
MIT License
46 stars 17 forks source link

RuleCache.CachePerWorld.count(IWorld) may cause java.util.ConcurrentModificationException #387

Closed qzwxsaedc closed 1 year ago

qzwxsaedc commented 1 year ago

https://github.com/McJtyMods/InControl/blob/235498f73827e0fcc256b0546f43ddbdd599e24f/src/main/java/mcjty/incontrol/rules/RuleCache.java#L208

HashMap.computeIfAbsent() might be modify current map if the specified key is not already associated with a value (or is mapped to null). So you can't use it in foreach.

For example:

[27Jun2023 17:28:34.858] [Worker-Main10/ERROR] [net.minecraftforge.eventbus.EventBus/EVENTBUS]: Exception caught during firing event: null
    Index: 10
    Listeners:
        0: HIGH
        1: ASM: class me.shedaniel.architectury.event.forge.EventHandlerImplCommon event(Lnet/minecraftforge/event/entity/living/LivingSpawnEvent$CheckSpawn;)V
        2: NORMAL
        3: ASM: class net.pavocado.exoticbirds.ForgeEventSubscriber checkSpawns(Lnet/minecraftforge/event/entity/living/LivingSpawnEvent$CheckSpawn;)V
        4: ASM: class com.minecraftabnormals.environmental.core.other.EnvironmentalEvents onLivingSpawn(Lnet/minecraftforge/event/entity/living/LivingSpawnEvent$CheckSpawn;)V
        5: net.minecraftforge.eventbus.EventBus$$Lambda$2729/0x0000000800e2d840@541f143a
        6: net.minecraftforge.eventbus.EventBus$$Lambda$2729/0x0000000800e2d840@6dce5b1c
        7: LOWEST
        8: ASM: vazkii.quark.content.world.module.underground.SpiderNestUndergroundBiomeModule@6eebfba5 onZombieSpawn(Lnet/minecraftforge/event/entity/living/LivingSpawnEvent$CheckSpawn;)V
        9: ASM: vazkii.quark.content.mobs.module.ForgottenModule@75683ee3 onSkeletonSpawn(Lnet/minecraftforge/event/entity/living/LivingSpawnEvent$CheckSpawn;)V
        10: ASM: mcjty.incontrol.ForgeEventHandlers@77b64e0a onEntitySpawnEvent(Lnet/minecraftforge/event/entity/living/LivingSpawnEvent$CheckSpawn;)V
java.util.ConcurrentModificationException
    at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1135)
    at mcjty.incontrol.rules.RuleCache$CachePerWorld.lambda$count$1(RuleCache.java:208)
    at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
    at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
    at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658)
    at mcjty.incontrol.rules.RuleCache$CachePerWorld.count(RuleCache.java:202)
    at mcjty.incontrol.rules.RuleCache$CachePerWorld.getCount(RuleCache.java:226)
    at mcjty.incontrol.rules.RuleCache.getCount(RuleCache.java:62)
    at mcjty.incontrol.rules.support.GenericRuleEvaluator.lambda$getCounter$34(GenericRuleEvaluator.java:492)
    at mcjty.incontrol.rules.support.GenericRuleEvaluator.lambda$addMinCountCheck$18(GenericRuleEvaluator.java:395)
    at mcjty.incontrol.rules.support.GenericRuleEvaluator.match(GenericRuleEvaluator.java:607)
    at mcjty.incontrol.rules.SpawnRule.match(SpawnRule.java:277)
    at mcjty.incontrol.ForgeEventHandlers.onEntitySpawnEvent(ForgeEventHandlers.java:113)
    at net.minecraftforge.eventbus.ASMEventHandler_1868_ForgeEventHandlers_onEntitySpawnEvent_CheckSpawn.invoke(.dynamic)
    at net.minecraftforge.eventbus.ASMEventHandler.invoke(ASMEventHandler.java:85)
    at net.minecraftforge.eventbus.EventBus.post(EventBus.java:302)
    at net.minecraftforge.eventbus.EventBus.post(EventBus.java:283)
    at net.minecraftforge.event.ForgeEventFactory.canEntitySpawn(ForgeEventFactory.java:187)
    at net.minecraftforge.common.ForgeHooks.canEntitySpawn(ForgeHooks.java:1152)
    at untamedwilds.world.FaunaSpawn.performWorldGenSpawning(FaunaSpawn.java:131)
    at untamedwilds.world.gen.feature.FeatureDenseWater.generate(FeatureDenseWater.java:26)
    at untamedwilds.world.gen.feature.FeatureDenseWater.place(FeatureDenseWater.java:17)
    at net.minecraft.world.gen.feature.ConfiguredFeature.place(SourceFile:55)
    at net.minecraft.world.gen.feature.DecoratedFeature.lambda$place$0(SourceFile:23)
    at java.base/java.util.stream.Streams$StreamBuilderImpl.forEachRemaining(Streams.java:411)
    at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658)
    at net.minecraft.world.gen.feature.DecoratedFeature.place(SourceFile:22)
    at net.minecraft.world.gen.feature.DecoratedFeature.place(SourceFile:14)
    at net.minecraft.world.gen.feature.ConfiguredFeature.place(SourceFile:55)
    at net.minecraft.world.biome.Biome.generate(Biome.java:254)
    at net.minecraft.world.gen.ChunkGenerator.applyBiomeDecoration(SourceFile:220)
    at net.minecraft.world.chunk.ChunkStatus.lambda$static$9(ChunkStatus.java:77)
    at net.minecraft.world.chunk.ChunkStatus.generate(ChunkStatus.java:198)
    at net.minecraft.world.server.ChunkManager.lambda$null$18(ChunkManager.java:524)
    at com.mojang.datafixers.util.Either$Left.map(Either.java:38)
    at net.minecraft.world.server.ChunkManager.lambda$scheduleChunkGeneration$20(ChunkManager.java:522)
    at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1072)
    at java.base/java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:478)
    at net.minecraft.world.chunk.ChunkTaskPriorityQueueSorter.lambda$null$1(SourceFile:58)
    at net.minecraft.util.concurrent.DelegatedTaskExecutor.pollTask(SourceFile:94)
    at net.minecraft.util.concurrent.DelegatedTaskExecutor.pollUntil(SourceFile:137)
    at net.minecraft.util.concurrent.DelegatedTaskExecutor.run(SourceFile:105)
    at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1426)
    at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
    at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
    at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
    at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
    at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
McJty commented 1 year ago

I'll check it out soon. Thanks for reporting

McJty commented 1 year ago

Hmm that can't be the reason. It's perfectly fine to do computeIfAbsent on another map while iterating over something else. And that's exactly what is happening. Not sure what you get that error though. This seems to be a bug in UntamedWilds

McJty commented 1 year ago

UntamedWilds seems to be spawning mobs during feature generation. I don't think that's how you should do this to be honest

McJty commented 1 year ago

Right that's the problem. Worldgen happens in another thread. You cannot do entity spawning there. This is a concurrent modification exception because the computeIfAbsent is done in the wrong thread. So report to them