diff --git a/core/src/main/java/com/volmit/iris/core/IrisSettings.java b/core/src/main/java/com/volmit/iris/core/IrisSettings.java index c26b09b3b..826746193 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisSettings.java +++ b/core/src/main/java/com/volmit/iris/core/IrisSettings.java @@ -145,7 +145,10 @@ public class IrisSettings { @Data public static class IrisSettingsPregen { + public boolean useCacheByDefault = true; + public boolean useHighPriority = false; public boolean useVirtualThreads = false; + public boolean useTicketQueue = false; public int maxConcurrency = 256; } diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java b/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java index c31bf5029..757dfcf8f 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java @@ -33,7 +33,6 @@ import org.bukkit.Chunk; import org.bukkit.World; import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -43,22 +42,22 @@ import java.util.concurrent.atomic.AtomicInteger; public class AsyncPregenMethod implements PregeneratorMethod { private static final AtomicInteger THREAD_COUNT = new AtomicInteger(); private final World world; - private final ExecutorService service; + private final Executor executor; private final Semaphore semaphore; private final int threads; + private final boolean urgent; private final Map lastUse; - public AsyncPregenMethod(World world, int threads) { + public AsyncPregenMethod(World world, int unusedThreads) { if (!PaperLib.isPaper()) { throw new UnsupportedOperationException("Cannot use PaperAsync on non paper!"); } this.world = world; - service = IrisSettings.get().getPregen().isUseVirtualThreads() ? - Executors.newVirtualThreadPerTaskExecutor() : - new MultiBurst("Iris Async Pregen", Thread.MIN_PRIORITY); + this.executor = IrisSettings.get().getPregen().isUseTicketQueue() ? new TicketExecutor() : new ServiceExecutor(); this.threads = IrisSettings.get().getPregen().getMaxConcurrency(); - semaphore = new Semaphore(threads); + this.semaphore = new Semaphore(this.threads, true); + this.urgent = IrisSettings.get().getPregen().useHighPriority; this.lastUse = new KMap<>(); } @@ -70,13 +69,18 @@ public class AsyncPregenMethod implements PregeneratorMethod { return; } - for (Chunk i : new ArrayList<>(lastUse.keySet())) { - Long lastUseTime = lastUse.get(i); - if (!i.isLoaded() || (lastUseTime != null && M.ms() - lastUseTime >= 10000)) { - i.unload(); - lastUse.remove(i); + long minTime = M.ms() - 10_000; + lastUse.entrySet().removeIf(i -> { + final Chunk chunk = i.getKey(); + final Long lastUseTime = i.getValue(); + if (!chunk.isLoaded() || lastUseTime == null) + return true; + if (lastUseTime < minTime) { + chunk.unload(); + return true; } - } + return false; + }); world.save(); }).get(); } catch (Throwable e) { @@ -84,21 +88,6 @@ public class AsyncPregenMethod implements PregeneratorMethod { } } - private void completeChunk(int x, int z, PregenListener listener) { - try { - PaperLib.getChunkAtAsync(world, x, z, true).thenAccept((i) -> { - lastUse.put(i, M.ms()); - listener.onChunkGenerated(x, z); - listener.onChunkCleaned(x, z); - }).get(); - } catch (InterruptedException ignored) { - } catch (Throwable e) { - e.printStackTrace(); - } finally { - semaphore.release(); - } - } - @Override public void init() { unloadAndSaveAllChunks(); @@ -114,7 +103,7 @@ public class AsyncPregenMethod implements PregeneratorMethod { public void close() { semaphore.acquireUninterruptibly(threads); unloadAndSaveAllChunks(); - service.shutdown(); + executor.shutdown(); resetWorkerThreads(); } @@ -141,7 +130,7 @@ public class AsyncPregenMethod implements PregeneratorMethod { } catch (InterruptedException e) { return; } - service.submit(() -> completeChunk(x, z, listener)); + executor.generate(x, z, listener); } @Override @@ -153,7 +142,6 @@ public class AsyncPregenMethod implements PregeneratorMethod { return null; } - public static void increaseWorkerThreads() { THREAD_COUNT.updateAndGet(i -> { if (i > 0) return 1; @@ -167,7 +155,7 @@ public class AsyncPregenMethod implements PregeneratorMethod { pool.getClass().getDeclaredMethod("adjustThreadCount", int.class).invoke(pool, adjusted); return threads; } catch (Throwable e) { - Iris.warn("Failed to increase worker threads, please increase it manually to " + adjusted); + Iris.warn("Failed to increase worker threads, if you are on paper or a fork of it please increase it manually to " + adjusted); Iris.warn("For more information see https://docs.papermc.io/paper/reference/global-configuration#chunk_system_worker_threads"); if (e instanceof InvocationTargetException) e.printStackTrace(); } @@ -191,4 +179,56 @@ public class AsyncPregenMethod implements PregeneratorMethod { return i; }); } + + private interface Executor { + void generate(int x, int z, PregenListener listener); + default void shutdown() {} + } + + private class ServiceExecutor implements Executor { + private final ExecutorService service = IrisSettings.get().getPregen().isUseVirtualThreads() ? + Executors.newVirtualThreadPerTaskExecutor() : + new MultiBurst("Iris Async Pregen", Thread.MIN_PRIORITY); + + public void generate(int x, int z, PregenListener listener) { + service.submit(() -> { + try { + PaperLib.getChunkAtAsync(world, x, z, true, urgent).thenAccept((i) -> { + listener.onChunkGenerated(x, z); + listener.onChunkCleaned(x, z); + if (i == null) return; + lastUse.put(i, M.ms()); + }).get(); + } catch (InterruptedException ignored) { + } catch (Throwable e) { + e.printStackTrace(); + } finally { + semaphore.release(); + } + }); + } + + @Override + public void shutdown() { + service.shutdown(); + } + } + + private class TicketExecutor implements Executor { + @Override + public void generate(int x, int z, PregenListener listener) { + PaperLib.getChunkAtAsync(world, x, z, true, urgent) + .exceptionally(e -> { + e.printStackTrace(); + return null; + }) + .thenAccept(i -> { + semaphore.release(); + listener.onChunkGenerated(x, z); + listener.onChunkCleaned(x, z); + if (i == null) return; + lastUse.put(i, M.ms()); + }); + } + } } diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java b/core/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java index 15b3dc8d3..06651213c 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java @@ -142,7 +142,7 @@ public class IrisToolbelt { * @return the pregenerator job (already started) */ public static PregeneratorJob pregenerate(PregenTask task, PregeneratorMethod method, Engine engine) { - return pregenerate(task, method, engine, true); + return pregenerate(task, method, engine, IrisSettings.get().getPregen().useCacheByDefault); } /**