diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/DhLitWorldGenRegion.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/DhLitWorldGenRegion.java index 838bca76f..34a27482d 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/DhLitWorldGenRegion.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/DhLitWorldGenRegion.java @@ -21,6 +21,7 @@ package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject; import java.lang.invoke.MethodHandles; import java.util.List; +import java.util.concurrent.locks.ReentrantLock; import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment; import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; @@ -66,6 +67,12 @@ public class DhLitWorldGenRegion extends WorldGenRegion private final List cache; Long2ObjectOpenHashMap chunkMap = new Long2ObjectOpenHashMap(); + /** + * Present to reduce the chance that we accidentally break underlying MC code that isn't thread safe, + * specifically: "it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap.getAndMoveToFirst()" + */ + ReentrantLock getChunkLock = new ReentrantLock(); + #if PRE_MC_1_18_2 private ChunkPos overrideCenterPos = null; @@ -90,6 +97,8 @@ public class DhLitWorldGenRegion extends WorldGenRegion #endif #endif + + public DhLitWorldGenRegion( ServerLevel serverLevel, DummyLightEngine lightEngine, List chunkList, ChunkStatus chunkStatus, int writeRadius, @@ -104,6 +113,8 @@ public class DhLitWorldGenRegion extends WorldGenRegion this.size = Mth.floor(Math.sqrt(chunkList.size())); } + + #if POST_MC_1_17_1 // Bypass BCLib mixin overrides. @Override @@ -205,7 +216,16 @@ public class DhLitWorldGenRegion extends WorldGenRegion @Override public ChunkAccess getChunk(int i, int j) { - return this.getChunk(i, j, ChunkStatus.EMPTY); + try + { + // lock is to prevent issues with underlying MC code that doesn't support multithreading + this.getChunkLock.lock(); + return this.getChunk(i, j, ChunkStatus.EMPTY); + } + finally + { + this.getChunkLock.unlock(); + } } // Override to ensure no other mod mixins cause skipping the overrided @@ -213,7 +233,16 @@ public class DhLitWorldGenRegion extends WorldGenRegion @Override public ChunkAccess getChunk(int i, int j, ChunkStatus chunkStatus) { - return this.getChunk(i, j, chunkStatus, true); + try + { + // lock is to prevent issues with underlying MC code that doesn't support multithreading + this.getChunkLock.lock(); + return this.getChunk(i, j, chunkStatus, true); + } + finally + { + this.getChunkLock.unlock(); + } } // Use this instead of super.getChunk() to bypass C2ME concurrency checks diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/RegionFileStorageExternalCache.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/RegionFileStorageExternalCache.java index 25c84a577..6352f5f84 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/RegionFileStorageExternalCache.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/RegionFileStorageExternalCache.java @@ -13,21 +13,20 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.locks.ReentrantLock; public class RegionFileStorageExternalCache implements AutoCloseable { public final RegionFileStorage storage; public static final int MAX_CACHE_SIZE = 16; - @Override - public void close() throws IOException - { - RegionFileCache cache; - while ((cache = this.regionFileCache.poll()) != null) - { - cache.file.close(); - } - } + /** + * Present to reduce the chance that we accidentally break underlying MC code that isn't thread safe, + * specifically: "it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap.getAndMoveToFirst()" + */ + ReentrantLock getRegionFileLock = new ReentrantLock(); + + static class RegionFileCache { @@ -42,6 +41,8 @@ public class RegionFileStorageExternalCache implements AutoCloseable } + + public ConcurrentLinkedQueue regionFileCache = new ConcurrentLinkedQueue<>(); public RegionFileStorageExternalCache(RegionFileStorage storage) { this.storage = storage; } @@ -61,6 +62,8 @@ public class RegionFileStorageExternalCache implements AutoCloseable try { + this.getRegionFileLock.lock(); + #if MC_1_16_5 || MC_1_17_1 rFile = this.storage.getRegionFile(pos); #else @@ -85,6 +88,10 @@ public class RegionFileStorageExternalCache implements AutoCloseable } #endif } + finally + { + this.getRegionFileLock.unlock(); + } } if (retryCount >= maxRetryCount) @@ -140,7 +147,7 @@ public class RegionFileStorageExternalCache implements AutoCloseable @Nullable public CompoundTag read(ChunkPos pos) throws IOException { - RegionFile file = getRegionFile(pos); + RegionFile file = this.getRegionFile(pos); if (file == null) { return null; @@ -162,4 +169,16 @@ public class RegionFileStorageExternalCache implements AutoCloseable } } + + @Override + public void close() throws IOException + { + RegionFileCache cache; + while ((cache = this.regionFileCache.poll()) != null) + { + cache.file.close(); + } + } + + } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java index 35a5a7b71..e9bc14cfb 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureReference.java @@ -63,7 +63,7 @@ public final class StepStructureReference for (ChunkAccess chunk : chunksToDo) { // System.out.println("StepStructureReference: "+chunk.getPos()); - environment.params.generator.createReferences(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk); + this.environment.params.generator.createReferences(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk); } } diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java index 94b92526c..b4d76c08d 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/step/StepStructureStart.java @@ -38,7 +38,7 @@ public final class StepStructureStart { private static final Logger LOGGER = DhLoggerBuilder.getLogger(); private static final ChunkStatus STATUS = ChunkStatus.STRUCTURE_STARTS; - private static final ReentrantLock structurePlacementLock = new ReentrantLock(); + private static final ReentrantLock STRUCTURE_PLACEMENT_LOCK = new ReentrantLock(); private final BatchGenerationEnvironment environment; @@ -96,7 +96,7 @@ public final class StepStructureStart // hopefully this shouldn't cause any performance issues (this step is generally quite quick so hopefully it should be fine) // and should prevent some concurrency issues - structurePlacementLock.lock(); + STRUCTURE_PLACEMENT_LOCK.lock(); #if PRE_MC_1_19_2 environment.params.generator.createStructures(environment.params.registry, tParams.structFeat, chunk, environment.params.structures, @@ -140,7 +140,7 @@ public final class StepStructureStart #endif - structurePlacementLock.unlock(); + STRUCTURE_PLACEMENT_LOCK.unlock(); } } }