mirror of
https://github.com/LeavesMC/Leaves.git
synced 2025-12-19 14:59:32 +00:00
1609 lines
68 KiB
Diff
1609 lines
68 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: violetc <58360096+s-yh-china@users.noreply.github.com>
|
|
Date: Fri, 29 Oct 2021 16:52:57 +0800
|
|
Subject: [PATCH] Leaves Server Config And Command
|
|
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
index 19c388c98d7e86391b4798bcf3a19d9932c81aed..e5d331d0e5bf2d80685289430682ca7a9ccbefff 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -1143,6 +1143,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
LOGGER.info("Done ({})! For help, type \"help\"", doneTime);
|
|
// Paper end
|
|
|
|
+ top.leavesmc.leaves.LeavesConfig.createWorldSections = false; // Leaves - dont let plugin create worlds fill our config
|
|
org.spigotmc.WatchdogThread.tick(); // Paper
|
|
org.spigotmc.WatchdogThread.hasStarted = true; // Paper
|
|
Arrays.fill( this.recentTps, 20 );
|
|
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
index 7fb484e4a97070e75b8611a59d84c9732ed5d17b..27f7507a50537ec76f88518d3584d7c880f6eee4 100644
|
|
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
@@ -220,6 +220,9 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
|
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
|
|
io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // Paper - init PaperBrigadierProvider
|
|
|
|
+ top.leavesmc.leaves.LeavesConfig.init((java.io.File) options.valueOf("leaves-settings")); // Leaves - Server Config
|
|
+ System.setProperty("spark.serverconfigs.extra", "leaves.yml"); // Leaves - spark config
|
|
+
|
|
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics // Leaves - down
|
|
|
|
this.setPvpAllowed(dedicatedserverproperties.pvp);
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
index 12b5796ac962b73a36538d313b77c07784d6ebe7..98e673938df540f47ef882620daadd2da566f671 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
@@ -1037,6 +1037,7 @@ public final class CraftServer implements Server {
|
|
|
|
org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot
|
|
this.console.paperConfigurations.reloadConfigs(this.console);
|
|
+ top.leavesmc.leaves.LeavesConfig.init((File) console.options.valueOf("leaves-settings")); // Leaves - Server Config
|
|
for (ServerLevel world : this.console.getAllLevels()) {
|
|
// world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty
|
|
world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters, config.spawnAnimals); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean))
|
|
@@ -3009,6 +3010,14 @@ public final class CraftServer implements Server {
|
|
{
|
|
return CraftServer.this.console.paperConfigurations.createLegacyObject(CraftServer.this.console);
|
|
}
|
|
+
|
|
+ // Leaves start - add config to timings report
|
|
+ @Override
|
|
+ public YamlConfiguration getLeavesConfig()
|
|
+ {
|
|
+ return top.leavesmc.leaves.LeavesConfig.config;
|
|
+ }
|
|
+ /// Leaves end - add config to timings report
|
|
|
|
@Override
|
|
public void restart() {
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
|
index dd95c9d931da5ee2cb3e620c71cc90d178c51fbc..d1ebe4f340c53f987a42fffcc462f2eab4686d1b 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
|
@@ -166,6 +166,14 @@ public class Main {
|
|
.ofType(File.class)
|
|
.defaultsTo(new File("paper.yml"))
|
|
.describedAs("Yml file");
|
|
+
|
|
+ // Leaves start - Server Config
|
|
+ acceptsAll(asList("leaves", "leaves-settings"), "File for leaves settings")
|
|
+ .withRequiredArg()
|
|
+ .ofType(File.class)
|
|
+ .defaultsTo(new File("leaves.yml"))
|
|
+ .describedAs("Yml file");
|
|
+ // Leaves end - Server Config
|
|
|
|
acceptsAll(asList("add-plugin", "add-extra-plugin-jar"), "Specify paths to extra plugin jars to be loaded in addition to those in the plugins folder. This argument can be specified multiple times, once for each extra plugin jar path.")
|
|
.withRequiredArg()
|
|
diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..4eac1921b5cb8616881bcb56b889336ac559920e
|
|
--- /dev/null
|
|
+++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
|
|
@@ -0,0 +1,876 @@
|
|
+package top.leavesmc.leaves;
|
|
+
|
|
+import com.destroystokyo.paper.util.SneakyThrow;
|
|
+import io.papermc.paper.configuration.GlobalConfiguration;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import org.bukkit.Bukkit;
|
|
+import org.bukkit.command.Command;
|
|
+import org.bukkit.configuration.file.YamlConfiguration;
|
|
+import top.leavesmc.leaves.command.LeavesCommand;
|
|
+import top.leavesmc.leaves.config.ConfigVerify;
|
|
+import top.leavesmc.leaves.config.GlobalConfig;
|
|
+import top.leavesmc.leaves.config.GlobalConfigManager;
|
|
+import top.leavesmc.leaves.config.RemovedConfig;
|
|
+import top.leavesmc.leaves.util.MathUtils;
|
|
+
|
|
+import java.io.File;
|
|
+import java.io.IOException;
|
|
+import java.util.Collections;
|
|
+import java.util.List;
|
|
+import java.util.logging.Level;
|
|
+import java.util.Random;
|
|
+
|
|
+import top.leavesmc.leaves.protocol.CarpetServerProtocol.CarpetRule;
|
|
+import top.leavesmc.leaves.protocol.CarpetServerProtocol.CarpetRules;
|
|
+
|
|
+import top.leavesmc.leaves.protocol.bladeren.BladerenProtocol.LeavesFeatureSet;
|
|
+import top.leavesmc.leaves.protocol.bladeren.BladerenProtocol.LeavesFeature;
|
|
+
|
|
+public final class LeavesConfig {
|
|
+
|
|
+ public static final String CONFIG_HEADER = "Configuration file for Leaves.";
|
|
+ public static final int CURRENT_CONFIG_VERSION = 5;
|
|
+
|
|
+ private static File configFile;
|
|
+ public static YamlConfiguration config;
|
|
+ private static int configVersion;
|
|
+ public static boolean createWorldSections = true;
|
|
+
|
|
+ public static void init(final File file) {
|
|
+ LeavesConfig.configFile = file;
|
|
+ config = new YamlConfiguration();
|
|
+ config.options().setHeader(Collections.singletonList(CONFIG_HEADER));
|
|
+ config.options().copyDefaults(true);
|
|
+
|
|
+ if (!file.exists()) {
|
|
+ try {
|
|
+ boolean is = file.createNewFile();
|
|
+ if (!is) {
|
|
+ throw new IOException("Can't create file");
|
|
+ }
|
|
+ } catch (final Exception ex) {
|
|
+ Bukkit.getLogger().log(Level.SEVERE, "Failure to create leaves config", ex);
|
|
+ }
|
|
+ } else {
|
|
+ try {
|
|
+ config.load(file);
|
|
+ } catch (final Exception ex) {
|
|
+ Bukkit.getLogger().log(Level.SEVERE, "Failure to load leaves config", ex);
|
|
+ SneakyThrow.sneaky(ex); /* Rethrow, this is critical */
|
|
+ throw new RuntimeException(ex); // unreachable
|
|
+ }
|
|
+ }
|
|
+
|
|
+ LeavesConfig.configVersion = LeavesConfig.config.getInt("config-version", CURRENT_CONFIG_VERSION);
|
|
+ LeavesConfig.config.set("config-version", CURRENT_CONFIG_VERSION);
|
|
+
|
|
+ updateConfigVersion(config);
|
|
+
|
|
+ GlobalConfigManager.init();
|
|
+
|
|
+ registerCommand("leaves", new LeavesCommand("leaves"));
|
|
+ }
|
|
+
|
|
+ public static void save() {
|
|
+ try {
|
|
+ config.save(LeavesConfig.configFile);
|
|
+ } catch (final Exception ex) {
|
|
+ Bukkit.getLogger().log(Level.SEVERE, "Unable to save leaves config", ex);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Deprecated(forRemoval = true)
|
|
+ private static void updateConfigVersion(final YamlConfiguration config) {
|
|
+ if (configVersion < CURRENT_CONFIG_VERSION) {
|
|
+ switch (configVersion) {
|
|
+ case 1 -> {
|
|
+ snowballAndEggCanKnockback = config.getBoolean("settings.snowball-and-egg-can-knockback-player", snowballAndEggCanKnockback);
|
|
+ fakeplayerSupport = config.getBoolean("settings.fakeplayer.enable", fakeplayerSupport);
|
|
+ unableFakeplayerNames = (List<String>) config.getList("settings.fakeplayer.unable-fakeplayer-names", unableFakeplayerNames);
|
|
+ shearsInDispenserCanZeroAmount = config.getBoolean("settings.shears-in-dispenser-can-zero-amount", shearsInDispenserCanZeroAmount);
|
|
+ redstoneShearsWrench = config.getBoolean("settings.redstone-shears-wrench", redstoneShearsWrench);
|
|
+ buddingAmethystCanPushByPiston = config.getBoolean("settings.budding-amethyst-can-push-by-piston", buddingAmethystCanPushByPiston);
|
|
+ spectatorDontGetAdvancement = config.getBoolean("settings.spectator-dont-get-advancement", spectatorDontGetAdvancement);
|
|
+ stickChangeArmorStandArmStatus = config.getBoolean("settings.stick-change-armorstand-arm-status", stickChangeArmorStandArmStatus);
|
|
+ noChatSign = config.getBoolean("settings.no-chat-sign", noChatSign);
|
|
+
|
|
+ config.set("settings.snowball-and-egg-can-knockback-player", null);
|
|
+ config.set("settings.player-can-edit-sign", null);
|
|
+ config.set("settings.fakeplayer", null);
|
|
+ config.set("settings.shears-in-dispenser-can-zero-amount", null);
|
|
+ config.set("settings.redstone-shears-wrench", null);
|
|
+ config.set("settings.budding-amethyst-can-push-by-piston", null);
|
|
+ config.set("settings.spectator-dont-get-advancement", null);
|
|
+ config.set("settings.stick-change-armorstand-arm-status", null);
|
|
+ config.set("settings.no-chat-sign", null);
|
|
+ }
|
|
+
|
|
+ case 2 -> {
|
|
+ config.set("settings.modify.player-can-edit-sign", null);
|
|
+ config.set("settings.performance.skip-clone-loot-parameters", null);
|
|
+ }
|
|
+
|
|
+ case 3 -> {
|
|
+ boolean carpetAlternative = config.getBoolean("settings.protocol.carpet-alternative-block-placement", false);
|
|
+ alternativeBlockPlacement = carpetAlternative ? "CARPET" : "NONE";
|
|
+ config.set("settings.protocol.carpet-alternative-block-placement", null);
|
|
+ }
|
|
+
|
|
+ case 4 -> {
|
|
+ shearsInDispenserCanZeroAmount = config.getBoolean("settings.modify.shears-in-dispenser-can-zero-amount", shearsInDispenserCanZeroAmount);
|
|
+ instantBlockUpdaterReintroduced = config.getBoolean("settings.modify.instant-block-updater-reintroduced", instantBlockUpdaterReintroduced);
|
|
+ redstoneDontCantOnTrapDoor = config.getBoolean("settings.modify.redstone-wire-dont-connect-if-on-trapdoor", redstoneDontCantOnTrapDoor);
|
|
+ mendingCompatibilityInfinity = config.getBoolean("settings.modify.mending-compatibility-infinity", mendingCompatibilityInfinity);
|
|
+ zeroTickPlants = config.getBoolean("settings.modify.zero-tick-plants", zeroTickPlants);
|
|
+
|
|
+ config.set("settings.modify.shears-in-dispenser-can-zero-amount", null);
|
|
+ config.set("settings.modify.instant-block-updater-reintroduced", null);
|
|
+ config.set("settings.modify.redstone-wire-dont-connect-if-on-trapdoor", null);
|
|
+ config.set("settings.modify.mending-compatibility-infinity", null);
|
|
+ config.set("settings.modify.zero-tick-plants", null);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static void registerCommand(String name, Command command) {
|
|
+ MinecraftServer.getServer().server.getCommandMap().register(name, "Leaves", command);
|
|
+ }
|
|
+
|
|
+ public static void unregisterCommand(String name) {
|
|
+ name = name.toLowerCase(java.util.Locale.ENGLISH).trim();
|
|
+ MinecraftServer.getServer().server.getCommandMap().getKnownCommands().remove(name);
|
|
+ }
|
|
+
|
|
+ // Leaves start - modify
|
|
+
|
|
+ // Leaves start - modify - fakeplayer
|
|
+
|
|
+ @GlobalConfig(name = "enable", category = {"modify", "fakeplayer"}, verify = FakeplayerVerify.class)
|
|
+ public static boolean fakeplayerSupport = true;
|
|
+
|
|
+ private static class FakeplayerVerify extends ConfigVerify.BooleanConfigVerify {
|
|
+ @Override
|
|
+ public String check(Boolean old, Boolean value) {
|
|
+ if (value) {
|
|
+ registerCommand("bot", new top.leavesmc.leaves.bot.BotCommand("bot"));
|
|
+ top.leavesmc.leaves.bot.agent.Actions.registerAll();
|
|
+ } else {
|
|
+ unregisterCommand("bot");
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "unable-fakeplayer-names", category = {"modify", "fakeplayer"}, verify = ConfigVerify.ListConfigVerify.class)
|
|
+ public static List<String> unableFakeplayerNames = List.of("player-name");
|
|
+
|
|
+ @GlobalConfig(name = "limit", category = {"modify", "fakeplayer"}, verify = ConfigVerify.IntConfigVerify.class)
|
|
+ public static int fakeplayerLimit = 10;
|
|
+
|
|
+ @GlobalConfig(name = "prefix", category = {"modify", "fakeplayer"}, verify = ConfigVerify.StringConfigVerify.class)
|
|
+ public static String fakeplayerPrefix = "";
|
|
+
|
|
+ @GlobalConfig(name = "suffix", category = {"modify", "fakeplayer"}, verify = ConfigVerify.StringConfigVerify.class)
|
|
+ public static String fakeplayerSuffix = "";
|
|
+
|
|
+ @GlobalConfig(name = "always-send-data", category = {"modify", "fakeplayer"})
|
|
+ public static boolean alwaysSendFakeplayerData = true;
|
|
+
|
|
+ @GlobalConfig(name = "resident-fakeplayer", category = {"modify", "fakeplayer"})
|
|
+ public static boolean fakeplayerResident = false;
|
|
+
|
|
+ @GlobalConfig(name = "open-fakeplayer-inventory", category = {"modify", "fakeplayer"})
|
|
+ public static boolean openFakeplayerInventory = false;
|
|
+
|
|
+ @GlobalConfig(name = "skip-sleep-check", category = {"modify", "fakeplayer"})
|
|
+ public static boolean fakeplayerSkipSleep = false;
|
|
+
|
|
+ @GlobalConfig(name = "spawn-phantom", category = {"modify", "fakeplayer"})
|
|
+ public static boolean fakeplayerSpawnPhantom = false;
|
|
+
|
|
+ @GlobalConfig(name = "regen-amount", category = {"modify", "fakeplayer"}, verify = RegenAmountVerify.class)
|
|
+ public static double fakeplayerRegenAmount = 0.010;
|
|
+
|
|
+ private static class RegenAmountVerify extends ConfigVerify.DoubleConfigVerify {
|
|
+ @Override
|
|
+ public String check(Double old, Double value) {
|
|
+ return value > 0.0 ? null : "regen-amount need > 0.0f";
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Leaves end - modify - fakeplayer
|
|
+
|
|
+ // Leaves start - modify - minecraft-old
|
|
+
|
|
+ @GlobalConfig(name = "shears-in-dispenser-can-zero-amount", category = {"modify", "minecraft-old"})
|
|
+ public static boolean shearsInDispenserCanZeroAmount = false;
|
|
+
|
|
+ @GlobalConfig(name = "instant-block-updater-reintroduced", category = {"modify", "minecraft-old"}, lock = true)
|
|
+ public static boolean instantBlockUpdaterReintroduced = false;
|
|
+
|
|
+ @GlobalConfig(name = "armor-stand-cant-kill-by-mob-projectile", category = {"modify", "minecraft-old"})
|
|
+ public static boolean armorStandCantKillByMobProjectile = false;
|
|
+
|
|
+ @GlobalConfig(name = "cce-update-suppression", category = {"modify", "minecraft-old"})
|
|
+ public static boolean cceUpdateSuppression = false;
|
|
+
|
|
+ @GlobalConfig(name = "villager-infinite-discounts", category = {"modify", "minecraft-old"}, verify = VillagerInfiniteDiscountsVerify.class)
|
|
+ public static boolean villagerInfiniteDiscounts = false;
|
|
+
|
|
+ private static class VillagerInfiniteDiscountsVerify extends ConfigVerify.BooleanConfigVerify {
|
|
+ @Override
|
|
+ public String check(Boolean old, Boolean value) {
|
|
+ top.leavesmc.leaves.util.VillagerInfiniteDiscountHelper.doVillagerInfiniteDiscount(value);
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "copper-bulb-1gt-delay", category = {"modify", "minecraft-old"})
|
|
+ public static boolean copperBulb1gt = false;
|
|
+
|
|
+ @GlobalConfig(name = "crafter-1gt-delay", category = {"modify", "minecraft-old"})
|
|
+ public static boolean crafter1gt = false;
|
|
+
|
|
+ @GlobalConfig(name = "redstone-wire-dont-connect-if-on-trapdoor", category = {"modify", "minecraft-old"})
|
|
+ public static boolean redstoneDontCantOnTrapDoor = false;
|
|
+
|
|
+ @GlobalConfig(name = "mending-compatibility-infinity", category = {"modify", "minecraft-old"})
|
|
+ public static boolean mendingCompatibilityInfinity = false;
|
|
+
|
|
+ @GlobalConfig(name = "zero-tick-plants", category = {"modify", "minecraft-old"})
|
|
+ public static boolean zeroTickPlants = false;
|
|
+
|
|
+ @GlobalConfig(name = "loot-world-random", category = {"modify", "minecraft-old"}, verify = LootWorldRandomVerify.class)
|
|
+ public static boolean lootWorldRandom = false;
|
|
+
|
|
+ private static class LootWorldRandomVerify extends ConfigVerify.BooleanConfigVerify {
|
|
+ @Override
|
|
+ public String check(Boolean old, Boolean value) {
|
|
+ LeavesFeatureSet.register(LeavesFeature.of("loot_world_random", value));
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "protection-stacking", category = {"modify", "minecraft-old"})
|
|
+ public static boolean protectionStacking = false;
|
|
+
|
|
+ // Leaves end - modify - minecraft-old
|
|
+
|
|
+ // Leaves start - modify - elytra-aeronautics
|
|
+
|
|
+ @GlobalConfig(name = "no-chunk-load", category = {"modify", "elytra-aeronautics"})
|
|
+ public static boolean elytraAeronauticsNoChunk = false;
|
|
+
|
|
+ @GlobalConfig(name = "no-chunk-height", category = {"modify", "elytra-aeronautics"}, verify = ConfigVerify.DoubleConfigVerify.class)
|
|
+ public static double elytraAeronauticsNoChunkHeight = 500.0D;
|
|
+
|
|
+ @GlobalConfig(name = "no-chunk-speed", category = {"modify", "elytra-aeronautics"}, verify = ConfigVerify.DoubleConfigVerify.class)
|
|
+ public static double elytraAeronauticsNoChunkSpeed = -1.0D;
|
|
+
|
|
+ @GlobalConfig(name = "message", category = {"modify", "elytra-aeronautics"})
|
|
+ public static boolean elytraAeronauticsNoChunkMes = true;
|
|
+
|
|
+ @GlobalConfig(name = "message-start", category = {"modify", "elytra-aeronautics"}, verify = ConfigVerify.StringConfigVerify.class)
|
|
+ public static String elytraAeronauticsNoChunkStartMes = "Flight enter cruise mode";
|
|
+
|
|
+ @GlobalConfig(name = "message-end", category = {"modify", "elytra-aeronautics"}, verify = ConfigVerify.StringConfigVerify.class)
|
|
+ public static String elytraAeronauticsNoChunkEndMes = "Flight exit cruise mode";
|
|
+
|
|
+ // Leaves end - modify - elytra-aeronautics
|
|
+
|
|
+ @GlobalConfig(name = "redstone-shears-wrench", category = "modify")
|
|
+ public static boolean redstoneShearsWrench = true;
|
|
+
|
|
+ @GlobalConfig(name = "budding-amethyst-can-push-by-piston", category = "modify")
|
|
+ public static boolean buddingAmethystCanPushByPiston = false;
|
|
+
|
|
+ @GlobalConfig(name = "spectator-dont-get-advancement", category = "modify")
|
|
+ public static boolean spectatorDontGetAdvancement = false;
|
|
+
|
|
+ @GlobalConfig(name = "stick-change-armorstand-arm-status", category = "modify")
|
|
+ public static boolean stickChangeArmorStandArmStatus = true;
|
|
+
|
|
+ @GlobalConfig(name = "snowball-and-egg-can-knockback-player", category = "modify")
|
|
+ public static boolean snowballAndEggCanKnockback = true;
|
|
+
|
|
+ @GlobalConfig(name = "flatten-triangular-distribution", category = "modify")
|
|
+ public static boolean flattenTriangularDistribution = false;
|
|
+
|
|
+ @GlobalConfig(name = "player-operation-limiter", category = "modify")
|
|
+ public static boolean playerOperationLimiter = false;
|
|
+
|
|
+ @GlobalConfig(name = "renewable-elytra", category = "modify", verify = RenewableElytraVerify.class)
|
|
+ public static double renewableElytra = -1.0F;
|
|
+
|
|
+ private static class RenewableElytraVerify extends ConfigVerify.DoubleConfigVerify {
|
|
+ @Override
|
|
+ public String check(Double old, Double value) {
|
|
+ return value <= 1.0 ? null : "renewable-elytra need <= 1.0f";
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static int shulkerBoxStackSize = 1;
|
|
+ @GlobalConfig(name = "stackable-shulker-boxes", category = "modify", verify = StackableShulkerVerify.class)
|
|
+ private static String stackableShulkerBoxes = "false";
|
|
+
|
|
+ private static class StackableShulkerVerify extends ConfigVerify.StringConfigVerify {
|
|
+ @Override
|
|
+ public String check(String old, String value) {
|
|
+ String realValue = MathUtils.isNumeric(value) ? value : value.equals("true") ? "2" : "1";
|
|
+ shulkerBoxStackSize = Integer.parseInt(realValue);
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "force-void-trade", category = "modify")
|
|
+ public static boolean forceVoidTrade = false;
|
|
+
|
|
+ @GlobalConfig(name = "disable-moved-wrongly-threshold", category = "modify")
|
|
+ public static boolean disableMovedWronglyThreshold = false;
|
|
+
|
|
+ @GlobalConfig(name = "mc-technical-survival-mode", category = "modify", verify = McTechnicalModeVerify.class, lock = true)
|
|
+ public static boolean mcTechnicalMode = true;
|
|
+
|
|
+ private static class McTechnicalModeVerify extends ConfigVerify.BooleanConfigVerify {
|
|
+ @Override
|
|
+ public String check(Boolean old, Boolean value) {
|
|
+ if (value) {
|
|
+ top.leavesmc.leaves.util.McTechnicalModeHelper.doMcTechnicalMode();
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "return-nether-portal-fix", category = "modify")
|
|
+ public static boolean netherPortalFix = false;
|
|
+
|
|
+ @GlobalConfig(name = "use-vanilla-random", category = "modify", lock = true, verify = UseVanillaRandomVerify.class)
|
|
+ public static boolean useVanillaRandom = false;
|
|
+
|
|
+ private static class UseVanillaRandomVerify extends ConfigVerify.BooleanConfigVerify {
|
|
+ @Override
|
|
+ public String check(Boolean old, Boolean value) {
|
|
+ LeavesFeatureSet.register(LeavesFeature.of("use_vanilla_random", value));
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "fix-update-suppression-crash", category = "modify")
|
|
+ public static boolean updateSuppressionCrashFix = true;
|
|
+
|
|
+ @GlobalConfig(name = "bedrock-break-list", category = "modify", lock = true)
|
|
+ public static boolean bedrockBreakList = false;
|
|
+
|
|
+ @GlobalConfig(name = "disable-distance-check-for-use-item", category = "modify")
|
|
+ public static boolean disableDistanceCheckForUseItem = false;
|
|
+
|
|
+ @GlobalConfig(name = "no-feather-falling-trample", category = "modify")
|
|
+ public static boolean noFeatherFallingTrample = false;
|
|
+
|
|
+ @GlobalConfig(name = "shared-villager-discounts", category = "modify")
|
|
+ public static boolean sharedVillagerDiscounts = false;
|
|
+
|
|
+ @GlobalConfig(name = "disable-check-out-of-order-command", category = "modify")
|
|
+ public static boolean disableCheckOutOfOrderCommand = false;
|
|
+
|
|
+ @GlobalConfig(name = "despawn-enderman-with-block", category = "modify")
|
|
+ public static boolean despawnEndermanWithBlock = false;
|
|
+
|
|
+ @GlobalConfig(name = "creative-no-clip", category = "modify", verify = CreativeNoClipVerify.class)
|
|
+ public static boolean creativeNoClip = false;
|
|
+
|
|
+ private static class CreativeNoClipVerify extends ConfigVerify.BooleanConfigVerify {
|
|
+ @Override
|
|
+ public String check(Boolean old, Boolean value) {
|
|
+ CarpetRules.register(CarpetRule.of("carpet", "creativeNoClip", value));
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "shave-snow-layers", category = "modify")
|
|
+ public static boolean shaveSnowLayers = true;
|
|
+
|
|
+ @GlobalConfig(name = "ignore-lc", category = "modify")
|
|
+ public static boolean ignoreLC = false;
|
|
+
|
|
+ @GlobalConfig(name = "disable-packet-limit", category = "modify")
|
|
+ public static boolean disablePacketLimit = false;
|
|
+
|
|
+ @GlobalConfig(name = "lava-riptide", category = "modify", verify = LavaRiptideVerify.class)
|
|
+ public static boolean lavaRiptide = false;
|
|
+
|
|
+ private static class LavaRiptideVerify extends ConfigVerify.BooleanConfigVerify {
|
|
+ @Override
|
|
+ public String check(Boolean old, Boolean value) {
|
|
+ LeavesFeatureSet.register(LeavesFeature.of("lava_riptide", value));
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "no-block-update-command", category = "modify", verify = NoBlockUpdateVerify.class)
|
|
+ public static boolean noBlockUpdateCommand = false;
|
|
+
|
|
+ @GlobalConfig(name = "no-tnt-place-update", category = "modify")
|
|
+ public static boolean noTNTPlaceUpdate = false;
|
|
+
|
|
+ private static class NoBlockUpdateVerify extends ConfigVerify.BooleanConfigVerify {
|
|
+ @Override
|
|
+ public String check(Boolean old, Boolean value) {
|
|
+ if (value) {
|
|
+ registerCommand("blockupdate", new top.leavesmc.leaves.command.NoBlockUpdateCommand("blockupdate"));
|
|
+ } else {
|
|
+ unregisterCommand("blockupdate");
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "raider-die-skip-self-raid-check", category = "modify")
|
|
+ public static boolean skipSelfRaidCheck = false;
|
|
+
|
|
+ @GlobalConfig(name = "container-passthrough", category = "modify")
|
|
+ public static boolean containerPassthrough = false;
|
|
+
|
|
+ @GlobalConfig(name = "avoid-anvil-too-expensive", category = "modify", verify = AnvilNotExpensiveVerify.class)
|
|
+ public static boolean avoidAnvilTooExpensive = false;
|
|
+
|
|
+ private static class AnvilNotExpensiveVerify extends ConfigVerify.BooleanConfigVerify {
|
|
+ @Override
|
|
+ public String check(Boolean old, Boolean value) {
|
|
+ CarpetRules.register(CarpetRule.of("pca", "avoidAnvilTooExpensive", value));
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "bow-infinity-fix", category = "modify")
|
|
+ public static boolean bowInfinityFix = false;
|
|
+
|
|
+ @GlobalConfig(name = "hopper-counter", category = "modify")
|
|
+ public static boolean hopperCounter = false;
|
|
+
|
|
+ @GlobalConfig(name = "spider-jockeys-drop-gapples", category = "modify", verify = JockeysDropGAppleVerify.class)
|
|
+ public static double spiderJockeysDropGapples = -1.0;
|
|
+
|
|
+ private static class JockeysDropGAppleVerify extends ConfigVerify.DoubleConfigVerify {
|
|
+ @Override
|
|
+ public String check(Double old, Double value) {
|
|
+ return value <= 1.0 ? null : "spider-jockeys-drop-gapples need <= 1.0f";
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "renewable-deepslate", category = "modify")
|
|
+ public static boolean renewableDeepslate = false;
|
|
+
|
|
+ @GlobalConfig(name = "renewable-sponges", category = "modify")
|
|
+ public static boolean renewableSponges = false;
|
|
+
|
|
+ // Leaves start - modify - removed
|
|
+
|
|
+ @RemovedConfig
|
|
+ @GlobalConfig(name = "tick-command", category = "modify")
|
|
+ public static boolean tickCommand = false;
|
|
+
|
|
+ // Leaves end - modify - removed
|
|
+
|
|
+ // Leaves end - modify
|
|
+
|
|
+ // Leaves start - performance
|
|
+
|
|
+ // Leaves start - performance - fix
|
|
+
|
|
+ @GlobalConfig(name = "fix-paper-6045", category = {"performance", "fix"})
|
|
+ public static boolean fixPaper6045 = true;
|
|
+
|
|
+ @GlobalConfig(name = "fix-paper-9372", category = {"performance", "fix"})
|
|
+ public static boolean fixPaper9372 = true;
|
|
+
|
|
+ // Leaves end - performance - fix
|
|
+
|
|
+ // Leaves start - performance - remove
|
|
+
|
|
+ @GlobalConfig(name = "tick-guard-lambda", category = {"performance", "remove"})
|
|
+ public static boolean removeTickGuardLambda = true;
|
|
+
|
|
+ @GlobalConfig(name = "inventory-contains-iterators", category = {"performance", "remove"})
|
|
+ public static boolean removeInventoryContainsIterators = true;
|
|
+
|
|
+ @GlobalConfig(name = "get-nearby-players-streams", category = {"performance", "remove"})
|
|
+ public static boolean removeGetNearPlayerStreams = true;
|
|
+
|
|
+ @GlobalConfig(name = "range-check-streams-and-iterators", category = {"performance", "remove"})
|
|
+ public static boolean removeRangeCheckStreams = true;
|
|
+
|
|
+ @GlobalConfig(name = "damage-lambda", category = {"performance", "remove"})
|
|
+ public static boolean removeDamageLambda = true;
|
|
+
|
|
+ // Leaves end - performance - remove
|
|
+
|
|
+ @GlobalConfig(name = "optimized-dragon-respawn", category = "performance")
|
|
+ public static boolean optimizedDragonRespawn = false;
|
|
+
|
|
+ @GlobalConfig(name = "dont-send-useless-entity-packets", category = "performance")
|
|
+ public static boolean dontSendUselessEntityPackets = true;
|
|
+
|
|
+ @GlobalConfig(name = "optimize-entity-coordinate-key", category = "performance")
|
|
+ public static boolean optimizeEntityCoordinateKey = true;
|
|
+
|
|
+ @GlobalConfig(name = "enable-suffocation-optimization", category = "performance")
|
|
+ public static boolean enableSuffocationOptimization = true;
|
|
+
|
|
+ @GlobalConfig(name = "strip-raytracing-for-entity", category = "performance")
|
|
+ public static boolean entityStripRaytracing = true;
|
|
+
|
|
+ @GlobalConfig(name = "check-spooky-season-once-an-hour", category = "performance")
|
|
+ public static boolean checkSpookySeasonOnceAnHour = true;
|
|
+
|
|
+ @GlobalConfig(name = "optimize-chunk-ticking", category = "performance", lock = true)
|
|
+ public static boolean optimizeChunkTicking = true;
|
|
+
|
|
+ @GlobalConfig(name = "skip-poi-find-in-vehicle", category = "performance")
|
|
+ public static boolean skipPOIFindingInVehicle = true;
|
|
+
|
|
+ @GlobalConfig(name = "entity-target-find-optimization", category = "performance")
|
|
+ public static boolean entityTargetFindingOptimization = true;
|
|
+
|
|
+ @GlobalConfig(name = "use-more-thread-unsafe-random", category = "performance")
|
|
+ public static boolean useMoreThreadUnsafeRandom = true;
|
|
+
|
|
+ @GlobalConfig(name = "inactive-goal-selector-disable", category = "performance")
|
|
+ public static boolean throttleInactiveGoalSelectorTick = false;
|
|
+
|
|
+ @GlobalConfig(name = "reduce-entity-allocations", category = "performance")
|
|
+ public static boolean reduceEntityAllocations = true;
|
|
+
|
|
+ @GlobalConfig(name = "cache-climb-check", category = "performance")
|
|
+ public static boolean cacheClimbCheck = true;
|
|
+
|
|
+ @GlobalConfig(name = "biome-temperatures-use-aging-cache", category = "performance", lock = true)
|
|
+ public static boolean biomeTemperaturesUseAgingCache = true;
|
|
+
|
|
+ @GlobalConfig(name = "reduce-entity-fluid-lookup", category = "performance")
|
|
+ public static boolean reduceEntityFluidLookup = true;
|
|
+
|
|
+ @GlobalConfig(name = "reduce-chuck-load-and-lookup", category = "performance")
|
|
+ public static boolean reduceChuckLoadAndLookup = true;
|
|
+
|
|
+ @GlobalConfig(name = "improve-fluid-direction-caching", category = "performance", lock = true)
|
|
+ public static boolean improveFluidDirectionCaching = true;
|
|
+
|
|
+ @GlobalConfig(name = "cache-ignite-odds", category = "performance")
|
|
+ public static boolean cacheIgniteOdds = true;
|
|
+
|
|
+ @GlobalConfig(name = "faster-chunk-serialization", category = "performance")
|
|
+ public static boolean fasterChunkSerialization = true;
|
|
+
|
|
+ @GlobalConfig(name = "optimize-world-generation-and-block-access", category = "performance")
|
|
+ public static boolean optimizeWorldGenerationAccess = true;
|
|
+
|
|
+ @GlobalConfig(name = "cache-world-generator-sea-level", category = "performance")
|
|
+ public static boolean cacheWorldGeneratorSeaLevel = true;
|
|
+
|
|
+ @GlobalConfig(name = "skip-secondary-POI-sensor-if-absent", category = "performance")
|
|
+ public static boolean skipSecondaryPOISensorIfAbsent = true;
|
|
+
|
|
+ @GlobalConfig(name = "cache-CubeVoxelShape-shape-array", category = "performance")
|
|
+ public static boolean cacheCubeVoxelShapeShapeArray = true;
|
|
+
|
|
+ @GlobalConfig(name = "store-mob-counts-in-array", category = "performance")
|
|
+ public static boolean storeMobCountsInArray = true;
|
|
+
|
|
+ @GlobalConfig(name = "cache-BlockStatePairKey-hash", category = "performance")
|
|
+ public static boolean cacheBlockStatePairKeyHash = true;
|
|
+
|
|
+ @GlobalConfig(name = "optimize-noise-generation", category = "performance")
|
|
+ public static boolean optimizeNoiseGeneration = false;
|
|
+
|
|
+ @GlobalConfig(name = "optimize-sun-burn-tick", category = "performance")
|
|
+ public static boolean optimizeSunBurnTick = true;
|
|
+
|
|
+ @GlobalConfig(name = "use-optimized-collection", category = "performance")
|
|
+ public static boolean useOptimizedCollection = true;
|
|
+
|
|
+ @GlobalConfig(name = "optimized-CubePointRange", category = "performance")
|
|
+ public static boolean optimizedCubePointRange = true;
|
|
+
|
|
+ @GlobalConfig(name = "check-frozen-ticks-before-landing-block", category = "performance")
|
|
+ public static boolean checkFrozenTicksBeforeLandingBlock = true;
|
|
+
|
|
+ @GlobalConfig(name = "cache-ominous-banner-item", category = "performance")
|
|
+ public static boolean cacheOminousBannerItem = true;
|
|
+
|
|
+ @GlobalConfig(name = "skip-entity-move-if-movement-is-zero", category = "performance")
|
|
+ public static boolean skipEntityMoveIfMovementIsZero = true;
|
|
+
|
|
+ @GlobalConfig(name = "skip-cloning-advancement-criteria", category = "performance")
|
|
+ public static boolean skipCloningAdvancementCriteria = false;
|
|
+
|
|
+ @GlobalConfig(name = "skip-negligible-planar-movement-multiplication", category = "performance")
|
|
+ public static boolean skipNegligiblePlanarMovementMultiplication = true;
|
|
+
|
|
+ @GlobalConfig(name = "fix-villagers-dont-release-memory", category = "performance")
|
|
+ public static boolean villagersDontReleaseMemoryFix = false;
|
|
+
|
|
+ // Leaves start - performance - removed
|
|
+
|
|
+ @RemovedConfig
|
|
+ @GlobalConfig(name = "async-pathfinding", category = "performance")
|
|
+ public static boolean asyncPathfinding = false;
|
|
+
|
|
+ @RemovedConfig
|
|
+ @GlobalConfig(name = "async-mob-spawning", category = "performance")
|
|
+ public static boolean asyncMobSpawning = false;
|
|
+
|
|
+ @RemovedConfig
|
|
+ @GlobalConfig(name = "async-entity-tracker", category = "performance")
|
|
+ public static boolean asyncEntityTracker = false;
|
|
+
|
|
+ // Leaves end - performance - removed
|
|
+
|
|
+ // Leaves end - performance
|
|
+
|
|
+ // Leaves start - protocol
|
|
+
|
|
+ // Leaves start - protocol - bladeren
|
|
+
|
|
+ @GlobalConfig(name = "protocol", category = {"protocol", "bladeren"})
|
|
+ public static boolean bladerenLeavesProtocol = true;
|
|
+
|
|
+ @GlobalConfig(name = "mspt-sync-protocol", category = {"protocol", "bladeren"}, verify = MSPTSyncVerify.class)
|
|
+ public static boolean msptSyncProtocol = false;
|
|
+
|
|
+ private static class MSPTSyncVerify extends ConfigVerify.BooleanConfigVerify {
|
|
+ @Override
|
|
+ public String check(Boolean old, Boolean value) {
|
|
+ LeavesFeatureSet.register(LeavesFeature.of("mspt_sync", value));
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "mspt-sync-tick-interval", category = {"protocol", "bladeren"}, verify = MSPTSyncIntervalVerify.class)
|
|
+ public static int msptSyncTickInterval = 20;
|
|
+
|
|
+ private static class MSPTSyncIntervalVerify extends ConfigVerify.IntConfigVerify {
|
|
+ @Override
|
|
+ public String check(Integer old, Integer value) {
|
|
+ return value > 0 ? null : "mspt-sync-tick-interval need > 0";
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Leaves end - protocol - bladeren
|
|
+
|
|
+ // Leaves start - protocol - syncmatica
|
|
+
|
|
+ @GlobalConfig(name = "enable", category = {"protocol", "syncmatica"}, verify = SyncmaticaVerify.class)
|
|
+ public static boolean syncmaticaProtocol = false;
|
|
+
|
|
+ @GlobalConfig(name = "quota", category = {"protocol", "syncmatica"})
|
|
+ public static boolean syncmaticaQuota = false;
|
|
+
|
|
+ @GlobalConfig(name = "quota-limit", category = {"protocol", "syncmatica"}, verify = ConfigVerify.IntConfigVerify.class)
|
|
+ public static int syncmaticaQuotaLimit = 40000000;
|
|
+
|
|
+ public static class SyncmaticaVerify extends ConfigVerify.BooleanConfigVerify {
|
|
+ @Override
|
|
+ public String check(Boolean old, Boolean value) {
|
|
+ if (value) {
|
|
+ top.leavesmc.leaves.protocol.syncmatica.SyncmaticaProtocol.init();
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Leaves end - protocol - syncmatica
|
|
+
|
|
+ @GlobalConfig(name = "pca-sync-protocol", category = "protocol")
|
|
+ public static boolean pcaSyncProtocol = false;
|
|
+
|
|
+ @GlobalConfig(name = "pca-sync-player-entity", category = "protocol", verify = PcaPlayerEntityVerify.class)
|
|
+ public static String pcaSyncPlayerEntity = "OPS";
|
|
+
|
|
+ private static class PcaPlayerEntityVerify extends ConfigVerify.StringConfigVerify {
|
|
+ private static final List<String> pcaSyncPlayerEntityList = List.of("NOBODY", "BOT", "OPS", "OPS_AND_SELF", "EVERYONE");
|
|
+
|
|
+ @Override
|
|
+ public String check(String old, String value) {
|
|
+ if (!pcaSyncPlayerEntityList.contains(value)) {
|
|
+ return "pca-sync-player-entity value error";
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "bbor-protocol", category = "protocol")
|
|
+ public static boolean bborProtocol = false;
|
|
+
|
|
+ @GlobalConfig(name = "jade-protocol", category = "protocol")
|
|
+ public static boolean jadeProtocol = false;
|
|
+
|
|
+ @GlobalConfig(name = "alternative-block-placement", category = "protocol", verify = AlternativePlaceVerify.class)
|
|
+ public static String alternativeBlockPlacement = "NONE";
|
|
+
|
|
+
|
|
+ private static class AlternativePlaceVerify extends ConfigVerify.StringConfigVerify {
|
|
+ private static final List<String> alternativeBlockPlacementType = List.of("NONE", "CARPET", "CARPET_FIX", "LITEMATICA");
|
|
+
|
|
+ @Override
|
|
+ public String check(String old, String value) {
|
|
+ if (!alternativeBlockPlacementType.contains(value)) {
|
|
+ return "alternative-block-placement value error";
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "appleskin-protocol", category = "protocol")
|
|
+ public static boolean appleskinProtocol = false;
|
|
+
|
|
+ @GlobalConfig(name = "xaero-map-protocol", category = "protocol")
|
|
+ public static boolean xaeroMapProtocol = false;
|
|
+
|
|
+ @GlobalConfig(name = "xaero-map-server-id", category = "protocol", verify = ConfigVerify.IntConfigVerify.class)
|
|
+ public static int xaeroMapServerID = new Random().nextInt();
|
|
+
|
|
+ @GlobalConfig(name = "servux-protocol", category = "protocol")
|
|
+ public static boolean servuxProtocol = false;
|
|
+
|
|
+ @GlobalConfig(name = "leaves-carpet-support", category = "protocol")
|
|
+ public static boolean leavesCarpetSupport = false;
|
|
+
|
|
+ // Leaves end - protocol
|
|
+
|
|
+ // Leaves start - misc
|
|
+
|
|
+ // Leaves start - misc - auto-update
|
|
+
|
|
+ @GlobalConfig(name = "enable", category = {"misc", "auto-update"}, lock = true, verify = AutoUpdateVerify.class)
|
|
+ public static boolean autoUpdate = false;
|
|
+
|
|
+ private static class AutoUpdateVerify extends ConfigVerify.BooleanConfigVerify {
|
|
+ @Override
|
|
+ public void runAfterLoader(Boolean value) {
|
|
+ top.leavesmc.leaves.util.LeavesUpdateHelper.init();
|
|
+ if (value) {
|
|
+ LeavesLogger.LOGGER.warning("Auto-Update is not completely safe. Enabling it may cause data security problems!");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "time", category = {"misc", "auto-update"}, lock = true, verify = ConfigVerify.ListConfigVerify.class)
|
|
+ public static List<String> autoUpdateTime = List.of("14:00", "2:00");
|
|
+
|
|
+ // Leaves end - misc - auto-update
|
|
+
|
|
+ // Leaves start - misc - extra-yggdrasil-service
|
|
+
|
|
+ @GlobalConfig(name = "enable", category = {"misc", "extra-yggdrasil-service"}, verify = ExtraYggdrasilVerify.class)
|
|
+ public static boolean extraYggdrasilService = false;
|
|
+
|
|
+ public static class ExtraYggdrasilVerify extends ConfigVerify.BooleanConfigVerify {
|
|
+ @Override
|
|
+ public String check(Boolean old, Boolean value) {
|
|
+ if (value) {
|
|
+ LeavesLogger.LOGGER.warning("extra-yggdrasil-service is an unofficial support. Enabling it may cause data security problems!");
|
|
+ GlobalConfiguration.get().unsupportedSettings.performUsernameValidation = true; // always check username
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "login-protect", category = {"misc", "extra-yggdrasil-service"})
|
|
+ public static boolean extraYggdrasilLoginProtect = false;
|
|
+
|
|
+ @GlobalConfig(name = "urls", category = {"misc", "extra-yggdrasil-service"}, verify = ExtraYggdrasilUrlsVerify.class)
|
|
+ public static List<String> extraYggdrasilServiceList = List.of("https://url.with.authlib-injector-yggdrasil");
|
|
+
|
|
+ public static class ExtraYggdrasilUrlsVerify extends ConfigVerify.ListConfigVerify {
|
|
+ @Override
|
|
+ public String check(List<?> old, List<?> value) {
|
|
+ top.leavesmc.leaves.profile.LeavesMinecraftSessionService.initExtraYggdrasilList();
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // Leaves end - misc - extra-yggdrasil-service
|
|
+
|
|
+ @GlobalConfig(name = "disable-method-profiler", category = "misc")
|
|
+ public static boolean disableMethodProfiler = true;
|
|
+
|
|
+ @GlobalConfig(name = "no-chat-sign", category = "misc")
|
|
+ public static boolean noChatSign = true;
|
|
+
|
|
+ @GlobalConfig(name = "dont-respond-ping-before-start-fully", category = "misc")
|
|
+ public static boolean dontRespondPingBeforeStart = true;
|
|
+
|
|
+ @GlobalConfig(name = "server-lang", category = "misc", lock = true, verify = ServerLangVerify.class)
|
|
+ public static String serverLang = "en_us";
|
|
+
|
|
+ private static class ServerLangVerify extends ConfigVerify.StringConfigVerify {
|
|
+ private static final List<String> supportLang = List.of("en_us", "zh_cn");
|
|
+
|
|
+ @Override
|
|
+ public String check(String old, String value) {
|
|
+ if (!supportLang.contains(value)) {
|
|
+ return "server-lang value error";
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "server-mod-name", category = "misc", verify = ConfigVerify.StringConfigVerify.class)
|
|
+ public static String serverModName = "Leaves";
|
|
+
|
|
+ @GlobalConfig(name = "bstats-privacy-mode", category = "misc")
|
|
+ public static boolean bstatsPrivacyMode = false;
|
|
+
|
|
+ // Leaves end - misc
|
|
+
|
|
+ // Leaves start - region
|
|
+ public static top.leavesmc.leaves.region.RegionFileFormat regionFormatName = top.leavesmc.leaves.region.RegionFileFormat.ANVIL;
|
|
+ @GlobalConfig(name = "format", category = "region", lock = true, verify = RegionFormatVerify.class)
|
|
+ public static String regionFormat = "ANVIL";
|
|
+
|
|
+ private static class RegionFormatVerify extends ConfigVerify.StringConfigVerify {
|
|
+ @Override
|
|
+ public String check(String old, String value) {
|
|
+ top.leavesmc.leaves.region.RegionFileFormat format = top.leavesmc.leaves.region.RegionFileFormat.fromString(value);
|
|
+ if (format == top.leavesmc.leaves.region.RegionFileFormat.INVALID) {
|
|
+ return "Unknown region format " + value;
|
|
+ }
|
|
+ regionFormatName = format;
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "flush-frequency", category = {"region", "linear"}, lock = true, verify = ConfigVerify.IntConfigVerify.class)
|
|
+ public static int linearFlushFrequency = 10;
|
|
+
|
|
+ @GlobalConfig(name = "flush-max-threads", category = {"region", "linear"}, lock = true, verify = ConfigVerify.IntConfigVerify.class)
|
|
+ public static int linearFlushThreads = 1;
|
|
+
|
|
+ public static int getLinearFlushThreads() {
|
|
+ if (linearFlushThreads < 0) {
|
|
+ return Math.max(Runtime.getRuntime().availableProcessors() + linearFlushThreads, 1);
|
|
+ } else {
|
|
+ return Math.max(linearFlushThreads, 1);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "compression-level", category = {"region", "linear"}, lock = true, verify = LinearCompressVerify.class)
|
|
+ public static int linearCompressionLevel = 1;
|
|
+
|
|
+ private static class LinearCompressVerify extends ConfigVerify.IntConfigVerify {
|
|
+ @Override
|
|
+ public String check(Integer old, Integer value) {
|
|
+ if (value < 1 || value > 22) {
|
|
+ return "linear.compression-level need between 1 and 22";
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(name = "crash-on-broken-symlink", category = {"region", "linear"}, lock = true)
|
|
+ public static boolean linearCrashOnBrokenSymlink = true;
|
|
+
|
|
+ // Leaves end - region
|
|
+}
|
|
diff --git a/src/main/java/top/leavesmc/leaves/command/CommandArgument.java b/src/main/java/top/leavesmc/leaves/command/CommandArgument.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..eadc6d168fb13299348b0c275ae352ee2f1e1ea2
|
|
--- /dev/null
|
|
+++ b/src/main/java/top/leavesmc/leaves/command/CommandArgument.java
|
|
@@ -0,0 +1,43 @@
|
|
+package top.leavesmc.leaves.command;
|
|
+
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+
|
|
+import java.util.ArrayList;
|
|
+import java.util.Arrays;
|
|
+import java.util.List;
|
|
+
|
|
+public class CommandArgument {
|
|
+
|
|
+ private final List<CommandArgumentType<?>> argumentTypes;
|
|
+ private final List<List<String>> tabComplete;
|
|
+
|
|
+ public CommandArgument(CommandArgumentType<?>... argumentTypes) {
|
|
+ this.argumentTypes = List.of(argumentTypes);
|
|
+ this.tabComplete = new ArrayList<>();
|
|
+ for (int i = 0; i < argumentTypes.length; i++) {
|
|
+ tabComplete.add(new ArrayList<>());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public List<String> tabComplete(int n) {
|
|
+ if (tabComplete.size() > n) {
|
|
+ return tabComplete.get(n);
|
|
+ } else {
|
|
+ return List.of();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public CommandArgument setTabComplete(int index, List<String> list) {
|
|
+ tabComplete.set(index, list);
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ public CommandArgumentResult parse(int index, String @NotNull [] args) {
|
|
+ Object[] result = new Object[argumentTypes.size()];
|
|
+ Arrays.fill(result, null);
|
|
+ for (int i = index, j = 0; i < args.length && j < result.length; i++, j++) {
|
|
+ result[j] = argumentTypes.get(j).pasre(args[i]);
|
|
+ }
|
|
+ return new CommandArgumentResult(new ArrayList<>(Arrays.asList(result)));
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/top/leavesmc/leaves/command/CommandArgumentResult.java b/src/main/java/top/leavesmc/leaves/command/CommandArgumentResult.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..340eaca64c96180b895a075ce9e44402cd104eed
|
|
--- /dev/null
|
|
+++ b/src/main/java/top/leavesmc/leaves/command/CommandArgumentResult.java
|
|
@@ -0,0 +1,62 @@
|
|
+package top.leavesmc.leaves.command;
|
|
+
|
|
+import net.minecraft.core.BlockPos;
|
|
+import org.bukkit.util.Vector;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.Objects;
|
|
+
|
|
+public class CommandArgumentResult {
|
|
+
|
|
+ private final List<Object> result;
|
|
+
|
|
+ public CommandArgumentResult(List<Object> result) {
|
|
+ this.result = result;
|
|
+ }
|
|
+
|
|
+ public Integer readInt(int def) {
|
|
+ return Objects.requireNonNullElse(read(Integer.class), def);
|
|
+ }
|
|
+
|
|
+ public Double readDouble(double def) {
|
|
+ return Objects.requireNonNullElse(read(Double.class), def);
|
|
+ }
|
|
+
|
|
+ public String readString(String def) {
|
|
+ return Objects.requireNonNullElse(read(String.class), def);
|
|
+ }
|
|
+
|
|
+ public BlockPos readPos() {
|
|
+ Integer[] pos = {read(Integer.class), read(Integer.class), read(Integer.class)};
|
|
+ for (Integer po : pos) {
|
|
+ if (po == null) {
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+ return new BlockPos(pos[0], pos[1], pos[2]);
|
|
+ }
|
|
+
|
|
+ public Vector readVector() {
|
|
+ Double[] pos = {read(Double.class), read(Double.class), read(Double.class)};
|
|
+ for (Double po : pos) {
|
|
+ if (po == null) {
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+ return new Vector(pos[0], pos[1], pos[2]);
|
|
+ }
|
|
+
|
|
+ public <T> T read(Class<T> tClass) {
|
|
+ if (result.isEmpty()) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ Object obj = result.remove(0);
|
|
+ if (tClass.isInstance(obj)) {
|
|
+ return tClass.cast(obj);
|
|
+ } else {
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+
|
|
+}
|
|
diff --git a/src/main/java/top/leavesmc/leaves/command/CommandArgumentType.java b/src/main/java/top/leavesmc/leaves/command/CommandArgumentType.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..edf12195c7224ca2fb5d3c2ac3fcf485d3049d07
|
|
--- /dev/null
|
|
+++ b/src/main/java/top/leavesmc/leaves/command/CommandArgumentType.java
|
|
@@ -0,0 +1,37 @@
|
|
+package top.leavesmc.leaves.command;
|
|
+
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+
|
|
+public abstract class CommandArgumentType<E> {
|
|
+
|
|
+ public static final CommandArgumentType<Integer> INTEGER = new CommandArgumentType<>() {
|
|
+ @Override
|
|
+ public Integer pasre(@NotNull String arg) {
|
|
+ try {
|
|
+ return Integer.parseInt(arg);
|
|
+ } catch (NumberFormatException e) {
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+
|
|
+ public static final CommandArgumentType<Double> DOUBLE = new CommandArgumentType<>() {
|
|
+ @Override
|
|
+ public Double pasre(@NotNull String arg) {
|
|
+ try {
|
|
+ return Double.parseDouble(arg);
|
|
+ } catch (NumberFormatException e) {
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+
|
|
+ public static final CommandArgumentType<String> STRING = new CommandArgumentType<>() {
|
|
+ @Override
|
|
+ public String pasre(@NotNull String arg) {
|
|
+ return arg;
|
|
+ }
|
|
+ };
|
|
+
|
|
+ public abstract E pasre(@NotNull String arg);
|
|
+}
|
|
diff --git a/src/main/java/top/leavesmc/leaves/command/LeavesCommand.java b/src/main/java/top/leavesmc/leaves/command/LeavesCommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..9b6fb546a672fa5b27047fec638e42b2b5dbf533
|
|
--- /dev/null
|
|
+++ b/src/main/java/top/leavesmc/leaves/command/LeavesCommand.java
|
|
@@ -0,0 +1,118 @@
|
|
+package top.leavesmc.leaves.command;
|
|
+
|
|
+import io.papermc.paper.command.CommandUtil;
|
|
+import it.unimi.dsi.fastutil.Pair;
|
|
+import net.minecraft.Util;
|
|
+import org.bukkit.Bukkit;
|
|
+import org.bukkit.Location;
|
|
+import org.bukkit.command.Command;
|
|
+import org.bukkit.command.CommandSender;
|
|
+import org.bukkit.permissions.Permission;
|
|
+import org.bukkit.permissions.PermissionDefault;
|
|
+import org.bukkit.plugin.PluginManager;
|
|
+import org.checkerframework.checker.nullness.qual.Nullable;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import top.leavesmc.leaves.command.subcommands.ConfigCommand;
|
|
+
|
|
+import java.util.ArrayList;
|
|
+import java.util.Arrays;
|
|
+import java.util.Collections;
|
|
+import java.util.HashMap;
|
|
+import java.util.List;
|
|
+import java.util.Locale;
|
|
+import java.util.Map;
|
|
+import java.util.Set;
|
|
+import java.util.stream.Collectors;
|
|
+
|
|
+import static net.kyori.adventure.text.Component.text;
|
|
+import static net.kyori.adventure.text.format.NamedTextColor.RED;
|
|
+
|
|
+public final class LeavesCommand extends Command {
|
|
+ static final String BASE_PERM = "bukkit.command.leaves.";
|
|
+ // subcommand label -> subcommand
|
|
+ private static final Map<String, LeavesSubcommand> SUBCOMMANDS = Util.make(() -> {
|
|
+ final Map<Set<String>, LeavesSubcommand> commands = new HashMap<>();
|
|
+ commands.put(Set.of("config"), new ConfigCommand());
|
|
+
|
|
+ return commands.entrySet().stream()
|
|
+ .flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue())))
|
|
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
|
+ });
|
|
+ private static final Set<String> COMPLETABLE_SUBCOMMANDS = SUBCOMMANDS.entrySet().stream().filter(entry -> entry.getValue().tabCompletes()).map(Map.Entry::getKey).collect(Collectors.toSet());
|
|
+
|
|
+ public LeavesCommand(final String name) {
|
|
+ super(name);
|
|
+ this.description = "Leaves related commands";
|
|
+ this.usageMessage = "/leaves [" + String.join(" | ", SUBCOMMANDS.keySet()) + "]";
|
|
+ final List<String> permissions = new ArrayList<>();
|
|
+ permissions.add("bukkit.command.leaves");
|
|
+ permissions.addAll(SUBCOMMANDS.keySet().stream().map(s -> BASE_PERM + s).toList());
|
|
+ this.setPermission(String.join(";", permissions));
|
|
+ final PluginManager pluginManager = Bukkit.getServer().getPluginManager();
|
|
+ for (final String perm : permissions) {
|
|
+ if (pluginManager.getPermission(perm) == null) {
|
|
+ pluginManager.addPermission(new Permission(perm, PermissionDefault.OP));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static boolean testPermission(final CommandSender sender, final String permission) {
|
|
+ if (sender.hasPermission(BASE_PERM + permission) || sender.hasPermission("bukkit.command.leaves")) {
|
|
+ return true;
|
|
+ }
|
|
+ sender.sendMessage(Bukkit.permissionMessage());
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ @NotNull
|
|
+
|
|
+ @Override
|
|
+ public List<String> tabComplete(final @NotNull CommandSender sender, final @NotNull String alias, final String[] args, final @Nullable Location location) throws IllegalArgumentException {
|
|
+ if (args.length <= 1) {
|
|
+ return CommandUtil.getListMatchingLast(sender, args, COMPLETABLE_SUBCOMMANDS);
|
|
+ }
|
|
+
|
|
+ final @Nullable Pair<String, LeavesSubcommand> subCommand = resolveCommand(args[0]);
|
|
+ if (subCommand != null) {
|
|
+ return subCommand.second().tabComplete(sender, subCommand.first(), Arrays.copyOfRange(args, 1, args.length));
|
|
+ }
|
|
+
|
|
+ return Collections.emptyList();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean execute(final @NotNull CommandSender sender, final @NotNull String commandLabel, final String[] args) {
|
|
+ if (!testPermission(sender)) {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ if (args.length == 0) {
|
|
+ sender.sendMessage(text("Usage: " + this.usageMessage, RED));
|
|
+ return false;
|
|
+ }
|
|
+ final Pair<String, LeavesSubcommand> subCommand = resolveCommand(args[0]);
|
|
+
|
|
+ if (subCommand == null) {
|
|
+ sender.sendMessage(text("Usage: " + this.usageMessage, RED));
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (!testPermission(sender, subCommand.first())) {
|
|
+ return true;
|
|
+ }
|
|
+ final String[] choppedArgs = Arrays.copyOfRange(args, 1, args.length);
|
|
+ return subCommand.second().execute(sender, subCommand.first(), choppedArgs);
|
|
+ }
|
|
+
|
|
+ @Nullable
|
|
+ private static Pair<String, LeavesSubcommand> resolveCommand(String label) {
|
|
+ label = label.toLowerCase(Locale.ENGLISH);
|
|
+ LeavesSubcommand subCommand = SUBCOMMANDS.get(label);
|
|
+
|
|
+ if (subCommand != null) {
|
|
+ return Pair.of(label, subCommand);
|
|
+ }
|
|
+
|
|
+ return null;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/top/leavesmc/leaves/command/LeavesSubcommand.java b/src/main/java/top/leavesmc/leaves/command/LeavesSubcommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..7ba1b573c8e49cc0838c25bc26687d14841a9e7f
|
|
--- /dev/null
|
|
+++ b/src/main/java/top/leavesmc/leaves/command/LeavesSubcommand.java
|
|
@@ -0,0 +1,18 @@
|
|
+package top.leavesmc.leaves.command;
|
|
+
|
|
+import org.bukkit.command.CommandSender;
|
|
+
|
|
+import java.util.Collections;
|
|
+import java.util.List;
|
|
+
|
|
+public interface LeavesSubcommand {
|
|
+ boolean execute(CommandSender sender, String subCommand, String[] args);
|
|
+
|
|
+ default List<String> tabComplete(final CommandSender sender, final String subCommand, final String[] args) {
|
|
+ return Collections.emptyList();
|
|
+ }
|
|
+
|
|
+ default boolean tabCompletes() {
|
|
+ return true;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/top/leavesmc/leaves/command/subcommands/ConfigCommand.java b/src/main/java/top/leavesmc/leaves/command/subcommands/ConfigCommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..205e563ed4b3f59e294c2866952c73d22bd367b0
|
|
--- /dev/null
|
|
+++ b/src/main/java/top/leavesmc/leaves/command/subcommands/ConfigCommand.java
|
|
@@ -0,0 +1,86 @@
|
|
+package top.leavesmc.leaves.command.subcommands;
|
|
+
|
|
+import io.papermc.paper.command.CommandUtil;
|
|
+import net.kyori.adventure.text.Component;
|
|
+import net.kyori.adventure.text.JoinConfiguration;
|
|
+import net.kyori.adventure.text.format.NamedTextColor;
|
|
+import org.bukkit.command.CommandSender;
|
|
+import top.leavesmc.leaves.command.LeavesSubcommand;
|
|
+import top.leavesmc.leaves.config.GlobalConfigManager;
|
|
+
|
|
+import java.util.ArrayList;
|
|
+import java.util.Collections;
|
|
+import java.util.List;
|
|
+
|
|
+public class ConfigCommand implements LeavesSubcommand {
|
|
+
|
|
+ @Override
|
|
+ public boolean execute(CommandSender sender, String subCommand, String[] args) {
|
|
+ if (args.length < 1) {
|
|
+ sender.sendMessage(Component.text("Leaves Config", NamedTextColor.GRAY));
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ GlobalConfigManager.VerifiedConfig verifiedConfig = GlobalConfigManager.getVerifiedConfig(args[0]);
|
|
+ if (verifiedConfig == null) {
|
|
+ sender.sendMessage(Component.join(JoinConfiguration.noSeparators(),
|
|
+ Component.text("Config ", NamedTextColor.GRAY),
|
|
+ Component.text(args[0], NamedTextColor.RED),
|
|
+ Component.text(" is Not Found.", NamedTextColor.GRAY)
|
|
+ ));
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ if (args.length > 1) {
|
|
+ try {
|
|
+ verifiedConfig.set(args[1]);
|
|
+ sender.sendMessage(Component.join(JoinConfiguration.noSeparators(),
|
|
+ Component.text("Config ", NamedTextColor.GRAY),
|
|
+ Component.text(args[0], NamedTextColor.AQUA),
|
|
+ Component.text(" changed to ", NamedTextColor.GRAY),
|
|
+ Component.text(verifiedConfig.getString(), NamedTextColor.AQUA)
|
|
+ ));
|
|
+ } catch (IllegalArgumentException exception) {
|
|
+ sender.sendMessage(Component.join(JoinConfiguration.noSeparators(),
|
|
+ Component.text("Config ", NamedTextColor.GRAY),
|
|
+ Component.text(args[0], NamedTextColor.RED),
|
|
+ Component.text(" modify error by ", NamedTextColor.GRAY),
|
|
+ Component.text(exception.getMessage(), NamedTextColor.RED)
|
|
+ ));
|
|
+ }
|
|
+ } else {
|
|
+ sender.sendMessage(Component.join(JoinConfiguration.noSeparators(),
|
|
+ Component.text("Config ", NamedTextColor.GRAY),
|
|
+ Component.text(args[0], NamedTextColor.AQUA),
|
|
+ Component.text(" value is ", NamedTextColor.GRAY),
|
|
+ Component.text(verifiedConfig.getString(), NamedTextColor.AQUA)
|
|
+ ));
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public List<String> tabComplete(CommandSender sender, String subCommand, String[] args) {
|
|
+ switch (args.length) {
|
|
+ case 1 -> {
|
|
+ List<String> list = new ArrayList<>(GlobalConfigManager.getVerifiedConfigPaths());
|
|
+ return CommandUtil.getListMatchingLast(sender, args, list);
|
|
+ }
|
|
+
|
|
+ case 2 -> {
|
|
+ GlobalConfigManager.VerifiedConfig verifiedConfig = GlobalConfigManager.getVerifiedConfig(args[0]);
|
|
+ if (verifiedConfig != null) {
|
|
+ if (verifiedConfig.config().lock()) {
|
|
+ return Collections.singletonList("<LOCKED CONFIG>");
|
|
+ }
|
|
+ return CommandUtil.getListMatchingLast(sender, args, verifiedConfig.verify().valueSuggest());
|
|
+ } else {
|
|
+ return Collections.singletonList("<ERROR CONFIG>");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return Collections.emptyList();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/top/leavesmc/leaves/config/ConfigVerify.java b/src/main/java/top/leavesmc/leaves/config/ConfigVerify.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..6cd0d02ed56140752d40642d8fcf7dc51423210a
|
|
--- /dev/null
|
|
+++ b/src/main/java/top/leavesmc/leaves/config/ConfigVerify.java
|
|
@@ -0,0 +1,60 @@
|
|
+package top.leavesmc.leaves.config;
|
|
+
|
|
+import java.util.List;
|
|
+
|
|
+public interface ConfigVerify<E> {
|
|
+
|
|
+ default String check(E old, E value) {
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ E convert(String value);
|
|
+
|
|
+ default List<String> valueSuggest() {
|
|
+ return List.of("<value>");
|
|
+ }
|
|
+
|
|
+ default void runAfterLoader(E value) {
|
|
+ }
|
|
+
|
|
+ class BooleanConfigVerify implements ConfigVerify<Boolean> {
|
|
+
|
|
+ @Override
|
|
+ public Boolean convert(String value) {
|
|
+ return Boolean.parseBoolean(value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public List<String> valueSuggest() {
|
|
+ return List.of("false", "true");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ class IntConfigVerify implements ConfigVerify<Integer> {
|
|
+ @Override
|
|
+ public Integer convert(String value) {
|
|
+ return Integer.parseInt(value);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ class StringConfigVerify implements ConfigVerify<String> {
|
|
+ @Override
|
|
+ public String convert(String value) {
|
|
+ return value;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ class DoubleConfigVerify implements ConfigVerify<Double> {
|
|
+ @Override
|
|
+ public Double convert(String value) {
|
|
+ return Double.parseDouble(value);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ class ListConfigVerify implements ConfigVerify<List<?>> {
|
|
+ @Override
|
|
+ public List<?> convert(String value) {
|
|
+ throw new IllegalArgumentException("not support"); // TODO
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/top/leavesmc/leaves/config/GlobalConfig.java b/src/main/java/top/leavesmc/leaves/config/GlobalConfig.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..f6b946e5dfb5e3a2c169f88e8fb54718b0ca84ea
|
|
--- /dev/null
|
|
+++ b/src/main/java/top/leavesmc/leaves/config/GlobalConfig.java
|
|
@@ -0,0 +1,19 @@
|
|
+package top.leavesmc.leaves.config;
|
|
+
|
|
+import java.lang.annotation.ElementType;
|
|
+import java.lang.annotation.Retention;
|
|
+import java.lang.annotation.RetentionPolicy;
|
|
+import java.lang.annotation.Target;
|
|
+
|
|
+@Target(ElementType.FIELD)
|
|
+@Retention(RetentionPolicy.RUNTIME)
|
|
+public @interface GlobalConfig {
|
|
+
|
|
+ String name();
|
|
+
|
|
+ String[] category();
|
|
+
|
|
+ boolean lock() default false;
|
|
+
|
|
+ Class<? extends ConfigVerify<?>> verify() default ConfigVerify.BooleanConfigVerify.class;
|
|
+}
|
|
diff --git a/src/main/java/top/leavesmc/leaves/config/GlobalConfigManager.java b/src/main/java/top/leavesmc/leaves/config/GlobalConfigManager.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..55899c275c496fc6441fbb15b22bb89406e587ae
|
|
--- /dev/null
|
|
+++ b/src/main/java/top/leavesmc/leaves/config/GlobalConfigManager.java
|
|
@@ -0,0 +1,133 @@
|
|
+package top.leavesmc.leaves.config;
|
|
+
|
|
+import org.bukkit.Bukkit;
|
|
+import top.leavesmc.leaves.LeavesConfig;
|
|
+import top.leavesmc.leaves.LeavesLogger;
|
|
+
|
|
+import java.lang.reflect.Constructor;
|
|
+import java.lang.reflect.Field;
|
|
+import java.lang.reflect.Modifier;
|
|
+import java.util.HashMap;
|
|
+import java.util.Map;
|
|
+import java.util.Set;
|
|
+import java.util.logging.Level;
|
|
+
|
|
+public class GlobalConfigManager {
|
|
+
|
|
+ private static boolean firstLoad = true;
|
|
+ private static final Map<String, VerifiedConfig> verifiedConfigs = new HashMap<>();
|
|
+
|
|
+ public static void init() {
|
|
+ verifiedConfigs.clear();
|
|
+
|
|
+ Class<LeavesConfig> clazz = LeavesConfig.class;
|
|
+ for (Field field : clazz.getDeclaredFields()) {
|
|
+ if (Modifier.isStatic(field.getModifiers())) {
|
|
+ GlobalConfig globalConfig = field.getAnnotation(GlobalConfig.class);
|
|
+ if (globalConfig != null) {
|
|
+ try {
|
|
+ VerifiedConfig verifiedConfig = VerifiedConfig.build(globalConfig, field);
|
|
+ if (field.getAnnotation(RemovedConfig.class) != null) {
|
|
+ LeavesConfig.config.set(verifiedConfig.path, null);
|
|
+ } else {
|
|
+ field.setAccessible(true);
|
|
+ if (globalConfig.lock() && !firstLoad) {
|
|
+ continue;
|
|
+ }
|
|
+ Object defValue = field.get(null);
|
|
+ LeavesConfig.config.addDefault(verifiedConfig.path, defValue);
|
|
+
|
|
+ Object savedValue = LeavesConfig.config.get(verifiedConfig.path);
|
|
+ String checkInfo = verifiedConfig.verify.check(null, savedValue);
|
|
+ if (checkInfo == null) {
|
|
+ field.set(null, savedValue);
|
|
+ } else {
|
|
+ LeavesConfig.config.set(verifiedConfig.path, defValue);
|
|
+ LeavesLogger.LOGGER.warning(checkInfo + ", reset to " + defValue);
|
|
+ }
|
|
+
|
|
+ verifiedConfigs.put(verifiedConfig.path.substring("settings.".length()), verifiedConfig);
|
|
+ }
|
|
+ } catch (Exception e) {
|
|
+ Bukkit.getLogger().log(Level.SEVERE, "Failure to load leaves config", e);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ verifiedConfigs.forEach((path, config) -> config.verify.runAfterLoader(config.get()));
|
|
+
|
|
+ firstLoad = false;
|
|
+ LeavesConfig.save();
|
|
+ }
|
|
+
|
|
+ public static VerifiedConfig getVerifiedConfig(String path) {
|
|
+ return verifiedConfigs.get(path);
|
|
+ }
|
|
+
|
|
+ public static Set<String> getVerifiedConfigPaths() {
|
|
+ return verifiedConfigs.keySet();
|
|
+ }
|
|
+
|
|
+ public record VerifiedConfig(GlobalConfig config, ConfigVerify<? super Object> verify, Field field, String path) {
|
|
+
|
|
+ public void set(String realValue) throws IllegalArgumentException {
|
|
+ if (config.lock()) {
|
|
+ throw new IllegalArgumentException("locked");
|
|
+ }
|
|
+
|
|
+ Object value;
|
|
+ try {
|
|
+ value = verify.convert(realValue);
|
|
+ } catch (Exception e) {
|
|
+ throw new IllegalArgumentException("value parse error: " + e.getMessage());
|
|
+ }
|
|
+
|
|
+ String checkInfo = verify.check(this.get(), value);
|
|
+ if (checkInfo != null) {
|
|
+ throw new IllegalArgumentException(checkInfo);
|
|
+ }
|
|
+
|
|
+ try {
|
|
+ field.set(null, value);
|
|
+ LeavesConfig.config.set(path, value);
|
|
+ LeavesConfig.save();
|
|
+ } catch (IllegalAccessException e) {
|
|
+ throw new IllegalArgumentException("?");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public String getString() {
|
|
+ return this.get().toString();
|
|
+ }
|
|
+
|
|
+ public Object get() {
|
|
+ try {
|
|
+ return field.get(null);
|
|
+ } catch (IllegalAccessException e) {
|
|
+ LeavesLogger.LOGGER.log(Level.SEVERE, "Failure to get " + path + " value", e);
|
|
+ return "<VALUE ERROR>";
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static VerifiedConfig build(GlobalConfig config, Field field) {
|
|
+ StringBuilder path = new StringBuilder("settings.");
|
|
+ for (int i = 0; i < config.category().length; i++) {
|
|
+ path.append(config.category()[i]).append(".");
|
|
+ }
|
|
+ path.append(config.name());
|
|
+
|
|
+ ConfigVerify configVerify = null;
|
|
+ try {
|
|
+ Constructor<? extends ConfigVerify<?>> constructor = config.verify().getDeclaredConstructor();
|
|
+ constructor.setAccessible(true);
|
|
+ configVerify = constructor.newInstance();
|
|
+ } catch (Exception e) {
|
|
+ e.printStackTrace();
|
|
+ }
|
|
+
|
|
+
|
|
+ return new VerifiedConfig(config, configVerify, field, path.toString());
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/top/leavesmc/leaves/config/RemovedConfig.java b/src/main/java/top/leavesmc/leaves/config/RemovedConfig.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..942992b3aba4492be7b24854129a570377fa17bc
|
|
--- /dev/null
|
|
+++ b/src/main/java/top/leavesmc/leaves/config/RemovedConfig.java
|
|
@@ -0,0 +1,12 @@
|
|
+package top.leavesmc.leaves.config;
|
|
+
|
|
+import java.lang.annotation.ElementType;
|
|
+import java.lang.annotation.Retention;
|
|
+import java.lang.annotation.RetentionPolicy;
|
|
+import java.lang.annotation.Target;
|
|
+
|
|
+@Target(ElementType.FIELD)
|
|
+@Retention(RetentionPolicy.RUNTIME)
|
|
+public @interface RemovedConfig {
|
|
+
|
|
+}
|