From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sun, 3 Mar 2019 18:25:06 -0800
Subject: [PATCH] Tuinity Server Config


diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java
index e33e889c291d37a821a4fbd40d9aac7bb079de0d..5dfa0658838c4801cdf260eae8b98163f729e5af 100644
--- a/src/main/java/co/aikar/timings/TimingsExport.java
+++ b/src/main/java/co/aikar/timings/TimingsExport.java
@@ -229,7 +229,8 @@ public class TimingsExport extends Thread {
         parent.put("config", createObject(
             pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)),
             pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)),
-            pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null))
+            pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)), // Tuinity - add config to timings report
+            pair("tuinity", mapAsJSON(Bukkit.spigot().getTuinityConfig(), null)) // Tuinity - add config to timings report
         ));
 
         new TimingsExport(listeners, parent, history).start();
diff --git a/src/main/java/com/tuinity/tuinity/config/TuinityConfig.java b/src/main/java/com/tuinity/tuinity/config/TuinityConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f66484a80d3cc7caaf8a111bd50229e673bd8e0
--- /dev/null
+++ b/src/main/java/com/tuinity/tuinity/config/TuinityConfig.java
@@ -0,0 +1,236 @@
+package com.tuinity.tuinity.config;
+
+import com.destroystokyo.paper.util.SneakyThrow;
+import org.bukkit.Bukkit;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.YamlConfiguration;
+import java.io.File;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.List;
+import java.util.logging.Level;
+
+public final class TuinityConfig {
+
+    public static final String CONFIG_HEADER = "Configuration file for Tuinity.";
+    public static final int CURRENT_CONFIG_VERSION = 2;
+
+    private static final Object[] EMPTY = new Object[0];
+
+    private static File configFile;
+    public static YamlConfiguration config;
+    private static int configVersion;
+    public static boolean createWorldSections = true;
+
+    public static void init(final File file) {
+        // TODO remove this in the future...
+        final File tuinityConfig = new File(file.getParent(), "tuinity.yml");
+        if (!tuinityConfig.exists()) {
+            final File oldConfig = new File(file.getParent(), "concrete.yml");
+            oldConfig.renameTo(tuinityConfig);
+        }
+        TuinityConfig.configFile = file;
+        final YamlConfiguration config = new YamlConfiguration();
+        config.options().header(CONFIG_HEADER);
+        config.options().copyDefaults(true);
+
+        if (!file.exists()) {
+            try {
+                file.createNewFile();
+            } catch (final Exception ex) {
+                Bukkit.getLogger().log(Level.SEVERE, "Failure to create tuinity config", ex);
+            }
+        } else {
+            try {
+                config.load(file);
+            } catch (final Exception ex) {
+                Bukkit.getLogger().log(Level.SEVERE, "Failure to load tuinity config", ex);
+                SneakyThrow.sneaky(ex); /* Rethrow, this is critical */
+                throw new RuntimeException(ex); // unreachable
+            }
+        }
+
+        TuinityConfig.load(config);
+    }
+
+    public static void load(final YamlConfiguration config) {
+        TuinityConfig.config = config;
+        TuinityConfig.configVersion = TuinityConfig.getInt("config-version-please-do-not-modify-me", CURRENT_CONFIG_VERSION);
+        TuinityConfig.set("config-version-please-do-not-modify-me", CURRENT_CONFIG_VERSION);
+
+        for (final Method method : TuinityConfig.class.getDeclaredMethods()) {
+            if (method.getReturnType() != void.class || method.getParameterCount() != 0 ||
+                    !Modifier.isPrivate(method.getModifiers()) || !Modifier.isStatic(method.getModifiers())) {
+                continue;
+            }
+
+            try {
+                method.setAccessible(true);
+                method.invoke(null, EMPTY);
+            } catch (final Exception ex) {
+                SneakyThrow.sneaky(ex); /* Rethrow, this is critical */
+                throw new RuntimeException(ex); // unreachable
+            }
+        }
+
+        /* We re-save to add new options */
+        try {
+            config.save(TuinityConfig.configFile);
+        } catch (final Exception ex) {
+            Bukkit.getLogger().log(Level.SEVERE, "Unable to save tuinity config", ex);
+        }
+    }
+
+    static void set(final String path, final Object value) {
+        TuinityConfig.config.set(path, value);
+    }
+
+    static boolean getBoolean(final String path, final boolean dfl) {
+        TuinityConfig.config.addDefault(path, Boolean.valueOf(dfl));
+        return TuinityConfig.config.getBoolean(path, dfl);
+    }
+
+    static int getInt(final String path, final int dfl) {
+        TuinityConfig.config.addDefault(path, Integer.valueOf(dfl));
+        return TuinityConfig.config.getInt(path, dfl);
+    }
+
+    static long getLong(final String path, final long dfl) {
+        TuinityConfig.config.addDefault(path, Long.valueOf(dfl));
+        return TuinityConfig.config.getLong(path, dfl);
+    }
+
+    static double getDouble(final String path, final double dfl) {
+        TuinityConfig.config.addDefault(path, Double.valueOf(dfl));
+        return TuinityConfig.config.getDouble(path, dfl);
+    }
+
+    static String getString(final String path, final String dfl) {
+        TuinityConfig.config.addDefault(path, dfl);
+        return TuinityConfig.config.getString(path, dfl);
+    }
+
+    public static final class WorldConfig {
+
+        public final String worldName;
+        public String configPath;
+        ConfigurationSection worldDefaults;
+
+        public WorldConfig(final String worldName) {
+            this.worldName = worldName;
+            this.init();
+        }
+
+        public void init() {
+            this.worldDefaults = TuinityConfig.config.getConfigurationSection("world-settings.default");
+            if (this.worldDefaults == null) {
+                this.worldDefaults = TuinityConfig.config.createSection("world-settings.default");
+            }
+
+            String worldSectionPath = TuinityConfig.configVersion < 1 ? this.worldName : "world-settings.".concat(this.worldName);
+            ConfigurationSection section = TuinityConfig.config.getConfigurationSection(worldSectionPath);
+            this.configPath = worldSectionPath;
+            if (TuinityConfig.createWorldSections) {
+                if (section == null) {
+                    section = TuinityConfig.config.createSection(worldSectionPath);
+                }
+                TuinityConfig.config.set(worldSectionPath, section);
+            }
+
+            this.load();
+        }
+
+        public void load() {
+            for (final Method method : TuinityConfig.WorldConfig.class.getDeclaredMethods()) {
+                if (method.getReturnType() != void.class || method.getParameterCount() != 0 ||
+                        !Modifier.isPrivate(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) {
+                    continue;
+                }
+
+                try {
+                    method.setAccessible(true);
+                    method.invoke(this, EMPTY);
+                } catch (final Exception ex) {
+                    SneakyThrow.sneaky(ex); /* Rethrow, this is critical */
+                    throw new RuntimeException(ex); // unreachable
+                }
+            }
+
+            if (TuinityConfig.configVersion < 1) {
+                ConfigurationSection oldSection = TuinityConfig.config.getConfigurationSection(this.worldName);
+                TuinityConfig.config.set("world-settings.".concat(this.worldName), oldSection);
+                TuinityConfig.config.set(this.worldName, null);
+            }
+
+            /* We re-save to add new options */
+            try {
+                TuinityConfig.config.save(TuinityConfig.configFile);
+            } catch (final Exception ex) {
+                Bukkit.getLogger().log(Level.SEVERE, "Unable to save tuinity config", ex);
+            }
+        }
+
+        /**
+         * update world defaults for the specified path, but also sets this world's config value for the path
+         * if it exists
+         */
+        void set(final String path, final Object val) {
+            final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath);
+            this.worldDefaults.set(path, val);
+            if (config != null && config.get(path) != null) {
+                config.set(path, val);
+            }
+        }
+
+        boolean getBoolean(final String path, final boolean dfl) {
+            final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath);
+            this.worldDefaults.addDefault(path, Boolean.valueOf(dfl));
+            if (TuinityConfig.configVersion < 1) {
+                if (config != null && config.getBoolean(path) == dfl) {
+                    config.set(path, null);
+                }
+            }
+            return config == null ? this.worldDefaults.getBoolean(path) : config.getBoolean(path, this.worldDefaults.getBoolean(path));
+        }
+
+        int getInt(final String path, final int dfl) {
+            final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath);
+            this.worldDefaults.addDefault(path, Integer.valueOf(dfl));
+            if (TuinityConfig.configVersion < 1) {
+                if (config != null && config.getInt(path) == dfl) {
+                    config.set(path, null);
+                }
+            }
+            return config == null ? this.worldDefaults.getInt(path) : config.getInt(path, this.worldDefaults.getInt(path));
+        }
+
+        long getLong(final String path, final long dfl) {
+            final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath);
+            this.worldDefaults.addDefault(path, Long.valueOf(dfl));
+            if (TuinityConfig.configVersion < 1) {
+                if (config != null && config.getLong(path) == dfl) {
+                    config.set(path, null);
+                }
+            }
+            return config == null ? this.worldDefaults.getLong(path) : config.getLong(path, this.worldDefaults.getLong(path));
+        }
+
+        double getDouble(final String path, final double dfl) {
+            final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath);
+            this.worldDefaults.addDefault(path, Double.valueOf(dfl));
+            if (TuinityConfig.configVersion < 1) {
+                if (config != null && config.getDouble(path) == dfl) {
+                    config.set(path, null);
+                }
+            }
+            return config == null ? this.worldDefaults.getDouble(path) : config.getDouble(path, this.worldDefaults.getDouble(path));
+        }
+
+        String getString(final String path, final String dfl) {
+            final ConfigurationSection config = TuinityConfig.config.getConfigurationSection(this.configPath);
+            this.worldDefaults.addDefault(path, dfl);
+            return config == null ? this.worldDefaults.getString(path) : config.getString(path, this.worldDefaults.getString(path));
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/server/DedicatedServer.java b/src/main/java/net/minecraft/server/DedicatedServer.java
index d4793a1d476d8d6687ec8782501c31265f284daa..617ba6fb85c55967360ca270ee8feeff5acbf8e0 100644
--- a/src/main/java/net/minecraft/server/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/DedicatedServer.java
@@ -175,6 +175,7 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer
         com.destroystokyo.paper.PaperConfig.registerCommands();
         com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // load version history now
         // Paper end
+        com.tuinity.tuinity.config.TuinityConfig.init((java.io.File) options.valueOf("tuinity-settings")); // Tuinity - Server Config
 
         this.setPVP(dedicatedserverproperties.pvp);
         this.setAllowFlight(dedicatedserverproperties.allowFlight);
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 74f89ea456e23937d0fec14831508365f3014ab0..dc8e4a86ddae9ea4dfd62e591523fdc8a6599151 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -960,6 +960,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
                 // Paper end
 
                 PaperJvmChecker.checkJvm(); // Paper jvm version nag
+                com.tuinity.tuinity.config.TuinityConfig.createWorldSections = false; // Tuinity - don't let plugin created worlds fill our config
                 org.spigotmc.WatchdogThread.tick(); // Paper
                 org.spigotmc.WatchdogThread.hasStarted = true; // Paper
                 Arrays.fill( recentTps, 20 );
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index f5ab99156ce5429e63976183cbf115d5340a83a1..8efdd9bd0827d1f6a31d5f943f986dabe7d05137 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -94,6 +94,8 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
     public final com.destroystokyo.paper.PaperWorldConfig paperConfig; // Paper
     public final ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
 
+    public final com.tuinity.tuinity.config.TuinityConfig.WorldConfig tuinityConfig; // Tuinity - Server Config
+
     public final co.aikar.timings.WorldTimingsHandler timings; // Paper
     public static BlockPosition lastPhysicsProblem; // Spigot
     private org.spigotmc.TickLimiter entityLimiter;
@@ -125,6 +127,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
         this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((WorldDataServer) worlddatamutable).getName()); // Spigot
         this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(((WorldDataServer) worlddatamutable).getName(), this.spigotConfig); // Paper
         this.chunkPacketBlockController = this.paperConfig.antiXray ? new ChunkPacketBlockControllerAntiXray(this, executor) : ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray
+        this.tuinityConfig = new com.tuinity.tuinity.config.TuinityConfig.WorldConfig(((WorldDataServer)worlddatamutable).getName()); // Tuinity - Server Config
         this.generator = gen;
         this.world = new CraftWorld((WorldServer) this, gen, env);
         this.ticksPerAnimalSpawns = this.getServer().getTicksPerAnimalSpawns(); // CraftBukkit
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index e03f3a9d10d948689060e9fc9c06ad3d113eac93..b6bd513ff86de123f40302070633dcb2f47ce108 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -864,6 +864,7 @@ public final class CraftServer implements Server {
 
         org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot
         com.destroystokyo.paper.PaperConfig.init((File) console.options.valueOf("paper-settings")); // Paper
+        com.tuinity.tuinity.config.TuinityConfig.init((File) console.options.valueOf("tuinity-settings")); // Tuinity - Server Config
         for (WorldServer world : console.getWorlds()) {
             world.worldDataServer.setDifficulty(config.difficulty);
             world.setSpawnFlags(config.spawnMonsters, config.spawnAnimals);
@@ -898,6 +899,7 @@ public final class CraftServer implements Server {
             }
             world.spigotConfig.init(); // Spigot
             world.paperConfig.init(); // Paper
+            world.tuinityConfig.init(); // Tuinity - Server Config
         }
 
         Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
@@ -2344,6 +2346,14 @@ public final class CraftServer implements Server {
             return com.destroystokyo.paper.PaperConfig.config;
         }
 
+        // Tuinity start - add config to timings report
+        @Override
+        public YamlConfiguration getTuinityConfig()
+        {
+            return com.tuinity.tuinity.config.TuinityConfig.config;
+        }
+        // Tuinity end - add config to timings report
+
         @Override
         public void restart() {
             org.spigotmc.RestartCommand.restart();
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index ac32e19afe7255fedecc2cadbc47d2a332b80a90..0f6cb508a170360b6479f9c34048412453fbb89d 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -138,6 +138,13 @@ public class Main {
                         .defaultsTo(new File("paper.yml"))
                         .describedAs("Yml file");
                 // Paper end
+                // Tuinity Start - Server Config
+                acceptsAll(asList("tuinity", "tuinity-settings"), "File for tuinity settings")
+                        .withRequiredArg()
+                        .ofType(File.class)
+                        .defaultsTo(new File("tuinity.yml"))
+                        .describedAs("Yml file");
+                /* Conctete End - Server Config */
 
                 // Paper start
                 acceptsAll(asList("server-name"), "Name of the server")
