diff --git a/pom.xml b/pom.xml index e58f06e2e..8865472b4 100644 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,5 @@ - 4.0.0 @@ -152,10 +153,6 @@ bcn http://bytecode.ninja/repository/bcn/ - - CodeMC - https://repo.codemc.org/repository/maven-public - nexus Lumine Releases @@ -188,18 +185,6 @@ 1.16.2 provided - - org.bukkit.craftbukkit - cb-1.15.1 - 1.15.1 - provided - - - org.bukkit.craftbukkit - cb-1.14.4 - 1.14.4 - provided - com.sk89q.worldedit @@ -219,11 +204,6 @@ caffeine 2.8.5 - - org.bstats - bstats-bukkit - 1.7 - org.projectlombok lombok diff --git a/src/main/java/com/volmit/iris/Iris.java b/src/main/java/com/volmit/iris/Iris.java index 62cf376da..3c7cfe370 100644 --- a/src/main/java/com/volmit/iris/Iris.java +++ b/src/main/java/com/volmit/iris/Iris.java @@ -6,7 +6,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; -import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.World.Environment; @@ -42,6 +41,7 @@ import com.volmit.iris.util.IrisLock; import com.volmit.iris.util.J; import com.volmit.iris.util.KList; import com.volmit.iris.util.M; +import com.volmit.iris.util.MetricsLite; import com.volmit.iris.util.MortarPlugin; import com.volmit.iris.util.NastyRunnable; import com.volmit.iris.util.Permission; @@ -206,7 +206,10 @@ public class Iris extends MortarPlugin private void bstats() { - new Metrics(this, 8757); + J.s(() -> + { + new MetricsLite(Iris.instance, 8757); + }); } public static File getTemp() diff --git a/src/main/java/com/volmit/iris/IrisSettings.java b/src/main/java/com/volmit/iris/IrisSettings.java index c1e53f707..93511bcda 100644 --- a/src/main/java/com/volmit/iris/IrisSettings.java +++ b/src/main/java/com/volmit/iris/IrisSettings.java @@ -30,6 +30,14 @@ public class IrisSettings @Desc("Iris uses a lot of caching to speed up chunk generation. Setting this higher uses more memory, but may improve performance. Anything past 8,000 should be avoided because there is little benefit past this value.") public int atomicCacheSize = 3000; + @DontObfuscate + @Desc("Max pregen async chunk threads.") + public int maxAsyncChunkPregenThreads = 300; + + @DontObfuscate + @Desc("More cpu for pregen gui but looks nice.") + public boolean maxPregenGuiFPS = false; + @DontObfuscate @Desc("Compress parallax data in memory to reduce memory usage in exchange for more cpu usage.") public boolean parallaxCompression = true; @@ -50,6 +58,10 @@ public class IrisSettings @Desc("System Effects") public boolean systemEffects = true; + @DontObfuscate + @Desc("Disable all nms") + public boolean disableNMS = false; + @DontObfuscate @Desc("System Spawn Overrides") public boolean systemEntitySpawnOverrides = true; diff --git a/src/main/java/com/volmit/iris/command/CommandIris.java b/src/main/java/com/volmit/iris/command/CommandIris.java index fea017b90..a39dd187f 100644 --- a/src/main/java/com/volmit/iris/command/CommandIris.java +++ b/src/main/java/com/volmit/iris/command/CommandIris.java @@ -46,6 +46,9 @@ public class CommandIris extends MortarCommand @Command private CommandIrisPregen pregen; + @Command + private CommandIrisReload reload; + public CommandIris() { super("iris", "ir", "irs"); diff --git a/src/main/java/com/volmit/iris/command/CommandIrisPregen.java b/src/main/java/com/volmit/iris/command/CommandIrisPregen.java index 57db92c0e..ce7c3c257 100644 --- a/src/main/java/com/volmit/iris/command/CommandIrisPregen.java +++ b/src/main/java/com/volmit/iris/command/CommandIrisPregen.java @@ -40,36 +40,30 @@ public class CommandIrisPregen extends MortarCommand } return true; } - /* TODO: help else if(args[0].equalsIgnoreCase("pause")) { if(PregenJob.task == -1) { sender.sendMessage("No Active Pregens"); } + else { - if (PregenJob.isPaused()) { - PregenJob.resume(); - } else { - PregenJob.pause(); + PregenJob.pauseResume(); + + if(PregenJob.isPaused()) + { + sender.sendMessage("Pregen Paused"); + } + + else + { + sender.sendMessage("Pregen Resumed"); } - sender.sendMessage("Paused Active Pregen"); - } - return true; - } else if(args[0].equalsIgnoreCase("resume")){ - if(!PregenJob.isPaused()) - { - sender.sendMessage("No Paused Pregens"); - } - else - { - sender.sendMessage("Resumed Paused Pregen"); - PregenJob.resume(); } + return true; } - */ if(sender.isPlayer()) { diff --git a/src/main/java/com/volmit/iris/gen/nms/INMS.java b/src/main/java/com/volmit/iris/gen/nms/INMS.java index 61943a745..2f967ace6 100644 --- a/src/main/java/com/volmit/iris/gen/nms/INMS.java +++ b/src/main/java/com/volmit/iris/gen/nms/INMS.java @@ -3,6 +3,7 @@ package com.volmit.iris.gen.nms; import org.bukkit.Bukkit; import com.volmit.iris.Iris; +import com.volmit.iris.IrisSettings; import com.volmit.iris.gen.nms.v16_2.NMSBinding16_2; import com.volmit.iris.gen.nms.v1X.NMSBinding1X; import com.volmit.iris.util.KMap; @@ -22,6 +23,11 @@ public class INMS private static final String getNMSTag() { + if(IrisSettings.get().disableNMS) + { + return "BUKKIT"; + } + try { return Bukkit.getServer().getClass().getCanonicalName().split("\\Q.\\E")[3]; diff --git a/src/main/java/com/volmit/iris/gen/nms/v16_2/NMSCreator16_2.java b/src/main/java/com/volmit/iris/gen/nms/v16_2/NMSCreator16_2.java index 8d4f13b93..39e4f8143 100644 --- a/src/main/java/com/volmit/iris/gen/nms/v16_2/NMSCreator16_2.java +++ b/src/main/java/com/volmit/iris/gen/nms/v16_2/NMSCreator16_2.java @@ -2,6 +2,8 @@ package com.volmit.iris.gen.nms.v16_2; import java.io.File; import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.util.List; import java.util.Locale; import java.util.Map; @@ -210,11 +212,85 @@ class NMSCreator16_2 implements INMSCreator private Dimension getConsoleDimension(DedicatedServer console) { - if(PaperLib.isPaper()) + Dimension dim = null; + + try { - return new V((MinecraftServer) console, true).get("customRegistry"); + dim = new V((MinecraftServer) console, true).get("customRegistry"); + + if(dim != null) + { + return dim; + } } - return console.f; + catch(Throwable e) + { + + } + + try + { + dim = new V((MinecraftServer) console, true).get("f"); + + if(dim != null) + { + return dim; + } + } + + catch(Throwable e) + { + + } + + for(Field i : MinecraftServer.class.getDeclaredFields()) + { + if(i.getType().equals(dim.getClass())) + { + i.setAccessible(true); + + if(Modifier.isStatic(i.getModifiers())) + { + try + { + return (Dimension) i.get(null); + } + + catch(Throwable e) + { + e.printStackTrace(); + } + } + + else + { + try + { + return (Dimension) i.get((MinecraftServer) console); + } + + catch(Throwable e) + { + e.printStackTrace(); + } + } + } + } + + if(dim == null) + { + try + { + throw new RuntimeException("Cannot find dimension field!"); + } + + catch(Throwable e) + { + e.printStackTrace(); + } + } + + return dim; } } diff --git a/src/main/java/com/volmit/iris/gui/PregenGui.java b/src/main/java/com/volmit/iris/gui/PregenGui.java index 476372b2c..5a2e38f45 100644 --- a/src/main/java/com/volmit/iris/gui/PregenGui.java +++ b/src/main/java/com/volmit/iris/gui/PregenGui.java @@ -5,6 +5,8 @@ import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; import java.awt.image.BufferedImage; import java.awt.image.ImageObserver; import java.io.File; @@ -16,13 +18,14 @@ import javax.swing.JFrame; import javax.swing.JPanel; import com.volmit.iris.Iris; +import com.volmit.iris.IrisSettings; import com.volmit.iris.util.ChunkPosition; import com.volmit.iris.util.J; import com.volmit.iris.util.KList; import com.volmit.iris.util.M; import com.volmit.iris.util.PregenJob; -public class PregenGui extends JPanel +public class PregenGui extends JPanel implements KeyListener { private PregenJob job; private static final long serialVersionUID = 2094606939770332040L; @@ -76,12 +79,25 @@ public class PregenGui extends JPanel String[] prog = job.getProgress(); int h = g.getFontMetrics().getHeight() + 5; int hh = 20; - for(String i : prog) + + if(job.paused()) { - g.drawString(i, 20, hh += h); + g.drawString("PAUSED", 20, hh += h); + + g.drawString("Press P to Resume", 20, hh += h); } - J.sleep((long) 250); + else + { + for(String i : prog) + { + g.drawString(i, 20, hh += h); + } + + g.drawString("Press P to Pause", 20, hh += h); + } + + J.sleep((long) (IrisSettings.get().isMaxPregenGuiFPS() ? 4 : 250)); repaint(); } @@ -104,6 +120,7 @@ public class PregenGui extends JPanel { JFrame frame = new JFrame("Pregen View"); PregenGui nv = new PregenGui(); + frame.addKeyListener(nv); nv.l = new ReentrantLock(); nv.job = j; j.subscribe((c, b) -> @@ -142,4 +159,25 @@ public class PregenGui extends JPanel createAndShowGUI(g); }); } + + @Override + public void keyTyped(KeyEvent e) + { + + } + + @Override + public void keyPressed(KeyEvent e) + { + + } + + @Override + public void keyReleased(KeyEvent e) + { + if(e.getKeyCode() == KeyEvent.VK_P) + { + PregenJob.pauseResume(); + } + } } diff --git a/src/main/java/com/volmit/iris/util/MetricsLite.java b/src/main/java/com/volmit/iris/util/MetricsLite.java new file mode 100644 index 000000000..71ec9b5da --- /dev/null +++ b/src/main/java/com/volmit/iris/util/MetricsLite.java @@ -0,0 +1,434 @@ +package com.volmit.iris.util; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.ServicePriority; + +import javax.net.ssl.HttpsURLConnection; +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.Timer; +import java.util.TimerTask; +import java.util.UUID; +import java.util.logging.Level; +import java.util.zip.GZIPOutputStream; + +/** + * bStats collects some data for plugin authors. + *

+ * Check out https://bStats.org/ to learn more about bStats! + */ +public class MetricsLite +{ + + static + { + // You can use the property to disable the check in your test environment + if(System.getProperty("bstats.relocatecheck") == null || !System.getProperty("bstats.relocatecheck").equals("false")) + { + // Maven's Relocate is clever and changes strings, too. So we have to use this + // little "trick" ... :D + final String defaultPackage = new String(new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's', '.', 'b', 'u', 'k', 'k', 'i', 't'}); + final String examplePackage = new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); + // We want to make sure nobody just copy & pastes the example and use the wrong + // package names + if(MetricsLite.class.getPackage().getName().equals(defaultPackage) || MetricsLite.class.getPackage().getName().equals(examplePackage)) + { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + // The version of this bStats class + public static final int B_STATS_VERSION = 1; + + // The url to which the data is sent + private static final String URL = "https://bStats.org/submitData/bukkit"; + + // Is bStats enabled on this server? + private boolean enabled; + + // Should failed requests be logged? + private static boolean logFailedRequests; + + // Should the sent data be logged? + private static boolean logSentData; + + // Should the response text be logged? + private static boolean logResponseStatusText; + + // The uuid of the server + private static String serverUUID; + + // The plugin + private final Plugin plugin; + + // The plugin id + private final int pluginId; + + /** + * Class constructor. + * + * @param plugin + * The plugin which stats should be submitted. + * @param pluginId + * The id of the plugin. It can be found at + * What is my + * plugin id? + */ + public MetricsLite(Plugin plugin, int pluginId) + { + if(plugin == null) + { + throw new IllegalArgumentException("Plugin cannot be null!"); + } + this.plugin = plugin; + this.pluginId = pluginId; + + // Get the config file + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yml"); + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + + // Check if the config file exists + if(!config.isSet("serverUuid")) + { + + // Add default values + config.addDefault("enabled", true); + // Every server gets it's unique random id. + config.addDefault("serverUuid", UUID.randomUUID().toString()); + // Should failed request be logged? + config.addDefault("logFailedRequests", false); + // Should the sent data be logged? + config.addDefault("logSentData", false); + // Should the response text be logged? + config.addDefault("logResponseStatusText", false); + + // Inform the server owners about bStats + config.options().header("bStats collects some data for plugin authors like how many servers are using their plugins.\n" + "To honor their work, you should not disable it.\n" + "This has nearly no effect on the server performance!\n" + "Check out https://bStats.org/ to learn more :)").copyDefaults(true); + try + { + config.save(configFile); + } + catch(IOException ignored) + { + } + } + + // Load the data + serverUUID = config.getString("serverUuid"); + logFailedRequests = config.getBoolean("logFailedRequests", false); + enabled = config.getBoolean("enabled", true); + logSentData = config.getBoolean("logSentData", false); + logResponseStatusText = config.getBoolean("logResponseStatusText", false); + if(enabled) + { + boolean found = false; + // Search for all other bStats Metrics classes to see if we are the first one + for(Class service : Bukkit.getServicesManager().getKnownServices()) + { + try + { + service.getField("B_STATS_VERSION"); // Our identifier :) + found = true; // We aren't the first + break; + } + catch(NoSuchFieldException ignored) + { + } + } + // Register our service + Bukkit.getServicesManager().register(MetricsLite.class, this, plugin, ServicePriority.Normal); + if(!found) + { + // We are the first! + startSubmitting(); + } + } + } + + /** + * Checks if bStats is enabled. + * + * @return Whether bStats is enabled or not. + */ + public boolean isEnabled() + { + return enabled; + } + + /** + * Starts the Scheduler which submits our data every 30 minutes. + */ + private void startSubmitting() + { + final Timer timer = new Timer(true); // We use a timer cause the Bukkit scheduler is affected by server lags + timer.scheduleAtFixedRate(new TimerTask() + { + @Override + public void run() + { + if(!plugin.isEnabled()) + { // Plugin was disabled + timer.cancel(); + return; + } + // Nevertheless we want our code to run in the Bukkit main thread, so we have to + // use the Bukkit scheduler + // Don't be afraid! The connection to the bStats server is still async, only the + // stats collection is sync ;) + Bukkit.getScheduler().runTask(plugin, () -> submitData()); + } + }, 1000 * 60 * 5, 1000 * 60 * 30); + // Submit the data every 30 minutes, first time after 5 minutes to give other + // plugins enough time to start + // WARNING: Changing the frequency has no effect but your plugin WILL be + // blocked/deleted! + // WARNING: Just don't do it! + } + + /** + * Gets the plugin specific data. This method is called using Reflection. + * + * @return The plugin specific data. + */ + public JsonObject getPluginData() + { + JsonObject data = new JsonObject(); + + String pluginName = plugin.getDescription().getName(); + String pluginVersion = plugin.getDescription().getVersion(); + + data.addProperty("pluginName", pluginName); // Append the name of the plugin + data.addProperty("id", pluginId); // Append the id of the plugin + data.addProperty("pluginVersion", pluginVersion); // Append the version of the plugin + data.add("customCharts", new JsonArray()); + + return data; + } + + /** + * Gets the server specific data. + * + * @return The server specific data. + */ + private JsonObject getServerData() + { + // Minecraft specific data + int playerAmount; + try + { + // Around MC 1.8 the return type was changed to a collection from an array, + // This fixes java.lang.NoSuchMethodError: + // org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); + playerAmount = onlinePlayersMethod.getReturnType().equals(Collection.class) ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; + } + catch(Exception e) + { + playerAmount = Bukkit.getOnlinePlayers().size(); // Just use the new method if the Reflection failed + } + int onlineMode = Bukkit.getOnlineMode() ? 1 : 0; + String bukkitVersion = Bukkit.getVersion(); + String bukkitName = Bukkit.getName(); + + // OS/Java specific data + String javaVersion = System.getProperty("java.version"); + String osName = System.getProperty("os.name"); + String osArch = System.getProperty("os.arch"); + String osVersion = System.getProperty("os.version"); + int coreCount = Runtime.getRuntime().availableProcessors(); + + JsonObject data = new JsonObject(); + + data.addProperty("serverUUID", serverUUID); + + data.addProperty("playerAmount", playerAmount); + data.addProperty("onlineMode", onlineMode); + data.addProperty("bukkitVersion", bukkitVersion); + data.addProperty("bukkitName", bukkitName); + + data.addProperty("javaVersion", javaVersion); + data.addProperty("osName", osName); + data.addProperty("osArch", osArch); + data.addProperty("osVersion", osVersion); + data.addProperty("coreCount", coreCount); + + return data; + } + + /** + * Collects the data and sends it afterwards. + */ + private void submitData() + { + final JsonObject data = getServerData(); + + JsonArray pluginData = new JsonArray(); + // Search for all other bStats Metrics classes to get their plugin data + for(Class service : Bukkit.getServicesManager().getKnownServices()) + { + try + { + service.getField("B_STATS_VERSION"); // Our identifier :) + + for(RegisteredServiceProvider provider : Bukkit.getServicesManager().getRegistrations(service)) + { + try + { + Object plugin = provider.getService().getMethod("getPluginData").invoke(provider.getProvider()); + if(plugin instanceof JsonObject) + { + pluginData.add((JsonObject) plugin); + } + else + { // old bstats version compatibility + try + { + Class jsonObjectJsonSimple = Class.forName("org.json.simple.JSONObject"); + if(plugin.getClass().isAssignableFrom(jsonObjectJsonSimple)) + { + Method jsonStringGetter = jsonObjectJsonSimple.getDeclaredMethod("toJSONString"); + jsonStringGetter.setAccessible(true); + String jsonString = (String) jsonStringGetter.invoke(plugin); + JsonObject object = new JsonParser().parse(jsonString).getAsJsonObject(); + pluginData.add(object); + } + } + catch(ClassNotFoundException e) + { + // minecraft version 1.14+ + if(logFailedRequests) + { + this.plugin.getLogger().log(Level.SEVERE, "Encountered unexpected exception ", e); + } + } + } + } + catch(NullPointerException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) + { + } + } + } + catch(NoSuchFieldException ignored) + { + } + } + + data.add("plugins", pluginData); + + // Create a new thread for the connection to the bStats server + new Thread(() -> + { + try + { + // Send the data + sendData(plugin, data); + } + catch(Exception e) + { + // Something went wrong! :( + if(logFailedRequests) + { + plugin.getLogger().log(Level.WARNING, "Could not submit plugin stats of " + plugin.getName(), e); + } + } + }).start(); + } + + /** + * Sends the data to the bStats server. + * + * @param plugin + * Any plugin. It's just used to get a logger instance. + * @param data + * The data to send. + * @throws Exception + * If the request failed. + */ + private static void sendData(Plugin plugin, JsonObject data) throws Exception + { + if(data == null) + { + throw new IllegalArgumentException("Data cannot be null!"); + } + if(Bukkit.isPrimaryThread()) + { + throw new IllegalAccessException("This method must not be called from the main thread!"); + } + if(logSentData) + { + plugin.getLogger().info("Sending data to bStats: " + data); + } + HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection(); + + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + + // Add headers + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format + connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION); + + // Send data + connection.setDoOutput(true); + try(DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) + { + outputStream.write(compressedData); + } + + StringBuilder builder = new StringBuilder(); + try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) + { + String line; + while((line = bufferedReader.readLine()) != null) + { + builder.append(line); + } + } + + if(logResponseStatusText) + { + plugin.getLogger().info("Sent data to bStats and received response: " + builder); + } + } + + /** + * Gzips the given String. + * + * @param str + * The string to gzip. + * @return The gzipped String. + * @throws IOException + * If the compression failed. + */ + private static byte[] compress(final String str) throws IOException + { + if(str == null) + { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try(GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) + { + gzip.write(str.getBytes(StandardCharsets.UTF_8)); + } + return outputStream.toByteArray(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/volmit/iris/util/PrecisionStopwatch.java b/src/main/java/com/volmit/iris/util/PrecisionStopwatch.java index ecf051c58..5b6995c3d 100644 --- a/src/main/java/com/volmit/iris/util/PrecisionStopwatch.java +++ b/src/main/java/com/volmit/iris/util/PrecisionStopwatch.java @@ -98,4 +98,9 @@ public class PrecisionStopwatch { public boolean isProfiling() { return profiling; } + + public void rewind(long l) + { + startMillis -= l; + } } diff --git a/src/main/java/com/volmit/iris/util/PregenJob.java b/src/main/java/com/volmit/iris/util/PregenJob.java index 22019ac87..ffea08d9a 100644 --- a/src/main/java/com/volmit/iris/util/PregenJob.java +++ b/src/main/java/com/volmit/iris/util/PregenJob.java @@ -12,15 +12,16 @@ import org.bukkit.event.Listener; import org.bukkit.event.world.ChunkUnloadEvent; import com.volmit.iris.Iris; +import com.volmit.iris.IrisSettings; import com.volmit.iris.gen.IrisTerrainProvider; import com.volmit.iris.gen.scaffold.IrisWorlds; import com.volmit.iris.gui.PregenGui; import io.papermc.lib.PaperLib; -import org.bukkit.scheduler.BukkitTask; public class PregenJob implements Listener { + private static PregenJob instance; private World world; private int size; private int total; @@ -52,13 +53,15 @@ public class PregenJob implements Listener private long nogen = M.ms(); private KList requeueMCA = new KList(); private RollingSequence acps = new RollingSequence(PaperLib.isPaper() ? 8 : 32); - private BukkitTask pausedTask; - private boolean isPaused = false; + private boolean paused = false; + private long pausedAt = 0; + private double pms = 0; int xc = 0; public PregenJob(World world, int size, MortarSender sender, Runnable onDone) { g.set(0); + instance = this; working = new Semaphore(tc()); this.s = PrecisionStopwatch.start(); Iris.instance.registerListener(this); @@ -105,7 +108,7 @@ public class PregenJob implements Listener public int tc() { - return 48; + return IrisSettings.get().maxAsyncChunkPregenThreads; } public static void stop() @@ -127,42 +130,36 @@ public class PregenJob implements Listener task = -1; } - // TODO: Cannot get paused value from this. Have to check bukkit tasks, not sure how. - // TODO: Trying to add functionality here to allow for pausing an continuing. - public static boolean isPaused(){ - return false; - //return this.isPaused; - } - public static void pause() { - try + if(instance.paused) { - // Save the task, tell bukkit to cancel it - stop(); + return; } - catch(Throwable e) - { - } - task = -1; + instance.pms = instance.s.getMilliseconds(); + instance.paused = true; + instance.pausedAt = M.ms(); } public static void resume() { - try + if(!instance.paused) { - // Load task and tell bukkit to continue it + return; } - catch(Throwable e) - { - } - task = -1; + instance.paused = false; + instance.s.rewind(instance.pausedAt - M.ms()); } public void onTick() { + if(paused) + { + return; + } + if(completed) { return; @@ -192,7 +189,11 @@ public class PregenJob implements Listener private void tickMetrics() { long eta = (long) ((total - genned) * (s.getMilliseconds() / (double) genned)); - String ss = "Pregen: " + Form.pc(Math.min((double) genned / (double) total, 1.0), 0) + ", Elapsed: " + Form.duration((long) s.getMilliseconds()) + ", ETA: " + (genned >= total - 5 ? "Any second..." : s.getMilliseconds() < 25000 ? "Calculating..." : Form.duration(eta)) + " MS: " + Form.duration((s.getMilliseconds() / (double) genned), 2); + String ss = "Pregen: " + Form.pc(Math.min((double) genned / (double) total, 1.0), 0) + ", Elapsed: " + + + Form.duration((long) (paused ? pms : s.getMilliseconds())) + + + ", ETA: " + (genned >= total - 5 ? "Any second..." : s.getMilliseconds() < 25000 ? "Calculating..." : Form.duration(eta)) + " MS: " + Form.duration((s.getMilliseconds() / (double) genned), 2); Iris.info(ss); if(sender.isPlayer() && sender.player().isOnline()) { @@ -459,7 +460,30 @@ public class PregenJob implements Listener { long eta = (long) ((total - genned) * 1000D / cps); - return new String[] {"Progress: " + Form.pc(Math.min((double) genned / (double) total, 1.0), 0), "Generated: " + Form.f(genned) + " Chunks", "Remaining: " + Form.f(total - genned) + " Chunks", "Elapsed: " + Form.duration((long) s.getMilliseconds(), 2), "Estimate: " + ((genned >= total - 5 ? "Any second..." : s.getMilliseconds() < 25000 ? "Calculating..." : Form.duration(eta, 2))), "ChunksMS: " + Form.duration(1000D / cps, 2), "Chunks/s: " + Form.f(cps, 1), + return new String[] {"Progress: " + Form.pc(Math.min((double) genned / (double) total, 1.0), 0), "Generated: " + Form.f(genned) + " Chunks", "Remaining: " + Form.f(total - genned) + " Chunks", "Elapsed: " + Form.duration((long) (paused ? pms : s.getMilliseconds()), 2), "Estimate: " + ((genned >= total - 5 ? "Any second..." : s.getMilliseconds() < 25000 ? "Calculating..." : Form.duration(eta, 2))), "ChunksMS: " + Form.duration(1000D / cps, 2), "Chunks/s: " + Form.f(cps, 1), }; } + + public static void pauseResume() + { + if(instance.paused) + { + resume(); + } + + else + { + pause(); + } + } + + public static boolean isPaused() + { + return instance.paused; + } + + public boolean paused() + { + return paused; + } } \ No newline at end of file