9
0
mirror of https://github.com/VolmitSoftware/Iris.git synced 2026-01-06 15:51:30 +00:00

restructure safeguard

This commit is contained in:
Julian Krings
2025-09-29 15:45:56 +02:00
parent 9d796bd2a0
commit 526efd3ae1
16 changed files with 484 additions and 565 deletions

View File

@@ -62,7 +62,7 @@ val serverMinHeap = "2G"
val serverMaxHeap = "8G"
//Valid values are: none, truecolor, indexed256, indexed16, indexed8
val color = "truecolor"
val errorReporting = findProperty("errorReporting") as Boolean? ?: false
val errorReporting = "true" == findProperty("errorReporting")
val nmsBindings = mapOf(
"v1_21_R5" to "1.21.8-R0.1-SNAPSHOT",
@@ -76,7 +76,7 @@ val nmsBindings = mapOf(
"v1_20_R1" to "1.20.1-R0.1-SNAPSHOT",
)
val jvmVersion = mapOf<String, Int>()
nmsBindings.forEach { key, value ->
nmsBindings.forEach { (key, value) ->
project(":nms:$key") {
apply<JavaPlugin>()
apply<NMSToolsPlugin>()
@@ -112,7 +112,7 @@ nmsBindings.forEach { key, value ->
tasks {
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
nmsBindings.forEach { key, _ ->
nmsBindings.forEach { (key, _) ->
from(project(":nms:$key").tasks.named("remap").map { zipTree(it.outputs.files.singleFile) })
}
from(project(":core").tasks.shadowJar.flatMap { it.archiveFile }.map { zipTree(it) })

View File

@@ -184,10 +184,10 @@ val generateTemplates = tasks.register<Copy>("generateTemplates") {
"commit" to provider {
val res = runCatching { project.extensions.getByType<Grgit>().head().id }
res.getOrDefault("")
.takeIf { it.length == 40 } ?: {
logger.error("Git commit hash not found", res.exceptionOrNull())
.takeIf { it.length == 40 } ?: run {
this.logger.error("Git commit hash not found", res.exceptionOrNull())
"unknown"
}()
}
},
)

View File

@@ -28,7 +28,6 @@ import com.volmit.iris.core.link.IrisPapiExpansion;
import com.volmit.iris.core.link.MultiverseCoreLink;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import com.volmit.iris.core.pregenerator.LazyPregenerator;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.core.tools.IrisToolbelt;
@@ -43,7 +42,6 @@ import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.exceptions.IrisException;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.function.NastyRunnable;
import com.volmit.iris.util.io.FileWatcher;
import com.volmit.iris.util.io.IO;
@@ -53,7 +51,6 @@ import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.misc.Bindings;
import com.volmit.iris.util.misc.SlimJar;
import com.volmit.iris.util.misc.getHardware;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.IrisService;
import com.volmit.iris.util.plugin.VolmitPlugin;
@@ -83,9 +80,6 @@ import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.volmit.iris.core.safeguard.IrisSafeguard.*;
import static com.volmit.iris.core.safeguard.ServerBootSFG.passedserversoftware;
@SuppressWarnings("CanBeFinal")
public class Iris extends VolmitPlugin implements Listener {
private static final Queue<Runnable> syncJobs = new ShurikenQueue<>();
@@ -306,9 +300,6 @@ public class Iris extends VolmitPlugin implements Listener {
public static void info(String format, Object... args) {
msg(C.WHITE + String.format(format, args));
}
public static void safeguard(String format, Object... args) {
msg(C.RESET + String.format(format, args));
}
@SuppressWarnings("deprecation")
public static void later(NastyRunnable object) {
@@ -447,16 +438,15 @@ public class Iris extends VolmitPlugin implements Listener {
IO.delete(new File("iris"));
compat = IrisCompat.configured(getDataFile("compat.json"));
ServerConfigurator.configure();
IrisSafeguard.IrisSafeguardSystem();
IrisSafeguard.execute();
getSender().setTag(getTag());
IrisSafeguard.splash(true);
IrisSafeguard.splash();
linkMultiverseCore = new MultiverseCoreLink();
configWatcher = new FileWatcher(getDataFile("settings.json"));
services.values().forEach(IrisService::onEnable);
services.values().forEach(this::registerListener);
addShutdownHook();
J.s(() -> {
J.a(IrisSafeguard::suggestPaper);
J.a(() -> IO.delete(getTemp()));
J.a(LazyPregenerator::loadLazyGenerators, 100);
J.a(this::bstats);
@@ -464,7 +454,6 @@ public class Iris extends VolmitPlugin implements Listener {
J.sr(this::tickQueue, 0);
J.s(this::setupPapi);
J.a(ServerConfigurator::configure, 20);
IrisSafeguard.splash(false);
autoStartStudio();
checkForBukkitWorlds(s -> true);
@@ -557,10 +546,10 @@ public class Iris extends VolmitPlugin implements Listener {
enable();
super.onEnable();
Bukkit.getPluginManager().registerEvents(this, this);
setupChecks();
}
public void onDisable() {
if (IrisSafeguard.isForceShutdown()) return;
services.values().forEach(IrisService::onDisable);
Bukkit.getScheduler().cancelTasks(this);
HandlerList.unregisterAll((Plugin) this);
@@ -588,49 +577,7 @@ public class Iris extends VolmitPlugin implements Listener {
@Override
public String getTag(String subTag) {
if (unstablemode) {
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.RED + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
}
if (warningmode) {
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() {
boolean passed = true;
Iris.info("Version Information: " + instance.getServer().getVersion() + " | " + instance.getServer().getBukkitVersion());
if (INMS.get() instanceof NMSBinding1X) {
passed = false;
Iris.warn("============================================");
Iris.warn("=");
Iris.warn("=");
Iris.warn("=");
Iris.warn("Iris is not compatible with this version of Minecraft.");
Iris.warn("=");
Iris.warn("=");
Iris.warn("=");
Iris.warn("============================================");
}
try {
Class.forName("io.papermc.paper.configuration.PaperConfigurations");
} catch (ClassNotFoundException e) {
Iris.info(C.RED + "Iris requires paper or above to function properly..");
return false;
}
try {
Class.forName("org.purpurmc.purpur.PurpurConfig");
} catch (ClassNotFoundException e) {
Iris.info("We recommend using Purpur for the best experience with Iris.");
Iris.info("Purpur is a fork of Paper that is optimized for performance and stability.");
Iris.info("Plugins that work on Spigot / Paper work on Purpur.");
Iris.info("You can download it here: https://purpurmc.org");
return false;
}
return passed;
return IrisSafeguard.mode().tag(subTag);
}
private void checkConfigHotload() {
@@ -738,88 +685,11 @@ public class Iris extends VolmitPlugin implements Listener {
}
public void splash() {
if (!IrisSettings.get().getGeneral().isSplashLogoStartup()) {
return;
}
String padd = Form.repeat(" ", 8);
String padd2 = Form.repeat(" ", 4);
String[] info = {"", "", "", "", "", padd2 + C.IRIS + " Iris", padd2 + C.GRAY + " by " + "<rainbow>Volmit Software", padd2 + C.GRAY + " v" + C.IRIS + getDescription().getVersion()};
if (unstablemode) {
info = new String[]{"", "", "", "", "", padd2 + C.RED + " Iris", padd2 + C.GRAY + " by " + C.DARK_RED + "Volmit Software", padd2 + C.GRAY + " v" + C.RED + getDescription().getVersion()};
}
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 = {
padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@",
padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.IRIS + " .(((()))). ",
padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.IRIS + " .((((((())))))). ",
padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.IRIS + " ((((((((())))))))) " + C.GRAY + " @",
padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.IRIS + " ((((((((-))))))))) " + C.GRAY + " @@",
padd + C.GRAY + "@@@&&" + C.IRIS + " ((((((({ })))))))) " + C.GRAY + " &&@@@",
padd + C.GRAY + "@@" + C.IRIS + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@",
padd + C.GRAY + "@" + C.IRIS + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@",
padd + C.GRAY + "" + C.IRIS + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@",
padd + C.GRAY + "" + C.IRIS + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@",
padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@"
};
String[] splashunstable = {
padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@",
padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.RED + " .(((()))). ",
padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.RED + " .((((((())))))). ",
padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.RED + " ((((((((())))))))) " + C.GRAY + " @",
padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.RED + " ((((((((-))))))))) " + C.GRAY + " @@",
padd + C.GRAY + "@@@&&" + C.RED + " ((((((({ })))))))) " + C.GRAY + " &&@@@",
padd + C.GRAY + "@@" + C.RED + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@",
padd + C.GRAY + "@" + C.RED + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@",
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 + "@@@@@@@@@@@@@@"
};
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;
}
if (!passedserversoftware) {
Iris.info("Server type & version: " + C.RED + Bukkit.getVersion());
} else { Iris.info("Server type & version: " + Bukkit.getVersion()); }
Iris.info("Java: " + getJava());
if (getHardware.getProcessMemory() < 5999) {
Iris.warn("6GB+ Ram is recommended");
Iris.warn("Process Memory: " + getHardware.getProcessMemory() + " MB");
}
Iris.info("Bukkit distro: " + Bukkit.getName());
Iris.info("Server type & version: " + Bukkit.getName() + " v" + Bukkit.getVersion());
Iris.info("Custom Biomes: " + INMS.get().countCustomBiomes());
setupChecks();
printPacks();
for (int i = 0; i < info.length; i++) {
splash[i] += info[i];
}
Iris.info("\n\n " + new KList<>(splash).toString("\n") + "\n");
IrisSafeguard.mode().trySplash();
}
private void printPacks() {

View File

@@ -1,64 +0,0 @@
package com.volmit.iris.core.safeguard;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import io.papermc.lib.PaperLib;
import java.util.concurrent.atomic.AtomicBoolean;
public class IrisSafeguard {
private static final AtomicBoolean sfg = new AtomicBoolean(false);
public static boolean unstablemode = false;
public static boolean warningmode = false;
public static boolean stablemode = false;
public static void IrisSafeguardSystem() {
Iris.info("Enabled Iris SafeGuard");
ServerBootSFG.BootCheck();
}
public static void splash(boolean early) {
if (early && (ServerBootSFG.safeguardPassed || IrisSettings.get().getGeneral().DoomsdayAnnihilationSelfDestructMode))
return;
if (!sfg.getAndSet(true)) {
Iris.instance.splash();
UtilsSFG.splash();
}
}
public static String mode() {
if (unstablemode) {
return "unstable";
} else if (warningmode) {
return "warning";
} else {
return "stable";
}
}
public static void suggestPaper() {
PaperLib.suggestPaper(Iris.instance);
}
public static KMap<String, Object> asContext() {
KMap<String, Object> m = new KMap<>();
m.put("diskSpace", !ServerBootSFG.hasEnoughDiskSpace);
m.put("javaVersion", !ServerBootSFG.isCorrectJDK);
m.put("jre", ServerBootSFG.isJRE);
m.put("missingAgent", ServerBootSFG.missingAgent);
m.put("missingDimensionTypes", ServerBootSFG.missingDimensionTypes);
m.put("failedInjection", ServerBootSFG.failedInjection);
m.put("unsupportedVersion", ServerBootSFG.unsuportedversion);
m.put("serverSoftware", !ServerBootSFG.passedserversoftware);
KList<String> incompatiblePlugins = new KList<>();
ServerBootSFG.incompatibilities.forEach((plugin, present) -> {
if (present) incompatiblePlugins.add(plugin);
});
m.put("plugins", incompatiblePlugins);
return m;
}
}

View File

@@ -1,80 +0,0 @@
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().DoomsdayAnnihilationSelfDestructMode) {
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 DoomsdayAnnihilationSelfDestructMode to true if you wish to proceed.");
while (true) {
try {
Thread.sleep(Long.MAX_VALUE);
} 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 + "CAUSE: " + C.YELLOW + UtilsSFG.MSGIncompatibleWarnings());
Iris.info("");
}
}
}

View File

@@ -1,8 +0,0 @@
package com.volmit.iris.core.safeguard;
public class PerformanceSFG {
public static void calculatePerformance() {
}
}

View File

@@ -1,194 +0,0 @@
package com.volmit.iris.core.safeguard;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisWorlds;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.agent.Agent;
import com.volmit.iris.util.collection.KSet;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.stream.Collectors;
import static com.volmit.iris.Iris.getJavaVersion;
import static com.volmit.iris.core.safeguard.IrisSafeguard.*;
public class ServerBootSFG {
public static final Map<String, Boolean> incompatibilities = new HashMap<>();
public static boolean isCorrectJDK = true;
public static boolean hasEnoughDiskSpace = true;
public static boolean isJRE = false;
public static boolean hasPrivileges = true;
public static boolean unsuportedversion = false;
public static boolean missingDimensionTypes = false;
public static boolean missingAgent = false;
public static boolean failedInjection = false;
protected static boolean safeguardPassed;
public static boolean passedserversoftware = true;
protected static int count;
protected static byte severityLow;
protected static byte severityMedium;
protected static byte severityHigh;
public static String allIncompatibilities;
public static void BootCheck() {
Iris.info("Checking for possible conflicts..");
PluginManager pluginManager = Bukkit.getPluginManager();
Plugin[] plugins = pluginManager.getPlugins();
incompatibilities.clear();
incompatibilities.put("dynmap", false);
incompatibilities.put("Stratos", false);
String pluginName;
for (Plugin plugin : plugins) {
pluginName = plugin.getName();
Boolean flag = incompatibilities.get(pluginName);
if (flag != null && !flag) {
severityHigh++;
incompatibilities.put(pluginName, true);
}
}
StringJoiner joiner = new StringJoiner(", ");
for (Map.Entry<String, Boolean> entry : incompatibilities.entrySet()) {
if (entry.getValue()) {
joiner.add(entry.getKey());
}
}
// Legacy ServerInfo
String distro = Bukkit.getName().toLowerCase();
if (
!distro.contains("purpur") &&
!distro.contains("paper") &&
!distro.contains("spigot") &&
!distro.contains("pufferfish") &&
!distro.contains("bukkit")) {
passedserversoftware = false;
joiner.add("Server Software");
severityMedium++;
}
if (INMS.get() instanceof NMSBinding1X) {
unsuportedversion = true;
joiner.add("Unsupported Minecraft Version");
severityHigh++;
}
if (!List.of(21).contains(getJavaVersion())) {
isCorrectJDK = false;
joiner.add("Unsupported Java version");
severityMedium++;
}
if (!isJDK()) {
isJRE = true;
joiner.add("Unsupported JDK");
severityMedium++;
}
// if (!hasPrivileges()){
// hasPrivileges = false;
// joiner.add("Insufficient Privileges");
// severityMedium++;
// } Some servers dont like this
if (!enoughDiskSpace()){
hasEnoughDiskSpace = false;
joiner.add("Insufficient Disk Space");
severityMedium++;
}
if (!Agent.install()) {
missingAgent = true;
joiner.add("Missing Java Agent");
severityHigh++;
} else {
if (missingDimensionTypes()) {
missingDimensionTypes = true;
joiner.add("Missing Dimension Types");
severityHigh++;
}
if (!INMS.get().injectBukkit()) {
failedInjection = true;
joiner.add("Failed Bukkit Injection");
severityHigh++;
}
}
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 (severityMedium >= 1 && severityHigh == 0) {
warningmode = true;
Iris.safeguard("Warning mode has been activated.");
}
if (severityHigh >= 1) {
unstablemode = true;
Iris.safeguard("Unstable mode has been activated.");
}
}
}
public static boolean isJDK() {
try {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// If the compiler is null, it means this is a JRE environment, not a JDK.
return compiler != null;
} catch (Exception ignored) {}
return false;
}
public static boolean hasPrivileges() {
Path pv = Paths.get(Bukkit.getWorldContainer() + "iristest.json");
try (FileChannel fc = FileChannel.open(pv, StandardOpenOption.CREATE, StandardOpenOption.DELETE_ON_CLOSE, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
if (Files.isReadable(pv) && Files.isWritable(pv)) {
return true;
}
} catch (Exception e) {
return false;
}
return false;
}
public static boolean enoughDiskSpace() {
File freeSpace = Bukkit.getWorldContainer();
double gigabytes = freeSpace.getFreeSpace() / (1024.0 * 1024.0 * 1024.0);
return gigabytes > 3;
}
private static boolean checkJavac(String path) {
return !path.isEmpty() && (new File(path, "javac").exists() || new File(path, "javac.exe").exists());
}
private static boolean missingDimensionTypes() {
return INMS.get().missingDimensionTypes(getDimensionTypes().toArray(String[]::new));
}
private static KSet<String> getDimensionTypes() {
return IrisWorlds.get()
.getDimensions()
.map(IrisDimension::getDimensionTypeKey)
.collect(Collectors.toCollection(KSet::new));
}
}

View File

@@ -1,76 +0,0 @@
package com.volmit.iris.core.safeguard;
import com.volmit.iris.Iris;
import com.volmit.iris.util.agent.Agent;
import com.volmit.iris.util.format.C;
public class UtilsSFG {
public static void splash() {
ModesSFG.selectMode();
}
public static void printIncompatibleWarnings() {
String[] parts = Iris.instance.getDescription().getVersion().split("-");
String minVersion = parts[1];
String maxVersion = parts[2];
if (ServerBootSFG.safeguardPassed) {
Iris.safeguard(C.BLUE + "0 Conflicts found");
} else {
if (IrisSafeguard.unstablemode) {
Iris.safeguard(C.DARK_RED + "" + ServerBootSFG.count + " Conflicts found");
}
if (IrisSafeguard.warningmode) {
Iris.safeguard(C.YELLOW + "" + ServerBootSFG.count + " Conflicts found");
}
if (ServerBootSFG.incompatibilities.get("dynmap")) {
Iris.safeguard(C.RED + "Dynmap");
Iris.safeguard(C.RED + "- The plugin Dynmap is not compatible with the server.");
Iris.safeguard(C.RED + "- If you want to have a map plugin like Dynmap, consider Bluemap.");
}
if (ServerBootSFG.incompatibilities.get("Stratos")) {
Iris.safeguard(C.YELLOW + "Stratos");
Iris.safeguard(C.YELLOW + "- Iris is not compatible with other worldgen plugins.");
}
if (ServerBootSFG.unsuportedversion) {
Iris.safeguard(C.RED + "Server Version");
Iris.safeguard(C.RED + "- Iris only supports " + minVersion + " > " + maxVersion);
}
if (ServerBootSFG.missingDimensionTypes) {
Iris.safeguard(C.RED + "Dimension Types");
Iris.safeguard(C.RED + "- Required Iris dimension types were not loaded.");
Iris.safeguard(C.RED + "- If this still happens after a restart please contact support.");
}
if (ServerBootSFG.missingAgent) {
Iris.safeguard(C.RED + "Java Agent");
Iris.safeguard(C.RED + "- Please enable dynamic agent loading by adding -XX:+EnableDynamicAgentLoading to your jvm arguments.");
Iris.safeguard(C.RED + "- or add the jvm argument -javaagent:" + Agent.AGENT_JAR.getPath());
}
if (!ServerBootSFG.passedserversoftware) {
Iris.safeguard(C.YELLOW + "Unsupported Server Software");
Iris.safeguard(C.YELLOW + "- Please consider using Paper or Purpur instead.");
}
if (!ServerBootSFG.hasPrivileges) {
Iris.safeguard(C.YELLOW + "Insufficient Privileges");
Iris.safeguard(C.YELLOW + "- The server has insufficient Privileges to run iris. Please contact support.");
}
if (!ServerBootSFG.hasEnoughDiskSpace) {
Iris.safeguard(C.YELLOW + "Insufficient Disk Space");
Iris.safeguard(C.YELLOW + "- The server has insufficient Free DiskSpace to run iris required 3GB+.");
}
if (!ServerBootSFG.isCorrectJDK) {
Iris.safeguard(C.YELLOW + "Unsupported java version");
Iris.safeguard(C.YELLOW + "- Please consider using JDK 21 Instead of JDK " + Iris.getJavaVersion());
}
if (ServerBootSFG.isJRE) {
Iris.safeguard(C.YELLOW + "Unsupported Server JDK");
Iris.safeguard(C.YELLOW + "- Please consider using JDK 21 Instead of JRE " + Iris.getJavaVersion());
}
}
}
public static String MSGIncompatibleWarnings() {
return ServerBootSFG.allIncompatibilities;
}
}

View File

@@ -20,6 +20,7 @@ package com.volmit.iris.util.format;
import com.volmit.iris.Iris;
import com.volmit.iris.util.plugin.VolmitSender;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import org.apache.commons.lang.Validate;
@@ -495,6 +496,14 @@ public enum C {
return STRIP_COLOR_PATTERN.matcher(input).replaceAll("");
}
public static String strip(final String input) {
if (input == null) {
return null;
}
return MiniMessage.miniMessage().stripTags(stripColor(input));
}
/**
* DyeColor to ChatColor
*

View File

@@ -56,7 +56,7 @@ public class Bindings {
options.setEnvironment(BuildConstants.ENVIRONMENT);
options.setBeforeSend((event, hint) -> {
if (suppress(event.getThrowable())) return null;
event.setTag("iris.safeguard", IrisSafeguard.mode());
event.setTag("iris.safeguard", IrisSafeguard.mode().getId());
event.setTag("iris.nms", INMS.get().getClass().getCanonicalName());
var context = IrisContext.get();
if (context != null) event.getContexts().set("engine", context.asContext());
@@ -67,6 +67,7 @@ public class Bindings {
Sentry.configureScope(scope -> {
if (settings.includeServerId) scope.setUser(ServerID.asUser());
scope.addAttachment(Attachments.PLUGINS);
scope.addAttachment(Attachments.SAFEGUARD);
scope.setTag("server", Bukkit.getVersion());
scope.setTag("server.type", Bukkit.getName());
scope.setTag("server.api", Bukkit.getBukkitVersion());

View File

@@ -2,6 +2,7 @@ package com.volmit.iris.util.sentry;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.volmit.iris.core.safeguard.IrisSafeguard;
import com.volmit.iris.util.collection.KMap;
import io.sentry.Attachment;
import org.bukkit.Bukkit;
@@ -12,6 +13,7 @@ import java.util.concurrent.Callable;
public class Attachments {
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();
public static final Attachment PLUGINS = jsonProvider(Attachments::plugins, "plugins.json");
public static final Attachment SAFEGUARD = jsonProvider(IrisSafeguard::asAttachment, "safeguard.json");
public static Attachment json(Object object, String name) {
return new Attachment(GSON.toJson(object).getBytes(StandardCharsets.UTF_8), name, "application/json", "event.attachment", true);

View File

@@ -0,0 +1,143 @@
package com.volmit.iris.core.safeguard
import com.volmit.iris.Iris
import com.volmit.iris.core.IrisSettings
import com.volmit.iris.core.safeguard.task.Diagnostic
import com.volmit.iris.core.safeguard.task.Task
import com.volmit.iris.core.safeguard.task.ValueWithDiagnostics
import com.volmit.iris.core.safeguard.task.tasks
import com.volmit.iris.util.format.C
import com.volmit.iris.util.scheduling.J
import org.bukkit.Bukkit
import java.util.*
object IrisSafeguard {
@Volatile
private var forceShutdown = false
private var results: Map<Task, ValueWithDiagnostics<Mode>> = emptyMap()
private var context: Map<String, String> = emptyMap()
private var attachment: Map<String, List<String>> = emptyMap()
private var mode = Mode.STABLE
private var count = 0
@JvmStatic
fun execute() {
val results = LinkedHashMap<Task, ValueWithDiagnostics<Mode>>(tasks.size)
val context = LinkedHashMap<String, String>(tasks.size)
val attachment = LinkedHashMap<String, List<String>>(tasks.size)
var mode = Mode.STABLE
var count = 0
for (task in tasks) {
var result: ValueWithDiagnostics<Mode>
try {
result = task.run()
} catch (e: Throwable) {
Iris.reportError(e)
result = ValueWithDiagnostics(
Mode.WARNING,
Diagnostic(Diagnostic.Logger.ERROR, "Error while running task ${task.id}", e)
)
}
mode = mode.highest(result.value)
results[task] = result
context[task.id] = result.value.id
attachment[task.id] = result.diagnostics.flatMap { it.toString().split('\n') }
if (result.value != Mode.STABLE) count++
}
this.results = Collections.unmodifiableMap(results)
this.context = Collections.unmodifiableMap(context)
this.attachment = Collections.unmodifiableMap(attachment)
this.mode = mode
this.count = count
}
@JvmStatic
fun mode() = mode
@JvmStatic
fun asContext() = context
@JvmStatic
fun asAttachment() = attachment
@JvmStatic
fun splash() {
Iris.instance.splash()
printReports()
printFooter()
}
@JvmStatic
fun printReports() {
when (mode) {
Mode.STABLE -> Iris.info(C.BLUE.toString() + "0 Conflicts found")
Mode.WARNING -> Iris.warn(C.GOLD.toString() + "%s Issues found", count)
Mode.UNSTABLE -> Iris.error(C.DARK_RED.toString() + "%s Issues found", count)
}
results.values.forEach { it.log(withStackTrace = true) }
}
@JvmStatic
fun printFooter() {
when (mode) {
Mode.STABLE -> Iris.info(C.BLUE.toString() + "Iris is running Stable")
Mode.WARNING -> warning()
Mode.UNSTABLE -> unstable()
}
}
@JvmStatic
fun isForceShutdown() = forceShutdown
private fun warning() {
Iris.warn(C.GOLD.toString() + "Iris is running in Warning Mode")
Iris.warn("")
Iris.warn(C.DARK_GRAY.toString() + "--==<" + C.GOLD + " IMPORTANT " + C.DARK_GRAY + ">==--")
Iris.warn(C.GOLD.toString() + "Iris is running in warning mode which may cause the following issues:")
Iris.warn("- Data Loss")
Iris.warn("- Errors")
Iris.warn("- Broken worlds")
Iris.warn("- Unexpected behavior.")
Iris.warn("- And perhaps further complications.")
Iris.warn("")
}
private fun unstable() {
Iris.error(C.DARK_RED.toString() + "Iris is running in Unstable Mode")
Iris.error("")
Iris.error(C.DARK_GRAY.toString() + "--==<" + C.RED + " IMPORTANT " + C.DARK_GRAY + ">==--")
Iris.error("Iris is running in unstable mode which may cause the following issues:")
Iris.error(C.DARK_RED.toString() + "Server Issues")
Iris.error("- Server won't boot")
Iris.error("- Data Loss")
Iris.error("- Unexpected behavior.")
Iris.error("- And More...")
Iris.error(C.DARK_RED.toString() + "World Issues")
Iris.error("- Worlds can't load due to corruption.")
Iris.error("- Worlds may slowly corrupt until they can't load.")
Iris.error("- World data loss.")
Iris.error("- And More...")
Iris.error(C.DARK_RED.toString() + "ATTENTION: " + C.RED + "While running Iris in unstable mode, you won't be eligible for support.")
if (IrisSettings.get().general.isDoomsdayAnnihilationSelfDestructMode) {
Iris.error(C.DARK_RED.toString() + "Boot Unstable is set to true, continuing with the startup process in 10 seconds.")
J.sleep(10000L)
} else {
Iris.error(C.DARK_RED.toString() + "Go to plugins/iris/settings.json and set DoomsdayAnnihilationSelfDestructMode to true if you wish to proceed.")
Iris.error(C.DARK_RED.toString() + "The server will shutdown in 10 seconds.")
J.sleep(10000L)
Iris.error(C.DARK_RED.toString() + "Shutting down server.")
forceShutdown = true
try {
Bukkit.getPluginManager().disablePlugins()
} finally {
Runtime.getRuntime().halt(42)
}
}
Iris.info("")
}
}

View File

@@ -0,0 +1,76 @@
package com.volmit.iris.core.safeguard
import com.volmit.iris.BuildConstants
import com.volmit.iris.Iris
import com.volmit.iris.core.IrisSettings
import com.volmit.iris.util.format.C
import com.volmit.iris.util.format.Form
enum class Mode(private val color: C) {
STABLE(C.IRIS),
WARNING(C.GOLD),
UNSTABLE(C.RED);
val id = name.lowercase()
fun highest(m: Mode): Mode {
return if (m.ordinal > ordinal) m else this
}
fun tag(subTag: String?): String {
if (subTag == null || subTag.isBlank()) return wrap("Iris") + C.GRAY + ": "
return wrap("Iris") + " " + wrap(subTag) + C.GRAY + ": "
}
private fun wrap(tag: String?): String {
return C.BOLD.toString() + "" + C.DARK_GRAY + "[" + C.BOLD + color + tag + C.BOLD + C.DARK_GRAY + "]" + C.RESET
}
fun trySplash() {
if (!IrisSettings.get().general.isSplashLogoStartup) return
splash()
}
fun splash() {
val padd = Form.repeat(" ", 8)
val padd2 = Form.repeat(" ", 4)
val splash = arrayOf(
padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@",
padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + color + " .(((()))). ",
padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + color + " .((((((())))))). ",
padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + color + " ((((((((())))))))) " + C.GRAY + " @",
padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + color + " ((((((((-))))))))) " + C.GRAY + " @@",
padd + C.GRAY + "@@@&&" + color + " ((((((({ })))))))) " + C.GRAY + " &&@@@",
padd + C.GRAY + "@@" + color + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@",
padd + C.GRAY + "@" + color + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@",
padd + C.GRAY + "" + color + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@",
padd + C.GRAY + "" + color + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@",
padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@",
)
val info = arrayOf(
"",
"",
"",
"",
"",
padd2 + color + " Iris",
padd2 + C.GRAY + " by " + color + "Volmit Software",
padd2 + C.GRAY + " v" + color + Iris.instance.description.version,
padd2 + C.GRAY + " c" + color + BuildConstants.COMMIT + C.GRAY + "/" + color + BuildConstants.ENVIRONMENT,
)
val builder = StringBuilder("\n\n")
for (i in splash.indices) {
builder.append(splash[i])
if (i < info.size) {
builder.append(info[i])
}
builder.append("\n")
}
Iris.info(builder.toString())
}
}

View File

@@ -0,0 +1,28 @@
package com.volmit.iris.core.safeguard.task
import com.volmit.iris.core.safeguard.Mode
import com.volmit.iris.util.format.Form
import kotlin.properties.PropertyDelegateProvider
import kotlin.properties.ReadOnlyProperty
abstract class Task(
val id: String,
val name: String = Form.capitalizeWords(id.replace(" ", "_").lowercase()),
) {
abstract fun run(): ValueWithDiagnostics<Mode>
companion object {
fun of(id: String, name: String = id, action: () -> ValueWithDiagnostics<Mode>) = object : Task(id, name) {
override fun run() = action()
}
fun of(id: String, action: () -> ValueWithDiagnostics<Mode>) = object : Task(id) {
override fun run() = action()
}
fun task(action: () -> ValueWithDiagnostics<Mode>) = PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, Task>> { _, _ ->
ReadOnlyProperty { _, property -> of(property.name, action) }
}
}
}

View File

@@ -0,0 +1,138 @@
package com.volmit.iris.core.safeguard.task
import com.volmit.iris.Iris
import com.volmit.iris.core.IrisWorlds
import com.volmit.iris.core.nms.INMS
import com.volmit.iris.core.nms.v1X.NMSBinding1X
import com.volmit.iris.core.safeguard.Mode
import com.volmit.iris.core.safeguard.Mode.*
import com.volmit.iris.core.safeguard.task.Diagnostic.Logger.*
import com.volmit.iris.core.safeguard.task.Task.Companion.of
import com.volmit.iris.util.agent.Agent
import com.volmit.iris.util.misc.getHardware
import org.bukkit.Bukkit
import java.util.stream.Collectors
import javax.tools.ToolProvider
import kotlin.properties.PropertyDelegateProvider
import kotlin.properties.ReadOnlyProperty
private val memory by task {
val mem = getHardware.getProcessMemory()
if (mem >= 5999) STABLE.withDiagnostics()
else STABLE.withDiagnostics(
WARN.create("Low Memory"),
WARN.create("- 6GB+ Ram is recommended"),
WARN.create("- Process Memory: $mem MB")
)
}
private val incompatibilities by task {
val plugins = mutableSetOf("dynmap", "Stratos")
plugins.removeIf { server.pluginManager.getPlugin(it) == null }
if (plugins.isEmpty()) STABLE.withDiagnostics()
else {
val diagnostics = mutableListOf<Diagnostic>()
if ("dynmap" in plugins) diagnostics.addAll(
ERROR.create("Dynmap"),
ERROR.create("- The plugin Dynmap is not compatible with the server."),
ERROR.create("- If you want to have a map plugin like Dynmap, consider Bluemap.")
)
if ("Stratos" in plugins) diagnostics.addAll(
ERROR.create("Stratos"),
ERROR.create("- Iris is not compatible with other worldgen plugins.")
)
WARNING.withDiagnostics(diagnostics)
}
}
private val software by task {
val supported = setOf(
"purpur",
"pufferfish",
"paper",
"spigot",
"bukkit"
)
if (supported.any { server.name.contains(it, true) }) STABLE.withDiagnostics()
else WARNING.withDiagnostics(
WARN.create("Unsupported Server Software"),
WARN.create("- Please consider using Paper or Purpur instead.")
)
}
private val version by task {
val parts = Iris.instance.description.version.split('-')
val minVersion = parts[1]
val maxVersion = parts[2]
if (INMS.get() !is NMSBinding1X) STABLE.withDiagnostics()
else UNSTABLE.withDiagnostics(
ERROR.create("Server Version"),
ERROR.create("- Iris only supports $minVersion > $maxVersion")
)
}
private val injection by task {
if (!Agent.install()) UNSTABLE.withDiagnostics(
ERROR.create("Java Agent"),
ERROR.create("- Please enable dynamic agent loading by adding -XX:+EnableDynamicAgentLoading to your jvm arguments."),
ERROR.create("- or add the jvm argument -javaagent:" + Agent.AGENT_JAR.path)
)
else if (!INMS.get().injectBukkit()) UNSTABLE.withDiagnostics(
ERROR.create("Code Injection"),
ERROR.create("- Failed to inject code. Please contact support")
)
else STABLE.withDiagnostics()
}
private val dimensionTypes by task {
val keys = IrisWorlds.get()
.dimensions
.map { it.dimensionTypeKey }
.collect(Collectors.toSet())
if (!INMS.get().missingDimensionTypes(*keys.toTypedArray())) STABLE.withDiagnostics()
else UNSTABLE.withDiagnostics(
ERROR.create("Dimension Types"),
ERROR.create("- Required Iris dimension types were not loaded."),
ERROR.create("- If this still happens after a restart please contact support.")
)
}
private val diskSpace by task {
if (server.worldContainer.freeSpace.toDouble().div(0x4000_0000) > 3) STABLE.withDiagnostics()
else WARNING.withDiagnostics(
WARN.create("Insufficient Disk Space"),
WARN.create("- 3GB of free space is required for Iris to function.")
)
}
private val java by task {
val version = Iris.getJavaVersion()
val jdk = runCatching { ToolProvider.getSystemJavaCompiler() }.getOrNull() != null
if (version in setOf(21) && jdk) STABLE.withDiagnostics()
else WARNING.withDiagnostics(
WARN.create("Unsupported Java version"),
WARN.create("- Please consider using JDK 21 Instead of ${if(jdk) "JDK" else "JRE"} $version")
)
}
val tasks = listOf(
memory,
incompatibilities,
software,
version,
injection,
dimensionTypes,
diskSpace,
java,
)
private val server get() = Bukkit.getServer()
private fun <T> MutableList<T>.addAll(vararg values: T) = values.forEach(this::add)
fun task(action: () -> ValueWithDiagnostics<Mode>) = PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, Task>> { _, _ ->
ReadOnlyProperty { _, property -> of(property.name, action) }
}

View File

@@ -0,0 +1,74 @@
package com.volmit.iris.core.safeguard.task
import com.volmit.iris.Iris
import com.volmit.iris.util.format.C
import java.io.ByteArrayOutputStream
import java.io.PrintStream
data class ValueWithDiagnostics<out T>(
val value: T,
val diagnostics: List<Diagnostic>
) {
constructor(value: T, vararg diagnostics: Diagnostic) : this(value, diagnostics.toList())
@JvmOverloads
fun log(
withException: Boolean = true,
withStackTrace: Boolean = false
) {
diagnostics.forEach { it.log(withException, withStackTrace) }
}
}
data class Diagnostic @JvmOverloads constructor(
val logger: Logger = Logger.ERROR,
val message: String,
val exception: Throwable? = null
) {
enum class Logger(
private val logger: (String) -> Unit
) {
DEBUG(Iris::debug),
RAW(Iris::msg),
INFO(Iris::info),
WARN(Iris::warn),
ERROR(Iris::error);
fun print(message: String) = message.split('\n').forEach(logger)
fun create(message: String, exception: Throwable? = null) = Diagnostic(this, message, exception)
}
@JvmOverloads
fun log(
withException: Boolean = true,
withStackTrace: Boolean = false
) {
logger.print(render(withException, withStackTrace))
}
fun render(
withException: Boolean = true,
withStackTrace: Boolean = false
): String = buildString {
append(message)
if (withException && exception != null) {
append(": ")
append(exception)
if (withStackTrace) {
ByteArrayOutputStream().use { os ->
val ps = PrintStream(os)
exception.printStackTrace(ps)
ps.flush()
append("\n")
append(os.toString())
}
}
}
}
override fun toString(): String = C.strip(render())
}
fun <T> T.withDiagnostics(vararg diagnostics: Diagnostic) = ValueWithDiagnostics(this, diagnostics.toList())
fun <T> T.withDiagnostics(diagnostics: List<Diagnostic>) = ValueWithDiagnostics(this, diagnostics)