-
Bug
-
Resolution: Unresolved
-
None
-
1.20.6, 24w19b, 24w20a, 24w21b, 1.21 Pre-Release 2, 1.21 Release Candidate 1, 1.21, 1.21.1, 24w34a, 1.21.3
-
None
-
Community Consensus
-
World generation
-
Normal
-
Platform
Upon looking at the code flow for worldgen structure generation, I can see there is a very rare ConcurrentModificationException crash that is possible to trigger. It relies on a race condition that would be incredibly difficult to reproduce but it does exist.
Here's a run down of the code analysis.
StructureTemplates are stored globally for all threads to access. So if you have a TallHouse.nbt file you loaded once, that StructureTemplate is then stored and cached for all threads to use the exact same object.
Within StructureTemplate, they hold a Palette class object of all the blocks in that template. The Palette has a hashmap field called cache. This cache field is using a normal HashMap which means it is not thread safe.
Worldgen will create the structure layout on different worldgen threads. You can have two chunks on different threads trying to generate the layout for the same structure.
In theory, if you generate two chunks at the exact same point in time, and both threads goes into the TallHouse.nbt's StructureTemplate, calls the Palette's blocks method that mutates the cache field if the given block to filter for doesn't already exist in the cache, then a ConcurrentModificationException crash can happen due to the cache field mutating on one thread while another thread is also trying to access the cache for this specific StructureTemplate object.
Again, I have not be able to reproduce the crash but the code flow shows it does exist but would be difficult to trigger reliably at all. The solution is to change
private final Map<Block, List<StructureTemplate.StructureBlockInfo>> cache = Maps.newHashMap();
to be
private final Map<Block, List<StructureTemplate.StructureBlockInfo>> cache = Maps.newConcurrentMap();
This will make this cache on the global StructureTemplate object safe for all worldgen threads to access and mutate.