mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-04 00:46:08 +00:00
Merge branch 'Pixeldev' into origin
This commit is contained in:
commit
3ae896457b
@ -53,6 +53,7 @@ dependencies {
|
|||||||
compileOnly 'commons-io:commons-io:2.13.0'
|
compileOnly 'commons-io:commons-io:2.13.0'
|
||||||
compileOnly 'commons-lang:commons-lang:2.6'
|
compileOnly 'commons-lang:commons-lang:2.6'
|
||||||
compileOnly 'com.github.oshi:oshi-core:5.8.5'
|
compileOnly 'com.github.oshi:oshi-core:5.8.5'
|
||||||
|
compileOnly 'org.lz4:lz4-java:1.8.0'
|
||||||
|
|
||||||
// Third Party Integrations
|
// Third Party Integrations
|
||||||
compileOnly 'com.ticxo.playeranimator:PlayerAnimator:R1.2.7'
|
compileOnly 'com.ticxo.playeranimator:PlayerAnimator:R1.2.7'
|
||||||
|
@ -30,7 +30,6 @@ import com.volmit.iris.core.loader.IrisData;
|
|||||||
import com.volmit.iris.core.nms.INMS;
|
import com.volmit.iris.core.nms.INMS;
|
||||||
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
|
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
|
||||||
import com.volmit.iris.core.pregenerator.LazyPregenerator;
|
import com.volmit.iris.core.pregenerator.LazyPregenerator;
|
||||||
import com.volmit.iris.core.safeguard.ServerBootSFG;
|
|
||||||
import com.volmit.iris.core.service.StudioSVC;
|
import com.volmit.iris.core.service.StudioSVC;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
import com.volmit.iris.engine.EnginePanic;
|
import com.volmit.iris.engine.EnginePanic;
|
||||||
@ -64,6 +63,7 @@ import com.volmit.iris.util.scheduling.J;
|
|||||||
import com.volmit.iris.util.scheduling.Queue;
|
import com.volmit.iris.util.scheduling.Queue;
|
||||||
import com.volmit.iris.util.scheduling.ShurikenQueue;
|
import com.volmit.iris.util.scheduling.ShurikenQueue;
|
||||||
import io.papermc.lib.PaperLib;
|
import io.papermc.lib.PaperLib;
|
||||||
|
import lombok.Getter;
|
||||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||||
import net.kyori.adventure.text.serializer.ComponentSerializer;
|
import net.kyori.adventure.text.serializer.ComponentSerializer;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
@ -95,10 +95,9 @@ import java.net.URL;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode;
|
import static com.volmit.iris.core.safeguard.IrisSafeguard.*;
|
||||||
import static com.volmit.iris.core.safeguard.ServerBootSFG.passedserversoftware;
|
import static com.volmit.iris.core.safeguard.ServerBootSFG.passedserversoftware;
|
||||||
import static com.volmit.iris.util.misc.getHardware.getCPUModel;
|
import static com.volmit.iris.util.misc.getHardware.getCPUModel;
|
||||||
import static com.volmit.iris.util.misc.getHardware.getCPUThreads;
|
|
||||||
|
|
||||||
@SuppressWarnings("CanBeFinal")
|
@SuppressWarnings("CanBeFinal")
|
||||||
public class Iris extends VolmitPlugin implements Listener {
|
public class Iris extends VolmitPlugin implements Listener {
|
||||||
@ -350,7 +349,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getJavaVersion() {
|
public static int getJavaVersion() {
|
||||||
String version = System.getProperty("java.version");
|
String version = System.getProperty("java.version");
|
||||||
if (version.startsWith("1.")) {
|
if (version.startsWith("1.")) {
|
||||||
version = version.substring(2, 3);
|
version = version.substring(2, 3);
|
||||||
@ -469,13 +468,9 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
J.s(this::setupPapi);
|
J.s(this::setupPapi);
|
||||||
J.a(ServerConfigurator::configure, 20);
|
J.a(ServerConfigurator::configure, 20);
|
||||||
splash();
|
splash();
|
||||||
UtilsSFG.UnstableMode();
|
UtilsSFG.splash();
|
||||||
UtilsSFG.SupportedServerSoftware();
|
|
||||||
UtilsSFG.printIncompatibleWarnings();
|
|
||||||
UtilsSFG.unstablePrompt();
|
|
||||||
|
|
||||||
autoStartStudio();
|
autoStartStudio();
|
||||||
ServerBootSFG.CheckIrisWorlds();
|
|
||||||
checkForBukkitWorlds();
|
checkForBukkitWorlds();
|
||||||
IrisToolbelt.retainMantleDataForSlice(String.class.getCanonicalName());
|
IrisToolbelt.retainMantleDataForSlice(String.class.getCanonicalName());
|
||||||
IrisToolbelt.retainMantleDataForSlice(BlockData.class.getCanonicalName());
|
IrisToolbelt.retainMantleDataForSlice(BlockData.class.getCanonicalName());
|
||||||
@ -596,9 +591,11 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
if (unstablemode) {
|
if (unstablemode) {
|
||||||
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.RED + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
|
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.RED + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
|
||||||
}
|
}
|
||||||
else {
|
if (warningmode) {
|
||||||
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.IRIS + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
|
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.GOLD + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
|
||||||
}
|
}
|
||||||
|
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.IRIS + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean setupChecks() {
|
private boolean setupChecks() {
|
||||||
@ -728,7 +725,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
File ff = new File(w.worldFolder(), "iris/pack");
|
File ff = new File(w.worldFolder(), "iris/pack");
|
||||||
if (!ff.exists() || ff.listFiles().length == 0) {
|
if (!ff.exists() || ff.listFiles().length == 0) {
|
||||||
ff.mkdirs();
|
ff.mkdirs();
|
||||||
service(StudioSVC.class).installIntoWorld(sender, dim.getLoadKey(), ff.getParentFile());
|
service(StudioSVC.class).installIntoWorld(sender, dim.getLoadKey(), w.worldFolder());
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey());
|
return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey());
|
||||||
@ -745,6 +742,9 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
if (unstablemode) {
|
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()};
|
info = new String[]{"", "", "", "", "", padd2 + C.RED + " Iris", padd2 + C.GRAY + " by " + C.DARK_RED + "Volmit Software", padd2 + C.GRAY + " v" + C.RED + getDescription().getVersion()};
|
||||||
}
|
}
|
||||||
|
if (warningmode) {
|
||||||
|
info = new String[]{"", "", "", "", "", padd2 + C.GOLD + " Iris", padd2 + C.GRAY + " by " + C.GOLD + "Volmit Software", padd2 + C.GRAY + " v" + C.GOLD + getDescription().getVersion()};
|
||||||
|
}
|
||||||
|
|
||||||
String[] splashstable = {
|
String[] splashstable = {
|
||||||
padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@",
|
padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@",
|
||||||
@ -773,9 +773,28 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
padd + C.GRAY + "" + C.RED + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@",
|
padd + C.GRAY + "" + C.RED + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@",
|
||||||
padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@"
|
padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@"
|
||||||
};
|
};
|
||||||
String[] splash = unstablemode ? splashunstable : splashstable; // Choose the appropriate splash array based on unstablemode
|
String[] splashwarning = {
|
||||||
|
padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@",
|
||||||
|
padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.GOLD + " .(((()))). ",
|
||||||
|
padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.GOLD + " .((((((())))))). ",
|
||||||
|
padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.GOLD + " ((((((((())))))))) " + C.GRAY + " @",
|
||||||
|
padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.GOLD + " ((((((((-))))))))) " + C.GRAY + " @@",
|
||||||
|
padd + C.GRAY + "@@@&&" + C.GOLD + " ((((((({ })))))))) " + C.GRAY + " &&@@@",
|
||||||
|
padd + C.GRAY + "@@" + C.GOLD + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@",
|
||||||
|
padd + C.GRAY + "@" + C.GOLD + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@",
|
||||||
|
padd + C.GRAY + "" + C.GOLD + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@",
|
||||||
|
padd + C.GRAY + "" + C.GOLD + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@",
|
||||||
|
padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@"
|
||||||
|
};
|
||||||
|
String[] splash;
|
||||||
|
File freeSpace = new File(Bukkit.getWorldContainer() + ".");
|
||||||
|
if (unstablemode) {
|
||||||
|
splash = splashunstable;
|
||||||
|
} else if (warningmode) {
|
||||||
|
splash = splashwarning;
|
||||||
|
} else {
|
||||||
|
splash = splashstable;
|
||||||
|
}
|
||||||
OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
|
OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
|
||||||
String osArch = osBean.getArch();
|
String osArch = osBean.getArch();
|
||||||
String osName = osBean.getName();
|
String osName = osBean.getName();
|
||||||
@ -783,17 +802,40 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
if (!passedserversoftware) {
|
if (!passedserversoftware) {
|
||||||
Iris.info("Server type & version: " + C.RED + Bukkit.getVersion());
|
Iris.info("Server type & version: " + C.RED + Bukkit.getVersion());
|
||||||
} else { Iris.info("Server type & version: " + Bukkit.getVersion()); }
|
} else { Iris.info("Server type & version: " + Bukkit.getVersion()); }
|
||||||
|
if (!instance.getServer().getVersion().contains("Purpur")) {
|
||||||
|
if (instance.getServer().getVersion().contains("Spigot") && instance.getServer().getVersion().contains("Bukkit")) {
|
||||||
|
Iris.info(C.RED + " Iris requires paper or above to function properly..");
|
||||||
|
} else {
|
||||||
|
Iris.info(C.YELLOW + "Purpur is recommended to use with iris.");
|
||||||
|
}
|
||||||
|
}
|
||||||
Iris.info("Server OS: " + osName + " (" + osArch + ")");
|
Iris.info("Server OS: " + osName + " (" + osArch + ")");
|
||||||
|
|
||||||
if(unstablemode) Iris.info("Server Cpu: " + C.DARK_RED + getCPUModel());
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
if(getCPUModel().contains("Intel")) Iris.info("Server Cpu: " + C.BLUE + getCPUModel());
|
Iris.info("Process Threads: " + Runtime.getRuntime().availableProcessors());
|
||||||
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");
|
Iris.info("Process Memory: " + getHardware.getProcessMemory() + " MB");
|
||||||
|
Iris.info("Free DiskSpace: " + Form.ofSize(freeSpace.getFreeSpace(), 1024));
|
||||||
if (getHardware.getProcessMemory() < 5999) {
|
if (getHardware.getProcessMemory() < 5999) {
|
||||||
Iris.warn("6GB+ Ram is recommended");
|
Iris.warn("6GB+ Ram is recommended");
|
||||||
}
|
}
|
||||||
|
@ -141,12 +141,12 @@ public class IrisSettings {
|
|||||||
public int resourceLoaderCacheSize = 1_024;
|
public int resourceLoaderCacheSize = 1_024;
|
||||||
public int objectLoaderCacheSize = 4_096;
|
public int objectLoaderCacheSize = 4_096;
|
||||||
public int scriptLoaderCacheSize = 512;
|
public int scriptLoaderCacheSize = 512;
|
||||||
public boolean dynamicPerformanceMode = true;
|
public int tectonicUnloadThreads = -1; // -1 = Disabled and instead use the dynamic method
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class IrisSettingsGeneral {
|
public static class IrisSettingsGeneral {
|
||||||
public boolean bootUnstable = false;
|
public boolean ignoreBootMode = false;
|
||||||
public boolean useIntegratedChunkHandler = false;
|
public boolean useIntegratedChunkHandler = false;
|
||||||
public boolean commandSounds = true;
|
public boolean commandSounds = true;
|
||||||
public boolean debug = false;
|
public boolean debug = false;
|
||||||
|
@ -20,20 +20,31 @@ package com.volmit.iris.core.commands;
|
|||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
|
import com.volmit.iris.core.service.IrisEngineSVC;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
import com.volmit.iris.engine.mantle.EngineMantle;
|
|
||||||
import com.volmit.iris.util.decree.DecreeExecutor;
|
import com.volmit.iris.util.decree.DecreeExecutor;
|
||||||
import com.volmit.iris.util.decree.DecreeOrigin;
|
import com.volmit.iris.util.decree.DecreeOrigin;
|
||||||
import com.volmit.iris.util.decree.annotations.Decree;
|
import com.volmit.iris.util.decree.annotations.Decree;
|
||||||
import com.volmit.iris.util.decree.annotations.Param;
|
import com.volmit.iris.util.decree.annotations.Param;
|
||||||
import com.volmit.iris.util.format.C;
|
import com.volmit.iris.util.format.C;
|
||||||
import com.volmit.iris.util.format.Form;
|
import com.volmit.iris.util.format.Form;
|
||||||
import com.volmit.iris.util.mantle.Mantle;
|
import com.volmit.iris.util.io.IO;
|
||||||
|
import com.volmit.iris.util.mantle.TectonicPlate;
|
||||||
|
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.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.io.*;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
@Decree(name = "Developer", origin = DecreeOrigin.BOTH, description = "Iris World Manager", aliases = {"dev"})
|
@Decree(name = "Developer", origin = DecreeOrigin.BOTH, description = "Iris World Manager", aliases = {"dev"})
|
||||||
public class CommandDeveloper implements DecreeExecutor {
|
public class CommandDeveloper implements DecreeExecutor {
|
||||||
@ -51,13 +62,14 @@ public class CommandDeveloper implements DecreeExecutor {
|
|||||||
Engine engine = IrisToolbelt.access(world).getEngine();
|
Engine engine = IrisToolbelt.access(world).getEngine();
|
||||||
if(engine != null) {
|
if(engine != null) {
|
||||||
long lastUseSize = engine.getMantle().getLastUseMapMemoryUsage();
|
long lastUseSize = engine.getMantle().getLastUseMapMemoryUsage();
|
||||||
long outputToUnload = engine.getMantle().getToUnload();
|
|
||||||
|
|
||||||
Iris.info("-------------------------");
|
Iris.info("-------------------------");
|
||||||
Iris.info(C.DARK_PURPLE + "Engine Status");
|
Iris.info(C.DARK_PURPLE + "Engine Status");
|
||||||
Iris.info(C.DARK_PURPLE + "Tectonic Limit: " + C.LIGHT_PURPLE + engine.getMantle().getTectonicLimit());
|
Iris.info(C.DARK_PURPLE + "Tectonic Threads: " + C.LIGHT_PURPLE + engine.getMantle().getDynamicThreads());
|
||||||
Iris.info(C.DARK_PURPLE + "Tectonic Plates: " + C.LIGHT_PURPLE + engine.getMantle().getLoadedRegionCount());
|
Iris.info(C.DARK_PURPLE + "Tectonic Limit: " + C.LIGHT_PURPLE + IrisEngineSVC.getTectonicLimit());
|
||||||
Iris.info(C.DARK_PURPLE + "Tectonic ToUnload: " + C.LIGHT_PURPLE + outputToUnload);
|
Iris.info(C.DARK_PURPLE + "Tectonic Loaded Plates: " + C.LIGHT_PURPLE + engine.getMantle().getLoadedRegionCount());
|
||||||
|
Iris.info(C.DARK_PURPLE + "Tectonic Plates: " + C.LIGHT_PURPLE + engine.getMantle().getNotClearedLoadedRegions());
|
||||||
|
Iris.info(C.DARK_PURPLE + "Tectonic ToUnload: " + C.LIGHT_PURPLE + engine.getMantle().getToUnload());
|
||||||
Iris.info(C.DARK_PURPLE + "Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration((long) engine.getMantle().getTectonicDuration()));
|
Iris.info(C.DARK_PURPLE + "Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration((long) engine.getMantle().getTectonicDuration()));
|
||||||
Iris.info(C.DARK_PURPLE + "Cache Size: " + C.LIGHT_PURPLE + Form.f(IrisData.cacheSize()));
|
Iris.info(C.DARK_PURPLE + "Cache Size: " + C.LIGHT_PURPLE + Form.f(IrisData.cacheSize()));
|
||||||
Iris.info(C.DARK_PURPLE + "LastUse Size: " + C.LIGHT_PURPLE + Form.mem(lastUseSize));
|
Iris.info(C.DARK_PURPLE + "LastUse Size: " + C.LIGHT_PURPLE + Form.mem(lastUseSize));
|
||||||
@ -66,6 +78,92 @@ public class CommandDeveloper implements DecreeExecutor {
|
|||||||
Iris.info(C.RED + "Engine is null!");
|
Iris.info(C.RED + "Engine is null!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Decree(description = "Test", origin = DecreeOrigin.BOTH)
|
||||||
|
public void test() {
|
||||||
|
Iris.info("Test Developer CMD Executed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Decree(description = "Test the compression algorithms")
|
||||||
|
public void compression(
|
||||||
|
@Param(description = "base IrisWorld") World world,
|
||||||
|
@Param(description = "raw TectonicPlate File") String path,
|
||||||
|
@Param(description = "Algorithm to Test") String algorithm,
|
||||||
|
@Param(description = "Amount of Tests") int amount) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
File file = new File(path);
|
||||||
|
if (!file.exists()) return;
|
||||||
|
|
||||||
|
Engine engine = IrisToolbelt.access(world).getEngine();
|
||||||
|
if(engine != null) {
|
||||||
|
int height = engine.getTarget().getHeight();
|
||||||
|
ExecutorService service = Executors.newFixedThreadPool(1);
|
||||||
|
VolmitSender sender = sender();
|
||||||
|
service.submit(() -> {
|
||||||
|
try {
|
||||||
|
DataInputStream raw = new DataInputStream(new FileInputStream(file));
|
||||||
|
TectonicPlate plate = new TectonicPlate(height, raw);
|
||||||
|
raw.close();
|
||||||
|
|
||||||
|
double d1 = 0;
|
||||||
|
double d2 = 0;
|
||||||
|
long size = 0;
|
||||||
|
File folder = new File("tmp");
|
||||||
|
folder.mkdirs();
|
||||||
|
for (int i = 0; i < amount; i++) {
|
||||||
|
File tmp = new File(folder, RandomStringUtils.randomAlphanumeric(10) + "." + algorithm + ".bin");
|
||||||
|
DataOutputStream dos = createOutput(tmp, algorithm);
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
plate.write(dos);
|
||||||
|
dos.close();
|
||||||
|
d1 += System.currentTimeMillis() - start;
|
||||||
|
if (size == 0)
|
||||||
|
size = tmp.length();
|
||||||
|
start = System.currentTimeMillis();
|
||||||
|
DataInputStream din = createInput(tmp, algorithm);
|
||||||
|
new TectonicPlate(height, din);
|
||||||
|
din.close();
|
||||||
|
d2 += System.currentTimeMillis() - start;
|
||||||
|
tmp.delete();
|
||||||
|
}
|
||||||
|
IO.delete(folder);
|
||||||
|
sender.sendMessage(algorithm + " is " + Form.fileSize(size) + " big after compression");
|
||||||
|
sender.sendMessage(algorithm + " Took " + d2/amount + "ms to read");
|
||||||
|
sender.sendMessage(algorithm + " Took " + d1/amount + "ms to write");
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
service.shutdown();
|
||||||
|
} else {
|
||||||
|
Iris.info(C.RED + "Engine is null!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataInputStream createInput(File file, String algorithm) throws Throwable {
|
||||||
|
FileInputStream in = new FileInputStream(file);
|
||||||
|
|
||||||
|
return new DataInputStream(switch (algorithm) {
|
||||||
|
case "gzip" -> new GZIPInputStream(in);
|
||||||
|
case "lz4f" -> new LZ4FrameInputStream(in);
|
||||||
|
case "lz4b" -> new LZ4BlockInputStream(in);
|
||||||
|
default -> throw new IllegalStateException("Unexpected value: " + algorithm);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataOutputStream createOutput(File file, String algorithm) throws Throwable {
|
||||||
|
FileOutputStream out = new FileOutputStream(file);
|
||||||
|
|
||||||
|
return new DataOutputStream(switch (algorithm) {
|
||||||
|
case "gzip" -> new GZIPOutputStream(out);
|
||||||
|
case "lz4f" -> new LZ4FrameOutputStream(out);
|
||||||
|
case "lz4b" -> new LZ4BlockOutputStream(out);
|
||||||
|
default -> throw new IllegalStateException("Unexpected value: " + algorithm);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,7 +34,9 @@ public class CommandFind implements DecreeExecutor {
|
|||||||
@Decree(description = "Find a biome")
|
@Decree(description = "Find a biome")
|
||||||
public void biome(
|
public void biome(
|
||||||
@Param(description = "The biome to look for")
|
@Param(description = "The biome to look for")
|
||||||
IrisBiome biome
|
IrisBiome biome,
|
||||||
|
@Param(description = "Should you be teleported", defaultValue = "true")
|
||||||
|
boolean teleport
|
||||||
) {
|
) {
|
||||||
Engine e = engine();
|
Engine e = engine();
|
||||||
|
|
||||||
@ -43,13 +45,15 @@ public class CommandFind implements DecreeExecutor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.gotoBiome(biome, player());
|
e.gotoBiome(biome, player(), teleport);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Decree(description = "Find a region")
|
@Decree(description = "Find a region")
|
||||||
public void region(
|
public void region(
|
||||||
@Param(description = "The region to look for")
|
@Param(description = "The region to look for")
|
||||||
IrisRegion region
|
IrisRegion region,
|
||||||
|
@Param(description = "Should you be teleported", defaultValue = "true")
|
||||||
|
boolean teleport
|
||||||
) {
|
) {
|
||||||
Engine e = engine();
|
Engine e = engine();
|
||||||
|
|
||||||
@ -58,13 +62,15 @@ public class CommandFind implements DecreeExecutor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.gotoRegion(region, player());
|
e.gotoRegion(region, player(), teleport);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Decree(description = "Find a structure")
|
@Decree(description = "Find a structure")
|
||||||
public void structure(
|
public void structure(
|
||||||
@Param(description = "The structure to look for")
|
@Param(description = "The structure to look for")
|
||||||
IrisJigsawStructure structure
|
IrisJigsawStructure structure,
|
||||||
|
@Param(description = "Should you be teleported", defaultValue = "true")
|
||||||
|
boolean teleport
|
||||||
) {
|
) {
|
||||||
Engine e = engine();
|
Engine e = engine();
|
||||||
|
|
||||||
@ -73,13 +79,15 @@ public class CommandFind implements DecreeExecutor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.gotoJigsaw(structure, player());
|
e.gotoJigsaw(structure, player(), teleport);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Decree(description = "Find a point of interest.")
|
@Decree(description = "Find a point of interest.")
|
||||||
public void poi(
|
public void poi(
|
||||||
@Param(description = "The type of PoI to look for.")
|
@Param(description = "The type of PoI to look for.")
|
||||||
String type
|
String type,
|
||||||
|
@Param(description = "Should you be teleported", defaultValue = "true")
|
||||||
|
boolean teleport
|
||||||
) {
|
) {
|
||||||
Engine e = engine();
|
Engine e = engine();
|
||||||
if (e == null) {
|
if (e == null) {
|
||||||
@ -87,13 +95,15 @@ public class CommandFind implements DecreeExecutor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.gotoPOI(type, player());
|
e.gotoPOI(type, player(), teleport);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Decree(description = "Find an object")
|
@Decree(description = "Find an object")
|
||||||
public void object(
|
public void object(
|
||||||
@Param(description = "The object to look for", customHandler = ObjectHandler.class)
|
@Param(description = "The object to look for", customHandler = ObjectHandler.class)
|
||||||
String object
|
String object,
|
||||||
|
@Param(description = "Should you be teleported", defaultValue = "true")
|
||||||
|
boolean teleport
|
||||||
) {
|
) {
|
||||||
Engine e = engine();
|
Engine e = engine();
|
||||||
|
|
||||||
@ -102,6 +112,6 @@ public class CommandFind implements DecreeExecutor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.gotoObject(object, player());
|
e.gotoObject(object, player(), teleport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,45 +23,35 @@ import com.volmit.iris.core.IrisSettings;
|
|||||||
import com.volmit.iris.core.service.StudioSVC;
|
import com.volmit.iris.core.service.StudioSVC;
|
||||||
import com.volmit.iris.core.tools.IrisBenchmarking;
|
import com.volmit.iris.core.tools.IrisBenchmarking;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
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.IrisDimension;
|
||||||
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
|
||||||
import com.volmit.iris.core.safeguard.UtilsSFG;
|
import com.volmit.iris.core.safeguard.UtilsSFG;
|
||||||
import com.volmit.iris.util.collection.KList;
|
|
||||||
import com.volmit.iris.util.decree.DecreeContext;
|
|
||||||
import com.volmit.iris.util.decree.DecreeExecutor;
|
import com.volmit.iris.util.decree.DecreeExecutor;
|
||||||
import com.volmit.iris.util.decree.DecreeOrigin;
|
import com.volmit.iris.util.decree.DecreeOrigin;
|
||||||
import com.volmit.iris.util.decree.annotations.Decree;
|
import com.volmit.iris.util.decree.annotations.Decree;
|
||||||
import com.volmit.iris.util.decree.annotations.Param;
|
import com.volmit.iris.util.decree.annotations.Param;
|
||||||
import com.volmit.iris.util.decree.specialhandlers.NullablePlayerHandler;
|
import com.volmit.iris.util.decree.specialhandlers.NullablePlayerHandler;
|
||||||
import com.volmit.iris.util.format.C;
|
import com.volmit.iris.util.format.C;
|
||||||
import com.volmit.iris.util.format.Form;
|
|
||||||
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.plugin.VolmitSender;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import com.volmit.iris.util.scheduling.jobs.QueueJob;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Chunk;
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
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.service.EditSVC.deletingWorld;
|
||||||
import static com.volmit.iris.core.tools.IrisBenchmarking.inProgress;
|
import static com.volmit.iris.core.tools.IrisBenchmarking.inProgress;
|
||||||
import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode;
|
import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode;
|
||||||
import static com.volmit.iris.core.safeguard.ServerBootSFG.incompatiblePlugins;
|
import static com.volmit.iris.core.safeguard.ServerBootSFG.incompatibilities;
|
||||||
|
|
||||||
@Decree(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command")
|
@Decree(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command")
|
||||||
public class CommandIris implements DecreeExecutor {
|
public class CommandIris implements DecreeExecutor {
|
||||||
private CommandStudio studio;
|
private CommandStudio studio;
|
||||||
private CommandPregen pregen;
|
private CommandPregen pregen;
|
||||||
|
private CommandLazyPregen lazyPregen;
|
||||||
private CommandSettings settings;
|
private CommandSettings settings;
|
||||||
private CommandObject object;
|
private CommandObject object;
|
||||||
private CommandJigsaw jigsaw;
|
private CommandJigsaw jigsaw;
|
||||||
@ -72,6 +62,7 @@ public class CommandIris implements DecreeExecutor {
|
|||||||
private CommandDeveloper developer;
|
private CommandDeveloper developer;
|
||||||
|
|
||||||
public static @Getter String BenchDimension;
|
public static @Getter String BenchDimension;
|
||||||
|
public static boolean worldCreation = false;
|
||||||
|
|
||||||
@Decree(description = "Create a new world", aliases = {"+", "c"})
|
@Decree(description = "Create a new world", aliases = {"+", "c"})
|
||||||
public void create(
|
public void create(
|
||||||
@ -83,7 +74,7 @@ public class CommandIris implements DecreeExecutor {
|
|||||||
long seed
|
long seed
|
||||||
) {
|
) {
|
||||||
if(sender() instanceof Player) {
|
if(sender() instanceof Player) {
|
||||||
if (incompatiblePlugins.get("Multiverse-Core")) {
|
if (incompatibilities.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 + "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 + "it is strongly advised for you to take action. see log for full detail");
|
||||||
sender().sendMessage(C.RED + "----------------------------------------------------------------");
|
sender().sendMessage(C.RED + "----------------------------------------------------------------");
|
||||||
@ -91,7 +82,7 @@ public class CommandIris implements DecreeExecutor {
|
|||||||
sender().sendMessage(C.RED + UtilsSFG.MSGIncompatibleWarnings());
|
sender().sendMessage(C.RED + UtilsSFG.MSGIncompatibleWarnings());
|
||||||
sender().sendMessage(C.RED + "----------------------------------------------------------------");
|
sender().sendMessage(C.RED + "----------------------------------------------------------------");
|
||||||
}
|
}
|
||||||
if (unstablemode && !incompatiblePlugins.get("Multiverse-Core")) {
|
if (unstablemode && !incompatibilities.get("Multiverse-Core")) {
|
||||||
sender().sendMessage(C.RED + "Your server is experiencing an incompatibility with the Iris plugin.");
|
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 + "Please rectify this problem to avoid further complications.");
|
||||||
sender().sendMessage(C.RED + "----------------------------------------------------------------");
|
sender().sendMessage(C.RED + "----------------------------------------------------------------");
|
||||||
@ -117,6 +108,7 @@ public class CommandIris implements DecreeExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
worldCreation = true;
|
||||||
IrisToolbelt.createWorld()
|
IrisToolbelt.createWorld()
|
||||||
.dimension(type.getLoadKey())
|
.dimension(type.getLoadKey())
|
||||||
.name(name)
|
.name(name)
|
||||||
@ -128,9 +120,10 @@ public class CommandIris implements DecreeExecutor {
|
|||||||
sender().sendMessage(C.RED + "Exception raised during creation. See the console for more details.");
|
sender().sendMessage(C.RED + "Exception raised during creation. See the console for more details.");
|
||||||
Iris.error("Exception raised during world creation: " + e.getMessage());
|
Iris.error("Exception raised during world creation: " + e.getMessage());
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
|
worldCreation = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
worldCreation = false;
|
||||||
sender().sendMessage(C.GREEN + "Successfully created your world!");
|
sender().sendMessage(C.GREEN + "Successfully created your world!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,6 +156,8 @@ public class CommandIris implements DecreeExecutor {
|
|||||||
public void version() {
|
public void version() {
|
||||||
sender().sendMessage(C.GREEN + "Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software");
|
sender().sendMessage(C.GREEN + "Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//todo Move to React
|
||||||
@Decree(description = "Benchmark your server", origin = DecreeOrigin.CONSOLE)
|
@Decree(description = "Benchmark your server", origin = DecreeOrigin.CONSOLE)
|
||||||
public void serverbenchmark() throws InterruptedException {
|
public void serverbenchmark() throws InterruptedException {
|
||||||
if(!inProgress) {
|
if(!inProgress) {
|
||||||
@ -171,6 +166,7 @@ public class CommandIris implements DecreeExecutor {
|
|||||||
Iris.info(C.RED + "Benchmark already is in progress.");
|
Iris.info(C.RED + "Benchmark already is in progress.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
/todo Fix PREGEN
|
/todo Fix PREGEN
|
||||||
@Decree(description = "Benchmark a pack", origin = DecreeOrigin.CONSOLE)
|
@Decree(description = "Benchmark a pack", origin = DecreeOrigin.CONSOLE)
|
||||||
@ -239,7 +235,7 @@ public class CommandIris implements DecreeExecutor {
|
|||||||
IrisToolbelt.evacuate(world, "Deleting world");
|
IrisToolbelt.evacuate(world, "Deleting world");
|
||||||
deletingWorld = true;
|
deletingWorld = true;
|
||||||
Bukkit.unloadWorld(world, false);
|
Bukkit.unloadWorld(world, false);
|
||||||
int retries = 10;
|
int retries = 12;
|
||||||
if (delete) {
|
if (delete) {
|
||||||
if (deleteDirectory(world.getWorldFolder())) {
|
if (deleteDirectory(world.getWorldFolder())) {
|
||||||
sender().sendMessage(C.GREEN + "Successfully removed world folder");
|
sender().sendMessage(C.GREEN + "Successfully removed world folder");
|
||||||
@ -249,13 +245,12 @@ public class CommandIris implements DecreeExecutor {
|
|||||||
sender().sendMessage(C.GREEN + "Successfully removed world folder");
|
sender().sendMessage(C.GREEN + "Successfully removed world folder");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sender().sendMessage(C.GREEN + "DEBUG1");
|
|
||||||
retries--;
|
retries--;
|
||||||
if (retries == 0){
|
if (retries == 0){
|
||||||
sender().sendMessage(C.RED + "Failed to remove world folder");
|
sender().sendMessage(C.RED + "Failed to remove world folder");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
J.sleep(2000);
|
J.sleep(3000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -364,77 +359,6 @@ public class CommandIris implements DecreeExecutor {
|
|||||||
sender().sendMessage(C.GREEN + "Hotloaded settings");
|
sender().sendMessage(C.GREEN + "Hotloaded settings");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Decree(name = "regen", description = "Regenerate nearby chunks.", aliases = "rg", sync = true, origin = DecreeOrigin.PLAYER)
|
|
||||||
public void regen(
|
|
||||||
@Param(name = "radius", description = "The radius of nearby cunks", defaultValue = "5")
|
|
||||||
int radius
|
|
||||||
) {
|
|
||||||
if (IrisToolbelt.isIrisWorld(player().getWorld())) {
|
|
||||||
VolmitSender sender = sender();
|
|
||||||
J.a(() -> {
|
|
||||||
DecreeContext.touch(sender);
|
|
||||||
PlatformChunkGenerator plat = IrisToolbelt.access(player().getWorld());
|
|
||||||
Engine engine = plat.getEngine();
|
|
||||||
try {
|
|
||||||
Chunk cx = player().getLocation().getChunk();
|
|
||||||
KList<Runnable> js = new KList<>();
|
|
||||||
BurstExecutor b = MultiBurst.burst.burst();
|
|
||||||
b.setMulticore(false);
|
|
||||||
int rad = engine.getMantle().getRealRadius();
|
|
||||||
for (int i = -(radius + rad); i <= radius + rad; i++) {
|
|
||||||
for (int j = -(radius + rad); j <= radius + rad; j++) {
|
|
||||||
engine.getMantle().getMantle().deleteChunk(i + cx.getX(), j + cx.getZ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = -radius; i <= radius; i++) {
|
|
||||||
for (int j = -radius; j <= radius; j++) {
|
|
||||||
int finalJ = j;
|
|
||||||
int finalI = i;
|
|
||||||
b.queue(() -> plat.injectChunkReplacement(player().getWorld(), finalI + cx.getX(), finalJ + cx.getZ(), (f) -> {
|
|
||||||
synchronized (js) {
|
|
||||||
js.add(f);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.complete();
|
|
||||||
sender().sendMessage(C.GREEN + "Regenerating " + Form.f(js.size()) + " Sections");
|
|
||||||
QueueJob<Runnable> r = new QueueJob<>() {
|
|
||||||
final KList<Future<?>> futures = new KList<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute(Runnable runnable) {
|
|
||||||
futures.add(J.sfut(runnable));
|
|
||||||
|
|
||||||
if (futures.size() > 64) {
|
|
||||||
while (futures.isNotEmpty()) {
|
|
||||||
try {
|
|
||||||
futures.remove(0).get();
|
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "Regenerating";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
r.queue(js);
|
|
||||||
r.execute(sender());
|
|
||||||
} catch (Throwable e) {
|
|
||||||
sender().sendMessage("Unable to parse view-distance");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
sender().sendMessage(C.RED + "You must be in an Iris World to use regen!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Decree(description = "Update the pack of a world (UNSAFE!)", name = "^world", aliases = "update-world")
|
@Decree(description = "Update the pack of a world (UNSAFE!)", name = "^world", aliases = "update-world")
|
||||||
public void updateWorld(
|
public void updateWorld(
|
||||||
@Param(description = "The world to update", contextual = true)
|
@Param(description = "The world to update", contextual = true)
|
||||||
|
@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.core.commands;
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.IrisSettings;
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Decree(name = "lazypregen", aliases = "lazy", description = "Pregenerate your Iris worlds!")
|
||||||
|
public class CommandLazyPregen implements DecreeExecutor {
|
||||||
|
public String worldName;
|
||||||
|
@Decree(description = "Pregenerate a world")
|
||||||
|
public void start(
|
||||||
|
@Param(description = "The radius of the pregen in blocks", aliases = "size")
|
||||||
|
int radius,
|
||||||
|
@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,
|
||||||
|
@Param(aliases = "maxcpm", description = "Limit the chunks per minute the pregen will generate", defaultValue = "999999999")
|
||||||
|
int cpm,
|
||||||
|
@Param(aliases = "silent", description = "Silent generation", defaultValue = "false")
|
||||||
|
boolean silent
|
||||||
|
) {
|
||||||
|
|
||||||
|
worldName = world.getName();
|
||||||
|
File worldDirectory = new File(Bukkit.getWorldContainer(), world.getName());
|
||||||
|
File lazyFile = new File(worldDirectory, "lazygen.json");
|
||||||
|
if (lazyFile.exists()) {
|
||||||
|
sender().sendMessage(C.BLUE + "Lazy pregen is already in progress");
|
||||||
|
Iris.info(C.YELLOW + "Lazy pregen is already in progress");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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(cpm)
|
||||||
|
.radiusBlocks(radius)
|
||||||
|
.position(0)
|
||||||
|
.silent(silent)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
File lazyGenFile = new File(worldDirectory, "lazygen.json");
|
||||||
|
LazyPregenerator pregenerator = new LazyPregenerator(pregenJob, lazyGenFile);
|
||||||
|
pregenerator.start();
|
||||||
|
|
||||||
|
String msg = C.GREEN + "LazyPregen 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Decree(description = "Stop the active pregeneration task", aliases = "x")
|
||||||
|
public void stop(
|
||||||
|
@Param(aliases = "world", description = "The world to pause")
|
||||||
|
World world
|
||||||
|
) throws IOException {
|
||||||
|
if (LazyPregenerator.getInstance() != null) {
|
||||||
|
LazyPregenerator.getInstance().shutdownInstance(world);
|
||||||
|
sender().sendMessage(C.LIGHT_PURPLE + "Closed lazygen instance for " + world.getName());
|
||||||
|
} else {
|
||||||
|
sender().sendMessage(C.YELLOW + "No active pregeneration tasks to stop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Decree(description = "Pause / continue the active pregeneration task", aliases = {"t", "resume", "unpause"})
|
||||||
|
public void pause(
|
||||||
|
@Param(aliases = "world", description = "The world to pause")
|
||||||
|
World world
|
||||||
|
) {
|
||||||
|
if (LazyPregenerator.getInstance() != null) {
|
||||||
|
LazyPregenerator.getInstance().setPausedLazy(world);
|
||||||
|
sender().sendMessage(C.GREEN + "Paused/unpaused Lazy Pregen, now: " + (LazyPregenerator.getInstance().isPausedLazy(world) ? "Paused" : "Running") + ".");
|
||||||
|
} else {
|
||||||
|
sender().sendMessage(C.YELLOW + "No active Lazy Pregen tasks to pause/unpause.");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,6 +19,7 @@
|
|||||||
package com.volmit.iris.core.commands;
|
package com.volmit.iris.core.commands;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.IrisSettings;
|
||||||
import com.volmit.iris.core.gui.PregeneratorJob;
|
import com.volmit.iris.core.gui.PregeneratorJob;
|
||||||
import com.volmit.iris.core.pregenerator.LazyPregenerator;
|
import com.volmit.iris.core.pregenerator.LazyPregenerator;
|
||||||
import com.volmit.iris.core.pregenerator.PregenTask;
|
import com.volmit.iris.core.pregenerator.PregenTask;
|
||||||
@ -43,12 +44,8 @@ public class CommandPregen implements DecreeExecutor {
|
|||||||
@Param(description = "The world to pregen", contextual = true)
|
@Param(description = "The world to pregen", contextual = true)
|
||||||
World world,
|
World world,
|
||||||
@Param(aliases = "middle", description = "The center location of the pregen. Use \"me\" for your current location", defaultValue = "0,0")
|
@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
|
|
||||||
) {
|
) {
|
||||||
if(method.equals("async") || method.equals("lazy")){
|
|
||||||
if (method.equalsIgnoreCase("async")) {
|
|
||||||
try {
|
try {
|
||||||
if (sender().isPlayer() && access() == null) {
|
if (sender().isPlayer() && access() == null) {
|
||||||
sender().sendMessage(C.RED + "The engine access for this world is null!");
|
sender().sendMessage(C.RED + "The engine access for this world is null!");
|
||||||
@ -71,41 +68,6 @@ public class CommandPregen implements DecreeExecutor {
|
|||||||
e.printStackTrace();
|
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")
|
@Decree(description = "Stop the active pregeneration task", aliases = "x")
|
||||||
public void stop() {
|
public void stop() {
|
||||||
|
@ -29,9 +29,11 @@ import com.volmit.iris.core.service.StudioSVC;
|
|||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
import com.volmit.iris.engine.object.*;
|
import com.volmit.iris.engine.object.*;
|
||||||
|
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.collection.KSet;
|
import com.volmit.iris.util.collection.KSet;
|
||||||
|
import com.volmit.iris.util.decree.DecreeContext;
|
||||||
import com.volmit.iris.util.decree.DecreeExecutor;
|
import com.volmit.iris.util.decree.DecreeExecutor;
|
||||||
import com.volmit.iris.util.decree.DecreeOrigin;
|
import com.volmit.iris.util.decree.DecreeOrigin;
|
||||||
import com.volmit.iris.util.decree.annotations.Decree;
|
import com.volmit.iris.util.decree.annotations.Decree;
|
||||||
@ -48,8 +50,13 @@ import com.volmit.iris.util.math.M;
|
|||||||
import com.volmit.iris.util.math.RNG;
|
import com.volmit.iris.util.math.RNG;
|
||||||
import com.volmit.iris.util.math.Spiraler;
|
import com.volmit.iris.util.math.Spiraler;
|
||||||
import com.volmit.iris.util.noise.CNG;
|
import com.volmit.iris.util.noise.CNG;
|
||||||
|
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.O;
|
import com.volmit.iris.util.scheduling.O;
|
||||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||||
|
import com.volmit.iris.util.scheduling.jobs.QueueJob;
|
||||||
import io.papermc.lib.PaperLib;
|
import io.papermc.lib.PaperLib;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.event.inventory.InventoryType;
|
import org.bukkit.event.inventory.InventoryType;
|
||||||
@ -67,6 +74,8 @@ import java.time.Duration;
|
|||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@Decree(name = "studio", aliases = {"std", "s"}, description = "Studio Commands", studio = true)
|
@Decree(name = "studio", aliases = {"std", "s"}, description = "Studio Commands", studio = true)
|
||||||
@ -143,6 +152,77 @@ public class CommandStudio implements DecreeExecutor {
|
|||||||
sender().sendMessage(C.GREEN + "The \"" + dimension.getName() + "\" pack has version: " + dimension.getVersion());
|
sender().sendMessage(C.GREEN + "The \"" + dimension.getName() + "\" pack has version: " + dimension.getVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Decree(name = "regen", description = "Regenerate nearby chunks.", aliases = "rg", sync = true, origin = DecreeOrigin.PLAYER)
|
||||||
|
public void regen(
|
||||||
|
@Param(name = "radius", description = "The radius of nearby cunks", defaultValue = "5")
|
||||||
|
int radius
|
||||||
|
) {
|
||||||
|
if (IrisToolbelt.isIrisWorld(player().getWorld())) {
|
||||||
|
VolmitSender sender = sender();
|
||||||
|
J.a(() -> {
|
||||||
|
DecreeContext.touch(sender);
|
||||||
|
PlatformChunkGenerator plat = IrisToolbelt.access(player().getWorld());
|
||||||
|
Engine engine = plat.getEngine();
|
||||||
|
try {
|
||||||
|
Chunk cx = player().getLocation().getChunk();
|
||||||
|
KList<Runnable> js = new KList<>();
|
||||||
|
BurstExecutor b = MultiBurst.burst.burst();
|
||||||
|
b.setMulticore(false);
|
||||||
|
int rad = engine.getMantle().getRealRadius();
|
||||||
|
for (int i = -(radius + rad); i <= radius + rad; i++) {
|
||||||
|
for (int j = -(radius + rad); j <= radius + rad; j++) {
|
||||||
|
engine.getMantle().getMantle().deleteChunk(i + cx.getX(), j + cx.getZ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = -radius; i <= radius; i++) {
|
||||||
|
for (int j = -radius; j <= radius; j++) {
|
||||||
|
int finalJ = j;
|
||||||
|
int finalI = i;
|
||||||
|
b.queue(() -> plat.injectChunkReplacement(player().getWorld(), finalI + cx.getX(), finalJ + cx.getZ(), (f) -> {
|
||||||
|
synchronized (js) {
|
||||||
|
js.add(f);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b.complete();
|
||||||
|
sender().sendMessage(C.GREEN + "Regenerating " + Form.f(js.size()) + " Sections");
|
||||||
|
QueueJob<Runnable> r = new QueueJob<>() {
|
||||||
|
final KList<Future<?>> futures = new KList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Runnable runnable) {
|
||||||
|
futures.add(J.sfut(runnable));
|
||||||
|
|
||||||
|
if (futures.size() > 64) {
|
||||||
|
while (futures.isNotEmpty()) {
|
||||||
|
try {
|
||||||
|
futures.remove(0).get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Regenerating";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
r.queue(js);
|
||||||
|
r.execute(sender());
|
||||||
|
} catch (Throwable e) {
|
||||||
|
sender().sendMessage("Unable to parse view-distance");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
sender().sendMessage(C.RED + "You must be in an Iris World to use regen!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Decree(description = "Convert objects in the \"convert\" folder")
|
@Decree(description = "Convert objects in the \"convert\" folder")
|
||||||
public void convert() {
|
public void convert() {
|
||||||
Iris.service(ConversionSVC.class).check(sender());
|
Iris.service(ConversionSVC.class).check(sender());
|
||||||
|
@ -40,6 +40,8 @@ import com.volmit.iris.util.scheduling.ChronoLatch;
|
|||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -52,6 +54,8 @@ import java.util.zip.GZIPInputStream;
|
|||||||
import java.util.zip.GZIPOutputStream;
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(exclude = "manager")
|
||||||
|
@ToString(exclude = "manager")
|
||||||
public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
|
public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
|
||||||
public static final AtomicDouble tlt = new AtomicDouble(0);
|
public static final AtomicDouble tlt = new AtomicDouble(0);
|
||||||
private static final int CACHE_SIZE = 100000;
|
private static final int CACHE_SIZE = 100000;
|
||||||
|
@ -167,7 +167,7 @@ public class IrisPregenerator {
|
|||||||
generator.close();
|
generator.close();
|
||||||
ticker.interrupt();
|
ticker.interrupt();
|
||||||
listener.onClose();
|
listener.onClose();
|
||||||
getMantle().trim(0);
|
getMantle().trim(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void visitRegion(int x, int z, boolean regions) {
|
private void visitRegion(int x, int z, boolean regions) {
|
||||||
|
@ -14,22 +14,32 @@ import com.volmit.iris.util.scheduling.J;
|
|||||||
import io.papermc.lib.PaperLib;
|
import io.papermc.lib.PaperLib;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.world.WorldUnloadEvent;
|
import org.bukkit.event.world.WorldUnloadEvent;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class LazyPregenerator extends Thread implements Listener {
|
public class LazyPregenerator extends Thread implements Listener {
|
||||||
|
@Getter
|
||||||
|
private static LazyPregenerator instance;
|
||||||
private final LazyPregenJob job;
|
private final LazyPregenJob job;
|
||||||
private final File destination;
|
private final File destination;
|
||||||
private final int maxPosition;
|
private final int maxPosition;
|
||||||
private final World world;
|
private World world;
|
||||||
private final long rate;
|
private final long rate;
|
||||||
private final ChronoLatch latch;
|
private final ChronoLatch latch;
|
||||||
private static AtomicInteger lazyGeneratedChunks;
|
private static AtomicInteger lazyGeneratedChunks;
|
||||||
@ -37,6 +47,10 @@ public class LazyPregenerator extends Thread implements Listener {
|
|||||||
private final AtomicInteger lazyTotalChunks;
|
private final AtomicInteger lazyTotalChunks;
|
||||||
private final AtomicLong startTime;
|
private final AtomicLong startTime;
|
||||||
private final RollingSequence chunksPerSecond;
|
private final RollingSequence chunksPerSecond;
|
||||||
|
private final RollingSequence chunksPerMinute;
|
||||||
|
|
||||||
|
// A map to keep track of jobs for each world
|
||||||
|
private static final Map<String, LazyPregenJob> jobs = new HashMap<>();
|
||||||
|
|
||||||
public LazyPregenerator(LazyPregenJob job, File destination) {
|
public LazyPregenerator(LazyPregenJob job, File destination) {
|
||||||
this.job = job;
|
this.job = job;
|
||||||
@ -44,16 +58,16 @@ public class LazyPregenerator extends Thread implements Listener {
|
|||||||
this.maxPosition = new Spiraler(job.getRadiusBlocks() * 2, job.getRadiusBlocks() * 2, (x, z) -> {
|
this.maxPosition = new Spiraler(job.getRadiusBlocks() * 2, job.getRadiusBlocks() * 2, (x, z) -> {
|
||||||
}).count();
|
}).count();
|
||||||
this.world = Bukkit.getWorld(job.getWorld());
|
this.world = Bukkit.getWorld(job.getWorld());
|
||||||
this.rate = Math.round((1D / (job.chunksPerMinute / 60D)) * 1000D);
|
this.rate = Math.round((1D / (job.getChunksPerMinute() / 60D)) * 1000D);
|
||||||
this.latch = new ChronoLatch(6000);
|
this.latch = new ChronoLatch(15000);
|
||||||
startTime = new AtomicLong(M.ms());
|
this.startTime = new AtomicLong(M.ms());
|
||||||
chunksPerSecond = new RollingSequence(10);
|
this.chunksPerSecond = new RollingSequence(10);
|
||||||
|
this.chunksPerMinute = new RollingSequence(10);
|
||||||
lazyGeneratedChunks = new AtomicInteger(0);
|
lazyGeneratedChunks = new AtomicInteger(0);
|
||||||
generatedLast = new AtomicInteger(0);
|
this.generatedLast = new AtomicInteger(0);
|
||||||
lazyTotalChunks = new AtomicInteger();
|
this.lazyTotalChunks = new AtomicInteger((int) Math.ceil(Math.pow((2.0 * job.getRadiusBlocks()) / 16, 2)));
|
||||||
|
jobs.put(job.getWorld(), job);
|
||||||
int radius = job.getRadiusBlocks();
|
LazyPregenerator.instance = this;
|
||||||
lazyTotalChunks.set((int) Math.ceil(Math.pow((2.0 * radius) / 16, 2)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LazyPregenerator(File file) throws IOException {
|
public LazyPregenerator(File file) throws IOException {
|
||||||
@ -63,7 +77,6 @@ public class LazyPregenerator extends Thread implements Listener {
|
|||||||
public static void loadLazyGenerators() {
|
public static void loadLazyGenerators() {
|
||||||
for (World i : Bukkit.getWorlds()) {
|
for (World i : Bukkit.getWorlds()) {
|
||||||
File lazygen = new File(i.getWorldFolder(), "lazygen.json");
|
File lazygen = new File(i.getWorldFolder(), "lazygen.json");
|
||||||
|
|
||||||
if (lazygen.exists()) {
|
if (lazygen.exists()) {
|
||||||
try {
|
try {
|
||||||
LazyPregenerator p = new LazyPregenerator(lazygen);
|
LazyPregenerator p = new LazyPregenerator(lazygen);
|
||||||
@ -97,18 +110,18 @@ public class LazyPregenerator extends Thread implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void tick() {
|
public void tick() {
|
||||||
if (latch.flip()) {
|
LazyPregenJob job = jobs.get(world.getName());
|
||||||
|
if (latch.flip() && !job.paused) {
|
||||||
long eta = computeETA();
|
long eta = computeETA();
|
||||||
save();
|
save();
|
||||||
int secondGenerated = lazyGeneratedChunks.get() - generatedLast.get();
|
int secondGenerated = lazyGeneratedChunks.get() - generatedLast.get();
|
||||||
generatedLast.set(lazyGeneratedChunks.get());
|
generatedLast.set(lazyGeneratedChunks.get());
|
||||||
secondGenerated = secondGenerated / 6;
|
secondGenerated = secondGenerated / 15;
|
||||||
chunksPerSecond.put(secondGenerated);
|
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));
|
chunksPerMinute.put(secondGenerated * 60);
|
||||||
//Iris.info("Debug: " + maxPosition);
|
if (!job.isSilent()) {
|
||||||
//Iris.info("Debug1: " + job.getPosition());
|
Iris.info("LazyGen: " + C.IRIS + world.getName() + C.RESET + " RTT: " + Form.f(lazyGeneratedChunks.get()) + " of " + Form.f(lazyTotalChunks.get()) + " " + Form.f((int) chunksPerMinute.getAverage()) + "/m ETA: " + Form.duration((double) eta, 2));
|
||||||
|
}
|
||||||
// todo: Maxpos borked
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lazyGeneratedChunks.get() >= lazyTotalChunks.get()) {
|
if (lazyGeneratedChunks.get() >= lazyTotalChunks.get()) {
|
||||||
@ -123,27 +136,43 @@ public class LazyPregenerator extends Thread implements Listener {
|
|||||||
} else {
|
} else {
|
||||||
int pos = job.getPosition() + 1;
|
int pos = job.getPosition() + 1;
|
||||||
job.setPosition(pos);
|
job.setPosition(pos);
|
||||||
|
if (!job.paused) {
|
||||||
tickGenerate(getChunk(pos));
|
tickGenerate(getChunk(pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private long computeETA() {
|
private long computeETA() {
|
||||||
return (long) (lazyTotalChunks.get() > 1024 ? // Generated chunks exceed 1/8th of total?
|
return (long) ((lazyTotalChunks.get() - lazyGeneratedChunks.get()) / chunksPerMinute.getAverage()) * 1000;
|
||||||
// If yes, use smooth function (which gets more accurate over time since its less sensitive to outliers)
|
// todo broken
|
||||||
((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 final ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
private void tickGenerate(Position2 chunk) {
|
private void tickGenerate(Position2 chunk) {
|
||||||
|
executorService.submit(() -> {
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
if (PaperLib.isPaper()) {
|
if (PaperLib.isPaper()) {
|
||||||
PaperLib.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true).thenAccept((i) -> Iris.verbose("Generated Async " + chunk));
|
PaperLib.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true)
|
||||||
} else {
|
.thenAccept((i) -> {
|
||||||
J.s(() -> world.getChunkAt(chunk.getX(), chunk.getZ()));
|
LazyPregenJob j = jobs.get(world.getName());
|
||||||
Iris.verbose("Generated " + chunk);
|
if (!j.paused) {
|
||||||
|
Iris.verbose("Generated Async " + chunk);
|
||||||
}
|
}
|
||||||
|
latch.countDown();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
J.s(() -> {
|
||||||
|
world.getChunkAt(chunk.getX(), chunk.getZ());
|
||||||
|
Iris.verbose("Generated " + chunk);
|
||||||
|
latch.countDown();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
latch.await();
|
||||||
|
} catch (InterruptedException ignored) {}
|
||||||
lazyGeneratedChunks.addAndGet(1);
|
lazyGeneratedChunks.addAndGet(1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tickRegenerate(Position2 chunk) {
|
private void tickRegenerate(Position2 chunk) {
|
||||||
@ -177,6 +206,64 @@ public class LazyPregenerator extends Thread implements Listener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setPausedLazy(World world) {
|
||||||
|
// todo: doesnt actually pause
|
||||||
|
LazyPregenJob job = jobs.get(world.getName());
|
||||||
|
if (isPausedLazy(world)){
|
||||||
|
job.paused = false;
|
||||||
|
} else {
|
||||||
|
job.paused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( job.paused) {
|
||||||
|
Iris.info(C.BLUE + "LazyGen: " + C.IRIS + world.getName() + C.BLUE + " Paused");
|
||||||
|
} else {
|
||||||
|
Iris.info(C.BLUE + "LazyGen: " + C.IRIS + world.getName() + C.BLUE + " Resumed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPausedLazy(World world) {
|
||||||
|
LazyPregenJob job = jobs.get(world.getName());
|
||||||
|
return job != null && job.isPaused();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdownInstance(World world) throws IOException {
|
||||||
|
Iris.info("LazyGen: " + C.IRIS + world.getName() + C.BLUE + " Shutting down..");
|
||||||
|
LazyPregenJob job = jobs.get(world.getName());
|
||||||
|
File worldDirectory = new File(Bukkit.getWorldContainer(), world.getName());
|
||||||
|
File lazyFile = new File(worldDirectory, "lazygen.json");
|
||||||
|
|
||||||
|
if (job == null) {
|
||||||
|
Iris.error("No Lazygen job found for world: " + world.getName());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!job.isPaused()) {
|
||||||
|
job.setPaused(true);
|
||||||
|
}
|
||||||
|
save();
|
||||||
|
jobs.remove(world.getName());
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (lazyFile.exists()){
|
||||||
|
lazyFile.delete();
|
||||||
|
J.sleep(1000);
|
||||||
|
}
|
||||||
|
Iris.info("LazyGen: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
|
||||||
|
}
|
||||||
|
}.runTaskLater(Iris.instance, 20L);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Iris.error("Failed to shutdown Lazygen for " + world.getName());
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
saveNow();
|
||||||
|
interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void saveNow() throws IOException {
|
public void saveNow() throws IOException {
|
||||||
IO.writeAll(this.destination, new Gson().toJson(job));
|
IO.writeAll(this.destination, new Gson().toJson(job));
|
||||||
}
|
}
|
||||||
@ -190,10 +277,15 @@ public class LazyPregenerator extends Thread implements Listener {
|
|||||||
@Builder.Default
|
@Builder.Default
|
||||||
private boolean healing = false;
|
private boolean healing = false;
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private int chunksPerMinute = 32; // 48 hours is roughly 5000 radius
|
private int chunksPerMinute = 32;
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private int radiusBlocks = 5000;
|
private int radiusBlocks = 5000;
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private int position = 0;
|
private int position = 0;
|
||||||
|
@Builder.Default
|
||||||
|
boolean silent = false;
|
||||||
|
@Builder.Default
|
||||||
|
boolean paused = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package com.volmit.iris.core.safeguard;
|
package com.volmit.iris.core.safeguard;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.IrisSettings;
|
|
||||||
import com.volmit.iris.util.format.C;
|
|
||||||
|
|
||||||
public class IrisSafeguard {
|
public class IrisSafeguard {
|
||||||
public static boolean unstablemode = false;
|
public static boolean unstablemode = false;
|
||||||
|
public static boolean warningmode = false;
|
||||||
|
public static boolean stablemode = false;
|
||||||
|
|
||||||
public static void IrisSafeguardSystem() {
|
public static void IrisSafeguardSystem() {
|
||||||
Iris.info("Enabled Iris SafeGuard");
|
Iris.info("Enabled Iris SafeGuard");
|
||||||
ServerBootSFG.BootCheck();
|
ServerBootSFG.BootCheck();
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
package com.volmit.iris.core.safeguard;
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.IrisSettings;
|
||||||
|
import com.volmit.iris.util.format.C;
|
||||||
|
|
||||||
|
public class ModesSFG {
|
||||||
|
public static void selectMode() {
|
||||||
|
if (IrisSafeguard.unstablemode) {
|
||||||
|
Iris.safeguard(C.DARK_RED + "Iris is running in Unstable Mode");
|
||||||
|
unstable();
|
||||||
|
}
|
||||||
|
if (IrisSafeguard.warningmode) {
|
||||||
|
Iris.safeguard(C.GOLD + "Iris is running in Warning Mode");
|
||||||
|
warning();
|
||||||
|
}
|
||||||
|
if (IrisSafeguard.stablemode) {
|
||||||
|
stable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stable() {
|
||||||
|
Iris.safeguard(C.BLUE + "Iris is running Stable");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void unstable() {
|
||||||
|
|
||||||
|
UtilsSFG.printIncompatibleWarnings();
|
||||||
|
|
||||||
|
if (IrisSafeguard.unstablemode) {
|
||||||
|
Iris.info("");
|
||||||
|
Iris.info(C.DARK_GRAY + "--==<" + C.RED + " IMPORTANT " + C.DARK_GRAY + ">==--");
|
||||||
|
Iris.info(C.RED + "Iris is running in unstable mode which may cause the following issues:");
|
||||||
|
Iris.info(C.DARK_RED + "Server Issues");
|
||||||
|
Iris.info(C.RED + "- Server won't 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 can't load due to corruption.");
|
||||||
|
Iris.info(C.RED + "- Worlds may slowly corrupt until they can't 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 won't be eligible for support.");
|
||||||
|
Iris.info(C.DARK_RED + "CAUSE: " + C.RED + UtilsSFG.MSGIncompatibleWarnings());
|
||||||
|
|
||||||
|
if (IrisSettings.get().getGeneral().ignoreBootMode) {
|
||||||
|
Iris.info(C.DARK_RED + "Boot Unstable is set to true, continuing with the startup process.");
|
||||||
|
} else {
|
||||||
|
Iris.info(C.DARK_RED + "Go to plugins/iris/settings.json and set ignoreBootMode to true if you wish to proceed.");
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// no
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Iris.info("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void warning() {
|
||||||
|
|
||||||
|
UtilsSFG.printIncompatibleWarnings();
|
||||||
|
|
||||||
|
if (IrisSafeguard.warningmode) {
|
||||||
|
Iris.info("");
|
||||||
|
Iris.info(C.DARK_GRAY + "--==<" + C.GOLD + " IMPORTANT " + C.DARK_GRAY + ">==--");
|
||||||
|
Iris.info(C.GOLD + "Iris is running in warning mode which may cause the following issues:");
|
||||||
|
Iris.info(C.YELLOW + "- Data Loss");
|
||||||
|
Iris.info(C.YELLOW + "- Errors");
|
||||||
|
Iris.info(C.YELLOW + "- Broken worlds");
|
||||||
|
Iris.info(C.YELLOW + "- Unexpected behavior.");
|
||||||
|
Iris.info(C.YELLOW + "- And perhaps further complications.");
|
||||||
|
Iris.info(C.GOLD + "ATTENTION: " + C.YELLOW + "While running Iris in unstable mode, you won't be eligible for support.");
|
||||||
|
Iris.info(C.GOLD + "CAUSE: " + C.YELLOW + UtilsSFG.MSGIncompatibleWarnings());
|
||||||
|
Iris.info("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,5 @@
|
|||||||
package com.volmit.iris.core.safeguard;
|
package com.volmit.iris.core.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 class PerformanceSFG {
|
||||||
public static void calculatePerformance() {
|
public static void calculatePerformance() {
|
||||||
|
|
||||||
|
@ -1,52 +1,59 @@
|
|||||||
package com.volmit.iris.core.safeguard;
|
package com.volmit.iris.core.safeguard;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.IrisSettings;
|
|
||||||
import com.volmit.iris.core.nms.INMS;
|
import com.volmit.iris.core.nms.INMS;
|
||||||
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
|
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
|
||||||
import com.volmit.iris.util.SFG.WorldHandlerSFG;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
import javax.print.attribute.standard.Severity;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.*;
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.StringJoiner;
|
||||||
|
|
||||||
|
import static com.volmit.iris.Iris.getJavaVersion;
|
||||||
import static com.volmit.iris.Iris.instance;
|
import static com.volmit.iris.Iris.instance;
|
||||||
import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode;
|
import static com.volmit.iris.core.safeguard.IrisSafeguard.*;
|
||||||
import static com.volmit.iris.core.tools.IrisToolbelt.access;
|
|
||||||
|
|
||||||
public class ServerBootSFG {
|
public class ServerBootSFG {
|
||||||
public static final Map<String, Boolean> incompatiblePlugins = new HashMap<>();
|
public static final Map<String, Boolean> incompatibilities = new HashMap<>();
|
||||||
|
public static boolean isJDK17 = true;
|
||||||
|
public static boolean hasEnoughDiskSpace = false;
|
||||||
|
public static boolean isJRE = false;
|
||||||
|
public static boolean hasPrivileges = false;
|
||||||
public static boolean unsuportedversion = false;
|
public static boolean unsuportedversion = false;
|
||||||
protected static boolean safeguardPassed;
|
protected static boolean safeguardPassed;
|
||||||
public static boolean passedserversoftware = true;
|
public static boolean passedserversoftware = true;
|
||||||
protected static byte count;
|
protected static int count;
|
||||||
public static String allIncompatiblePlugins;
|
protected static byte severityLow;
|
||||||
|
protected static byte severityMedium;
|
||||||
|
protected static byte severityHigh;
|
||||||
|
public static String allIncompatibilities;
|
||||||
|
|
||||||
public static void BootCheck() {
|
public static void BootCheck() {
|
||||||
Iris.info("Checking for possible conflicts..");
|
Iris.info("Checking for possible conflicts..");
|
||||||
org.bukkit.plugin.PluginManager pluginManager = Bukkit.getPluginManager();
|
org.bukkit.plugin.PluginManager pluginManager = Bukkit.getPluginManager();
|
||||||
Plugin[] plugins = pluginManager.getPlugins();
|
Plugin[] plugins = pluginManager.getPlugins();
|
||||||
|
|
||||||
incompatiblePlugins.clear();
|
incompatibilities.clear();
|
||||||
incompatiblePlugins.put("Multiverse-Core", false);
|
incompatibilities.put("Multiverse-Core", false);
|
||||||
incompatiblePlugins.put("Dynmap", false);
|
incompatibilities.put("Dynmap", false);
|
||||||
incompatiblePlugins.put("TerraformGenerator", false);
|
incompatibilities.put("TerraformGenerator", false);
|
||||||
incompatiblePlugins.put("Stratos", false);
|
incompatibilities.put("Stratos", false);
|
||||||
|
|
||||||
String pluginName;
|
String pluginName;
|
||||||
for (Plugin plugin : plugins) {
|
for (Plugin plugin : plugins) {
|
||||||
pluginName = plugin.getName();
|
pluginName = plugin.getName();
|
||||||
Boolean flag = incompatiblePlugins.get(pluginName);
|
Boolean flag = incompatibilities.get(pluginName);
|
||||||
if (flag != null && !flag) {
|
if (flag != null && !flag) {
|
||||||
count++;
|
severityHigh++;
|
||||||
incompatiblePlugins.put(pluginName, true);
|
incompatibilities.put(pluginName, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StringJoiner joiner = new StringJoiner(", ");
|
StringJoiner joiner = new StringJoiner(", ");
|
||||||
for (Map.Entry<String, Boolean> entry : incompatiblePlugins.entrySet()) {
|
for (Map.Entry<String, Boolean> entry : incompatibilities.entrySet()) {
|
||||||
if (entry.getValue()) {
|
if (entry.getValue()) {
|
||||||
joiner.add(entry.getKey());
|
joiner.add(entry.getKey());
|
||||||
}
|
}
|
||||||
@ -56,56 +63,108 @@ public class ServerBootSFG {
|
|||||||
!instance.getServer().getVersion().contains("Paper") &&
|
!instance.getServer().getVersion().contains("Paper") &&
|
||||||
!instance.getServer().getVersion().contains("Spigot") &&
|
!instance.getServer().getVersion().contains("Spigot") &&
|
||||||
!instance.getServer().getVersion().contains("Pufferfish") &&
|
!instance.getServer().getVersion().contains("Pufferfish") &&
|
||||||
!instance.getServer().getVersion().contains("Bukkit"))
|
!instance.getServer().getVersion().contains("Bukkit")) {
|
||||||
{
|
|
||||||
passedserversoftware = false;
|
passedserversoftware = false;
|
||||||
joiner.add("Server Software");
|
joiner.add("Server Software");
|
||||||
count++;
|
severityHigh++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (INMS.get() instanceof NMSBinding1X) {
|
if (INMS.get() instanceof NMSBinding1X) {
|
||||||
unsuportedversion = true;
|
unsuportedversion = true;
|
||||||
joiner.add("Unsupported Minecraft Version");
|
joiner.add("Unsupported Minecraft Version");
|
||||||
count++;
|
severityHigh++;
|
||||||
}
|
}
|
||||||
|
|
||||||
allIncompatiblePlugins = joiner.toString();
|
if (getJavaVersion() != 17) {
|
||||||
|
isJDK17 = false;
|
||||||
|
joiner.add("Unsupported Java version");
|
||||||
|
severityMedium++;
|
||||||
|
}
|
||||||
|
if (!isJDK()) {
|
||||||
|
isJRE = true;
|
||||||
|
joiner.add("Unsupported JDK");
|
||||||
|
severityMedium++;
|
||||||
|
}
|
||||||
|
if (!hasPrivileges()){
|
||||||
|
hasPrivileges = true;
|
||||||
|
joiner.add("Insufficient Privileges");
|
||||||
|
severityHigh++;
|
||||||
|
}
|
||||||
|
if (!enoughDiskSpace()){
|
||||||
|
hasEnoughDiskSpace = false;
|
||||||
|
joiner.add("Insufficient Disk Space");
|
||||||
|
severityHigh++;
|
||||||
|
}
|
||||||
|
|
||||||
safeguardPassed = (count == 0);
|
allIncompatibilities = joiner.toString();
|
||||||
|
|
||||||
|
safeguardPassed = (severityHigh == 0 && severityMedium == 0 && severityLow == 0);
|
||||||
|
count = severityHigh + severityMedium + severityLow;
|
||||||
|
if (safeguardPassed) {
|
||||||
|
stablemode = true;
|
||||||
|
Iris.safeguard("Stable mode has been activated.");
|
||||||
|
}
|
||||||
if (!safeguardPassed) {
|
if (!safeguardPassed) {
|
||||||
|
if (severityMedium >= 1 && severityHigh == 0) {
|
||||||
|
warningmode = true;
|
||||||
|
Iris.safeguard("Warning mode has been activated.");
|
||||||
|
}
|
||||||
|
if (severityHigh >= 1) {
|
||||||
unstablemode = true;
|
unstablemode = true;
|
||||||
Iris.safeguard("Unstable mode has been activated.");
|
Iris.safeguard("Unstable mode has been activated.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void CheckIrisWorlds() {
|
|
||||||
StringJoiner joiner = new StringJoiner(", ");
|
|
||||||
|
|
||||||
// Get the main server folder
|
|
||||||
File serverFolder = Bukkit.getWorldContainer();
|
|
||||||
|
|
||||||
// List all files in the server folder
|
|
||||||
File[] listOfFiles = serverFolder.listFiles();
|
|
||||||
|
|
||||||
if (listOfFiles != null) {
|
|
||||||
for (File file : listOfFiles) {
|
|
||||||
// Check if it is a directory (world folders are directories)
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
// Check for an "iris" folder inside the world directory
|
|
||||||
File irisFolder = new File(file, "iris");
|
|
||||||
if (irisFolder.exists() && irisFolder.isDirectory()) {
|
|
||||||
String worldName = file.getName();
|
|
||||||
joiner.add(worldName);
|
|
||||||
|
|
||||||
// Check if the world is already loaded
|
|
||||||
if (Bukkit.getWorld(worldName) == null) {
|
|
||||||
WorldHandlerSFG.LoadWorld(worldName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isJDK() {
|
||||||
|
String path = System.getProperty("sun.boot.library.path");
|
||||||
|
if (path != null) {
|
||||||
|
String javacPath = "";
|
||||||
|
if (path.endsWith(File.separator + "bin")) {
|
||||||
|
javacPath = path;
|
||||||
} else {
|
} else {
|
||||||
Bukkit.getLogger().warning("No files found in the server folder.");
|
int libIndex = path.lastIndexOf(File.separator + "lib");
|
||||||
}
|
if (libIndex > 0) {
|
||||||
// No Idea what I should do with this
|
javacPath = path.substring(0, libIndex) + File.separator + "bin";
|
||||||
String worldsList = joiner.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (checkJavac(javacPath))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
path = System.getProperty("java.home");
|
||||||
|
return path != null && checkJavac(path + File.separator + "bin");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasPrivileges() {
|
||||||
|
File pv = new File(Bukkit.getWorldContainer() + "iristest.json");
|
||||||
|
if (pv.exists()){
|
||||||
|
pv.delete();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (pv.createNewFile()){
|
||||||
|
if (pv.canWrite() && pv.canRead()){
|
||||||
|
pv.delete();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean enoughDiskSpace() {
|
||||||
|
File freeSpace = new File(Bukkit.getWorldContainer() + ".");
|
||||||
|
double gigabytes = freeSpace.getFreeSpace() / (1024.0 * 1024.0 * 1024.0);
|
||||||
|
if (gigabytes > 3){
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean checkJavac(String path) {
|
||||||
|
return !path.isEmpty() && (new File(path, "javac").exists() || new File(path, "javac.exe").exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -1,43 +1,37 @@
|
|||||||
package com.volmit.iris.core.safeguard;
|
package com.volmit.iris.core.safeguard;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.IrisSettings;
|
|
||||||
import com.volmit.iris.util.format.C;
|
import com.volmit.iris.util.format.C;
|
||||||
|
|
||||||
public class UtilsSFG {
|
public class UtilsSFG {
|
||||||
public static void UnstableMode(){
|
public static void splash() {
|
||||||
if (IrisSafeguard.unstablemode) {
|
ModesSFG.selectMode();
|
||||||
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 (!ServerBootSFG.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() {
|
public static void printIncompatibleWarnings() {
|
||||||
// String SupportedIrisVersion = getDescription().getVersion(); //todo Automatic version
|
// String SupportedIrisVersion = getDescription().getVersion(); //todo Automatic version
|
||||||
|
|
||||||
if (ServerBootSFG.safeguardPassed) {
|
if (ServerBootSFG.safeguardPassed) {
|
||||||
Iris.safeguard(C.BLUE + "0 Conflicts found");
|
Iris.safeguard(C.BLUE + "0 Conflicts found");
|
||||||
} else {
|
} else {
|
||||||
|
if (IrisSafeguard.unstablemode) {
|
||||||
Iris.safeguard(C.DARK_RED + "" + ServerBootSFG.count + " Conflicts found");
|
Iris.safeguard(C.DARK_RED + "" + ServerBootSFG.count + " Conflicts found");
|
||||||
IrisSafeguard.unstablemode = true;
|
}
|
||||||
|
if (IrisSafeguard.warningmode) {
|
||||||
|
Iris.safeguard(C.YELLOW + "" + ServerBootSFG.count + " Conflicts found");
|
||||||
|
}
|
||||||
|
|
||||||
if (ServerBootSFG.incompatiblePlugins.get("Multiverse-Core")) {
|
if (ServerBootSFG.incompatibilities.get("Multiverse-Core")) {
|
||||||
Iris.safeguard(C.RED + "Multiverse");
|
Iris.safeguard(C.RED + "Multiverse");
|
||||||
Iris.safeguard(C.RED + "- The plugin Multiverse is not compatible with the server.");
|
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.");
|
Iris.safeguard(C.RED + "- If you want to have a world manager, consider using PhantomWorlds or MyWorlds instead.");
|
||||||
}
|
}
|
||||||
if (ServerBootSFG.incompatiblePlugins.get("Dynmap")) {
|
if (ServerBootSFG.incompatibilities.get("Dynmap")) {
|
||||||
Iris.safeguard(C.RED + "Dynmap");
|
Iris.safeguard(C.RED + "Dynmap");
|
||||||
Iris.safeguard(C.RED + "- The plugin Dynmap is not compatible with the server.");
|
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.");
|
Iris.safeguard(C.RED + "- If you want to have a map plugin like Dynmap, consider Bluemap.");
|
||||||
}
|
}
|
||||||
if (ServerBootSFG.incompatiblePlugins.get("TerraformGenerator") || ServerBootSFG.incompatiblePlugins.get("Stratos")) {
|
if (ServerBootSFG.incompatibilities.get("TerraformGenerator") || ServerBootSFG.incompatibilities.get("Stratos")) {
|
||||||
Iris.safeguard(C.YELLOW + "Terraform Generator / Stratos");
|
Iris.safeguard(C.YELLOW + "Terraform Generator / Stratos");
|
||||||
Iris.safeguard(C.YELLOW + "- Iris is not compatible with other worldgen plugins.");
|
Iris.safeguard(C.YELLOW + "- Iris is not compatible with other worldgen plugins.");
|
||||||
}
|
}
|
||||||
@ -48,49 +42,27 @@ public class UtilsSFG {
|
|||||||
if (!ServerBootSFG.passedserversoftware) {
|
if (!ServerBootSFG.passedserversoftware) {
|
||||||
Iris.safeguard(C.RED + "Unsupported Server Software");
|
Iris.safeguard(C.RED + "Unsupported Server Software");
|
||||||
Iris.safeguard(C.RED + "- Please consider using Paper or Purpur instead.");
|
Iris.safeguard(C.RED + "- Please consider using Paper or Purpur instead.");
|
||||||
|
}
|
||||||
|
if (!ServerBootSFG.hasPrivileges) {
|
||||||
|
Iris.safeguard(C.RED + "Insufficient Privileges");
|
||||||
|
Iris.safeguard(C.RED + "- The server has insufficient Privileges to run iris. Please contact support.");
|
||||||
|
}
|
||||||
|
if (!ServerBootSFG.hasEnoughDiskSpace) {
|
||||||
|
Iris.safeguard(C.RED + "Insufficient Disk Space");
|
||||||
|
Iris.safeguard(C.RED + "- The server has insufficient Free DiskSpace to run iris required 3GB+.");
|
||||||
|
}
|
||||||
|
if (!ServerBootSFG.isJDK17) {
|
||||||
|
Iris.safeguard(C.YELLOW + "Unsupported java version");
|
||||||
|
Iris.safeguard(C.YELLOW + "- Please consider using JDK 17 Instead of JDK " + Iris.getJavaVersion());
|
||||||
|
}
|
||||||
|
if (!ServerBootSFG.isJRE) {
|
||||||
|
Iris.safeguard(C.YELLOW + "Unsupported Server JDK");
|
||||||
|
Iris.safeguard(C.YELLOW + "- Please consider using JDK 17 Instead of JRE " + Iris.getJavaVersion());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String MSGIncompatibleWarnings() {
|
public static String MSGIncompatibleWarnings() {
|
||||||
return ServerBootSFG.allIncompatiblePlugins;
|
return ServerBootSFG.allIncompatibilities;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void unstablePrompt() {
|
|
||||||
if (IrisSafeguard.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("");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,150 +0,0 @@
|
|||||||
package com.volmit.iris.core.service;
|
|
||||||
|
|
||||||
import java.nio.file.*;
|
|
||||||
import static java.nio.file.StandardWatchEventKinds.*;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import com.google.gson.JsonParseException;
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.util.SFG.WorldHandlerSFG;
|
|
||||||
import com.volmit.iris.util.format.C;
|
|
||||||
import com.volmit.iris.util.plugin.IrisService;
|
|
||||||
import com.volmit.iris.util.scheduling.Looper;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
|
||||||
|
|
||||||
public class HotDropWorldSVC extends Looper implements IrisService {
|
|
||||||
private WatchService watchService;
|
|
||||||
private JavaPlugin plugin;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEnable() {
|
|
||||||
this.plugin = Iris.instance; // Assuming Iris.instance is your plugin instance
|
|
||||||
initializeWatchService();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDisable() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeWatchService() {
|
|
||||||
try {
|
|
||||||
this.watchService = FileSystems.getDefault().newWatchService();
|
|
||||||
Path path = Paths.get(Bukkit.getWorldContainer().getAbsolutePath());
|
|
||||||
path.register(watchService, ENTRY_CREATE);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Iris.reportError(e);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected long loop() {
|
|
||||||
WatchKey key;
|
|
||||||
try {
|
|
||||||
key = watchService.poll();
|
|
||||||
if (key != null) {
|
|
||||||
for (WatchEvent<?> event : key.pollEvents()) {
|
|
||||||
WatchEvent.Kind<?> kind = event.kind();
|
|
||||||
|
|
||||||
if (kind == ENTRY_CREATE) {
|
|
||||||
WatchEvent<Path> ev = (WatchEvent<Path>) event;
|
|
||||||
Path filename = ev.context();
|
|
||||||
|
|
||||||
File newDir = new File(Bukkit.getWorldContainer(), filename.toString());
|
|
||||||
File irisFolder = new File(newDir, "iris");
|
|
||||||
if (irisFolder.exists() && irisFolder.isDirectory()) {
|
|
||||||
Iris.info("World HotDrop Detected!");
|
|
||||||
String worldName = newDir.getName();
|
|
||||||
String version = getVersionFromIrisFolder(irisFolder);
|
|
||||||
|
|
||||||
if (Bukkit.getWorld(worldName) == null && isPackValid(worldName, version)) {
|
|
||||||
Bukkit.getScheduler().runTask(this.plugin, () -> WorldHandlerSFG.LoadWorld(worldName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
key.reset();
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
Iris.reportError(e);
|
|
||||||
e.printStackTrace();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getVersionFromIrisFolder(File irisFolder) {
|
|
||||||
File versionFile = new File(irisFolder, "some_version_file.json");
|
|
||||||
|
|
||||||
if (versionFile.exists() && versionFile.isFile()) {
|
|
||||||
try (FileReader reader = new FileReader(versionFile)) {
|
|
||||||
JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject();
|
|
||||||
if (jsonObject.has("version")) {
|
|
||||||
return jsonObject.get("version").getAsString();
|
|
||||||
}
|
|
||||||
} catch (IOException | JsonParseException e) {
|
|
||||||
Iris.reportError(e);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "???";
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isPackValid(String worldPackName, String version) {
|
|
||||||
try {
|
|
||||||
File packFolder = Iris.service(StudioSVC.class).getWorkspaceFolder();
|
|
||||||
File[] serverPacks = packFolder.listFiles(File::isDirectory);
|
|
||||||
if (serverPacks != null) {
|
|
||||||
for (File serverPack : serverPacks) {
|
|
||||||
String serverPackName = serverPack.getName();
|
|
||||||
String serverPackVersion = getPackVersion(serverPack);
|
|
||||||
|
|
||||||
if (serverPackName.equals(worldPackName)) {
|
|
||||||
if (serverPackVersion.equals(version)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
Iris.info("Version mismatch for pack '" + worldPackName + "'. Expected: " + serverPackVersion + ", Found: " + version);
|
|
||||||
Iris.info(C.GOLD + "Cant load the world!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Iris.info("Pack '" + worldPackName + "' not found on the server.");
|
|
||||||
Iris.info(C.GOLD + "Cant load the world!");
|
|
||||||
} else {
|
|
||||||
Iris.info("No packs found in the server's workspace folder.");
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Iris.reportError(e);
|
|
||||||
e.printStackTrace();
|
|
||||||
Iris.info("Error checking if pack is valid: " + e.getMessage());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getPackVersion(File pack) {
|
|
||||||
String version = "???";
|
|
||||||
File dimensionFile = new File(pack, "dimensions/" + pack.getName() + ".json");
|
|
||||||
if (dimensionFile.isFile()) {
|
|
||||||
try (FileReader reader = new FileReader(dimensionFile)) {
|
|
||||||
JsonObject json = JsonParser.parseReader(reader).getAsJsonObject();
|
|
||||||
if (json.has("version")) {
|
|
||||||
version = json.get("version").getAsString();
|
|
||||||
}
|
|
||||||
} catch (IOException | JsonParseException e) {
|
|
||||||
Iris.reportError(e);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,163 @@
|
|||||||
|
package com.volmit.iris.core.service;
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
|
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
||||||
|
import com.volmit.iris.util.collection.KMap;
|
||||||
|
import com.volmit.iris.util.format.C;
|
||||||
|
import com.volmit.iris.util.format.Form;
|
||||||
|
import com.volmit.iris.util.misc.getHardware;
|
||||||
|
import com.volmit.iris.util.plugin.IrisService;
|
||||||
|
import com.volmit.iris.util.scheduling.Looper;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class IrisEngineSVC implements IrisService {
|
||||||
|
private static final AtomicInteger tectonicLimit = new AtomicInteger(30);
|
||||||
|
private final ReentrantLock lastUseLock = new ReentrantLock();
|
||||||
|
private final KMap<Engine, Long> lastUse = new KMap<>();
|
||||||
|
private Looper cacheTicker;
|
||||||
|
private Looper trimTicker;
|
||||||
|
private Looper unloadTicker;
|
||||||
|
public List<World> corruptedIrisWorlds = new ArrayList<>();
|
||||||
|
|
||||||
|
// todo make this work with multiple worlds
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
tectonicLimit.set(2);
|
||||||
|
long t = getHardware.getProcessMemory();
|
||||||
|
while (t > 250) {
|
||||||
|
tectonicLimit.getAndAdd(1);
|
||||||
|
t = t - 250;
|
||||||
|
}
|
||||||
|
tectonicLimit.set(10); // DEBUG CODE
|
||||||
|
this.setup();
|
||||||
|
cacheTicker.start();
|
||||||
|
trimTicker.start();
|
||||||
|
unloadTicker.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getTectonicLimit() {
|
||||||
|
return tectonicLimit.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setup() {
|
||||||
|
cacheTicker = new Looper() {
|
||||||
|
@Override
|
||||||
|
protected long loop() {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
lastUseLock.lock();
|
||||||
|
try {
|
||||||
|
for (Engine key : new ArrayList<>(lastUse.keySet())) {
|
||||||
|
Long last = lastUse.get(key);
|
||||||
|
if (last == null)
|
||||||
|
continue;
|
||||||
|
if (now - last > 60000) { // 1 minute
|
||||||
|
lastUse.remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lastUseLock.unlock();
|
||||||
|
}
|
||||||
|
return 1000;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
trimTicker = new Looper() {
|
||||||
|
private final Supplier<Engine> supplier = createSupplier();
|
||||||
|
@Override
|
||||||
|
protected long loop() {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
Engine engine = supplier.get();
|
||||||
|
if (engine != null) {
|
||||||
|
engine.getMantle().trim(tectonicLimit.get() / lastUse.size());
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.reportError(e);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = lastUse.size();
|
||||||
|
long time = (size > 0 ? 1000/size : 1000) - (System.currentTimeMillis() - start);
|
||||||
|
if (time <= 0)
|
||||||
|
return 0;
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
unloadTicker = new Looper() {
|
||||||
|
private final Supplier<Engine> supplier = createSupplier();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected long loop() {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
Engine engine = supplier.get();
|
||||||
|
if (engine != null) {
|
||||||
|
long unloadStart = System.currentTimeMillis();
|
||||||
|
int count = engine.getMantle().unloadTectonicPlate();
|
||||||
|
if (count > 0) {
|
||||||
|
Iris.info(C.GOLD + "Unloaded " + C.YELLOW + count + " TectonicPlates in " + C.RED + Form.duration(System.currentTimeMillis() - unloadStart, 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.reportError(e);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = lastUse.size();
|
||||||
|
long time = (size > 0 ? 1000/size : 1000) - (System.currentTimeMillis() - start);
|
||||||
|
if (time <= 0)
|
||||||
|
return 0;
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Supplier<Engine> createSupplier() {
|
||||||
|
AtomicInteger i = new AtomicInteger();
|
||||||
|
return () -> {
|
||||||
|
List<World> worlds = Bukkit.getWorlds();
|
||||||
|
if (i.get() >= worlds.size()) {
|
||||||
|
i.set(0);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
for (int j = 0; j < worlds.size(); j++) {
|
||||||
|
PlatformChunkGenerator generator = IrisToolbelt.access(worlds.get(i.getAndIncrement()));
|
||||||
|
if (i.get() >= worlds.size()) {
|
||||||
|
i.set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generator != null) {
|
||||||
|
Engine engine = generator.getEngine();
|
||||||
|
if (engine != null) {
|
||||||
|
lastUseLock.lock();
|
||||||
|
lastUse.put(engine, System.currentTimeMillis());
|
||||||
|
lastUseLock.unlock();
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.reportError(e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
cacheTicker.interrupt();
|
||||||
|
trimTicker.interrupt();
|
||||||
|
unloadTicker.interrupt();
|
||||||
|
lastUse.clear();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.volmit.iris.core.service;
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.util.plugin.IrisService;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.world.WorldLoadEvent;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
import static java.lang.System.getLogger;
|
||||||
|
|
||||||
|
public class WorldLoadSFG implements IrisService {
|
||||||
|
private JavaPlugin plugin;
|
||||||
|
@EventHandler
|
||||||
|
public void onWorldLoad(WorldLoadEvent event) {
|
||||||
|
World world = event.getWorld();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
this.plugin = Iris.instance;
|
||||||
|
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,7 @@ import com.volmit.iris.core.IrisSettings;
|
|||||||
import com.volmit.iris.core.ServerConfigurator;
|
import com.volmit.iris.core.ServerConfigurator;
|
||||||
import com.volmit.iris.core.pregenerator.PregenTask;
|
import com.volmit.iris.core.pregenerator.PregenTask;
|
||||||
import com.volmit.iris.core.service.StudioSVC;
|
import com.volmit.iris.core.service.StudioSVC;
|
||||||
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
import com.volmit.iris.engine.object.IrisDimension;
|
import com.volmit.iris.engine.object.IrisDimension;
|
||||||
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
||||||
import com.volmit.iris.core.safeguard.UtilsSFG;
|
import com.volmit.iris.core.safeguard.UtilsSFG;
|
||||||
@ -45,6 +46,8 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static com.volmit.iris.core.tools.IrisPackBenchmarking.benchmark;
|
import static com.volmit.iris.core.tools.IrisPackBenchmarking.benchmark;
|
||||||
import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode;
|
import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode;
|
||||||
@ -173,7 +176,6 @@ public class IrisCreator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//if (benchmark){loaded = true;}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,8 +19,7 @@
|
|||||||
package com.volmit.iris.core.tools;
|
package com.volmit.iris.core.tools;
|
||||||
|
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
import com.volmit.iris.engine.object.IrisDimension;
|
import com.volmit.iris.engine.object.*;
|
||||||
import com.volmit.iris.engine.object.IrisWorld;
|
|
||||||
import com.volmit.iris.engine.platform.BukkitChunkGenerator;
|
import com.volmit.iris.engine.platform.BukkitChunkGenerator;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
@ -79,6 +78,7 @@ public class IrisWorldCreator {
|
|||||||
? dim.getLoader().getDataFolder() :
|
? dim.getLoader().getDataFolder() :
|
||||||
new File(w.worldFolder(), "iris/pack"), dimensionName);
|
new File(w.worldFolder(), "iris/pack"), dimensionName);
|
||||||
|
|
||||||
|
|
||||||
return new WorldCreator(name)
|
return new WorldCreator(name)
|
||||||
.environment(findEnvironment())
|
.environment(findEnvironment())
|
||||||
.generateStructures(true)
|
.generateStructures(true)
|
||||||
|
@ -35,6 +35,8 @@ import com.volmit.iris.util.noise.CNG;
|
|||||||
import com.volmit.iris.util.stream.ProceduralStream;
|
import com.volmit.iris.util.stream.ProceduralStream;
|
||||||
import com.volmit.iris.util.stream.interpolation.Interpolated;
|
import com.volmit.iris.util.stream.interpolation.Interpolated;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.Biome;
|
import org.bukkit.block.Biome;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
@ -42,6 +44,8 @@ import org.bukkit.block.data.BlockData;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(exclude = "data")
|
||||||
|
@ToString(exclude = "data")
|
||||||
public class IrisComplex implements DataProvider {
|
public class IrisComplex implements DataProvider {
|
||||||
private static final BlockData AIR = Material.AIR.createBlockData();
|
private static final BlockData AIR = Material.AIR.createBlockData();
|
||||||
private RNG rng;
|
private RNG rng;
|
||||||
|
@ -50,6 +50,9 @@ import com.volmit.iris.util.scheduling.ChronoLatch;
|
|||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.Biome;
|
import org.bukkit.block.Biome;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
@ -62,8 +65,12 @@ import java.util.Set;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(exclude = "context")
|
||||||
|
@ToString(exclude = "context")
|
||||||
public class IrisEngine implements Engine {
|
public class IrisEngine implements Engine {
|
||||||
private final AtomicInteger bud;
|
private final AtomicInteger bud;
|
||||||
private final AtomicInteger buds;
|
private final AtomicInteger buds;
|
||||||
@ -250,7 +257,10 @@ public class IrisEngine implements Engine {
|
|||||||
if (!f.exists()) {
|
if (!f.exists()) {
|
||||||
try {
|
try {
|
||||||
f.getParentFile().mkdirs();
|
f.getParentFile().mkdirs();
|
||||||
IO.writeAll(f, new Gson().toJson(new IrisEngineData()));
|
IrisEngineData data = new IrisEngineData();
|
||||||
|
data.getStatistics().setVersion(getIrisVersion());
|
||||||
|
data.getStatistics().setMCVersion(getMCVersion());
|
||||||
|
IO.writeAll(f, new Gson().toJson(data));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -418,7 +428,6 @@ public class IrisEngine implements Engine {
|
|||||||
|
|
||||||
J.a(() -> {
|
J.a(() -> {
|
||||||
try {
|
try {
|
||||||
getMantle().trim();
|
|
||||||
getData().getObjectLoader().clean();
|
getData().getObjectLoader().clean();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
@ -518,4 +527,37 @@ public class IrisEngine implements Engine {
|
|||||||
public int getCacheID() {
|
public int getCacheID() {
|
||||||
return cacheId;
|
return cacheId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getIrisVersion() {
|
||||||
|
String input = Iris.instance.getDescription().getVersion();
|
||||||
|
int hyphenIndex = input.indexOf('-');
|
||||||
|
if (hyphenIndex != -1) {
|
||||||
|
String result = input.substring(0, hyphenIndex);
|
||||||
|
result = result.replaceAll("\\.", "");
|
||||||
|
return Integer.parseInt(result);
|
||||||
|
}
|
||||||
|
Iris.error("Failed to assign a Iris Version");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getMCVersion() {
|
||||||
|
try {
|
||||||
|
String version = Bukkit.getVersion();
|
||||||
|
Matcher matcher = Pattern.compile("\\(MC: ([\\d.]+)\\)").matcher(version);
|
||||||
|
if (matcher.find()) {
|
||||||
|
version = matcher.group(1).replaceAll("\\.", "");
|
||||||
|
long versionNumber = Long.parseLong(version);
|
||||||
|
if (versionNumber > Integer.MAX_VALUE) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return (int) versionNumber;
|
||||||
|
}
|
||||||
|
Iris.error("Failed to assign a Minecraft Version");
|
||||||
|
return -1;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Iris.error("Failed to assign a Minecraft Version");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,8 @@ import com.volmit.iris.util.format.Form;
|
|||||||
import com.volmit.iris.util.mantle.Mantle;
|
import com.volmit.iris.util.mantle.Mantle;
|
||||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
import org.bukkit.util.BlockVector;
|
import org.bukkit.util.BlockVector;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -49,6 +51,8 @@ import static com.volmit.iris.core.tools.IrisPackBenchmarking.benchmark;
|
|||||||
import static com.volmit.iris.core.safeguard.PerformanceSFG.*;
|
import static com.volmit.iris.core.safeguard.PerformanceSFG.*;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(exclude = "engine")
|
||||||
|
@ToString(exclude = "engine")
|
||||||
public class IrisEngineMantle implements EngineMantle {
|
public class IrisEngineMantle implements EngineMantle {
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
private final Mantle mantle;
|
private final Mantle mantle;
|
||||||
|
@ -25,11 +25,15 @@ import com.volmit.iris.engine.scripting.EngineExecutionEnvironment;
|
|||||||
import com.volmit.iris.engine.scripting.IrisScriptingAPI;
|
import com.volmit.iris.engine.scripting.IrisScriptingAPI;
|
||||||
import com.volmit.iris.util.format.C;
|
import com.volmit.iris.util.format.C;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
import org.apache.bsf.BSFException;
|
import org.apache.bsf.BSFException;
|
||||||
import org.apache.bsf.BSFManager;
|
import org.apache.bsf.BSFManager;
|
||||||
import org.apache.bsf.engines.javascript.JavaScriptEngine;
|
import org.apache.bsf.engines.javascript.JavaScriptEngine;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(exclude = "engine")
|
||||||
|
@ToString(exclude = "engine")
|
||||||
public class IrisExecutionEnvironment implements EngineExecutionEnvironment {
|
public class IrisExecutionEnvironment implements EngineExecutionEnvironment {
|
||||||
private final BSFManager manager;
|
private final BSFManager manager;
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
|
@ -523,8 +523,9 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
return getTarget().getBurster();
|
return getTarget().getBurster();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
default void clean() {
|
default void clean() {
|
||||||
burst().lazy(() -> getMantle().trim());
|
burst().lazy(() -> getMantle().trim(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
@BlockCoordinates
|
@BlockCoordinates
|
||||||
@ -803,7 +804,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
return getBiomeOrMantle(l.getBlockX(), l.getBlockY(), l.getBlockZ());
|
return getBiomeOrMantle(l.getBlockX(), l.getBlockY(), l.getBlockZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
default void gotoBiome(IrisBiome biome, Player player) {
|
default void gotoBiome(IrisBiome biome, Player player, boolean teleport) {
|
||||||
Set<String> regionKeys = getDimension()
|
Set<String> regionKeys = getDimension()
|
||||||
.getAllRegions(this).stream()
|
.getAllRegions(this).stream()
|
||||||
.filter((i) -> i.getAllBiomes(this).contains(biome))
|
.filter((i) -> i.getAllBiomes(this).contains(biome))
|
||||||
@ -815,13 +816,13 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
&& lb.matches(engine, chunk);
|
&& lb.matches(engine, chunk);
|
||||||
|
|
||||||
if (!regionKeys.isEmpty()) {
|
if (!regionKeys.isEmpty()) {
|
||||||
locator.find(player);
|
locator.find(player, teleport, "Biome " + biome.getName());
|
||||||
} else {
|
} else {
|
||||||
player.sendMessage(C.RED + biome.getName() + " is not in any defined regions!");
|
player.sendMessage(C.RED + biome.getName() + " is not in any defined regions!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default void gotoJigsaw(IrisJigsawStructure s, Player player) {
|
default void gotoJigsaw(IrisJigsawStructure s, Player player, boolean teleport) {
|
||||||
if (s.getLoadKey().equals(getDimension().getStronghold())) {
|
if (s.getLoadKey().equals(getDimension().getStronghold())) {
|
||||||
KList<Position2> p = getDimension().getStrongholds(getSeedManager().getSpawn());
|
KList<Position2> p = getDimension().getStrongholds(getSeedManager().getSpawn());
|
||||||
|
|
||||||
@ -858,7 +859,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
if (getDimension().getJigsawStructures().stream()
|
if (getDimension().getJigsawStructures().stream()
|
||||||
.map(IrisJigsawStructurePlacement::getStructure)
|
.map(IrisJigsawStructurePlacement::getStructure)
|
||||||
.collect(Collectors.toSet()).contains(s.getLoadKey())) {
|
.collect(Collectors.toSet()).contains(s.getLoadKey())) {
|
||||||
Locator.jigsawStructure(s.getLoadKey()).find(player);
|
Locator.jigsawStructure(s.getLoadKey()).find(player, teleport, "Structure " + s.getLoadKey());
|
||||||
} else {
|
} else {
|
||||||
Set<String> biomeKeys = getDimension().getAllBiomes(this).stream()
|
Set<String> biomeKeys = getDimension().getAllBiomes(this).stream()
|
||||||
.filter((i) -> i.getJigsawStructures()
|
.filter((i) -> i.getJigsawStructures()
|
||||||
@ -885,7 +886,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!regionKeys.isEmpty()) {
|
if (!regionKeys.isEmpty()) {
|
||||||
locator.find(player);
|
locator.find(player, teleport, "Structure " + s.getLoadKey());
|
||||||
} else {
|
} else {
|
||||||
player.sendMessage(C.RED + s.getLoadKey() + " is not in any defined regions, biomes or dimensions!");
|
player.sendMessage(C.RED + s.getLoadKey() + " is not in any defined regions, biomes or dimensions!");
|
||||||
}
|
}
|
||||||
@ -893,7 +894,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default void gotoObject(String s, Player player) {
|
default void gotoObject(String s, Player player, boolean teleport) {
|
||||||
Set<String> biomeKeys = getDimension().getAllBiomes(this).stream()
|
Set<String> biomeKeys = getDimension().getAllBiomes(this).stream()
|
||||||
.filter((i) -> i.getObjects().stream().anyMatch((f) -> f.getPlace().contains(s)))
|
.filter((i) -> i.getObjects().stream().anyMatch((f) -> f.getPlace().contains(s)))
|
||||||
.map(IrisRegistrant::getLoadKey)
|
.map(IrisRegistrant::getLoadKey)
|
||||||
@ -916,23 +917,23 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!regionKeys.isEmpty()) {
|
if (!regionKeys.isEmpty()) {
|
||||||
locator.find(player);
|
locator.find(player, teleport, "Object " + s);
|
||||||
} else {
|
} else {
|
||||||
player.sendMessage(C.RED + s + " is not in any defined regions or biomes!");
|
player.sendMessage(C.RED + s + " is not in any defined regions or biomes!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default void gotoRegion(IrisRegion r, Player player) {
|
default void gotoRegion(IrisRegion r, Player player, boolean teleport) {
|
||||||
if (!getDimension().getAllRegions(this).contains(r)) {
|
if (!getDimension().getAllRegions(this).contains(r)) {
|
||||||
player.sendMessage(C.RED + r.getName() + " is not defined in the dimension!");
|
player.sendMessage(C.RED + r.getName() + " is not defined in the dimension!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Locator.region(r.getLoadKey()).find(player);
|
Locator.region(r.getLoadKey()).find(player, teleport, "Region " + r.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
default void gotoPOI(String type, Player p) {
|
default void gotoPOI(String type, Player p, boolean teleport) {
|
||||||
Locator.poi(type).find(p);
|
Locator.poi(type).find(p, teleport, "POI " + type);
|
||||||
}
|
}
|
||||||
|
|
||||||
default void cleanupMantleChunk(int x, int z) {
|
default void cleanupMantleChunk(int x, int z) {
|
||||||
|
@ -21,8 +21,12 @@ package com.volmit.iris.engine.framework;
|
|||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.util.math.RollingSequence;
|
import com.volmit.iris.util.math.RollingSequence;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(exclude = "engine")
|
||||||
|
@ToString(exclude = "engine")
|
||||||
public class EngineAssignedComponent implements EngineComponent {
|
public class EngineAssignedComponent implements EngineComponent {
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
private final RollingSequence metrics;
|
private final RollingSequence metrics;
|
||||||
|
@ -23,8 +23,12 @@ import com.volmit.iris.engine.object.IrisDimension;
|
|||||||
import com.volmit.iris.engine.object.IrisWorld;
|
import com.volmit.iris.engine.object.IrisWorld;
|
||||||
import com.volmit.iris.util.parallel.MultiBurst;
|
import com.volmit.iris.util.parallel.MultiBurst;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(exclude = "data")
|
||||||
|
@ToString(exclude = "data")
|
||||||
public class EngineTarget {
|
public class EngineTarget {
|
||||||
private final MultiBurst burster;
|
private final MultiBurst burster;
|
||||||
private final IrisData data;
|
private final IrisData data;
|
||||||
|
@ -27,6 +27,7 @@ import com.volmit.iris.engine.object.IrisJigsawStructure;
|
|||||||
import com.volmit.iris.engine.object.IrisObject;
|
import com.volmit.iris.engine.object.IrisObject;
|
||||||
import com.volmit.iris.engine.object.IrisRegion;
|
import com.volmit.iris.engine.object.IrisRegion;
|
||||||
import com.volmit.iris.util.context.ChunkContext;
|
import com.volmit.iris.util.context.ChunkContext;
|
||||||
|
import com.volmit.iris.util.format.C;
|
||||||
import com.volmit.iris.util.format.Form;
|
import com.volmit.iris.util.format.Form;
|
||||||
import com.volmit.iris.util.math.M;
|
import com.volmit.iris.util.math.M;
|
||||||
import com.volmit.iris.util.math.Position2;
|
import com.volmit.iris.util.math.Position2;
|
||||||
@ -39,6 +40,7 @@ import com.volmit.iris.util.scheduling.J;
|
|||||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||||
import com.volmit.iris.util.scheduling.jobs.SingleJob;
|
import com.volmit.iris.util.scheduling.jobs.SingleJob;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -109,23 +111,35 @@ public interface Locator<T> {
|
|||||||
|
|
||||||
boolean matches(Engine engine, Position2 chunk);
|
boolean matches(Engine engine, Position2 chunk);
|
||||||
|
|
||||||
default void find(Player player) {
|
default void find(Player player, boolean teleport, String message) {
|
||||||
find(player, 30_000);
|
find(player, location -> {
|
||||||
|
if (teleport) {
|
||||||
|
J.s(() -> player.teleport(location));
|
||||||
|
} else {
|
||||||
|
player.sendMessage(C.GREEN + message + " at: " + location.getBlockX() + " " + location.getBlockY() + " " + location.getBlockZ());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
default void find(Player player, long timeout) {
|
default void find(Player player, Consumer<Location> consumer) {
|
||||||
|
find(player, 30_000, consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
default void find(Player player, long timeout, Consumer<Location> consumer) {
|
||||||
AtomicLong checks = new AtomicLong();
|
AtomicLong checks = new AtomicLong();
|
||||||
long ms = M.ms();
|
long ms = M.ms();
|
||||||
new SingleJob("Searching", () -> {
|
new SingleJob("Searching", () -> {
|
||||||
try {
|
try {
|
||||||
Position2 at = find(IrisToolbelt.access(player.getWorld()).getEngine(), new Position2(player.getLocation().getBlockX() >> 4, player.getLocation().getBlockZ() >> 4), timeout, checks::set).get();
|
World world = player.getWorld();
|
||||||
|
Engine engine = IrisToolbelt.access(world).getEngine();
|
||||||
|
Position2 at = find(engine, new Position2(player.getLocation().getBlockX() >> 4, player.getLocation().getBlockZ() >> 4), timeout, checks::set).get();
|
||||||
|
|
||||||
if (at != null) {
|
if (at != null) {
|
||||||
J.s(() -> player.teleport(new Location(player.getWorld(), (at.getX() << 4) + 8,
|
consumer.accept(new Location(world, (at.getX() << 4) + 8,
|
||||||
IrisToolbelt.access(player.getWorld()).getEngine().getHeight(
|
engine.getHeight(
|
||||||
(at.getX() << 4) + 8,
|
(at.getX() << 4) + 8,
|
||||||
(at.getZ() << 4) + 8, false),
|
(at.getZ() << 4) + 8, false),
|
||||||
(at.getZ() << 4) + 8)));
|
(at.getZ() << 4) + 8));
|
||||||
}
|
}
|
||||||
} catch (WrongEngineBroException | InterruptedException | ExecutionException e) {
|
} catch (WrongEngineBroException | InterruptedException | ExecutionException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -143,8 +143,8 @@ public interface EngineMantle extends IObjectPlacer {
|
|||||||
return getEngine().getDimension().isDebugSmartBore();
|
return getEngine().getDimension().isDebugSmartBore();
|
||||||
}
|
}
|
||||||
|
|
||||||
default void trim(long dur) {
|
default void trim(long dur, int limit) {
|
||||||
getMantle().trim(dur);
|
getMantle().trim(dur, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
default IrisData getData() {
|
default IrisData getData() {
|
||||||
@ -175,8 +175,11 @@ public interface EngineMantle extends IObjectPlacer {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default void trim() {
|
default void trim(int limit) {
|
||||||
getMantle().trim(TimeUnit.SECONDS.toMillis(IrisSettings.get().getPerformance().getMantleKeepAlive()));
|
getMantle().trim(TimeUnit.SECONDS.toMillis(IrisSettings.get().getPerformance().getMantleKeepAlive()), limit);
|
||||||
|
}
|
||||||
|
default int unloadTectonicPlate(){
|
||||||
|
return getMantle().unloadTectonicPlate();
|
||||||
}
|
}
|
||||||
|
|
||||||
default MultiBurst burst() {
|
default MultiBurst burst() {
|
||||||
@ -293,12 +296,15 @@ public interface EngineMantle extends IObjectPlacer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default long getToUnload(){
|
default long getToUnload(){
|
||||||
return getMantle().FakeToUnload.get();
|
return getMantle().getToUnload().size();
|
||||||
}
|
}
|
||||||
default double getTectonicLimit(){
|
default long getDynamicThreads(){
|
||||||
return getMantle().tectonicLimit.get();
|
return getMantle().getDynamicThreads().get();
|
||||||
|
}
|
||||||
|
default long getNotClearedLoadedRegions(){
|
||||||
|
return getMantle().getLoadedRegions().size() - getMantle().getToUnload().size();
|
||||||
}
|
}
|
||||||
default double getTectonicDuration(){
|
default double getTectonicDuration(){
|
||||||
return getMantle().adjustedIdleDuration.get();
|
return getMantle().getAdjustedIdleDuration().get();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -20,8 +20,12 @@ package com.volmit.iris.engine.mantle;
|
|||||||
|
|
||||||
import com.volmit.iris.util.mantle.MantleFlag;
|
import com.volmit.iris.util.mantle.MantleFlag;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(exclude = "engineMantle")
|
||||||
|
@ToString(exclude = "engineMantle")
|
||||||
public abstract class IrisMantleComponent implements MantleComponent {
|
public abstract class IrisMantleComponent implements MantleComponent {
|
||||||
private final EngineMantle engineMantle;
|
private final EngineMantle engineMantle;
|
||||||
private final MantleFlag flag;
|
private final MantleFlag flag;
|
||||||
|
@ -18,17 +18,41 @@
|
|||||||
|
|
||||||
package com.volmit.iris.engine.object;
|
package com.volmit.iris.engine.object;
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class IrisEngineStatistics {
|
public class IrisEngineStatistics {
|
||||||
private int totalHotloads = 0;
|
private int totalHotloads = 0;
|
||||||
private int chunksGenerated = 0;
|
private int chunksGenerated = 0;
|
||||||
|
private int IrisCreationVersion = 0;
|
||||||
|
private int MinecraftVersion = 0;
|
||||||
|
|
||||||
public void generatedChunk() {
|
public void generatedChunk() {
|
||||||
chunksGenerated++;
|
chunksGenerated++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setVersion(int i) {
|
||||||
|
IrisCreationVersion = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMCVersion(int i) {
|
||||||
|
MinecraftVersion = i;
|
||||||
|
}
|
||||||
|
public int getMCVersion() {
|
||||||
|
return MinecraftVersion;
|
||||||
|
}
|
||||||
|
public int getVersion() {
|
||||||
|
return MinecraftVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void hotloaded() {
|
public void hotloaded() {
|
||||||
totalHotloads++;
|
totalHotloads++;
|
||||||
}
|
}
|
||||||
|
@ -27,10 +27,14 @@ import com.volmit.iris.engine.object.IrisBiome;
|
|||||||
import com.volmit.iris.engine.object.IrisDimension;
|
import com.volmit.iris.engine.object.IrisDimension;
|
||||||
import com.volmit.iris.engine.object.IrisExpression;
|
import com.volmit.iris.engine.object.IrisExpression;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(exclude = "engine")
|
||||||
|
@ToString(exclude = "engine")
|
||||||
public class IrisScriptingAPI {
|
public class IrisScriptingAPI {
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
private IrisRegistrant preprocessorObject;
|
private IrisRegistrant preprocessorObject;
|
||||||
|
@ -1,179 +0,0 @@
|
|||||||
package com.volmit.iris.util.SFG;
|
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.core.IrisSettings;
|
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
|
||||||
import com.volmit.iris.core.service.StudioSVC;
|
|
||||||
import com.volmit.iris.engine.object.IrisDimension;
|
|
||||||
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.util.format.C;
|
|
||||||
import com.volmit.iris.util.plugin.VolmitSender;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.WorldCreator;
|
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
|
||||||
import org.bukkit.generator.ChunkGenerator;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import static com.volmit.iris.Iris.service;
|
|
||||||
|
|
||||||
public class WorldHandlerSFG {
|
|
||||||
static String WorldToLoad;
|
|
||||||
static String WorldEngine;
|
|
||||||
static String worldNameToCheck = "YourWorldName";
|
|
||||||
private static VolmitSender sender;
|
|
||||||
public static void LoadWorld(String selectedWorld){
|
|
||||||
if(Objects.equals(selectedWorld, "Benchmark")){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
worldNameToCheck = selectedWorld;
|
|
||||||
boolean worldExists = doesWorldExist(worldNameToCheck);
|
|
||||||
WorldEngine = selectedWorld;
|
|
||||||
|
|
||||||
if (!worldExists) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
WorldToLoad = selectedWorld;
|
|
||||||
File BUKKIT_YML = new File("bukkit.yml");
|
|
||||||
String pathtodim = selectedWorld + "\\iris\\pack\\dimensions\\";
|
|
||||||
File directory = new File(Bukkit.getWorldContainer(), pathtodim);
|
|
||||||
|
|
||||||
String dimension = null;
|
|
||||||
if (directory.exists() && directory.isDirectory()) {
|
|
||||||
File[] files = directory.listFiles();
|
|
||||||
if (files != null) {
|
|
||||||
for (File file : files) {
|
|
||||||
if (file.isFile()) {
|
|
||||||
String fileName = file.getName();
|
|
||||||
if (fileName.endsWith(".json")) {
|
|
||||||
dimension = fileName.substring(0, fileName.length() - 5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
YamlConfiguration yml = YamlConfiguration.loadConfiguration(BUKKIT_YML);
|
|
||||||
String gen = "Iris:" + dimension;
|
|
||||||
ConfigurationSection section = yml.contains("worlds") ? yml.getConfigurationSection("worlds") : yml.createSection("worlds");
|
|
||||||
if (!section.contains(selectedWorld)) {
|
|
||||||
section.createSection(selectedWorld).set("generator", gen);
|
|
||||||
try {
|
|
||||||
yml.save(BUKKIT_YML);
|
|
||||||
Iris.info("Registered \"" + selectedWorld + "\" in bukkit.yml");
|
|
||||||
} catch (IOException e) {
|
|
||||||
Iris.error("Failed to update bukkit.yml!");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
checkForBukkitWorlds();
|
|
||||||
}
|
|
||||||
static boolean doesWorldExist(String worldName) {
|
|
||||||
File worldContainer = Bukkit.getWorldContainer();
|
|
||||||
File worldDirectory = new File(worldContainer, worldName);
|
|
||||||
return worldDirectory.exists() && worldDirectory.isDirectory();
|
|
||||||
}
|
|
||||||
private static void checkForBukkitWorlds() {
|
|
||||||
FileConfiguration fc = new YamlConfiguration();
|
|
||||||
try {
|
|
||||||
fc.load(new File("bukkit.yml"));
|
|
||||||
ConfigurationSection section = fc.getConfigurationSection("worlds");
|
|
||||||
if (section == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> worldsToLoad = Collections.singletonList(WorldToLoad);
|
|
||||||
|
|
||||||
for (String s : section.getKeys(false)) {
|
|
||||||
if (!worldsToLoad.contains(s)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ConfigurationSection entry = section.getConfigurationSection(s);
|
|
||||||
if (!entry.contains("generator", true)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String generator = entry.getString("generator");
|
|
||||||
if (generator.startsWith("Iris:")) {
|
|
||||||
generator = generator.split("\\Q:\\E")[1];
|
|
||||||
} else if (generator.equalsIgnoreCase("Iris")) {
|
|
||||||
generator = IrisSettings.get().getGenerator().getDefaultWorldType();
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Iris.info("2 World: %s | Generator: %s", s, generator);
|
|
||||||
if (Bukkit.getWorlds().stream().anyMatch(w -> w.getName().equals(s))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "...");
|
|
||||||
new WorldCreator(s)
|
|
||||||
.generator(getDefaultWorldGenerator(s, generator))
|
|
||||||
.environment(IrisData.loadAnyDimension(generator).getEnvironment())
|
|
||||||
.createWorld();
|
|
||||||
Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!");
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static ChunkGenerator getDefaultWorldGenerator(String worldName, String id) {
|
|
||||||
Iris.debug("Default World Generator Called for " + worldName + " using ID: " + id);
|
|
||||||
if (worldName.equals("test")) {
|
|
||||||
try {
|
|
||||||
throw new RuntimeException();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
Iris.info(e.getStackTrace()[1].getClassName());
|
|
||||||
if (e.getStackTrace()[1].getClassName().contains("com.onarandombox.MultiverseCore")) {
|
|
||||||
Iris.debug("MVC Test detected, Quick! Send them the dummy!");
|
|
||||||
return new DummyChunkGenerator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IrisDimension dim;
|
|
||||||
if (id == null || id.isEmpty()) {
|
|
||||||
dim = IrisData.loadAnyDimension(IrisSettings.get().getGenerator().getDefaultWorldType());
|
|
||||||
} else {
|
|
||||||
dim = IrisData.loadAnyDimension(id);
|
|
||||||
}
|
|
||||||
Iris.debug("Generator ID: " + id + " requested by bukkit/plugin");
|
|
||||||
|
|
||||||
if (dim == null) {
|
|
||||||
Iris.warn("Unable to find dimension type " + id + " Looking for online packs...");
|
|
||||||
|
|
||||||
service(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender()), id, true);
|
|
||||||
dim = IrisData.loadAnyDimension(id);
|
|
||||||
|
|
||||||
if (dim == null) {
|
|
||||||
throw new RuntimeException("Can't find dimension " + id + "!");
|
|
||||||
} else {
|
|
||||||
Iris.info("Resolved missing dimension, proceeding with generation.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Iris.debug("Assuming IrisDimension: " + dim.getName());
|
|
||||||
IrisWorld w = IrisWorld.builder()
|
|
||||||
.name(worldName)
|
|
||||||
.seed(1337)
|
|
||||||
.environment(dim.getEnvironment())
|
|
||||||
.worldFolder(new File(Bukkit.getWorldContainer(), worldName))
|
|
||||||
.minHeight(dim.getMinHeight())
|
|
||||||
.maxHeight(dim.getMaxHeight())
|
|
||||||
.build();
|
|
||||||
Iris.debug("Generator Config: " + w.toString());
|
|
||||||
File ff = new File(w.worldFolder(), "iris/pack");
|
|
||||||
if (!ff.exists() || ff.listFiles().length == 0) {
|
|
||||||
ff.mkdirs();
|
|
||||||
service(StudioSVC.class).installIntoWorld(sender, dim.getLoadKey(), ff.getParentFile());
|
|
||||||
}
|
|
||||||
return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey());
|
|
||||||
}
|
|
||||||
}
|
|
@ -23,8 +23,10 @@ import com.volmit.iris.util.function.Consumer2;
|
|||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
public class HashPalette<T> implements Palette<T> {
|
public class HashPalette<T> implements Palette<T> {
|
||||||
|
private final ReentrantLock lock = new ReentrantLock();
|
||||||
private final LinkedHashMap<T, Integer> palette;
|
private final LinkedHashMap<T, Integer> palette;
|
||||||
private final KMap<Integer, T> lookup;
|
private final KMap<Integer, T> lookup;
|
||||||
private final AtomicInteger size;
|
private final AtomicInteger size;
|
||||||
@ -47,14 +49,18 @@ public class HashPalette<T> implements Palette<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int add(T t) {
|
public int add(T t) {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
int index = size.getAndIncrement();
|
int index = size.getAndIncrement();
|
||||||
palette.put(t, index);
|
palette.put(t, index);
|
||||||
|
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
lookup.put(index, t);
|
lookup.put(index, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -74,6 +80,8 @@ public class HashPalette<T> implements Palette<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void iterate(Consumer2<T, Integer> c) {
|
public void iterate(Consumer2<T, Integer> c) {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
for (T i : palette.keySet()) {
|
for (T i : palette.keySet()) {
|
||||||
if (i == null) {
|
if (i == null) {
|
||||||
continue;
|
continue;
|
||||||
@ -81,5 +89,8 @@ public class HashPalette<T> implements Palette<T> {
|
|||||||
|
|
||||||
c.accept(i, id(i));
|
c.accept(i, id(i));
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ import com.volmit.iris.engine.framework.Engine;
|
|||||||
import com.volmit.iris.engine.mantle.EngineMantle;
|
import com.volmit.iris.engine.mantle.EngineMantle;
|
||||||
import com.volmit.iris.engine.mantle.MantleWriter;
|
import com.volmit.iris.engine.mantle.MantleWriter;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.collection.KSet;
|
|
||||||
import com.volmit.iris.util.documentation.BlockCoordinates;
|
import com.volmit.iris.util.documentation.BlockCoordinates;
|
||||||
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||||
import com.volmit.iris.util.documentation.RegionCoordinates;
|
import com.volmit.iris.util.documentation.RegionCoordinates;
|
||||||
@ -37,25 +36,21 @@ import com.volmit.iris.util.function.Consumer4;
|
|||||||
import com.volmit.iris.util.math.M;
|
import com.volmit.iris.util.math.M;
|
||||||
import com.volmit.iris.util.matter.Matter;
|
import com.volmit.iris.util.matter.Matter;
|
||||||
import com.volmit.iris.util.matter.MatterSlice;
|
import com.volmit.iris.util.matter.MatterSlice;
|
||||||
import com.volmit.iris.util.misc.getHardware;
|
|
||||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||||
import com.volmit.iris.util.parallel.HyperLock;
|
import com.volmit.iris.util.parallel.HyperLock;
|
||||||
import com.volmit.iris.util.parallel.MultiBurst;
|
import com.volmit.iris.util.parallel.MultiBurst;
|
||||||
import com.volmit.iris.util.scheduling.Looper;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
import org.checkerframework.checker.units.qual.A;
|
|
||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The mantle can store any type of data slice anywhere and manage regions & IO on it's own.
|
* The mantle can store any type of data slice anywhere and manage regions & IO on it's own.
|
||||||
@ -64,19 +59,16 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||||||
|
|
||||||
public class Mantle {
|
public class Mantle {
|
||||||
private final File dataFolder;
|
private final File dataFolder;
|
||||||
|
@Getter
|
||||||
private final int worldHeight;
|
private final int worldHeight;
|
||||||
private final Map<Long, Long> lastUse;
|
private final Map<Long, Long> lastUse;
|
||||||
@Getter
|
@Getter
|
||||||
private final Map<Long, TectonicPlate> loadedRegions;
|
private final Map<Long, TectonicPlate> loadedRegions;
|
||||||
private final HyperLock hyperLock;
|
private final HyperLock hyperLock;
|
||||||
private final KSet<Long> unload;
|
|
||||||
private final AtomicBoolean closed;
|
private final AtomicBoolean closed;
|
||||||
private final MultiBurst ioBurst;
|
private final MultiBurst ioBurst;
|
||||||
private final AtomicBoolean io;
|
private final AtomicBoolean ioTrim;
|
||||||
private final Object gcMonitor = new Object();
|
private final AtomicBoolean ioTectonicUnload;
|
||||||
long apm = getHardware.getAvailableProcessMemory();
|
|
||||||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
|
||||||
int tectonicLimitBeforeOutMemory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new mantle
|
* Create a new mantle
|
||||||
@ -90,9 +82,9 @@ public class Mantle {
|
|||||||
this.closed = new AtomicBoolean(false);
|
this.closed = new AtomicBoolean(false);
|
||||||
this.dataFolder = dataFolder;
|
this.dataFolder = dataFolder;
|
||||||
this.worldHeight = worldHeight;
|
this.worldHeight = worldHeight;
|
||||||
this.io = new AtomicBoolean(false);
|
this.ioTrim = new AtomicBoolean(false);
|
||||||
|
this.ioTectonicUnload = new AtomicBoolean(false);
|
||||||
dataFolder.mkdirs();
|
dataFolder.mkdirs();
|
||||||
unload = new KSet<>();
|
|
||||||
loadedRegions = new KMap<>();
|
loadedRegions = new KMap<>();
|
||||||
lastUse = new KMap<>();
|
lastUse = new KMap<>();
|
||||||
ioBurst = MultiBurst.burst;
|
ioBurst = MultiBurst.burst;
|
||||||
@ -119,7 +111,7 @@ public class Mantle {
|
|||||||
* @return the file
|
* @return the file
|
||||||
*/
|
*/
|
||||||
public static File fileForRegion(File folder, Long key) {
|
public static File fileForRegion(File folder, Long key) {
|
||||||
File f = new File(folder, "p." + key + ".ttp");
|
File f = new File(folder, "p." + key + ".ttp.lz4b");
|
||||||
if (!f.getParentFile().exists()) {
|
if (!f.getParentFile().exists()) {
|
||||||
f.getParentFile().mkdirs();
|
f.getParentFile().mkdirs();
|
||||||
}
|
}
|
||||||
@ -397,87 +389,104 @@ public class Mantle {
|
|||||||
return numberOfEntries * bytesPerEntry;
|
return numberOfEntries * bytesPerEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final AtomicDouble adjustedIdleDuration = new AtomicDouble(0);
|
||||||
|
@Getter
|
||||||
|
private final AtomicInteger dynamicThreads = new AtomicInteger(1);
|
||||||
|
@Getter
|
||||||
|
private final AtomicInteger forceAggressiveThreshold = new AtomicInteger(30);
|
||||||
|
@Getter
|
||||||
|
private final AtomicLong oldestTectonicPlate = new AtomicLong(0);
|
||||||
|
private final ReentrantLock unloadLock = new ReentrantLock();
|
||||||
|
@Getter
|
||||||
|
private final Set<Long> toUnload = new HashSet<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save & unload regions that have not been used for more than the
|
* Save & unload regions that have not been used for more than the
|
||||||
* specified amount of milliseconds
|
* specified amount of milliseconds
|
||||||
*
|
*
|
||||||
* @param baseIdleDuration the duration
|
* @param baseIdleDuration the duration
|
||||||
*/
|
*/
|
||||||
|
public synchronized void trim(long baseIdleDuration, int tectonicLimit) {
|
||||||
public AtomicInteger FakeToUnload = new AtomicInteger(0);
|
|
||||||
public AtomicDouble adjustedIdleDuration = new AtomicDouble(0);
|
|
||||||
public AtomicInteger tectonicLimit = new AtomicInteger(30);
|
|
||||||
|
|
||||||
|
|
||||||
public synchronized void trim(long baseIdleDuration) {
|
|
||||||
if (closed.get()) {
|
if (closed.get()) {
|
||||||
throw new RuntimeException("The Mantle is closed");
|
throw new RuntimeException("The Mantle is closed");
|
||||||
}
|
}
|
||||||
|
Iris.debug(C.BLUE + "TECTONIC TRIM HAS RUN");
|
||||||
if (IrisSettings.get().getPerformance().dynamicPerformanceMode){
|
|
||||||
tectonicLimit.set(2);
|
|
||||||
long t = getHardware.getProcessMemory();
|
|
||||||
for (; t > 250;){
|
|
||||||
tectonicLimit.getAndAdd(1);
|
|
||||||
t = t - 250;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
adjustedIdleDuration.set(baseIdleDuration);
|
adjustedIdleDuration.set(baseIdleDuration);
|
||||||
|
|
||||||
if (loadedRegions.size() > tectonicLimit.get()) {
|
if (loadedRegions != null) {
|
||||||
|
if (loadedRegions.size() > tectonicLimit) {
|
||||||
// todo update this correctly and maybe do something when its above a 100%
|
// todo update this correctly and maybe do something when its above a 100%
|
||||||
if (IrisSettings.get().getPerformance().dynamicPerformanceMode) {
|
adjustedIdleDuration.set(Math.max(adjustedIdleDuration.get() - (1000 * (((loadedRegions.size() - tectonicLimit) / (double) tectonicLimit) * 100) * 0.4), 4000));
|
||||||
int tectonicLimitValue = tectonicLimit.get();
|
|
||||||
adjustedIdleDuration.set(Math.max(adjustedIdleDuration.get() - (1000 * (((loadedRegions.size() - tectonicLimitValue) / (double) tectonicLimitValue) * 100) * 0.4), 4000));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
io.set(true);
|
ioTrim.set(true);
|
||||||
|
unloadLock.lock();
|
||||||
try {
|
try {
|
||||||
Iris.debug("Trimming Tectonic Plates older than " + Form.duration(adjustedIdleDuration.get(), 0));
|
Iris.debug("Trimming Tectonic Plates older than " + Form.duration(adjustedIdleDuration.get(), 0));
|
||||||
Set<Long> toUnload = new HashSet<>();
|
if (lastUse != null) {
|
||||||
|
for (Long i : new ArrayList<>(lastUse.keySet())) {
|
||||||
for (Long i : lastUse.keySet()) {
|
|
||||||
double finalAdjustedIdleDuration = adjustedIdleDuration.get();
|
double finalAdjustedIdleDuration = adjustedIdleDuration.get();
|
||||||
hyperLock.withLong(i, () -> {
|
hyperLock.withLong(i, () -> {
|
||||||
if (M.ms() - lastUse.get(i) >= finalAdjustedIdleDuration) {
|
Long lastUseTime = lastUse.get(i);
|
||||||
|
if (lastUseTime != null && M.ms() - lastUseTime >= finalAdjustedIdleDuration) {
|
||||||
toUnload.add(i);
|
toUnload.add(i);
|
||||||
FakeToUnload.addAndGet(1);
|
|
||||||
Iris.debug("Tectonic Region added to unload");
|
Iris.debug("Tectonic Region added to unload");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BurstExecutor burstExecutor = new BurstExecutor(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()), toUnload.size());
|
} finally {
|
||||||
|
ioTrim.set(false);
|
||||||
|
unloadLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (Long i : toUnload) {
|
public int unloadTectonicPlate() {
|
||||||
burstExecutor.queue(() -> {
|
AtomicInteger i = new AtomicInteger();
|
||||||
hyperLock.withLong(i, () -> {
|
unloadLock.lock();
|
||||||
TectonicPlate m = loadedRegions.get(i);
|
try {
|
||||||
|
List<Future<?>> futures = new ArrayList<>();
|
||||||
|
ExecutorService service = Executors.newFixedThreadPool(dynamicThreads.get());
|
||||||
|
for (long id : new ArrayList<>(toUnload)) {
|
||||||
|
futures.add(service.submit(() ->
|
||||||
|
hyperLock.withLong(id, () -> {
|
||||||
|
TectonicPlate m = loadedRegions.get(id);
|
||||||
if (m != null) {
|
if (m != null) {
|
||||||
try {
|
try {
|
||||||
m.write(fileForRegion(dataFolder, i));
|
m.write(fileForRegion(dataFolder, id));
|
||||||
loadedRegions.remove(i);
|
loadedRegions.remove(id);
|
||||||
lastUse.remove(i);
|
lastUse.remove(id);
|
||||||
Iris.debug("Unloaded Tectonic Plate " + C.DARK_GREEN + Cache.keyX(i) + " " + Cache.keyZ(i));
|
toUnload.remove(id);
|
||||||
FakeToUnload.addAndGet(-1);
|
i.incrementAndGet();
|
||||||
|
Iris.info("Unloaded Tectonic Plate " + C.DARK_GREEN + Cache.keyX(id) + " " + Cache.keyZ(id));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
burstExecutor.complete();
|
try {
|
||||||
|
while (!futures.isEmpty()) {
|
||||||
|
futures.remove(0).get();
|
||||||
|
futures.removeIf(Future::isDone);
|
||||||
|
}
|
||||||
|
service.shutdown();
|
||||||
|
} catch (InterruptedException ignored) {}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
} finally {
|
} finally {
|
||||||
io.set(false);
|
unloadLock.unlock();
|
||||||
|
ioTectonicUnload.set(true);
|
||||||
}
|
}
|
||||||
|
return i.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This retreives a future of the Tectonic Plate at the given coordinates.
|
* This retreives a future of the Tectonic Plate at the given coordinates.
|
||||||
* All methods accessing tectonic plates should go through this method
|
* All methods accessing tectonic plates should go through this method
|
||||||
@ -488,7 +497,7 @@ public class Mantle {
|
|||||||
*/
|
*/
|
||||||
@RegionCoordinates
|
@RegionCoordinates
|
||||||
private TectonicPlate get(int x, int z) {
|
private TectonicPlate get(int x, int z) {
|
||||||
if (io.get()) {
|
if (ioTrim.get()) {
|
||||||
try {
|
try {
|
||||||
return getSafe(x, z).get();
|
return getSafe(x, z).get();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@ -545,6 +554,8 @@ public class Mantle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
File file = fileForRegion(dataFolder, x, z);
|
File file = fileForRegion(dataFolder, x, z);
|
||||||
|
if (!file.exists())
|
||||||
|
file = new File(dataFolder, file.getName().substring(".lz4b".length()));
|
||||||
|
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
try {
|
try {
|
||||||
@ -583,10 +594,6 @@ public class Mantle {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getWorldHeight() {
|
|
||||||
return worldHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MantleChunk getChunk(Chunk e) {
|
public MantleChunk getChunk(Chunk e) {
|
||||||
return getChunk(e.getX(), e.getZ());
|
return getChunk(e.getX(), e.getZ());
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,10 @@ import com.volmit.iris.util.format.C;
|
|||||||
import com.volmit.iris.util.format.Form;
|
import com.volmit.iris.util.format.Form;
|
||||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||||
|
import net.jpountz.lz4.LZ4BlockOutputStream;
|
||||||
|
import net.jpountz.lz4.LZ4FrameInputStream;
|
||||||
|
import net.jpountz.lz4.LZ4FrameOutputStream;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||||
@ -79,8 +83,14 @@ public class TectonicPlate {
|
|||||||
|
|
||||||
public static TectonicPlate read(int worldHeight, File file) throws IOException, ClassNotFoundException {
|
public static TectonicPlate read(int worldHeight, File file) throws IOException, ClassNotFoundException {
|
||||||
FileInputStream fin = new FileInputStream(file);
|
FileInputStream fin = new FileInputStream(file);
|
||||||
|
DataInputStream din;
|
||||||
|
if (file.getName().endsWith("ttp.lz4")) {
|
||||||
GZIPInputStream gzi = new GZIPInputStream(fin);
|
GZIPInputStream gzi = new GZIPInputStream(fin);
|
||||||
DataInputStream din = new DataInputStream(gzi);
|
din = new DataInputStream(gzi);
|
||||||
|
} else {
|
||||||
|
LZ4BlockInputStream lz4 = new LZ4BlockInputStream(fin);
|
||||||
|
din = new DataInputStream(lz4);
|
||||||
|
}
|
||||||
TectonicPlate p = new TectonicPlate(worldHeight, din);
|
TectonicPlate p = new TectonicPlate(worldHeight, din);
|
||||||
din.close();
|
din.close();
|
||||||
|
|
||||||
@ -164,11 +174,17 @@ public class TectonicPlate {
|
|||||||
public void write(File file) throws IOException {
|
public void write(File file) throws IOException {
|
||||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||||
FileOutputStream fos = new FileOutputStream(file);
|
FileOutputStream fos = new FileOutputStream(file);
|
||||||
|
DataOutputStream dos;
|
||||||
|
if (file.getName().endsWith("ttp")) {
|
||||||
GZIPOutputStream gzo = new GZIPOutputStream(fos);
|
GZIPOutputStream gzo = new GZIPOutputStream(fos);
|
||||||
DataOutputStream dos = new DataOutputStream(gzo);
|
dos = new DataOutputStream(gzo);
|
||||||
|
} else {
|
||||||
|
LZ4BlockOutputStream lz4 = new LZ4BlockOutputStream(fos);
|
||||||
|
dos = new DataOutputStream(lz4);
|
||||||
|
}
|
||||||
write(dos);
|
write(dos);
|
||||||
dos.close();
|
dos.close();
|
||||||
Iris.debug("Saved Tectonic Plate " + C.DARK_GREEN + file.getName().split("\\Q.\\E")[0] + C.RED + " in " + Form.duration(p.getMilliseconds(), 2));
|
Iris.info("Saved Tectonic Plate " + C.DARK_GREEN + file.getName().split("\\Q.\\E")[0] + C.RED + " in " + Form.duration(p.getMilliseconds(), 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,11 +13,6 @@ public class getHardware {
|
|||||||
OperatingSystem os = systemInfo.getOperatingSystem();
|
OperatingSystem os = systemInfo.getOperatingSystem();
|
||||||
return os.toString();
|
return os.toString();
|
||||||
}
|
}
|
||||||
public static int getCPUThreads(){
|
|
||||||
SystemInfo systemInfo = new SystemInfo();
|
|
||||||
CentralProcessor processor = systemInfo.getHardware().getProcessor();
|
|
||||||
return processor.getLogicalProcessorCount();
|
|
||||||
}
|
|
||||||
public static long getProcessMemory(){
|
public static long getProcessMemory(){
|
||||||
long maxMemory = Runtime.getRuntime().maxMemory() / (1024 * 1024);
|
long maxMemory = Runtime.getRuntime().maxMemory() / (1024 * 1024);
|
||||||
return maxMemory;
|
return maxMemory;
|
||||||
|
@ -18,6 +18,7 @@ libraries:
|
|||||||
- org.ow2.asm:asm:9.2
|
- org.ow2.asm:asm:9.2
|
||||||
- rhino:js:1.7R2
|
- rhino:js:1.7R2
|
||||||
- bsf:bsf:2.4.0
|
- bsf:bsf:2.4.0
|
||||||
|
- org.lz4:lz4-java:1.8.0
|
||||||
commands:
|
commands:
|
||||||
iris:
|
iris:
|
||||||
aliases: [ ir, irs ]
|
aliases: [ ir, irs ]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user