Merge branch 'Pixeldev' into origin

This commit is contained in:
Julian Krings 2023-12-23 20:53:18 +01:00 committed by GitHub
commit 3ae896457b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 1300 additions and 847 deletions

View File

@ -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'

View File

@ -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");
} }

View File

@ -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;

View File

@ -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);
});
}
} }

View File

@ -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);
} }
} }

View File

@ -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)

View File

@ -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.");
}
}
}

View File

@ -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() {

View File

@ -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());

View File

@ -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;

View File

@ -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) {

View File

@ -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;
} }
} }

View File

@ -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();

View File

@ -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("");
}
}
}

View File

@ -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() {

View File

@ -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());
}
}

View File

@ -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("");
}
} }
} }

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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() {
}
}

View File

@ -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;}
}); });

View File

@ -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)

View File

@ -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;

View File

@ -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;
}
}
} }

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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();
} }
} }

View File

@ -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;

View File

@ -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++;
} }

View File

@ -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;

View File

@ -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());
}
}

View File

@ -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();
}
} }
} }

View File

@ -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());
} }

View File

@ -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));
} }
/** /**

View File

@ -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;

View File

@ -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 ]