mirror of
https://github.com/LeavesMC/Leaves.git
synced 2025-12-19 14:59:32 +00:00
2052 lines
84 KiB
Diff
2052 lines
84 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/build.gradle.kts b/build.gradle.kts
|
|
index d88a9d1908373ba44143013cda1ae51477a835cf..b8132401ddaedf13bc9ddc74524166d0e0dcf419 100644
|
|
--- a/build.gradle.kts
|
|
+++ b/build.gradle.kts
|
|
@@ -240,6 +240,14 @@ tasks.registerRunTask("runDevServer") {
|
|
jvmArgs("-DPaper.pushPaperAssetsRoot=true")
|
|
}
|
|
|
|
+// Leaves start - create config file
|
|
+tasks.registerRunTask("createLeavesConfig") {
|
|
+ description = "Create a new leaves.yml"
|
|
+ mainClass = "org.leavesmc.leaves.config.GlobalConfigCreator"
|
|
+ classpath(sourceSets.main.map { it.runtimeClasspath })
|
|
+}
|
|
+// Leaves end - create config file
|
|
+
|
|
tasks.registerRunTask("runBundler") {
|
|
description = "Spin up a test server from the Mojang mapped bundler jar"
|
|
classpath(rootProject.tasks.named<io.papermc.paperweight.tasks.CreateBundlerJar>("createMojmapBundlerJar").flatMap { it.outputZip })
|
|
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
index faeb700647522379046f3cb3abcf478ff5aae95d..a8c5fa172b01b85df51fa3b4d20b6c4f734dfdda 100644
|
|
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
@@ -236,6 +236,9 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
|
this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark
|
|
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
|
|
|
|
+ org.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 ac8af406180bc680d46e8edc3da0fc2e5211345a..3d18ffbf3604705d8b99f69df156392dfed1863b 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
@@ -1114,6 +1114,7 @@ public final class CraftServer implements Server {
|
|
playerMetadata.removeAll(plugin);
|
|
}
|
|
// Paper end
|
|
+ org.leavesmc.leaves.LeavesConfig.init((File) console.options.valueOf("leaves-settings")); // Leaves - Server Config
|
|
this.reloadData();
|
|
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
|
|
io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper
|
|
@@ -3030,6 +3031,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 org.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 a41e6f5dc2d5516f081d7340e2dacffaf5663485..8f1230fcfa4fc27b513a4eb1023f107c8c7dd818 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
|
@@ -168,6 +168,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/org/leavesmc/leaves/LeavesConfig.java b/src/main/java/org/leavesmc/leaves/LeavesConfig.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..c306d4827e645d47692746c12100f793c5b83973
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/LeavesConfig.java
|
|
@@ -0,0 +1,962 @@
|
|
+package org.leavesmc.leaves;
|
|
+
|
|
+import com.destroystokyo.paper.util.SneakyThrow;
|
|
+import io.papermc.paper.configuration.GlobalConfiguration;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import net.minecraft.server.level.ServerLevel;
|
|
+import org.bukkit.command.Command;
|
|
+import org.bukkit.configuration.file.YamlConfiguration;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.leavesmc.leaves.command.LeavesCommand;
|
|
+import org.leavesmc.leaves.config.GlobalConfig;
|
|
+import org.leavesmc.leaves.config.GlobalConfigCategory;
|
|
+import org.leavesmc.leaves.config.RemovedConfig;
|
|
+import org.leavesmc.leaves.config.GlobalConfigManager;
|
|
+import org.leavesmc.leaves.region.RegionFileFormat;
|
|
+import org.leavesmc.leaves.util.MathUtils;
|
|
+
|
|
+import org.leavesmc.leaves.config.ConfigValidatorImpl.BooleanConfigValidator;
|
|
+import org.leavesmc.leaves.config.ConfigValidatorImpl.IntConfigValidator;
|
|
+import org.leavesmc.leaves.config.ConfigValidatorImpl.StringConfigValidator;
|
|
+import org.leavesmc.leaves.config.ConfigValidatorImpl.DoubleConfigValidator;
|
|
+import org.leavesmc.leaves.config.ConfigValidatorImpl.ListConfigValidator;
|
|
+import org.leavesmc.leaves.config.ConfigValidatorImpl.EnumConfigValidator;
|
|
+
|
|
+import java.io.File;
|
|
+import java.io.IOException;
|
|
+import java.util.Collections;
|
|
+import java.util.List;
|
|
+import java.util.Locale;
|
|
+import java.util.Random;
|
|
+
|
|
+import org.leavesmc.leaves.protocol.CarpetServerProtocol.CarpetRule;
|
|
+import org.leavesmc.leaves.protocol.CarpetServerProtocol.CarpetRules;
|
|
+
|
|
+import org.leavesmc.leaves.protocol.bladeren.BladerenProtocol.LeavesFeatureSet;
|
|
+import org.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 = 6;
|
|
+
|
|
+ private static File configFile;
|
|
+ public static YamlConfiguration config;
|
|
+
|
|
+ public static void init(final @NotNull 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) {
|
|
+ LeavesLogger.LOGGER.severe("Failure to create leaves config", ex);
|
|
+ }
|
|
+ } else {
|
|
+ try {
|
|
+ config.load(file);
|
|
+ } catch (final Exception ex) {
|
|
+ LeavesLogger.LOGGER.severe("Failure to load leaves config", ex);
|
|
+ SneakyThrow.sneaky(ex);
|
|
+ throw new RuntimeException(ex);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ LeavesConfig.config.set("config-version", CURRENT_CONFIG_VERSION);
|
|
+
|
|
+ GlobalConfigManager.init();
|
|
+
|
|
+ registerCommand("leaves", new LeavesCommand("leaves"));
|
|
+ }
|
|
+
|
|
+ public static void save() {
|
|
+ try {
|
|
+ config.save(LeavesConfig.configFile);
|
|
+ } catch (final Exception ex) {
|
|
+ LeavesLogger.LOGGER.severe("Unable to save leaves config", ex);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static void registerCommand(String name, Command command) {
|
|
+ MinecraftServer.getServer().server.getCommandMap().register(name, "leaves", command);
|
|
+ MinecraftServer.getServer().server.syncCommands();
|
|
+ }
|
|
+
|
|
+ public static void unregisterCommand(String name) {
|
|
+ name = name.toLowerCase(Locale.ENGLISH).trim();
|
|
+ MinecraftServer.getServer().server.getCommandMap().getKnownCommands().remove(name);
|
|
+ MinecraftServer.getServer().server.getCommandMap().getKnownCommands().remove("leaves:" + name);
|
|
+ MinecraftServer.getServer().server.syncCommands();
|
|
+ }
|
|
+
|
|
+ public static ModifyConfig modify = new ModifyConfig();
|
|
+
|
|
+ @GlobalConfigCategory("modify")
|
|
+ public static class ModifyConfig {
|
|
+
|
|
+ public FakeplayerConfig fakeplayer = new FakeplayerConfig();
|
|
+
|
|
+ @GlobalConfigCategory("fakeplayer")
|
|
+ public static class FakeplayerConfig {
|
|
+
|
|
+ @RemovedConfig(name = "enable", category = "fakeplayer", transform = true)
|
|
+ @GlobalConfig(value = "enable", validator = FakeplayerValidator.class)
|
|
+ public boolean enable = true;
|
|
+
|
|
+ private static class FakeplayerValidator extends BooleanConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
|
|
+ if (value) {
|
|
+ registerCommand("bot", new org.leavesmc.leaves.bot.BotCommand("bot"));
|
|
+ org.leavesmc.leaves.bot.agent.Actions.registerAll();
|
|
+ } else {
|
|
+ unregisterCommand("bot");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @RemovedConfig(name = "unable-fakeplayer-names", category = "fakeplayer", convert = ListConfigValidator.STRING.class, transform = true)
|
|
+ @GlobalConfig(value = "unable-fakeplayer-names", validator = ListConfigValidator.STRING.class)
|
|
+ public List<String> unableNames = List.of("player-name");
|
|
+
|
|
+ @GlobalConfig(value = "limit", validator = IntConfigValidator.class)
|
|
+ public int limit = 10;
|
|
+
|
|
+ @GlobalConfig(value = "prefix", validator = StringConfigValidator.class)
|
|
+ public String prefix = "";
|
|
+
|
|
+ @GlobalConfig(value = "suffix", validator = StringConfigValidator.class)
|
|
+ public String suffix = "";
|
|
+
|
|
+ @GlobalConfig(value = "regen-amount", validator = RegenAmountValidator.class)
|
|
+ public double regenAmount = 0.0;
|
|
+
|
|
+ private static class RegenAmountValidator extends DoubleConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Double old, Double value) throws IllegalArgumentException {
|
|
+ if (value < 0.0) {
|
|
+ throw new IllegalArgumentException("regen-amount need >= 0.0");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("always-send-data")
|
|
+ public boolean canSendDataAlways = true;
|
|
+
|
|
+ @GlobalConfig("resident-fakeplayer")
|
|
+ public boolean canResident = false;
|
|
+
|
|
+ @GlobalConfig("open-fakeplayer-inventory")
|
|
+ public boolean canOpenInventory = false;
|
|
+
|
|
+ @GlobalConfig("skip-sleep-check")
|
|
+ public boolean canSkipSleep = false;
|
|
+
|
|
+ @GlobalConfig("spawn-phantom")
|
|
+ public boolean canSpawnPhantom = false;
|
|
+
|
|
+ @GlobalConfig("use-action")
|
|
+ public boolean canUseAction = true;
|
|
+
|
|
+ @GlobalConfig("modify-config")
|
|
+ public boolean canModifyConfig = false;
|
|
+
|
|
+ @GlobalConfig("manual-save-and-load")
|
|
+ public boolean canManualSaveAndLoad = false;
|
|
+
|
|
+ @GlobalConfig(value = "cache-skin", lock = true)
|
|
+ public boolean useSkinCache = false;
|
|
+ }
|
|
+
|
|
+ public MinecraftOLDConfig oldMC = new MinecraftOLDConfig();
|
|
+
|
|
+ @GlobalConfigCategory("minecraft-old")
|
|
+ public static class MinecraftOLDConfig {
|
|
+
|
|
+ public BlockUpdaterConfig updater = new BlockUpdaterConfig();
|
|
+
|
|
+ @GlobalConfigCategory("block-updater")
|
|
+ public static class BlockUpdaterConfig {
|
|
+ @RemovedConfig(name = "instant-block-updater-reintroduced", category = "modify", transform = true)
|
|
+ @RemovedConfig(name = "instant-block-updater-reintroduced", category = {"modify", "minecraft-old"}, transform = true)
|
|
+ @GlobalConfig(value = "instant-block-updater-reintroduced", lock = true)
|
|
+ public boolean instantBlockUpdaterReintroduced = false;
|
|
+
|
|
+ @RemovedConfig(name = "cce-update-suppression", category = {"modify", "minecraft-old"}, transform = true)
|
|
+ @GlobalConfig("cce-update-suppression")
|
|
+ public boolean cceUpdateSuppression = false;
|
|
+
|
|
+ @RemovedConfig(name = "redstone-wire-dont-connect-if-on-trapdoor", category = "modify", transform = true)
|
|
+ @RemovedConfig(name = "redstone-wire-dont-connect-if-on-trapdoor", category = {"modify", "minecraft-old"}, transform = true)
|
|
+ @GlobalConfig("redstone-wire-dont-connect-if-on-trapdoor")
|
|
+ public boolean redstoneDontCantOnTrapDoor = false;
|
|
+ }
|
|
+
|
|
+ @RemovedConfig(name = "shears-in-dispenser-can-zero-amount", category = {}, transform = true)
|
|
+ @RemovedConfig(name = "shears-in-dispenser-can-zero-amount", category = "modify", transform = true)
|
|
+ @GlobalConfig("shears-in-dispenser-can-zero-amount")
|
|
+ public boolean shearsInDispenserCanZeroAmount = false;
|
|
+
|
|
+ @GlobalConfig("armor-stand-cant-kill-by-mob-projectile")
|
|
+ public boolean armorStandCantKillByMobProjectile = false;
|
|
+
|
|
+ @GlobalConfig(value = "villager-infinite-discounts", validator = VillagerInfiniteDiscountsValidator.class)
|
|
+ public boolean villagerInfiniteDiscounts = false;
|
|
+
|
|
+ private static class VillagerInfiniteDiscountsValidator extends BooleanConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
|
|
+ org.leavesmc.leaves.util.VillagerInfiniteDiscountHelper.doVillagerInfiniteDiscount(value);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("copper-bulb-1gt-delay")
|
|
+ public boolean copperBulb1gt = false;
|
|
+
|
|
+ @GlobalConfig("crafter-1gt-delay")
|
|
+ public boolean crafter1gt = false;
|
|
+
|
|
+ @RemovedConfig(name = "zero-tick-plants", category = "modify", transform = true)
|
|
+ @GlobalConfig("zero-tick-plants")
|
|
+ public boolean zeroTickPlants = false;
|
|
+
|
|
+ @RemovedConfig(name = "loot-world-random", category = {"modify", "minecraft-old"}, transform = true)
|
|
+ @GlobalConfig(value = "rng-fishing", lock = true, validator = RNGFishingValidator.class)
|
|
+ public boolean rngFishing = false;
|
|
+
|
|
+ private static class RNGFishingValidator extends BooleanConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
|
|
+ LeavesFeatureSet.register(LeavesFeature.of("rng_fishing", value));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("allow-grindstone-overstacking")
|
|
+ public boolean allowGrindstoneOverstacking = false;
|
|
+
|
|
+ @GlobalConfig("allow-entity-portal-with-passenger")
|
|
+ public boolean allowEntityPortalWithPassenger = true;
|
|
+
|
|
+ @GlobalConfig("disable-gateway-portal-entity-ticking")
|
|
+ public boolean disableGatewayPortalEntityTicking = false;
|
|
+
|
|
+ @GlobalConfig("disable-LivingEntity-ai-step-alive-check")
|
|
+ public boolean disableLivingEntityAiStepAliveCheck = false;
|
|
+
|
|
+ @GlobalConfig("fix-fortress-mob-spawn")
|
|
+ public boolean fixFortressMobSpawn = false;
|
|
+
|
|
+ @GlobalConfig("old-block-entity-behaviour")
|
|
+ public boolean oldBlockEntityBehaviour = false;
|
|
+
|
|
+ @GlobalConfig("old-hopper-suck-in-behavior")
|
|
+ public boolean oldHopperSuckInBehavior = false;
|
|
+
|
|
+ public RaidConfig raid = new RaidConfig();
|
|
+
|
|
+ @GlobalConfigCategory("revert-raid-changes")
|
|
+ public static class RaidConfig {
|
|
+ @GlobalConfig("allow-bad-omen-trigger-raid")
|
|
+ public boolean allowBadOmenTriggerRaid = false;
|
|
+
|
|
+ @GlobalConfig("give-bad-omen-when-kill-patrol-leader")
|
|
+ public boolean giveBadOmenWhenKillPatrolLeader = false;
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("allow-anvil-destroy-item-entities")
|
|
+ public boolean allowAnvilDestroyItemEntities = false;
|
|
+
|
|
+ @GlobalConfig("string-tripwire-hook-duplicate")
|
|
+ public boolean stringTripwireHookDuplicate = false;
|
|
+ }
|
|
+
|
|
+ public ElytraAeronauticsConfig elytraAeronautics = new ElytraAeronauticsConfig();
|
|
+
|
|
+ @GlobalConfigCategory("elytra-aeronautics")
|
|
+ public static class ElytraAeronauticsConfig {
|
|
+ @GlobalConfig("no-chunk-load")
|
|
+ public boolean noChunk = false;
|
|
+
|
|
+ @GlobalConfig(value = "no-chunk-height", validator = DoubleConfigValidator.class)
|
|
+ public double noChunkHeight = 500.0D;
|
|
+
|
|
+ @GlobalConfig(value = "no-chunk-speed", validator = DoubleConfigValidator.class)
|
|
+ public double noChunkSpeed = -1.0D;
|
|
+
|
|
+ @GlobalConfig("message")
|
|
+ public boolean noChunkMes = true;
|
|
+
|
|
+ @GlobalConfig(value = "message-start", validator = StringConfigValidator.class)
|
|
+ public String noChunkStartMes = "Flight enter cruise mode";
|
|
+
|
|
+ @GlobalConfig(value = "message-end", validator = StringConfigValidator.class)
|
|
+ public String noChunkEndMes = "Flight exit cruise mode";
|
|
+ }
|
|
+
|
|
+ @RemovedConfig(name = "redstone-shears-wrench", category = {}, transform = true)
|
|
+ @GlobalConfig("redstone-shears-wrench")
|
|
+ public boolean redstoneShearsWrench = true;
|
|
+
|
|
+ @RemovedConfig(name = "budding-amethyst-can-push-by-piston", category = {}, transform = true)
|
|
+ @GlobalConfig("budding-amethyst-can-push-by-piston")
|
|
+ public boolean buddingAmethystCanPushByPiston = false;
|
|
+
|
|
+ @RemovedConfig(name = "spectator-dont-get-advancement", category = {}, transform = true)
|
|
+ @GlobalConfig("spectator-dont-get-advancement")
|
|
+ public boolean spectatorDontGetAdvancement = false;
|
|
+
|
|
+ @RemovedConfig(name = "stick-change-armorstand-arm-status", category = {}, transform = true)
|
|
+ @GlobalConfig("stick-change-armorstand-arm-status")
|
|
+ public boolean stickChangeArmorStandArmStatus = true;
|
|
+
|
|
+ @RemovedConfig(name = "snowball-and-egg-can-knockback-player", category = {}, transform = true)
|
|
+ @GlobalConfig("snowball-and-egg-can-knockback-player")
|
|
+ public boolean snowballAndEggCanKnockback = true;
|
|
+
|
|
+ @GlobalConfig("flatten-triangular-distribution")
|
|
+ public boolean flattenTriangularDistribution = false;
|
|
+
|
|
+ @GlobalConfig("player-operation-limiter")
|
|
+ public boolean playerOperationLimiter = false;
|
|
+
|
|
+ @GlobalConfig(value = "renewable-elytra", validator = RenewableElytraValidator.class)
|
|
+ public double renewableElytra = -1.0F;
|
|
+
|
|
+ private static class RenewableElytraValidator extends DoubleConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Double old, Double value) throws IllegalArgumentException {
|
|
+ if (value > 1.0) {
|
|
+ throw new IllegalArgumentException("renewable-elytra need <= 1.0f");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public int shulkerBoxStackSize = 1;
|
|
+ @GlobalConfig(value = "stackable-shulker-boxes", validator = StackableShulkerValidator.class)
|
|
+ private String stackableShulkerBoxes = "false";
|
|
+
|
|
+ private static class StackableShulkerValidator extends StringConfigValidator {
|
|
+ @Override
|
|
+ public void verify(String old, String value) throws IllegalArgumentException {
|
|
+ String realValue = MathUtils.isNumeric(value) ? value : value.equals("true") ? "2" : "1";
|
|
+ LeavesConfig.modify.shulkerBoxStackSize = Integer.parseInt(realValue);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("force-void-trade")
|
|
+ public boolean forceVoidTrade = false;
|
|
+
|
|
+ @GlobalConfig(value = "mc-technical-survival-mode", validator = McTechnicalModeValidator.class, lock = true)
|
|
+ public boolean mcTechnicalMode = true;
|
|
+
|
|
+ private static class McTechnicalModeValidator extends BooleanConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
|
|
+ if (value) {
|
|
+ org.leavesmc.leaves.util.McTechnicalModeHelper.doMcTechnicalMode();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("return-nether-portal-fix")
|
|
+ public boolean netherPortalFix = false;
|
|
+
|
|
+ @GlobalConfig(value = "use-vanilla-random", lock = true, validator = UseVanillaRandomValidator.class)
|
|
+ public boolean useVanillaRandom = false;
|
|
+
|
|
+ private static class UseVanillaRandomValidator extends BooleanConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
|
|
+ LeavesFeatureSet.register(LeavesFeature.of("use_vanilla_random", value));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("fix-update-suppression-crash")
|
|
+ public boolean updateSuppressionCrashFix = true;
|
|
+
|
|
+ @GlobalConfig(value = "bedrock-break-list", lock = true)
|
|
+ public boolean bedrockBreakList = false;
|
|
+
|
|
+ @GlobalConfig(value = "disable-distance-check-for-use-item", validator = DisableDistanceCheckForUseItemValidator.class)
|
|
+ public boolean disableDistanceCheckForUseItem = false;
|
|
+
|
|
+ private static class DisableDistanceCheckForUseItemValidator extends BooleanConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
|
|
+ if (!value && old != null && LeavesConfig.protocol.alternativeBlockPlacement != ProtocolConfig.AlternativePlaceType.NONE) {
|
|
+ throw new IllegalArgumentException("alternative-block-placement is enable, disable-distance-check-for-use-item always need true");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("no-feather-falling-trample")
|
|
+ public boolean noFeatherFallingTrample = false;
|
|
+
|
|
+ @GlobalConfig("shared-villager-discounts")
|
|
+ public boolean sharedVillagerDiscounts = false;
|
|
+
|
|
+ @GlobalConfig("disable-check-out-of-order-command")
|
|
+ public boolean disableCheckOutOfOrderCommand = false;
|
|
+
|
|
+ @GlobalConfig("despawn-enderman-with-block")
|
|
+ public boolean despawnEndermanWithBlock = false;
|
|
+
|
|
+ @GlobalConfig(value = "creative-no-clip", validator = CreativeNoClipValidator.class)
|
|
+ public boolean creativeNoClip = false;
|
|
+
|
|
+ private static class CreativeNoClipValidator extends BooleanConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
|
|
+ CarpetRules.register(CarpetRule.of("carpet", "creativeNoClip", value));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("shave-snow-layers")
|
|
+ public boolean shaveSnowLayers = true;
|
|
+
|
|
+ @GlobalConfig("ignore-lc")
|
|
+ public boolean ignoreLC = false;
|
|
+
|
|
+ @GlobalConfig("disable-packet-limit")
|
|
+ public boolean disablePacketLimit = false;
|
|
+
|
|
+ @GlobalConfig(value = "lava-riptide", validator = LavaRiptideValidator.class)
|
|
+ public boolean lavaRiptide = false;
|
|
+
|
|
+ private static class LavaRiptideValidator extends BooleanConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
|
|
+ LeavesFeatureSet.register(LeavesFeature.of("lava_riptide", value));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(value = "no-block-update-command", validator = NoBlockUpdateValidator.class)
|
|
+ public boolean noBlockUpdateCommand = false;
|
|
+
|
|
+ private static class NoBlockUpdateValidator extends BooleanConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
|
|
+ if (value) {
|
|
+ registerCommand("blockupdate", new org.leavesmc.leaves.command.NoBlockUpdateCommand("blockupdate"));
|
|
+ } else {
|
|
+ unregisterCommand("blockupdate");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("no-tnt-place-update")
|
|
+ public boolean noTNTPlaceUpdate = false;
|
|
+
|
|
+ @GlobalConfig("raider-die-skip-self-raid-check")
|
|
+ public boolean skipSelfRaidCheck = false;
|
|
+
|
|
+ @GlobalConfig("container-passthrough")
|
|
+ public boolean containerPassthrough = false;
|
|
+
|
|
+ @GlobalConfig(value = "avoid-anvil-too-expensive", validator = AnvilNotExpensiveValidator.class)
|
|
+ public boolean avoidAnvilTooExpensive = false;
|
|
+
|
|
+ private static class AnvilNotExpensiveValidator extends BooleanConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
|
|
+ CarpetRules.register(CarpetRule.of("pca", "avoidAnvilTooExpensive", value));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("bow-infinity-fix")
|
|
+ public boolean bowInfinityFix = false;
|
|
+
|
|
+ @GlobalConfig("hopper-counter")
|
|
+ public boolean hopperCounter = false;
|
|
+
|
|
+ @GlobalConfig(value = "spider-jockeys-drop-gapples", validator = JockeysDropGAppleValidator.class)
|
|
+ public double spiderJockeysDropGapples = -1.0;
|
|
+
|
|
+ private static class JockeysDropGAppleValidator extends DoubleConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Double old, Double value) throws IllegalArgumentException {
|
|
+ if (value > 1.0) {
|
|
+ throw new IllegalArgumentException("spider-jockeys-drop-gapples need <= 1.0f");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("renewable-deepslate")
|
|
+ public boolean renewableDeepslate = false;
|
|
+
|
|
+ @GlobalConfig("renewable-sponges")
|
|
+ public boolean renewableSponges = false;
|
|
+
|
|
+ @GlobalConfig(value = "renewable-coral", validator = RenewableCoralValidator.class)
|
|
+ public RenewableCoralType renewableCoral = RenewableCoralType.FALSE;
|
|
+
|
|
+ public enum RenewableCoralType {
|
|
+ FALSE, TRUE, EXPANDED
|
|
+ }
|
|
+
|
|
+ private static class RenewableCoralValidator extends EnumConfigValidator<RenewableCoralType> {
|
|
+ @Override
|
|
+ public void verify(RenewableCoralType old, RenewableCoralType value) throws IllegalArgumentException {
|
|
+ CarpetRules.register(CarpetRule.of("carpet", "renewableCoral", value));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("fast-resume")
|
|
+ public boolean fastResume = false;
|
|
+
|
|
+ @GlobalConfig(value = "force-peaceful-mode", validator = ForcePeacefulModeValidator.class)
|
|
+ public int forcePeacefulMode = -1;
|
|
+
|
|
+ private static class ForcePeacefulModeValidator extends IntConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Integer old, Integer value) throws IllegalArgumentException {
|
|
+ for (ServerLevel level : MinecraftServer.getServer().getAllLevels()) {
|
|
+ level.chunkSource.peacefulModeSwitchTick = value;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("disable-vault-blacklist")
|
|
+ public boolean disableVaultBlacklist = false;
|
|
+
|
|
+ @RemovedConfig(name = "tick-command", category = "modify")
|
|
+ @RemovedConfig(name = "player-can-edit-sign", category = "modify")
|
|
+ @RemovedConfig(name = "mending-compatibility-infinity", category = {"modify", "minecraft-old"})
|
|
+ @RemovedConfig(name = "protection-stacking", category = {"modify", "minecraft-old"})
|
|
+ @RemovedConfig(name = "disable-moved-wrongly-threshold", category = {"modify"})
|
|
+ private final boolean removed = false;
|
|
+ }
|
|
+
|
|
+ public static PerformanceConfig performance = new PerformanceConfig();
|
|
+
|
|
+ @GlobalConfigCategory("performance")
|
|
+ public static class PerformanceConfig {
|
|
+
|
|
+ public PerformanceRemoveConfig remove = new PerformanceRemoveConfig();
|
|
+
|
|
+ @GlobalConfigCategory("remove")
|
|
+ public static class PerformanceRemoveConfig {
|
|
+ @GlobalConfig("tick-guard-lambda")
|
|
+ public boolean tickGuardLambda = true;
|
|
+
|
|
+ @GlobalConfig("inventory-contains-iterators")
|
|
+ public boolean inventoryContainsIterators = true;
|
|
+
|
|
+ @GlobalConfig("damage-lambda")
|
|
+ public boolean damageLambda = true;
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("optimized-dragon-respawn")
|
|
+ public boolean optimizedDragonRespawn = false;
|
|
+
|
|
+ @GlobalConfig("dont-send-useless-entity-packets")
|
|
+ public boolean dontSendUselessEntityPackets = true;
|
|
+
|
|
+ @GlobalConfig("enable-suffocation-optimization")
|
|
+ public boolean enableSuffocationOptimization = true;
|
|
+
|
|
+ @GlobalConfig("check-spooky-season-once-an-hour")
|
|
+ public boolean checkSpookySeasonOnceAnHour = true;
|
|
+
|
|
+ @GlobalConfig("inactive-goal-selector-disable")
|
|
+ public boolean throttleInactiveGoalSelectorTick = false;
|
|
+
|
|
+ @GlobalConfig("reduce-entity-allocations")
|
|
+ public boolean reduceEntityAllocations = true;
|
|
+
|
|
+ @GlobalConfig("cache-climb-check")
|
|
+ public boolean cacheClimbCheck = true;
|
|
+
|
|
+ @GlobalConfig(value = "biome-temperatures-use-aging-cache", lock = true)
|
|
+ public boolean biomeTemperaturesUseAgingCache = true;
|
|
+
|
|
+ @GlobalConfig("reduce-chuck-load-and-lookup")
|
|
+ public boolean reduceChuckLoadAndLookup = true;
|
|
+
|
|
+ @GlobalConfig("cache-ignite-odds")
|
|
+ public boolean cacheIgniteOdds = true;
|
|
+
|
|
+ @GlobalConfig("faster-chunk-serialization")
|
|
+ public boolean fasterChunkSerialization = true;
|
|
+
|
|
+ @GlobalConfig("skip-secondary-POI-sensor-if-absent")
|
|
+ public boolean skipSecondaryPOISensorIfAbsent = true;
|
|
+
|
|
+ @GlobalConfig("store-mob-counts-in-array")
|
|
+ public boolean storeMobCountsInArray = true;
|
|
+
|
|
+ @GlobalConfig("optimize-noise-generation")
|
|
+ public boolean optimizeNoiseGeneration = false;
|
|
+
|
|
+ @GlobalConfig("optimize-sun-burn-tick")
|
|
+ public boolean optimizeSunBurnTick = true;
|
|
+
|
|
+ @GlobalConfig("optimized-CubePointRange")
|
|
+ public boolean optimizedCubePointRange = true;
|
|
+
|
|
+ @GlobalConfig("check-frozen-ticks-before-landing-block")
|
|
+ public boolean checkFrozenTicksBeforeLandingBlock = true;
|
|
+
|
|
+ @GlobalConfig("skip-entity-move-if-movement-is-zero")
|
|
+ public boolean skipEntityMoveIfMovementIsZero = true;
|
|
+
|
|
+ @GlobalConfig("skip-cloning-advancement-criteria")
|
|
+ public boolean skipCloningAdvancementCriteria = false;
|
|
+
|
|
+ @GlobalConfig("skip-negligible-planar-movement-multiplication")
|
|
+ public boolean skipNegligiblePlanarMovementMultiplication = true;
|
|
+
|
|
+ @GlobalConfig("fix-villagers-dont-release-memory")
|
|
+ public boolean villagersDontReleaseMemoryFix = false;
|
|
+
|
|
+ @RemovedConfig(name = "cache-world-generator-sea-level", category = "performance")
|
|
+ @RemovedConfig(name = "cache-ominous-banner-item", category = "performance")
|
|
+ @RemovedConfig(name = "use-optimized-collection", category = "performance")
|
|
+ @RemovedConfig(name = "async-pathfinding", category = "performance")
|
|
+ @RemovedConfig(name = "async-mob-spawning", category = "performance")
|
|
+ @RemovedConfig(name = "async-entity-tracker", category = "performance")
|
|
+ @RemovedConfig(name = "fix-paper-6045", category = {"performance", "fix"})
|
|
+ @RemovedConfig(name = "fix-paper-9372", category = {"performance", "fix"})
|
|
+ @RemovedConfig(name = "skip-clone-loot-parameters", category = "performance")
|
|
+ @RemovedConfig(name = "skip-poi-find-in-vehicle", category = "performance")
|
|
+ @RemovedConfig(name = "strip-raytracing-for-entity", category = "performance")
|
|
+ @RemovedConfig(name = "get-nearby-players-streams", category = {"performance", "remove"})
|
|
+ @RemovedConfig(name = "optimize-world-generation-and-block-access", category = "performance")
|
|
+ @RemovedConfig(name = "cache-CubeVoxelShape-shape-array", category = "performance")
|
|
+ @RemovedConfig(name = "reduce-entity-fluid-lookup", category = "performance")
|
|
+ @RemovedConfig(name = "optimize-entity-coordinate-key", category = "performance")
|
|
+ @RemovedConfig(name = "entity-target-find-optimization", category = "performance")
|
|
+ @RemovedConfig(name = "use-more-thread-unsafe-random", category = "performance")
|
|
+ @RemovedConfig(name = "range-check-streams-and-iterators", category = {"performance", "remove"})
|
|
+ @RemovedConfig(name = "improve-fluid-direction-caching", category = "performance")
|
|
+ @RemovedConfig(name = "cache-BlockStatePairKey-hash", category = "performance")
|
|
+ @RemovedConfig(name = "optimize-chunk-ticking", category = "performance")
|
|
+ private final boolean removedPerformance = true;
|
|
+ }
|
|
+
|
|
+ public static ProtocolConfig protocol = new ProtocolConfig();
|
|
+
|
|
+ @GlobalConfigCategory("protocol")
|
|
+ public static class ProtocolConfig {
|
|
+
|
|
+ public BladerenConfig bladeren = new BladerenConfig();
|
|
+
|
|
+ @GlobalConfigCategory("bladeren")
|
|
+ public static class BladerenConfig {
|
|
+ @GlobalConfig("protocol")
|
|
+ public boolean enable = true;
|
|
+
|
|
+ @GlobalConfig(value = "mspt-sync-protocol", validator = MSPTSyncValidator.class)
|
|
+ public boolean msptSyncProtocol = false;
|
|
+
|
|
+ private static class MSPTSyncValidator extends BooleanConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
|
|
+ LeavesFeatureSet.register(LeavesFeature.of("mspt_sync", value));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(value = "mspt-sync-tick-interval", validator = MSPTSyncIntervalValidator.class)
|
|
+ public int msptSyncTickInterval = 20;
|
|
+
|
|
+ private static class MSPTSyncIntervalValidator extends IntConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Integer old, Integer value) throws IllegalArgumentException {
|
|
+ if (value <= 0) {
|
|
+ throw new IllegalArgumentException("mspt-sync-tick-interval need > 0");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public SyncmaticaConfig syncmatica = new SyncmaticaConfig();
|
|
+
|
|
+ @GlobalConfigCategory("syncmatica")
|
|
+ public static class SyncmaticaConfig {
|
|
+ @GlobalConfig(value = "enable", validator = SyncmaticaValidator.class)
|
|
+ public boolean enable = false;
|
|
+
|
|
+ public static class SyncmaticaValidator extends BooleanConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
|
|
+ if (value) {
|
|
+ org.leavesmc.leaves.protocol.syncmatica.SyncmaticaProtocol.init();
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("quota")
|
|
+ public boolean useQuota = false;
|
|
+
|
|
+ @GlobalConfig(value = "quota-limit", validator = IntConfigValidator.class)
|
|
+ public int quotaLimit = 40000000;
|
|
+ }
|
|
+
|
|
+ public PCAConfig pca = new PCAConfig();
|
|
+
|
|
+ @GlobalConfigCategory("pca")
|
|
+ public static class PCAConfig {
|
|
+ @RemovedConfig(name = "pca-sync-protocol", category = "protocol", transform = true)
|
|
+ @GlobalConfig(value = "pca-sync-protocol", validator = PcaValidator.class)
|
|
+ public boolean enable = false;
|
|
+
|
|
+ public static class PcaValidator extends BooleanConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
|
|
+ if (old != null && old != value) {
|
|
+ org.leavesmc.leaves.protocol.PcaSyncProtocol.onConfigModify(value);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @RemovedConfig(name = "pca-sync-player-entity", category = "protocol", convert = PcaPlayerEntityValidator.class, transform = true)
|
|
+ @GlobalConfig(value = "pca-sync-player-entity", validator = PcaPlayerEntityValidator.class)
|
|
+ public PcaPlayerEntityType syncPlayerEntity = PcaPlayerEntityType.OPS;
|
|
+
|
|
+ public enum PcaPlayerEntityType {
|
|
+ NOBODY, BOT, OPS, OPS_AND_SELF, EVERYONE
|
|
+ }
|
|
+
|
|
+ private static class PcaPlayerEntityValidator extends EnumConfigValidator<PcaPlayerEntityType> {
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public AppleSkinConfig appleskin = new AppleSkinConfig();
|
|
+
|
|
+ @GlobalConfigCategory("appleskin")
|
|
+ public static class AppleSkinConfig {
|
|
+ @RemovedConfig(name = "appleskin-protocol", category = "protocol")
|
|
+ @GlobalConfig("protocol")
|
|
+ public boolean enable = false;
|
|
+
|
|
+ @GlobalConfig("sync-tick-interval")
|
|
+ public int syncTickInterval = 20;
|
|
+ }
|
|
+
|
|
+ public ServuxConfig servux = new ServuxConfig();
|
|
+
|
|
+ @GlobalConfigCategory("servux")
|
|
+ public static class ServuxConfig {
|
|
+ @RemovedConfig(name = "servux-protocol", category = "protocol", transform = true)
|
|
+ @GlobalConfig("structure-protocol")
|
|
+ public boolean structureProtocol = false;
|
|
+
|
|
+ @GlobalConfig("entity-protocol")
|
|
+ public boolean entityProtocol = false;
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("bbor-protocol")
|
|
+ public boolean bborProtocol = false;
|
|
+
|
|
+ @GlobalConfig("jade-protocol")
|
|
+ public boolean jadeProtocol = false;
|
|
+
|
|
+ @GlobalConfig(value = "alternative-block-placement", validator = AlternativePlaceValidator.class)
|
|
+ public AlternativePlaceType alternativeBlockPlacement = AlternativePlaceType.NONE;
|
|
+
|
|
+ public enum AlternativePlaceType {
|
|
+ NONE, CARPET, CARPET_FIX, LITEMATICA
|
|
+ }
|
|
+
|
|
+ private static class AlternativePlaceValidator extends EnumConfigValidator<AlternativePlaceType> {
|
|
+ @Override
|
|
+ public void runAfterLoader(AlternativePlaceType value, boolean firstLoad) {
|
|
+ if (value != AlternativePlaceType.NONE) {
|
|
+ LeavesConfig.modify.disableDistanceCheckForUseItem = true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("xaero-map-protocol")
|
|
+ public boolean xaeroMapProtocol = false;
|
|
+
|
|
+ @GlobalConfig(value = "xaero-map-server-id", validator = IntConfigValidator.class)
|
|
+ public int xaeroMapServerID = new Random().nextInt();
|
|
+
|
|
+ @GlobalConfig("leaves-carpet-support")
|
|
+ public boolean leavesCarpetSupport = false;
|
|
+ }
|
|
+
|
|
+ public static MiscConfig mics = new MiscConfig();
|
|
+
|
|
+ @GlobalConfigCategory("misc")
|
|
+ public static class MiscConfig {
|
|
+
|
|
+ public AutoUpdateConfig autoUpdate = new AutoUpdateConfig();
|
|
+
|
|
+ @GlobalConfigCategory("auto-update")
|
|
+ public static class AutoUpdateConfig {
|
|
+ @GlobalConfig(value = "enable", lock = true, validator = AutoUpdateValidator.class)
|
|
+ public boolean enable = false;
|
|
+
|
|
+ private static class AutoUpdateValidator extends BooleanConfigValidator {
|
|
+ @Override
|
|
+ public void runAfterLoader(Boolean value, boolean firstLoad) {
|
|
+ if (firstLoad) {
|
|
+ org.leavesmc.leaves.util.LeavesUpdateHelper.init();
|
|
+ if (value) {
|
|
+ LeavesLogger.LOGGER.warning("Auto-Update is not completely safe. Enabling it may cause data security problems!");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(value = "download-source", lock = true, validator = DownloadSourceValidator.class)
|
|
+ public String source = "application";
|
|
+
|
|
+ public static class DownloadSourceValidator extends StringConfigValidator {
|
|
+ private static final List<String> suggestSourceList = List.of("application", "ghproxy", "cloud");
|
|
+
|
|
+ @Override
|
|
+ public List<String> valueSuggest() {
|
|
+ return suggestSourceList;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("allow-experimental")
|
|
+ public Boolean allowExperimental = false;
|
|
+
|
|
+ @GlobalConfig(value = "time", lock = true, validator = ListConfigValidator.STRING.class)
|
|
+ public List<String> updateTime = List.of("14:00", "2:00");
|
|
+ }
|
|
+
|
|
+ public ExtraYggdrasilConfig yggdrasil = new ExtraYggdrasilConfig();
|
|
+
|
|
+ @GlobalConfigCategory("extra-yggdrasil-service")
|
|
+ public static class ExtraYggdrasilConfig {
|
|
+ @GlobalConfig(value = "enable", validator = ExtraYggdrasilValidator.class)
|
|
+ public boolean enable = false;
|
|
+
|
|
+ public static class ExtraYggdrasilValidator extends BooleanConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
|
|
+ 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
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("login-protect")
|
|
+ public boolean loginProtect = false;
|
|
+
|
|
+ @GlobalConfig(value = "urls", lock = true, validator = ExtraYggdrasilUrlsValidator.class)
|
|
+ public List<String> serviceList = List.of("https://url.with.authlib-injector-yggdrasil");
|
|
+
|
|
+ public static class ExtraYggdrasilUrlsValidator extends ListConfigValidator.STRING {
|
|
+ @Override
|
|
+ public void verify(List<String> old, List<String> value) throws IllegalArgumentException {
|
|
+ org.leavesmc.leaves.profile.LeavesMinecraftSessionService.initExtraYggdrasilList(value);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig("disable-method-profiler")
|
|
+ public boolean disableMethodProfiler = true;
|
|
+
|
|
+ @RemovedConfig(name = "no-chat-sign", category = {}, transform = true)
|
|
+ @GlobalConfig("no-chat-sign")
|
|
+ public boolean noChatSign = true;
|
|
+
|
|
+ @GlobalConfig("dont-respond-ping-before-start-fully")
|
|
+ public boolean dontRespondPingBeforeStart = true;
|
|
+
|
|
+ @GlobalConfig(value = "server-lang", lock = true, validator = ServerLangValidator.class)
|
|
+ public String serverLang = "en_us";
|
|
+
|
|
+ private static class ServerLangValidator extends StringConfigValidator {
|
|
+ private static final List<String> supportLang = List.of("en_us", "zh_cn");
|
|
+
|
|
+ @Override
|
|
+ public void verify(String old, String value) throws IllegalArgumentException {
|
|
+ if (!supportLang.contains(value)) {
|
|
+ throw new IllegalArgumentException("lang " + value + " not supported");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public List<String> valueSuggest() {
|
|
+ return supportLang;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(value = "server-mod-name", validator = StringConfigValidator.class)
|
|
+ public String serverModName = "Leaves";
|
|
+
|
|
+ @GlobalConfig("bstats-privacy-mode")
|
|
+ public boolean bstatsPrivacyMode = false;
|
|
+
|
|
+ @GlobalConfig("force-minecraft-command")
|
|
+ public boolean forceMinecraftCommand = false;
|
|
+
|
|
+ @GlobalConfig("leaves-packet-event")
|
|
+ public boolean leavesPacketEvent = true;
|
|
+ }
|
|
+
|
|
+ public static RegionConfig region = new RegionConfig();
|
|
+
|
|
+ @GlobalConfigCategory("region")
|
|
+ public static class RegionConfig {
|
|
+
|
|
+ @GlobalConfig(value = "format", lock = true, validator = RegionFormatValidator.class)
|
|
+ public org.leavesmc.leaves.region.RegionFileFormat format = org.leavesmc.leaves.region.RegionFileFormat.ANVIL;
|
|
+
|
|
+ private static class RegionFormatValidator extends EnumConfigValidator<RegionFileFormat> {
|
|
+ }
|
|
+
|
|
+ public LinearConfig linear = new LinearConfig();
|
|
+
|
|
+ @GlobalConfigCategory("linear")
|
|
+ public static class LinearConfig {
|
|
+
|
|
+ @GlobalConfig(value = "flush-frequency", lock = true, validator = IntConfigValidator.class)
|
|
+ public int flushFrequency = 10;
|
|
+
|
|
+ @GlobalConfig(value = "auto-convert-anvil-to-linear", lock = true)
|
|
+ public boolean autoConvertAnvilToLinear = false;
|
|
+
|
|
+ @GlobalConfig(value = "flush-max-threads", lock = true, validator = IntConfigValidator.class)
|
|
+ public int flushThreads = 1;
|
|
+
|
|
+ public int getLinearFlushThreads() {
|
|
+ if (flushThreads < 0) {
|
|
+ return Math.max(Runtime.getRuntime().availableProcessors() + flushThreads, 1);
|
|
+ } else {
|
|
+ return Math.max(flushThreads, 1);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @GlobalConfig(value = "compression-level", lock = true, validator = LinearCompressValidator.class)
|
|
+ public int compressionLevel = 1;
|
|
+
|
|
+ private static class LinearCompressValidator extends IntConfigValidator {
|
|
+ @Override
|
|
+ public void verify(Integer old, Integer value) throws IllegalArgumentException {
|
|
+ if (value < 1 || value > 22) {
|
|
+ throw new IllegalArgumentException("linear.compression-level need between 1 and 22");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @RemovedConfig(name = "crash-on-broken-symlink", category = {"region", "linear"})
|
|
+ private final boolean linearCrashOnBrokenSymlink = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static FixConfig fix = new FixConfig();
|
|
+
|
|
+ @GlobalConfigCategory("fix")
|
|
+ public static class FixConfig {
|
|
+ @GlobalConfig("vanilla-hopper")
|
|
+ public boolean vanillaHopper = false;
|
|
+
|
|
+ @RemovedConfig(name = "spigot-EndPlatform-destroy", category = "fix")
|
|
+ private final boolean spigotEndPlatformDestroy = false;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/command/CommandArgument.java b/src/main/java/org/leavesmc/leaves/command/CommandArgument.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..0bccbf7816ef621316f0da4911ec112f4753f88e
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/command/CommandArgument.java
|
|
@@ -0,0 +1,55 @@
|
|
+package org.leavesmc.leaves.command;
|
|
+
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+
|
|
+import java.util.ArrayList;
|
|
+import java.util.Arrays;
|
|
+import java.util.List;
|
|
+
|
|
+public class CommandArgument {
|
|
+
|
|
+ public static final CommandArgument EMPTY = new CommandArgument();
|
|
+
|
|
+ private final List<CommandArgumentType<?>> argumentTypes;
|
|
+ private final List<List<String>> tabComplete;
|
|
+
|
|
+ private 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 static CommandArgument of(CommandArgumentType<?>... argumentTypes) {
|
|
+ return new CommandArgument(argumentTypes);
|
|
+ }
|
|
+
|
|
+ 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 CommandArgument setAllTabComplete(List<List<String>> tabComplete) {
|
|
+ this.tabComplete.clear();
|
|
+ this.tabComplete.addAll(tabComplete);
|
|
+ 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/org/leavesmc/leaves/command/CommandArgumentResult.java b/src/main/java/org/leavesmc/leaves/command/CommandArgumentResult.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..46aa6eaa75b65aad6bdbe4a5f517b42e87bcca77
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/command/CommandArgumentResult.java
|
|
@@ -0,0 +1,69 @@
|
|
+package org.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 int readInt(int def) {
|
|
+ return Objects.requireNonNullElse(read(Integer.class), def);
|
|
+ }
|
|
+
|
|
+ public double readDouble(double def) {
|
|
+ return Objects.requireNonNullElse(read(Double.class), def);
|
|
+ }
|
|
+
|
|
+ public float readFloat(float def) {
|
|
+ return Objects.requireNonNullElse(read(Float.class), def);
|
|
+ }
|
|
+
|
|
+ public String readString(String def) {
|
|
+ return Objects.requireNonNullElse(read(String.class), def);
|
|
+ }
|
|
+
|
|
+ public boolean readBoolean(boolean def) {
|
|
+ return Objects.requireNonNullElse(read(Boolean.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/org/leavesmc/leaves/command/CommandArgumentType.java b/src/main/java/org/leavesmc/leaves/command/CommandArgumentType.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..4ca3508475bbd9771768704e300fe12b717489d6
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/command/CommandArgumentType.java
|
|
@@ -0,0 +1,55 @@
|
|
+package org.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<Float> FLOAT = new CommandArgumentType<>() {
|
|
+ @Override
|
|
+ public Float pasre(@NotNull String arg) {
|
|
+ try {
|
|
+ return Float.parseFloat(arg);
|
|
+ } catch (NumberFormatException e) {
|
|
+ return null;
|
|
+ }
|
|
+ }
|
|
+ };
|
|
+
|
|
+ public static final CommandArgumentType<String> STRING = new CommandArgumentType<>() {
|
|
+ @Override
|
|
+ public String pasre(@NotNull String arg) {
|
|
+ return arg;
|
|
+ }
|
|
+ };
|
|
+
|
|
+ public static final CommandArgumentType<Boolean> BOOLEAN = new CommandArgumentType<>() {
|
|
+ @Override
|
|
+ public Boolean pasre(@NotNull String arg) {
|
|
+ return Boolean.parseBoolean(arg);
|
|
+ }
|
|
+ };
|
|
+
|
|
+ public abstract E pasre(@NotNull String arg);
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java b/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..393163c80b9e2ce04b089e90d20eefd7b7ad8366
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java
|
|
@@ -0,0 +1,117 @@
|
|
+package org.leavesmc.leaves.command;
|
|
+
|
|
+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.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.command.subcommands.*;
|
|
+
|
|
+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 LeavesCommandUtil.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/org/leavesmc/leaves/command/LeavesSubcommand.java b/src/main/java/org/leavesmc/leaves/command/LeavesSubcommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..4b61fccc71d98a7b69bb7f88fb88ea0a55ca1ed2
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/command/LeavesSubcommand.java
|
|
@@ -0,0 +1,18 @@
|
|
+package org.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/org/leavesmc/leaves/command/subcommands/ConfigCommand.java b/src/main/java/org/leavesmc/leaves/command/subcommands/ConfigCommand.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..56ad63ae93e1322140d59efc234ba90f0d5c7ab8
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/command/subcommands/ConfigCommand.java
|
|
@@ -0,0 +1,83 @@
|
|
+package org.leavesmc.leaves.command.subcommands;
|
|
+
|
|
+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 org.leavesmc.leaves.command.LeavesCommandUtil;
|
|
+import org.leavesmc.leaves.command.LeavesSubcommand;
|
|
+import org.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 LeavesCommandUtil.getListMatchingLast(sender, args, list);
|
|
+ }
|
|
+
|
|
+ case 2 -> {
|
|
+ GlobalConfigManager.VerifiedConfig verifiedConfig = GlobalConfigManager.getVerifiedConfig(args[0]);
|
|
+ if (verifiedConfig != null) {
|
|
+ return LeavesCommandUtil.getListMatchingLast(sender, args, verifiedConfig.validator().valueSuggest());
|
|
+ } else {
|
|
+ return Collections.singletonList("<ERROR CONFIG>");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return Collections.emptyList();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/config/ConfigConverter.java b/src/main/java/org/leavesmc/leaves/config/ConfigConverter.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..178f7e8636d135b084444b3b0c476631aac66dcc
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/config/ConfigConverter.java
|
|
@@ -0,0 +1,21 @@
|
|
+package org.leavesmc.leaves.config;
|
|
+
|
|
+public interface ConfigConverter<E> {
|
|
+
|
|
+ E convert(String value) throws IllegalArgumentException;
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ default E loadConvert(Object value) throws IllegalArgumentException {
|
|
+ try {
|
|
+ return (E) value;
|
|
+ } catch (ClassCastException e) {
|
|
+ throw new IllegalArgumentException(e);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ default Object saveConvert(E value) {
|
|
+ return value;
|
|
+ }
|
|
+
|
|
+ Class<E> getFieldClass();
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/config/ConfigValidator.java b/src/main/java/org/leavesmc/leaves/config/ConfigValidator.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..d343ae8d44a78e1d1536a2611b4bbbf9143c218e
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/config/ConfigValidator.java
|
|
@@ -0,0 +1,16 @@
|
|
+package org.leavesmc.leaves.config;
|
|
+
|
|
+import java.util.List;
|
|
+
|
|
+public interface ConfigValidator<E> extends ConfigConverter<E> {
|
|
+
|
|
+ default void verify(E old, E value) throws IllegalArgumentException {
|
|
+ }
|
|
+
|
|
+ default List<String> valueSuggest() {
|
|
+ return List.of("<value>");
|
|
+ }
|
|
+
|
|
+ default void runAfterLoader(E value, boolean firstLoad) {
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/config/ConfigValidatorImpl.java b/src/main/java/org/leavesmc/leaves/config/ConfigValidatorImpl.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..0e9cdc0fa9380ad07ad74a3933733fe4053b678b
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/config/ConfigValidatorImpl.java
|
|
@@ -0,0 +1,108 @@
|
|
+package org.leavesmc.leaves.config;
|
|
+
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+
|
|
+import java.lang.reflect.ParameterizedType;
|
|
+import java.lang.reflect.Type;
|
|
+import java.util.ArrayList;
|
|
+import java.util.List;
|
|
+import java.util.Locale;
|
|
+
|
|
+public abstract class ConfigValidatorImpl<E> implements ConfigValidator<E> {
|
|
+
|
|
+ private Class<E> fieldClass;
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ public ConfigValidatorImpl() {
|
|
+ Type superClass = getClass().getGenericSuperclass();
|
|
+ if (superClass instanceof ParameterizedType) {
|
|
+ Type[] actualTypeArguments = ((ParameterizedType) superClass).getActualTypeArguments();
|
|
+ if (actualTypeArguments[0] instanceof Class) {
|
|
+ this.fieldClass = (Class<E>) actualTypeArguments[0];
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Class<E> getFieldClass() {
|
|
+ return fieldClass;
|
|
+ }
|
|
+
|
|
+ public static class BooleanConfigValidator extends ConfigValidatorImpl<Boolean> {
|
|
+
|
|
+ @Override
|
|
+ public Boolean convert(String value) throws IllegalArgumentException {
|
|
+ return Boolean.parseBoolean(value);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public List<String> valueSuggest() {
|
|
+ return List.of("false", "true");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static class IntConfigValidator extends ConfigValidatorImpl<Integer> {
|
|
+ @Override
|
|
+ public Integer convert(String value) throws IllegalArgumentException {
|
|
+ return Integer.parseInt(value);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static class StringConfigValidator extends ConfigValidatorImpl<String> {
|
|
+ @Override
|
|
+ public String convert(String value) throws IllegalArgumentException {
|
|
+ return value;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static class DoubleConfigValidator extends ConfigValidatorImpl<Double> {
|
|
+ @Override
|
|
+ public Double convert(String value) throws IllegalArgumentException {
|
|
+ return Double.parseDouble(value);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public abstract static class ListConfigValidator<E> extends ConfigValidatorImpl<List<E>> {
|
|
+ public static class STRING extends ListConfigValidator<String> {
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public List<E> convert(String value) throws IllegalArgumentException {
|
|
+ throw new IllegalArgumentException("not support"); // TODO
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public abstract static class EnumConfigValidator<E extends Enum<E>> extends ConfigValidatorImpl<E> {
|
|
+
|
|
+ private final List<String> enumValues;
|
|
+
|
|
+ public EnumConfigValidator() {
|
|
+ super();
|
|
+ this.enumValues = new ArrayList<>() {{
|
|
+ for (E e : getFieldClass().getEnumConstants()) {
|
|
+ add(e.name().toLowerCase(Locale.ROOT));
|
|
+ }
|
|
+ }};
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public E convert(@NotNull String value) throws IllegalArgumentException {
|
|
+ return Enum.valueOf(getFieldClass(), value.toUpperCase(Locale.ROOT));
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public E loadConvert(@NotNull Object value) throws IllegalArgumentException {
|
|
+ return this.convert(value.toString());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Object saveConvert(@NotNull E value) {
|
|
+ return value.toString().toUpperCase(Locale.ROOT);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public List<String> valueSuggest() {
|
|
+ return enumValues;
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/config/GlobalConfig.java b/src/main/java/org/leavesmc/leaves/config/GlobalConfig.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..d6af8fd7552c5560f4397b9961dd5c39014e12ae
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/config/GlobalConfig.java
|
|
@@ -0,0 +1,17 @@
|
|
+package org.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 value();
|
|
+
|
|
+ boolean lock() default false;
|
|
+
|
|
+ Class<? extends ConfigValidator<?>> validator() default ConfigValidatorImpl.BooleanConfigValidator.class;
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/config/GlobalConfigCategory.java b/src/main/java/org/leavesmc/leaves/config/GlobalConfigCategory.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..1e109a8b95f7dd25f68f7b3d2115c8cf3c43e58c
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/config/GlobalConfigCategory.java
|
|
@@ -0,0 +1,12 @@
|
|
+package org.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.TYPE)
|
|
+@Retention(RetentionPolicy.RUNTIME)
|
|
+public @interface GlobalConfigCategory {
|
|
+ String value();
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/config/GlobalConfigCreator.java b/src/main/java/org/leavesmc/leaves/config/GlobalConfigCreator.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..dfc38bd1fbec54da52188e9ea860448e14342a99
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/config/GlobalConfigCreator.java
|
|
@@ -0,0 +1,84 @@
|
|
+package org.leavesmc.leaves.config;
|
|
+
|
|
+import org.bukkit.configuration.file.YamlConfiguration;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.LeavesConfig;
|
|
+
|
|
+import java.io.File;
|
|
+import java.io.IOException;
|
|
+import java.lang.reflect.Field;
|
|
+import java.lang.reflect.Modifier;
|
|
+import java.util.Collections;
|
|
+
|
|
+import static org.leavesmc.leaves.config.GlobalConfigManager.CONFIG_START;
|
|
+
|
|
+@SuppressWarnings("CallToPrintStackTrace")
|
|
+public class GlobalConfigCreator {
|
|
+
|
|
+ private static YamlConfiguration config;
|
|
+
|
|
+ @SuppressWarnings("ResultOfMethodCallIgnored")
|
|
+ public static void main(String[] args) {
|
|
+ config = new YamlConfiguration();
|
|
+ config.options().setHeader(Collections.singletonList(LeavesConfig.CONFIG_HEADER));
|
|
+
|
|
+ config.set("config-version", LeavesConfig.CURRENT_CONFIG_VERSION);
|
|
+
|
|
+ for (Field field : LeavesConfig.class.getDeclaredFields()) {
|
|
+ initField(field, null, CONFIG_START);
|
|
+ }
|
|
+
|
|
+ config.set("settings.protocol.xaero-map-server-id", 0);
|
|
+
|
|
+ try {
|
|
+ File file = new File("leaves.yml");
|
|
+ if (file.exists()) {
|
|
+ file.delete();
|
|
+ }
|
|
+ file.createNewFile();
|
|
+ config.save(file);
|
|
+ } catch (IOException e) {
|
|
+ e.printStackTrace();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static void initCategory(@NotNull Field categoryField, @NotNull GlobalConfigCategory globalCategory, @Nullable Object upstreamField, @NotNull String upstreamPath) {
|
|
+ try {
|
|
+ Object category = categoryField.get(upstreamField);
|
|
+ String categoryPath = upstreamPath + globalCategory.value() + ".";
|
|
+ for (Field field : categoryField.getType().getDeclaredFields()) {
|
|
+ initField(field, category, categoryPath);
|
|
+ }
|
|
+ } catch (Exception e) {
|
|
+ e.printStackTrace();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static void initField(@NotNull Field field, @Nullable Object upstreamField, @NotNull String upstreamPath) {
|
|
+ if (upstreamField != null || Modifier.isStatic(field.getModifiers())) {
|
|
+ field.setAccessible(true);
|
|
+
|
|
+ GlobalConfig globalConfig = field.getAnnotation(GlobalConfig.class);
|
|
+ if (globalConfig != null) {
|
|
+ initConfig(field, globalConfig, upstreamField, upstreamPath);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ GlobalConfigCategory globalCategory = field.getType().getAnnotation(GlobalConfigCategory.class);
|
|
+ if (globalCategory != null) {
|
|
+ initCategory(field, globalCategory, upstreamField, upstreamPath);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+
|
|
+ private static void initConfig(@NotNull Field field, GlobalConfig globalConfig, @Nullable Object upstreamField, @NotNull String upstreamPath) {
|
|
+ try {
|
|
+ GlobalConfigManager.VerifiedConfig verifiedConfig = GlobalConfigManager.VerifiedConfig.build(globalConfig, field, upstreamField, upstreamPath);
|
|
+ config.set(verifiedConfig.path(), verifiedConfig.validator().saveConvert(field.get(upstreamField)));
|
|
+ } catch (Exception e) {
|
|
+ e.printStackTrace();
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/config/GlobalConfigManager.java b/src/main/java/org/leavesmc/leaves/config/GlobalConfigManager.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..adc023d5b669d712ae7eae740f5ab43a7bd5731e
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/config/GlobalConfigManager.java
|
|
@@ -0,0 +1,232 @@
|
|
+package org.leavesmc.leaves.config;
|
|
+
|
|
+import org.jetbrains.annotations.Contract;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.jetbrains.annotations.Nullable;
|
|
+import org.leavesmc.leaves.LeavesConfig;
|
|
+import org.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;
|
|
+
|
|
+public class GlobalConfigManager {
|
|
+
|
|
+ public final static String CONFIG_START = "settings.";
|
|
+
|
|
+ private static boolean firstLoad = true;
|
|
+ private static final Map<String, VerifiedConfig> verifiedConfigs = new HashMap<>();
|
|
+
|
|
+ public static void init() {
|
|
+ verifiedConfigs.clear();
|
|
+
|
|
+ for (Field field : LeavesConfig.class.getDeclaredFields()) {
|
|
+ initField(field, null, CONFIG_START);
|
|
+ }
|
|
+
|
|
+ verifiedConfigs.forEach((path, config) -> config.validator.runAfterLoader(config.get(), firstLoad));
|
|
+
|
|
+ firstLoad = false;
|
|
+ LeavesConfig.save();
|
|
+ }
|
|
+
|
|
+ private static void initCategory(@NotNull Field categoryField, @NotNull GlobalConfigCategory globalCategory, @Nullable Object upstreamField, @NotNull String upstreamPath) {
|
|
+ try {
|
|
+ Object category = categoryField.get(upstreamField);
|
|
+ String categoryPath = upstreamPath + globalCategory.value() + ".";
|
|
+ for (Field field : categoryField.getType().getDeclaredFields()) {
|
|
+ initField(field, category, categoryPath);
|
|
+ }
|
|
+ } catch (Exception e) {
|
|
+ LeavesLogger.LOGGER.severe("Failure to load leaves config" + upstreamPath, e);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static void initField(@NotNull Field field, @Nullable Object upstreamField, @NotNull String upstreamPath) {
|
|
+ if (upstreamField != null || Modifier.isStatic(field.getModifiers())) {
|
|
+ field.setAccessible(true);
|
|
+
|
|
+ for (RemovedConfig config : field.getAnnotationsByType(RemovedConfig.class)) {
|
|
+ RemovedVerifiedConfig.build(config, field, upstreamField).run();
|
|
+ }
|
|
+
|
|
+ GlobalConfig globalConfig = field.getAnnotation(GlobalConfig.class);
|
|
+ if (globalConfig != null) {
|
|
+ initConfig(field, globalConfig, upstreamField, upstreamPath);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ GlobalConfigCategory globalCategory = field.getType().getAnnotation(GlobalConfigCategory.class);
|
|
+ if (globalCategory != null) {
|
|
+ initCategory(field, globalCategory, upstreamField, upstreamPath);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static void initConfig(@NotNull Field field, GlobalConfig globalConfig, @Nullable Object upstreamField, @NotNull String upstreamPath) {
|
|
+ try {
|
|
+ VerifiedConfig verifiedConfig = VerifiedConfig.build(globalConfig, field, upstreamField, upstreamPath);
|
|
+
|
|
+ if (globalConfig.lock() && !firstLoad) {
|
|
+ verifiedConfigs.put(verifiedConfig.path.substring(CONFIG_START.length()), verifiedConfig);
|
|
+ }
|
|
+
|
|
+ ConfigValidator<? super Object> validator = verifiedConfig.validator;
|
|
+
|
|
+ Object defValue = validator.saveConvert(field.get(upstreamField));
|
|
+ LeavesConfig.config.addDefault(verifiedConfig.path, defValue);
|
|
+
|
|
+ try {
|
|
+ Object savedValue = LeavesConfig.config.get(verifiedConfig.path);
|
|
+ if (savedValue == null) {
|
|
+ throw new IllegalArgumentException("?");
|
|
+ }
|
|
+
|
|
+ if (savedValue.getClass() != validator.getFieldClass()) {
|
|
+ savedValue = validator.loadConvert(savedValue);
|
|
+ }
|
|
+
|
|
+ validator.verify(null, savedValue);
|
|
+
|
|
+ field.set(upstreamField, savedValue);
|
|
+ } catch (IllegalArgumentException | ClassCastException e) {
|
|
+ LeavesConfig.config.set(verifiedConfig.path, defValue);
|
|
+ LeavesLogger.LOGGER.warning(e.getMessage() + ", reset to " + defValue);
|
|
+ }
|
|
+
|
|
+ verifiedConfigs.put(verifiedConfig.path.substring(CONFIG_START.length()), verifiedConfig);
|
|
+ } catch (Exception e) {
|
|
+ LeavesLogger.LOGGER.severe("Failure to load leaves config", e);
|
|
+ throw new RuntimeException();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static VerifiedConfig getVerifiedConfig(String path) {
|
|
+ return verifiedConfigs.get(path);
|
|
+ }
|
|
+
|
|
+ @Contract(pure = true)
|
|
+ public static @NotNull Set<String> getVerifiedConfigPaths() {
|
|
+ return verifiedConfigs.keySet();
|
|
+ }
|
|
+
|
|
+ public record RemovedVerifiedConfig(ConfigConverter<?> convert, boolean transform, Field field, Object upstreamField, String path) {
|
|
+
|
|
+ public void run() {
|
|
+ if (transform) {
|
|
+ if (LeavesConfig.config.contains(path)) {
|
|
+ Object savedValue = LeavesConfig.config.get(path);
|
|
+ if (savedValue != null) {
|
|
+ try {
|
|
+ if (savedValue.getClass() != convert.getFieldClass()) {
|
|
+ savedValue = convert.loadConvert(savedValue);
|
|
+ }
|
|
+ field.set(upstreamField, savedValue);
|
|
+ } catch (IllegalAccessException | IllegalArgumentException e) {
|
|
+ LeavesLogger.LOGGER.warning("Failure to load leaves config" + path, e);
|
|
+ }
|
|
+ } else {
|
|
+ LeavesLogger.LOGGER.warning("Failed to convert saved value for " + path + ", reset to default");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ LeavesConfig.config.set(path, null);
|
|
+ }
|
|
+
|
|
+ @Contract("_, _, _ -> new")
|
|
+ public static @NotNull RemovedVerifiedConfig build(@NotNull RemovedConfig config, @NotNull Field field, @Nullable Object upstreamField) {
|
|
+ StringBuilder path = new StringBuilder("settings.");
|
|
+ for (String category : config.category()) {
|
|
+ path.append(category).append(".");
|
|
+ }
|
|
+ path.append(config.name());
|
|
+
|
|
+ ConfigConverter<?> converter = null;
|
|
+ try {
|
|
+ Constructor<? extends ConfigConverter<?>> constructor = config.convert().getDeclaredConstructor();
|
|
+ constructor.setAccessible(true);
|
|
+ converter = constructor.newInstance();
|
|
+ } catch (Exception e) {
|
|
+ LeavesLogger.LOGGER.warning("Failure to load leaves config" + path, e);
|
|
+ }
|
|
+
|
|
+ return new RemovedVerifiedConfig(converter, config.transform(), field, upstreamField, path.toString());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public record VerifiedConfig(ConfigValidator<? super Object> validator, boolean lock, Field field, Object upstreamField, String path) {
|
|
+
|
|
+ public void set(String stringValue) throws IllegalArgumentException {
|
|
+ Object value;
|
|
+ try {
|
|
+ value = validator.convert(stringValue);
|
|
+ } catch (IllegalArgumentException e) {
|
|
+ throw new IllegalArgumentException("value parse error: " + e.getMessage());
|
|
+ }
|
|
+
|
|
+ validator.verify(this.get(), value);
|
|
+
|
|
+ try {
|
|
+ LeavesConfig.config.set(path, validator.saveConvert(value));
|
|
+ LeavesConfig.save();
|
|
+ if (lock) {
|
|
+ throw new IllegalArgumentException("locked, will load after restart");
|
|
+ }
|
|
+ field.set(upstreamField, value);
|
|
+ } catch (IllegalAccessException e) {
|
|
+ throw new IllegalArgumentException(e.getMessage());
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public Object get() {
|
|
+ try {
|
|
+ return field.get(upstreamField);
|
|
+ } catch (IllegalAccessException e) {
|
|
+ LeavesLogger.LOGGER.severe("Failure to get " + path + " value", e);
|
|
+ return "<VALUE ERROR>";
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public String getString() {
|
|
+ Object value = this.get();
|
|
+
|
|
+ Object savedValue = LeavesConfig.config.get(path);
|
|
+ try {
|
|
+ if (savedValue != null) {
|
|
+ if (validator.getFieldClass() != savedValue.getClass()) {
|
|
+ savedValue = validator.loadConvert(savedValue);
|
|
+ }
|
|
+
|
|
+ if (!savedValue.equals(value)) {
|
|
+ return value.toString() + "(" + savedValue + " after restart)";
|
|
+ }
|
|
+ }
|
|
+ } catch (IllegalArgumentException e) {
|
|
+ LeavesLogger.LOGGER.severe("Failure to get " + path + " value", e);
|
|
+ }
|
|
+ return value.toString();
|
|
+ }
|
|
+
|
|
+ @SuppressWarnings("unchecked")
|
|
+ @NotNull
|
|
+ @Contract("_, _, _, _ -> new")
|
|
+ public static VerifiedConfig build(@NotNull GlobalConfig config, @NotNull Field field, @Nullable Object upstreamField, @NotNull String upstreamPath) {
|
|
+ String path = upstreamPath + config.value();
|
|
+
|
|
+ ConfigValidator<? super Object> validator;
|
|
+ try {
|
|
+ Constructor<? extends ConfigValidator<?>> constructor = config.validator().getDeclaredConstructor();
|
|
+ constructor.setAccessible(true);
|
|
+ validator = (ConfigValidator<? super Object>) constructor.newInstance();
|
|
+ } catch (Exception e) {
|
|
+ LeavesLogger.LOGGER.severe("Failure to load leaves config" + path, e);
|
|
+ throw new RuntimeException();
|
|
+ }
|
|
+
|
|
+ return new VerifiedConfig(validator, config.lock(), field, upstreamField, path);
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/leavesmc/leaves/config/RemovedConfig.java b/src/main/java/org/leavesmc/leaves/config/RemovedConfig.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..a0364c2a5c4d56d30500233cd8294793309c7978
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/leavesmc/leaves/config/RemovedConfig.java
|
|
@@ -0,0 +1,27 @@
|
|
+package org.leavesmc.leaves.config;
|
|
+
|
|
+import java.lang.annotation.ElementType;
|
|
+import java.lang.annotation.Repeatable;
|
|
+import java.lang.annotation.Retention;
|
|
+import java.lang.annotation.RetentionPolicy;
|
|
+import java.lang.annotation.Target;
|
|
+
|
|
+@Target(ElementType.FIELD)
|
|
+@Retention(RetentionPolicy.RUNTIME)
|
|
+@Repeatable(RemovedConfig.Array.class)
|
|
+public @interface RemovedConfig {
|
|
+
|
|
+ String name();
|
|
+
|
|
+ String[] category();
|
|
+
|
|
+ boolean transform() default false;
|
|
+
|
|
+ Class<? extends ConfigConverter<?>> convert() default ConfigValidatorImpl.BooleanConfigValidator.class;
|
|
+
|
|
+ @Target(ElementType.FIELD)
|
|
+ @Retention(RetentionPolicy.RUNTIME)
|
|
+ @interface Array {
|
|
+ RemovedConfig[] value();
|
|
+ }
|
|
+}
|