From 7afdbc2a533608ba96337b73113ecce7a06cab2e Mon Sep 17 00:00:00 2001 From: RePixelatedMC Date: Mon, 6 Nov 2023 15:03:40 +0100 Subject: [PATCH] - Added Lazy pregen as an option --- .../iris/core/commands/CommandPregen.java | 83 ++++++++++++++----- .../core/pregenerator/IrisPregenerator.java | 5 -- .../core/pregenerator/LazyPregenerator.java | 44 +++++++++- .../iris/core/tools/IrisPackBenchmarking.java | 2 +- .../iris/engine/safeguard/UtilsSFG.java | 2 +- 5 files changed, 105 insertions(+), 31 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandPregen.java b/core/src/main/java/com/volmit/iris/core/commands/CommandPregen.java index c92f373ce..b59687ce6 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandPregen.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandPregen.java @@ -20,6 +20,7 @@ import com.volmit.iris.Iris; import com.volmit.iris.core.gui.PregeneratorJob; +import com.volmit.iris.core.pregenerator.LazyPregenerator; import com.volmit.iris.core.pregenerator.PregenTask; import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.util.decree.DecreeExecutor; @@ -27,9 +28,12 @@ import com.volmit.iris.util.decree.annotations.Param; import com.volmit.iris.util.format.C; import com.volmit.iris.util.math.Position2; +import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.util.Vector; +import java.io.File; + @Decree(name = "pregen", aliases = "pregenerate", description = "Pregenerate your Iris worlds!") public class CommandPregen implements DecreeExecutor { @Decree(description = "Pregenerate a world") @@ -39,29 +43,68 @@ public void start( @Param(description = "The world to pregen", contextual = true) World world, @Param(aliases = "middle", description = "The center location of the pregen. Use \"me\" for your current location", defaultValue = "0,0") - Vector center + Vector center, + @Param(aliases = "method", description = "The pregen method that will get used. Lazy or Async", defaultValue = "async") + String method ) { - try { - if (sender().isPlayer() && access() == null) { - sender().sendMessage(C.RED + "The engine access for this world is null!"); - sender().sendMessage(C.RED + "Please make sure the world is loaded & the engine is initialized. Generate a new chunk, for example."); + if(method.equals("async") || method.equals("lazy")){ + if (method.equalsIgnoreCase("async")) { + try { + if (sender().isPlayer() && access() == null) { + sender().sendMessage(C.RED + "The engine access for this world is null!"); + sender().sendMessage(C.RED + "Please make sure the world is loaded & the engine is initialized. Generate a new chunk, for example."); + } + radius = Math.max(radius, 1024); + int w = (radius >> 9 + 1) * 2; + IrisToolbelt.pregenerate(PregenTask + .builder() + .center(new Position2(center.getBlockX() >> 9, center.getBlockZ() >> 9)) + .width(w) + .height(w) + .build(), world); + String msg = C.GREEN + "Pregen started in " + C.GOLD + world.getName() + C.GREEN + " of " + C.GOLD + (radius * 2) + C.GREEN + " by " + C.GOLD + (radius * 2) + C.GREEN + " blocks from " + C.GOLD + center.getX() + "," + center.getZ(); + sender().sendMessage(msg); + Iris.info(msg); + } catch (Throwable e) { + sender().sendMessage(C.RED + "Epic fail. See console."); + Iris.reportError(e); + e.printStackTrace(); + } + } + if (method.equalsIgnoreCase("lazy")) { + String worldName = world.getName(); + try { + if (sender().isPlayer() && access() == null) { + sender().sendMessage(C.RED + "The engine access for this world is null!"); + sender().sendMessage(C.RED + "Please make sure the world is loaded & the engine is initialized. Generate a new chunk, for example."); + } + + LazyPregenerator.LazyPregenJob pregenJob = LazyPregenerator.LazyPregenJob.builder() + .world(worldName) + .healingPosition(0) + .healing(false) + .chunksPerMinute(999999999) + .radiusBlocks(radius) + .position(0) + .build(); + + LazyPregenerator pregenerator = new LazyPregenerator(pregenJob, new File("plugins/Iris/lazygen.json")); + pregenerator.start(); + + String msg = C.GREEN + "Pregen started in " + C.GOLD + worldName + C.GREEN + " of " + C.GOLD + (radius * 2) + C.GREEN + " by " + C.GOLD + (radius * 2) + C.GREEN + " blocks from " + C.GOLD + center.getX() + "," + center.getZ(); + sender().sendMessage(msg); + Iris.info(msg); + } catch (Throwable e) { + sender().sendMessage(C.RED + "Epic fail. See console."); + Iris.reportError(e); + e.printStackTrace(); + } } - radius = Math.max(radius, 1024); - int w = (radius >> 9 + 1) * 2; - IrisToolbelt.pregenerate(PregenTask - .builder() - .center(new Position2(center.getBlockX() >> 9, center.getBlockZ() >> 9)) - .width(w) - .height(w) - .build(), world); - String msg = C.GREEN + "Pregen started in " + C.GOLD + world.getName() + C.GREEN + " of " + C.GOLD + (radius * 2) + C.GREEN + " by " + C.GOLD + (radius * 2) + C.GREEN + " blocks from " + C.GOLD + center.getX() + "," + center.getZ(); - sender().sendMessage(msg); - Iris.info(msg); - } catch (Throwable e) { - sender().sendMessage(C.RED + "Epic fail. See console."); - Iris.reportError(e); - e.printStackTrace(); + } else { + sender().sendMessage(C.RED + "Please use a valid method."); + } + } @Decree(description = "Stop the active pregeneration task", aliases = "x") diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java b/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java index a66ec20d6..513600a95 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java @@ -132,11 +132,6 @@ private long computeETA() { ); } - public static void shareData(){ - long_generatedChunks = generated.get(); - long_totalChunks = totalChunks.get(); - } - public static long getLongGeneratedChunks() { return long_generatedChunks; } diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/LazyPregenerator.java b/core/src/main/java/com/volmit/iris/core/pregenerator/LazyPregenerator.java index 065d03169..7deeb181e 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/LazyPregenerator.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/LazyPregenerator.java @@ -2,9 +2,12 @@ import com.google.gson.Gson; import com.volmit.iris.Iris; +import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; import com.volmit.iris.util.io.IO; +import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.Position2; +import com.volmit.iris.util.math.RollingSequence; import com.volmit.iris.util.math.Spiraler; import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; @@ -20,6 +23,7 @@ import java.io.File; import java.io.IOException; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; public class LazyPregenerator extends Thread implements Listener { private final LazyPregenJob job; @@ -28,6 +32,11 @@ public class LazyPregenerator extends Thread implements Listener { private final World world; private final long rate; private final ChronoLatch latch; + private static AtomicInteger lazyGeneratedChunks; + private final AtomicInteger generatedLast; + private final AtomicInteger lazyTotalChunks; + private final AtomicLong startTime; + private final RollingSequence chunksPerSecond; public LazyPregenerator(LazyPregenJob job, File destination) { this.job = job; @@ -36,7 +45,15 @@ public LazyPregenerator(LazyPregenJob job, File destination) { }).count(); this.world = Bukkit.getWorld(job.getWorld()); this.rate = Math.round((1D / (job.chunksPerMinute / 60D)) * 1000D); - this.latch = new ChronoLatch(60000); + this.latch = new ChronoLatch(6000); + startTime = new AtomicLong(M.ms()); + chunksPerSecond = new RollingSequence(10); + lazyGeneratedChunks = new AtomicInteger(0); + generatedLast = new AtomicInteger(0); + lazyTotalChunks = new AtomicInteger(); + + int radius = job.getRadiusBlocks(); + lazyTotalChunks.set((int) Math.ceil(Math.pow((2.0 * radius) / 16, 2))); } public LazyPregenerator(File file) throws IOException { @@ -81,17 +98,26 @@ public void run() { public void tick() { if (latch.flip()) { + long eta = computeETA(); save(); - Iris.info("LazyGen: " + world.getName() + " RTT: " + Form.duration((Math.pow((job.radiusBlocks / 16D), 2) / job.chunksPerMinute) * 60 * 1000, 2)); + int secondGenerated = lazyGeneratedChunks.get() - generatedLast.get(); + generatedLast.set(lazyGeneratedChunks.get()); + secondGenerated = secondGenerated / 6; + chunksPerSecond.put(secondGenerated); + Iris.info("LazyGen: " + C.IRIS + world.getName() + C.RESET + " RTT: " + Form.f(lazyGeneratedChunks.get()) + " of " + Form.f(lazyTotalChunks.get()) + " " + Form.f((int) chunksPerSecond.getAverage()) + "/s ETA: " + Form.duration((double) eta, 2)); + //Iris.info("Debug: " + maxPosition); + //Iris.info("Debug1: " + job.getPosition()); + + // todo: Maxpos borked } - if (job.getPosition() >= maxPosition) { + if (lazyGeneratedChunks.get() >= lazyTotalChunks.get()) { if (job.isHealing()) { int pos = (job.getHealingPosition() + 1) % maxPosition; job.setHealingPosition(pos); tickRegenerate(getChunk(pos)); } else { - Iris.verbose("Completed Lazy Gen!"); + Iris.info("Completed Lazy Gen!"); interrupt(); } } else { @@ -101,6 +127,15 @@ public void tick() { } } + private long computeETA() { + return (long) (lazyTotalChunks.get() > 1024 ? // Generated chunks exceed 1/8th of total? + // If yes, use smooth function (which gets more accurate over time since its less sensitive to outliers) + ((lazyTotalChunks.get() - lazyGeneratedChunks.get()) * ((double) (M.ms() - startTime.get()) / (double) lazyGeneratedChunks.get())) : + // If no, use quick function (which is less accurate over time but responds better to the initial delay) + ((lazyTotalChunks.get() - lazyGeneratedChunks.get()) / chunksPerSecond.getAverage()) * 1000 // + ); + } + private void tickGenerate(Position2 chunk) { if (PaperLib.isPaper()) { PaperLib.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true).thenAccept((i) -> Iris.verbose("Generated Async " + chunk)); @@ -108,6 +143,7 @@ private void tickGenerate(Position2 chunk) { J.s(() -> world.getChunkAt(chunk.getX(), chunk.getZ())); Iris.verbose("Generated " + chunk); } + lazyGeneratedChunks.addAndGet(1); } private void tickRegenerate(Position2 chunk) { diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisPackBenchmarking.java b/core/src/main/java/com/volmit/iris/core/tools/IrisPackBenchmarking.java index ef454e30b..13577cc82 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisPackBenchmarking.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisPackBenchmarking.java @@ -126,7 +126,7 @@ static void startLazyBenchmark(){ int x = 0; int z = 0; LazyPregenerator.LazyPregenJob pregenJob = LazyPregenerator.LazyPregenJob.builder() - .world("Benchmark") + //.world("Benchmark") .healingPosition(0) .healing(false) .chunksPerMinute(3200) diff --git a/core/src/main/java/com/volmit/iris/engine/safeguard/UtilsSFG.java b/core/src/main/java/com/volmit/iris/engine/safeguard/UtilsSFG.java index 65a06499b..fa94e33a3 100644 --- a/core/src/main/java/com/volmit/iris/engine/safeguard/UtilsSFG.java +++ b/core/src/main/java/com/volmit/iris/engine/safeguard/UtilsSFG.java @@ -38,7 +38,7 @@ public static void printIncompatibleWarnings(){ if (incompatiblePlugins.get("Dynmap")) { Iris.safeguard(C.RED + "Dynmap"); Iris.safeguard(C.RED + "- The plugin Dynmap is not compatible with the server."); - Iris.safeguard(C.RED + "- If you want to have a map plugin like Dynmap, consider Bluemap or LiveAtlas."); + Iris.safeguard(C.RED + "- If you want to have a map plugin like Dynmap, consider Bluemap."); } if (incompatiblePlugins.get("TerraformGenerator") || incompatiblePlugins.get("Stratos")) { Iris.safeguard(C.YELLOW + "Terraform Generator / Stratos");