diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index fd49641ec..6aa236a30 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -30,6 +30,7 @@ import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.v1X.NMSBinding1X; import com.volmit.iris.core.pregenerator.LazyPregenerator; +import com.volmit.iris.core.service.ChunkHandlerSVC; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.engine.EnginePanic; @@ -39,7 +40,7 @@ import com.volmit.iris.engine.object.IrisWorld; import com.volmit.iris.engine.platform.BukkitChunkGenerator; import com.volmit.iris.engine.platform.DummyChunkGenerator; import com.volmit.iris.engine.safeguard.IrisSafeguard; -import com.volmit.iris.engine.safeguard.ServerBoot; +import com.volmit.iris.engine.safeguard.UtilsSFG; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.exceptions.IrisException; @@ -52,6 +53,7 @@ import com.volmit.iris.util.io.InstanceState; import com.volmit.iris.util.io.JarScanner; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.misc.getHardware; import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.plugin.IrisService; import com.volmit.iris.util.plugin.Metrics; @@ -94,7 +96,9 @@ import java.util.Date; import java.util.Map; import static com.volmit.iris.engine.safeguard.IrisSafeguard.unstablemode; -import static com.volmit.iris.engine.safeguard.ServerBoot.passedserversoftware; +import static com.volmit.iris.engine.safeguard.ServerBootSFG.passedserversoftware; +import static com.volmit.iris.util.misc.getHardware.getCPUModel; +import static com.volmit.iris.util.misc.getHardware.getCPUThreads; @SuppressWarnings("CanBeFinal") public class Iris extends VolmitPlugin implements Listener { @@ -438,7 +442,7 @@ public class Iris extends VolmitPlugin implements Listener { private static void fixShading() { ShadeFix.fix(ComponentSerializer.class); } - + private ChunkHandlerSVC chunkHandlerSVC; private void enable() { instance = this; services = new KMap<>(); @@ -446,6 +450,7 @@ public class Iris extends VolmitPlugin implements Listener { INMS.get(); IO.delete(new File("iris")); setupAudience(); + IrisSafeguard.IrisSafeguardSystem(); sender = new VolmitSender(Bukkit.getConsoleSender()); sender.setTag(getTag()); instance = this; @@ -465,9 +470,14 @@ public class Iris extends VolmitPlugin implements Listener { J.s(this::setupPapi); J.a(ServerConfigurator::configure, 20); splash(); - ServerBoot.UnstableMode(); - ServerBoot.SupportedServerSoftware(); - ServerBoot.printincompatiblepluginWarnings(); + UtilsSFG.UnstableMode(); + UtilsSFG.SupportedServerSoftware(); + UtilsSFG.printIncompatibleWarnings(); + UtilsSFG.unstablePrompt(); + if(IrisSettings.get().getGeneral().useIntegratedChunkHandler) { + chunkHandlerSVC = new ChunkHandlerSVC(this); + Iris.info(C.LIGHT_PURPLE + "Started Intergrated ChunkHandlerSVC"); + } autoStartStudio(); checkForBukkitWorlds(); IrisToolbelt.retainMantleDataForSlice(String.class.getCanonicalName()); @@ -555,7 +565,6 @@ public class Iris extends VolmitPlugin implements Listener { enable(); super.onEnable(); Bukkit.getPluginManager().registerEvents(this, this); - IrisSafeguard.IrisSafeguardSystem(); setupChecks(); } @@ -587,7 +596,12 @@ public class Iris extends VolmitPlugin implements Listener { @Override public String getTag(String subTag) { - return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.IRIS + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": "; + if (unstablemode) { + return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.RED + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": "; + } + else { + return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.IRIS + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": "; + } } private boolean setupChecks() { @@ -731,6 +745,10 @@ public class Iris extends VolmitPlugin implements Listener { String padd = Form.repeat(" ", 8); String padd2 = Form.repeat(" ", 4); String[] info = {"", "", "", "", "", padd2 + C.IRIS + " Iris", padd2 + C.GRAY + " by " + "Volmit Software", padd2 + C.GRAY + " v" + C.IRIS + getDescription().getVersion()}; + if (unstablemode) { + info = new String[]{"", "", "", "", "", padd2 + C.RED + " Iris", padd2 + C.GRAY + " by " + C.DARK_RED + "Volmit Software", padd2 + C.GRAY + " v" + C.RED + getDescription().getVersion()}; + } + String[] splashstable = { padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@", padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.IRIS + " .(((()))). ", @@ -761,7 +779,6 @@ public class Iris extends VolmitPlugin implements Listener { String[] splash = unstablemode ? splashunstable : splashstable; // Choose the appropriate splash array based on unstablemode - long maxMemory = Runtime.getRuntime().maxMemory() / (1024 * 1024); OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); String osArch = osBean.getArch(); String osName = osBean.getName(); @@ -771,8 +788,16 @@ public class Iris extends VolmitPlugin implements Listener { } else { Iris.info("Server type & version: " + Bukkit.getVersion()); } Iris.info("Server OS: " + osName + " (" + osArch + ")"); - Iris.info("Process Memory: " + maxMemory + " MB"); - if (maxMemory < 5999) { + + if(unstablemode) Iris.info("Server Cpu: " + C.DARK_RED + getCPUModel()); + + if(getCPUModel().contains("Intel")) Iris.info("Server Cpu: " + C.BLUE + getCPUModel()); + if(getCPUModel().contains("Ryzen")) Iris.info("Server Cpu: " + C.RED + getCPUModel()); + if(!getCPUModel().contains("Intel") && !getCPUModel().contains("Ryzen")) Iris.info("Server Cpu: " + C.DARK_GRAY + getCPUModel()); + + Iris.info("Process Threads: " + getCPUThreads()); + Iris.info("Process Memory: " + getHardware.getProcessMemory() + " MB"); + if (getHardware.getProcessMemory() < 5999) { Iris.warn("6GB+ Ram is recommended"); } Iris.info("Bukkit version: " + Bukkit.getBukkitVersion()); 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 3d2a381d6..2c570a788 100644 --- a/core/src/main/java/com/volmit/iris/core/IrisSettings.java +++ b/core/src/main/java/com/volmit/iris/core/IrisSettings.java @@ -145,6 +145,8 @@ public class IrisSettings { @Data public static class IrisSettingsGeneral { + public boolean bootUnstable = false; + public boolean useIntegratedChunkHandler = false; public boolean commandSounds = true; public boolean debug = false; public boolean disableNMS = false; diff --git a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java index 58a05d43c..98a5fc7be 100644 --- a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java +++ b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java @@ -61,13 +61,12 @@ public class ServerConfigurator { long tt = f.getLong("settings.timeout-time"); if (tt < TimeUnit.MINUTES.toSeconds(5)) { - Iris.warn("Updating spigot.yml timeout-time: " + tt + " -> " + TimeUnit.MINUTES.toSeconds(5) + " (5 minutes)"); + Iris.warn("Updating spigot.yml timeout-time: " + tt + " -> " + TimeUnit.MINUTES.toSeconds(20) + " (5 minutes)"); Iris.warn("You can disable this change (autoconfigureServer) in Iris settings, then change back the value."); f.set("settings.timeout-time", TimeUnit.MINUTES.toSeconds(5)); f.save(spigotConfig); } } - private static void increasePaperWatchdog() throws IOException, InvalidConfigurationException { File spigotConfig = new File("config/paper-global.yml"); FileConfiguration f = new YamlConfiguration(); @@ -75,7 +74,7 @@ public class ServerConfigurator { long tt = f.getLong("watchdog.early-warning-delay"); if (tt < TimeUnit.MINUTES.toMillis(3)) { - Iris.warn("Updating paper.yml watchdog early-warning-delay: " + tt + " -> " + TimeUnit.MINUTES.toMillis(3) + " (3 minutes)"); + Iris.warn("Updating paper.yml watchdog early-warning-delay: " + tt + " -> " + TimeUnit.MINUTES.toMillis(15) + " (3 minutes)"); Iris.warn("You can disable this change (autoconfigureServer) in Iris settings, then change back the value."); f.set("watchdog.early-warning-delay", TimeUnit.MINUTES.toMillis(3)); f.save(spigotConfig); diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java index 481d3b2dd..2a4dd688a 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java @@ -22,11 +22,13 @@ import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.tools.IrisBenchmarking; +import com.volmit.iris.core.tools.IrisCreator; import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisDimension; +import com.volmit.iris.engine.object.IrisWorld; import com.volmit.iris.engine.platform.PlatformChunkGenerator; -import com.volmit.iris.engine.safeguard.ServerBoot; +import com.volmit.iris.engine.safeguard.UtilsSFG; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.decree.DecreeContext; import com.volmit.iris.util.decree.DecreeExecutor; @@ -36,11 +38,13 @@ import com.volmit.iris.util.decree.annotations.Param; import com.volmit.iris.util.decree.specialhandlers.NullablePlayerHandler; import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; +import com.volmit.iris.util.mantle.MantleChunk; import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.jobs.QueueJob; +import lombok.Getter; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.World; @@ -48,11 +52,14 @@ import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import java.io.File; +import java.io.IOException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import static com.volmit.iris.core.service.EditSVC.deletingWorld; import static com.volmit.iris.core.tools.IrisBenchmarking.inProgress; -import static com.volmit.iris.engine.safeguard.ServerBoot.multiverse; +import static com.volmit.iris.engine.safeguard.IrisSafeguard.unstablemode; +import static com.volmit.iris.engine.safeguard.ServerBootSFG.incompatiblePlugins; @Decree(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command") public class CommandIris implements DecreeExecutor { @@ -66,6 +73,8 @@ public class CommandIris implements DecreeExecutor { private CommandFind find; private CommandWorldManager manager; + public static @Getter String BenchDimension; + @Decree(description = "Create a new world", aliases = {"+", "c"}) public void create( @Param(aliases = "world-name", description = "The name of the world to create") @@ -75,19 +84,34 @@ public class CommandIris implements DecreeExecutor { @Param(description = "The seed to generate the world with", defaultValue = "1337") long seed ) { - if (multiverse){ - sender().sendMessage(C.RED + "Your server has an incompatibility that may corrupt all worlds on the server if not handled properly."); - sender().sendMessage(C.RED + "it is strongly advised for you to take action. see log for full detail"); - Iris.safeguard(C.RED + "----------------------------------------------------------------"); - Iris.safeguard(C.RED + "Command ran: /iris create"); - ServerBoot.printincompatiblepluginWarnings(); - Iris.safeguard(C.RED + "----------------------------------------------------------------"); - } - if (name.equals("iris")) { - sender().sendMessage(C.RED + "You cannot use the world name \"iris\" for creating worlds as Iris uses this directory for studio worlds."); - sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?"); - return; + if(sender() instanceof Player) { + if (incompatiblePlugins.get("Multiverse-Core")) { + sender().sendMessage(C.RED + "Your server has an incompatibility that may corrupt all worlds on the server if not handled properly."); + sender().sendMessage(C.RED + "it is strongly advised for you to take action. see log for full detail"); + sender().sendMessage(C.RED + "----------------------------------------------------------------"); + sender().sendMessage(C.RED + "Command ran: /iris create"); + sender().sendMessage(C.RED + UtilsSFG.MSGIncompatibleWarnings()); + sender().sendMessage(C.RED + "----------------------------------------------------------------"); + } + if (unstablemode && !incompatiblePlugins.get("Multiverse-Core")) { + sender().sendMessage(C.RED + "Your server is experiencing an incompatibility with the Iris plugin."); + sender().sendMessage(C.RED + "Please rectify this problem to avoid further complications."); + sender().sendMessage(C.RED + "----------------------------------------------------------------"); + sender().sendMessage(C.RED + "Command ran: /iris create"); + sender().sendMessage(C.RED + UtilsSFG.MSGIncompatibleWarnings()); + sender().sendMessage(C.RED + "----------------------------------------------------------------"); + } } + if (name.equals("iris")) { + sender().sendMessage(C.RED + "You cannot use the world name \"iris\" for creating worlds as Iris uses this directory for studio worlds."); + sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?"); + return; + } + if (name.equals("Benchmark")) { + sender().sendMessage(C.RED + "You cannot use the world name \"Benchmark\" for creating worlds as Iris uses this directory for Benchmarking Packs."); + sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?"); + return; + } if (new File(Bukkit.getWorldContainer(), name).exists()) { sender().sendMessage(C.RED + "That folder already exists!"); @@ -142,13 +166,43 @@ public class CommandIris implements DecreeExecutor { sender().sendMessage(C.GREEN + "Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software"); } @Decree(description = "Benchmark your server", origin = DecreeOrigin.CONSOLE) - public void benchmark() throws InterruptedException { + public void serverbenchmark() throws InterruptedException { if(!inProgress) { IrisBenchmarking.runBenchmark(); } else { Iris.info(C.RED + "Benchmark already is in progress."); } } + /* + /todo Fix PREGEN + @Decree(description = "Benchmark a pack", origin = DecreeOrigin.CONSOLE) + public void packbenchmark( + @Param(description = "Dimension to benchmark") + IrisDimension type + ) throws InterruptedException { + + BenchDimension = type.getLoadKey(); + + IrisPackBenchmarking.runBenchmark(); + } */ + + /* /todo Different approach this feels useless atm + @Decree(description = "Check for instabilities", origin = DecreeOrigin.CONSOLE) + public void fixunstable() throws InterruptedException { + if (unstablemode){ + sender().sendMessage(C.RED + "Incompatibilities are posted in console.."); + + Iris.info(C.RED + "Your server is experiencing an incompatibility with the Iris plugin."); + Iris.info(C.RED + "Please rectify this problem to avoid further complications."); + Iris.info(C.RED + "----------------------------------------------------------------"); + Iris.info(C.RED + "Command ran: /iris fixunstable"); + UtilsSFG.printIncompatibleWarnings(); + Iris.info(C.RED + "----------------------------------------------------------------"); + } else { + Iris.info(C.BLUE + "Iris is running stable.."); + sender().sendMessage("Iris is running stable.."); + } + } */ @Decree(description = "Print world height information", origin = DecreeOrigin.PLAYER) public void height() { @@ -162,6 +216,67 @@ public class CommandIris implements DecreeExecutor { Iris.service(StudioSVC.class).open(sender(), 1337, "overworld"); } + @Decree(description = "Remove an Iris world", aliases = {"del", "rm", "delete"}, sync = true) + public void remove( + @Param(description = "The world to remove") + World world, + @Param(description = "Whether to also remove the folder (if set to false, just does not load the world)", defaultValue = "true") + boolean delete + ) { + if (!IrisToolbelt.isIrisWorld(world)) { + sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", Bukkit.getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList())); + return; + } + sender().sendMessage(C.GREEN + "Removing world: " + world.getName()); + try { + if (IrisToolbelt.removeWorld(world)) { + sender().sendMessage(C.GREEN + "Successfully removed " + world.getName() + " from bukkit.yml"); + } else { + sender().sendMessage(C.YELLOW + "Looks like the world was already removed from bukkit.yml"); + } + } catch (IOException e) { + sender().sendMessage(C.RED + "Failed to save bukkit.yml because of " + e.getMessage()); + e.printStackTrace(); + } + IrisToolbelt.evacuate(world, "Deleting world"); + deletingWorld = true; + Bukkit.unloadWorld(world, false); + int retries = 10; + if (delete) { + if (deleteDirectory(world.getWorldFolder())) { + sender().sendMessage(C.GREEN + "Successfully removed world folder"); + } else { + while(true){ + if (deleteDirectory(world.getWorldFolder())){ + sender().sendMessage(C.GREEN + "Successfully removed world folder"); + break; + } + sender().sendMessage(C.GREEN + "DEBUG1"); + retries--; + if (retries == 0){ + sender().sendMessage(C.RED + "Failed to remove world folder"); + break; + } + J.sleep(2000); + } + } + } + deletingWorld = false; + } + + public static boolean deleteDirectory(File dir) { + if (dir.isDirectory()) { + File[] children = dir.listFiles(); + for (int i = 0; i < children.length; i++) { + boolean success = deleteDirectory(children[i]); + if (!success) { + return false; + } + } + } + return dir.delete(); + } + @Decree(description = "Set aura spins") public void aura( @Param(description = "The h color value", defaultValue = "-20") 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 32906de2a..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 @@ package com.volmit.iris.core.commands; 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.Decree; 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,35 +43,75 @@ public class CommandPregen implements DecreeExecutor { @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(); + } } - 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(); + } + } + } else { + sender().sendMessage(C.RED + "Please use a valid method."); + } + } @Decree(description = "Stop the active pregeneration task", aliases = "x") public void stop() { if (PregeneratorJob.shutdownInstance()) { - sender().sendMessage(C.GREEN + "Stopped pregeneration task"); + Iris.info( C.BLUE + "Finishing up mca region..."); + sender().sendMessage(C.DARK_BLUE + "Stopped pregeneration task"); } else { sender().sendMessage(C.YELLOW + "No active pregeneration tasks to stop"); } 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 b080dee01..16405436c 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 @@ -281,6 +281,7 @@ public class CommandStudio implements DecreeExecutor { @Param(description = "The dimension to profile", contextual = true, defaultValue = "default") IrisDimension dimension ) { + // Todo: Make this more accurate File pack = dimension.getLoadFile().getParentFile().getParentFile(); File report = Iris.instance.getDataFile("profile.txt"); IrisProject project = new IrisProject(pack); diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandWorldManager.java b/core/src/main/java/com/volmit/iris/core/commands/CommandWorldManager.java index 7fd039764..1f82ea3d9 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandWorldManager.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandWorldManager.java @@ -147,51 +147,6 @@ public class CommandWorldManager implements DecreeExecutor { sender().sendMessage(C.GREEN + "Evacuating world" + world.getName()); IrisToolbelt.evacuate(world); } - @Decree(description = "Remove an Iris world", aliases = {"del", "rm", "delete"}, sync = true) - public void remove( - @Param(description = "The world to remove") - World world, - @Param(description = "Whether to also remove the folder (if set to false, just does not load the world)", defaultValue = "true") - boolean delete - ) { - if (!IrisToolbelt.isIrisWorld(world)) { - sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", Bukkit.getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList())); - return; - } - sender().sendMessage(C.GREEN + "Removing world: " + world.getName()); - try { - if (IrisToolbelt.removeWorld(world)) { - sender().sendMessage(C.GREEN + "Successfully removed " + world.getName() + " from bukkit.yml"); - } else { - sender().sendMessage(C.YELLOW + "Looks like the world was already removed from bukkit.yml"); - } - } catch (IOException e) { - sender().sendMessage(C.RED + "Failed to save bukkit.yml because of " + e.getMessage()); - e.printStackTrace(); - } - IrisToolbelt.evacuate(world, "Deleting world"); - Bukkit.unloadWorld(world, false); - if (delete) { - if (deleteDirectory(world.getWorldFolder())) { - sender().sendMessage(C.GREEN + "Successfully removed world folder"); - } else { - sender().sendMessage(C.RED + "Failed to remove world folder"); - } - } - - } - public static boolean deleteDirectory(File dir) { - if (dir.isDirectory()) { - File[] children = dir.listFiles(); - for (int i = 0; i < children.length; i++) { - boolean success = deleteDirectory(children[i]); - if (!success) { - return false; - } - } - } - return dir.delete(); - } boolean doesWorldExist(String worldName) { File worldContainer = Bukkit.getWorldContainer(); 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 9ef0faebf..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 @@ -19,7 +19,9 @@ package com.volmit.iris.core.pregenerator; import com.volmit.iris.Iris; +import com.volmit.iris.core.tools.IrisPackBenchmarking; import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.math.M; @@ -28,12 +30,16 @@ import com.volmit.iris.util.math.RollingSequence; import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.Looper; +import lombok.Getter; +import lombok.Setter; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import static com.volmit.iris.core.tools.IrisPackBenchmarking.benchmark; + public class IrisPregenerator { private final PregenTask task; private final PregeneratorMethod generator; @@ -44,10 +50,10 @@ public class IrisPregenerator { private final RollingSequence chunksPerSecond; private final RollingSequence chunksPerMinute; private final RollingSequence regionsPerMinute; - private final AtomicInteger generated; + private static AtomicInteger generated; private final AtomicInteger generatedLast; private final AtomicInteger generatedLastMinute; - private final AtomicInteger totalChunks; + private static AtomicInteger totalChunks; private final AtomicLong startTime; private final ChronoLatch minuteLatch; private final AtomicReference currentGeneratorMethod; @@ -56,6 +62,8 @@ public class IrisPregenerator { private final KSet net; private final ChronoLatch cl; private final ChronoLatch saveLatch = new ChronoLatch(30000); + static long long_generatedChunks = 0; + static long long_totalChunks = 0; public IrisPregenerator(PregenTask task, PregeneratorMethod generator, PregenListener listener) { this.listener = listenify(listener); @@ -92,6 +100,8 @@ public class IrisPregenerator { chunksPerMinute.put(minuteGenerated); regionsPerMinute.put((double) minuteGenerated / 1024D); } + long_generatedChunks = generated.get(); + long_totalChunks = totalChunks.get(); listener.onTick(chunksPerSecond.getAverage(), chunksPerMinute.getAverage(), regionsPerMinute.getAverage(), @@ -102,9 +112,12 @@ public class IrisPregenerator { if (cl.flip()) { double percentage = ((double) generated.get() / (double) totalChunks.get()) * 100; - Iris.info("Pregen: " + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (%.0f%%) " + Form.f((int) chunksPerSecond.getAverage()) + "/s ETA: " + Form.duration((double) eta, 2), percentage); + if(benchmark) { + Iris.info(C.GREEN +"Benchmark: " + C.WHITE + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (%.0f%%) " + Form.f((int) chunksPerSecond.getAverage()) + "/s ETA: " + Form.duration((double) eta, 2), percentage); + } else { + Iris.info("Pregen: " + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (%.0f%%) " + Form.f((int) chunksPerSecond.getAverage()) + "/s ETA: " + Form.duration((double) eta, 2), percentage); + } } - return 1000; } }; @@ -119,6 +132,14 @@ public class IrisPregenerator { ); } + public static long getLongGeneratedChunks() { + return long_generatedChunks; + } + public static long getLongTotalChunks() { + return long_totalChunks; + } + + public void close() { shutdown.set(true); } 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 @@ package com.volmit.iris.core.pregenerator; 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 org.bukkit.event.world.WorldUnloadEvent; 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 class LazyPregenerator extends Thread implements Listener { }).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 class LazyPregenerator extends Thread implements Listener { 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 class LazyPregenerator extends Thread implements Listener { } } + 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 @@ public class LazyPregenerator extends Thread implements Listener { 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/service/ChunkHandlerSVC.java b/core/src/main/java/com/volmit/iris/core/service/ChunkHandlerSVC.java new file mode 100644 index 000000000..c245653be --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/service/ChunkHandlerSVC.java @@ -0,0 +1,163 @@ +package com.volmit.iris.core.service; + +import com.volmit.iris.core.tools.IrisToolbelt; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.world.ChunkLoadEvent; +import org.bukkit.event.world.ChunkUnloadEvent; +import org.bukkit.event.world.WorldLoadEvent; +import org.bukkit.event.world.WorldUnloadEvent; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +public class ChunkHandlerSVC implements Listener { + // Idk how it works but it works lol + private final JavaPlugin plugin; + private static BukkitTask task; + private final Map worlds = new ConcurrentHashMap<>(); + + private static final Map> playersInChunk = new ConcurrentHashMap<>(); + + public ChunkHandlerSVC(JavaPlugin plugin) { + this.plugin = plugin; + Bukkit.getPluginManager().registerEvents(this, plugin); + + for (World world : Bukkit.getWorlds()) { + if (IrisToolbelt.isIrisWorld(world)) { + worlds.put(world, new ChunkUnloader(plugin, world)); + } + } + + startTask(); + } + + private void startTask() { + if (task == null) { + task = new BukkitRunnable() { + @Override + public void run() { + worlds.values().forEach(ChunkUnloader::update); + } + }.runTaskTimerAsynchronously(plugin, 0L, 1L); + } + } + + @EventHandler + public void onPlayerMove(PlayerMoveEvent event) { + Player player = event.getPlayer(); + Chunk previousChunk = event.getFrom().getChunk(); + Chunk currentChunk = event.getTo().getChunk(); + + if (!previousChunk.equals(currentChunk)) { + playersInChunk.computeIfAbsent(previousChunk, k -> ConcurrentHashMap.newKeySet()).remove(player); + playersInChunk.computeIfAbsent(currentChunk, k -> ConcurrentHashMap.newKeySet()).add(player); + } + } + + public static void exit() { + if (task != null) { + task.cancel(); + } + } + + @EventHandler + public void onWorldLoad(WorldLoadEvent event) { + World world = event.getWorld(); + if (IrisToolbelt.isIrisWorld(world)) { + worlds.put(world, new ChunkUnloader(plugin, world)); + } + } + + @EventHandler + public void onWorldUnload(WorldUnloadEvent event) { + worlds.remove(event.getWorld()); + } + + @EventHandler + public void onChunkLoad(ChunkLoadEvent event) { + World world = event.getWorld(); + if (worlds.containsKey(world)) { + worlds.get(world).onChunkLoad(event.getChunk()); + } + } + + @EventHandler + public void onChunkUnload(ChunkUnloadEvent event) { + World world = event.getWorld(); + if (worlds.containsKey(world)) { + worlds.get(world).onChunkUnload(event.getChunk()); + } + } + + private static class ChunkUnloader { + private final JavaPlugin plugin; + private final World world; + private final Map chunks = new ConcurrentHashMap<>(); + + private ChunkUnloader(JavaPlugin plugin, World world) { + this.plugin = plugin; + this.world = world; + } + + public void onChunkLoad(Chunk chunk) { + // System.out.printf("%s > Loaded Chunk [x=%s, z=%s]%n", world.getName(), chunk.getX(), chunk.getZ()); + chunks.put(chunk, System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(3)); + } + + public void onChunkUnload(Chunk chunk) { + chunks.remove(chunk); + playersInChunk.remove(chunk); + } + + public void update() { + try { + long currentTime = System.currentTimeMillis(); + Set chunkSet = new HashSet<>(chunks.keySet()); + for (Chunk chunk : chunkSet) { + if (!chunk.isLoaded()) { + continue; + } + + if (isChunkNearby(chunk)) { + chunks.put(chunk, currentTime + TimeUnit.MINUTES.toMillis(3)); + } else if (chunks.get(chunk) <= currentTime) { + unloadChunk(chunk); + } + } + } catch (Exception e) { + // Log the error message + System.out.println("Error in update method: " + e.getMessage()); + } + } + + + private boolean isChunkNearby(Chunk chunk) { + Set players = playersInChunk.get(chunk); + if (players == null) { + players = ConcurrentHashMap.newKeySet(); + playersInChunk.put(chunk, players); + } + return !players.isEmpty(); + } + + private void unloadChunk(Chunk chunk) { + try { + // System.out.printf("%s > Unloading Chunk [x=%s, z=%s]%n", world.getName(), chunk.getX(), chunk.getZ()); + Bukkit.getScheduler().runTask(plugin, () -> chunk.unload(true)); + } catch (Exception e) { + System.out.println("Error unloading chunk: " + e.getMessage()); + } + } + } +} diff --git a/core/src/main/java/com/volmit/iris/core/service/EditSVC.java b/core/src/main/java/com/volmit/iris/core/service/EditSVC.java index 834b1712a..dc944f1f2 100644 --- a/core/src/main/java/com/volmit/iris/core/service/EditSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/EditSVC.java @@ -33,6 +33,7 @@ import org.bukkit.event.world.WorldUnloadEvent; public class EditSVC implements IrisService { private KMap editors; + public static boolean deletingWorld = false; @Override public void onEnable() { @@ -71,11 +72,12 @@ public class EditSVC implements IrisService { @EventHandler public void on(WorldUnloadEvent e) { - if (editors.containsKey(e.getWorld())) { + if (editors.containsKey(e.getWorld()) && !deletingWorld) { editors.remove(e.getWorld()).close(); } } + public void update() { for (World i : editors.k()) { if (M.ms() - editors.get(i).last() > 1000) { diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisBenchmarking.java b/core/src/main/java/com/volmit/iris/core/tools/IrisBenchmarking.java index 5503815a7..300a4467f 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisBenchmarking.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisBenchmarking.java @@ -27,11 +27,11 @@ import java.io.IOException; import java.io.InputStreamReader; import static com.google.common.math.LongMath.isPrime; - +import static com.volmit.iris.util.misc.getHardware.getCPUModel; +import static com.volmit.iris.util.misc.getHardware.getDiskModel; public class IrisBenchmarking { static String ServerOS; static String filePath = "benchmark.dat"; - private static long startTime; static double avgWriteSpeedMBps; static double avgReadSpeedMBps; static double highestWriteSpeedMBps; @@ -56,6 +56,7 @@ public class IrisBenchmarking { static boolean Winsat = false; static boolean WindowsDiskSpeed = false; public static boolean inProgress = false; + static double startTime; // Good enough for now. . . public static void runBenchmark() throws InterruptedException { @@ -237,29 +238,6 @@ public class IrisBenchmarking { return false; } - public static String getCPUModel() { - try { - SystemInfo systemInfo = new SystemInfo(); - CentralProcessor processor = systemInfo.getHardware().getProcessor(); - String cpuModel = processor.getProcessorIdentifier().getName(); - return cpuModel.isEmpty() ? "Unknown CPU Model" : cpuModel; - } catch (Exception e) { - e.printStackTrace(); - return "Unknown CPU Model"; - } - } - - public static String getDiskModel() { - SystemInfo systemInfo = new SystemInfo(); - List diskStores = systemInfo.getHardware().getDiskStores(); - if (!diskStores.isEmpty()) { - HWDiskStore firstDisk = diskStores.get(0); - return firstDisk.getModel(); - } else { - return "Unknown Disk Model"; - } - } - public static void warningFallback() { Iris.info(C.RED + "Using the " + C.DARK_RED + "FALLBACK" + C.RED + " method due to compatibility issues. "); Iris.info(C.RED + "Please note that this may result in less accurate results."); @@ -645,6 +623,4 @@ public class IrisBenchmarking { return 0.0; } - // todo JMH BENCHMARKS - } \ No newline at end of file diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java b/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java index 372a63a74..04e8b9cba 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java @@ -26,6 +26,7 @@ import com.volmit.iris.core.pregenerator.PregenTask; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.platform.PlatformChunkGenerator; +import com.volmit.iris.engine.safeguard.UtilsSFG; import com.volmit.iris.util.exceptions.IrisException; import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; @@ -45,6 +46,9 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; +import static com.volmit.iris.core.tools.IrisPackBenchmarking.benchmark; +import static com.volmit.iris.engine.safeguard.IrisSafeguard.unstablemode; + /** * Makes it a lot easier to setup an engine, world, studio or whatever */ @@ -93,6 +97,9 @@ public class IrisCreator { yml.save(BUKKIT_YML); return true; } + public static boolean worldLoaded(){ + return true; + } /** * Create the IrisAccess (contains the world) @@ -100,7 +107,15 @@ public class IrisCreator { * @return the IrisAccess * @throws IrisException shit happens */ + IrisPackBenchmarking PackBench = new IrisPackBenchmarking(); public World create() throws IrisException { + if (unstablemode){ + Iris.info(C.RED + "Your server is experiencing an incompatibility with the Iris plugin. Please rectify this problem to avoid further complications."); + Iris.info(C.RED + "----------------------------------------------------------------"); + Iris.info(C.RED + "Operation ran: Loading Iris World.."); + UtilsSFG.printIncompatibleWarnings(); + Iris.info(C.RED + "----------------------------------------------------------------"); + } if (Bukkit.isPrimaryThread()) { throw new IrisException("You cannot invoke create() on the main thread."); } @@ -117,6 +132,9 @@ public class IrisCreator { if (!studio()) { Iris.service(StudioSVC.class).installIntoWorld(sender, d.getLoadKey(), new File(Bukkit.getWorldContainer(), name())); } + if (benchmark) { + Iris.service(StudioSVC.class).installIntoWorld(sender, d.getLoadKey(), new File(Bukkit.getWorldContainer(), name())); + } PlatformChunkGenerator access = null; AtomicReference world = new AtomicReference<>(); @@ -143,17 +161,19 @@ public class IrisCreator { } return finalAccess1.getEngine().getGenerated(); }; - while (g.get() < req) { - double v = (double) g.get() / (double) req; - - if (sender.isPlayer()) { - sender.sendProgress(v, "Generating"); - J.sleep(16); - } else { - sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - g.get()) + " Left)"))); - J.sleep(1000); + if(!benchmark) { + while (g.get() < req) { + double v = (double) g.get() / (double) req; + if (sender.isPlayer()) { + sender.sendProgress(v, "Generating"); + J.sleep(16); + } else { + sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - g.get()) + " Left)"))); + J.sleep(1000); + } } } + //if (benchmark){loaded = true;} }); @@ -177,7 +197,7 @@ public class IrisCreator { }); } - if (studio) { + if (studio || benchmark) { J.s(() -> { Iris.linkMultiverseCore.removeFromConfig(world.get()); 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 new file mode 100644 index 000000000..13577cc82 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisPackBenchmarking.java @@ -0,0 +1,170 @@ +package com.volmit.iris.core.tools; + + +import com.volmit.iris.Iris; +import com.volmit.iris.core.pregenerator.IrisPregenerator; +import com.volmit.iris.core.pregenerator.LazyPregenerator; +import com.volmit.iris.core.pregenerator.PregenTask; +import com.volmit.iris.util.exceptions.IrisException; +import com.volmit.iris.util.format.C; +import com.volmit.iris.util.math.Position2; + +import com.volmit.iris.util.scheduling.J; +import org.apache.commons.io.FileUtils; +import org.bukkit.Bukkit; + +import java.io.File; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import static com.volmit.iris.core.commands.CommandIris.BenchDimension; + + +public class IrisPackBenchmarking { + public static boolean loaded = false; + public static boolean benchmark = false; + static boolean cancelled = false; + static boolean pregenInProgress = false; + static long startTime; + static long totalChunks; + static long generatedChunks; + static double elapsedTimeNs; + + public static void runBenchmark() { + // IrisPackBenchmarking IrisPackBenchmarking = new IrisPackBenchmarking(); + benchmark = true; + Iris.info(C.BLUE + "Benchmarking Dimension: " + C.AQUA + BenchDimension); + //progress(); + CompletableFuture future = CompletableFuture.runAsync(() -> { + Iris.info(C.GOLD + "Setting everything up.."); + try { + String BenchmarkFolder = "\\Benchmark"; + File folder = new File(BenchmarkFolder); + if (folder.exists() && folder.isDirectory()) { + FileUtils.deleteDirectory(folder); + Iris.debug("Deleted old Benchmark"); + } else { + Iris.info(C.GOLD + "Old Benchmark not found!"); + if(folder.exists()){ + Iris.info(C.RED + "FAILED To remove old Benchmark!"); + //cancelled = true; + + } + } + } catch (Exception e) { + throw new RuntimeException(); + } + + }).thenRun(() -> { + Iris.info(C.GOLD + "Creating Benchmark Environment"); + createBenchmark(); + + }).thenRun(() -> { + Iris.info( C.BLUE + "Benchmark Started!"); + boolean done = false; + startBenchmarkTimer(); + startBenchmark(); + basicScheduler(); + }).thenRun(() -> { + + }); + // cancelled = future.cancel(true); + try { + future.get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + } + + private static void results(){ + double averageCps = calculateAverageCPS(); + Iris.info("Benchmark Dimension: " + BenchDimension); + Iris.info("Speeds"); + Iris.info("- Average CPS: " + roundToTwoDecimalPlaces(averageCps)); + Iris.info("Duration: " + roundToTwoDecimalPlaces(elapsedTimeNs)); + + } + private static void basicScheduler() { + while (true) { + totalChunks = IrisPregenerator.getLongTotalChunks(); + generatedChunks = IrisPregenerator.getLongGeneratedChunks(); + if(totalChunks > 0) { + if (generatedChunks >= totalChunks) { + Iris.info("Benchmark Completed!"); + elapsedTimeNs = stopBenchmarkTimer(); + results(); + break; + } + } + //J.sleep(100); test + } + } + static void createBenchmark(){ + try { + IrisToolbelt.createWorld() + .dimension(BenchDimension) + .name("Benchmark") + .seed(1337) + .studio(false) + .create(); + } catch (IrisException e) { + throw new RuntimeException(e); + } + } + static void startBenchmark(){ + int x = 0; + int z = 0; + IrisToolbelt.pregenerate(PregenTask + .builder() + .center(new Position2(x, z)) + .width(5) + .height(5) + .build(), Bukkit.getWorld("Benchmark") + ); + } + static void startLazyBenchmark(){ + int x = 0; + int z = 0; + LazyPregenerator.LazyPregenJob pregenJob = LazyPregenerator.LazyPregenJob.builder() + //.world("Benchmark") + .healingPosition(0) + .healing(false) + .chunksPerMinute(3200) + .radiusBlocks(5000) + .position(0) + .build(); + + LazyPregenerator pregenerator = new LazyPregenerator(pregenJob, new File("plugins/Iris/lazygen.json")); + pregenerator.start(); + } + public static double calculateAverageCPS() { + double elapsedTimeSec = elapsedTimeNs / 1_000_000_000.0; // Convert to seconds + return generatedChunks / elapsedTimeSec; + } + + private static void startBenchmarkTimer() { + startTime = System.nanoTime(); + } + + private static double stopBenchmarkTimer() { + long endTime = System.nanoTime(); + return (endTime - startTime) / 1_000_000_000.0; + } + + public static void deleteDirectory(File dir) { + File[] files = dir.listFiles(); + if(files != null) { + for(File file: files) { + if(file.isDirectory()) { + deleteDirectory(file); + } else { + file.delete(); + } + } + } + dir.delete(); + } + private static double roundToTwoDecimalPlaces(double value) { + return Double.parseDouble(String.format("%.2f", value)); + } +} \ No newline at end of file diff --git a/core/src/main/java/com/volmit/iris/engine/IrisEngineMantle.java b/core/src/main/java/com/volmit/iris/engine/IrisEngineMantle.java index 2ba5b5526..d7a88eb77 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisEngineMantle.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisEngineMantle.java @@ -19,6 +19,8 @@ package com.volmit.iris.engine; import com.volmit.iris.Iris; +import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.tools.IrisPackBenchmarking; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.mantle.EngineMantle; @@ -31,6 +33,7 @@ import com.volmit.iris.engine.object.*; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KSet; +import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.parallel.BurstExecutor; @@ -42,6 +45,9 @@ import java.io.IOException; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import static com.volmit.iris.core.tools.IrisPackBenchmarking.benchmark; +import static com.volmit.iris.engine.safeguard.PerformanceSFG.lowPerformance; + @Data public class IrisEngineMantle implements EngineMantle { private final Engine engine; @@ -280,10 +286,21 @@ public class IrisEngineMantle implements EngineMantle { x = Math.max(x, c); x = (Math.max(x, 16) + 16) >> 4; x = x % 2 == 0 ? x + 1 : x; - Iris.info("Mantle Size: " + x + " Chunks"); - Iris.info(" Object Mantle Size: " + u + " (" + ((Math.max(u, 16) + 16) >> 4) + ")"); - Iris.info(" Jigsaw Mantle Size: " + jig + " (" + ((Math.max(jig, 16) + 16) >> 4) + ")"); - Iris.info(" Carving Mantle Size: " + c + " (" + ((Math.max(c, 16) + 16) >> 4) + ")"); + if (benchmark){ + x = 4; + Iris.info("Mantle Size: " + x + " Chunks " + C.BLUE + "BENCHMARK MODE"); + } else { + if(lowPerformance){ + x = 4; + Iris.info("Mantle Size: " + x + " Chunks" + C.GOLD + "LOW PERFORMANCE MODE"); + } else { + Iris.info("Mantle Size: " + x + " Chunks"); + Iris.info(" Object Mantle Size: " + u + " (" + ((Math.max(u, 16) + 16) >> 4) + ")"); + Iris.info(" Jigsaw Mantle Size: " + jig + " (" + ((Math.max(jig, 16) + 16) >> 4) + ")"); + Iris.info(" Carving Mantle Size: " + c + " (" + ((Math.max(c, 16) + 16) >> 4) + ")"); + } + } + return x; } diff --git a/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java b/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java index b3dae5bf0..9d7283d49 100644 --- a/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java +++ b/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java @@ -101,7 +101,7 @@ public class PlannedStructure { int sz = (v.getD() / 2); int xx = i.getPosition().getX() + sx; int zz = i.getPosition().getZ() + sz; - RNG rngf = new RNG(Cache.key(xx, zz)); + RNG rng = new RNG(Cache.key(xx, zz)); int offset = i.getPosition().getY() - startHeight; int height; diff --git a/core/src/main/java/com/volmit/iris/engine/safeguard/IrisSafeguard.java b/core/src/main/java/com/volmit/iris/engine/safeguard/IrisSafeguard.java index 439668519..218fc4845 100644 --- a/core/src/main/java/com/volmit/iris/engine/safeguard/IrisSafeguard.java +++ b/core/src/main/java/com/volmit/iris/engine/safeguard/IrisSafeguard.java @@ -7,7 +7,7 @@ public class IrisSafeguard { public static boolean unstablemode = false; public static void IrisSafeguardSystem() { Iris.info("Enabled Iris SafeGuard"); - ServerBoot.BootCheck(); + ServerBootSFG.BootCheck(); } } diff --git a/core/src/main/java/com/volmit/iris/engine/safeguard/PerformanceSFG.java b/core/src/main/java/com/volmit/iris/engine/safeguard/PerformanceSFG.java new file mode 100644 index 000000000..35ea78a57 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/engine/safeguard/PerformanceSFG.java @@ -0,0 +1,15 @@ +package com.volmit.iris.engine.safeguard; + +import com.volmit.iris.core.IrisSettings; +import oshi.SystemInfo; +import oshi.hardware.GlobalMemory; + +import static com.volmit.iris.util.misc.getHardware.*; + +public class PerformanceSFG { + public static boolean lowPerformance = false; + public static void calculatePerformance(){ + + + } +} diff --git a/core/src/main/java/com/volmit/iris/engine/safeguard/SafeguardUtils.java b/core/src/main/java/com/volmit/iris/engine/safeguard/SafeguardUtils.java deleted file mode 100644 index 221ef1d66..000000000 --- a/core/src/main/java/com/volmit/iris/engine/safeguard/SafeguardUtils.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.volmit.iris.engine.safeguard; -public class SafeguardUtils { - public static void resetdatapacks(){ - - } -} diff --git a/core/src/main/java/com/volmit/iris/engine/safeguard/ServerBoot.java b/core/src/main/java/com/volmit/iris/engine/safeguard/ServerBoot.java deleted file mode 100644 index 27f993b9f..000000000 --- a/core/src/main/java/com/volmit/iris/engine/safeguard/ServerBoot.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.volmit.iris.engine.safeguard; - -import com.volmit.iris.Iris; -import com.volmit.iris.core.nms.INMS; -import com.volmit.iris.core.nms.v1X.NMSBinding1X; -import com.volmit.iris.util.format.C; -import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; - -import static com.volmit.iris.Iris.instance; -import static com.volmit.iris.engine.safeguard.IrisSafeguard.unstablemode; - -public class ServerBoot { - public static boolean multiverse = false; - public static boolean dynmap = false; - public static boolean terraform = false; - public static boolean stratos = false; - public static boolean correctversion = true; - - protected static boolean safeguardPassed; - public static boolean passedserversoftware = true; - protected static byte count; - - public static void BootCheck() { - Iris.info("Checking for possible conflicts.."); - org.bukkit.plugin.PluginManager pluginManager = Bukkit.getPluginManager(); - Plugin[] plugins = pluginManager.getPlugins(); - if (INMS.get() instanceof NMSBinding1X) { - unstablemode = true; - correctversion = false; - } - - StringBuilder pluginList = new StringBuilder("Plugin list: "); - count = 0; - - for (Plugin plugin : plugins) { - String pluginName = plugin.getName(); - if (pluginName.equalsIgnoreCase("Multiverse-Core")) { - multiverse = true; - count++; - } - if (pluginName.equalsIgnoreCase("Dynmap")) { - dynmap = true; - count++; - } - if (pluginName.equalsIgnoreCase("TerraformGenerator")) { - terraform = true; - count++; - } - if (pluginName.equalsIgnoreCase("Stratos")) { - stratos = true; - count++; - } - pluginList.append(pluginName).append(", "); - } - - if ( - !instance.getServer().getVersion().contains("Purpur") && - !instance.getServer().getVersion().contains("Paper") && - !instance.getServer().getVersion().contains("Spigot") && - !instance.getServer().getVersion().contains("Pufferfish") && - !instance.getServer().getVersion().contains("Bukkit")) - { - unstablemode = true; - passedserversoftware = false; - } - - safeguardPassed = (count == 0); - if(!safeguardPassed){ - unstablemode = true; - } - if (unstablemode){ - Iris.safeguard("Unstable mode has been activated."); - } - Iris.safeguard(pluginList.toString()); - - } - public static void UnstableMode(){ - if (unstablemode) { - Iris.safeguard(C.DARK_RED + "Iris is running in Unstable Mode"); - } else { - Iris.safeguard(C.BLUE + "Iris is running Stable"); - } - } - public static void SupportedServerSoftware(){ - if (!passedserversoftware) { - Iris.safeguard(C.DARK_RED + "Server is running unsupported server software"); - Iris.safeguard(C.RED + "Supported: Purpur, Pufferfish, Paper, Spigot, Bukkit"); - } - } - public static void printincompatiblepluginWarnings(){ - - if (safeguardPassed) { - Iris.safeguard(C.BLUE + "0 Conflicts found"); - } else { - Iris.safeguard(C.DARK_RED + "" + count + " Conflicts found"); - unstablemode = true; - - if (multiverse) { - Iris.safeguard(C.RED + "Multiverse"); - Iris.safeguard(C.RED + "- The plugin Multiverse is not compatible with the server."); - Iris.safeguard(C.RED + "- If you want to have a world manager, consider using PhantomWorlds or MyWorlds instead."); - } - if (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."); - } - if (terraform || stratos) { - Iris.safeguard(C.YELLOW + "Terraform Generator / Stratos"); - Iris.safeguard(C.YELLOW + "- Iris is not compatible with other worldgen plugins."); - } - } - } -} diff --git a/core/src/main/java/com/volmit/iris/engine/safeguard/ServerBootSFG.java b/core/src/main/java/com/volmit/iris/engine/safeguard/ServerBootSFG.java new file mode 100644 index 000000000..713b3cbef --- /dev/null +++ b/core/src/main/java/com/volmit/iris/engine/safeguard/ServerBootSFG.java @@ -0,0 +1,78 @@ +package com.volmit.iris.engine.safeguard; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMS; +import com.volmit.iris.core.nms.v1X.NMSBinding1X; +import com.volmit.iris.util.format.C; +import lombok.Getter; +import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; + +import java.util.*; + +import static com.volmit.iris.Iris.dump; +import static com.volmit.iris.Iris.instance; +import static com.volmit.iris.engine.safeguard.IrisSafeguard.unstablemode; + +public class ServerBootSFG { + public static final Map incompatiblePlugins = new HashMap<>(); + public static boolean unsuportedversion = false; + protected static boolean safeguardPassed; + public static boolean passedserversoftware = true; + protected static byte count; + public static String allIncompatiblePlugins; + + public static void BootCheck() { + Iris.info("Checking for possible conflicts.."); + org.bukkit.plugin.PluginManager pluginManager = Bukkit.getPluginManager(); + Plugin[] plugins = pluginManager.getPlugins(); + + incompatiblePlugins.clear(); + incompatiblePlugins.put("Multiverse-Core", false); + incompatiblePlugins.put("Dynmap", false); + incompatiblePlugins.put("TerraformGenerator", false); + incompatiblePlugins.put("Stratos", false); + + String pluginName; + for (Plugin plugin : plugins) { + pluginName = plugin.getName(); + Boolean flag = incompatiblePlugins.get(pluginName); + if (flag != null && !flag) { + count++; + incompatiblePlugins.put(pluginName, true); + } + } + + StringJoiner joiner = new StringJoiner(", "); + for (Map.Entry entry : incompatiblePlugins.entrySet()) { + if (entry.getValue()) { + joiner.add(entry.getKey()); + } + } + if ( + !instance.getServer().getVersion().contains("Purpur") && + !instance.getServer().getVersion().contains("Paper") && + !instance.getServer().getVersion().contains("Spigot") && + !instance.getServer().getVersion().contains("Pufferfish") && + !instance.getServer().getVersion().contains("Bukkit")) + { + passedserversoftware = false; + joiner.add("Server Software"); + count++; + } + if (INMS.get() instanceof NMSBinding1X) { + unsuportedversion = true; + joiner.add("Unsupported Minecraft Version"); + count++; + } + + allIncompatiblePlugins = joiner.toString(); + + safeguardPassed = (count == 0); + if(!safeguardPassed){ + unstablemode = true; + Iris.safeguard("Unstable mode has been activated."); + } + + } +} 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 new file mode 100644 index 000000000..fa94e33a3 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/engine/safeguard/UtilsSFG.java @@ -0,0 +1,99 @@ +package com.volmit.iris.engine.safeguard; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.util.format.C; + +import static com.volmit.iris.engine.safeguard.IrisSafeguard.unstablemode; +import static com.volmit.iris.engine.safeguard.ServerBootSFG.*; + +public class UtilsSFG { + public static void UnstableMode(){ + if (unstablemode) { + Iris.safeguard(C.DARK_RED + "Iris is running in Unstable Mode"); + } else { + Iris.safeguard(C.BLUE + "Iris is running Stable"); + } + } + public static void SupportedServerSoftware(){ + if (!passedserversoftware) { + Iris.safeguard(C.DARK_RED + "Server is running unsupported server software"); + Iris.safeguard(C.RED + "Supported: Purpur, Pufferfish, Paper, Spigot, Bukkit"); + } + } + public static void printIncompatibleWarnings(){ + // String SupportedIrisVersion = getDescription().getVersion(); //todo Automatic version + + if (safeguardPassed) { + Iris.safeguard(C.BLUE + "0 Conflicts found"); + } else { + Iris.safeguard(C.DARK_RED + "" + count + " Conflicts found"); + unstablemode = true; + + if (incompatiblePlugins.get("Multiverse-Core")) { + Iris.safeguard(C.RED + "Multiverse"); + Iris.safeguard(C.RED + "- The plugin Multiverse is not compatible with the server."); + Iris.safeguard(C.RED + "- If you want to have a world manager, consider using PhantomWorlds or MyWorlds instead."); + } + 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."); + } + if (incompatiblePlugins.get("TerraformGenerator") || incompatiblePlugins.get("Stratos")) { + Iris.safeguard(C.YELLOW + "Terraform Generator / Stratos"); + Iris.safeguard(C.YELLOW + "- Iris is not compatible with other worldgen plugins."); + } + if (unsuportedversion) { + Iris.safeguard(C.RED + "Server Version"); + Iris.safeguard(C.RED + "- Iris only supports 1.19.2 > 1.20.2"); + } + if (!passedserversoftware) { + Iris.safeguard(C.RED + "Unsupported Server Software"); + Iris.safeguard(C.RED + "- Please consider using Paper or Purpur instead."); + + } + } + } + + public static String MSGIncompatibleWarnings() { + return allIncompatiblePlugins; + } + + + public static void unstablePrompt() { + if (unstablemode) { + Iris.info(""); + Iris.info(C.DARK_GRAY + "--==<" + C.RED + " IMPORTANT " + C.DARK_GRAY + ">==--"); + Iris.info(C.RED + "Iris is running in unstable mode what may cause the following issues."); + Iris.info(C.DARK_RED + "Server Issues"); + Iris.info(C.RED + "- Server wont boot"); + Iris.info(C.RED + "- Data Loss"); + Iris.info(C.RED + "- Unexpected behavior."); + Iris.info(C.RED + "- And More.."); + Iris.info(C.DARK_RED + "World Issues"); + Iris.info(C.RED + "- Worlds cant load due to corruption.."); + Iris.info(C.RED + "- Worlds may slowly corrupt till they wont be able to load."); + Iris.info(C.RED + "- World data loss."); + Iris.info(C.RED + "- And More.."); + Iris.info(C.DARK_RED + "ATTENTION:" + C.RED + " While running iris in unstable mode you wont be eligible for support."); + Iris.info(C.DARK_RED + "CAUSE: " + C.RED + MSGIncompatibleWarnings()); + Iris.info(""); + if (IrisSettings.get().getGeneral().bootUnstable) { + Iris.info(C.DARK_RED + "Boot Unstable is set to true, continuing with the startup process."); + } + + if (!IrisSettings.get().getGeneral().isBootUnstable()) { + Iris.info(C.DARK_RED + "Go to plugins/iris/settings.json and set ignoreUnstable to true if you wish to proceed."); + while (true) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // No + } + } + } + Iris.info(""); + } + } +} diff --git a/core/src/main/java/com/volmit/iris/util/misc/getHardware.java b/core/src/main/java/com/volmit/iris/util/misc/getHardware.java new file mode 100644 index 000000000..ea5aa06d5 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/misc/getHardware.java @@ -0,0 +1,48 @@ +package com.volmit.iris.util.misc; + +import oshi.SystemInfo; +import oshi.hardware.CentralProcessor; +import oshi.hardware.HWDiskStore; +import oshi.software.os.OperatingSystem; + +import java.util.List; + +public class getHardware { + public static String getServerOS() { + SystemInfo systemInfo = new SystemInfo(); + OperatingSystem os = systemInfo.getOperatingSystem(); + return os.toString(); + } + public static int getCPUThreads(){ + SystemInfo systemInfo = new SystemInfo(); + CentralProcessor processor = systemInfo.getHardware().getProcessor(); + return processor.getLogicalProcessorCount(); + } + public static long getProcessMemory(){ + long maxMemory = Runtime.getRuntime().maxMemory() / (1024 * 1024); + return maxMemory; + } + + public static String getCPUModel() { + try { + SystemInfo systemInfo = new SystemInfo(); + CentralProcessor processor = systemInfo.getHardware().getProcessor(); + String cpuModel = processor.getProcessorIdentifier().getName(); + return cpuModel.isEmpty() ? "Unknown CPU Model" : cpuModel; + } catch (Exception e) { + e.printStackTrace(); + return "Unknown CPU Model"; + } + } + + public static String getDiskModel() { + SystemInfo systemInfo = new SystemInfo(); + List diskStores = systemInfo.getHardware().getDiskStores(); + if (!diskStores.isEmpty()) { + HWDiskStore firstDisk = diskStores.get(0); + return firstDisk.getModel(); + } else { + return "Unknown Disk Model"; + } + } +}