From f33f5feac70b00f97acf108a57367276be03219e Mon Sep 17 00:00:00 2001 From: Lumine1909 <133463833+Lumine1909@users.noreply.github.com> Date: Tue, 24 Jun 2025 13:52:35 -0700 Subject: [PATCH] Refactor command system, fix bugs (#573) --- .../features/0032-Renewable-Elytra.patch | 4 +- .../features/0050-Creative-fly-no-clip.patch | 9 +- .../0055-No-block-update-command.patch | 166 +++++++------- .../features/0072-Bow-infinity-fix.patch | 4 +- .../features/0075-Replay-Mod-API.patch | 6 +- .../features/0091-Servux-Protocol.patch | 4 +- ...ked-hopper-no-longer-send-NC-updates.patch | 4 +- .../0126-Spawn-invulnerable-time.patch | 40 +--- ...003-Leaves-Server-Config-And-Command.patch | 11 +- .../org/leavesmc/leaves/LeavesConfig.java | 17 +- .../org/leavesmc/leaves/bot/BotCommand.java | 111 +-------- .../leaves/bot/ServerBotGameMode.java | 2 +- .../leavesmc/leaves/bot/agent/Actions.java | 18 +- .../leavesmc/leaves/bot/agent/Configs.java | 6 +- .../bot/subcommands/BotActionCommand.java | 212 ++++++++---------- .../bot/subcommands/BotConfigCommand.java | 91 +++----- .../bot/subcommands/BotCreateCommand.java | 26 +-- .../bot/subcommands/BotListCommand.java | 36 ++- .../bot/subcommands/BotLoadCommand.java | 33 +-- .../bot/subcommands/BotRemoveCommand.java | 38 ++-- .../bot/subcommands/BotSaveCommand.java | 33 +-- .../leaves/command/LeavesCommand.java | 129 +---------- .../leaves/command/LeavesCommandUtil.java | 16 +- .../leaves/command/LeavesRootCommand.java | 126 +++++++++++ .../leaves/command/LeavesSubcommand.java | 25 +-- .../command/LeavesSuggestionBuilder.java | 49 ++++ .../command/LeavesSuggestionCommand.java | 14 +- .../leaves/command/NoBlockUpdateCommand.java | 53 ----- .../subcommands/BlockUpdateCommand.java | 33 +++ .../command/subcommands/ConfigCommand.java | 42 ++-- .../command/subcommands/CounterCommand.java | 74 +++--- .../PeacefulModeSwitchCommand.java | 28 +-- .../command/subcommands/ReloadCommand.java | 3 +- .../command/subcommands/ReportCommand.java | 84 ++++--- .../command/subcommands/UpdateCommand.java | 8 +- 35 files changed, 649 insertions(+), 906 deletions(-) create mode 100644 leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesRootCommand.java create mode 100644 leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesSuggestionBuilder.java delete mode 100644 leaves-server/src/main/java/org/leavesmc/leaves/command/NoBlockUpdateCommand.java create mode 100644 leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/BlockUpdateCommand.java diff --git a/leaves-server/minecraft-patches/features/0032-Renewable-Elytra.patch b/leaves-server/minecraft-patches/features/0032-Renewable-Elytra.patch index e4540336..5e528c3d 100644 --- a/leaves-server/minecraft-patches/features/0032-Renewable-Elytra.patch +++ b/leaves-server/minecraft-patches/features/0032-Renewable-Elytra.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Renewable Elytra This patch is Powered by Carpet-TIS-Addition(https://github.com/plusls/Carpet-TIS-Addition) diff --git a/net/minecraft/world/entity/monster/Phantom.java b/net/minecraft/world/entity/monster/Phantom.java -index 483b0499f1f70b3aa8862e6cd8e512748492bee0..896c6fe4ee76708f09022934056cd9de74c5e851 100644 +index 483b0499f1f70b3aa8862e6cd8e512748492bee0..5467a1b28525386dfae2a04d8c69d23f163c74f5 100644 --- a/net/minecraft/world/entity/monster/Phantom.java +++ b/net/minecraft/world/entity/monster/Phantom.java @@ -231,6 +231,20 @@ public class Phantom extends FlyingMob implements Enemy { @@ -20,7 +20,7 @@ index 483b0499f1f70b3aa8862e6cd8e512748492bee0..896c6fe4ee76708f09022934056cd9de + if (org.leavesmc.leaves.LeavesConfig.modify.renewableElytra > 0.0D) { + if (source.getEntity() instanceof Shulker && this.random.nextDouble() < org.leavesmc.leaves.LeavesConfig.modify.renewableElytra) { + net.minecraft.world.item.ItemStack item = new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.ELYTRA); -+ item.setDamageValue(432); ++ item.setDamageValue(431); + this.spawnAtLocation(level, item); + } + } diff --git a/leaves-server/minecraft-patches/features/0050-Creative-fly-no-clip.patch b/leaves-server/minecraft-patches/features/0050-Creative-fly-no-clip.patch index e5ff38d0..c80e36b4 100644 --- a/leaves-server/minecraft-patches/features/0050-Creative-fly-no-clip.patch +++ b/leaves-server/minecraft-patches/features/0050-Creative-fly-no-clip.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Creative fly no clip diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java -index 2fe76bc1c26423ed5e39453ac1b27a2cc66b1f2e..3eb9a9f6d7f8d28d527941177a5faf2c97628594 100644 +index 2fe76bc1c26423ed5e39453ac1b27a2cc66b1f2e..f6e963d75fdcd951e5f5624f7d69cbbf6b8b480f 100644 --- a/net/minecraft/world/entity/player/Player.java +++ b/net/minecraft/world/entity/player/Player.java @@ -277,8 +277,8 @@ public abstract class Player extends LivingEntity { @@ -37,7 +37,7 @@ index 2fe76bc1c26423ed5e39453ac1b27a2cc66b1f2e..3eb9a9f6d7f8d28d527941177a5faf2c AABB aabb; if (this.isPassenger() && !this.getVehicle().isRemoved()) { aabb = this.getBoundingBox().minmax(this.getVehicle().getBoundingBox()).inflate(1.0, 0.0, 1.0); -@@ -1931,6 +1931,21 @@ public abstract class Player extends LivingEntity { +@@ -1931,6 +1931,26 @@ public abstract class Player extends LivingEntity { return this.gameMode() == GameType.SPECTATOR; } @@ -54,6 +54,11 @@ index 2fe76bc1c26423ed5e39453ac1b27a2cc66b1f2e..3eb9a9f6d7f8d28d527941177a5faf2c + return world.isUnobstructed(state, pos, context); + } + } ++ ++ @Override ++ public boolean isCollidable(boolean ignoreClimbing) { ++ return !isCreativeFlyOrSpectator() && super.isCollidable(ignoreClimbing); ++ } + // Leaves end - creative no clip + @Override diff --git a/leaves-server/minecraft-patches/features/0055-No-block-update-command.patch b/leaves-server/minecraft-patches/features/0055-No-block-update-command.patch index f6081e5b..a96f937e 100644 --- a/leaves-server/minecraft-patches/features/0055-No-block-update-command.patch +++ b/leaves-server/minecraft-patches/features/0055-No-block-update-command.patch @@ -4,90 +4,94 @@ Date: Mon, 3 Feb 2025 19:16:16 +0800 Subject: [PATCH] No block update command -diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index b8a9b2f5671537cf0a805dc2c98945094bd7b8b1..a2199f7aac4f44a70087dd90fe9330fcb8970772 100644 ---- a/net/minecraft/server/level/ServerLevel.java -+++ b/net/minecraft/server/level/ServerLevel.java -@@ -1789,6 +1789,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java +index 5e54d6de0430cd137fbe13ca8f17dc487ce52ff3..a68ca4ccec97b9fc6f9a6ae698722842cb6bf42d 100644 +--- a/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -381,7 +381,7 @@ public class ServerPlayerGameMode { + org.bukkit.block.BlockState state = bblock.getState(); + 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 + 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 7c13e7b7a547150642c4a4bddf5e8dee1d580984..ac4996dda7bcf5f20391f45e3f703b21557a1669 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, AutoCl @Override - public void updateNeighborsAt(BlockPos pos, Block block, @Nullable Orientation orientation) { -+ if (org.leavesmc.leaves.command.NoBlockUpdateCommand.isNoBlockUpdate()) return; // Leaves - no block update - if (captureBlockStates) { return; } // Paper - Cancel all physics during placement - this.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, block, null, orientation); - } -diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java -index 649d17dcd7856e3b1344192d8ea4b2e9f73fc03b..93b7c607e0f527a910fc15c88c9a0a9ede26f23d 100644 ---- a/net/minecraft/world/item/ItemStack.java -+++ b/net/minecraft/world/item/ItemStack.java -@@ -482,7 +482,7 @@ public final class ItemStack implements DataComponentHolder { - net.minecraft.world.level.block.state.BlockState block = serverLevel.getBlockState(newPos); + public boolean setBlock(BlockPos pos, BlockState state, int flags, int recursionLeft) { ++ // Leaves start - no block update ++ if (org.leavesmc.leaves.command.subcommands.BlockUpdateCommand.isNoBlockUpdate()) { ++ flags = flags & ~1 | net.minecraft.world.level.block.Block.UPDATE_SKIP_ON_PLACE; ++ } ++ // Leaves end - no block update + // CraftBukkit start - tree generation + if (this.captureTreeGeneration) { + // Paper start - Protect Bedrock and End Portal/Frames from being destroyed +@@ -1190,6 +1195,11 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl + BlockState state = newState; + BlockState blockState = oldState; + BlockState blockState1 = currentState; ++ // Leaves start - no block update ++ if (org.leavesmc.leaves.command.subcommands.BlockUpdateCommand.isNoBlockUpdate()) { ++ flags = flags & ~1 | net.minecraft.world.level.block.Block.UPDATE_SKIP_ON_PLACE; ++ } ++ // Leaves end - no block update + if (blockState1 == state) { + if (blockState != blockState1) { + this.setBlocksDirty(pos, blockState, blockState1); +@@ -1208,7 +1218,12 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl - if (!(block.getBlock() instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // Containers get placed automatically -- block.onPlace(serverLevel, newPos, oldBlock, true, context); -+ if (!org.leavesmc.leaves.command.NoBlockUpdateCommand.isNoBlockUpdate()) block.onPlace(serverLevel, newPos, oldBlock, true, context); // Leaves - no block update - } - - serverLevel.notifyAndUpdatePhysics(newPos, null, oldBlock, block, serverLevel.getBlockState(newPos), updateFlags, net.minecraft.world.level.block.Block.UPDATE_LIMIT); // send null chunk as chunk.k() returns false by this point -diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index 845319dd3e355f739cce70b7df3172dd146601b1..7fca1659bd85b1a737355fb9a8377dff64a7fe17 100644 ---- a/net/minecraft/world/level/chunk/LevelChunk.java -+++ b/net/minecraft/world/level/chunk/LevelChunk.java -@@ -413,7 +413,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p - return null; - } else { - if (!this.level.isClientSide && (flags & 512) == 0 && (!this.level.captureBlockStates || block instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled. -- state.onPlace(this.level, pos, blockState, flag1); -+ if (!org.leavesmc.leaves.command.NoBlockUpdateCommand.isNoBlockUpdate()) state.onPlace(this.level, pos, blockState, flag1); // Leaves - no block update - } - - if (state.hasBlockEntity()) { -diff --git a/net/minecraft/world/level/material/FlowingFluid.java b/net/minecraft/world/level/material/FlowingFluid.java -index ace1099a12c762b2e73b71dd3551cf351fedf067..0ccc884066b0a217c7b833c33d3fe96dd7ad0a0b 100644 ---- a/net/minecraft/world/level/material/FlowingFluid.java -+++ b/net/minecraft/world/level/material/FlowingFluid.java -@@ -476,6 +476,7 @@ public abstract class FlowingFluid extends Fluid { - - @Override - public void tick(ServerLevel level, BlockPos pos, BlockState blockState, FluidState fluidState) { -+ if (org.leavesmc.leaves.command.NoBlockUpdateCommand.isNoBlockUpdate()) return; // Leaves - no block update - if (!fluidState.isSource()) { - FluidState newLiquid = this.getNewLiquid(level, pos, level.getBlockState(pos)); - int spreadDelay = this.getSpreadDelay(level, pos, fluidState, newLiquid); -diff --git a/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java -index 028eae2f9a459b60e92f3344091083aa93b54485..63684402f7c89c7c5d71902db4bfb23132b1d28d 100644 ---- a/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java -+++ b/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java -@@ -47,6 +47,7 @@ public class CollectingNeighborUpdater implements NeighborUpdater { + if ((flags & 16) == 0 && recursionLeft > 0) { + int i = flags & -34; +- ++ // Leaves start - no block update ++ if (org.leavesmc.leaves.command.subcommands.BlockUpdateCommand.isNoBlockUpdate()) { ++ this.updatePOIOnBlockStateChange(pos, blockState, blockState1); ++ return; ++ } ++ // Leaves end - no block update + // CraftBukkit start + 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 +--- 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 addAndRun(BlockPos pos, CollectingNeighborUpdater.NeighborUpdates updates) { -+ if (org.leavesmc.leaves.command.NoBlockUpdateCommand.isNoBlockUpdate()) return; // Leaves - no block update - boolean flag = this.count > 0; - boolean flag1 = this.maxChainedNeighborUpdates >= 0 && this.count >= this.maxChainedNeighborUpdates; - this.count++; -diff --git a/net/minecraft/world/level/redstone/InstantNeighborUpdater.java b/net/minecraft/world/level/redstone/InstantNeighborUpdater.java -index d0da64e325f83ab073221a3fa7284e42b6a88534..32e10dccde3e80969641ba1fb67479b5a0bada06 100644 ---- a/net/minecraft/world/level/redstone/InstantNeighborUpdater.java -+++ b/net/minecraft/world/level/redstone/InstantNeighborUpdater.java -@@ -16,17 +16,20 @@ public class InstantNeighborUpdater implements NeighborUpdater { + private void checkIfExtend(Level level, BlockPos pos, BlockState state) { ++ if (org.leavesmc.leaves.command.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 +--- a/net/minecraft/world/level/redstone/NeighborUpdater.java ++++ b/net/minecraft/world/level/redstone/NeighborUpdater.java +@@ -34,6 +34,11 @@ public interface NeighborUpdater { + static void executeShapeUpdate( + 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()) { ++ flags = flags & ~1 | net.minecraft.world.level.block.Block.UPDATE_SKIP_ON_PLACE; ++ } ++ // Leaves end - no block update + BlockState blockState = level.getBlockState(pos); + if ((flags & 128) == 0 || !blockState.is(Blocks.REDSTONE_WIRE)) { + BlockState blockState1 = blockState.updateShape(level, level, pos, direction, neighborPos, neighborState, level.getRandom()); +@@ -48,6 +53,7 @@ public interface NeighborUpdater { - @Override - public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLevel) { -+ if (org.leavesmc.leaves.command.NoBlockUpdateCommand.isNoBlockUpdate()) return; // Leaves - no block update - NeighborUpdater.executeShapeUpdate(this.level, direction, pos, neighborPos, state, flags, recursionLevel - 1); - } - - @Override - public void neighborChanged(BlockPos pos, Block neighborBlock, @Nullable Orientation orientation) { -+ if (org.leavesmc.leaves.command.NoBlockUpdateCommand.isNoBlockUpdate()) return; // Leaves - no block update - BlockState blockState = this.level.getBlockState(pos); - this.neighborChanged(blockState, pos, neighborBlock, orientation, false); - } - - @Override - public void neighborChanged(BlockState state, BlockPos pos, Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) { -+ if (org.leavesmc.leaves.command.NoBlockUpdateCommand.isNoBlockUpdate()) return; // Leaves - no block update - NeighborUpdater.executeUpdate(this.level, state, pos, neighborBlock, orientation, movedByPiston); - } - } + 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 + 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 diff --git a/leaves-server/minecraft-patches/features/0072-Bow-infinity-fix.patch b/leaves-server/minecraft-patches/features/0072-Bow-infinity-fix.patch index f03e48a0..f87c49c9 100644 --- a/leaves-server/minecraft-patches/features/0072-Bow-infinity-fix.patch +++ b/leaves-server/minecraft-patches/features/0072-Bow-infinity-fix.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Bow infinity fix diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java -index a00e1ccb915e9e33b0c56b228cb0447d8af1e195..7d606ed45d88bc269943c013b4793583bacb1c83 100644 +index ee8c0d0edbb296106a128c48f4186ba3a5bf9df8..0f1a398c588b7e0832612a50734b7db8b3a48ccc 100644 --- a/net/minecraft/world/entity/player/Player.java +++ b/net/minecraft/world/entity/player/Player.java -@@ -2165,7 +2165,7 @@ public abstract class Player extends LivingEntity { +@@ -2170,7 +2170,7 @@ public abstract class Player extends LivingEntity { } if (anyEventCancelled.booleanValue() && !this.abilities.instabuild && this instanceof final ServerPlayer player) this.resyncUsingItem(player); // Paper - resync if no item matched the Predicate diff --git a/leaves-server/minecraft-patches/features/0075-Replay-Mod-API.patch b/leaves-server/minecraft-patches/features/0075-Replay-Mod-API.patch index ee42985f..26704277 100644 --- a/leaves-server/minecraft-patches/features/0075-Replay-Mod-API.patch +++ b/leaves-server/minecraft-patches/features/0075-Replay-Mod-API.patch @@ -120,10 +120,10 @@ index 814bb2981ab32b216b7953e9b14fe09e96cc7c89..45f884bf598b38ec45baf423b84f5293 .filter(player -> !playerList.isOp(player.getGameProfile())) .map(player -> player.getGameProfile().getName()), diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 5fd09fe2c544d197035f4500a0672f73b1da2501..27729923db521bc5b875badb1ee3fe75d5c16fdd 100644 +index 68490d8dc26c2d5f4999361fd7ad72a83581f48f..122e5e46a2c1e4be5c9d04501bfe064f239ec230 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -2646,7 +2646,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2645,7 +2645,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe if (entity instanceof ServerPlayer serverPlayer) { ServerLevel.this.players.add(serverPlayer); // Leaves start - skip @@ -132,7 +132,7 @@ index 5fd09fe2c544d197035f4500a0672f73b1da2501..27729923db521bc5b875badb1ee3fe75 ServerLevel.this.realPlayers.add(serverPlayer); } // Leaves end - skip -@@ -2721,7 +2721,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2720,7 +2720,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe if (entity instanceof ServerPlayer serverPlayer) { ServerLevel.this.players.remove(serverPlayer); // Leaves start - skip diff --git a/leaves-server/minecraft-patches/features/0091-Servux-Protocol.patch b/leaves-server/minecraft-patches/features/0091-Servux-Protocol.patch index dcf7ba15..c72e649e 100644 --- a/leaves-server/minecraft-patches/features/0091-Servux-Protocol.patch +++ b/leaves-server/minecraft-patches/features/0091-Servux-Protocol.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Servux Protocol diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 9b1a65036392a965dc0ce93247dfc0cf53630034..c4113e01a8624397e78a18834bdcd857bf953bbe 100644 +index 122e5e46a2c1e4be5c9d04501bfe064f239ec230..cda2a31196b43abe2e32a3d755b42f043c97f5de 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -2207,6 +2207,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2206,6 +2206,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } this.lastSpawnChunkRadius = i; diff --git a/leaves-server/minecraft-patches/features/0092-Placing-locked-hopper-no-longer-send-NC-updates.patch b/leaves-server/minecraft-patches/features/0092-Placing-locked-hopper-no-longer-send-NC-updates.patch index 45d19e67..5f577958 100644 --- a/leaves-server/minecraft-patches/features/0092-Placing-locked-hopper-no-longer-send-NC-updates.patch +++ b/leaves-server/minecraft-patches/features/0092-Placing-locked-hopper-no-longer-send-NC-updates.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Placing locked hopper no longer send NC updates diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 7c13e7b7a547150642c4a4bddf5e8dee1d580984..148d92e12c238b81087f68756da7d17da435d3ea 100644 +index ac4996dda7bcf5f20391f45e3f703b21557a1669..31f52bef093849dc15add696bb7bcfb5f326589a 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java -@@ -1200,7 +1200,11 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl +@@ -1210,7 +1210,11 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl } if ((flags & 1) != 0) { diff --git a/leaves-server/minecraft-patches/features/0126-Spawn-invulnerable-time.patch b/leaves-server/minecraft-patches/features/0126-Spawn-invulnerable-time.patch index 2cc8560e..c671adfd 100644 --- a/leaves-server/minecraft-patches/features/0126-Spawn-invulnerable-time.patch +++ b/leaves-server/minecraft-patches/features/0126-Spawn-invulnerable-time.patch @@ -5,36 +5,14 @@ Subject: [PATCH] Spawn invulnerable time diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index d4984c919a88fa930dfec823cd9b471fa47f3565..6f845730bb0a9dcd1b26e68171e80edc669b6430 100644 +index d4984c919a88fa930dfec823cd9b471fa47f3565..8a622da26cff56f404b7d8b6131c27c65a31cdfe 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -221,6 +221,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc - private int lastSentFood = -99999999; - private boolean lastFoodSaturationZero = true; - public int lastSentExp = -99999999; -+ private int spawnInvulnerableTime = 60; // Leaves - spawn invulnerable time - private ChatVisiblity chatVisibility = ChatVisiblity.FULL; - public ParticleStatus particleStatus = ParticleStatus.ALL; - private boolean canChatColor = true; -@@ -751,6 +752,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc - this.resetOperationCountPerTick(); // Leaves - player operation limiter - this.gameMode.tick(); - this.wardenSpawnTracker.tick(); -+ if (org.leavesmc.leaves.LeavesConfig.modify.oldMC.spawnInvulnerableTime && this.invulnerableTime > 0) --this.spawnInvulnerableTime; // Leaves - spawn invulnerable time - if (this.invulnerableTime > 0) { - this.invulnerableTime--; - } -@@ -1185,6 +1187,13 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc - if (this.isInvulnerableTo(level, damageSource)) { - return false; - } else { -+ // Leaves start - spawn invulnerable time -+ if (org.leavesmc.leaves.LeavesConfig.modify.oldMC.spawnInvulnerableTime) { -+ if (this.spawnInvulnerableTime > 0 && !damageSource.is(net.minecraft.tags.DamageTypeTags.BYPASSES_INVULNERABILITY)) { -+ return false; -+ } -+ } -+ // Leaves end - spawn invulnerable time - Entity entity = damageSource.getEntity(); - if (!( // Paper - split the if statement. If below statement is false, hurtServer would not have been evaluated. Return false. - !(entity instanceof Player player && !this.canHarmPlayer(player)) +@@ -474,6 +474,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc + this.adventure$displayName = org.leavesmc.leaves.LeavesConfig.fix.vanillaDisplayName ? io.papermc.paper.adventure.PaperAdventure.asAdventure(this.getDisplayName()) : net.kyori.adventure.text.Component.text(this.getScoreboardName()); // Paper // Leaves - Vanilla display name + this.bukkitPickUpLoot = true; + this.maxHealthCache = this.getMaxHealth(); ++ if (org.leavesmc.leaves.LeavesConfig.modify.oldMC.spawnInvulnerableTime) this.invulnerableTime = 60; // Leaves - spawn invulnerable time + } + + @Override diff --git a/leaves-server/paper-patches/features/0003-Leaves-Server-Config-And-Command.patch b/leaves-server/paper-patches/features/0003-Leaves-Server-Config-And-Command.patch index dd8e365d..fb55af82 100644 --- a/leaves-server/paper-patches/features/0003-Leaves-Server-Config-And-Command.patch +++ b/leaves-server/paper-patches/features/0003-Leaves-Server-Config-And-Command.patch @@ -18,19 +18,18 @@ index 62e2d5704c348955bc8284dc2d54c933b7bcdd06..7ef20f0138fad39a1d23edd7b26ddc88 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..e227cb58989c32a2e1dff1b731efe771db33b26e 100644 +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,14 @@ public class BukkitCommandNode extends LiteralCommandNode { +@@ -106,6 +106,13 @@ public class BukkitCommandNode extends LiteralCommandNode { List results = null; Location pos = context.getSource().getLocation(); try { + // Leaves start - custom suggestion + if (this.command instanceof org.leavesmc.leaves.command.LeavesSuggestionCommand suggestionCommand) { -+ CompletableFuture suggestions = suggestionCommand.tabSuggestion(sender, this.literal, args, pos.clone(), builder); -+ if (suggestions != null) { -+ return suggestions; -+ } ++ 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()); diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/LeavesConfig.java b/leaves-server/src/main/java/org/leavesmc/leaves/LeavesConfig.java index 99fd4ee4..56785a3c 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/LeavesConfig.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/LeavesConfig.java @@ -81,7 +81,7 @@ public final class LeavesConfig { GlobalConfigManager.init(); - registerCommand("leaves", new LeavesCommand("leaves")); + registerCommand("leaves", new LeavesCommand()); } public static void reload() { @@ -138,7 +138,7 @@ public final class LeavesConfig { @Override public void verify(Boolean old, Boolean value) throws IllegalArgumentException { if (value) { - registerCommand("bot", new org.leavesmc.leaves.bot.BotCommand("bot")); + registerCommand("bot", new org.leavesmc.leaves.bot.BotCommand()); org.leavesmc.leaves.bot.agent.Actions.registerAll(); } else { unregisterCommand("bot"); @@ -523,20 +523,9 @@ public final class LeavesConfig { } } - @GlobalConfig(value = "no-block-update-command", validator = NoBlockUpdateValidator.class) + @GlobalConfig(value = "no-block-update-command") public boolean noBlockUpdateCommand = false; - private static class NoBlockUpdateValidator extends BooleanConfigValidator { - @Override - public void verify(Boolean old, Boolean value) throws IllegalArgumentException { - if (value) { - registerCommand("blockupdate", new org.leavesmc.leaves.command.NoBlockUpdateCommand("blockupdate")); - } else { - unregisterCommand("blockupdate"); - } - } - } - @GlobalConfig("no-tnt-place-update") public boolean noTNTPlaceUpdate = false; diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/BotCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/BotCommand.java index 55b517d8..bf58ff5d 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/bot/BotCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/BotCommand.java @@ -1,20 +1,6 @@ package org.leavesmc.leaves.bot; -import com.mojang.brigadier.suggestion.Suggestions; -import com.mojang.brigadier.suggestion.SuggestionsBuilder; -import it.unimi.dsi.fastutil.Pair; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; import net.minecraft.Util; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.permissions.Permission; -import org.bukkit.permissions.PermissionDefault; -import org.bukkit.plugin.PluginManager; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.leavesmc.leaves.LeavesConfig; import org.leavesmc.leaves.bot.subcommands.BotActionCommand; import org.leavesmc.leaves.bot.subcommands.BotConfigCommand; @@ -23,37 +9,15 @@ import org.leavesmc.leaves.bot.subcommands.BotListCommand; import org.leavesmc.leaves.bot.subcommands.BotLoadCommand; import org.leavesmc.leaves.bot.subcommands.BotRemoveCommand; import org.leavesmc.leaves.bot.subcommands.BotSaveCommand; -import org.leavesmc.leaves.command.LeavesCommandUtil; +import org.leavesmc.leaves.command.LeavesRootCommand; import org.leavesmc.leaves.command.LeavesSubcommand; -import org.leavesmc.leaves.command.LeavesSuggestionCommand; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; import java.util.HashMap; -import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; -import static net.kyori.adventure.text.Component.text; - -//TODO rewrite -public class BotCommand extends Command implements LeavesSuggestionCommand { - - public BotCommand(String name) { - super(name); - this.description = "FakePlayer Command"; - this.usageMessage = "/bot [" + String.join(" | ", usableSubcommands()) + "]"; - this.setPermission("bukkit.command.bot"); - final PluginManager pluginManager = Bukkit.getServer().getPluginManager(); - if (pluginManager.getPermission("bukkit.command.bot") == null) { - pluginManager.addPermission(new Permission("bukkit.command.bot", PermissionDefault.OP)); - } - } +public class BotCommand extends LeavesRootCommand { // subcommand label -> subcommand private static final Map SUBCOMMANDS = Util.make(() -> { @@ -71,75 +35,12 @@ public class BotCommand extends Command implements LeavesSuggestionCommand { .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); }); - @NotNull - @Override - public List tabComplete(final @NotNull CommandSender sender, final @NotNull String alias, final String[] args, final @Nullable Location location) throws IllegalArgumentException { - if (args.length <= 1) { - return LeavesCommandUtil.getListMatchingLast(sender, args, usableSubcommands(), "bukkit.command.bot.", "bukkit.command.bot"); - } - - final @Nullable Pair subCommand = resolveCommand(args[0]); - if (subCommand != null) { - var list = subCommand.second().tabComplete(sender, subCommand.first(), Arrays.copyOfRange(args, 1, args.length), location); - return LeavesCommandUtil.getListMatchingLast(sender, args, list, "bukkit.command.bot.", "bukkit.command.bot"); - } - - return Collections.emptyList(); + public BotCommand() { + super("bot", "FakePlayer Command", "bukkit.command.bot", SUBCOMMANDS); } @Override - public @Nullable CompletableFuture tabSuggestion(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] args, @Nullable Location location, @NotNull SuggestionsBuilder builder) throws IllegalArgumentException { - if (args.length > 1) { - final @Nullable Pair subCommand = resolveCommand(args[0]); - if (subCommand != null) { - return subCommand.second().tabSuggestion(sender, subCommand.first(), Arrays.copyOfRange(args, 1, args.length), location, builder); - } - } - return null; - } - - @Override - public boolean execute(final @NotNull CommandSender sender, final @NotNull String commandLabel, final String @NotNull [] args) { - if (!testPermission(sender) || !LeavesConfig.modify.fakeplayer.enable) return true; - - if (args.length == 0) { - sender.sendMessage(unknownMessage()); - return false; - } - final Pair subCommand = resolveCommand(args[0]); - - if (subCommand == null) { - sender.sendMessage(unknownMessage()); - return false; - } - - final String[] choppedArgs = Arrays.copyOfRange(args, 1, args.length); - return subCommand.second().execute(sender, subCommand.first(), choppedArgs); - } - - @Nullable - private static Pair resolveCommand(String label) { - label = label.toLowerCase(Locale.ENGLISH); - LeavesSubcommand subCommand = SUBCOMMANDS.get(label); - - if (subCommand != null) { - return Pair.of(label, subCommand); - } - - return null; - } - - public Collection usableSubcommands() { - List subcommands = new ArrayList<>(); - for (var entry : SUBCOMMANDS.entrySet()) { - if (entry.getValue().tabCompletes()) { - subcommands.add(entry.getKey()); - } - } - return subcommands; - } - - public Component unknownMessage() { - return text("Usage: /bot [" + String.join(" | ", usableSubcommands()) + "]", NamedTextColor.RED); + public boolean isEnabled() { + return LeavesConfig.modify.fakeplayer.enable; } } \ No newline at end of file diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/ServerBotGameMode.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/ServerBotGameMode.java index fc9e957e..e1a12931 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/bot/ServerBotGameMode.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/ServerBotGameMode.java @@ -60,7 +60,7 @@ public class ServerBotGameMode extends ServerPlayerGameMode { return false; } else { this.level.captureDrops = null; - BlockState iblockdata1 = block.playerWillDestroy(this.level, pos, iblockdata, this.player); + BlockState iblockdata1 = org.leavesmc.leaves.command.subcommands.BlockUpdateCommand.isNoBlockUpdate() ? iblockdata : block.playerWillDestroy(this.level, pos, iblockdata, this.player); // Leaves - no block update boolean flag = this.level.removeBlock(pos, false); if (flag) { diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/Actions.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/Actions.java index 7651b61d..b7c53402 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/Actions.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/Actions.java @@ -3,7 +3,23 @@ package org.leavesmc.leaves.bot.agent; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.leavesmc.leaves.bot.agent.actions.*; +import org.leavesmc.leaves.bot.agent.actions.AttackAction; +import org.leavesmc.leaves.bot.agent.actions.BreakBlockAction; +import org.leavesmc.leaves.bot.agent.actions.DropAction; +import org.leavesmc.leaves.bot.agent.actions.FishAction; +import org.leavesmc.leaves.bot.agent.actions.JumpAction; +import org.leavesmc.leaves.bot.agent.actions.LookAction; +import org.leavesmc.leaves.bot.agent.actions.RotateAction; +import org.leavesmc.leaves.bot.agent.actions.RotationAction; +import org.leavesmc.leaves.bot.agent.actions.ShootAction; +import org.leavesmc.leaves.bot.agent.actions.SneakAction; +import org.leavesmc.leaves.bot.agent.actions.SwimAction; +import org.leavesmc.leaves.bot.agent.actions.UseItemAction; +import org.leavesmc.leaves.bot.agent.actions.UseItemOffHandAction; +import org.leavesmc.leaves.bot.agent.actions.UseItemOnAction; +import org.leavesmc.leaves.bot.agent.actions.UseItemOnOffhandAction; +import org.leavesmc.leaves.bot.agent.actions.UseItemToAction; +import org.leavesmc.leaves.bot.agent.actions.UseItemToOffhandAction; import java.util.Collection; import java.util.HashMap; diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/Configs.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/Configs.java index 8418ae91..b602e9e3 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/Configs.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/Configs.java @@ -4,7 +4,11 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.leavesmc.leaves.bot.ServerBot; -import org.leavesmc.leaves.bot.agent.configs.*; +import org.leavesmc.leaves.bot.agent.configs.AlwaysSendDataConfig; +import org.leavesmc.leaves.bot.agent.configs.SimulationDistanceConfig; +import org.leavesmc.leaves.bot.agent.configs.SkipSleepConfig; +import org.leavesmc.leaves.bot.agent.configs.SpawnPhantomConfig; +import org.leavesmc.leaves.bot.agent.configs.TickTypeConfig; import java.util.Collection; import java.util.HashMap; diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotActionCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotActionCommand.java index af98d824..29d13645 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotActionCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotActionCommand.java @@ -1,13 +1,12 @@ package org.leavesmc.leaves.bot.subcommands; -import com.mojang.brigadier.suggestion.Suggestions; -import com.mojang.brigadier.suggestion.SuggestionsBuilder; import net.kyori.adventure.text.format.NamedTextColor; import net.minecraft.network.chat.Component; import org.apache.commons.lang3.tuple.Pair; import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.LeavesConfig; import org.leavesmc.leaves.bot.BotList; import org.leavesmc.leaves.bot.ServerBot; @@ -15,94 +14,49 @@ import org.leavesmc.leaves.bot.agent.AbstractBotAction; import org.leavesmc.leaves.bot.agent.Actions; import org.leavesmc.leaves.bot.agent.actions.CraftCustomBotAction; import org.leavesmc.leaves.command.LeavesSubcommand; +import org.leavesmc.leaves.command.LeavesSuggestionBuilder; import org.leavesmc.leaves.event.bot.BotActionStopEvent; -import java.util.ArrayList; -import java.util.Collections; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicInteger; import static net.kyori.adventure.text.Component.text; public class BotActionCommand implements LeavesSubcommand { @Override - public boolean execute(CommandSender sender, String subCommand, String[] args) { - if (!LeavesConfig.modify.fakeplayer.canUseAction) { - return false; - } - + public void execute(CommandSender sender, String subCommand, String[] args) { if (args.length < 2) { sender.sendMessage(text("Use /bot action to make fakeplayer do action", NamedTextColor.RED)); - return false; + return; } ServerBot bot = BotList.INSTANCE.getBotByName(args[0]); if (bot == null) { sender.sendMessage(text("This fakeplayer is not in server", NamedTextColor.RED)); - return false; + return; } - if (args[1].equals("list")) { - sender.sendMessage(bot.getScoreboardName() + "'s action list:"); - for (int i = 0; i < bot.getBotActions().size(); i++) { - sender.sendMessage(i + " " + bot.getBotActions().get(i).getName()); - } - return false; - } - - if (args[1].equals("stop")) { - if (args.length < 3) { - sender.sendMessage(text("Invalid index", NamedTextColor.RED)); - return false; - } - - String index = args[2]; - if (index.equals("all")) { - Set> forRemoval = new HashSet<>(); + switch (args[1].toLowerCase()) { + case "list" -> { + sender.sendMessage(bot.getScoreboardName() + "'s action list:"); for (int i = 0; i < bot.getBotActions().size(); i++) { - AbstractBotAction action = bot.getBotActions().get(i); - BotActionStopEvent event = new BotActionStopEvent( - bot.getBukkitEntity(), action.getName(), action.getUUID(), BotActionStopEvent.Reason.COMMAND, sender - ); - event.callEvent(); - if (!event.isCancelled()) { - forRemoval.add(action); - } - } - bot.getBotActions().removeAll(forRemoval); - sender.sendMessage(bot.getScoreboardName() + "'s action list cleared."); - } else { - try { - int i = Integer.parseInt(index); - if (i < 0 || i >= bot.getBotActions().size()) { - sender.sendMessage(text("Invalid index", NamedTextColor.RED)); - return false; - } - - AbstractBotAction action = bot.getBotActions().get(i); - BotActionStopEvent event = new BotActionStopEvent( - bot.getBukkitEntity(), action.getName(), action.getUUID(), BotActionStopEvent.Reason.COMMAND, sender - ); - event.callEvent(); - if (!event.isCancelled()) { - bot.getBotActions().remove(i); - sender.sendMessage(bot.getScoreboardName() + "'s " + action.getName() + " stopped."); - - } - } catch (NumberFormatException e) { - sender.sendMessage(text("Invalid index", NamedTextColor.RED)); + sender.sendMessage(i + " " + bot.getBotActions().get(i).getName()); } } - return false; + case "start" -> executeStart(bot, sender, args); + case "stop" -> executeStop(bot, sender, args); } + } - AbstractBotAction action = Actions.getForName(args[1]); + private void executeStart(ServerBot bot, CommandSender sender, String[] args) { + AbstractBotAction action = Actions.getForName(args[2]); if (action == null) { sender.sendMessage(text("Invalid action", NamedTextColor.RED)); - return false; + return; } CraftPlayer player; @@ -112,11 +66,7 @@ public class BotActionCommand implements LeavesSubcommand { player = bot.getBukkitEntity(); } - String[] realArgs = new String[args.length - 2]; - if (realArgs.length != 0) { - System.arraycopy(args, 2, realArgs, 0, realArgs.length); - } - + String[] realArgs = Arrays.copyOfRange(args, 3, args.length); AbstractBotAction newAction; try { if (action instanceof CraftCustomBotAction customBotAction) { @@ -127,76 +77,96 @@ public class BotActionCommand implements LeavesSubcommand { } } catch (IllegalArgumentException e) { sender.sendMessage(text("Action create error, please check your arguments, " + e.getMessage(), NamedTextColor.RED)); - return false; + return; } if (newAction == null) { - return false; + return; } if (bot.addBotAction(newAction, sender)) { sender.sendMessage("Action " + action.getName() + " has been issued to " + bot.getName().getString()); } - return true; + } + + private void executeStop(ServerBot bot, CommandSender sender, String[] args) { + if (args.length < 3) { + sender.sendMessage(text("Invalid index", NamedTextColor.RED)); + return; + } + + String index = args[2]; + if (index.equals("all")) { + Set> forRemoval = new HashSet<>(); + for (int i = 0; i < bot.getBotActions().size(); i++) { + AbstractBotAction action = bot.getBotActions().get(i); + BotActionStopEvent event = new BotActionStopEvent( + bot.getBukkitEntity(), action.getName(), action.getUUID(), BotActionStopEvent.Reason.COMMAND, sender + ); + event.callEvent(); + if (!event.isCancelled()) { + forRemoval.add(action); + } + } + bot.getBotActions().removeAll(forRemoval); + sender.sendMessage(bot.getScoreboardName() + "'s action list cleared."); + return; + } + try { + int i = Integer.parseInt(index); + if (i < 0 || i >= bot.getBotActions().size()) { + sender.sendMessage(text("Invalid index", NamedTextColor.RED)); + return; + } + + AbstractBotAction action = bot.getBotActions().get(i); + BotActionStopEvent event = new BotActionStopEvent( + bot.getBukkitEntity(), action.getName(), action.getUUID(), BotActionStopEvent.Reason.COMMAND, sender + ); + event.callEvent(); + if (!event.isCancelled()) { + bot.getBotActions().remove(i); + sender.sendMessage(bot.getScoreboardName() + "'s " + action.getName() + " stopped."); + + } + } catch (NumberFormatException e) { + sender.sendMessage(text("Invalid index", NamedTextColor.RED)); + } } @Override - public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { - if (!LeavesConfig.modify.fakeplayer.canUseAction) { - return Collections.emptyList(); - } - - List list = new ArrayList<>(); + public void suggest(@NotNull CommandSender sender, @NotNull String subCommand, String @NotNull [] args, Location location, @NotNull LeavesSuggestionBuilder builder) { BotList botList = BotList.INSTANCE; + ServerBot serverBot = null; - if (args.length <= 1) { - list.addAll(botList.bots.stream().map(e -> e.getName().getString()).toList()); - } else { - ServerBot bot = botList.getBotByName(args[0]); - if (bot == null) { - return Collections.singletonList("<" + args[0] + " not found>"); - } + if (args.length > 1 && (serverBot = botList.getBotByName(args[0])) == null) { + builder.suggest("<" + args[0] + " not found>"); + return; + } - if (args.length == 2) { - list.add("list"); - list.add("stop"); - list.addAll(Actions.getNames()); - } - - if (args.length >= 3) { - if (args[1].equals("stop")) { - list.add("all"); - for (int i = 0; i < bot.getBotActions().size(); i++) { - list.add(String.valueOf(i)); + switch (args.length) { + case 0, 1 -> botList.bots.forEach(bot -> builder.suggest(bot.getName().getString())); + case 2 -> builder.suggest("start").suggest("stop").suggest("list"); + case 3 -> { + switch (args[1].toLowerCase()) { + case "start" -> Actions.getNames().forEach(builder::suggest); + case "stop" -> { + builder.suggest("all"); + int[] index = new int[]{0}; + serverBot.getBotActions().forEach(a -> builder.suggest(String.valueOf(index[0]++))); } - } else { - return Collections.singletonList("<" + args[1] + " not found>"); } } - } - - return list; - } - - @Override - public CompletableFuture tabSuggestion(CommandSender sender, String subCommand, String[] args, Location location, SuggestionsBuilder builder) { - if (!LeavesConfig.modify.fakeplayer.canUseAction) { - return null; - } - - if (args.length >= 3) { - if (args[1].equals("stop")) { - return null; - } - AbstractBotAction action = Actions.getForName(args[1]); - if (action != null) { - Pair, String> results = action.getArgument().suggestion(args.length - 3, sender, args[args.length - 1]); - + case 4, 5, 6, 7 -> { + AbstractBotAction action = Actions.getForName(args[2]); + if (action == null) { + return; + } + Pair, String> results = action.getArgument().suggestion(args.length - 4, sender, args[args.length - 2]); if (results == null || results.getLeft() == null) { - return builder.buildFuture(); + return; } - builder = builder.createOffset(builder.getInput().lastIndexOf(' ') + 1); for (String s : results.getLeft()) { if (results.getRight() != null) { builder.suggest(s, Component.literal(results.getRight())); @@ -204,16 +174,12 @@ public class BotActionCommand implements LeavesSubcommand { builder.suggest(s); } } - - return builder.buildFuture(); } } - - return null; } @Override - public boolean tabCompletes() { + public boolean isEnabled() { return LeavesConfig.modify.fakeplayer.canUseAction; } } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotConfigCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotConfigCommand.java index aec1cb75..883a47bf 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotConfigCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotConfigCommand.java @@ -1,13 +1,13 @@ package org.leavesmc.leaves.bot.subcommands; -import com.mojang.brigadier.suggestion.Suggestions; -import com.mojang.brigadier.suggestion.SuggestionsBuilder; import net.kyori.adventure.text.format.NamedTextColor; import net.minecraft.network.chat.Component; import org.apache.commons.lang3.tuple.Pair; 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.LeavesConfig; import org.leavesmc.leaves.bot.BotList; import org.leavesmc.leaves.bot.ServerBot; @@ -15,52 +15,46 @@ import org.leavesmc.leaves.bot.agent.AbstractBotConfig; import org.leavesmc.leaves.bot.agent.Configs; import org.leavesmc.leaves.command.CommandArgumentResult; import org.leavesmc.leaves.command.LeavesSubcommand; +import org.leavesmc.leaves.command.LeavesSuggestionBuilder; import org.leavesmc.leaves.event.bot.BotConfigModifyEvent; -import java.util.ArrayList; -import java.util.Collections; +import java.util.Arrays; import java.util.List; import java.util.Objects; -import java.util.concurrent.CompletableFuture; import static net.kyori.adventure.text.Component.text; public class BotConfigCommand implements LeavesSubcommand { @Override - public boolean execute(CommandSender sender, String subCommand, String[] args) { - if (!LeavesConfig.modify.fakeplayer.canModifyConfig) { - return false; - } - + public void execute(CommandSender sender, String subCommand, String[] args) { if (args.length < 2) { sender.sendMessage(text("Use /bot config to modify fakeplayer's config", NamedTextColor.RED)); - return false; + return; } ServerBot bot = BotList.INSTANCE.getBotByName(args[0]); if (bot == null) { sender.sendMessage(text("This fakeplayer is not in server", NamedTextColor.RED)); - return false; + return; } if (!Configs.getConfigNames().contains(args[1])) { sender.sendMessage(text("This config is not accept", NamedTextColor.RED)); - return false; + return; } AbstractBotConfig config = bot.getConfig(Objects.requireNonNull(Configs.getConfig(args[1]))); if (args.length < 3) { config.getMessage().forEach(sender::sendMessage); } else { - String[] realArgs = new String[args.length - 2]; - System.arraycopy(args, 2, realArgs, 0, realArgs.length); + String[] realArgs = Arrays.copyOfRange(args, 2, args.length); BotConfigModifyEvent event = new BotConfigModifyEvent(bot.getBukkitEntity(), config.getName(), realArgs, sender); Bukkit.getPluginManager().callEvent(event); if (event.isCancelled()) { - return false; + return; } CommandArgumentResult result = config.getArgument().parse(0, realArgs); @@ -71,60 +65,33 @@ public class BotConfigCommand implements LeavesSubcommand { sender.sendMessage(text(e.getMessage(), NamedTextColor.RED)); } } - return true; } - @Override - public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { - if (!LeavesConfig.modify.fakeplayer.canModifyConfig) { - return Collections.emptyList(); - } - List list = new ArrayList<>(); + @Override + public void suggest(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] args, @Nullable Location location, LeavesSuggestionBuilder builder) throws IllegalArgumentException { BotList botList = BotList.INSTANCE; + ServerBot serverBot = null; - if (args.length <= 1) { - list.addAll(botList.bots.stream().map(e -> e.getName().getString()).toList()); - } else { - ServerBot bot = botList.getBotByName(args[0]); - if (bot == null) { - return Collections.singletonList("<" + args[0] + " not found>"); - } else { - if (args.length == 2) { - list.addAll(Configs.getConfigNames()); - } - - if (args.length >= 3) { - return Collections.singletonList("<" + args[1] + " not found>"); - } - } + if (args.length > 1 && (serverBot = botList.getBotByName(args[0])) == null) { + builder.suggest("<" + args[0] + " not found>"); + return; } - return list; - } - - @Override - public CompletableFuture tabSuggestion(CommandSender sender, String subCommand, String[] args, Location location, SuggestionsBuilder builder) { - if (!LeavesConfig.modify.fakeplayer.canModifyConfig) { - return null; - } - - if (args.length >= 3) { - ServerBot bot = BotList.INSTANCE.getBotByName(args[0]); - if (bot == null) { - return null; - } - - Configs config = Configs.getConfig(args[1]); - if (config != null) { - AbstractBotConfig botConfig = bot.getConfig(config); + switch (args.length) { + case 0, 1 -> botList.bots.forEach(bot -> builder.suggest(bot.getName().getString())); + case 2 -> Configs.getConfigNames().forEach(builder::suggest); + case 3, 4 -> { + Configs config = Configs.getConfig(args[1]); + if (config == null) { + return; + } + AbstractBotConfig botConfig = serverBot.getConfig(config); Pair, String> results = botConfig.getArgument().suggestion(args.length - 3, sender, args[args.length - 1]); - if (results == null || results.getLeft() == null) { - return builder.buildFuture(); + return; } - builder = builder.createOffset(builder.getInput().lastIndexOf(' ') + 1); for (String s : results.getLeft()) { if (results.getRight() != null) { builder.suggest(s, Component.literal(results.getRight())); @@ -132,16 +99,12 @@ public class BotConfigCommand implements LeavesSubcommand { builder.suggest(s); } } - - return builder.buildFuture(); } } - - return null; } @Override - public boolean tabCompletes() { + public boolean isEnabled() { return LeavesConfig.modify.fakeplayer.canModifyConfig; } } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotCreateCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotCreateCommand.java index 57eacbe0..0cbd1869 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotCreateCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotCreateCommand.java @@ -8,26 +8,25 @@ import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.leavesmc.leaves.LeavesConfig; import org.leavesmc.leaves.LeavesLogger; import org.leavesmc.leaves.bot.BotCreateState; import org.leavesmc.leaves.bot.BotList; import org.leavesmc.leaves.bot.BotUtil; import org.leavesmc.leaves.command.LeavesSubcommand; +import org.leavesmc.leaves.command.LeavesSuggestionBuilder; import org.leavesmc.leaves.event.bot.BotCreateEvent; -import java.util.ArrayList; -import java.util.List; - import static net.kyori.adventure.text.Component.text; public class BotCreateCommand implements LeavesSubcommand { @Override - public boolean execute(CommandSender sender, String subCommand, String[] args) { + public void execute(CommandSender sender, String subCommand, String[] args) { if (args.length < 1) { sender.sendMessage(text("Use /bot create [skin_name] to create a fakeplayer", NamedTextColor.RED)); - return false; + return; } String botName = args[0]; @@ -59,26 +58,19 @@ public class BotCreateCommand implements LeavesSubcommand { builder.spawnWithSkin(null); } - return true; } @Override - public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { - List list = new ArrayList<>(); + public void suggest(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] args, @Nullable Location location, LeavesSuggestionBuilder builder) throws IllegalArgumentException { if (args.length <= 1) { - list.add(""); + builder.suggest(""); } if (args.length == 2) { - list.add("[SkinName]"); + builder.suggest("[SkinName]"); } - if (sender instanceof ConsoleCommandSender) { - if (args.length == 3) { - for (var world : sender.getServer().getWorlds()) { - list.add(world.getName()); - } - } + if (sender instanceof ConsoleCommandSender && args.length == 3) { + Bukkit.getWorlds().forEach(world -> builder.suggest(world.getName())); } - return list; } private boolean canCreate(CommandSender sender, @NotNull String name) { diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotListCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotListCommand.java index 4cb54631..4d92cfcb 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotListCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotListCommand.java @@ -5,12 +5,13 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.command.CommandSender; -import org.bukkit.generator.WorldInfo; import org.jetbrains.annotations.NotNull; +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.command.LeavesSubcommand; +import org.leavesmc.leaves.command.LeavesSuggestionBuilder; import org.leavesmc.leaves.entity.Bot; import java.util.ArrayList; @@ -22,8 +23,17 @@ import static net.kyori.adventure.text.Component.text; public class BotListCommand implements LeavesSubcommand { + @NotNull + private static String formatPlayerNameList(@NotNull List list) { + if (list.isEmpty()) { + return ""; + } + String string = list.toString(); + return string.substring(1, string.length() - 1); + } + @Override - public boolean execute(CommandSender sender, String subCommand, String[] args) { + public void execute(CommandSender sender, String subCommand, String[] args) { BotList botList = BotList.INSTANCE; if (args.length < 2) { Map> botMap = new HashMap<>(); @@ -45,7 +55,7 @@ public class BotListCommand implements LeavesSubcommand { if (world == null) { sender.sendMessage(text("Unknown world", NamedTextColor.RED)); - return false; + return; } List snowBotList = new ArrayList<>(); @@ -58,26 +68,10 @@ public class BotListCommand implements LeavesSubcommand { sender.sendMessage(world.getName() + "(" + botList.bots.size() + "): " + formatPlayerNameList(snowBotList)); } - return true; } @Override - public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { - List list = new ArrayList<>(); - - if (args.length <= 1) { - list.addAll(Bukkit.getWorlds().stream().map(WorldInfo::getName).toList()); - } - - return list; - } - - @NotNull - private static String formatPlayerNameList(@NotNull List list) { - if (list.isEmpty()) { - return ""; - } - String string = list.toString(); - return string.substring(1, string.length() - 1); + public void suggest(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] args, @Nullable Location location, LeavesSuggestionBuilder builder) throws IllegalArgumentException { + Bukkit.getWorlds().forEach(world -> builder.suggest(world.getName())); } } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotLoadCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotLoadCommand.java index 4809654b..fbd223e3 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotLoadCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotLoadCommand.java @@ -3,61 +3,46 @@ package org.leavesmc.leaves.bot.subcommands; import net.kyori.adventure.text.format.NamedTextColor; 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.bot.BotList; import org.leavesmc.leaves.command.LeavesSubcommand; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import org.leavesmc.leaves.command.LeavesSuggestionBuilder; import static net.kyori.adventure.text.Component.text; public class BotLoadCommand implements LeavesSubcommand { @Override - public boolean execute(CommandSender sender, String subCommand, String[] args) { - if (!LeavesConfig.modify.fakeplayer.canManualSaveAndLoad) { - return false; - } - + public void execute(CommandSender sender, String subCommand, String[] args) { if (args.length < 1) { sender.sendMessage(text("Use /bot load to save a fakeplayer", NamedTextColor.RED)); - return false; + return; } String realName = args[0]; BotList botList = BotList.INSTANCE; if (!botList.getSavedBotList().contains(realName)) { sender.sendMessage(text("This fakeplayer is not saved", NamedTextColor.RED)); - return false; + return; } if (botList.loadNewBot(realName) == null) { sender.sendMessage(text("Can't load bot, please check", NamedTextColor.RED)); } - - return true; } @Override - public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { - if (!LeavesConfig.modify.fakeplayer.canManualSaveAndLoad) { - return Collections.emptyList(); - } - - List list = new ArrayList<>(); + public void suggest(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] args, @Nullable Location location, LeavesSuggestionBuilder builder) throws IllegalArgumentException { BotList botList = BotList.INSTANCE; - if (args.length <= 1) { - list.addAll(botList.getSavedBotList().keySet()); + botList.getSavedBotList().keySet().forEach(builder::suggest); } - - return list; } @Override - public boolean tabCompletes() { + public boolean isEnabled() { return LeavesConfig.modify.fakeplayer.canManualSaveAndLoad; } } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotRemoveCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotRemoveCommand.java index 71793ec8..c40bd6a7 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotRemoveCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotRemoveCommand.java @@ -5,15 +5,15 @@ 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.bot.BotList; import org.leavesmc.leaves.bot.ServerBot; import org.leavesmc.leaves.command.LeavesSubcommand; +import org.leavesmc.leaves.command.LeavesSuggestionBuilder; import org.leavesmc.leaves.event.bot.BotRemoveEvent; import org.leavesmc.leaves.plugin.MinecraftInternalPlugin; -import java.util.ArrayList; -import java.util.List; - import static net.kyori.adventure.text.Component.text; public class BotRemoveCommand implements LeavesSubcommand { @@ -21,10 +21,10 @@ public class BotRemoveCommand implements LeavesSubcommand { private final Component errorMessage = text("Usage: /bot remove [hour] [minute] [second]", NamedTextColor.RED); @Override - public boolean execute(CommandSender sender, String subCommand, String[] args) { + public void execute(CommandSender sender, String subCommand, String[] args) { if (args.length < 1 || args.length > 4) { sender.sendMessage(errorMessage); - return false; + return; } BotList botList = BotList.INSTANCE; @@ -32,18 +32,18 @@ public class BotRemoveCommand implements LeavesSubcommand { if (bot == null) { sender.sendMessage(text("This fakeplayer is not in server", NamedTextColor.RED)); - return false; + return; } if (args.length == 2 && args[1].equals("cancel")) { if (bot.removeTaskId == -1) { sender.sendMessage(text("This fakeplayer is not scheduled to be removed", NamedTextColor.RED)); - return false; + return; } Bukkit.getScheduler().cancelTask(bot.removeTaskId); bot.removeTaskId = -1; sender.sendMessage(text("Remove cancel")); - return false; + return; } if (args.length > 1) { @@ -74,7 +74,7 @@ public class BotRemoveCommand implements LeavesSubcommand { } } catch (NumberFormatException e) { sender.sendMessage(errorMessage); - return false; + return; } boolean isReschedule = bot.removeTaskId != -1; @@ -88,36 +88,30 @@ public class BotRemoveCommand implements LeavesSubcommand { }, time).getTaskId(); sender.sendMessage("This fakeplayer will be removed in " + h + "h " + m + "m " + s + "s" + (isReschedule ? " (rescheduled)" : "")); - - return false; + return; } botList.removeBot(bot, BotRemoveEvent.RemoveReason.COMMAND, sender, false); - return true; } @Override - public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { - List list = new ArrayList<>(); + public void suggest(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] args, @Nullable Location location, LeavesSuggestionBuilder builder) throws IllegalArgumentException { BotList botList = BotList.INSTANCE; if (args.length <= 1) { - list.addAll(botList.bots.stream().map(e -> e.getName().getString()).toList()); + botList.bots.forEach(bot -> builder.suggest(bot.getName().getString())); } if (args.length == 2) { - list.add("cancel"); - list.add("[hour]"); + builder.suggest("cancel"); + builder.suggest("[hour]"); } if (args.length > 2 && !args[1].equals("cancel")) { switch (args.length) { - case 3 -> list.add("[minute]"); - case 4 -> list.add("[second]"); + case 3 -> builder.suggest("[minute]"); + case 4 -> builder.suggest("[second]"); } } - - - return list; } } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotSaveCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotSaveCommand.java index c2028479..d1b22d9c 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotSaveCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotSaveCommand.java @@ -3,29 +3,24 @@ package org.leavesmc.leaves.bot.subcommands; import net.kyori.adventure.text.format.NamedTextColor; 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.bot.BotList; import org.leavesmc.leaves.bot.ServerBot; import org.leavesmc.leaves.command.LeavesSubcommand; +import org.leavesmc.leaves.command.LeavesSuggestionBuilder; import org.leavesmc.leaves.event.bot.BotRemoveEvent; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - import static net.kyori.adventure.text.Component.text; public class BotSaveCommand implements LeavesSubcommand { @Override - public boolean execute(CommandSender sender, String subCommand, String[] args) { - if (!LeavesConfig.modify.fakeplayer.canManualSaveAndLoad) { - return false; - } - + public void execute(CommandSender sender, String subCommand, String[] args) { if (args.length < 1) { sender.sendMessage(text("Use /bot save to save a fakeplayer", NamedTextColor.RED)); - return false; + return; } BotList botList = BotList.INSTANCE; @@ -33,34 +28,24 @@ public class BotSaveCommand implements LeavesSubcommand { if (bot == null) { sender.sendMessage(text("This fakeplayer is not in server", NamedTextColor.RED)); - return false; + return; } if (botList.removeBot(bot, BotRemoveEvent.RemoveReason.COMMAND, sender, true)) { sender.sendMessage(bot.getScoreboardName() + " saved to " + bot.createState.realName()); } - - return true; } @Override - public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { - if (!LeavesConfig.modify.fakeplayer.canManualSaveAndLoad) { - return Collections.emptyList(); - } - - List list = new ArrayList<>(); + public void suggest(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] args, @Nullable Location location, LeavesSuggestionBuilder builder) throws IllegalArgumentException { BotList botList = BotList.INSTANCE; - if (args.length <= 1) { - list.addAll(botList.bots.stream().map(e -> e.getName().getString()).toList()); + botList.bots.forEach(bot -> builder.suggest(bot.getName().getString())); } - - return list; } @Override - public boolean tabCompletes() { + public boolean isEnabled() { return LeavesConfig.modify.fakeplayer.canManualSaveAndLoad; } } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java index 7ef85249..34f3ce73 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java @@ -1,19 +1,7 @@ package org.leavesmc.leaves.command; -import com.mojang.brigadier.suggestion.Suggestions; -import com.mojang.brigadier.suggestion.SuggestionsBuilder; -import it.unimi.dsi.fastutil.Pair; -import net.kyori.adventure.text.Component; import net.minecraft.Util; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.permissions.Permission; -import org.bukkit.permissions.PermissionDefault; -import org.bukkit.plugin.PluginManager; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.command.subcommands.BlockUpdateCommand; import org.leavesmc.leaves.command.subcommands.ConfigCommand; import org.leavesmc.leaves.command.subcommands.CounterCommand; import org.leavesmc.leaves.command.subcommands.PeacefulModeSwitchCommand; @@ -21,22 +9,12 @@ import org.leavesmc.leaves.command.subcommands.ReloadCommand; import org.leavesmc.leaves.command.subcommands.ReportCommand; import org.leavesmc.leaves.command.subcommands.UpdateCommand; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; import java.util.HashMap; -import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; -import static net.kyori.adventure.text.Component.text; -import static net.kyori.adventure.text.format.NamedTextColor.RED; - -public final class LeavesCommand extends Command implements LeavesSuggestionCommand { +public final class LeavesCommand extends LeavesRootCommand { public static final String BASE_PERM = "bukkit.command.leaves."; @@ -49,111 +27,14 @@ public final class LeavesCommand extends Command implements LeavesSuggestionComm 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(final String name) { - super(name); - this.description = "Leaves related commands"; - this.usageMessage = "/leaves [" + String.join(" | ", SUBCOMMANDS.keySet()) + "]"; - final List permissions = new ArrayList<>(); - permissions.add("bukkit.command.leaves"); - permissions.addAll(SUBCOMMANDS.keySet().stream().map(s -> BASE_PERM + s).toList()); - this.setPermission(String.join(";", permissions)); - final PluginManager pluginManager = Bukkit.getServer().getPluginManager(); - for (final String perm : permissions) { - if (pluginManager.getPermission(perm) == null) { - pluginManager.addPermission(new Permission(perm, PermissionDefault.OP)); - } - } + public LeavesCommand() { + super("leaves", "Leaves related commands", "bukkit.command.leaves", SUBCOMMANDS); } - - private static boolean testPermission(final CommandSender sender, final String permission) { - if (sender.hasPermission(BASE_PERM + permission) || sender.hasPermission("bukkit.command.leaves")) { - return true; - } - sender.sendMessage(Bukkit.permissionMessage()); - return false; - } - - @NotNull - @Override - public List tabComplete(final @NotNull CommandSender sender, final @NotNull String alias, final String[] args, final @Nullable Location location) throws IllegalArgumentException { - if (args.length <= 1) { - return LeavesCommandUtil.getListMatchingLast(sender, args, usableSubcommands()); - } - - final @Nullable Pair subCommand = resolveCommand(args[0]); - if (subCommand != null) { - return subCommand.second().tabComplete(sender, subCommand.first(), Arrays.copyOfRange(args, 1, args.length), location); - } - - return Collections.emptyList(); - } - - @Nullable - @Override - public CompletableFuture tabSuggestion(final @NotNull CommandSender sender, final @NotNull String alias, final @NotNull String @NotNull [] args, final @Nullable Location location, final @NotNull SuggestionsBuilder builder) throws IllegalArgumentException { - if (args.length > 1) { - final @Nullable Pair subCommand = resolveCommand(args[0]); - if (subCommand != null) { - return subCommand.second().tabSuggestion(sender, subCommand.first(), Arrays.copyOfRange(args, 1, args.length), location, builder); - } - } - return null; - } - - @Override - public boolean execute(final @NotNull CommandSender sender, final @NotNull String commandLabel, final String @NotNull [] args) { - if (!testPermission(sender)) { - return true; - } - - if (args.length == 0) { - sender.sendMessage(unknownMessage()); - return false; - } - final Pair subCommand = resolveCommand(args[0]); - - if (subCommand == null) { - sender.sendMessage(unknownMessage()); - return false; - } - - if (!testPermission(sender, subCommand.first())) { - return true; - } - final String[] choppedArgs = Arrays.copyOfRange(args, 1, args.length); - return subCommand.second().execute(sender, subCommand.first(), choppedArgs); - } - - private Collection usableSubcommands() { - List subcommands = new ArrayList<>(); - for (var entry : SUBCOMMANDS.entrySet()) { - if (entry.getValue().tabCompletes()) { - subcommands.add(entry.getKey()); - } - } - return subcommands; - } - - public Component unknownMessage() { - return text("Usage: /leaves [" + String.join(" | ", usableSubcommands()) + "]", RED); - } - - @Nullable - private static Pair resolveCommand(String label) { - label = label.toLowerCase(Locale.ENGLISH); - LeavesSubcommand subCommand = SUBCOMMANDS.get(label); - - if (subCommand != null) { - return Pair.of(label, subCommand); - } - - return null; - } - } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesCommandUtil.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesCommandUtil.java index bb865157..afb48b7e 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesCommandUtil.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesCommandUtil.java @@ -107,14 +107,6 @@ public class LeavesCommandUtil { return results; } - private record Candidate(String item, int score) { - private static Candidate of(String item, int score) { - return new Candidate(item, score); - } - } - - // Copy from org/bukkit/command/defaults/HelpCommand.java - /** * Computes the Dameraur-Levenshtein Distance between two strings. Adapted * from the algorithm at Wikipedia: Damerau–Levenshtein distance @@ -178,4 +170,12 @@ public class LeavesCommandUtil { 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); + } + } } \ No newline at end of file diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesRootCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesRootCommand.java new file mode 100644 index 00000000..90bda53e --- /dev/null +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesRootCommand.java @@ -0,0 +1,126 @@ +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 subcommands; + + protected LeavesRootCommand( + @NotNull String name, + @NotNull String description, + @NotNull String basePermission, + @NotNull Map subCommands + ) { + super(name, description, String.format("/%s [%s]", name, String.join(" | ", subCommands.keySet())), Collections.emptyList()); + this.basePermission = basePermission; + this.subcommands = subCommands; + + final List 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 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 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 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 usableSubcommands() { + List subcommandList = new ArrayList<>(); + for (var entry : subcommands.entrySet()) { + if (entry.getValue().isEnabled()) { + subcommandList.add(entry.getKey()); + } + } + return subcommandList; + } +} diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesSubcommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesSubcommand.java index ff09291e..c026b634 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesSubcommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesSubcommand.java @@ -1,26 +1,7 @@ package org.leavesmc.leaves.command; -import com.mojang.brigadier.suggestion.Suggestions; -import com.mojang.brigadier.suggestion.SuggestionsBuilder; -import org.bukkit.Location; import org.bukkit.command.CommandSender; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletableFuture; - -public interface LeavesSubcommand { - boolean execute(CommandSender sender, String subCommand, String[] args); - - default List tabComplete(final CommandSender sender, final String subCommand, final String[] args, Location location) { - return Collections.emptyList(); - } - - default CompletableFuture tabSuggestion(final CommandSender sender, final String subCommand, final String[] args, final Location location, final SuggestionsBuilder builder) { - return null; - } - - default boolean tabCompletes() { - return true; - } -} +public interface LeavesSubcommand extends LeavesSuggestionCommand { + void execute(CommandSender sender, String subCommand, String[] args); +} \ No newline at end of file diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesSuggestionBuilder.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesSuggestionBuilder.java new file mode 100644 index 00000000..1eb02281 --- /dev/null +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesSuggestionBuilder.java @@ -0,0 +1,49 @@ +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 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(); + } +} diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesSuggestionCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesSuggestionCommand.java index 42750461..ed0f1c5f 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesSuggestionCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesSuggestionCommand.java @@ -1,15 +1,15 @@ package org.leavesmc.leaves.command; -import com.mojang.brigadier.suggestion.Suggestions; -import com.mojang.brigadier.suggestion.SuggestionsBuilder; import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.concurrent.CompletableFuture; - public interface LeavesSuggestionCommand { - @Nullable - CompletableFuture tabSuggestion(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] args, @Nullable Location location, @NotNull SuggestionsBuilder builder) throws IllegalArgumentException; -} + 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; + } +} \ No newline at end of file diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/NoBlockUpdateCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/NoBlockUpdateCommand.java deleted file mode 100644 index 7593a046..00000000 --- a/leaves-server/src/main/java/org/leavesmc/leaves/command/NoBlockUpdateCommand.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.leavesmc.leaves.command; - -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.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.leavesmc.leaves.LeavesConfig; - -import java.util.List; - -// TODO merge to /leaves blockupdate -public class NoBlockUpdateCommand extends Command { - - private static boolean noBlockUpdate = false; - - public NoBlockUpdateCommand(@NotNull String name) { - super(name); - this.description = "No Block Update Command"; - this.usageMessage = "/blockupdate"; - this.setPermission("bukkit.command.blockupdate"); - final PluginManager pluginManager = Bukkit.getServer().getPluginManager(); - if (pluginManager.getPermission("bukkit.command.blockupdate") == null) { - pluginManager.addPermission(new Permission("bukkit.command.blockupdate", PermissionDefault.OP)); - } - } - - @Override - public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, String @NotNull [] args) throws IllegalArgumentException { - return List.of(); - } - - @Override - public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, String @NotNull [] args) { - if (!testPermission(sender)) return true; - 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.blockupdate"); - - return true; - } - - public static boolean isNoBlockUpdate() { - return LeavesConfig.modify.noBlockUpdateCommand && noBlockUpdate; - } -} diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/BlockUpdateCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/BlockUpdateCommand.java new file mode 100644 index 00000000..18477f57 --- /dev/null +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/BlockUpdateCommand.java @@ -0,0 +1,33 @@ +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; + } +} diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/ConfigCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/ConfigCommand.java index 8ec9bd62..39afed44 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/ConfigCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/ConfigCommand.java @@ -1,7 +1,5 @@ package org.leavesmc.leaves.command.subcommands; -import com.mojang.brigadier.suggestion.Suggestions; -import com.mojang.brigadier.suggestion.SuggestionsBuilder; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.JoinConfiguration; import net.kyori.adventure.text.format.NamedTextColor; @@ -11,20 +9,17 @@ 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 java.util.Collections; -import java.util.List; -import java.util.concurrent.CompletableFuture; - public class ConfigCommand implements LeavesSubcommand { @Override - public boolean execute(CommandSender sender, String subCommand, String[] args) { + public void execute(CommandSender sender, String subCommand, String[] args) { if (args.length < 1) { sender.sendMessage(Component.text("Leaves Config", NamedTextColor.GRAY)); - return true; + return; } VerifiedConfig verifiedConfig = GlobalConfigManager.getVerifiedConfig(args[0]); @@ -34,7 +29,7 @@ public class ConfigCommand implements LeavesSubcommand { Component.text(args[0], NamedTextColor.RED), Component.text(" is Not Found.", NamedTextColor.GRAY) )); - return true; + return; } if (args.length > 1) { @@ -62,33 +57,24 @@ public class ConfigCommand implements LeavesSubcommand { Component.text(verifiedConfig.getString(), NamedTextColor.AQUA) )); } - - return true; } @Override - public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { + 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) { - return LeavesCommandUtil.getListMatchingLast(sender, args, verifiedConfig.validator().valueSuggest()); + LeavesCommandUtil.getListMatchingLast(sender, args, verifiedConfig.validator().valueSuggest()).forEach(builder::suggest); } else { - return Collections.singletonList(""); + builder.suggest(""); } } - return Collections.emptyList(); - } - - @Override - public CompletableFuture tabSuggestion(CommandSender sender, String subCommand, String @NotNull [] args, @Nullable Location location, @NotNull SuggestionsBuilder builder) { - if (args.length == 1) { - String arg = args[0]; - int dotIndex = arg.lastIndexOf("."); - builder = builder.createOffset(builder.getInput().lastIndexOf(' ') + dotIndex + 2); - LeavesCommandUtil.getListClosestMatchingLast(sender, arg.substring(dotIndex + 1), GlobalConfigManager.getVerifiedConfigSubPaths(arg), "bukkit.command.leaves.config") - .forEach(builder::suggest); - return builder.buildFuture(); - } - return null; } } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/CounterCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/CounterCommand.java index 8cd610ea..b0135c42 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/CounterCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/CounterCommand.java @@ -9,30 +9,26 @@ 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.Collections; import java.util.List; public class CounterCommand implements LeavesSubcommand { @Override - public boolean execute(CommandSender sender, String subCommand, String[] args) { - if (!LeavesConfig.modify.hopperCounter) { - return false; - } - + 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) )); - return true; } if (!HopperCounter.isEnabled()) { @@ -42,7 +38,6 @@ public class CounterCommand implements LeavesSubcommand { } else { sender.sendMessage(Component.text("Hopper Counter is not enabled", NamedTextColor.RED)); } - return true; } DyeColor color = DyeColor.byName(args[0], null); @@ -50,20 +45,19 @@ public class CounterCommand implements LeavesSubcommand { HopperCounter counter = HopperCounter.getCounter(color); if (args.length < 2) { displayCounter(sender, counter, false); - } else { - 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); - } + 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); } - return true; } switch (args[0]) { @@ -77,8 +71,6 @@ public class CounterCommand implements LeavesSubcommand { sender.sendMessage(Component.text("Hopper Counter now is disabled", NamedTextColor.GRAY)); } } - - return true; } private void displayCounter(CommandSender sender, @NotNull HopperCounter counter, boolean realTime) { @@ -88,35 +80,27 @@ public class CounterCommand implements LeavesSubcommand { } @Override - public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { - if (!LeavesConfig.modify.hopperCounter) { - return Collections.emptyList(); - } - - switch (args.length) { - case 1 -> { - if (!HopperCounter.isEnabled()) { - return Collections.singletonList("enable"); - } - - List list = new ArrayList<>(Arrays.stream(DyeColor.values()).map(DyeColor::getName).toList()); - list.add("reset"); - list.add("disable"); - return LeavesCommandUtil.getListMatchingLast(sender, args, list); + 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; } - case 2 -> { - if (DyeColor.byName(args[0], null) != null) { - return LeavesCommandUtil.getListMatchingLast(sender, args, "reset", "realtime"); - } + List 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); } } - - return Collections.emptyList(); } @Override - public boolean tabCompletes() { + public boolean isEnabled() { return LeavesConfig.modify.hopperCounter; } } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/PeacefulModeSwitchCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/PeacefulModeSwitchCommand.java index eb7c1df3..9defe8d5 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/PeacefulModeSwitchCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/PeacefulModeSwitchCommand.java @@ -12,31 +12,30 @@ import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.leavesmc.leaves.command.LeavesCommandUtil; import org.leavesmc.leaves.command.LeavesSubcommand; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import org.leavesmc.leaves.command.LeavesSuggestionBuilder; public class PeacefulModeSwitchCommand implements LeavesSubcommand { @Override - public boolean execute(CommandSender sender, String subCommand, String[] args) { + public void execute(CommandSender sender, String subCommand, String[] args) { World world; if (args.length == 0) { if (sender instanceof Player player) { world = player.getWorld(); } else { sender.sendMessage(Component.text("Must specify a world! ex: '/leaves peaceful world'", NamedTextColor.RED)); - return true; + return; } } else { final String input = args[0]; final World inputWorld = Bukkit.getWorld(input); if (inputWorld == null) { sender.sendMessage(Component.text("'" + input + "' is not a valid world!", NamedTextColor.RED)); - return true; + return; } else { world = inputWorld; } @@ -69,20 +68,13 @@ public class PeacefulModeSwitchCommand implements LeavesSubcommand { Component.text("/", color), Component.text(limit, color) )); - - return true; } @Override - public List tabComplete(final CommandSender sender, final String subCommand, final String[] args, Location location) { - return LeavesCommandUtil.getListMatchingLast(sender, args, this.suggestPeacefulModeSwitch(args)); - } - - private List suggestPeacefulModeSwitch(final String[] args) { - if (args.length == 1) { - return new ArrayList<>(Bukkit.getWorlds().stream().map(World::getName).toList()); + public void suggest(@NotNull CommandSender sender, @NotNull String alias, @NotNull String @NotNull [] args, @Nullable Location location, LeavesSuggestionBuilder builder) throws IllegalArgumentException { + if (args.length > 1) { + return; } - - return Collections.emptyList(); + LeavesCommandUtil.getListMatchingLast(sender, args, Bukkit.getWorlds().stream().map(World::getName).toList()).forEach(builder::suggest); } } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/ReloadCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/ReloadCommand.java index 168307a5..761dcfb8 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/ReloadCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/ReloadCommand.java @@ -9,9 +9,8 @@ import static net.kyori.adventure.text.format.NamedTextColor.GREEN; public class ReloadCommand implements LeavesSubcommand { @Override - public boolean execute(CommandSender sender, String subCommand, String[] args) { + public void execute(CommandSender sender, String subCommand, String[] args) { LeavesConfig.reload(); sender.sendMessage(text("Leaves config reload complete.", GREEN)); - return false; } } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/ReportCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/ReportCommand.java index d5197cb1..510474bb 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/ReportCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/ReportCommand.java @@ -19,17 +19,19 @@ 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.plugin.MinecraftInternalPlugin; +import org.leavesmc.leaves.command.LeavesSuggestionBuilder; import org.leavesmc.leaves.plugin.provider.configuration.LeavesPluginMeta; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.TreeMap; +import java.util.concurrent.CompletableFuture; import static net.kyori.adventure.text.Component.text; import static net.kyori.adventure.text.format.NamedTextColor.AQUA; @@ -41,48 +43,6 @@ public class ReportCommand implements LeavesSubcommand { 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"; - @Override - public boolean 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 true; - } - if (args[0].equals("bug-report")) { - Bukkit.getScheduler().runTaskAsynchronously(MinecraftInternalPlugin.INSTANCE, () -> { - sendOnSuccess(sender, BUG_REPORT_URL, Component.text("Successfully generated report url for \"bug-report\"", AQUA)); - }); - return true; - } else if (args[0].equals("not-vanilla")) { - Bukkit.getScheduler().runTaskAsynchronously(MinecraftInternalPlugin.INSTANCE, () -> { - sendOnSuccess(sender, NOT_VANILLA_URL, Component.text("Successfully generated report url for \"not-vanilla\"", AQUA)); - }); - return true; - } - sender.sendMessage(text("The template" + args[0] + " does not exist! Please select a correct template: \"bug-report\" or \"not-vanilla\"", RED)); - return true; - } - - @Override - public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { - if (args.length <= 1) { - return LeavesCommandUtil.getListMatchingLast(sender, args, List.of("bug-report", "not-vanilla"), COMMAND_PERM + ".", COMMAND_PERM); - } - return Collections.emptyList(); - } - - private void sendOnSuccess(CommandSender sender, String template, Component component) { - 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)); - 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)); - } 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))); - } - } - private static String generatePluginMessage() { final StringBuilder pluginList = new StringBuilder(); @@ -166,4 +126,40 @@ 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) { + 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)); + 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)); + } 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))); + } + } } \ No newline at end of file diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/UpdateCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/UpdateCommand.java index 6406e3fa..4af4c88f 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/UpdateCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/UpdateCommand.java @@ -9,14 +9,8 @@ import org.leavesmc.leaves.util.LeavesUpdateHelper; public class UpdateCommand implements LeavesSubcommand { @Override - public boolean execute(CommandSender sender, String subCommand, String[] args) { + 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(); - return true; - } - - @Override - public boolean tabCompletes() { - return false; } }