9
0
mirror of https://github.com/LeavesMC/Leaves.git synced 2025-12-21 15:59:33 +00:00
Files
LeavesMC/patches/server/0004-Leaves-Server-Config-And-Command.patch
2023-07-17 12:05:46 +08:00

1121 lines
54 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: violetc <58360096+s-yh-china@users.noreply.github.com>
Date: Fri, 29 Oct 2021 16:52:57 +0800
Subject: [PATCH] Leaves Server Config And Command
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java
index a2f71a6d1a9e98133dff6cd0f625da9435a8af14..45897b81a822b9523c16658ca46a507729f8d0d3 100644
--- a/src/main/java/co/aikar/timings/TimingsExport.java
+++ b/src/main/java/co/aikar/timings/TimingsExport.java
@@ -242,7 +242,8 @@ public class TimingsExport extends Thread {
parent.put("config", createObject(
pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)),
pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)),
- pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null))
+ pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)), // Leaves - add config to timings report
+ pair("leaves", mapAsJSON(Bukkit.spigot().getLeavesConfig(), null)) // Leaves - add config to timings report
));
new TimingsExport(listeners, parent, history).start();
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 670f25370554c3f8c40d2fcc4f5a31d7a372f452..18b10f1d1d62e1184a562ef52e1625b4927aec45 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1118,6 +1118,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
LOGGER.info("Done ({})! For help, type \"help\"", doneTime);
// Paper end
+ top.leavesmc.leaves.LeavesConfig.createWorldSections = false; // Leaves - dont let plugin create worlds fill our config
org.spigotmc.WatchdogThread.tick(); // Paper
org.spigotmc.WatchdogThread.hasStarted = true; // Paper
Arrays.fill( recentTps, 20 );
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index 9f422cbeaa52b3e6a0a27af4f8ad4ddb7808483f..3e3e11d4207172d6c24895cef6c7b5a0b09352ee 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -221,6 +221,9 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // load version history now
io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // init PaperBrigadierProvider
// Paper end
+
+ top.leavesmc.leaves.LeavesConfig.init((java.io.File) options.valueOf("leaves-settings")); // Leaves - Server Config
+ top.leavesmc.leaves.LeavesConfig.registerCommands(); // Leaves - Server Command
this.setPvpAllowed(dedicatedserverproperties.pvp);
this.setFlightAllowed(dedicatedserverproperties.allowFlight);
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 147d802d9207e358fdb2d1c7806fc2f634dcfd98..4f0a2c9b352f5824ec0c30d0f0af0fe16320aea3 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -176,6 +176,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// Paper end
public final com.destroystokyo.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
+ public final top.leavesmc.leaves.LeavesConfig.WorldConfig leavesConfig; // Leaves - World Config
public final co.aikar.timings.WorldTimingsHandler timings; // Paper
public static BlockPos lastPhysicsProblem; // Spigot
private org.spigotmc.TickLimiter entityLimiter;
@@ -276,6 +277,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, RegistryAccess iregistrycustom, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function<org.spigotmc.SpigotWorldConfig, io.papermc.paper.configuration.WorldConfiguration> paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - Async-Anti-Xray - Pass executor
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper
+ this.leavesConfig = new top.leavesmc.leaves.LeavesConfig.WorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData)worlddatamutable).getLevelName()); // Leaves - World Config
this.generator = gen;
this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env);
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 22402d237f036be3dcbaea3a63718e615766981c..a394fcb1afe37efda30893e06352941f1a049319 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1056,6 +1056,7 @@ public final class CraftServer implements Server {
org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot
this.console.paperConfigurations.reloadConfigs(this.console);
+ top.leavesmc.leaves.LeavesConfig.init((File) console.options.valueOf("leaves-settings")); // Leaves - Server Config
for (ServerLevel world : this.console.getAllLevels()) {
// world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty
world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters, config.spawnAnimals); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean))
@@ -1071,6 +1072,7 @@ public final class CraftServer implements Server {
}
}
world.spigotConfig.init(); // Spigot
+ world.leavesConfig.init(); // Leaves - World Config
}
Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
@@ -1086,6 +1088,7 @@ public final class CraftServer implements Server {
this.reloadData();
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper
+ top.leavesmc.leaves.LeavesConfig.registerCommands(); // Leaves - Server Command
this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*");
this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions");
@@ -2863,6 +2866,14 @@ public final class CraftServer implements Server {
{
return CraftServer.this.console.paperConfigurations.createLegacyObject(CraftServer.this.console);
}
+
+ // Leaves start - add config to timings report
+ @Override
+ public YamlConfiguration getLeavesConfig()
+ {
+ return top.leavesmc.leaves.LeavesConfig.config;
+ }
+ /// Leaves end - add config to timings report
@Override
public void restart() {
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index 35d2da9d91dcdd89de7c0f4af028fd182376ea8d..d73482fb1e71fe2951e96ae0593de268d533e5f2 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -165,6 +165,14 @@ public class Main {
.ofType(File.class)
.defaultsTo(new File("paper.yml"))
.describedAs("Yml file");
+
+ // Leaves start - Server Config
+ acceptsAll(asList("leaves", "leaves-settings"), "File for leaves settings")
+ .withRequiredArg()
+ .ofType(File.class)
+ .defaultsTo(new File("leaves.yml"))
+ .describedAs("Yml file");
+ // Leaves end - Server Config
acceptsAll(asList("add-plugin", "add-extra-plugin-jar"), "Specify paths to extra plugin jars to be loaded in addition to those in the plugins folder. This argument can be specified multiple times, once for each extra plugin jar path.")
.withRequiredArg()
diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..955904dfd4d22b7b2aacf6c800c33419624d52f3
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
@@ -0,0 +1,826 @@
+package top.leavesmc.leaves;
+
+import com.destroystokyo.paper.util.SneakyThrow;
+import com.google.common.base.Throwables;
+import net.minecraft.server.MinecraftServer;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.Random;
+
+// Powered by Tuinity(https://github.com/Tuinity/Tuinity)
+
+public final class LeavesConfig {
+
+ public static final String CONFIG_HEADER = "Configuration file for Leaves.";
+ public static final int CURRENT_CONFIG_VERSION = 3;
+
+ private static final Object[] EMPTY = new Object[0];
+
+ private static File configFile;
+ public static YamlConfiguration config;
+ private static int configVersion;
+ public static boolean createWorldSections = true;
+ static Map<String, Command> commands;
+
+ public static void init(final File file) {
+ LeavesConfig.configFile = file;
+ config = new YamlConfiguration();
+ config.options().header(CONFIG_HEADER);
+ config.options().copyDefaults(true);
+
+ if (!file.exists()) {
+ try {
+ file.createNewFile();
+ } catch (final Exception ex) {
+ Bukkit.getLogger().log(Level.SEVERE, "Failure to create leaves config", ex);
+ }
+ } else {
+ try {
+ config.load(file);
+ } catch (final Exception ex) {
+ Bukkit.getLogger().log(Level.SEVERE, "Failure to load leaves config", ex);
+ SneakyThrow.sneaky(ex); /* Rethrow, this is critical */
+ throw new RuntimeException(ex); // unreachable
+ }
+ }
+
+ if (config.contains("config-version-please-do-not-modify-me")) {
+ LeavesConfig.set("config-version-please-do-not-modify-me", null);
+ }
+ LeavesConfig.configVersion = LeavesConfig.getInt("config-version", CURRENT_CONFIG_VERSION);
+ LeavesConfig.set("config-version", CURRENT_CONFIG_VERSION);
+
+ updateConfigVersion(config);
+
+ LeavesConfig.load(config);
+ registerCarpetRules();
+
+ commands = new HashMap<>();
+ }
+
+ public static void load(final YamlConfiguration config) {
+ for (Method method : LeavesConfig.class.getDeclaredMethods()) {
+ if (Modifier.isPrivate(method.getModifiers())) {
+ if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE) {
+ try {
+ method.setAccessible(true);
+ method.invoke(null);
+ } catch (InvocationTargetException ex) {
+ throw Throwables.propagate(ex.getCause());
+ } catch (Exception ex) {
+ Bukkit.getLogger().log(Level.SEVERE, "Error invoking " + method, ex);
+ }
+ }
+ }
+ }
+
+ /* We re-save to add new options */
+ try {
+ config.save(LeavesConfig.configFile);
+ } catch (final Exception ex) {
+ Bukkit.getLogger().log(Level.SEVERE, "Unable to save leaves config", ex);
+ }
+ }
+
+ private static void updateConfigVersion(final YamlConfiguration config) {
+ if (configVersion < CURRENT_CONFIG_VERSION) {
+ switch (configVersion) {
+ case 1 -> {
+ snowballAndEggCanKnockback = config.getBoolean("settings.snowball-and-egg-can-knockback-player", snowballAndEggCanKnockback);
+ fakeplayerSupport = config.getBoolean("settings.fakeplayer.enable", fakeplayerSupport);
+ unableFakeplayerNames = (List<String>) config.getList("settings.fakeplayer.unable-fakeplayer-names", unableFakeplayerNames);
+ shearsInDispenserCanZeroAmount = config.getBoolean("settings.shears-in-dispenser-can-zero-amount", shearsInDispenserCanZeroAmount);
+ redstoneShearsWrench = config.getBoolean("settings.redstone-shears-wrench", redstoneShearsWrench);
+ buddingAmethystCanPushByPiston = config.getBoolean("settings.budding-amethyst-can-push-by-piston", buddingAmethystCanPushByPiston);
+ spectatorDontGetAdvancement = config.getBoolean("settings.spectator-dont-get-advancement", spectatorDontGetAdvancement);
+ stickChangeArmorStandArmStatus = config.getBoolean("settings.stick-change-armorstand-arm-status", stickChangeArmorStandArmStatus);
+ noChatSign = config.getBoolean("settings.no-chat-sign", noChatSign);
+
+ config.set("settings.snowball-and-egg-can-knockback-player", null);
+ config.set("settings.player-can-edit-sign", null);
+ config.set("settings.fakeplayer", null);
+ config.set("settings.shears-in-dispenser-can-zero-amount", null);
+ config.set("settings.redstone-shears-wrench", null);
+ config.set("settings.budding-amethyst-can-push-by-piston", null);
+ config.set("settings.spectator-dont-get-advancement", null);
+ config.set("settings.stick-change-armorstand-arm-status", null);
+ config.set("settings.no-chat-sign", null);
+ }
+
+ case 2 -> {
+ config.set("settings.modify.player-can-edit-sign", null);
+ config.set("settings.performance.skip-clone-loot-parameters", null);
+ }
+ }
+ }
+ }
+
+ static void set(final String path, final Object value) {
+ LeavesConfig.config.set(path, value);
+ }
+
+ public static void registerCommands() {
+ for (Map.Entry<String, Command> entry : commands.entrySet()) {
+ MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Leaves", entry.getValue());
+ }
+ }
+
+ static boolean getBoolean(final String path, final boolean dfl) {
+ LeavesConfig.config.addDefault(path, Boolean.valueOf(dfl));
+ return LeavesConfig.config.getBoolean(path, dfl);
+ }
+
+ static int getInt(final String path, final int dfl) {
+ LeavesConfig.config.addDefault(path, Integer.valueOf(dfl));
+ return LeavesConfig.config.getInt(path, dfl);
+ }
+
+ static long getLong(final String path, final long dfl) {
+ LeavesConfig.config.addDefault(path, Long.valueOf(dfl));
+ return LeavesConfig.config.getLong(path, dfl);
+ }
+
+ static double getDouble(final String path, final double dfl) {
+ LeavesConfig.config.addDefault(path, Double.valueOf(dfl));
+ return LeavesConfig.config.getDouble(path, dfl);
+ }
+
+ static String getString(final String path, final String dfl) {
+ LeavesConfig.config.addDefault(path, dfl);
+ return LeavesConfig.config.getString(path, dfl);
+ }
+
+ static <T> List<T> getList(final String path, final List<T> def) {
+ LeavesConfig.config.addDefault(path, def);
+ return (List<T>) LeavesConfig.config.getList(path, config.getList(path));
+ }
+
+ public static boolean snowballAndEggCanKnockback = true;
+ private static void snowballAndEggCanKnockback() {
+ snowballAndEggCanKnockback = getBoolean("settings.modify.snowball-and-egg-can-knockback-player", snowballAndEggCanKnockback);
+ }
+
+ public static boolean fakeplayerSupport = true;
+ public static List<String> unableFakeplayerNames = List.of("player-name");
+ public static int fakeplayerLimit = 10;
+ public static String fakeplayerPrefix = "";
+ public static String fakeplayerSuffix = "";
+ public static boolean alwaysSendFakeplayerData = true;
+ public static boolean fakeplayerResident = false;
+ public static boolean openFakeplayerInventory = false;
+ public static boolean fakeplayerSkipSleep = false;
+ private static void fakeplayer() {
+ fakeplayerSupport = getBoolean("settings.modify.fakeplayer.enable", fakeplayerSupport);
+ unableFakeplayerNames = getList("settings.modify.fakeplayer.unable-fakeplayer-names", unableFakeplayerNames);
+ fakeplayerLimit = getInt("settings.modify.fakeplayer.limit", fakeplayerLimit);
+ fakeplayerPrefix = getString("settings.modify.fakeplayer.prefix", fakeplayerPrefix);
+ fakeplayerSuffix = getString("settings.modify.fakeplayer.suffix", fakeplayerSuffix);
+ alwaysSendFakeplayerData = getBoolean("settings.modify.fakeplayer.always-send-data", alwaysSendFakeplayerData);
+ fakeplayerResident = getBoolean("settings.modify.fakeplayer.resident-fakeplayer", fakeplayerResident);
+ openFakeplayerInventory = getBoolean("settings.modify.fakeplayer.open-fakeplayer-inventory", openFakeplayerInventory);
+ fakeplayerSkipSleep = getBoolean("settings.modify.fakeplayer.skip-sleep-check", fakeplayerSkipSleep);
+ }
+
+ public static boolean shearsInDispenserCanZeroAmount = false;
+ private static void shearsInDispenserCanZeroAmount() {
+ shearsInDispenserCanZeroAmount = getBoolean("settings.modify.shears-in-dispenser-can-zero-amount", shearsInDispenserCanZeroAmount);
+ }
+
+ public static boolean redstoneShearsWrench = true;
+ private static void redstoneShearsWrench() {
+ redstoneShearsWrench = getBoolean("settings.modify.redstone-shears-wrench", redstoneShearsWrench);
+ }
+
+ public static boolean buddingAmethystCanPushByPiston = false;
+ private static void buddingAmethystCanPushByPiston() {
+ buddingAmethystCanPushByPiston = getBoolean("settings.modify.budding-amethyst-can-push-by-piston", buddingAmethystCanPushByPiston);
+ }
+
+ public static boolean spectatorDontGetAdvancement = false;
+ private static void spectatorDontGetAdvancement() {
+ spectatorDontGetAdvancement = getBoolean("settings.modify.spectator-dont-get-advancement", spectatorDontGetAdvancement);
+ }
+
+ public static boolean stickChangeArmorStandArmStatus = true;
+ private static void stickChangeArmorStandHasArm() {
+ stickChangeArmorStandArmStatus = getBoolean("settings.modify.stick-change-armorstand-arm-status", stickChangeArmorStandArmStatus);
+ }
+
+ public static boolean noChatSign = true;
+ private static void noChatSign() {
+ if (LeavesConfig.config.contains("settings.modify.no-chat-sign")) {
+ noChatSign = LeavesConfig.config.getBoolean("settings.modify.no-chat-sign");
+ LeavesConfig.config.set("settings.modify.no-chat-sign", null);
+ }
+ noChatSign = getBoolean("settings.misc.no-chat-sign", noChatSign);
+ }
+
+ public static boolean asyncMobSpawning = false;
+ private static boolean asyncMobSpawningLock = false;
+ private static void asyncMobSpawning() {
+ if (!asyncMobSpawningLock) {
+ asyncMobSpawning = getBoolean("settings.performance.async-mob-spawning", asyncMobSpawning);
+ asyncMobSpawningLock = true;
+ }
+
+ if (asyncMobSpawning) {
+ asyncMobSpawning = false;
+ LeavesLogger.LOGGER.severe("Async MobSpawning is updating, it can't work");
+ }
+ }
+
+ public static boolean dontSendUselessEntityPackets = true;
+ private static void dontSendUselessEntityPackets() {
+ dontSendUselessEntityPackets = getBoolean("settings.performance.dont-send-useless-entity-packets", dontSendUselessEntityPackets);
+ }
+
+ public static boolean asyncEntityTracker = false;
+ private static boolean asyncEntityTrackerLock = false;
+ private static void asyncEntityTracker() {
+ if (!asyncEntityTrackerLock) {
+ asyncEntityTracker = getBoolean("settings.performance.async-entity-tracker", asyncEntityTracker);
+ asyncEntityTrackerLock = true;
+ }
+
+ if (asyncEntityTracker) {
+ asyncEntityTracker = false;
+ LeavesLogger.LOGGER.severe("Async EntityTracker is updating, it can't work");
+ }
+ }
+
+ public static boolean fixPaper6045 = true;
+ private static void fixPaper6045() {
+ fixPaper6045 = getBoolean("settings.performance.fix.fix-paper-6045", fixPaper6045);
+ }
+
+ public static boolean optimizeEntityCoordinateKey = true;
+ private static void optimizeEntityCoordinateKey() {
+ optimizeEntityCoordinateKey = getBoolean("settings.performance.optimize-entity-coordinate-key", optimizeEntityCoordinateKey);
+ }
+
+ public static boolean enableSuffocationOptimization = true;
+ private static void enableSuffocationOptimization() {
+ enableSuffocationOptimization = getBoolean("settings.performance.enable-suffocation-optimization", enableSuffocationOptimization);
+ }
+
+ public static boolean entityStripRaytracing = true;
+ private static void entityStripRaytracing() {
+ entityStripRaytracing = getBoolean("settings.performance.strip-raytracing-for-entity", entityStripRaytracing);
+ }
+
+ public static boolean checkSpookySeasonOnceAnHour = true;
+ private static void checkSpookySeasonOnceAnHour() {
+ checkSpookySeasonOnceAnHour = getBoolean("settings.performance.check-spooky-season-once-an-hour", checkSpookySeasonOnceAnHour);
+ }
+
+ public static boolean optimizeChunkTicking = true;
+ private static boolean optimizeChunkTickingLock = false;
+ private static void optimizeChunkTicking() {
+ if (!optimizeChunkTickingLock) {
+ optimizeChunkTicking = getBoolean("settings.performance.optimize-chunk-ticking", optimizeChunkTicking);
+ optimizeChunkTickingLock = true;
+ }
+ }
+
+ public static boolean skipPOIFindingInVehicle = true;
+ private static void skipPOIFindingInVehicle() {
+ skipPOIFindingInVehicle = getBoolean("settings.performance.skip-poi-find-in-vehicle", skipPOIFindingInVehicle);
+ }
+
+ public static boolean entityTargetFindingOptimization = true;
+ private static void entityTargetFindingOptimization() {
+ entityTargetFindingOptimization = getBoolean("settings.performance.entity-target-find-optimization", entityTargetFindingOptimization);
+ }
+
+ public static boolean useMoreThreadUnsafeRandom = true;
+ private static void useMoreThreadUnsafeRandom() {
+ useMoreThreadUnsafeRandom = getBoolean("settings.performance.use-more-thread-unsafe-random", useMoreThreadUnsafeRandom);
+ }
+
+ public static boolean disableMethodProfiler = true;
+ private static void disableMethodProfiler() {
+ disableMethodProfiler = getBoolean("settings.misc.disable-method-profiler", disableMethodProfiler);
+ }
+
+ public static boolean throttleInactiveGoalSelectorTick = false;
+ private static void throttleInactiveGoalSelectorTick() {
+ throttleInactiveGoalSelectorTick = getBoolean("settings.performance.inactive-goal-selector-disable", throttleInactiveGoalSelectorTick);
+ }
+
+ public static boolean reduceEntityAllocations = true;
+ private static void reduceEntityAllocations() {
+ reduceEntityAllocations = getBoolean("settings.performance.reduce-entity-allocations", reduceEntityAllocations);
+ }
+
+ public static boolean removeTickGuardLambda = true;
+ private static void removeTickGuardLambda() {
+ removeTickGuardLambda = getBoolean("settings.performance.remove.tick-guard-lambda", removeTickGuardLambda);
+ }
+
+ public static boolean removeInventoryContainsIterators = true;
+ private static void removeInventoryContainsIterators() {
+ removeInventoryContainsIterators = getBoolean("settings.performance.remove.inventory-contains-iterators", removeInventoryContainsIterators);
+ }
+
+ public static boolean removeGetNearPlayerStreams = true;
+ private static void removeGetNearPlayerStreams() {
+ removeGetNearPlayerStreams = getBoolean("settings.performance.remove.get-nearby-players-streams", removeGetNearPlayerStreams);
+ }
+
+ public static boolean removeRangeCheckStreams = true;
+ private static void removeRangeCheckStreams() {
+ removeRangeCheckStreams = getBoolean("settings.performance.remove.range-check-streams-and-iterators", removeRangeCheckStreams);
+ }
+
+ // only config now
+ public static boolean asyncPathfinding = false;
+ private static boolean asyncPathfindingLock = false;
+ private static void asyncPathfinding() {
+ if (!asyncPathfindingLock) {
+ asyncPathfinding = getBoolean("settings.performance.async-pathfinding", asyncPathfinding);
+ asyncPathfindingLock = true;
+ }
+
+ if (asyncPathfinding) {
+ asyncPathfinding = false;
+ LeavesLogger.LOGGER.severe("Async Pathfinding is updating, it can't work");
+ }
+ }
+
+ public static boolean cacheClimbCheck = true;
+ private static void cacheClimbCheck() {
+ cacheClimbCheck = getBoolean("settings.performance.cache-climb-check", cacheClimbCheck);
+ }
+
+ public static boolean biomeTemperaturesUseAgingCache = true;
+ private static boolean biomeTemperaturesUseAgingCacheLock = false;
+ private static void biomeTemperaturesUseAgingCache() {
+ if (!biomeTemperaturesUseAgingCacheLock) {
+ biomeTemperaturesUseAgingCache = getBoolean("settings.performance.biome-temperatures-use-aging-cache", biomeTemperaturesUseAgingCache);
+ biomeTemperaturesUseAgingCacheLock = true;
+ }
+ }
+
+ public static boolean reduceEntityFluidLookup = true;
+ private static void reduceEntityFluidLookup() {
+ reduceEntityFluidLookup = getBoolean("settings.performance.reduce-entity-fluid-lookup", reduceEntityFluidLookup);
+ }
+
+ public static boolean reduceChuckLoadAndLookup = true;
+ private static void reduceChuckLoadAndLookup() {
+ reduceChuckLoadAndLookup = getBoolean("settings.performance.reduce-chuck-load-and-lookup", reduceChuckLoadAndLookup);
+ }
+
+ public static boolean simplerVanillaShapelessRecipes = true;
+ private static void simplerVanillaShapelessRecipes() {
+ simplerVanillaShapelessRecipes = getBoolean("settings.performance.simpler-vanilla-shapeless-recipes", simplerVanillaShapelessRecipes);
+ }
+
+ public static boolean pcaSyncProtocol = false;
+ private static void pcaSyncProtocol() {
+ pcaSyncProtocol = getBoolean("settings.protocol.pca-sync-protocol", pcaSyncProtocol);
+ }
+
+ public static String pcaSyncPlayerEntity = "OPS";
+ private static final List<String> pcaSyncPlayerEntityList = List.of("NOBODY", "BOT", "OPS", "OPS_AND_SELF", "EVERYONE");
+ private static void pcaSyncPlayerEntity() {
+ pcaSyncPlayerEntity = getString("settings.protocol.pca-sync-player-entity", pcaSyncPlayerEntity);
+ if (!pcaSyncPlayerEntityList.contains(pcaSyncPlayerEntity)) {
+ pcaSyncPlayerEntity = "OPS";
+ LeavesLogger.LOGGER.severe("pca-sync-player-entity value error, reset to OPS");
+ }
+ }
+
+ public static boolean bborProtocol = false;
+ private static void bborProtocol() {
+ bborProtocol = getBoolean("settings.protocol.bbor-protocol", bborProtocol);
+ }
+
+ public static boolean instantBlockUpdaterReintroduced = false;
+ private static boolean instantBlockUpdaterReintroducedLock = false;
+ private static void instantBlockUpdaterReintroduced() {
+ if (!instantBlockUpdaterReintroducedLock) {
+ instantBlockUpdaterReintroduced = getBoolean("settings.modify.instant-block-updater-reintroduced", instantBlockUpdaterReintroduced);
+ instantBlockUpdaterReintroducedLock = true;
+ }
+ }
+
+ public static boolean flattenTriangularDistribution = false;
+ private static void flattenTriangularDistribution() {
+ flattenTriangularDistribution = getBoolean("settings.modify.flatten-triangular-distribution", flattenTriangularDistribution);
+ }
+
+ public static boolean jadeProtocol = false;
+ private static void jadeProtocol() {
+ jadeProtocol = getBoolean("settings.protocol.jade-protocol", jadeProtocol);
+ }
+
+ public static boolean carpetAlternativeBlockPlacement = false;
+ private static void carpetAlternativeBlockPlacement() {
+ carpetAlternativeBlockPlacement = getBoolean("settings.protocol.carpet-alternative-block-placement", carpetAlternativeBlockPlacement);
+ }
+
+ public static boolean playerOperationLimiter = false;
+ private static void playerOperationLimiter() {
+ playerOperationLimiter = getBoolean("settings.modify.player-operation-limiter", playerOperationLimiter);
+ }
+
+ public static double renewableElytra = -1.0;
+ private static void renewableElytra() {
+ renewableElytra = getDouble("settings.modify.renewable-elytra", renewableElytra);
+ }
+
+ public static int shulkerBoxStackSize = 1;
+ private static String stackableShulkerBoxes = "false";
+ private static void stackableShulkerBoxes() {
+ stackableShulkerBoxes = getString("settings.modify.stackable-shulker-boxes", stackableShulkerBoxes);
+ stackableShulkerBoxes = MathUtils.isNumeric(stackableShulkerBoxes) ? stackableShulkerBoxes : stackableShulkerBoxes.equals("true") ? "2" : "1";
+ shulkerBoxStackSize = Integer.parseInt(stackableShulkerBoxes);
+ }
+
+ public static boolean improveFluidDirectionCaching = true;
+ private static boolean improveFluidDirectionCachingLock = false;
+ private static void improveFluidDirectionCaching() {
+ if (!improveFluidDirectionCachingLock) {
+ improveFluidDirectionCaching = getBoolean("settings.performance.improve-fluid-direction-caching", improveFluidDirectionCaching);
+ improveFluidDirectionCachingLock = true;
+ }
+ }
+
+ public static boolean mcTechnicalMode = true;
+ private static void mcTechnicalMode() {
+ mcTechnicalMode = getBoolean("settings.modify.mc-technical-survival-mode", mcTechnicalMode); // TODO better name?
+ doMcTechnicalMode();
+ }
+
+ public static void doMcTechnicalMode() {
+ if (mcTechnicalMode) {
+ }
+ }
+
+ public static boolean netherPortalFix = false;
+ private static void netherPortalFix() {
+ netherPortalFix = getBoolean("settings.modify.return-nether-portal-fix", netherPortalFix);
+ }
+
+ public static boolean appleskinProtocol = false;
+ private static void appleskinProtocol() {
+ appleskinProtocol = getBoolean("settings.protocol.appleskin-protocol", appleskinProtocol);
+ }
+
+ public static boolean xaeroMapProtocol = false;
+ public static int xaeroMapServerID = new Random().nextInt();
+ private static void xaeroMapProtocol() {
+ xaeroMapProtocol = getBoolean("settings.protocol.xaero-map-protocol", xaeroMapProtocol);
+ xaeroMapServerID = getInt("settings.protocol.xaero-map-server-id", xaeroMapServerID);
+ }
+
+ public static boolean extraYggdrasilService = false;
+ public static boolean extraYggdrasilLoginProtect = false;
+ public static List<String> extraYggdrasilServiceList = List.of("https://url.with.authlib-injector-yggdrasil");
+ private static void extraYggdrasilService() {
+ extraYggdrasilService = getBoolean("settings.misc.extra-yggdrasil-service.enable", extraYggdrasilService);
+ extraYggdrasilLoginProtect = getBoolean("settings.misc.extra-yggdrasil-service.login-protect", extraYggdrasilLoginProtect);
+ extraYggdrasilServiceList = getList("settings.misc.extra-yggdrasil-service.urls", extraYggdrasilServiceList);
+ if (extraYggdrasilService) {
+ }
+ }
+
+ public static boolean useVanillaRandom = false;
+ private static boolean useVanillaRandomLock = false;
+ private static void useVanillaRandom() {
+ if (!useVanillaRandomLock) {
+ useVanillaRandom = getBoolean("settings.modify.use-vanilla-random", useVanillaRandom);
+ useVanillaRandomLock = true;
+ }
+ }
+
+ public static boolean updateSuppressionCrashFix = true;
+ private static void updateSuppressionCrashFix() {
+ updateSuppressionCrashFix = getBoolean("settings.modify.fix-update-suppression-crash", updateSuppressionCrashFix);
+ }
+
+ public static boolean bedrockBreakList = false;
+ private static boolean bedrockBreakListLock = false;
+ private static void bedrockBreakList() {
+ if (!bedrockBreakListLock) {
+ bedrockBreakList = getBoolean("settings.modify.bedrock-break-list", bedrockBreakList);
+ bedrockBreakListLock = true;
+ }
+ }
+
+ public static boolean syncmaticaProtocol = false;
+ public static boolean syncmaticaQuota = false;
+ public static int syncmaticaQuotaLimit = 40000000;
+ private static void syncmaticaProtocol() {
+ syncmaticaProtocol = getBoolean("settings.protocol.syncmatica.enable", syncmaticaProtocol);
+ syncmaticaQuota = getBoolean("settings.protocol.syncmatica.quota", syncmaticaQuota);
+ syncmaticaQuotaLimit = getInt("settings.protocol.syncmatica.quota-limit", syncmaticaQuotaLimit);
+ if (syncmaticaProtocol) {
+ }
+ }
+
+ public static boolean disableDistanceCheckForUseItem = false;
+ private static void disableDistanceCheckForUseItem() {
+ disableDistanceCheckForUseItem = getBoolean("settings.modify.disable-distance-check-for-use-item", disableDistanceCheckForUseItem);
+ if (carpetAlternativeBlockPlacement) {
+ disableDistanceCheckForUseItem = true;
+ }
+ }
+
+ public static boolean noFeatherFallingTrample = false;
+ private static void noFeatherFallingTrample() {
+ noFeatherFallingTrample = getBoolean("settings.modify.no-feather-falling-trample", noFeatherFallingTrample);
+ }
+
+ public static boolean sharedVillagerDiscounts = false;
+ private static void sharedVillagerDiscounts() {
+ sharedVillagerDiscounts = getBoolean("settings.modify.shared-villager-discounts", sharedVillagerDiscounts);
+ }
+
+ public static boolean redstoneDontCantOnTrapDoor = false;
+ private static void redstoneDontCantOnTrapDoor() {
+ redstoneDontCantOnTrapDoor = getBoolean("settings.modify.redstone-wire-dont-connect-if-on-trapdoor", redstoneDontCantOnTrapDoor);
+ }
+
+ public static boolean disableCheckOutOfOrderCommand = false;
+ private static void disableCheckOutOfOrderCommand() {
+ disableCheckOutOfOrderCommand = getBoolean("settings.modify.disable-check-out-of-order-command", disableCheckOutOfOrderCommand);
+ }
+
+ public static boolean despawnEndermanWithBlock = false;
+ private static void despawnEndermanWithBlock() {
+ despawnEndermanWithBlock = getBoolean("settings.modify.despawn-enderman-with-block", despawnEndermanWithBlock);
+ }
+
+ public static boolean leavesCarpetSupport = false;
+ private static void leavesCarpetSupport() {
+ leavesCarpetSupport = getBoolean("settings.protocol.leaves-carpet-support", leavesCarpetSupport);
+ }
+
+ public static void registerCarpetRules() {
+ }
+
+ public static boolean creativeNoClip = false;
+ private static void creativeNoClip() {
+ creativeNoClip = getBoolean("settings.modify.creative-no-clip", creativeNoClip);
+ }
+
+ public static boolean optimizedDragonRespawn = false;
+ private static void optimizedDragonRespawn() {
+ optimizedDragonRespawn = getBoolean("settings.performance.optimized-dragon-respawn", optimizedDragonRespawn);
+ }
+
+ public static boolean mendingCompatibilityInfinity = false;
+ private static void mendingCompatibilityInfinity() {
+ mendingCompatibilityInfinity = getBoolean("settings.modify.mending-compatibility-infinity", mendingCompatibilityInfinity);
+ }
+
+ public static boolean shaveSnowLayers = true;
+ private static void shaveSnowLayers() {
+ shaveSnowLayers = getBoolean("settings.modify.shave-snow-layers", shaveSnowLayers);
+ }
+
+ public static boolean ignoreLC = false;
+ private static void ignoreLC() {
+ ignoreLC = getBoolean("settings.modify.ignore-lc", ignoreLC);
+ }
+
+ public static boolean elytraAeronauticsNoChunk = false;
+ public static double elytraAeronauticsNoChunkHeight = 500.0D;
+ public static double elytraAeronauticsNoChunkSpeed = -1.0D;
+ public static boolean elytraAeronauticsNoChunkMes = true;
+ public static String elytraAeronauticsNoChunkStartMes = "Flight enter cruise mode";
+ public static String elytraAeronauticsNoChunkEndMes = "Flight exit cruise mode";
+ private static void elytraAeronautics() {
+ elytraAeronauticsNoChunk = getBoolean("settings.modify.elytra-aeronautics.no-chunk-load", elytraAeronauticsNoChunk);
+ elytraAeronauticsNoChunkHeight = getDouble("settings.modify.elytra-aeronautics.no-chunk-height", elytraAeronauticsNoChunkHeight);
+ elytraAeronauticsNoChunkSpeed = getDouble("settings.modify.elytra-aeronautics.no-chunk-speed", elytraAeronauticsNoChunkSpeed);
+ elytraAeronauticsNoChunkMes = getBoolean("settings.modify.elytra-aeronautics.message", elytraAeronauticsNoChunkMes);
+ elytraAeronauticsNoChunkStartMes = getString("settings.modify.elytra-aeronautics.message-start", elytraAeronauticsNoChunkStartMes);
+ elytraAeronauticsNoChunkEndMes = getString("settings.modify.elytra-aeronautics.message-end", elytraAeronauticsNoChunkEndMes);
+ }
+
+ public static boolean msptSyncProtocol = false;
+ public static int msptSyncTickInterval = 20;
+ private static void msptSyncProtocol() {
+ msptSyncTickInterval = getInt("settings.protocol.bladeren.mspt-sync-tick-interval", msptSyncTickInterval);
+ msptSyncProtocol = getBoolean("settings.protocol.bladeren.mspt-sync-protocol", msptSyncProtocol);
+ }
+
+ public static boolean fixPaper9372 = true;
+ private static void fixPaper9372() {
+ fixPaper9372 = getBoolean("settings.performance.fix.fix-paper-9372", fixPaper9372);
+ }
+
+ public static boolean cacheIgniteOdds = true;
+ private static void cacheIgniteOdds() {
+ cacheIgniteOdds = getBoolean("settings.performance.cache-ignite-odds", cacheIgniteOdds);
+ }
+
+ public static boolean lavaRiptide = false;
+ private static void lavaRiptide() {
+ lavaRiptide = getBoolean("settings.modify.lava-riptide", lavaRiptide);
+ }
+
+ public static boolean noBlockUpdateCommand = false;
+ private static void noBlockUpdateCommand() {
+ noBlockUpdateCommand = getBoolean("settings.modify.no-block-update-command", noBlockUpdateCommand);
+ }
+
+ public static boolean skipSelfRaidCheck = false;
+ private static void skipSelfRaidCheck() {
+ skipSelfRaidCheck = getBoolean("settings.modify.raider-die-skip-self-raid-check", skipSelfRaidCheck);
+ }
+
+ public static boolean containerPassthrough = false;
+ private static void containerPassthrough() {
+ containerPassthrough = getBoolean("settings.modify.container-passthrough", containerPassthrough);
+ }
+
+ public static final class WorldConfig {
+
+ public final String worldName;
+ public String configPath;
+ ConfigurationSection worldDefaults;
+
+ public WorldConfig(final String worldName) {
+ this.worldName = worldName;
+ this.init();
+ }
+
+ public void init() {
+ this.worldDefaults = LeavesConfig.config.getConfigurationSection("world-settings.default");
+ if (this.worldDefaults == null) {
+ this.worldDefaults = LeavesConfig.config.createSection("world-settings.default");
+ }
+
+ String worldSectionPath = LeavesConfig.configVersion < CURRENT_CONFIG_VERSION ? this.worldName : "world-settings.".concat(this.worldName);
+ ConfigurationSection section = LeavesConfig.config.getConfigurationSection(worldSectionPath);
+ this.configPath = worldSectionPath;
+ if (LeavesConfig.createWorldSections) {
+ if (section == null) {
+ section = LeavesConfig.config.createSection(worldSectionPath);
+ }
+ LeavesConfig.config.set(worldSectionPath, section);
+ }
+
+ this.load();
+ }
+
+ public void load() {
+ for (final Method method : LeavesConfig.WorldConfig.class.getDeclaredMethods()) {
+ if (method.getReturnType() != void.class || method.getParameterCount() != 0 ||
+ !Modifier.isPrivate(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) {
+ continue;
+ }
+
+ try {
+ method.setAccessible(true);
+ method.invoke(this, EMPTY);
+ } catch (final Exception ex) {
+ SneakyThrow.sneaky(ex); /* Rethrow, this is critical */
+ throw new RuntimeException(ex); // unreachable
+ }
+ }
+
+ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) {
+ ConfigurationSection oldSection = LeavesConfig.config.getConfigurationSection(this.worldName);
+ LeavesConfig.config.set("world-settings.".concat(this.worldName), oldSection);
+ LeavesConfig.config.set(this.worldName, null);
+ }
+
+ /* We re-save to add new options */
+ try {
+ LeavesConfig.config.save(LeavesConfig.configFile);
+ } catch (final Exception ex) {
+ Bukkit.getLogger().log(Level.SEVERE, "Unable to save leaves config", ex);
+ }
+ }
+
+ void set(final String path, final Object val) {
+ final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath);
+ this.worldDefaults.set(path, val);
+ if (config != null && config.get(path) != null) {
+ config.set(path, val);
+ }
+ }
+
+ boolean getBoolean(final String path, final boolean dfl) {
+ final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath);
+ this.worldDefaults.addDefault(path, Boolean.valueOf(dfl));
+ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) {
+ if (config != null && config.getBoolean(path) == dfl) {
+ config.set(path, null);
+ }
+ }
+ return config == null ? this.worldDefaults.getBoolean(path) : config.getBoolean(path, this.worldDefaults.getBoolean(path));
+ }
+
+ boolean getBooleanRaw(final String path, final boolean dfl) {
+ final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath);
+ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) {
+ if (config != null && config.getBoolean(path) == dfl) {
+ config.set(path, null);
+ }
+ }
+ return config == null ? this.worldDefaults.getBoolean(path, dfl) : config.getBoolean(path, this.worldDefaults.getBoolean(path, dfl));
+ }
+
+ int getInt(final String path, final int dfl) {
+ final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath);
+ this.worldDefaults.addDefault(path, Integer.valueOf(dfl));
+ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) {
+ if (config != null && config.getInt(path) == dfl) {
+ config.set(path, null);
+ }
+ }
+ return config == null ? this.worldDefaults.getInt(path) : config.getInt(path, this.worldDefaults.getInt(path));
+ }
+
+ int getIntRaw(final String path, final int dfl) {
+ final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath);
+ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) {
+ if (config != null && config.getInt(path) == dfl) {
+ config.set(path, null);
+ }
+ }
+ return config == null ? this.worldDefaults.getInt(path, dfl) : config.getInt(path, this.worldDefaults.getInt(path, dfl));
+ }
+
+ long getLong(final String path, final long dfl) {
+ final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath);
+ this.worldDefaults.addDefault(path, Long.valueOf(dfl));
+ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) {
+ if (config != null && config.getLong(path) == dfl) {
+ config.set(path, null);
+ }
+ }
+ return config == null ? this.worldDefaults.getLong(path) : config.getLong(path, this.worldDefaults.getLong(path));
+ }
+
+ long getLongRaw(final String path, final long dfl) {
+ final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath);
+ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) {
+ if (config != null && config.getLong(path) == dfl) {
+ config.set(path, null);
+ }
+ }
+ return config == null ? this.worldDefaults.getLong(path, dfl) : config.getLong(path, this.worldDefaults.getLong(path, dfl));
+ }
+
+ double getDouble(final String path, final double dfl) {
+ final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath);
+ this.worldDefaults.addDefault(path, Double.valueOf(dfl));
+ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) {
+ if (config != null && config.getDouble(path) == dfl) {
+ config.set(path, null);
+ }
+ }
+ return config == null ? this.worldDefaults.getDouble(path) : config.getDouble(path, this.worldDefaults.getDouble(path));
+ }
+
+ double getDoubleRaw(final String path, final double dfl) {
+ final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath);
+ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) {
+ if (config != null && config.getDouble(path) == dfl) {
+ config.set(path, null);
+ }
+ }
+ return config == null ? this.worldDefaults.getDouble(path, dfl) : config.getDouble(path, this.worldDefaults.getDouble(path, dfl));
+ }
+
+ String getString(final String path, final String dfl) {
+ final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath);
+ this.worldDefaults.addDefault(path, dfl);
+ return config == null ? this.worldDefaults.getString(path) : config.getString(path, this.worldDefaults.getString(path));
+ }
+
+ String getStringRaw(final String path, final String dfl) {
+ final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath);
+ return config == null ? this.worldDefaults.getString(path, dfl) : config.getString(path, this.worldDefaults.getString(path, dfl));
+ }
+
+ List getList(final String path, final List dfl) {
+ final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath);
+ this.worldDefaults.addDefault(path, dfl);
+ return config == null ? this.worldDefaults.getList(path) : config.getList(path, this.worldDefaults.getList(path));
+ }
+
+ List getListRaw(final String path, final List dfl) {
+ final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath);
+ return config == null ? this.worldDefaults.getList(path, dfl) : config.getList(path, this.worldDefaults.getList(path, dfl));
+ }
+ }
+}
diff --git a/src/main/java/top/leavesmc/leaves/command/CommandArgument.java b/src/main/java/top/leavesmc/leaves/command/CommandArgument.java
new file mode 100644
index 0000000000000000000000000000000000000000..eadc6d168fb13299348b0c275ae352ee2f1e1ea2
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/command/CommandArgument.java
@@ -0,0 +1,43 @@
+package top.leavesmc.leaves.command;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class CommandArgument {
+
+ private final List<CommandArgumentType<?>> argumentTypes;
+ private final List<List<String>> tabComplete;
+
+ public CommandArgument(CommandArgumentType<?>... argumentTypes) {
+ this.argumentTypes = List.of(argumentTypes);
+ this.tabComplete = new ArrayList<>();
+ for (int i = 0; i < argumentTypes.length; i++) {
+ tabComplete.add(new ArrayList<>());
+ }
+ }
+
+ public List<String> tabComplete(int n) {
+ if (tabComplete.size() > n) {
+ return tabComplete.get(n);
+ } else {
+ return List.of();
+ }
+ }
+
+ public CommandArgument setTabComplete(int index, List<String> list) {
+ tabComplete.set(index, list);
+ return this;
+ }
+
+ public CommandArgumentResult parse(int index, String @NotNull [] args) {
+ Object[] result = new Object[argumentTypes.size()];
+ Arrays.fill(result, null);
+ for (int i = index, j = 0; i < args.length && j < result.length; i++, j++) {
+ result[j] = argumentTypes.get(j).pasre(args[i]);
+ }
+ return new CommandArgumentResult(new ArrayList<>(Arrays.asList(result)));
+ }
+}
diff --git a/src/main/java/top/leavesmc/leaves/command/CommandArgumentResult.java b/src/main/java/top/leavesmc/leaves/command/CommandArgumentResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..340eaca64c96180b895a075ce9e44402cd104eed
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/command/CommandArgumentResult.java
@@ -0,0 +1,62 @@
+package top.leavesmc.leaves.command;
+
+import net.minecraft.core.BlockPos;
+import org.bukkit.util.Vector;
+
+import java.util.List;
+import java.util.Objects;
+
+public class CommandArgumentResult {
+
+ private final List<Object> result;
+
+ public CommandArgumentResult(List<Object> result) {
+ this.result = result;
+ }
+
+ public Integer readInt(int def) {
+ return Objects.requireNonNullElse(read(Integer.class), def);
+ }
+
+ public Double readDouble(double def) {
+ return Objects.requireNonNullElse(read(Double.class), def);
+ }
+
+ public String readString(String def) {
+ return Objects.requireNonNullElse(read(String.class), def);
+ }
+
+ public BlockPos readPos() {
+ Integer[] pos = {read(Integer.class), read(Integer.class), read(Integer.class)};
+ for (Integer po : pos) {
+ if (po == null) {
+ return null;
+ }
+ }
+ return new BlockPos(pos[0], pos[1], pos[2]);
+ }
+
+ public Vector readVector() {
+ Double[] pos = {read(Double.class), read(Double.class), read(Double.class)};
+ for (Double po : pos) {
+ if (po == null) {
+ return null;
+ }
+ }
+ return new Vector(pos[0], pos[1], pos[2]);
+ }
+
+ public <T> T read(Class<T> tClass) {
+ if (result.isEmpty()) {
+ return null;
+ }
+
+ Object obj = result.remove(0);
+ if (tClass.isInstance(obj)) {
+ return tClass.cast(obj);
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/top/leavesmc/leaves/command/CommandArgumentType.java b/src/main/java/top/leavesmc/leaves/command/CommandArgumentType.java
new file mode 100644
index 0000000000000000000000000000000000000000..edf12195c7224ca2fb5d3c2ac3fcf485d3049d07
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/command/CommandArgumentType.java
@@ -0,0 +1,37 @@
+package top.leavesmc.leaves.command;
+
+import org.jetbrains.annotations.NotNull;
+
+public abstract class CommandArgumentType<E> {
+
+ public static final CommandArgumentType<Integer> INTEGER = new CommandArgumentType<>() {
+ @Override
+ public Integer pasre(@NotNull String arg) {
+ try {
+ return Integer.parseInt(arg);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+ };
+
+ public static final CommandArgumentType<Double> DOUBLE = new CommandArgumentType<>() {
+ @Override
+ public Double pasre(@NotNull String arg) {
+ try {
+ return Double.parseDouble(arg);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+ };
+
+ public static final CommandArgumentType<String> STRING = new CommandArgumentType<>() {
+ @Override
+ public String pasre(@NotNull String arg) {
+ return arg;
+ }
+ };
+
+ public abstract E pasre(@NotNull String arg);
+}