diff --git a/.editorconfig b/.editorconfig index c605f877..227a561f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,3 +1,5 @@ +root = true + [*] charset = utf-8 end_of_line = lf @@ -54,6 +56,7 @@ ij_java_blank_lines_after_package = 1 ij_java_blank_lines_around_class = 1 ij_java_blank_lines_around_field = 0 ij_java_blank_lines_around_field_in_interface = 0 +ij_java_blank_lines_around_field_with_annotations = 0 ij_java_blank_lines_around_initializer = 1 ij_java_blank_lines_around_method = 1 ij_java_blank_lines_around_method_in_interface = 1 @@ -131,6 +134,7 @@ ij_java_for_statement_right_paren_on_new_line = false ij_java_for_statement_wrap = off ij_java_generate_final_locals = false ij_java_generate_final_parameters = false +ij_java_generate_use_type_annotation_before_type = true ij_java_if_brace_force = never ij_java_imports_layout = *, |, javax.**, java.**, |, $* ij_java_indent_case_from_switch = true @@ -276,6 +280,7 @@ ij_java_spaces_around_relational_operators = true ij_java_spaces_around_shift_operators = true ij_java_spaces_around_type_bounds_in_type_parameters = true ij_java_spaces_around_unary_operator = false +ij_java_spaces_inside_block_braces_when_body_is_present = false ij_java_spaces_within_angle_brackets = false ij_java_spaces_within_annotation_parentheses = false ij_java_spaces_within_array_initializer_braces = false @@ -307,7 +312,7 @@ ij_java_test_name_suffix = Test ij_java_throws_keyword_wrap = off ij_java_throws_list_wrap = off ij_java_use_external_annotations = false -ij_java_use_fq_class_names = false +ij_java_use_fq_class_names = true ij_java_use_relative_indents = false ij_java_use_single_class_imports = true ij_java_variable_annotation_wrap = off @@ -393,6 +398,7 @@ ij_kotlin_finally_on_new_line = false ij_kotlin_if_rparen_on_new_line = true ij_kotlin_import_nested_classes = false ij_kotlin_imports_layout = *, java.**, javax.**, kotlin.**, ^ +ij_kotlin_indent_before_arrow_on_new_line = true ij_kotlin_insert_whitespaces_in_simple_one_line_method = true ij_kotlin_keep_blank_lines_before_right_brace = 2 ij_kotlin_keep_blank_lines_in_code = 2 @@ -428,6 +434,7 @@ ij_kotlin_space_before_when_parentheses = true ij_kotlin_space_before_while_parentheses = true ij_kotlin_spaces_around_additive_operators = true ij_kotlin_spaces_around_assignment_operators = true +ij_kotlin_spaces_around_elvis = true ij_kotlin_spaces_around_equality_operators = true ij_kotlin_spaces_around_function_type_arrow = true ij_kotlin_spaces_around_logical_operators = true @@ -521,6 +528,9 @@ ij_yaml_block_mapping_on_new_line = false ij_yaml_indent_sequence_value = true ij_yaml_keep_indents_on_empty_lines = false ij_yaml_keep_line_breaks = true +ij_yaml_line_comment_add_space = false +ij_yaml_line_comment_add_space_on_reformat = false +ij_yaml_line_comment_at_first_column = true ij_yaml_sequence_on_new_line = false ij_yaml_space_before_colon = false ij_yaml_spaces_within_braces = true diff --git a/patches/server/0001-Build-changes.patch b/patches/server/0001-Build-changes.patch index 0fcde09d..bf5eb8b9 100644 --- a/patches/server/0001-Build-changes.patch +++ b/patches/server/0001-Build-changes.patch @@ -273,6 +273,15 @@ index 774556a62eb240da42e84db4502e2ed43495be17..fdef98a7796d84c7b0ee61241859e10c Properties properties = new Properties(); if (stream != null) { +diff --git a/src/main/java/org/leavesmc/leaves/.editorconfig b/src/main/java/org/leavesmc/leaves/.editorconfig +new file mode 100644 +index 0000000000000000000000000000000000000000..6f086600baf9c98d681c4f5be5bb29c0e2086e6a +--- /dev/null ++++ b/src/main/java/org/leavesmc/leaves/.editorconfig +@@ -0,0 +1,2 @@ ++[*.java] ++ij_java_use_fq_class_names = false +\ No newline at end of file diff --git a/src/main/java/org/leavesmc/leaves/region/LeavesHooks.java b/src/main/java/org/leavesmc/leaves/region/LeavesHooks.java new file mode 100644 index 0000000000000000000000000000000000000000..47b6241ba0a23a0579b8b046f1e45832117b6581 diff --git a/patches/server/0006-Leaves-Server-Config-And-Command.patch b/patches/server/0006-Leaves-Server-Config-And-Command.patch index 86bf1265..0ae63526 100644 --- a/patches/server/0006-Leaves-Server-Config-And-Command.patch +++ b/patches/server/0006-Leaves-Server-Config-And-Command.patch @@ -85,7 +85,7 @@ index 44bbfc4eba78dfa268696c79b1d15c8f1271bbb1..a88ff89928c322fa1c42987a06991a56 .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..feddcbfa140aaac37fb502b8c5a09b36e6aa267b +index 0000000000000000000000000000000000000000..2c01d721b9a1b41ca4b82dc87aaf894a94ba1062 --- /dev/null +++ b/src/main/java/org/leavesmc/leaves/LeavesConfig.java @@ -0,0 +1,963 @@ @@ -191,14 +191,14 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + @GlobalConfigCategory("modify") + public static class ModifyConfig { + -+ public static FakeplayerConfig fakeplayer; ++ public FakeplayerConfig fakeplayer; + + @GlobalConfigCategory("fakeplayer") + public static class FakeplayerConfig { + + @RemovedConfig(name = "enable", category = "fakeplayer", transform = true) + @GlobalConfig(value = "enable", validator = FakeplayerValidator.class) -+ public static boolean enable = true; ++ public boolean enable = true; + + private static class FakeplayerValidator extends BooleanConfigValidator { + @Override @@ -214,19 +214,19 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + + @RemovedConfig(name = "unable-fakeplayer-names", category = "fakeplayer", convert = ListConfigValidator.STRING.class, transform = true) + @GlobalConfig(value = "unable-fakeplayer-names", validator = ListConfigValidator.STRING.class) -+ public static List unableNames = List.of("player-name"); ++ public List unableNames = List.of("player-name"); + + @GlobalConfig(value = "limit", validator = IntConfigValidator.class) -+ public static int limit = 10; ++ public int limit = 10; + + @GlobalConfig(value = "prefix", validator = StringConfigValidator.class) -+ public static String prefix = ""; ++ public String prefix = ""; + + @GlobalConfig(value = "suffix", validator = StringConfigValidator.class) -+ public static String suffix = ""; ++ public String suffix = ""; + + @GlobalConfig(value = "regen-amount", validator = RegenAmountValidator.class) -+ public static double regenAmount = 0.0; ++ public double regenAmount = 0.0; + + private static class RegenAmountValidator extends DoubleConfigValidator { + @Override @@ -238,67 +238,67 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig("always-send-data") -+ public static boolean canSendDataAlways = true; ++ public boolean canSendDataAlways = true; + + @GlobalConfig("resident-fakeplayer") -+ public static boolean canResident = false; ++ public boolean canResident = false; + + @GlobalConfig("open-fakeplayer-inventory") -+ public static boolean canOpenInventory = false; ++ public boolean canOpenInventory = false; + + @GlobalConfig("skip-sleep-check") -+ public static boolean canSkipSleep = false; ++ public boolean canSkipSleep = false; + + @GlobalConfig("spawn-phantom") -+ public static boolean canSpawnPhantom = false; ++ public boolean canSpawnPhantom = false; + + @GlobalConfig("use-action") -+ public static boolean canUseAction = true; ++ public boolean canUseAction = true; + + @GlobalConfig("modify-config") -+ public static boolean canModifyConfig = false; ++ public boolean canModifyConfig = false; + + @GlobalConfig("manual-save-and-load") -+ public static boolean canManualSaveAndLoad = false; ++ public boolean canManualSaveAndLoad = false; + + @GlobalConfig(value = "cache-skin", lock = true) -+ public static boolean useSkinCache = false; ++ public boolean useSkinCache = false; + } + -+ public static MinecraftOLDConfig oldMC; ++ public MinecraftOLDConfig oldMC; + + @GlobalConfigCategory("minecraft-old") + public static class MinecraftOLDConfig { + -+ public static BlockUpdaterConfig updater; ++ public BlockUpdaterConfig updater; + + @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 static boolean instantBlockUpdaterReintroduced = false; ++ public boolean instantBlockUpdaterReintroduced = false; + + @RemovedConfig(name = "cce-update-suppression", category = {"modify", "minecraft-old"}, transform = true) + @GlobalConfig("cce-update-suppression") -+ public static boolean cceUpdateSuppression = false; ++ 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 static boolean redstoneDontCantOnTrapDoor = false; ++ 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 static boolean shearsInDispenserCanZeroAmount = false; ++ public boolean shearsInDispenserCanZeroAmount = false; + + @GlobalConfig("armor-stand-cant-kill-by-mob-projectile") -+ public static boolean armorStandCantKillByMobProjectile = false; ++ public boolean armorStandCantKillByMobProjectile = false; + + @GlobalConfig(value = "villager-infinite-discounts", validator = VillagerInfiniteDiscountsValidator.class) -+ public static boolean villagerInfiniteDiscounts = false; ++ public boolean villagerInfiniteDiscounts = false; + + private static class VillagerInfiniteDiscountsValidator extends BooleanConfigValidator { + @Override @@ -308,18 +308,18 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig("copper-bulb-1gt-delay") -+ public static boolean copperBulb1gt = false; ++ public boolean copperBulb1gt = false; + + @GlobalConfig("crafter-1gt-delay") -+ public static boolean crafter1gt = false; ++ public boolean crafter1gt = false; + + @RemovedConfig(name = "zero-tick-plants", category = "modify", transform = true) + @GlobalConfig("zero-tick-plants") -+ public static boolean zeroTickPlants = false; ++ 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 static boolean rngFishing = false; ++ public boolean rngFishing = false; + + private static class RNGFishingValidator extends BooleanConfigValidator { + @Override @@ -329,92 +329,92 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig("allow-grindstone-overstacking") -+ public static boolean allowGrindstoneOverstacking = false; ++ public boolean allowGrindstoneOverstacking = false; + + @GlobalConfig("allow-entity-portal-with-passenger") -+ public static boolean allowEntityPortalWithPassenger = true; ++ public boolean allowEntityPortalWithPassenger = true; + + @GlobalConfig("disable-gateway-portal-entity-ticking") -+ public static boolean disableGatewayPortalEntityTicking = false; ++ public boolean disableGatewayPortalEntityTicking = false; + + @GlobalConfig("disable-LivingEntity-ai-step-alive-check") -+ public static boolean disableLivingEntityAiStepAliveCheck = false; ++ public boolean disableLivingEntityAiStepAliveCheck = false; + + @GlobalConfig("fix-fortress-mob-spawn") -+ public static boolean fixFortressMobSpawn = false; ++ public boolean fixFortressMobSpawn = false; + + @GlobalConfig("old-block-entity-behaviour") -+ public static boolean oldBlockEntityBehaviour = false; ++ public boolean oldBlockEntityBehaviour = false; + -+ public static RaidConfig raid; ++ public RaidConfig raid; + + @GlobalConfigCategory("revert-raid-changes") + public static class RaidConfig { + @GlobalConfig("allow-bad-omen-trigger-raid") -+ public static boolean allowBadOmenTriggerRaid = false; ++ public boolean allowBadOmenTriggerRaid = false; + + @GlobalConfig("give-bad-omen-when-kill-patrol-leader") -+ public static boolean giveBadOmenWhenKillPatrolLeader = false; ++ public boolean giveBadOmenWhenKillPatrolLeader = false; + } + + @GlobalConfig("allow-anvil-destroy-item-entities") -+ public static boolean allowAnvilDestroyItemEntities = false; ++ public boolean allowAnvilDestroyItemEntities = false; + + @GlobalConfig("string-tripwire-hook-duplicate") -+ public static boolean stringTripwireHookDuplicate = false; ++ public boolean stringTripwireHookDuplicate = false; + } + -+ public static ElytraAeronauticsConfig elytraAeronautics; ++ public ElytraAeronauticsConfig elytraAeronautics; + + @GlobalConfigCategory("elytra-aeronautics") + public static class ElytraAeronauticsConfig { + @GlobalConfig("no-chunk-load") -+ public static boolean noChunk = false; ++ public boolean noChunk = false; + + @GlobalConfig(value = "no-chunk-height", validator = DoubleConfigValidator.class) -+ public static double noChunkHeight = 500.0D; ++ public double noChunkHeight = 500.0D; + + @GlobalConfig(value = "no-chunk-speed", validator = DoubleConfigValidator.class) -+ public static double noChunkSpeed = -1.0D; ++ public double noChunkSpeed = -1.0D; + + @GlobalConfig("message") -+ public static boolean noChunkMes = true; ++ public boolean noChunkMes = true; + + @GlobalConfig(value = "message-start", validator = StringConfigValidator.class) -+ public static String noChunkStartMes = "Flight enter cruise mode"; ++ public String noChunkStartMes = "Flight enter cruise mode"; + + @GlobalConfig(value = "message-end", validator = StringConfigValidator.class) -+ public static String noChunkEndMes = "Flight exit cruise mode"; ++ public String noChunkEndMes = "Flight exit cruise mode"; + } + + @RemovedConfig(name = "redstone-shears-wrench", category = {}, transform = true) + @GlobalConfig("redstone-shears-wrench") -+ public static boolean redstoneShearsWrench = true; ++ public boolean redstoneShearsWrench = true; + + @RemovedConfig(name = "budding-amethyst-can-push-by-piston", category = {}, transform = true) + @GlobalConfig("budding-amethyst-can-push-by-piston") -+ public static boolean buddingAmethystCanPushByPiston = false; ++ public boolean buddingAmethystCanPushByPiston = false; + + @RemovedConfig(name = "spectator-dont-get-advancement", category = {}, transform = true) + @GlobalConfig("spectator-dont-get-advancement") -+ public static boolean spectatorDontGetAdvancement = false; ++ public boolean spectatorDontGetAdvancement = false; + + @RemovedConfig(name = "stick-change-armorstand-arm-status", category = {}, transform = true) + @GlobalConfig("stick-change-armorstand-arm-status") -+ public static boolean stickChangeArmorStandArmStatus = true; ++ public boolean stickChangeArmorStandArmStatus = true; + + @RemovedConfig(name = "snowball-and-egg-can-knockback-player", category = {}, transform = true) + @GlobalConfig("snowball-and-egg-can-knockback-player") -+ public static boolean snowballAndEggCanKnockback = true; ++ public boolean snowballAndEggCanKnockback = true; + + @GlobalConfig("flatten-triangular-distribution") -+ public static boolean flattenTriangularDistribution = false; ++ public boolean flattenTriangularDistribution = false; + + @GlobalConfig("player-operation-limiter") -+ public static boolean playerOperationLimiter = false; ++ public boolean playerOperationLimiter = false; + + @GlobalConfig(value = "renewable-elytra", validator = RenewableElytraValidator.class) -+ public static double renewableElytra = -1.0F; ++ public double renewableElytra = -1.0F; + + private static class RenewableElytraValidator extends DoubleConfigValidator { + @Override @@ -425,26 +425,26 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + } + -+ public static int shulkerBoxStackSize = 1; ++ public int shulkerBoxStackSize = 1; + @GlobalConfig(value = "stackable-shulker-boxes", validator = StackableShulkerValidator.class) -+ private static String stackableShulkerBoxes = "false"; ++ 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"; -+ shulkerBoxStackSize = Integer.parseInt(realValue); ++ LeavesConfig.modify.shulkerBoxStackSize = Integer.parseInt(realValue); + } + } + + @GlobalConfig("force-void-trade") -+ public static boolean forceVoidTrade = false; ++ public boolean forceVoidTrade = false; + + @GlobalConfig("disable-moved-wrongly-threshold") -+ public static boolean disableMovedWronglyThreshold = false; ++ public boolean disableMovedWronglyThreshold = false; + + @GlobalConfig(value = "mc-technical-survival-mode", validator = McTechnicalModeValidator.class, lock = true) -+ public static boolean mcTechnicalMode = true; ++ public boolean mcTechnicalMode = true; + + private static class McTechnicalModeValidator extends BooleanConfigValidator { + @Override @@ -456,10 +456,10 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig("return-nether-portal-fix") -+ public static boolean netherPortalFix = false; ++ public boolean netherPortalFix = false; + + @GlobalConfig(value = "use-vanilla-random", lock = true, validator = UseVanillaRandomValidator.class) -+ public static boolean useVanillaRandom = false; ++ public boolean useVanillaRandom = false; + + private static class UseVanillaRandomValidator extends BooleanConfigValidator { + @Override @@ -469,37 +469,37 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig("fix-update-suppression-crash") -+ public static boolean updateSuppressionCrashFix = true; ++ public boolean updateSuppressionCrashFix = true; + + @GlobalConfig(value = "bedrock-break-list", lock = true) -+ public static boolean bedrockBreakList = false; ++ public boolean bedrockBreakList = false; + + @GlobalConfig(value = "disable-distance-check-for-use-item", validator = DisableDistanceCheckForUseItemValidator.class) -+ public static boolean disableDistanceCheckForUseItem = false; ++ public boolean disableDistanceCheckForUseItem = false; + + private static class DisableDistanceCheckForUseItemValidator extends BooleanConfigValidator { + @Override + public void verify(Boolean old, Boolean value) throws IllegalArgumentException { -+ if (ProtocolConfig.alternativeBlockPlacement != ProtocolConfig.AlternativePlaceType.NONE && !value) { ++ 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 static boolean noFeatherFallingTrample = false; ++ public boolean noFeatherFallingTrample = false; + + @GlobalConfig("shared-villager-discounts") -+ public static boolean sharedVillagerDiscounts = false; ++ public boolean sharedVillagerDiscounts = false; + + @GlobalConfig("disable-check-out-of-order-command") -+ public static boolean disableCheckOutOfOrderCommand = false; ++ public boolean disableCheckOutOfOrderCommand = false; + + @GlobalConfig("despawn-enderman-with-block") -+ public static boolean despawnEndermanWithBlock = false; ++ public boolean despawnEndermanWithBlock = false; + + @GlobalConfig(value = "creative-no-clip", validator = CreativeNoClipValidator.class) -+ public static boolean creativeNoClip = false; ++ public boolean creativeNoClip = false; + + private static class CreativeNoClipValidator extends BooleanConfigValidator { + @Override @@ -509,16 +509,16 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig("shave-snow-layers") -+ public static boolean shaveSnowLayers = true; ++ public boolean shaveSnowLayers = true; + + @GlobalConfig("ignore-lc") -+ public static boolean ignoreLC = false; ++ public boolean ignoreLC = false; + + @GlobalConfig("disable-packet-limit") -+ public static boolean disablePacketLimit = false; ++ public boolean disablePacketLimit = false; + + @GlobalConfig(value = "lava-riptide", validator = LavaRiptideValidator.class) -+ public static boolean lavaRiptide = false; ++ public boolean lavaRiptide = false; + + private static class LavaRiptideValidator extends BooleanConfigValidator { + @Override @@ -528,7 +528,7 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig(value = "no-block-update-command", validator = NoBlockUpdateValidator.class) -+ public static boolean noBlockUpdateCommand = false; ++ public boolean noBlockUpdateCommand = false; + + private static class NoBlockUpdateValidator extends BooleanConfigValidator { + @Override @@ -542,16 +542,16 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig("no-tnt-place-update") -+ public static boolean noTNTPlaceUpdate = false; ++ public boolean noTNTPlaceUpdate = false; + + @GlobalConfig("raider-die-skip-self-raid-check") -+ public static boolean skipSelfRaidCheck = false; ++ public boolean skipSelfRaidCheck = false; + + @GlobalConfig("container-passthrough") -+ public static boolean containerPassthrough = false; ++ public boolean containerPassthrough = false; + + @GlobalConfig(value = "avoid-anvil-too-expensive", validator = AnvilNotExpensiveValidator.class) -+ public static boolean avoidAnvilTooExpensive = false; ++ public boolean avoidAnvilTooExpensive = false; + + private static class AnvilNotExpensiveValidator extends BooleanConfigValidator { + @Override @@ -561,13 +561,13 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig("bow-infinity-fix") -+ public static boolean bowInfinityFix = false; ++ public boolean bowInfinityFix = false; + + @GlobalConfig("hopper-counter") -+ public static boolean hopperCounter = false; ++ public boolean hopperCounter = false; + + @GlobalConfig(value = "spider-jockeys-drop-gapples", validator = JockeysDropGAppleValidator.class) -+ public static double spiderJockeysDropGapples = -1.0; ++ public double spiderJockeysDropGapples = -1.0; + + private static class JockeysDropGAppleValidator extends DoubleConfigValidator { + @Override @@ -579,13 +579,13 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig("renewable-deepslate") -+ public static boolean renewableDeepslate = false; ++ public boolean renewableDeepslate = false; + + @GlobalConfig("renewable-sponges") -+ public static boolean renewableSponges = false; ++ public boolean renewableSponges = false; + + @GlobalConfig(value = "renewable-coral", validator = RenewableCoralValidator.class) -+ public static RenewableCoralType renewableCoral = RenewableCoralType.FALSE; ++ public RenewableCoralType renewableCoral = RenewableCoralType.FALSE; + + public enum RenewableCoralType { + FALSE, TRUE, EXPANDED @@ -599,10 +599,10 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig("fast-resume") -+ public static boolean fastResume = false; ++ public boolean fastResume = false; + + @GlobalConfig(value = "force-peaceful-mode", validator = ForcePeacefulModeValidator.class) -+ public static int forcePeacefulMode = -1; ++ public int forcePeacefulMode = -1; + + private static class ForcePeacefulModeValidator extends IntConfigValidator { + @Override @@ -614,13 +614,13 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig("disable-vault-blacklist") -+ public static boolean disableVaultBlacklist = false; ++ 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"}) -+ private static final boolean removed = false; ++ private final boolean removed = false; + } + + public static PerformanceConfig performance; @@ -628,85 +628,85 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + @GlobalConfigCategory("performance") + public static class PerformanceConfig { + -+ public static PerformanceRemoveConfig remove; ++ public PerformanceRemoveConfig remove; + + @GlobalConfigCategory("remove") + public static class PerformanceRemoveConfig { + @GlobalConfig("tick-guard-lambda") -+ public static boolean tickGuardLambda = true; ++ public boolean tickGuardLambda = true; + + @GlobalConfig("inventory-contains-iterators") -+ public static boolean inventoryContainsIterators = true; ++ public boolean inventoryContainsIterators = true; + + @GlobalConfig("damage-lambda") -+ public static boolean damageLambda = true; ++ public boolean damageLambda = true; + } + + @GlobalConfig("optimized-dragon-respawn") -+ public static boolean optimizedDragonRespawn = false; ++ public boolean optimizedDragonRespawn = false; + + @GlobalConfig("dont-send-useless-entity-packets") -+ public static boolean dontSendUselessEntityPackets = true; ++ public boolean dontSendUselessEntityPackets = true; + + @GlobalConfig("enable-suffocation-optimization") -+ public static boolean enableSuffocationOptimization = true; ++ public boolean enableSuffocationOptimization = true; + + @GlobalConfig("check-spooky-season-once-an-hour") -+ public static boolean checkSpookySeasonOnceAnHour = true; ++ public boolean checkSpookySeasonOnceAnHour = true; + + @GlobalConfig("inactive-goal-selector-disable") -+ public static boolean throttleInactiveGoalSelectorTick = false; ++ public boolean throttleInactiveGoalSelectorTick = false; + + @GlobalConfig("reduce-entity-allocations") -+ public static boolean reduceEntityAllocations = true; ++ public boolean reduceEntityAllocations = true; + + @GlobalConfig("cache-climb-check") -+ public static boolean cacheClimbCheck = true; ++ public boolean cacheClimbCheck = true; + + @GlobalConfig(value = "biome-temperatures-use-aging-cache", lock = true) -+ public static boolean biomeTemperaturesUseAgingCache = true; ++ public boolean biomeTemperaturesUseAgingCache = true; + + @GlobalConfig("reduce-chuck-load-and-lookup") -+ public static boolean reduceChuckLoadAndLookup = true; ++ public boolean reduceChuckLoadAndLookup = true; + + @GlobalConfig("cache-ignite-odds") -+ public static boolean cacheIgniteOdds = true; ++ public boolean cacheIgniteOdds = true; + + @GlobalConfig("faster-chunk-serialization") -+ public static boolean fasterChunkSerialization = true; ++ public boolean fasterChunkSerialization = true; + + @GlobalConfig("cache-world-generator-sea-level") -+ public static boolean cacheWorldGeneratorSeaLevel = true; ++ public boolean cacheWorldGeneratorSeaLevel = true; + + @GlobalConfig("skip-secondary-POI-sensor-if-absent") -+ public static boolean skipSecondaryPOISensorIfAbsent = true; ++ public boolean skipSecondaryPOISensorIfAbsent = true; + + @GlobalConfig("store-mob-counts-in-array") -+ public static boolean storeMobCountsInArray = true; ++ public boolean storeMobCountsInArray = true; + + @GlobalConfig("optimize-noise-generation") -+ public static boolean optimizeNoiseGeneration = false; ++ public boolean optimizeNoiseGeneration = false; + + @GlobalConfig("optimize-sun-burn-tick") -+ public static boolean optimizeSunBurnTick = true; ++ public boolean optimizeSunBurnTick = true; + + @GlobalConfig("optimized-CubePointRange") -+ public static boolean optimizedCubePointRange = true; ++ public boolean optimizedCubePointRange = true; + + @GlobalConfig("check-frozen-ticks-before-landing-block") -+ public static boolean checkFrozenTicksBeforeLandingBlock = true; ++ public boolean checkFrozenTicksBeforeLandingBlock = true; + + @GlobalConfig("skip-entity-move-if-movement-is-zero") -+ public static boolean skipEntityMoveIfMovementIsZero = true; ++ public boolean skipEntityMoveIfMovementIsZero = true; + + @GlobalConfig("skip-cloning-advancement-criteria") -+ public static boolean skipCloningAdvancementCriteria = false; ++ public boolean skipCloningAdvancementCriteria = false; + + @GlobalConfig("skip-negligible-planar-movement-multiplication") -+ public static boolean skipNegligiblePlanarMovementMultiplication = true; ++ public boolean skipNegligiblePlanarMovementMultiplication = true; + + @GlobalConfig("fix-villagers-dont-release-memory") -+ public static boolean villagersDontReleaseMemoryFix = false; ++ public boolean villagersDontReleaseMemoryFix = false; + + @RemovedConfig(name = "cache-ominous-banner-item", category = "performance") + @RemovedConfig(name = "use-optimized-collection", category = "performance") @@ -729,7 +729,7 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + @RemovedConfig(name = "improve-fluid-direction-caching", category = "performance") + @RemovedConfig(name = "cache-BlockStatePairKey-hash", category = "performance") + @RemovedConfig(name = "optimize-chunk-ticking", category = "performance") -+ private final static boolean removedPerformance = true; ++ private final boolean removedPerformance = true; + } + + public static ProtocolConfig protocol; @@ -737,15 +737,15 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + @GlobalConfigCategory("protocol") + public static class ProtocolConfig { + -+ public static BladerenConfig bladeren; ++ public BladerenConfig bladeren; + + @GlobalConfigCategory("bladeren") + public static class BladerenConfig { + @GlobalConfig("protocol") -+ public static boolean enable = true; ++ public boolean enable = true; + + @GlobalConfig(value = "mspt-sync-protocol", validator = MSPTSyncValidator.class) -+ public static boolean msptSyncProtocol = false; ++ public boolean msptSyncProtocol = false; + + private static class MSPTSyncValidator extends BooleanConfigValidator { + @Override @@ -755,7 +755,7 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig(value = "mspt-sync-tick-interval", validator = MSPTSyncIntervalValidator.class) -+ public static int msptSyncTickInterval = 20; ++ public int msptSyncTickInterval = 20; + + private static class MSPTSyncIntervalValidator extends IntConfigValidator { + @Override @@ -767,12 +767,12 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + } + -+ public static SyncmaticaConfig syncmatica; ++ public SyncmaticaConfig syncmatica; + + @GlobalConfigCategory("syncmatica") + public static class SyncmaticaConfig { + @GlobalConfig(value = "enable", validator = SyncmaticaValidator.class) -+ public static boolean enable = false; ++ public boolean enable = false; + + public static class SyncmaticaValidator extends BooleanConfigValidator { + @Override @@ -784,19 +784,19 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig("quota") -+ public static boolean useQuota = false; ++ public boolean useQuota = false; + + @GlobalConfig(value = "quota-limit", validator = IntConfigValidator.class) -+ public static int quotaLimit = 40000000; ++ public int quotaLimit = 40000000; + } + -+ public static PCAConfig pca; ++ public PCAConfig pca; + + @GlobalConfigCategory("pca") + public static class PCAConfig { + @RemovedConfig(name = "pca-sync-protocol", category = "protocol", transform = true) + @GlobalConfig(value = "pca-sync-protocol", validator = PcaValidator.class) -+ public static boolean enable = false; ++ public boolean enable = false; + + public static class PcaValidator extends BooleanConfigValidator { + @Override @@ -809,7 +809,7 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + + @RemovedConfig(name = "pca-sync-player-entity", category = "protocol", convert = PcaPlayerEntityValidator.class, transform = true) + @GlobalConfig(value = "pca-sync-player-entity", validator = PcaPlayerEntityValidator.class) -+ public static PcaPlayerEntityType syncPlayerEntity = PcaPlayerEntityType.OPS; ++ public PcaPlayerEntityType syncPlayerEntity = PcaPlayerEntityType.OPS; + + public enum PcaPlayerEntityType { + NOBODY, BOT, OPS, OPS_AND_SELF, EVERYONE @@ -819,38 +819,38 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + } + -+ public static AppleSkinConfig appleskin; ++ public AppleSkinConfig appleskin; + + @GlobalConfigCategory("appleskin") + public static class AppleSkinConfig { + @RemovedConfig(name = "appleskin-protocol", category = "protocol") + @GlobalConfig("protocol") -+ public static boolean enable = false; ++ public boolean enable = false; + + @GlobalConfig("sync-tick-interval") -+ public static int syncTickInterval = 20; ++ public int syncTickInterval = 20; + } + -+ public static ServuxConfig servux; ++ public ServuxConfig servux; + + @GlobalConfigCategory("servux") + public static class ServuxConfig { + @RemovedConfig(name = "servux-protocol", category = "protocol", transform = true) + @GlobalConfig("structure-protocol") -+ public static boolean structureProtocol = false; ++ public boolean structureProtocol = false; + + @GlobalConfig("entity-protocol") -+ public static boolean entityProtocol = false; ++ public boolean entityProtocol = false; + } + + @GlobalConfig("bbor-protocol") -+ public static boolean bborProtocol = false; ++ public boolean bborProtocol = false; + + @GlobalConfig("jade-protocol") -+ public static boolean jadeProtocol = false; ++ public boolean jadeProtocol = false; + + @GlobalConfig(value = "alternative-block-placement", validator = AlternativePlaceValidator.class) -+ public static AlternativePlaceType alternativeBlockPlacement = AlternativePlaceType.NONE; ++ public AlternativePlaceType alternativeBlockPlacement = AlternativePlaceType.NONE; + + public enum AlternativePlaceType { + NONE, CARPET, CARPET_FIX, LITEMATICA @@ -860,19 +860,19 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + @Override + public void runAfterLoader(AlternativePlaceType value, boolean firstLoad) { + if (value != AlternativePlaceType.NONE) { -+ ModifyConfig.disableDistanceCheckForUseItem = true; ++ LeavesConfig.modify.disableDistanceCheckForUseItem = true; + } + } + } + + @GlobalConfig("xaero-map-protocol") -+ public static boolean xaeroMapProtocol = false; ++ public boolean xaeroMapProtocol = false; + + @GlobalConfig(value = "xaero-map-server-id", validator = IntConfigValidator.class) -+ public static int xaeroMapServerID = new Random().nextInt(); ++ public int xaeroMapServerID = new Random().nextInt(); + + @GlobalConfig("leaves-carpet-support") -+ public static boolean leavesCarpetSupport = false; ++ public boolean leavesCarpetSupport = false; + } + + public static MiscConfig mics; @@ -880,12 +880,12 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + @GlobalConfigCategory("misc") + public static class MiscConfig { + -+ public static AutoUpdateConfig autoUpdate; ++ public AutoUpdateConfig autoUpdate; + + @GlobalConfigCategory("auto-update") + public static class AutoUpdateConfig { + @GlobalConfig(value = "enable", lock = true, validator = AutoUpdateValidator.class) -+ public static boolean enable = false; ++ public boolean enable = false; + + private static class AutoUpdateValidator extends BooleanConfigValidator { + @Override @@ -900,7 +900,7 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig(value = "download-source", lock = true, validator = DownloadSourceValidator.class) -+ public static String source = "application"; ++ public String source = "application"; + + public static class DownloadSourceValidator extends StringConfigValidator { + private static final List suggestSourceList = List.of("application", "ghproxy", "cloud"); @@ -912,18 +912,18 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig("allow-experimental") -+ public static Boolean allowExperimental = false; ++ public Boolean allowExperimental = false; + + @GlobalConfig(value = "time", lock = true, validator = ListConfigValidator.STRING.class) -+ public static List updateTime = List.of("14:00", "2:00"); ++ public List updateTime = List.of("14:00", "2:00"); + } + -+ public static ExtraYggdrasilConfig yggdrasil; ++ public ExtraYggdrasilConfig yggdrasil; + + @GlobalConfigCategory("extra-yggdrasil-service") + public static class ExtraYggdrasilConfig { + @GlobalConfig(value = "enable", validator = ExtraYggdrasilValidator.class) -+ public static boolean enable = false; ++ public boolean enable = false; + + public static class ExtraYggdrasilValidator extends BooleanConfigValidator { + @Override @@ -936,10 +936,10 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig("login-protect") -+ public static boolean loginProtect = false; ++ public boolean loginProtect = false; + + @GlobalConfig(value = "urls", lock = true, validator = ExtraYggdrasilUrlsValidator.class) -+ public static List serviceList = List.of("https://url.with.authlib-injector-yggdrasil"); ++ public List serviceList = List.of("https://url.with.authlib-injector-yggdrasil"); + + public static class ExtraYggdrasilUrlsValidator extends ListConfigValidator.STRING { + @Override @@ -950,17 +950,17 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig("disable-method-profiler") -+ public static boolean disableMethodProfiler = true; ++ public boolean disableMethodProfiler = true; + + @RemovedConfig(name = "no-chat-sign", category = {}, transform = true) + @GlobalConfig("no-chat-sign") -+ public static boolean noChatSign = true; ++ public boolean noChatSign = true; + + @GlobalConfig("dont-respond-ping-before-start-fully") -+ public static boolean dontRespondPingBeforeStart = true; ++ public boolean dontRespondPingBeforeStart = true; + + @GlobalConfig(value = "server-lang", lock = true, validator = ServerLangValidator.class) -+ public static String serverLang = "en_us"; ++ public String serverLang = "en_us"; + + private static class ServerLangValidator extends StringConfigValidator { + private static final List supportLang = List.of("en_us", "zh_cn"); @@ -979,16 +979,16 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig(value = "server-mod-name", validator = StringConfigValidator.class) -+ public static String serverModName = "Leaves"; ++ public String serverModName = "Leaves"; + + @GlobalConfig("bstats-privacy-mode") -+ public static boolean bstatsPrivacyMode = false; ++ public boolean bstatsPrivacyMode = false; + + @GlobalConfig("force-minecraft-command") -+ public static boolean forceMinecraftCommand = false; ++ public boolean forceMinecraftCommand = false; + + @GlobalConfig("leaves-packet-event") -+ public static boolean leavesPacketEvent = true; ++ public boolean leavesPacketEvent = true; + } + + public static RegionConfig region; @@ -997,26 +997,26 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + public static class RegionConfig { + + @GlobalConfig(value = "format", lock = true, validator = RegionFormatValidator.class) -+ public static org.leavesmc.leaves.region.RegionFileFormat format = org.leavesmc.leaves.region.RegionFileFormat.ANVIL; ++ public org.leavesmc.leaves.region.RegionFileFormat format = org.leavesmc.leaves.region.RegionFileFormat.ANVIL; + + private static class RegionFormatValidator extends EnumConfigValidator { + } + -+ public static LinearConfig linear; ++ public LinearConfig linear; + + @GlobalConfigCategory("linear") + public static class LinearConfig { + + @GlobalConfig(value = "flush-frequency", lock = true, validator = IntConfigValidator.class) -+ public static int flushFrequency = 10; ++ public int flushFrequency = 10; + + @GlobalConfig(value = "auto-convert-anvil-to-linear", lock = true) -+ public static boolean autoConvertAnvilToLinear = false; ++ public boolean autoConvertAnvilToLinear = false; + + @GlobalConfig(value = "flush-max-threads", lock = true, validator = IntConfigValidator.class) -+ public static int flushThreads = 1; ++ public int flushThreads = 1; + -+ public static int getLinearFlushThreads() { ++ public int getLinearFlushThreads() { + if (flushThreads < 0) { + return Math.max(Runtime.getRuntime().availableProcessors() + flushThreads, 1); + } else { @@ -1025,7 +1025,7 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @GlobalConfig(value = "compression-level", lock = true, validator = LinearCompressValidator.class) -+ public static int compressionLevel = 1; ++ public int compressionLevel = 1; + + private static class LinearCompressValidator extends IntConfigValidator { + @Override @@ -1037,7 +1037,7 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + } + + @RemovedConfig(name = "crash-on-broken-symlink", category = {"region", "linear"}) -+ private static final boolean linearCrashOnBrokenSymlink = true; ++ private final boolean linearCrashOnBrokenSymlink = true; + } + } + @@ -1046,10 +1046,10 @@ index 0000000000000000000000000000000000000000..feddcbfa140aaac37fb502b8c5a09b36 + @GlobalConfigCategory("fix") + public static class FixConfig { + @GlobalConfig("vanilla-hopper") -+ public static boolean vanillaHopper = false; ++ public boolean vanillaHopper = false; + + @RemovedConfig(name = "spigot-EndPlatform-destroy", category = "fix") -+ private static final boolean spigotEndPlatformDestroy = false; ++ 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 @@ -1691,18 +1691,20 @@ index 0000000000000000000000000000000000000000..1e109a8b95f7dd25f68f7b3d2115c8cf +} 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..740c3e36e426b10a92d1b53096e5be28ce5916c3 +index 0000000000000000000000000000000000000000..79f1d346fcd42dc12e54376420d93b1b0f064056 --- /dev/null +++ b/src/main/java/org/leavesmc/leaves/config/GlobalConfigCreator.java -@@ -0,0 +1,80 @@ +@@ -0,0 +1,90 @@ +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.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collections; @@ -1720,7 +1722,7 @@ index 0000000000000000000000000000000000000000..740c3e36e426b10a92d1b53096e5be28 + config.set("config-version", LeavesConfig.CURRENT_CONFIG_VERSION); + + for (Field field : LeavesConfig.class.getDeclaredFields()) { -+ initField(field, CONFIG_START); ++ initField(field, null, CONFIG_START); + } + + config.set("settings.protocol.xaero-map-server-id", 0); @@ -1737,38 +1739,46 @@ index 0000000000000000000000000000000000000000..740c3e36e426b10a92d1b53096e5be28 + } + } + -+ private static void initCategory(@NotNull Field categoryField, @NotNull GlobalConfigCategory globalCategory, @NotNull String upstreamPath) { ++ private static void initCategory(@NotNull Field categoryField, @NotNull GlobalConfigCategory globalCategory, @Nullable Object upstreamField, @NotNull String upstreamPath) { + try { ++ Class categoryClass = categoryField.getType(); ++ ++ Constructor constructor = categoryClass.getDeclaredConstructor(); ++ constructor.setAccessible(true); ++ Object category = constructor.newInstance(); ++ categoryField.set(upstreamField, category); ++ + String categoryPath = upstreamPath + globalCategory.value() + "."; -+ for (Field field : categoryField.getType().getDeclaredFields()) { -+ initField(field, categoryPath); ++ ++ for (Field field : categoryClass.getDeclaredFields()) { ++ initField(field, category, categoryPath); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + -+ private static void initField(@NotNull Field field, @NotNull String upstreamPath) { ++ private static void initField(@NotNull Field field, @Nullable Object upstreamField, @NotNull String upstreamPath) { + if (Modifier.isStatic(field.getModifiers())) { + field.setAccessible(true); + + GlobalConfig globalConfig = field.getAnnotation(GlobalConfig.class); + if (globalConfig != null) { -+ initConfig(field, globalConfig, upstreamPath); ++ initConfig(field, globalConfig, upstreamField, upstreamPath); + return; + } + + GlobalConfigCategory globalCategory = field.getType().getAnnotation(GlobalConfigCategory.class); + if (globalCategory != null) { -+ initCategory(field, globalCategory, upstreamPath); ++ initCategory(field, globalCategory, upstreamField, upstreamPath); + } + } + } + + -+ private static void initConfig(@NotNull Field field, GlobalConfig globalConfig, @NotNull String 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, upstreamPath); ++ GlobalConfigManager.VerifiedConfig verifiedConfig = GlobalConfigManager.VerifiedConfig.build(globalConfig, field, upstreamField, upstreamPath); + config.set(verifiedConfig.path(), verifiedConfig.validator().saveConvert(field.get(null))); + } catch (Exception e) { + e.printStackTrace(); @@ -1777,14 +1787,15 @@ index 0000000000000000000000000000000000000000..740c3e36e426b10a92d1b53096e5be28 +} 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..82393d7c1ed9667f142cd4f6a74749bd8f6fc526 +index 0000000000000000000000000000000000000000..191717863d411178405f19b9b66d1ece2ba36feb --- /dev/null +++ b/src/main/java/org/leavesmc/leaves/config/GlobalConfigManager.java -@@ -0,0 +1,237 @@ +@@ -0,0 +1,239 @@ +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; + @@ -1806,7 +1817,7 @@ index 0000000000000000000000000000000000000000..82393d7c1ed9667f142cd4f6a74749bd + verifiedConfigs.clear(); + + for (Field field : LeavesConfig.class.getDeclaredFields()) { -+ initField(field, CONFIG_START); ++ initField(field, null, CONFIG_START); + } + + verifiedConfigs.forEach((path, config) -> config.validator.runAfterLoader(config.get(), firstLoad)); @@ -1815,48 +1826,49 @@ index 0000000000000000000000000000000000000000..82393d7c1ed9667f142cd4f6a74749bd + LeavesConfig.save(); + } + -+ private static void initCategory(@NotNull Field categoryField, @NotNull GlobalConfigCategory globalCategory, @NotNull String upstreamPath) { ++ private static void initCategory(@NotNull Field categoryField, @NotNull GlobalConfigCategory globalCategory, @Nullable Object upstreamField, @NotNull String upstreamPath) { + try { + Class categoryClass = categoryField.getType(); + + Constructor constructor = categoryClass.getDeclaredConstructor(); + constructor.setAccessible(true); -+ categoryField.set(null, constructor.newInstance()); ++ Object category = constructor.newInstance(); ++ categoryField.set(upstreamField, category); + + String categoryPath = upstreamPath + globalCategory.value() + "."; + + for (Field field : categoryClass.getDeclaredFields()) { -+ initField(field, categoryPath); ++ initField(field, category, categoryPath); + } + } catch (Exception e) { + LeavesLogger.LOGGER.severe("Failure to load leaves config" + upstreamPath, e); + } + } + -+ private static void initField(@NotNull Field field, @NotNull String upstreamPath) { -+ if (Modifier.isStatic(field.getModifiers())) { ++ 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).run(); ++ RemovedVerifiedConfig.build(config, field, upstreamField).run(); + } + + GlobalConfig globalConfig = field.getAnnotation(GlobalConfig.class); + if (globalConfig != null) { -+ initConfig(field, globalConfig, upstreamPath); ++ initConfig(field, globalConfig, upstreamField, upstreamPath); + return; + } + + GlobalConfigCategory globalCategory = field.getType().getAnnotation(GlobalConfigCategory.class); + if (globalCategory != null) { -+ initCategory(field, globalCategory, upstreamPath); ++ initCategory(field, globalCategory, upstreamField, upstreamPath); + } + } + } + -+ private static void initConfig(@NotNull Field field, GlobalConfig globalConfig, @NotNull String upstreamPath) { ++ private static void initConfig(@NotNull Field field, GlobalConfig globalConfig, @Nullable Object upstreamField, @NotNull String upstreamPath) { + try { -+ VerifiedConfig verifiedConfig = VerifiedConfig.build(globalConfig, field, upstreamPath); ++ VerifiedConfig verifiedConfig = VerifiedConfig.build(globalConfig, field, upstreamField, upstreamPath); + + if (globalConfig.lock() && !firstLoad) { + verifiedConfigs.put(verifiedConfig.path.substring(CONFIG_START.length()), verifiedConfig); @@ -1864,7 +1876,7 @@ index 0000000000000000000000000000000000000000..82393d7c1ed9667f142cd4f6a74749bd + + ConfigValidator validator = verifiedConfig.validator; + -+ Object defValue = validator.saveConvert(field.get(null)); ++ Object defValue = validator.saveConvert(field.get(upstreamField)); + LeavesConfig.config.addDefault(verifiedConfig.path, defValue); + + try { @@ -1879,7 +1891,7 @@ index 0000000000000000000000000000000000000000..82393d7c1ed9667f142cd4f6a74749bd + + validator.verify(null, savedValue); + -+ field.set(null, savedValue); ++ field.set(upstreamField, savedValue); + } catch (IllegalArgumentException | ClassCastException e) { + LeavesConfig.config.set(verifiedConfig.path, defValue); + LeavesLogger.LOGGER.warning(e.getMessage() + ", reset to " + defValue); @@ -1901,7 +1913,7 @@ index 0000000000000000000000000000000000000000..82393d7c1ed9667f142cd4f6a74749bd + return verifiedConfigs.keySet(); + } + -+ public record RemovedVerifiedConfig(ConfigConverter convert, boolean transform, Field field, String path) { ++ public record RemovedVerifiedConfig(ConfigConverter convert, boolean transform, Field field, Object upstreamField, String path) { + + public void run() { + if (transform) { @@ -1912,7 +1924,7 @@ index 0000000000000000000000000000000000000000..82393d7c1ed9667f142cd4f6a74749bd + if (savedValue.getClass() != convert.getFieldClass()) { + savedValue = convert.loadConvert(savedValue); + } -+ field.set(null, savedValue); ++ field.set(upstreamField, savedValue); + } catch (IllegalAccessException | IllegalArgumentException e) { + LeavesLogger.LOGGER.warning("Failure to load leaves config" + path, e); + } @@ -1924,8 +1936,8 @@ index 0000000000000000000000000000000000000000..82393d7c1ed9667f142cd4f6a74749bd + LeavesConfig.config.set(path, null); + } + -+ @Contract("_, _ -> new") -+ public static @NotNull RemovedVerifiedConfig build(@NotNull RemovedConfig config, Field field) { ++ @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("."); @@ -1941,11 +1953,11 @@ index 0000000000000000000000000000000000000000..82393d7c1ed9667f142cd4f6a74749bd + LeavesLogger.LOGGER.warning("Failure to load leaves config" + path, e); + } + -+ return new RemovedVerifiedConfig(converter, config.transform(), field, path.toString()); ++ return new RemovedVerifiedConfig(converter, config.transform(), field, upstreamField, path.toString()); + } + } + -+ public record VerifiedConfig(ConfigValidator validator, boolean lock, Field field, String path) { ++ public record VerifiedConfig(ConfigValidator validator, boolean lock, Field field, Object upstreamField, String path) { + + public void set(String stringValue) throws IllegalArgumentException { + Object value; @@ -1963,7 +1975,7 @@ index 0000000000000000000000000000000000000000..82393d7c1ed9667f142cd4f6a74749bd + if (lock) { + throw new IllegalArgumentException("locked, will load after restart"); + } -+ field.set(null, value); ++ field.set(upstreamField, value); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException(e.getMessage()); + } @@ -1971,7 +1983,7 @@ index 0000000000000000000000000000000000000000..82393d7c1ed9667f142cd4f6a74749bd + + public Object get() { + try { -+ return field.get(null); ++ return field.get(upstreamField); + } catch (IllegalAccessException e) { + LeavesLogger.LOGGER.severe("Failure to get " + path + " value", e); + return ""; @@ -2000,8 +2012,8 @@ index 0000000000000000000000000000000000000000..82393d7c1ed9667f142cd4f6a74749bd + + @SuppressWarnings("unchecked") + @NotNull -+ @Contract("_, _, _ -> new") -+ public static VerifiedConfig build(@NotNull GlobalConfig config, Field field, String upstreamPath) { ++ @Contract("_, _, _, _ -> new") ++ public static VerifiedConfig build(@NotNull GlobalConfig config, @NotNull Field field, @Nullable Object upstreamField, @NotNull String upstreamPath) { + String path = upstreamPath + config.value(); + + ConfigValidator validator; @@ -2014,7 +2026,7 @@ index 0000000000000000000000000000000000000000..82393d7c1ed9667f142cd4f6a74749bd + throw new RuntimeException(); + } + -+ return new VerifiedConfig(validator, config.lock(), field, path); ++ return new VerifiedConfig(validator, config.lock(), field, upstreamField, path); + } + } +}