diff --git a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/cache_strongholds/ChunkGeneratorMixin.java b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/cache_strongholds/ChunkGeneratorMixin.java index 0b865124..de35aa17 100644 --- a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/cache_strongholds/ChunkGeneratorMixin.java +++ b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/cache_strongholds/ChunkGeneratorMixin.java @@ -2,6 +2,8 @@ package org.embeddedt.modernfix.common.mixin.perf.cache_strongholds; import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; import net.minecraft.Util; import net.minecraft.core.Holder; import net.minecraft.nbt.*; @@ -17,6 +19,8 @@ import org.embeddedt.modernfix.duck.IChunkGenerator; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; import java.lang.ref.SoftReference; import java.nio.charset.StandardCharsets; @@ -29,6 +33,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; @Mixin(ChunkGeneratorStructureState.class) public class ChunkGeneratorMixin implements IChunkGenerator { @@ -55,8 +61,9 @@ public class ChunkGeneratorMixin implements IChunkGenerator { @WrapMethod(method = "generateRingPositions") private CompletableFuture> modernfix$cacheRingPositions(Holder structureSet, - ConcentricRingsStructurePlacement placement, - Operation>> original) { + ConcentricRingsStructurePlacement placement, + Operation>> original, + @Share("threadPool") LocalRef threadPoolRef) { if (this.mfix$server == null || this.mfix$dimensionPath == null) { return original.call(structureSet, placement); } @@ -71,13 +78,30 @@ public class ChunkGeneratorMixin implements IChunkGenerator { } var server = this.mfix$server; - return original.call(structureSet, placement).thenApplyAsync(positions -> { - // Skip write if server exited before we finished - if (server.isRunning()) { - mfix$writeToCache(cacheKey, positions); - } - return positions; - }, Util.ioPool()); + ExecutorService strongholdPool = Executors.newFixedThreadPool(Math.max(1, Runtime.getRuntime().availableProcessors() - 2)); + threadPoolRef.set(strongholdPool); + try { + return original.call(structureSet, placement).thenApplyAsync(positions -> { + // Skip write if server exited before we finished + if (server.isRunning()) { + mfix$writeToCache(cacheKey, positions); + } + return positions; + }, Util.ioPool()); + } finally { + strongholdPool.shutdown(); + } + } + + /** + * @author embeddedt + * @reason Ring position calculation is often not required for initial chunk generation, but the tasks still occupy + * CPU time on the main worker pool and prevent higher priority work from progressing. To fix this we use a + * dedicated pool. + */ + @Redirect(method = "generateRingPositions", at = @At(value = "INVOKE", target = "Lnet/minecraft/Util;backgroundExecutor()Ljava/util/concurrent/ExecutorService;")) + private ExecutorService useDedicatedService(@Share("threadPool") LocalRef threadPoolRef) { + return threadPoolRef.get(); } private String mfix$makeCacheKey(ConcentricRingsStructurePlacement placement) {