diff --git a/build.gradle b/build.gradle index 2484924d8..77c48256c 100644 --- a/build.gradle +++ b/build.gradle @@ -237,6 +237,8 @@ allprojects { implementation "net.kyori:adventure-text-minimessage:4.13.1" implementation 'net.kyori:adventure-platform-bukkit:4.3.2' implementation 'net.kyori:adventure-api:4.13.1' + //implementation 'org.bytedeco:javacpp:1.5.10' + //implementation 'org.bytedeco:cuda-platform:12.3-8.9-1.5.10' compileOnly 'io.lumine:Mythic-Dist:5.2.1' // Dynamically Loaded diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index 9fec3b7e8..950913796 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -806,9 +806,6 @@ public class Iris extends VolmitPlugin implements Listener { } else { splash = splashstable; } - OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); - String osArch = osBean.getArch(); - String osName = osBean.getName(); if (!passedserversoftware) { Iris.info("Server type & version: " + C.RED + Bukkit.getVersion()); @@ -821,35 +818,9 @@ public class Iris extends VolmitPlugin implements Listener { Iris.info(C.YELLOW + "Purpur is recommended to use with iris."); } } - Iris.info("Server OS: " + osName + " (" + osArch + ")"); - - try { - if (warningmode){ - Iris.info("Server Cpu: " + C.GOLD + getCPUModel()); - } else { - if(unstablemode){ - Iris.info("Server Cpu: " + C.DARK_RED + getCPUModel()); - } else { - 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("Ryzen") && !getCPUModel().contains("Intel")) { - Iris.info("Server Cpu: " + C.GRAY + getCPUModel()); - } - } - } - } catch (Exception e){ - Iris.info("Server Cpu: " + C.DARK_RED + "Failed"); - } - - Iris.info("Process Threads: " + Runtime.getRuntime().availableProcessors()); - Iris.info("Process Memory: " + getHardware.getProcessMemory() + " MB"); - Iris.info("Free DiskSpace: " + Form.ofSize(freeSpace.getFreeSpace(), 1024)); if (getHardware.getProcessMemory() < 5999) { Iris.warn("6GB+ Ram is recommended"); + Iris.warn("Process Memory: " + getHardware.getProcessMemory() + " MB"); } Iris.info("Bukkit version: " + Bukkit.getBukkitVersion()); Iris.info("Custom Biomes: " + INMS.get().countCustomBiomes()); 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 6ec02ef7f..ad77d9268 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 @@ -21,6 +21,7 @@ package com.volmit.iris.core.commands; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.loader.IrisData; +import com.volmit.iris.core.pregenerator.ChunkUpdater; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.tools.IrisBenchmarking; import com.volmit.iris.core.tools.IrisToolbelt; @@ -37,6 +38,7 @@ import com.volmit.iris.util.decree.annotations.Decree; 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.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; import lombok.Getter; @@ -76,6 +78,7 @@ public class CommandIris implements DecreeExecutor { private CommandWhat what; private CommandEdit edit; private CommandFind find; + private CommandSupport support; private CommandDeveloper developer; public static boolean worldCreation = false; String WorldEngine; @@ -317,6 +320,24 @@ public class CommandIris implements DecreeExecutor { return dir.delete(); } + @Decree(description = "Updates all chunk in the specified world") + public void updater( + @Param(description = "World to update chunks at") + World world + ) { + if (!IrisToolbelt.isIrisWorld(world)) { + sender().sendMessage(C.GOLD + "This is not an Iris world"); + return; + } + ChunkUpdater updater = new ChunkUpdater(world); + if (sender().isPlayer()) { + sender().sendMessage(C.GREEN + "Updating " + world.getName() + " Total chunks: " + Form.f(updater.getChunks())); + } else { + Iris.info(C.GREEN + "Updating " + world.getName() + " Total chunks: " + Form.f(updater.getChunks())); + } + updater.start(); + } + @Decree(description = "Set aura spins") public void aura( @Param(description = "The h color value", defaultValue = "-20") @@ -512,6 +533,7 @@ public class CommandIris implements DecreeExecutor { } catch (IOException e) { Iris.error("Failed to update bukkit.yml!"); e.printStackTrace(); + return; } } checkForBukkitWorlds(world); diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandSupport.java b/core/src/main/java/com/volmit/iris/core/commands/CommandSupport.java new file mode 100644 index 000000000..0f7baad0d --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandSupport.java @@ -0,0 +1,82 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2022 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.volmit.iris.core.commands; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.loader.IrisData; +import com.volmit.iris.core.pregenerator.ChunkUpdater; +import com.volmit.iris.core.service.IrisEngineSVC; +import com.volmit.iris.core.tools.IrisPackBenchmarking; +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.util.collection.KList; +import com.volmit.iris.util.decree.DecreeExecutor; +import com.volmit.iris.util.decree.DecreeOrigin; +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.format.Form; +import com.volmit.iris.util.io.IO; +import com.volmit.iris.util.mantle.TectonicPlate; +import com.volmit.iris.util.misc.Hastebin; +import com.volmit.iris.util.misc.Platform; +import com.volmit.iris.util.misc.getHardware; +import com.volmit.iris.util.nbt.mca.MCAFile; +import com.volmit.iris.util.nbt.mca.MCAUtil; +import com.volmit.iris.util.plugin.VolmitSender; +import net.jpountz.lz4.LZ4BlockInputStream; +import net.jpountz.lz4.LZ4BlockOutputStream; +import net.jpountz.lz4.LZ4FrameInputStream; +import net.jpountz.lz4.LZ4FrameOutputStream; +import org.apache.commons.lang.RandomStringUtils; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.World; +import oshi.SystemInfo; + +import java.io.*; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +@Decree(name = "Support", origin = DecreeOrigin.BOTH, description = "Iris World Manager", aliases = {"support"}) +public class CommandSupport implements DecreeExecutor { + + @Decree(description = "report") + public void report() { + try { + if (sender().isPlayer()) sender().sendMessage(C.GOLD + "Creating report.."); + if (!sender().isPlayer()) Iris.info(C.GOLD + "Creating report.."); + Hastebin.enviornment(sender()); + + } catch (Exception e) { + Iris.info(C.RED + "Something went wrong: "); + e.printStackTrace(); + } + } + + +} + + diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandUpdater.java b/core/src/main/java/com/volmit/iris/core/commands/CommandUpdater.java new file mode 100644 index 000000000..cb1ff6eeb --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandUpdater.java @@ -0,0 +1,107 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2022 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.volmit.iris.core.commands; + +import org.bukkit.World; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.pregenerator.ChunkUpdater; +import com.volmit.iris.core.tools.IrisToolbelt; +import com.volmit.iris.util.decree.DecreeExecutor; +import com.volmit.iris.util.decree.DecreeOrigin; +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.format.Form; + +@Decree(name = "Updater", origin = DecreeOrigin.BOTH, description = "Iris World Updater") +public class CommandUpdater implements DecreeExecutor { + private ChunkUpdater chunkUpdater; + + @Decree(description = "Updates all chunk in the specified world") + public void start( + @Param(description = "World to update chunks at") + World world + ) { + if (!IrisToolbelt.isIrisWorld(world)) { + sender().sendMessage(C.GOLD + "This is not an Iris world"); + return; + } + chunkUpdater = new ChunkUpdater(world); + if (sender().isPlayer()) { + sender().sendMessage(C.GREEN + "Updating " + world.getName() + C.GRAY + " Total chunks: " + Form.f(chunkUpdater.getChunks())); + } else { + Iris.info(C.GREEN + "Updating " + world.getName() + C.GRAY + " Total chunks: " + Form.f(chunkUpdater.getChunks())); + } + chunkUpdater.start(); + } + + @Decree(description = "Pause the updater") + public void pause( + @Param(description = "World to pause the Updater at") + World world + ) { + if (!IrisToolbelt.isIrisWorld(world)) { + sender().sendMessage(C.GOLD + "This is not an Iris world"); + return; + } + if (chunkUpdater == null) { + sender().sendMessage(C.GOLD + "You cant pause something that doesnt exist?"); + return; + } + boolean status = chunkUpdater.pause(); + if (sender().isPlayer()) { + if (status) { + sender().sendMessage(C.IRIS + "Paused task for: " + C.GRAY + world.getName()); + } else { + sender().sendMessage(C.IRIS + "Unpause task for: " + C.GRAY + world.getName()); + } + } else { + if (status) { + Iris.info(C.IRIS + "Paused task for: " + C.GRAY + world.getName()); + } else { + Iris.info(C.IRIS + "Unpause task for: " + C.GRAY + world.getName()); + } + } + } + + @Decree(description = "Stops the updater") + public void stop( + @Param(description = "World to stop the Updater at") + World world + ) { + if (!IrisToolbelt.isIrisWorld(world)) { + sender().sendMessage(C.GOLD + "This is not an Iris world"); + return; + } + if (chunkUpdater == null) { + sender().sendMessage(C.GOLD + "You cant stop something that doesnt exist?"); + return; + } + if (sender().isPlayer()) { + sender().sendMessage("Stopping Updater for: " + C.GRAY + world.getName()); + } else { + Iris.info("Stopping Updater for: " + C.GRAY + world.getName()); + } + chunkUpdater.stop(); + } + +} + + diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/ChunkUpdater.java b/core/src/main/java/com/volmit/iris/core/pregenerator/ChunkUpdater.java index 1e40ab566..d89ad3340 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/ChunkUpdater.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/ChunkUpdater.java @@ -1,70 +1,271 @@ package com.volmit.iris.core.pregenerator; import com.volmit.iris.Iris; +import com.volmit.iris.core.tools.IrisToolbelt; +import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.format.Form; +import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RollingSequence; import com.volmit.iris.util.math.Spiraler; -import com.volmit.iris.util.nbt.mca.MCAFile; -import com.volmit.iris.util.nbt.mca.MCAUtil; +import com.volmit.iris.util.scheduling.J; +import io.papermc.lib.PaperLib; +import org.bukkit.Chunk; import org.bukkit.World; - import java.io.File; +import java.util.ArrayList; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; public class ChunkUpdater { + private AtomicBoolean paused; private AtomicBoolean cancelled; - private KList chunkMap; + private KMap lastUse; private final RollingSequence chunksPerSecond; - private final RollingSequence mcaregionsPerSecond; private final AtomicInteger worldheightsize; private final AtomicInteger worldwidthsize; private final AtomicInteger totalChunks; private final AtomicInteger totalMaxChunks; private final AtomicInteger totalMcaregions; private final AtomicInteger position; - private final File[] McaFiles; + private AtomicInteger chunksProcessed; + private AtomicInteger chunksUpdated; + private AtomicLong startTime; + private ExecutorService executor; + private ExecutorService chunkExecutor; + private ScheduledExecutorService scheduler; + private CompletableFuture future; + private CountDownLatch latch; + private final Object pauseLock; + private final Engine engine; private final World world; public ChunkUpdater(World world) { - File cacheDir = new File("plugins" + File.separator + "iris" + File.separator + "cache"); - File chunkCacheDir = new File("plugins" + File.separator + "iris" + File.separator + "cache" + File.separator + "spiral"); - this.chunksPerSecond = new RollingSequence(10); - this.mcaregionsPerSecond = new RollingSequence(10); + this.engine = IrisToolbelt.access(world).getEngine(); + this.chunksPerSecond = new RollingSequence(5); this.world = world; - this.chunkMap = new KList<>(); - this.McaFiles = new File(world.getWorldFolder(), "region").listFiles((dir, name) -> name.endsWith(".mca")); + this.lastUse = new KMap(); this.worldheightsize = new AtomicInteger(calculateWorldDimensions(new File(world.getWorldFolder(), "region"), 1)); this.worldwidthsize = new AtomicInteger(calculateWorldDimensions(new File(world.getWorldFolder(), "region"), 0)); - this.totalMaxChunks = new AtomicInteger((worldheightsize.get() / 16 ) * (worldwidthsize.get() / 16)); + int m = Math.max(worldheightsize.get(), worldwidthsize.get()); + this.executor = Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors() / 3, 1)); + this.chunkExecutor = Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors() / 3, 1)); + this.scheduler = Executors.newScheduledThreadPool(1); + this.future = new CompletableFuture<>(); + this.startTime = new AtomicLong(); + this.worldheightsize.set(m); + this.worldwidthsize.set(m); + this.totalMaxChunks = new AtomicInteger((worldheightsize.get() / 16) * (worldwidthsize.get() / 16)); + this.chunksProcessed = new AtomicInteger(); + this.chunksUpdated = new AtomicInteger(); this.position = new AtomicInteger(0); + this.latch = new CountDownLatch(totalMaxChunks.get()); + this.paused = new AtomicBoolean(false); + this.pauseLock = new Object(); this.cancelled = new AtomicBoolean(false); this.totalChunks = new AtomicInteger(0); this.totalMcaregions = new AtomicInteger(0); } - public void start() { - Initialize(); + public int getChunks() { + return totalMaxChunks.get(); } - public void Initialize() { - Iris.info("Initializing.."); + public void start() { + unloadAndSaveAllChunks(); + update(); + } + + public boolean pause() { + unloadAndSaveAllChunks(); + if (paused.get()) { + paused.set(false); + return false; + } else { + paused.set(true); + return true; + } + } + + public void stop() { + unloadAndSaveAllChunks(); + cancelled.set(true); + } + + + private void update() { + Iris.info("Updating.."); try { - for (File mca : McaFiles) { - MCAFile MCARegion = MCAUtil.read(mca); - for (int pos = 0; pos != totalMaxChunks.get(); pos++) { - int[] coords = getChunk(pos); - if(MCARegion.hasChunk(coords[0], coords[1])) chunkMap.add(coords); + startTime.set(System.currentTimeMillis()); + scheduler.scheduleAtFixedRate(() -> { + try { + if (!paused.get()) { + long eta = computeETA(); + long elapsedSeconds = (System.currentTimeMillis() - startTime.get()) / 1000; + int processed = chunksProcessed.get(); + double cps = elapsedSeconds > 0 ? processed / (double) elapsedSeconds : 0; + chunksPerSecond.put(cps); + double percentage = ((double) chunksProcessed.get() / (double) totalMaxChunks.get()) * 100; + if (!cancelled.get()) { + Iris.info("Updated: " + Form.f(processed) + " of " + Form.f(totalMaxChunks.get()) + " (%.0f%%) " + Form.f(chunksPerSecond.getAverage()) + "/s, ETA: " + Form.duration(eta, + 2), percentage); + } + } + } catch (Exception e) { + e.printStackTrace(); } - } - Iris.info("Finished Initializing.."); + }, 0, 3, TimeUnit.SECONDS); + + CompletableFuture.runAsync(() -> { + for (int i = 0; i < totalMaxChunks.get(); i++) { + if (paused.get()) { + synchronized (pauseLock) { + try { + pauseLock.wait(); + } catch (InterruptedException e) { + Iris.error("Interrupted while waiting for executor: "); + e.printStackTrace(); + break; + } + } + } + executor.submit(() -> { + if (!cancelled.get()) { + processNextChunk(); + } + latch.countDown(); + }); + } + }).thenRun(() -> { + try { + latch.await(); + close(); + } catch (Exception e) { + Thread.currentThread().interrupt(); + } + }); + } catch (Exception e) { e.printStackTrace(); } } + public void close() { + try { + unloadAndSaveAllChunks(); + executor.shutdown(); + executor.awaitTermination(5, TimeUnit.SECONDS); + chunkExecutor.shutdown(); + chunkExecutor.awaitTermination(5, TimeUnit.SECONDS); + scheduler.shutdownNow(); + } catch (Exception ignored) { + } + if (cancelled.get()) { + Iris.info("Updated: " + Form.f(chunksUpdated.get()) + " Chunks"); + Iris.info("Irritated: " + Form.f(chunksProcessed.get()) + " of " + Form.f(totalMaxChunks.get())); + Iris.info("Stopped updater."); + } else { + Iris.info("Processed: " + Form.f(chunksProcessed.get()) + " Chunks"); + Iris.info("Finished Updating: " + Form.f(chunksUpdated.get()) + " Chunks"); + } + } + + private void processNextChunk() { + int pos = position.getAndIncrement(); + int[] coords = getChunk(pos); + if (loadChunksIfGenerated(coords[0], coords[1])) { + Chunk c = world.getChunkAt(coords[0], coords[1]); + engine.updateChunk(c); + chunksUpdated.incrementAndGet(); + } + chunksProcessed.getAndIncrement(); + } + + private boolean loadChunksIfGenerated(int x, int z) { + for (int dx = -1; dx <= 1; dx++) { + for (int dz = -1; dz <= 1; dz++) { + if (!PaperLib.isChunkGenerated(world, x + dx, z + dz)) { + return false; + } + } + } + + AtomicBoolean generated = new AtomicBoolean(true); + KList> futures = new KList<>(9); + for (int dx = -1; dx <= 1; dx++) { + for (int dz = -1; dz <= 1; dz++) { + int xx = x + dx; + int zz = z + dz; + futures.add(chunkExecutor.submit(() -> { + Chunk c; + try { + c = PaperLib.getChunkAtAsync(world, xx, zz, false).get(); + } catch (InterruptedException | ExecutionException e) { + generated.set(false); + return; + } + if (!c.isLoaded()) { + CountDownLatch latch = new CountDownLatch(1); + J.s(() -> { + c.load(false); + latch.countDown(); + }); + try { + latch.await(); + } catch (InterruptedException ignored) {} + } + if (!c.isGenerated()) { + generated.set(false); + } + lastUse.put(c, M.ms()); + })); + } + } + while (!futures.isEmpty()) { + futures.removeIf(Future::isDone); + try { + Thread.sleep(50); + } catch (InterruptedException ignored) {} + } + return generated.get(); + } + + private void unloadAndSaveAllChunks() { + try { + J.sfut(() -> { + if (world == null) { + Iris.warn("World was null somehow..."); + return; + } + + for (Chunk i : new ArrayList<>(lastUse.keySet())) { + Long lastUseTime = lastUse.get(i); + if (lastUseTime != null && M.ms() - lastUseTime >= 5000) { + i.unload(); + lastUse.remove(i); + } + } + world.save(); + }).get(); + } catch (Throwable e) { + e.printStackTrace(); + } + } + + private long computeETA() { + return (long) (totalMaxChunks.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) + ((totalMaxChunks.get() - chunksProcessed.get()) * ((double) (M.ms() - startTime.get()) / (double) chunksProcessed.get())) : + // If no, use quick function (which is less accurate over time but responds better to the initial delay) + ((totalMaxChunks.get() - chunksProcessed.get()) / chunksPerSecond.getAverage()) * 1000 + ); + } + public int calculateWorldDimensions(File regionDir, Integer o) { File[] files = regionDir.listFiles((dir, name) -> name.endsWith(".mca")); 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 300a4467f..79bf1b643 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 @@ -28,7 +28,6 @@ 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"; @@ -180,12 +179,12 @@ public class IrisBenchmarking { Iris.info("- Data Compression: " + formatDouble(calculateDataCompression) + " MBytes/Sec"); if (WindowsDiskSpeed) { - Iris.info("Disk Model: " + getDiskModel()); + //Iris.info("Disk Model: " + getDiskModel()); Iris.info(C.BLUE + "- Running with Windows System Assessment Tool"); Iris.info("- Sequential 64.0 Write: " + C.BLUE + formatDouble(avgWriteSpeedMBps) + " Mbps"); Iris.info("- Sequential 64.0 Read: " + C.BLUE + formatDouble(avgReadSpeedMBps) + " Mbps"); } else { - Iris.info("Disk Model: " + getDiskModel()); + // Iris.info("Disk Model: " + getDiskModel()); Iris.info(C.GREEN + "- Running in Native Mode"); Iris.info("- Average Write Speed: " + C.GREEN + formatDouble(avgWriteSpeedMBps) + " Mbps"); Iris.info("- Average Read Speed: " + C.GREEN + formatDouble(avgReadSpeedMBps) + " Mbps"); diff --git a/core/src/main/java/com/volmit/iris/util/misc/Hastebin.java b/core/src/main/java/com/volmit/iris/util/misc/Hastebin.java new file mode 100644 index 000000000..11e253b31 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/misc/Hastebin.java @@ -0,0 +1,135 @@ +package com.volmit.iris.util.misc; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.tools.IrisToolbelt; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.format.C; +import com.volmit.iris.util.format.Form; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import oshi.SystemInfo; + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.File; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.file.Files; +import java.util.List; + +public class Hastebin { + + public static void enviornment(CommandSender sender) { + // Construct the server information + StringBuilder sb = new StringBuilder(); + SystemInfo systemInfo = new SystemInfo(); + KList disks = new KList<>(getHardware.getDisk()); + KList interfaces = new KList<>(getHardware.getInterfaces()); + KList displays = new KList<>(getHardware.getEDID()); + KList sensors = new KList<>(getHardware.getSensors()); + KList gpus = new KList<>(getHardware.getGraphicsCards()); + KList powersources = new KList<>(getHardware.getPowerSources()); + + KList IrisWorlds = new KList<>(); + KList BukkitWorlds = new KList<>(); + + for (World w : Bukkit.getServer().getWorlds()) { + try { + Engine engine = IrisToolbelt.access(w).getEngine(); + if (engine != null) { + IrisWorlds.add(w); + } + } catch (Exception e) { + BukkitWorlds.add(w); + } + } + + sb.append(" -- == Iris Info == -- \n"); + sb.append("Iris Version Version: ").append(Iris.instance.getDescription().getVersion()).append("\n"); + sb.append("- Iris Worlds"); + for (World w : IrisWorlds.copy()) { + sb.append(" - ").append(w.getName()); + } + sb.append("- Bukkit Worlds"); + for (World w : BukkitWorlds.copy()) { + sb.append(" - ").append(w.getName()); + } + sb.append(" -- == Platform Overview == -- " + "\n"); + sb.append("Server Type: ").append(Bukkit.getVersion()).append("\n"); + sb.append("Server Uptime: ").append(Form.stampTime(systemInfo.getOperatingSystem().getSystemUptime())).append("\n"); + sb.append("Version: ").append(Platform.getVersion()).append(" - Platform: ").append(Platform.getName()).append("\n"); + sb.append("Java Vendor: ").append(Platform.ENVIRONMENT.getJavaVendor()).append(" - Java Version: ").append(Platform.ENVIRONMENT.getJavaVersion()).append("\n"); + sb.append(" -- == Processor Overview == -- " + "\n"); + sb.append("CPU Model: ").append(getHardware.getCPUModel()); + sb.append("CPU Architecture: ").append(Platform.CPU.getArchitecture()).append(" Available Processors: ").append(Platform.CPU.getAvailableProcessors()).append("\n"); + sb.append("CPU Load: ").append(Form.pc(Platform.CPU.getCPULoad())).append(" CPU Live Process Load: ").append(Form.pc(Platform.CPU.getLiveProcessCPULoad())).append("\n"); + sb.append("-=" + " Graphics " + "=- " + "\n"); + for (String gpu : gpus) { + sb.append(" ").append(gpu).append("\n"); + } + sb.append(" -- == Memory Information == -- " + "\n"); + sb.append("Physical Memory - Total: ").append(Form.memSize(Platform.MEMORY.PHYSICAL.getTotalMemory())).append(" Free: ").append(Form.memSize(Platform.MEMORY.PHYSICAL.getFreeMemory())).append(" Used: ").append(Form.memSize(Platform.MEMORY.PHYSICAL.getUsedMemory())).append("\n"); + sb.append("Virtual Memory - Total: ").append(Form.memSize(Platform.MEMORY.VIRTUAL.getTotalMemory())).append(" Free: ").append(Form.memSize(Platform.MEMORY.VIRTUAL.getFreeMemory())).append(" Used: ").append(Form.memSize(Platform.MEMORY.VIRTUAL.getUsedMemory())).append("\n"); + sb.append(" -- == Storage Information == -- " + "\n"); + for (String disk : disks) { + sb.append(" ").append(sb.append(disk)).append("\n"); + } + sb.append(" -- == Interface Information == -- "+ "\n" ); + for (String inter : interfaces) { + sb.append(" ").append(inter).append("\n"); + } + sb.append(" -- == Display Information == -- "+ "\n" ); + for (String display : displays) { + sb.append(display).append("\n"); + } + sb.append(" -- == Sensor Information == -- " + "\n"); + for (String sensor : sensors) { + sb.append(" ").append(sensor).append("\n"); + } + sb.append(" -- == Power Information == -- " + "\n"); + for (String power : powersources) { + sb.append(" ").append(power).append("\n"); + } + + try { + String hastebinUrl = uploadToHastebin(sb.toString()); + + // Create the clickable message + TextComponent message = new TextComponent("[Link]"); + TextComponent link = new TextComponent(hastebinUrl); + link.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, hastebinUrl)); + message.addExtra(link); + + // Send the clickable message to the player + sender.spigot().sendMessage(message); + } catch (Exception e) { + sender.sendMessage(C.DARK_RED + "Failed to upload server information to Hastebin."); + } + } + + private static String uploadToHastebin(String content) throws Exception { + URL url = new URL("https://paste.bytecode.ninja/documents"); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "text/plain"); + conn.setDoOutput(true); + + DataOutputStream wr = new DataOutputStream(conn.getOutputStream()); + wr.writeBytes(content); + wr.flush(); + wr.close(); + + BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String response = br.readLine(); + br.close(); + + return "https://paste.bytecode.ninja/" + response.split("\"")[3]; + } + + +} \ No newline at end of file diff --git a/core/src/main/java/com/volmit/iris/util/misc/Platform.java b/core/src/main/java/com/volmit/iris/util/misc/Platform.java new file mode 100644 index 000000000..afbf7c8c3 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/misc/Platform.java @@ -0,0 +1,145 @@ +package com.volmit.iris.util.misc; + +import com.sun.management.OperatingSystemMXBean; + +import java.io.File; +import java.lang.management.ManagementFactory; + +@SuppressWarnings("restriction") +public class Platform { + public static String getVersion() { + return getSystem().getVersion(); + } + + public static String getName() { + return getSystem().getName(); + } + + private static OperatingSystemMXBean getSystem() { + return (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); + } + + public static class ENVIRONMENT { + public static boolean canRunBatch() { + return getSystem().getName().toLowerCase().contains("windows"); + } + + public static String getJavaHome() { + return System.getProperty("java.home"); + } + + public static String getJavaVendor() { + return System.getProperty("java.vendor"); + } + + public static String getJavaVersion() { + return System.getProperty("java.version"); + } + } + + public static class STORAGE { + public static long getAbsoluteTotalSpace() { + long t = 0; + + for (File i : getRoots()) { + t += getTotalSpace(i); + } + + return t; + } + + public static long getTotalSpace() { + return getTotalSpace(new File(".")); + } + + public static long getTotalSpace(File root) { + return root.getTotalSpace(); + } + + public static long getAbsoluteFreeSpace() { + long t = 0; + + for (File i : getRoots()) { + t += getFreeSpace(i); + } + + return t; + } + + public static long getFreeSpace() { + return getFreeSpace(new File(".")); + } + + public static long getFreeSpace(File root) { + return root.getFreeSpace(); + } + + public static long getUsedSpace() { + return getTotalSpace() - getFreeSpace(); + } + + public static long getUsedSpace(File root) { + return getTotalSpace(root) - getFreeSpace(root); + } + + public static long getAbsoluteUsedSpace() { + return getAbsoluteTotalSpace() - getAbsoluteFreeSpace(); + } + + public static File[] getRoots() { + return File.listRoots(); + } + } + + public static class MEMORY { + public static class PHYSICAL { + public static long getTotalMemory() { + return getSystem().getTotalPhysicalMemorySize(); + } + + public static long getFreeMemory() { + return getSystem().getFreePhysicalMemorySize(); + } + + public static long getUsedMemory() { + return getTotalMemory() - getFreeMemory(); + } + } + + public static class VIRTUAL { + public static long getTotalMemory() { + return getSystem().getTotalSwapSpaceSize(); + } + + public static long getFreeMemory() { + return getSystem().getFreeSwapSpaceSize(); + } + + public static long getUsedMemory() { + return getTotalMemory() - getFreeMemory(); + } + + public static long getCommittedVirtualMemory() { + return getSystem().getCommittedVirtualMemorySize(); + } + } + } + + public static class CPU { + public static int getAvailableProcessors() { + return getSystem().getAvailableProcessors(); + } + + public static double getCPULoad() { + return getSystem().getSystemCpuLoad(); + } + + public static double getLiveProcessCPULoad() { + return getSystem().getProcessCpuLoad(); + } + + public static String getArchitecture() { + return getSystem().getArch(); + } + } +} \ No newline at end of file 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 index 0b9a52033..0e494e27c 100644 --- a/core/src/main/java/com/volmit/iris/util/misc/getHardware.java +++ b/core/src/main/java/com/volmit/iris/util/misc/getHardware.java @@ -1,11 +1,24 @@ package com.volmit.iris.util.misc; -import oshi.SystemInfo; -import oshi.hardware.CentralProcessor; -import oshi.hardware.HWDiskStore; -import oshi.software.os.OperatingSystem; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.format.C; +import com.volmit.iris.util.format.Form; +import org.jetbrains.annotations.Nullable; +import oshi.SystemInfo; +import oshi.hardware.*; +import oshi.software.os.FileSystem; +import oshi.software.os.OSFileStore; +import oshi.software.os.OperatingSystem; +import oshi.util.EdidUtil; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; import java.util.List; +import java.util.stream.Collectors; public class getHardware { public static String getServerOS() { @@ -44,14 +57,127 @@ public class getHardware { } } - 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 KList getSensors() { + try { + KList temps = new KList<>(); + SystemInfo systemInfo = new SystemInfo(); + temps.add("CPU Temperature: " + systemInfo.getHardware().getSensors().getCpuTemperature()); + temps.add("CPU Voltage: " + systemInfo.getHardware().getSensors().getCpuTemperature()); + temps.add("Fan Speeds: " + Arrays.toString(systemInfo.getHardware().getSensors().getFanSpeeds())); + return temps.copy(); + } catch (Exception e) { + e.printStackTrace(); } + return null; } -} + + public static KList getGraphicsCards() { + try { + KList gpus = new KList<>(); + SystemInfo systemInfo = new SystemInfo(); + for (GraphicsCard gpu : systemInfo.getHardware().getGraphicsCards()) { + gpus.add(C.BLUE + "Gpu Model: " + C.GRAY + gpu.getName()); + gpus.add("- vRam Size: " + C.GRAY + Form.memSize(gpu.getVRam())); + gpus.add("- Vendor: " + C.GRAY + gpu.getVendor()); + } + return gpus.copy(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static KList getDisk() { + try { + KList systemDisks = new KList<>(); + SystemInfo systemInfo = new SystemInfo(); + List diskStores = systemInfo.getHardware().getDiskStores(); + OperatingSystem operatingSystem = systemInfo.getOperatingSystem(); + List fileStores = operatingSystem.getFileSystem().getFileStores(); + + for (HWDiskStore disk : diskStores) { + systemDisks.add(C.BLUE + "Disk: " + disk.getName()); + systemDisks.add("- Model: " + disk.getModel()); + systemDisks.add("Partitions: " + disk.getPartitions()); + for (OSFileStore partition : fileStores) { + systemDisks.add(C.BLUE + "- Name: " + partition.getName()); + systemDisks.add(" - Description: " + partition.getDescription()); + systemDisks.add(" - Total Space: " + Form.memSize(partition.getTotalSpace())); + systemDisks.add(" - Free Space: " + Form.memSize(partition.getFreeSpace())); + systemDisks.add(" - Mount: " + partition.getMount()); + systemDisks.add(" - Label: " + partition.getLabel()); + } + systemDisks.add(C.DARK_GRAY + "-=" + C.BLUE +" Since Boot " + C.DARK_GRAY + "=- "); + systemDisks.add("- Total Reads: " + Form.memSize(disk.getReadBytes())); + systemDisks.add("- Total Writes: " + Form.memSize(disk.getWriteBytes())); + } + if (systemDisks.isEmpty()) { + systemDisks.add("Failed to get disks."); + } + return systemDisks.copy(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static KList getPowerSources() { + try { + KList systemPowerSources = new KList<>(); + SystemInfo systemInfo = new SystemInfo(); + List powerSources = systemInfo.getHardware().getPowerSources(); + for (PowerSource powersource : powerSources) { + systemPowerSources.add(C.BLUE + "- Name: " + powersource.getName()); + systemPowerSources.add("- RemainingCapacityPercent: " + powersource.getRemainingCapacityPercent()); + systemPowerSources.add("- Power Usage Rate: " + powersource.getPowerUsageRate()); + systemPowerSources.add("- Power OnLine: " + powersource.isPowerOnLine()); + systemPowerSources.add("- Capacity Units: " + powersource.getCapacityUnits()); + systemPowerSources.add("- Cycle Count: " + powersource.getCycleCount()); + } + if (systemPowerSources.isEmpty()) { + systemPowerSources.add("No PowerSources."); + } + return systemPowerSources.copy(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static KList getEDID() { + try { + KList systemEDID = new KList<>(); + SystemInfo systemInfo = new SystemInfo(); + HardwareAbstractionLayer hardware = systemInfo.getHardware(); + List displays = hardware.getDisplays(); + for (Display display : displays) { + systemEDID.add("Display: " + display.getEdid()); + } + if (!systemEDID.isEmpty()) { + systemEDID.add("No displays"); + } + return systemEDID.copy(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static KList getInterfaces() { + try { + KList interfaces = new KList<>(); + Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); + for (NetworkInterface ni : Collections.list(networkInterfaces)) { + interfaces.add(C.BLUE + "Display Name: %s", ni.getDisplayName()); + Enumeration inetAddresses = ni.getInetAddresses(); + for (InetAddress ia : Collections.list(inetAddresses)) { + interfaces.add("IP: %s", ia.getHostAddress()); + } + return interfaces.copy(); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} \ No newline at end of file diff --git a/core/src/main/java/com/volmit/iris/util/nbt/mca/Chunk.java b/core/src/main/java/com/volmit/iris/util/nbt/mca/Chunk.java index fdd0b969b..f74cdcf7f 100644 --- a/core/src/main/java/com/volmit/iris/util/nbt/mca/Chunk.java +++ b/core/src/main/java/com/volmit/iris/util/nbt/mca/Chunk.java @@ -41,6 +41,7 @@ public class Chunk { private int lastMCAUpdate; private CompoundTag data; private int dataVersion; + private int nativeIrisVersion; private long lastUpdate; private long inhabitedTime; private MCABiomeContainer biomes; @@ -83,6 +84,11 @@ public class Chunk { return c; } + public static void injectIrisData(Chunk c) { + World mainWorld = getServer().getWorlds().get(0); + c.data.put("Iris", nativeIrisVersion()); + } + private static CompoundTag defaultLevel() { CompoundTag level = new CompoundTag(); level.putString("Status", "full"); @@ -90,14 +96,19 @@ public class Chunk { return level; } + private static CompoundTag nativeIrisVersion() { + CompoundTag level = new CompoundTag(); + level.putString("Generator", "Iris " + Iris.instance.getDescription().getVersion()); + return level; + } + private void initReferences(long loadFlags) { if (data == null) { throw new NullPointerException("data cannot be null"); } - CompoundTag level; - if ((level = data.getCompoundTag("Level")) == null) { - throw new IllegalArgumentException("data does not contain \"Level\" tag"); - } + + CompoundTag level = data; + World mainWorld = getServer().getWorlds().get(0); dataVersion = data.getInt("DataVersion"); inhabitedTime = level.getLong("InhabitedTime");