9
0
mirror of https://github.com/LeavesMC/Leaves.git synced 2025-12-29 11:59:17 +00:00

feat: finish leaves command

This commit is contained in:
MC_XiaoHei
2025-08-24 15:13:29 +08:00
parent ef6c8205e0
commit d0fb999ec6
62 changed files with 584 additions and 1130 deletions

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] No block update command
diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java
index 5d4eb61af0b0f39a5d4c37f4a303fa24b3a2936d..48bb795216ca3fb301813080de403a048bbfa98c 100644
index 9cce442c16ced8d9320a5760580ff13f02cbf8f1..6c67c3b9e7c70366c2889932fd4c0265218656d4 100644
--- a/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -381,7 +381,7 @@ public class ServerPlayerGameMode {
@@ -13,12 +13,12 @@ index 5d4eb61af0b0f39a5d4c37f4a303fa24b3a2936d..48bb795216ca3fb301813080de403a04
this.level.captureDrops = new java.util.ArrayList<>();
// CraftBukkit end
- BlockState blockState1 = block.playerWillDestroy(this.level, pos, blockState, this.player);
+ BlockState blockState1 = org.leavesmc.leaves.command.subcommands.BlockUpdateCommand.isNoBlockUpdate() ? blockState : block.playerWillDestroy(this.level, pos, blockState, this.player); // Leaves - no block update
+ BlockState blockState1 = org.leavesmc.leaves.command.leaves.subcommands.BlockUpdateCommand.isNoBlockUpdate() ? blockState : block.playerWillDestroy(this.level, pos, blockState, this.player); // Leaves - no block update
boolean flag = this.level.removeBlock(pos, false);
if (flag) {
block.destroy(this.level, pos, blockState1);
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index ef8a072838558caab19e8a85f4b59cac570c2635..590252ca203124f0b720a73f174c92fbe49bc685 100644
index 6202ea6f6f8e6b751434848fb6551c61162d076b..a8c20ef3be53bd462e4c352a08f4b7201a8af373 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -1089,6 +1089,11 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
@@ -26,7 +26,7 @@ index ef8a072838558caab19e8a85f4b59cac570c2635..590252ca203124f0b720a73f174c92fb
@Override
public boolean setBlock(BlockPos pos, BlockState state, int flags, int recursionLeft) {
+ // Leaves start - no block update
+ if (org.leavesmc.leaves.command.subcommands.BlockUpdateCommand.isNoBlockUpdate()) {
+ if (org.leavesmc.leaves.command.leaves.subcommands.BlockUpdateCommand.isNoBlockUpdate()) {
+ flags = flags & ~1 | net.minecraft.world.level.block.Block.UPDATE_SKIP_ON_PLACE;
+ }
+ // Leaves end - no block update
@@ -38,7 +38,7 @@ index ef8a072838558caab19e8a85f4b59cac570c2635..590252ca203124f0b720a73f174c92fb
BlockState blockState = oldState;
BlockState blockState1 = currentState;
+ // Leaves start - no block update
+ if (org.leavesmc.leaves.command.subcommands.BlockUpdateCommand.isNoBlockUpdate()) {
+ if (org.leavesmc.leaves.command.leaves.subcommands.BlockUpdateCommand.isNoBlockUpdate()) {
+ flags = flags & ~1 | net.minecraft.world.level.block.Block.UPDATE_SKIP_ON_PLACE;
+ }
+ // Leaves end - no block update
@@ -51,7 +51,7 @@ index ef8a072838558caab19e8a85f4b59cac570c2635..590252ca203124f0b720a73f174c92fb
int i = flags & -34;
-
+ // Leaves start - no block update
+ if (org.leavesmc.leaves.command.subcommands.BlockUpdateCommand.isNoBlockUpdate()) {
+ if (org.leavesmc.leaves.command.leaves.subcommands.BlockUpdateCommand.isNoBlockUpdate()) {
+ this.updatePOIOnBlockStateChange(pos, blockState, blockState1);
+ return;
+ }
@@ -60,19 +60,19 @@ index ef8a072838558caab19e8a85f4b59cac570c2635..590252ca203124f0b720a73f174c92fb
blockState.updateIndirectNeighbourShapes(this, pos, i, recursionLeft - 1); // Don't call an event for the old block to limit event spam
boolean cancelledUpdates = false; // Paper - Fix block place logic
diff --git a/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/net/minecraft/world/level/block/piston/PistonBaseBlock.java
index 16aa9f5996dc6eda95541fddb01e00e41305357a..31ab92e0769aa4ce09da5073ad9b734eeebac9c5 100644
index 16aa9f5996dc6eda95541fddb01e00e41305357a..6bd7d937bab8baf7c657e689e8a1b4069c207ff9 100644
--- a/net/minecraft/world/level/block/piston/PistonBaseBlock.java
+++ b/net/minecraft/world/level/block/piston/PistonBaseBlock.java
@@ -105,6 +105,7 @@ public class PistonBaseBlock extends DirectionalBlock {
}
private void checkIfExtend(Level level, BlockPos pos, BlockState state) {
+ if (org.leavesmc.leaves.command.subcommands.BlockUpdateCommand.isNoBlockUpdate()) return; // Leaves - no block update
+ if (org.leavesmc.leaves.command.leaves.subcommands.BlockUpdateCommand.isNoBlockUpdate()) return; // Leaves - no block update
Direction direction = state.getValue(FACING);
boolean neighborSignal = this.getNeighborSignal(level, pos, direction);
if (neighborSignal && !state.getValue(EXTENDED)) {
diff --git a/net/minecraft/world/level/redstone/NeighborUpdater.java b/net/minecraft/world/level/redstone/NeighborUpdater.java
index 263bf2b795057c2d5218bf9cfb684e526601aa77..da1e77ccd8805ac0cb0729720b4a1742da67d35c 100644
index 8942aa2ca4796c7c36c0955141627ea905e0ec64..2d2b7f3284171517d1e68cef802ae197e2e6f8bb 100644
--- a/net/minecraft/world/level/redstone/NeighborUpdater.java
+++ b/net/minecraft/world/level/redstone/NeighborUpdater.java
@@ -34,6 +34,11 @@ public interface NeighborUpdater {
@@ -80,7 +80,7 @@ index 263bf2b795057c2d5218bf9cfb684e526601aa77..da1e77ccd8805ac0cb0729720b4a1742
LevelAccessor level, Direction direction, BlockPos pos, BlockPos neighborPos, BlockState neighborState, int flags, int recursionLeft
) {
+ // Leaves start - no block update
+ if (org.leavesmc.leaves.command.subcommands.BlockUpdateCommand.isNoBlockUpdate()) {
+ if (org.leavesmc.leaves.command.leaves.subcommands.BlockUpdateCommand.isNoBlockUpdate()) {
+ flags = flags & ~1 | net.minecraft.world.level.block.Block.UPDATE_SKIP_ON_PLACE;
+ }
+ // Leaves end - no block update
@@ -91,7 +91,7 @@ index 263bf2b795057c2d5218bf9cfb684e526601aa77..da1e77ccd8805ac0cb0729720b4a1742
static void executeUpdate(Level level, BlockState state, BlockPos pos, Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston, BlockPos sourcePos) {
// Paper end - Add source block to BlockPhysicsEvent
+ if (org.leavesmc.leaves.command.subcommands.BlockUpdateCommand.isNoBlockUpdate()) return; // Leaves - no block update
+ if (org.leavesmc.leaves.command.leaves.subcommands.BlockUpdateCommand.isNoBlockUpdate()) return; // Leaves - no block update
try {
// CraftBukkit start
org.bukkit.event.block.BlockPhysicsEvent event = new org.bukkit.event.block.BlockPhysicsEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), org.bukkit.craftbukkit.block.data.CraftBlockData.fromData(state), org.bukkit.craftbukkit.block.CraftBlock.at(level, sourcePos)); // Paper - Add source block to BlockPhysicsEvent

View File

@@ -6,13 +6,13 @@ Subject: [PATCH] Prevent loss of item drops due to update suppression when
diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java
index f258bc30014f94243ad832b33dcb6c9acd1f2f08..9a4eb1f8e01517707befa30b3ccacc7c84c0abe9 100644
index 6c67c3b9e7c70366c2889932fd4c0265218656d4..3cc4ebfb9f083e8872460d6c47ad1d76d2cba990 100644
--- a/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -382,7 +382,18 @@ public class ServerPlayerGameMode {
this.level.captureDrops = new java.util.ArrayList<>();
// CraftBukkit end
BlockState blockState1 = org.leavesmc.leaves.command.subcommands.BlockUpdateCommand.isNoBlockUpdate() ? blockState : block.playerWillDestroy(this.level, pos, blockState, this.player); // Leaves - no block update
BlockState blockState1 = org.leavesmc.leaves.command.leaves.subcommands.BlockUpdateCommand.isNoBlockUpdate() ? blockState : block.playerWillDestroy(this.level, pos, blockState, this.player); // Leaves - no block update
- boolean flag = this.level.removeBlock(pos, false);
+ // Leaves start - Prevent loss of item drops due to update suppression when breaking blocks
+ boolean flag;

View File

@@ -447,13 +447,13 @@ index a63330b232dc41f0a5bb36bb94dfb84f01504699..7fbce8302739ab016f1b64f8227c6d72
+ // Leaves end - Lithium Sleeping Block Entity
}
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index f31a48530e965f01507c335f50d898ed72767e3c..e5b12f0be3c21b14b1fd8a33b20a9292e3b7b8df 100644
index 3699a9688c15afb2219e504ce6f3f27ea038b575..fc3517a1f14b72f127ab1e9342750491066a56cc 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -1224,6 +1224,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
int i = flags & -34;
// Leaves start - no block update
if (org.leavesmc.leaves.command.subcommands.BlockUpdateCommand.isNoBlockUpdate()) {
if (org.leavesmc.leaves.command.leaves.subcommands.BlockUpdateCommand.isNoBlockUpdate()) {
+ if (org.leavesmc.leaves.LeavesConfig.performance.sleepingBlockEntity) org.leavesmc.leaves.lithium.common.hopper.HopperHelper.updateHopperOnUpdateSuppression(this, pos, flags, chunkAt, oldState != currentState); // Leaves - Lithium Sleeping Block Entity
this.updatePOIOnBlockStateChange(pos, blockState, blockState1);
return;

View File

@@ -17,24 +17,6 @@ index 62e2d5704c348955bc8284dc2d54c933b7bcdd06..7ef20f0138fad39a1d23edd7b26ddc88
@Override
public void executeAsync(final Runnable runnable) {
MCUtil.scheduleAsyncTask(this.catching(runnable, "asynchronous"));
diff --git a/src/main/java/io/papermc/paper/command/brigadier/bukkit/BukkitCommandNode.java b/src/main/java/io/papermc/paper/command/brigadier/bukkit/BukkitCommandNode.java
index 5c52b1563d20d7e977a5bb958c18b19dec5c365a..65664441c5692620a8b22513ded497b7951a3245 100644
--- a/src/main/java/io/papermc/paper/command/brigadier/bukkit/BukkitCommandNode.java
+++ b/src/main/java/io/papermc/paper/command/brigadier/bukkit/BukkitCommandNode.java
@@ -106,6 +106,13 @@ public class BukkitCommandNode extends LiteralCommandNode<CommandSourceStack> {
List<String> results = null;
Location pos = context.getSource().getLocation();
try {
+ // Leaves start - custom suggestion
+ if (this.command instanceof org.leavesmc.leaves.command.LeavesSuggestionCommand suggestionCommand) {
+ org.leavesmc.leaves.command.LeavesSuggestionBuilder suggestionBuilder = new org.leavesmc.leaves.command.LeavesSuggestionBuilder(builder.createOffset(builder.getInput().lastIndexOf(' ') + 1));
+ suggestionCommand.suggest(sender, this.literal, args, pos.clone(), suggestionBuilder);
+ return suggestionBuilder.build();
+ }
+ // Leaves end - custom suggestion
results = this.command.tabComplete(sender, this.literal, args, pos.clone());
} catch (CommandException ex) {
sender.sendMessage(Component.text("An internal error occurred while attempting to tab-complete this command", NamedTextColor.RED));
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 32fe51b19323e3c4c56e7f9e621e6e808ee5fe38..2eba1d900b20a781c4bb08caa2b30bfeb2d02b9d 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java

View File

@@ -7,7 +7,6 @@ import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.configuration.MemorySection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.permissions.Permission;
@@ -16,7 +15,6 @@ import org.bukkit.plugin.PluginManager;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.bot.agent.Actions;
import org.leavesmc.leaves.command.LeavesCommand;
import org.leavesmc.leaves.config.GlobalConfigManager;
import org.leavesmc.leaves.config.annotations.GlobalConfig;
import org.leavesmc.leaves.config.annotations.GlobalConfigCategory;
@@ -30,7 +28,8 @@ import org.leavesmc.leaves.config.api.impl.ConfigValidatorImpl.IntConfigValidato
import org.leavesmc.leaves.config.api.impl.ConfigValidatorImpl.ListConfigValidator;
import org.leavesmc.leaves.config.api.impl.ConfigValidatorImpl.LongConfigValidator;
import org.leavesmc.leaves.config.api.impl.ConfigValidatorImpl.StringConfigValidator;
import org.leavesmc.leaves.neo_command.bot.BotCommand;
import org.leavesmc.leaves.command.bot.BotCommand;
import org.leavesmc.leaves.command.leaves.LeavesCommand;
import org.leavesmc.leaves.profile.LeavesMinecraftSessionService;
import org.leavesmc.leaves.protocol.CarpetServerProtocol.CarpetRule;
import org.leavesmc.leaves.protocol.CarpetServerProtocol.CarpetRules;
@@ -94,8 +93,7 @@ public final class LeavesConfig {
GlobalConfigManager.init();
registerCommand("leaves", new LeavesCommand());
org.leavesmc.leaves.neo_command.leaves.LeavesCommand.INSTANCE.register();
LeavesCommand.INSTANCE.register();
}
public static void reload() {
@@ -121,11 +119,6 @@ public final class LeavesConfig {
}
}
public static void registerCommand(String name, Command command) {
MinecraftServer.getServer().server.getCommandMap().register(name, "leaves", command);
MinecraftServer.getServer().server.syncCommands();
}
public static ModifyConfig modify = new ModifyConfig();
@GlobalConfigCategory("modify")
@@ -196,10 +189,8 @@ public final class LeavesConfig {
public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
if (old != null && !old.equals(value)) {
Bukkit.getOnlinePlayers().stream()
.filter(sender ->
BotCommand.hasPermission(sender)
|| BotCommand.hasPermission(sender, "action")
).forEach(org.bukkit.entity.Player::updateCommands);
.filter(sender -> BotCommand.hasPermission(sender, "action"))
.forEach(org.bukkit.entity.Player::updateCommands);
}
}
}
@@ -213,8 +204,7 @@ public final class LeavesConfig {
if (old != null && !old.equals(value)) {
Bukkit.getOnlinePlayers().stream()
.filter(sender ->
BotCommand.hasPermission(sender)
|| BotCommand.hasPermission(sender, "config")
BotCommand.hasPermission(sender, "config")
).forEach(org.bukkit.entity.Player::updateCommands);
}
}
@@ -229,9 +219,7 @@ public final class LeavesConfig {
if (old != null && !old.equals(value)) {
Bukkit.getOnlinePlayers().stream()
.filter(sender ->
BotCommand.hasPermission(sender)
|| BotCommand.hasPermission(sender, "save")
|| BotCommand.hasPermission(sender, "load")
BotCommand.hasPermission(sender, "save") || BotCommand.hasPermission(sender, "load")
).forEach(org.bukkit.entity.Player::updateCommands);
}
}
@@ -678,9 +666,20 @@ public final class LeavesConfig {
}
}
@GlobalConfig(value = "no-block-update-command")
@GlobalConfig(value = "no-block-update-command", validator = NoBlockUpdateValidator.class)
public boolean noBlockUpdateCommand = false;
private static class NoBlockUpdateValidator extends BooleanConfigValidator {
@Override
public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
if (old != null && !old.equals(value)) {
Bukkit.getOnlinePlayers().stream()
.filter(sender -> LeavesCommand.hasPermission(sender, "blockupdate"))
.forEach(org.bukkit.entity.Player::updateCommands);
}
}
}
@GlobalConfig("no-tnt-place-update")
public boolean noTNTPlaceUpdate = false;
@@ -709,9 +708,20 @@ public final class LeavesConfig {
public static class HopperCounterConfig {
@TransferConfig(value = "modify.hopper-counter", transformer = HopperCounterTransfer.class)
@TransferConfig("modify.counter.enable")
@GlobalConfig("enable")
@GlobalConfig(value = "enable", validator = HopperCounterValidator.class)
public boolean enable = false;
private static class HopperCounterValidator extends BooleanConfigValidator {
@Override
public void verify(Boolean old, Boolean value) throws IllegalArgumentException {
if (old != null && !old.equals(value)) {
Bukkit.getOnlinePlayers().stream()
.filter(sender -> LeavesCommand.hasPermission(sender, "counter"))
.forEach(org.bukkit.entity.Player::updateCommands);
}
}
}
@TransferConfig("modify.counter.unlimited-speed")
@GlobalConfig("unlimited-speed")
public boolean unlimitedSpeed = false;

View File

@@ -19,6 +19,8 @@ import org.bukkit.event.player.PlayerGameModeChangeEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static org.leavesmc.leaves.command.leaves.subcommands.BlockUpdateCommand.isNoBlockUpdate;
public class ServerBotGameMode extends ServerPlayerGameMode {
public ServerBotGameMode(ServerBot bot) {
@@ -62,7 +64,7 @@ public class ServerBotGameMode extends ServerPlayerGameMode {
this.level.sendBlockUpdated(pos, blockState, blockState, 3);
return false;
} else {
BlockState blockState1 = org.leavesmc.leaves.command.subcommands.BlockUpdateCommand.isNoBlockUpdate() ? blockState : block.playerWillDestroy(this.level, pos, blockState, this.player); // Leaves - no block update
BlockState blockState1 = isNoBlockUpdate() ? blockState : block.playerWillDestroy(this.level, pos, blockState, this.player); // Leaves - no block update
boolean flag = this.level.removeBlock(pos, false);
if (flag) {
block.destroy(this.level, pos, blockState1);

View File

@@ -10,8 +10,8 @@ import org.leavesmc.leaves.LeavesLogger;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.event.bot.BotActionExecuteEvent;
import org.leavesmc.leaves.event.bot.BotActionStopEvent;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.WrappedArgument;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.WrappedArgument;
import org.leavesmc.leaves.util.UpdateSuppressionException;
import java.util.ArrayList;

View File

@@ -2,12 +2,12 @@ package org.leavesmc.leaves.bot.agent.actions;
import net.minecraft.network.chat.Component;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.command.CommandContext;
import java.util.function.Supplier;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static org.leavesmc.leaves.neo_command.ArgumentNode.ArgumentSuggestions.strings;
import static org.leavesmc.leaves.command.ArgumentNode.ArgumentSuggestions.strings;
public abstract class AbstractTimerBotAction<E extends AbstractTimerBotAction<E>> extends AbstractBotAction<E> {

View File

@@ -6,7 +6,7 @@ import net.minecraft.world.InteractionResult;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.event.bot.BotActionStopEvent;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.command.CommandContext;
import java.util.function.Supplier;

View File

@@ -14,7 +14,7 @@ import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.entity.bot.actions.CraftLookAction;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.command.CommandContext;
public class ServerLookAction extends AbstractBotAction<ServerLookAction> {

View File

@@ -7,13 +7,13 @@ import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.entity.bot.action.MoveAction.MoveDirection;
import org.leavesmc.leaves.entity.bot.actions.CraftMoveAction;
import org.leavesmc.leaves.event.bot.BotActionStopEvent;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.command.CommandContext;
import java.util.Arrays;
import java.util.Map;
import static java.util.stream.Collectors.toMap;
import static org.leavesmc.leaves.neo_command.ArgumentNode.ArgumentSuggestions.strings;
import static org.leavesmc.leaves.command.ArgumentNode.ArgumentSuggestions.strings;
public class ServerMoveAction extends AbstractStateBotAction<ServerMoveAction> {
private static final Map<String, MoveDirection> NAME_TO_DIRECTION = Arrays.stream(MoveDirection.values()).collect(toMap(

View File

@@ -7,7 +7,7 @@ import net.minecraft.network.chat.Component;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.entity.bot.actions.CraftRotationAction;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.command.CommandContext;
import java.text.DecimalFormat;

View File

@@ -8,8 +8,8 @@ import net.minecraft.nbt.CompoundTag;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.WrappedArgument;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.WrappedArgument;
import java.lang.reflect.Method;
import java.util.List;

View File

@@ -4,7 +4,7 @@ import com.mojang.brigadier.arguments.BoolArgumentType;
import net.minecraft.nbt.CompoundTag;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.command.CommandContext;
public class AlwaysSendDataConfig extends AbstractBotConfig<Boolean, Boolean, AlwaysSendDataConfig> {
private boolean value;

View File

@@ -5,7 +5,7 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.waypoints.ServerWaypointManager;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.command.CommandContext;
public class LocatorBarConfig extends AbstractBotConfig<Boolean, Boolean, LocatorBarConfig> {
private boolean value;

View File

@@ -5,7 +5,7 @@ import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.nbt.CompoundTag;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.command.CommandContext;
import static net.minecraft.network.chat.Component.literal;

View File

@@ -4,7 +4,7 @@ import com.mojang.brigadier.arguments.BoolArgumentType;
import net.minecraft.nbt.CompoundTag;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.command.CommandContext;
public class SkipSleepConfig extends AbstractBotConfig<Boolean, Boolean, SkipSleepConfig> {

View File

@@ -5,7 +5,7 @@ import net.minecraft.nbt.CompoundTag;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.command.CommandContext;
import java.util.List;

View File

@@ -7,7 +7,7 @@ import net.minecraft.nbt.CompoundTag;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.command.CommandContext;
public class TickTypeConfig extends AbstractBotConfig<ServerBot.TickType, String, TickTypeConfig> {
private ServerBot.TickType value;

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command;
package org.leavesmc.leaves.command;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;

View File

@@ -1,67 +0,0 @@
package org.leavesmc.leaves.command;
import org.apache.commons.lang3.tuple.Pair;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiFunction;
public class CommandArgument {
public static final CommandArgument EMPTY = new CommandArgument();
private static final Pair<List<String>, String> EMPTY_SUGGESTION_RESULT = Pair.of(List.of(), null);
private static final BiFunction<CommandSender, String, Pair<List<String>, String>> EMPTY_SUGGESTION = (sender, arg) -> EMPTY_SUGGESTION_RESULT;
private final List<BiFunction<CommandSender, String, Pair<List<String>, String>>> suggestions;
private final List<CommandArgumentType<?>> argumentTypes;
private CommandArgument(CommandArgumentType<?>... argumentTypes) {
this.argumentTypes = List.of(argumentTypes);
this.suggestions = new ArrayList<>();
for (int i = 0; i < argumentTypes.length; i++) {
suggestions.add(EMPTY_SUGGESTION);
}
}
public static CommandArgument of(CommandArgumentType<?>... argumentTypes) {
return new CommandArgument(argumentTypes);
}
public List<CommandArgumentType<?>> getArgumentTypes() {
return argumentTypes;
}
public CommandArgument setSuggestion(int n, BiFunction<CommandSender, String, Pair<List<String>, String>> suggestion) {
this.suggestions.set(n, suggestion);
return this;
}
public CommandArgument setSuggestion(int n, Pair<List<String>, String> suggestion) {
return this.setSuggestion(n, (sender, arg) -> suggestion);
}
public CommandArgument setSuggestion(int n, List<String> tabComplete) {
return this.setSuggestion(n, Pair.of(tabComplete, null));
}
public Pair<List<String>, String> suggestion(int n, CommandSender sender, String arg) {
if (suggestions.size() > n) {
return suggestions.get(n).apply(sender, arg);
} else {
return EMPTY_SUGGESTION.apply(sender, arg);
}
}
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).parse(args[i]);
}
return new CommandArgumentResult(new ArrayList<>(Arrays.asList(result)));
}
}

View File

@@ -1,92 +0,0 @@
package org.leavesmc.leaves.command;
import net.minecraft.core.BlockPos;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Objects;
public class CommandArgumentResult {
private final List<Object> result;
public CommandArgumentResult(List<Object> result) {
this.result = result;
}
public int readInt(int def) {
return Objects.requireNonNullElse(read(Integer.class), def);
}
public double readDouble(double def) {
return Objects.requireNonNullElse(read(Double.class), def);
}
public float readFloat(float def) {
return Objects.requireNonNullElse(read(Float.class), def);
}
public String readString(String def) {
return Objects.requireNonNullElse(read(String.class), def);
}
public boolean readBoolean(boolean def) {
return Objects.requireNonNullElse(read(Boolean.class), def);
}
public BlockPos readPos() {
Integer[] pos = {read(Integer.class), read(Integer.class), read(Integer.class)};
for (Integer po : pos) {
if (po == null) {
return null;
}
}
return new BlockPos(pos[0], pos[1], pos[2]);
}
public @Nullable 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 @NotNull Vector readVectorYZ(double x) {
Double[] pos = {x, read(Double.class), read(Double.class)};
for (Double po : pos) {
if (po == null) {
throw new IllegalArgumentException("Failed to read vector!");
}
}
return new Vector(pos[0], pos[1], pos[2]);
}
public Object readObject() {
if (result.isEmpty()) {
return null;
}
return result.removeFirst();
}
public <T> T read(Class<T> tClass, T def) {
return Objects.requireNonNullElse(read(tClass), def);
}
public <T> T read(Class<T> tClass) {
if (result.isEmpty()) {
return null;
}
Object obj = result.removeFirst();
if (tClass.isInstance(obj)) {
return tClass.cast(obj);
} else {
return null;
}
}
}

View File

@@ -1,59 +0,0 @@
package org.leavesmc.leaves.command;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.function.Function;
public abstract class CommandArgumentType<E> {
public static final CommandArgumentType<String> STRING = CommandArgumentType.string();
public static final CommandArgumentType<Integer> INTEGER = CommandArgumentType.of(Integer.class, Integer::parseInt);
public static final CommandArgumentType<Double> DOUBLE = CommandArgumentType.of(Double.class, Double::parseDouble);
public static final CommandArgumentType<Float> FLOAT = CommandArgumentType.of(Float.class, Float::parseFloat);
public static final CommandArgumentType<Boolean> BOOLEAN = CommandArgumentType.of(Boolean.class, Boolean::parseBoolean);
private final Class<E> type;
private CommandArgumentType(Class<E> type) {
this.type = type;
}
@NotNull
@Contract(value = "_, _ -> new", pure = true)
public static <E> CommandArgumentType<E> of(Class<E> type, Function<String, E> parse) {
return new CommandArgumentType<>(type) {
@Override
public E parse(@NotNull String arg) {
try {
return parse.apply(arg);
} catch (Exception ignore) {
return null;
}
}
};
}
@NotNull
@Contract(value = "_ -> new", pure = true)
public static <E extends Enum<E>> CommandArgumentType<E> ofEnum(Class<E> type) {
return of(type, (string -> Enum.valueOf(type, string.toUpperCase())));
}
@NotNull
@Contract(value = " -> new", pure = true)
private static CommandArgumentType<String> string() {
return new CommandArgumentType<>(String.class) {
@Override
public String parse(@NotNull String arg) {
return arg;
}
};
}
public Class<E> getType() {
return type;
}
public abstract E parse(@NotNull String arg);
}

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command;
package org.leavesmc.leaves.command;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.RedirectModifier;
@@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
import static org.leavesmc.leaves.neo_command.CommandNode.getNameForNode;
import static org.leavesmc.leaves.command.CommandNode.getNameForNode;
@SuppressWarnings({"ClassCanBeRecord", "unused"})
public class CommandContext {

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command;
package org.leavesmc.leaves.command;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command;
package org.leavesmc.leaves.command;
import com.google.common.base.Functions;
import com.google.common.collect.Iterables;
@@ -23,6 +23,13 @@ import java.util.Map;
public class CommandUtils {
public static void registerPermissions(String base, @NotNull List<? extends CommandNode> children) {
List<String> permissions = new ArrayList<>();
permissions.add(base);
permissions.addAll(children.stream().map((it) -> base + "." + it.getName()).toList());
registerPermissions(permissions);
}
public static void registerPermissions(@NotNull List<String> permissions) {
PluginManager pluginManager = Bukkit.getServer().getPluginManager();
for (String perm : permissions) {

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command;
package org.leavesmc.leaves.command;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command;
package org.leavesmc.leaves.command;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;

View File

@@ -1,38 +0,0 @@
package org.leavesmc.leaves.command;
import net.minecraft.Util;
import org.leavesmc.leaves.command.subcommands.BlockUpdateCommand;
import org.leavesmc.leaves.command.subcommands.ConfigCommand;
import org.leavesmc.leaves.command.subcommands.CounterCommand;
import org.leavesmc.leaves.command.subcommands.ReloadCommand;
import org.leavesmc.leaves.command.subcommands.ReportCommand;
import org.leavesmc.leaves.command.subcommands.UpdateCommand;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public final class LeavesCommand extends LeavesRootCommand {
public static final String BASE_PERM = "bukkit.command.leaves.";
// subcommand label -> subcommand
private static final Map<String, LeavesSubcommand> SUBCOMMANDS = Util.make(() -> {
final Map<Set<String>, LeavesSubcommand> commands = new HashMap<>();
commands.put(Set.of("config"), new ConfigCommand());
commands.put(Set.of("update"), new UpdateCommand());
commands.put(Set.of("counter"), new CounterCommand());
commands.put(Set.of("reload"), new ReloadCommand());
commands.put(Set.of("report"), new ReportCommand());
commands.put(Set.of("blockupdate"), new BlockUpdateCommand());
return commands.entrySet().stream()
.flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue())))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
});
public LeavesCommand() {
super("leaves", "Leaves related commands", "bukkit.command.leaves", SUBCOMMANDS);
}
}

View File

@@ -1,181 +0,0 @@
package org.leavesmc.leaves.command;
import com.google.common.base.Functions;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import net.minecraft.resources.ResourceLocation;
import org.bukkit.command.CommandSender;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@DefaultQualifier(NonNull.class)
public class LeavesCommandUtil {
private LeavesCommandUtil() {
}
// Code from Mojang - copyright them
public static List<String> getListMatchingLast(
final CommandSender sender,
final String[] args,
final String... matches
) {
return getListMatchingLast(sender, args, Arrays.asList(matches));
}
public static boolean matches(final String s, final String s1) {
return s1.regionMatches(true, 0, s, 0, s.length());
}
public static List<String> getListMatchingLast(
final CommandSender sender,
final String[] strings,
final Collection<?> collection
) {
return getListMatchingLast(sender, strings, collection, LeavesCommand.BASE_PERM, "bukkit.command.leaves");
}
public static List<String> getListMatchingLast(
final CommandSender sender,
final String[] strings,
final Collection<?> collection,
final String basePermission,
final String overridePermission
) {
String last = strings[strings.length - 1];
ArrayList<String> results = Lists.newArrayList();
if (!collection.isEmpty()) {
for (String s1 : Iterables.transform(collection, Functions.toStringFunction())) {
if (matches(last, s1) && (sender.hasPermission(basePermission + s1) || sender.hasPermission(overridePermission))) {
results.add(s1);
}
}
if (results.isEmpty()) {
for (Object object : collection) {
if (object instanceof ResourceLocation && matches(last, ((ResourceLocation) object).getPath())) {
results.add(String.valueOf(object));
}
}
}
}
return results;
}
// end copy stuff
public static List<String> getListClosestMatchingLast(
final CommandSender sender,
final String last,
final Collection<?> collection,
final String overridePermission
) {
ArrayList<Candidate> candidates = Lists.newArrayList();
if (collection.isEmpty() || !sender.hasPermission(overridePermission)) {
return Collections.emptyList();
}
String lastLower = last.toLowerCase();
for (String item : Iterables.transform(collection, Functions.toStringFunction())) {
String itemLower = item.toLowerCase();
if (itemLower.startsWith(lastLower)) {
candidates.add(Candidate.of(item, 0));
} else if (itemLower.contains(lastLower)) {
candidates.add(Candidate.of(item, damerauLevenshteinDistance(lastLower, itemLower)));
}
}
candidates.sort(Comparator.comparingInt(c -> c.score));
List<String> results = new ArrayList<>(candidates.size());
for (Candidate candidate : candidates) {
results.add(candidate.item);
}
return results;
}
/**
* Computes the Dameraur-Levenshtein Distance between two strings. Adapted
* from the algorithm at <a href="http://en.wikipedia.org/wiki/Damerau%E2%80%93Levenshtein_distance">Wikipedia: DamerauLevenshtein distance</a>
*
* @param s1 The first string being compared.
* @param s2 The second string being compared.
* @return The number of substitutions, deletions, insertions, and
* transpositions required to get from s1 to s2.
*/
@SuppressWarnings("DuplicatedCode")
private static int damerauLevenshteinDistance(@Nullable String s1, @Nullable String s2) {
if (s1 == null && s2 == null) {
return 0;
}
if (s1 != null && s2 == null) {
return s1.length();
}
if (s1 == null && s2 != null) {
return s2.length();
}
int s1Len = s1.length();
int s2Len = s2.length();
int[][] H = new int[s1Len + 2][s2Len + 2];
int INF = s1Len + s2Len;
H[0][0] = INF;
for (int i = 0; i <= s1Len; i++) {
H[i + 1][1] = i;
H[i + 1][0] = INF;
}
for (int j = 0; j <= s2Len; j++) {
H[1][j + 1] = j;
H[0][j + 1] = INF;
}
Map<Character, Integer> sd = new HashMap<>();
for (char Letter : (s1 + s2).toCharArray()) {
if (!sd.containsKey(Letter)) {
sd.put(Letter, 0);
}
}
for (int i = 1; i <= s1Len; i++) {
int DB = 0;
for (int j = 1; j <= s2Len; j++) {
int i1 = sd.get(s2.charAt(j - 1));
int j1 = DB;
if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
H[i + 1][j + 1] = H[i][j];
DB = j;
} else {
H[i + 1][j + 1] = Math.min(H[i][j], Math.min(H[i + 1][j], H[i][j + 1])) + 1;
}
H[i + 1][j + 1] = Math.min(H[i + 1][j + 1], H[i1][j1] + (i - i1 - 1) + 1 + (j - j1 - 1));
}
sd.put(s1.charAt(i - 1), i);
}
return H[s1Len + 1][s2Len + 1];
}
// Copy from org/bukkit/command/defaults/HelpCommand.java
private record Candidate(String item, int score) {
private static Candidate of(String item, int score) {
return new Candidate(item, score);
}
}
}

View File

@@ -1,126 +0,0 @@
package org.leavesmc.leaves.command;
import it.unimi.dsi.fastutil.Pair;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.PluginManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.format.NamedTextColor.RED;
public abstract class LeavesRootCommand extends Command implements LeavesSuggestionCommand {
protected final String basePermission;
protected final Map<String, LeavesSubcommand> subcommands;
protected LeavesRootCommand(
@NotNull String name,
@NotNull String description,
@NotNull String basePermission,
@NotNull Map<String, LeavesSubcommand> subCommands
) {
super(name, description, String.format("/%s [%s]", name, String.join(" | ", subCommands.keySet())), Collections.emptyList());
this.basePermission = basePermission;
this.subcommands = subCommands;
final List<String> permissions = new ArrayList<>();
permissions.add(basePermission);
permissions.addAll(subCommands.keySet().stream().map(s -> basePermission + "." + s).toList());
this.setPermission(String.join(";", permissions));
final PluginManager pluginManager = Bukkit.getServer().getPluginManager();
for (final String perm : permissions) {
if (pluginManager.getPermission(perm) == null) {
pluginManager.addPermission(new Permission(perm, PermissionDefault.OP));
}
}
}
protected boolean testPermission(final CommandSender sender, final String permission) {
if (sender.hasPermission(basePermission) || sender.hasPermission(basePermission + "." + permission)) {
return true;
}
sender.sendMessage(Bukkit.permissionMessage());
return false;
}
@Override
public boolean execute(@NotNull CommandSender sender, @NotNull String label, @NotNull String @NotNull [] args) {
if (!testPermission(sender) || !isEnabled()) {
return true;
}
if (args.length == 0) {
sender.sendMessage(unknownMessage());
return true;
}
final Pair<String, LeavesSubcommand> subCommand = resolveCommand(args[0]);
if (subCommand == null) {
sender.sendMessage(unknownMessage());
return true;
}
if (!testPermission(sender, subCommand.first())) {
return true;
}
final String[] choppedArgs = Arrays.copyOfRange(args, 1, args.length);
subCommand.second().execute(sender, subCommand.first(), choppedArgs);
return true;
}
@Override
public void suggest(final @NotNull CommandSender sender, final @NotNull String alias, final @NotNull String @NotNull [] args, final @Nullable Location location, @NotNull LeavesSuggestionBuilder builder) throws IllegalArgumentException {
if (!testPermission(sender) || !isEnabled()) {
return;
}
if (args.length <= 1) {
LeavesCommandUtil.getListMatchingLast(sender, args, usableSubcommands(), basePermission + ".", basePermission).forEach(builder::suggest);
return;
}
final @Nullable Pair<String, LeavesSubcommand> subCommand = resolveCommand(args[0]);
if (subCommand != null) {
subCommand.second().suggest(sender, subCommand.first(), Arrays.copyOfRange(args, 1, args.length), location, builder);
}
}
public Component unknownMessage() {
return text(String.format("Usage: /%s [%s]", this.getName(), String.join(" | ", usableSubcommands())), RED);
}
@Nullable
public Pair<String, LeavesSubcommand> resolveCommand(String label) {
label = label.toLowerCase(Locale.ENGLISH);
LeavesSubcommand subCommand = subcommands.get(label);
if (subCommand != null && subCommand.isEnabled()) {
return Pair.of(label, subCommand);
}
return null;
}
public Collection<String> usableSubcommands() {
List<String> subcommandList = new ArrayList<>();
for (var entry : subcommands.entrySet()) {
if (entry.getValue().isEnabled()) {
subcommandList.add(entry.getKey());
}
}
return subcommandList;
}
}

View File

@@ -1,7 +0,0 @@
package org.leavesmc.leaves.command;
import org.bukkit.command.CommandSender;
public interface LeavesSubcommand extends LeavesSuggestionCommand {
void execute(CommandSender sender, String subCommand, String[] args);
}

View File

@@ -1,49 +0,0 @@
package org.leavesmc.leaves.command;
import com.mojang.brigadier.Message;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import java.util.concurrent.CompletableFuture;
public class LeavesSuggestionBuilder {
private SuggestionsBuilder vanillaBuilder;
public LeavesSuggestionBuilder(SuggestionsBuilder builder) {
this.vanillaBuilder = builder;
}
public CompletableFuture<Suggestions> build() {
return vanillaBuilder.buildFuture();
}
public LeavesSuggestionBuilder suggest(String text) {
vanillaBuilder.suggest(text);
return this;
}
public LeavesSuggestionBuilder suggest(String text, Message tooltip) {
vanillaBuilder.suggest(text, tooltip);
return this;
}
public LeavesSuggestionBuilder suggest(int value) {
vanillaBuilder.suggest(value);
return this;
}
public LeavesSuggestionBuilder suggest(int value, Message tooltip) {
vanillaBuilder.suggest(value, tooltip);
return this;
}
public LeavesSuggestionBuilder createOffset(int start) {
vanillaBuilder = vanillaBuilder.createOffset(start);
return this;
}
public String getInput() {
return vanillaBuilder.getInput();
}
}

View File

@@ -1,15 +0,0 @@
package org.leavesmc.leaves.command;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface LeavesSuggestionCommand {
default void suggest(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] args, @Nullable Location location, LeavesSuggestionBuilder builder) throws IllegalArgumentException {
}
default boolean isEnabled() {
return true;
}
}

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command;
package org.leavesmc.leaves.command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.ArgumentBuilder;

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command;
package org.leavesmc.leaves.command;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command.bot;
package org.leavesmc.leaves.command.bot;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
@@ -11,8 +11,8 @@ import org.bukkit.entity.Player;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.entity.bot.Bot;
import org.leavesmc.leaves.entity.bot.CraftBot;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.CustomArgumentType;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.CustomArgumentType;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;

View File

@@ -1,22 +1,19 @@
package org.leavesmc.leaves.neo_command.bot;
package org.leavesmc.leaves.command.bot;
import com.mojang.brigadier.builder.ArgumentBuilder;
import net.minecraft.commands.CommandSourceStack;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.neo_command.CommandNode;
import org.leavesmc.leaves.neo_command.CommandUtils;
import org.leavesmc.leaves.neo_command.LiteralNode;
import org.leavesmc.leaves.neo_command.bot.subcommands.ActionCommand;
import org.leavesmc.leaves.neo_command.bot.subcommands.ConfigCommand;
import org.leavesmc.leaves.neo_command.bot.subcommands.CreateCommand;
import org.leavesmc.leaves.neo_command.bot.subcommands.ListCommand;
import org.leavesmc.leaves.neo_command.bot.subcommands.LoadCommand;
import org.leavesmc.leaves.neo_command.bot.subcommands.RemoveCommand;
import org.leavesmc.leaves.neo_command.bot.subcommands.SaveCommand;
import org.leavesmc.leaves.command.LiteralNode;
import org.leavesmc.leaves.command.bot.subcommands.ActionCommand;
import org.leavesmc.leaves.command.bot.subcommands.ConfigCommand;
import org.leavesmc.leaves.command.bot.subcommands.CreateCommand;
import org.leavesmc.leaves.command.bot.subcommands.ListCommand;
import org.leavesmc.leaves.command.bot.subcommands.LoadCommand;
import org.leavesmc.leaves.command.bot.subcommands.RemoveCommand;
import org.leavesmc.leaves.command.bot.subcommands.SaveCommand;
import java.util.ArrayList;
import java.util.List;
import static org.leavesmc.leaves.command.CommandUtils.registerPermissions;
public class BotCommand extends LiteralNode {
public static final BotCommand INSTANCE = new BotCommand();
@@ -37,10 +34,7 @@ public class BotCommand extends LiteralNode {
@Override
protected ArgumentBuilder<CommandSourceStack, ?> compile() {
List<String> permissions = new ArrayList<>();
permissions.add(PERM_BASE);
permissions.addAll(this.children.stream().map(CommandNode::getName).toList());
CommandUtils.registerPermissions(permissions);
registerPermissions(PERM_BASE, this.children);
return super.compile();
}

View File

@@ -1,8 +1,8 @@
package org.leavesmc.leaves.neo_command.bot;
package org.leavesmc.leaves.command.bot;
import net.minecraft.commands.CommandSourceStack;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.neo_command.LiteralNode;
import org.leavesmc.leaves.command.LiteralNode;
public abstract class BotSubcommand extends LiteralNode {

View File

@@ -1,16 +1,16 @@
package org.leavesmc.leaves.neo_command.bot.subcommands;
package org.leavesmc.leaves.command.bot.subcommands;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.commands.CommandSourceStack;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.CustomArgumentNode;
import org.leavesmc.leaves.neo_command.bot.BotSubcommand;
import org.leavesmc.leaves.neo_command.bot.subcommands.action.ListCommand;
import org.leavesmc.leaves.neo_command.bot.subcommands.action.StartCommand;
import org.leavesmc.leaves.neo_command.bot.subcommands.action.StopCommand;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.CustomArgumentNode;
import org.leavesmc.leaves.command.bot.BotSubcommand;
import org.leavesmc.leaves.command.bot.subcommands.action.ListCommand;
import org.leavesmc.leaves.command.bot.subcommands.action.StartCommand;
import org.leavesmc.leaves.command.bot.subcommands.action.StopCommand;
public class ActionCommand extends BotSubcommand {
@@ -27,7 +27,7 @@ public class ActionCommand extends BotSubcommand {
public static class BotArgument extends CustomArgumentNode<ServerBot, String> {
protected BotArgument() {
super("bot", new org.leavesmc.leaves.neo_command.bot.BotArgument());
super("bot", new org.leavesmc.leaves.command.bot.BotArgument());
children(
StartCommand::new,
StopCommand::new,

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command.bot.subcommands;
package org.leavesmc.leaves.command.bot.subcommands;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
@@ -11,10 +11,10 @@ import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.bot.agent.Configs;
import org.leavesmc.leaves.bot.agent.configs.AbstractBotConfig;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.CustomArgumentNode;
import org.leavesmc.leaves.neo_command.LiteralNode;
import org.leavesmc.leaves.neo_command.bot.BotSubcommand;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.CustomArgumentNode;
import org.leavesmc.leaves.command.LiteralNode;
import org.leavesmc.leaves.command.bot.BotSubcommand;
import java.util.Collection;
import java.util.function.Supplier;
@@ -41,7 +41,7 @@ public class ConfigCommand extends BotSubcommand {
private static class BotArgument extends CustomArgumentNode<ServerBot, String> {
protected BotArgument() {
super("bot", new org.leavesmc.leaves.neo_command.bot.BotArgument());
super("bot", new org.leavesmc.leaves.command.bot.BotArgument());
Configs.getConfigs().stream()
.map(this::configNodeCreator)
.forEach(this::children);

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command.bot.subcommands;
package org.leavesmc.leaves.command.bot.subcommands;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
@@ -20,9 +20,9 @@ import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.bot.BotCreateState;
import org.leavesmc.leaves.bot.BotList;
import org.leavesmc.leaves.event.bot.BotCreateEvent;
import org.leavesmc.leaves.neo_command.ArgumentNode;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.bot.BotSubcommand;
import org.leavesmc.leaves.command.ArgumentNode;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.bot.BotSubcommand;
import static net.kyori.adventure.text.Component.text;
import static net.minecraft.commands.arguments.DimensionArgument.getDimension;

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command.bot.subcommands;
package org.leavesmc.leaves.command.bot.subcommands;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import io.papermc.paper.adventure.PaperAdventure;
@@ -16,9 +16,9 @@ import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.bot.BotList;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.neo_command.ArgumentNode;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.bot.BotSubcommand;
import org.leavesmc.leaves.command.ArgumentNode;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.bot.BotSubcommand;
import java.util.List;
import java.util.Objects;

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command.bot.subcommands;
package org.leavesmc.leaves.command.bot.subcommands;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
@@ -11,9 +11,9 @@ import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.bot.BotList;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.neo_command.ArgumentNode;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.bot.BotSubcommand;
import org.leavesmc.leaves.command.ArgumentNode;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.bot.BotSubcommand;
import java.util.Set;
import java.util.concurrent.CompletableFuture;

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command.bot.subcommands;
package org.leavesmc.leaves.command.bot.subcommands;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
@@ -10,10 +10,10 @@ import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.bot.BotList;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.event.bot.BotRemoveEvent;
import org.leavesmc.leaves.neo_command.ArgumentNode;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.CustomArgumentNode;
import org.leavesmc.leaves.neo_command.bot.BotSubcommand;
import org.leavesmc.leaves.command.ArgumentNode;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.CustomArgumentNode;
import org.leavesmc.leaves.command.bot.BotSubcommand;
import org.leavesmc.leaves.plugin.MinecraftInternalPlugin;
import java.util.regex.Matcher;
@@ -44,7 +44,7 @@ public class RemoveCommand extends BotSubcommand {
private static class BotArgument extends CustomArgumentNode<ServerBot, String> {
public BotArgument() {
super("bot", new org.leavesmc.leaves.neo_command.bot.BotArgument());
super("bot", new org.leavesmc.leaves.command.bot.BotArgument());
children(RemoveTimeArgument::new);
}

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command.bot.subcommands;
package org.leavesmc.leaves.command.bot.subcommands;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.kyori.adventure.text.format.NamedTextColor;
@@ -9,9 +9,9 @@ import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.bot.BotList;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.event.bot.BotRemoveEvent;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.CustomArgumentNode;
import org.leavesmc.leaves.neo_command.bot.BotSubcommand;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.CustomArgumentNode;
import org.leavesmc.leaves.command.bot.BotSubcommand;
import static io.papermc.paper.adventure.PaperAdventure.asAdventure;
import static net.kyori.adventure.text.Component.join;
@@ -33,7 +33,7 @@ public class SaveCommand extends BotSubcommand {
private static class BotArgument extends CustomArgumentNode<ServerBot, String> {
private BotArgument() {
super("bot", new org.leavesmc.leaves.neo_command.bot.BotArgument());
super("bot", new org.leavesmc.leaves.command.bot.BotArgument());
}
@Override

View File

@@ -1,13 +1,13 @@
package org.leavesmc.leaves.neo_command.bot.subcommands.action;
package org.leavesmc.leaves.command.bot.subcommands.action;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.bot.agent.actions.AbstractBotAction;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.LiteralNode;
import org.leavesmc.leaves.neo_command.bot.subcommands.ActionCommand;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.LiteralNode;
import org.leavesmc.leaves.command.bot.subcommands.ActionCommand;
import java.util.List;

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command.bot.subcommands.action;
package org.leavesmc.leaves.command.bot.subcommands.action;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.builder.ArgumentBuilder;
@@ -11,9 +11,9 @@ import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.bot.agent.Actions;
import org.leavesmc.leaves.bot.agent.actions.AbstractBotAction;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.LiteralNode;
import org.leavesmc.leaves.neo_command.WrappedArgument;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.LiteralNode;
import org.leavesmc.leaves.command.WrappedArgument;
import java.util.List;
import java.util.Map;
@@ -26,7 +26,7 @@ import static net.kyori.adventure.text.JoinConfiguration.spaces;
import static net.kyori.adventure.text.event.HoverEvent.showText;
import static net.kyori.adventure.text.format.NamedTextColor.AQUA;
import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
import static org.leavesmc.leaves.neo_command.bot.subcommands.ActionCommand.BotArgument.getBot;
import static org.leavesmc.leaves.command.bot.subcommands.ActionCommand.BotArgument.getBot;
public class StartCommand extends LiteralNode {

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.neo_command.bot.subcommands.action;
package org.leavesmc.leaves.command.bot.subcommands.action;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
@@ -10,10 +10,10 @@ import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.bot.ServerBot;
import org.leavesmc.leaves.bot.agent.actions.AbstractBotAction;
import org.leavesmc.leaves.event.bot.BotActionStopEvent;
import org.leavesmc.leaves.neo_command.ArgumentNode;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.LiteralNode;
import org.leavesmc.leaves.neo_command.bot.subcommands.ActionCommand;
import org.leavesmc.leaves.command.ArgumentNode;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.LiteralNode;
import org.leavesmc.leaves.command.bot.subcommands.ActionCommand;
import java.util.HashSet;
import java.util.List;

View File

@@ -1,32 +1,38 @@
package org.leavesmc.leaves.neo_command.leaves;
package org.leavesmc.leaves.command.leaves;
import com.mojang.brigadier.builder.ArgumentBuilder;
import net.minecraft.commands.CommandSourceStack;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.neo_command.CommandNode;
import org.leavesmc.leaves.neo_command.CommandUtils;
import org.leavesmc.leaves.neo_command.LiteralNode;
import org.leavesmc.leaves.neo_command.leaves.subcommands.ConfigCommand;
import org.leavesmc.leaves.command.LiteralNode;
import org.leavesmc.leaves.command.leaves.subcommands.BlockUpdateCommand;
import org.leavesmc.leaves.command.leaves.subcommands.ConfigCommand;
import org.leavesmc.leaves.command.leaves.subcommands.CounterCommand;
import org.leavesmc.leaves.command.leaves.subcommands.ReloadCommand;
import org.leavesmc.leaves.command.leaves.subcommands.ReportCommand;
import org.leavesmc.leaves.command.leaves.subcommands.UpdateCommand;
import java.util.ArrayList;
import java.util.List;
import static org.leavesmc.leaves.command.CommandUtils.registerPermissions;
public class LeavesCommand extends LiteralNode {
public static final LeavesCommand INSTANCE = new LeavesCommand();
private static final String PERM_BASE = "bukkit.command.leaves";
private LeavesCommand() {
super("leaves_new");
children(ConfigCommand::new);
super("leaves");
children(
BlockUpdateCommand::new,
ConfigCommand::new,
CounterCommand::new,
ReloadCommand::new,
ReportCommand::new,
UpdateCommand::new
);
}
@Override
protected ArgumentBuilder<CommandSourceStack, ?> compile() {
List<String> permissions = new ArrayList<>();
permissions.add(PERM_BASE);
permissions.addAll(this.children.stream().map(CommandNode::getName).toList());
CommandUtils.registerPermissions(permissions);
registerPermissions(PERM_BASE, this.children);
return super.compile();
}

View File

@@ -0,0 +1,22 @@
package org.leavesmc.leaves.command.leaves;
import net.minecraft.commands.CommandSourceStack;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.command.LiteralNode;
public abstract class LeavesSubcommand extends LiteralNode {
protected LeavesSubcommand(String name) {
super(name);
}
@Override
public boolean requires(@NotNull CommandSourceStack source) {
return hasPermission(source.getSender());
}
protected boolean hasPermission(CommandSender sender) {
return LeavesCommand.hasPermission(sender, this.name);
}
}

View File

@@ -0,0 +1,101 @@
package org.leavesmc.leaves.command.leaves.subcommands;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.commands.CommandSourceStack;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.LiteralNode;
import org.leavesmc.leaves.command.leaves.LeavesSubcommand;
import static net.kyori.adventure.text.Component.join;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.JoinConfiguration.spaces;
import static net.kyori.adventure.text.format.NamedTextColor.AQUA;
import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
public class BlockUpdateCommand extends LeavesSubcommand {
private static boolean noBlockUpdate = false;
public static boolean isNoBlockUpdate() {
return LeavesConfig.modify.noBlockUpdateCommand && noBlockUpdate;
}
public BlockUpdateCommand() {
super("blockupdate");
children(
EnableNode::new,
DisableNode::new
);
}
@Override
protected boolean execute(@NotNull CommandContext context) throws CommandSyntaxException {
context.getSender().sendMessage(join(spaces(),
text("Block update is", GRAY),
text(noBlockUpdate ? "disabled" : "enabled", AQUA)
));
return true;
}
@Override
public boolean requires(@NotNull CommandSourceStack source) {
return LeavesConfig.modify.noBlockUpdateCommand && super.requires(source);
}
private class EnableNode extends LiteralNode {
private EnableNode() {
super("enable");
}
@Override
protected boolean execute(@NotNull CommandContext context) {
CommandSender sender = context.getSender();
if (!noBlockUpdate) {
sender.sendMessage(join(spaces(),
text("Block update is already", GRAY),
text("enabled", AQUA)
));
return true;
}
noBlockUpdate = false;
Bukkit.getOnlinePlayers().stream()
.filter(BlockUpdateCommand.this::hasPermission)
.forEach(player -> player.sendMessage(join(spaces(),
text("Block update is", GRAY),
text("enabled", AQUA)
)));
return true;
}
}
private class DisableNode extends LiteralNode {
private DisableNode() {
super("disable");
}
@Override
protected boolean execute(@NotNull CommandContext context) {
CommandSender sender = context.getSender();
if (noBlockUpdate) {
sender.sendMessage(join(spaces(),
text("Block update is already", GRAY),
text("disabled", AQUA)
));
return true;
}
noBlockUpdate = true;
Bukkit.getOnlinePlayers().stream()
.filter(BlockUpdateCommand.this::hasPermission)
.forEach(player -> player.sendMessage(join(spaces(),
text("Block update is", GRAY),
text("disabled", AQUA)
)));
return true;
}
}
}

View File

@@ -1,19 +1,16 @@
package org.leavesmc.leaves.neo_command.leaves.subcommands;
package org.leavesmc.leaves.command.leaves.subcommands;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.commands.CommandSourceStack;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.command.LeavesCommandUtil;
import org.leavesmc.leaves.config.GlobalConfigManager;
import org.leavesmc.leaves.config.VerifiedConfig;
import org.leavesmc.leaves.neo_command.ArgumentNode;
import org.leavesmc.leaves.neo_command.CommandContext;
import org.leavesmc.leaves.neo_command.LiteralNode;
import org.leavesmc.leaves.neo_command.leaves.LeavesCommand;
import org.leavesmc.leaves.command.ArgumentNode;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.leaves.LeavesSubcommand;
import java.util.concurrent.CompletableFuture;
@@ -21,20 +18,15 @@ import static net.kyori.adventure.text.Component.join;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.JoinConfiguration.spaces;
import static net.kyori.adventure.text.format.NamedTextColor.*;
import static org.leavesmc.leaves.neo_command.CommandUtils.getListClosestMatchingLast;
import static org.leavesmc.leaves.command.CommandUtils.getListClosestMatchingLast;
public class ConfigCommand extends LiteralNode {
public class ConfigCommand extends LeavesSubcommand {
public ConfigCommand() {
super("config");
children(PathArgument::new);
}
@Override
public boolean requires(@NotNull CommandSourceStack source) {
return LeavesCommand.hasPermission(source.getSender(), "config");
}
private static class PathArgument extends ArgumentNode<String> {
public PathArgument() {
@@ -93,18 +85,13 @@ public class ConfigCommand extends LiteralNode {
@Override
protected CompletableFuture<Suggestions> getSuggestions(@NotNull CommandContext context, @NotNull SuggestionsBuilder builder) {
String path = context.getArgument(PathArgument.class);
String value = context.getArgumentOrDefault(ValueArgument.class, "");
VerifiedConfig verifiedConfig = GlobalConfigManager.getVerifiedConfig(path);
if (verifiedConfig == null) {
return builder
.suggest("<ERROR CONFIG>", net.minecraft.network.chat.Component.literal("This config path does not exist."))
.buildFuture();
}
LeavesCommandUtil.getListMatchingLast(
context.getSender(),
new String[]{value},
verifiedConfig.validator().valueSuggest()
).forEach(builder::suggest);
verifiedConfig.validator().valueSuggest().forEach(builder::suggest);
return builder.buildFuture();
}

View File

@@ -0,0 +1,170 @@
package org.leavesmc.leaves.command.leaves.subcommands;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.DyeColor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.LiteralNode;
import org.leavesmc.leaves.command.leaves.LeavesSubcommand;
import org.leavesmc.leaves.util.HopperCounter;
import static net.kyori.adventure.text.Component.join;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.JoinConfiguration.spaces;
import static net.kyori.adventure.text.format.NamedTextColor.AQUA;
import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
public class CounterCommand extends LeavesSubcommand {
public CounterCommand() {
super("counter");
children(
EnableNode::new,
DisableNode::new,
ResetAllNode::new
);
for (DyeColor color : DyeColor.values()) {
children(() -> new ColorNode(color));
}
}
@Override
public boolean requires(@NotNull CommandSourceStack source) {
return LeavesConfig.modify.hopperCounter.enable && super.requires(source);
}
@Override
protected boolean execute(@NotNull CommandContext context) {
context.getSender().sendMessage(join(spaces(),
text("Hopper counter is", GRAY),
text(HopperCounter.isEnabled() ? "enabled" : "disabled", AQUA)
));
return true;
}
private static class EnableNode extends LiteralNode {
private EnableNode() {
super("enable");
}
@Override
protected boolean execute(@NotNull CommandContext context) {
CommandSender sender = context.getSender();
if (HopperCounter.isEnabled()) {
sender.sendMessage(join(spaces(),
text("Hopper counter is already", GRAY),
text("disabled", AQUA)
));
return true;
}
HopperCounter.setEnabled(true);
sender.sendMessage(join(spaces(),
text("Hopper counter is now", GRAY),
text("enabled", AQUA)
));
return true;
}
}
private static class DisableNode extends LiteralNode {
private DisableNode() {
super("disable");
}
@Override
protected boolean execute(@NotNull CommandContext context) {
CommandSender sender = context.getSender();
if (!HopperCounter.isEnabled()) {
sender.sendMessage(join(spaces(),
text("Hopper counter is already", GRAY),
text("disabled", AQUA)
));
return true;
}
HopperCounter.setEnabled(false);
sender.sendMessage(join(spaces(),
text("Hopper counter is now", GRAY),
text("disabled", AQUA)
));
return true;
}
}
private static class ResetAllNode extends LiteralNode {
private ResetAllNode() {
super("reset");
}
@Override
protected boolean execute(@NotNull CommandContext context) {
HopperCounter.resetAll(MinecraftServer.getServer(), false);
context.getSender().sendMessage(text("Restarted all counters", GRAY));
return true;
}
}
private static class ColorNode extends LiteralNode {
private final DyeColor color;
private final HopperCounter counter;
private ColorNode(@NotNull DyeColor color) {
super(color.getName());
this.color = color;
this.counter = HopperCounter.getCounter(color);
children(
ResetNode::new,
RealtimeNode::new
);
}
@Override
protected boolean execute(@NotNull CommandContext context) {
displayCounter(context.getSender(), false);
return true;
}
private void displayCounter(CommandSender sender, boolean realTime) {
for (Component component : counter.format(MinecraftServer.getServer(), realTime)) {
sender.sendMessage(component);
}
}
private class ResetNode extends LiteralNode {
private ResetNode() {
super("reset");
}
@Override
protected boolean execute(@NotNull CommandContext context) {
counter.reset(MinecraftServer.getServer());
context.getSender().sendMessage(join(spaces(),
text("Restarted counter", GRAY),
text(color.getName(), TextColor.color(color.getTextColor()))
));
return true;
}
}
private class RealtimeNode extends LiteralNode {
private RealtimeNode() {
super("realtime");
}
@Override
protected boolean execute(@NotNull CommandContext context) {
displayCounter(context.getSender(), true);
return true;
}
}
}
}

View File

@@ -0,0 +1,30 @@
package org.leavesmc.leaves.command.leaves.subcommands;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.leaves.LeavesSubcommand;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.format.NamedTextColor.GREEN;
public class ReloadCommand extends LeavesSubcommand {
public ReloadCommand() {
super("reload");
}
@Override
protected boolean execute(@NotNull CommandContext context) throws CommandSyntaxException {
LeavesConfig.reload();
CommandSender sender = context.getSender();
sender.sendMessage(text("Leaves config reload complete", GREEN));
Bukkit.getOnlinePlayers().stream()
.filter(player -> player.hasPermission("leaves.command.config.notify") && player != sender)
.forEach(player -> player.sendMessage(text("Leaves config reloaded", GREEN)));
return true;
}
}

View File

@@ -1,4 +1,4 @@
package org.leavesmc.leaves.command.subcommands;
package org.leavesmc.leaves.command.leaves.subcommands;
import io.papermc.paper.plugin.configuration.PluginMeta;
import io.papermc.paper.plugin.entrypoint.Entrypoint;
@@ -8,22 +8,18 @@ import io.papermc.paper.plugin.provider.type.paper.PaperPluginParent;
import io.papermc.paper.plugin.provider.type.spigot.SpigotPluginProvider;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.packs.repository.Pack;
import net.minecraft.server.packs.repository.PackRepository;
import net.minecraft.world.flag.FeatureFlagSet;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.command.LeavesCommandUtil;
import org.leavesmc.leaves.command.LeavesSubcommand;
import org.leavesmc.leaves.command.LeavesSuggestionBuilder;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.LiteralNode;
import org.leavesmc.leaves.command.leaves.LeavesSubcommand;
import org.leavesmc.leaves.plugin.provider.configuration.LeavesPluginMeta;
import java.net.URLEncoder;
@@ -33,17 +29,43 @@ import java.util.List;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
import static net.kyori.adventure.text.Component.join;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.JoinConfiguration.noSeparators;
import static net.kyori.adventure.text.JoinConfiguration.spaces;
import static net.kyori.adventure.text.format.NamedTextColor.AQUA;
import static net.kyori.adventure.text.format.NamedTextColor.RED;
import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
import static net.kyori.adventure.text.format.TextDecoration.UNDERLINED;
public class ReportCommand implements LeavesSubcommand {
public class ReportCommand extends LeavesSubcommand {
private static final String BASE_URL = "https://github.com/LeavesMC/Leaves/issues/new?template=";
private static final String BUG_REPORT_URL = BASE_URL + "1-bug-report.yml&leaves-version=${version}&plugin-list=${plugins}%0a%0a${datapacks}";
private static final String NOT_VANILLA_URL = BASE_URL + "2-not-vanilla.yml&leaves-version=${version}";
private static final String BUG_REPORT_URL = "https://github.com/LeavesMC/Leaves/issues/new?template=1-bug-report.yml&leaves-version=${version}&plugin-list=${plugins}%0a%0a${datapacks}";
private static final String NOT_VANILLA_URL = "https://github.com/LeavesMC/Leaves/issues/new?template=2-not-vanilla.yml&leaves-version=${version}";
private static final String COMMAND_PERM = "bukkit.command.leaves.report";
public ReportCommand() {
super("report");
children(
() -> new ReportTypeNode("bug-report", BUG_REPORT_URL),
() -> new ReportTypeNode("not-vanilla", NOT_VANILLA_URL)
);
}
private static String generatePluginMessage() {
private static class ReportTypeNode extends LiteralNode {
private final String url;
private ReportTypeNode(String type, String url) {
super(type);
this.url = url;
}
@Override
protected boolean execute(CommandContext context) {
CompletableFuture.runAsync(() -> sendOnSuccess(context.getSender(), url, name));
return true;
}
}
private static @NotNull String generatePluginMessage() {
final StringBuilder pluginList = new StringBuilder();
final TreeMap<String, PluginProvider<JavaPlugin>> paperPlugins = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
@@ -98,7 +120,7 @@ public class ReportCommand implements LeavesSubcommand {
return pluginList.toString();
}
private static String generateDataPackMessage() {
private static @NotNull String generateDataPackMessage() {
final StringBuilder dataPackList = new StringBuilder();
PackRepository packRepository = MinecraftServer.getServer().getPackRepository();
@@ -130,39 +152,30 @@ public class ReportCommand implements LeavesSubcommand {
return dataPackList.toString();
}
@Override
public void execute(CommandSender sender, String subCommand, String[] args) {
if (args.length < 1) {
sender.sendMessage(text("Please select a report template: \"bug-report\" or \"not-vanilla\"", RED));
return;
}
if (args[0].equals("bug-report")) {
CompletableFuture.runAsync(() -> sendOnSuccess(sender, BUG_REPORT_URL, Component.text("Successfully generated report url for \"bug-report\"", AQUA)));
return;
} else if (args[0].equals("not-vanilla")) {
CompletableFuture.runAsync(() -> sendOnSuccess(sender, NOT_VANILLA_URL, Component.text("Successfully generated report url for \"not-vanilla\"", AQUA)));
return;
}
sender.sendMessage(text("The template" + args[0] + " does not exist! Please select a correct template: \"bug-report\" or \"not-vanilla\"", RED));
}
@Override
public void suggest(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] args, @Nullable Location location, LeavesSuggestionBuilder builder) throws IllegalArgumentException {
if (args.length <= 1) {
LeavesCommandUtil.getListMatchingLast(sender, args, List.of("bug-report", "not-vanilla"), COMMAND_PERM + ".", COMMAND_PERM).forEach(builder::suggest);
}
}
private void sendOnSuccess(CommandSender sender, String template, Component component) {
private static void sendOnSuccess(@NotNull CommandSender sender, @NotNull String template, String type) {
String finalUrl = template
.replace("${version}", URLEncoder.encode(Bukkit.getVersionMessage(), StandardCharsets.UTF_8))
.replace("${plugins}", URLEncoder.encode(generatePluginMessage(), StandardCharsets.UTF_8))
.replace("${datapacks}", URLEncoder.encode(generateDataPackMessage(), StandardCharsets.UTF_8));
Component base = join(noSeparators(),
text("Successfully generated report url for ", GRAY),
text(type, AQUA),
text(",", GRAY)
);
if (sender instanceof ConsoleCommandSender) {
sender.sendMessage(component.append(text(", please copy it as you are running this command in console")));
sender.sendMessage(text(finalUrl, AQUA).decorate(TextDecoration.UNDERLINED));
sender.sendMessage(join(spaces(),
base,
text("please open it in your browser:", GRAY),
text(finalUrl, AQUA)
));
} else {
sender.sendMessage(component.append(text(", click this message to open")).decorate(TextDecoration.UNDERLINED).hoverEvent(Component.text("Click to open the report url", NamedTextColor.WHITE)).clickEvent(ClickEvent.openUrl(finalUrl)));
sender.sendMessage(join(spaces(),
base,
text("click here to continue", AQUA)
.decorate(UNDERLINED)
.hoverEvent(text("Open the report url"))
.clickEvent(ClickEvent.openUrl(finalUrl))
));
}
}
}

View File

@@ -0,0 +1,31 @@
package org.leavesmc.leaves.command.leaves.subcommands;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.command.CommandContext;
import org.leavesmc.leaves.command.leaves.LeavesSubcommand;
import org.leavesmc.leaves.util.LeavesUpdateHelper;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
public class UpdateCommand extends LeavesSubcommand {
public UpdateCommand() {
super("update");
}
@Override
protected boolean execute(@NotNull CommandContext context) throws CommandSyntaxException {
CommandSender sender = context.getSender();
if (sender instanceof ConsoleCommandSender) {
sender.sendMessage(text("Trying to update Leaves...", GRAY));
} else {
sender.sendMessage(text("Trying to update Leaves, see the console for more info", GRAY));
}
LeavesUpdateHelper.tryUpdateLeaves();
return true;
}
}

View File

@@ -1,33 +0,0 @@
package org.leavesmc.leaves.command.subcommands;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.JoinConfiguration;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.command.LeavesSubcommand;
public class BlockUpdateCommand implements LeavesSubcommand {
private static boolean noBlockUpdate = false;
public static boolean isNoBlockUpdate() {
return LeavesConfig.modify.noBlockUpdateCommand && noBlockUpdate;
}
@Override
public void execute(@NotNull CommandSender sender, @NotNull String commandLabel, String @NotNull [] args) {
noBlockUpdate = !noBlockUpdate;
Bukkit.broadcast(Component.join(JoinConfiguration.noSeparators(),
Component.text("Block update status: ", NamedTextColor.GRAY),
Component.text(!noBlockUpdate, noBlockUpdate ? NamedTextColor.AQUA : NamedTextColor.GRAY)
), "bukkit.command.leaves.blockupdate");
}
@Override
public boolean isEnabled() {
return LeavesConfig.modify.noBlockUpdateCommand;
}
}

View File

@@ -1,92 +0,0 @@
package org.leavesmc.leaves.command.subcommands;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.JoinConfiguration;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.command.LeavesCommandUtil;
import org.leavesmc.leaves.command.LeavesSubcommand;
import org.leavesmc.leaves.command.LeavesSuggestionBuilder;
import org.leavesmc.leaves.config.GlobalConfigManager;
import org.leavesmc.leaves.config.VerifiedConfig;
import static net.kyori.adventure.text.Component.text;
public class ConfigCommand implements LeavesSubcommand {
@Override
public void execute(CommandSender sender, String subCommand, String[] args) {
if (args.length < 1) {
sender.sendMessage(text("Leaves Config", NamedTextColor.GRAY));
return;
}
VerifiedConfig verifiedConfig = GlobalConfigManager.getVerifiedConfig(args[0]);
if (verifiedConfig == null) {
sender.sendMessage(Component.join(JoinConfiguration.spaces(),
text("Config", NamedTextColor.GRAY),
text(args[0], NamedTextColor.RED),
text("is Not Found.", NamedTextColor.GRAY)
));
return;
}
if (args.length > 1) {
try {
verifiedConfig.set(args[1]);
sender.sendMessage(Component.join(JoinConfiguration.spaces(),
text("Config", NamedTextColor.GRAY),
text(args[0], NamedTextColor.AQUA),
text("changed to", NamedTextColor.GRAY),
text(verifiedConfig.getString(), NamedTextColor.AQUA)
));
Bukkit.getOnlinePlayers().stream().filter(player -> player.hasPermission("leaves.command.config.notify") && player != sender).forEach(
player -> player.sendMessage(Component.join(JoinConfiguration.spaces(),
text(sender.getName() + ":", NamedTextColor.GRAY),
text("Config", NamedTextColor.GRAY),
text(args[0], NamedTextColor.AQUA),
text("changed to", NamedTextColor.GRAY),
text(verifiedConfig.getString(), NamedTextColor.AQUA)
))
);
} catch (IllegalArgumentException exception) {
sender.sendMessage(Component.join(JoinConfiguration.spaces(),
text("Config", NamedTextColor.GRAY),
text(args[0], NamedTextColor.RED),
text("modify error by", NamedTextColor.GRAY),
text(exception.getMessage(), NamedTextColor.RED)
));
}
} else {
sender.sendMessage(Component.join(JoinConfiguration.spaces(),
text("Config", NamedTextColor.GRAY),
text(args[0], NamedTextColor.AQUA),
text("value is", NamedTextColor.GRAY),
text(verifiedConfig.getString(), NamedTextColor.AQUA)
));
}
}
@Override
public void suggest(@NotNull CommandSender sender, @NotNull String subCommand, String @NotNull [] args, @Nullable Location location, @NotNull LeavesSuggestionBuilder builder) {
if (args.length <= 1) {
String arg = args[0];
int dotIndex = arg.lastIndexOf(".");
builder.createOffset(builder.getInput().lastIndexOf(' ') + dotIndex + 2);
LeavesCommandUtil.getListClosestMatchingLast(sender, arg.substring(dotIndex + 1), GlobalConfigManager.getVerifiedConfigSubPaths(arg), "bukkit.command.leaves.config")
.forEach(builder::suggest);
}
if (args.length == 2) {
VerifiedConfig verifiedConfig = GlobalConfigManager.getVerifiedConfig(args[0]);
if (verifiedConfig != null) {
LeavesCommandUtil.getListMatchingLast(sender, args, verifiedConfig.validator().valueSuggest()).forEach(builder::suggest);
} else {
builder.suggest("<ERROR CONFIG>");
}
}
}
}

View File

@@ -1,106 +0,0 @@
package org.leavesmc.leaves.command.subcommands;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.JoinConfiguration;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.DyeColor;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.command.LeavesCommandUtil;
import org.leavesmc.leaves.command.LeavesSubcommand;
import org.leavesmc.leaves.command.LeavesSuggestionBuilder;
import org.leavesmc.leaves.util.HopperCounter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class CounterCommand implements LeavesSubcommand {
@Override
public void execute(CommandSender sender, String subCommand, String[] args) {
if (args.length < 1) {
sender.sendMessage(Component.join(JoinConfiguration.noSeparators(),
Component.text("Hopper Counter: ", NamedTextColor.GRAY),
Component.text(HopperCounter.isEnabled(), HopperCounter.isEnabled() ? NamedTextColor.AQUA : NamedTextColor.GRAY)
));
}
if (!HopperCounter.isEnabled()) {
if (args[0].equals("enable")) {
HopperCounter.setEnabled(true);
sender.sendMessage(Component.text("Hopper Counter now is enabled", NamedTextColor.AQUA));
} else {
sender.sendMessage(Component.text("Hopper Counter is not enabled", NamedTextColor.RED));
}
}
DyeColor color = DyeColor.byName(args[0], null);
if (color != null) {
HopperCounter counter = HopperCounter.getCounter(color);
if (args.length < 2) {
displayCounter(sender, counter, false);
return;
}
switch (args[1]) {
case "reset" -> {
counter.reset(MinecraftServer.getServer());
sender.sendMessage(Component.join(JoinConfiguration.noSeparators(),
Component.text("Restarted "),
Component.text(color.getName(), TextColor.color(color.getTextColor())),
Component.text(" counter")
));
}
case "realtime" -> displayCounter(sender, counter, true);
}
}
switch (args[0]) {
case "reset" -> {
HopperCounter.resetAll(MinecraftServer.getServer(), false);
sender.sendMessage(Component.text("Restarted all counters"));
}
case "disable" -> {
HopperCounter.setEnabled(false);
HopperCounter.resetAll(MinecraftServer.getServer(), true);
sender.sendMessage(Component.text("Hopper Counter now is disabled", NamedTextColor.GRAY));
}
}
}
private void displayCounter(CommandSender sender, @NotNull HopperCounter counter, boolean realTime) {
for (Component component : counter.format(MinecraftServer.getServer(), realTime)) {
sender.sendMessage(component);
}
}
@Override
public void suggest(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] args, @Nullable Location location, LeavesSuggestionBuilder builder) throws IllegalArgumentException {
if (args.length <= 1) {
if (!HopperCounter.isEnabled()) {
builder.suggest("enable");
return;
}
List<String> list = new ArrayList<>(Arrays.stream(DyeColor.values()).map(DyeColor::getName).toList());
list.add("reset");
list.add("disable");
LeavesCommandUtil.getListMatchingLast(sender, args, list).forEach(builder::suggest);
}
if (args.length == 2) {
if (DyeColor.byName(args[0], null) != null) {
LeavesCommandUtil.getListMatchingLast(sender, args, "reset", "realtime").forEach(builder::suggest);
}
}
}
@Override
public boolean isEnabled() {
return LeavesConfig.modify.hopperCounter.enable;
}
}

View File

@@ -1,20 +0,0 @@
package org.leavesmc.leaves.command.subcommands;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.leavesmc.leaves.LeavesConfig;
import org.leavesmc.leaves.command.LeavesSubcommand;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.format.NamedTextColor.GREEN;
public class ReloadCommand implements LeavesSubcommand {
@Override
public void execute(CommandSender sender, String subCommand, String[] args) {
LeavesConfig.reload();
sender.sendMessage(text("Leaves config reload complete.", GREEN));
Bukkit.getOnlinePlayers().stream().filter(player -> player.hasPermission("leaves.command.config.notify") && player != sender).forEach(
player -> player.sendMessage(text("Leaves config reload complete.", GREEN))
);
}
}

View File

@@ -1,16 +0,0 @@
package org.leavesmc.leaves.command.subcommands;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.command.CommandSender;
import org.leavesmc.leaves.command.LeavesSubcommand;
import org.leavesmc.leaves.util.LeavesUpdateHelper;
public class UpdateCommand implements LeavesSubcommand {
@Override
public void execute(CommandSender sender, String subCommand, String[] args) {
sender.sendMessage(Component.text("Trying to update Leaves, see the console for more info.", NamedTextColor.GRAY));
LeavesUpdateHelper.tryUpdateLeaves();
}
}