diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java b/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java index 555ce4f48..11aca2556 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java @@ -58,7 +58,7 @@ import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.O; import com.volmit.iris.util.scheduling.PrecisionStopwatch; -import com.volmit.iris.util.scheduling.jobs.ParallelQueueJob; +import com.volmit.iris.util.scheduling.jobs.ParallelRadiusJob; import io.papermc.lib.PaperLib; import org.bukkit.*; import org.bukkit.event.inventory.InventoryType; @@ -181,49 +181,40 @@ public class CommandStudio implements DecreeExecutor { int rad = engine.getMantle().getRadius(); var mantle = engine.getMantle().getMantle(); var chunkMap = new KMap(); - ParallelQueueJob prep = new ParallelQueueJob<>() { + ParallelRadiusJob prep = new ParallelRadiusJob(Integer.MAX_VALUE) { @Override - public void execute(Position2 pos) { - var cpos = pos.add(x, z); - if (Math.abs(pos.getX()) <= radius && Math.abs(pos.getZ()) <= radius) { - mantle.deleteChunk(cpos.getX(), cpos.getZ()); + protected void execute(int rX, int rZ) { + if (Math.abs(rX) <= radius && Math.abs(rZ) <= radius) { + mantle.deleteChunk(rX + x, rZ + z); return; } - chunkMap.put(cpos, mantle.getChunk(cpos.getX(), cpos.getZ())); - mantle.deleteChunk(cpos.getX(), cpos.getZ()); + rX += x; + rZ += z; + chunkMap.put(new Position2(rX, rZ), mantle.getChunk(rX, rZ)); + mantle.deleteChunk(rX, rZ); } @Override public String getName() { return "Preparing Mantle"; } - }; - for (int xx = -(radius + rad); xx <= radius + rad; xx++) { - for (int zz = -(radius + rad); zz <= radius + rad; zz++) { - prep.queue(new Position2(xx, zz)); - } - } + }.retarget(radius + rad, 0, 0); CountDownLatch pLatch = new CountDownLatch(1); prep.execute(sender(), pLatch::countDown); pLatch.await(); - ParallelQueueJob job = new ParallelQueueJob<>() { + ParallelRadiusJob job = new ParallelRadiusJob(Integer.MAX_VALUE) { @Override - public void execute(Position2 p) { - plat.injectChunkReplacement(world, p.getX(), p.getZ(), executor); + protected void execute(int x, int z) { + plat.injectChunkReplacement(world, x, z, executor); } @Override public String getName() { return "Regenerating"; } - }; - for (int i = -radius; i <= radius; i++) { - for (int j = -radius; j <= radius; j++) { - job.queue(new Position2(i + x, j + z)); - } - } + }.retarget(radius, x, z); CountDownLatch latch = new CountDownLatch(1); job.execute(sender(), latch::countDown); latch.await(); diff --git a/core/src/main/java/com/volmit/iris/util/scheduling/jobs/ParallelRadiusJob.java b/core/src/main/java/com/volmit/iris/util/scheduling/jobs/ParallelRadiusJob.java new file mode 100644 index 000000000..71df2a3f5 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/scheduling/jobs/ParallelRadiusJob.java @@ -0,0 +1,86 @@ +package com.volmit.iris.util.scheduling.jobs; + +import com.volmit.iris.util.math.Spiraler; +import com.volmit.iris.util.parallel.MultiBurst; +import lombok.SneakyThrows; +import lombok.Synchronized; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicInteger; + +public abstract class ParallelRadiusJob implements Job { + private final ExecutorService service; + private final AtomicInteger completed; + private volatile int radiusX, radiusZ; + private volatile int offsetX, offsetZ; + private volatile int total; + private final Semaphore lock; + private final int lockSize; + + public ParallelRadiusJob(int concurrent) { + this(concurrent, MultiBurst.burst); + } + + public ParallelRadiusJob(int concurrent, ExecutorService service) { + this.service = service; + completed = new AtomicInteger(0); + lock = new Semaphore(concurrent); + lockSize = concurrent; + } + + public ParallelRadiusJob retarget(int radius, int offsetX, int offsetZ) { + return retarget(radius, radius, offsetX, offsetZ); + } + + @Synchronized + public ParallelRadiusJob retarget(int radiusX, int radiusZ, int offsetX, int offsetZ) { + completed.set(0); + this.radiusX = radiusX; + this.radiusZ = radiusZ; + this.offsetX = offsetX; + this.offsetZ = offsetZ; + total = (radiusX * 2 + 1) * (radiusZ * 2 + 1); + return this; + } + + @Override + @SneakyThrows + @Synchronized + public void execute() { + new Spiraler(radiusX * 2 + 3, radiusZ * 2 + 3, this::submit).drain(); + lock.acquire(lockSize); + lock.release(lockSize); + } + + @SneakyThrows + private void submit(int x, int z) { + if (Math.abs(x) > radiusX || Math.abs(z) > radiusZ) return; + lock.acquire(); + service.submit(() -> { + try { + execute(x + offsetX, z + offsetZ); + } finally { + completeWork(); + } + }); + } + + protected abstract void execute(int x, int z); + + @Override + public void completeWork() { + completed.incrementAndGet(); + lock.release(); + } + + @Override + public int getTotalWork() { + return total; + } + + @Override + public int getWorkCompleted() { + return completed.get(); + } +}