From aeb8e07d29a60e6d844d5d6338c6831c7cdb1b91 Mon Sep 17 00:00:00 2001 From: violetc <58360096+s-yh-china@users.noreply.github.com> Date: Sat, 16 Aug 2025 19:08:14 +0800 Subject: [PATCH] Fix fakeplayer break action * 2 --- .../features/0007-Leaves-Fakeplayer.patch | 127 +++++++++++++++++- .../leavesmc/leaves/bot/BotRecipeBook.java | 56 ++++++++ .../org/leavesmc/leaves/bot/ServerBot.java | 32 ++++- .../leaves/bot/ServerBotGameMode.java | 50 ++++--- .../agent/actions/ServerBreakBlockAction.java | 67 ++++++--- 5 files changed, 283 insertions(+), 49 deletions(-) create mode 100644 leaves-server/src/main/java/org/leavesmc/leaves/bot/BotRecipeBook.java diff --git a/leaves-server/minecraft-patches/features/0007-Leaves-Fakeplayer.patch b/leaves-server/minecraft-patches/features/0007-Leaves-Fakeplayer.patch index 6024e567..8fc4fcc2 100644 --- a/leaves-server/minecraft-patches/features/0007-Leaves-Fakeplayer.patch +++ b/leaves-server/minecraft-patches/features/0007-Leaves-Fakeplayer.patch @@ -100,6 +100,105 @@ index fdeca41d40705f28864ce4443d01cd872c9d51b0..5c0e338dc1b0eb5724d10a73d6fc7975 boolean flag = false; AdvancementProgress orStartProgress = this.getOrStartProgress(advancement); boolean isDone = orStartProgress.isDone(); +diff --git a/net/minecraft/server/commands/BanIpCommands.java b/net/minecraft/server/commands/BanIpCommands.java +index bb5dbfeb6915a808d6f70e332bf9f0a3f9b7d19a..62f23d47b55eb59956d69153d508b5c9ab544adf 100644 +--- a/net/minecraft/server/commands/BanIpCommands.java ++++ b/net/minecraft/server/commands/BanIpCommands.java +@@ -44,6 +44,12 @@ public class BanIpCommands { + return banIp(source, username, reason); + } else { + ServerPlayer playerByName = source.getServer().getPlayerList().getPlayerByName(username); ++ // Leaves start - disable ban ++ if (playerByName instanceof org.leavesmc.leaves.bot.ServerBot) { ++ source.sendFailure(Component.literal("Permission denied")); ++ return 0; ++ } ++ // Leaves end - disable ban + if (playerByName != null) { + return banIp(source, playerByName.getIpAddress(), reason); + } else { +diff --git a/net/minecraft/server/commands/BanPlayerCommands.java b/net/minecraft/server/commands/BanPlayerCommands.java +index ac3ba9d0ea344fa189912d359b718fbe05e7aa49..61a4db144f721b47ac1000df72263bceb6e38ec0 100644 +--- a/net/minecraft/server/commands/BanPlayerCommands.java ++++ b/net/minecraft/server/commands/BanPlayerCommands.java +@@ -44,8 +44,16 @@ public class BanPlayerCommands { + private static int banPlayers(CommandSourceStack source, Collection gameProfiles, @Nullable Component reason) throws CommandSyntaxException { + UserBanList bans = source.getServer().getPlayerList().getBans(); + int i = 0; +- ++ boolean hasBot = false; // Leaves - disable kick + for (GameProfile gameProfile : gameProfiles) { ++ // Leaves start - disable ban ++ if (gameProfile instanceof org.leavesmc.leaves.bot.BotList.CustomGameProfile) { ++ source.sendFailure(Component.literal("Permission denied")); ++ hasBot = true; ++ continue; ++ } ++ // Leaves end - disable ban ++ ServerPlayer player = source.getServer().getPlayerList().getPlayer(gameProfile.getId()); + if (!bans.isBanned(gameProfile)) { + UserBanListEntry userBanListEntry = new UserBanListEntry( + gameProfile, null, source.getTextName(), null, reason == null ? null : reason.getString() +@@ -55,7 +63,6 @@ public class BanPlayerCommands { + source.sendSuccess( + () -> Component.translatable("commands.ban.success", Component.literal(gameProfile.getName()), userBanListEntry.getReason()), true + ); +- ServerPlayer player = source.getServer().getPlayerList().getPlayer(gameProfile.getId()); + if (player != null) { + player.connection.disconnect(Component.translatable("multiplayer.disconnect.banned"), org.bukkit.event.player.PlayerKickEvent.Cause.BANNED); // Paper - kick event cause + } +@@ -63,7 +70,13 @@ public class BanPlayerCommands { + } + + if (i == 0) { +- throw ERROR_ALREADY_BANNED.create(); ++ // Leaves start - disable kick ++ if (hasBot) { ++ return i; ++ } else { ++ throw ERROR_ALREADY_BANNED.create(); ++ } ++ // Leaves end - disable kick + } else { + return i; + } +diff --git a/net/minecraft/server/commands/KickCommand.java b/net/minecraft/server/commands/KickCommand.java +index 14e2e0fcf20c8fa875bbefb97a673be4928d099a..8af40a77dc3da1599da2793168488f88686b8785 100644 +--- a/net/minecraft/server/commands/KickCommand.java ++++ b/net/minecraft/server/commands/KickCommand.java +@@ -46,9 +46,17 @@ public class KickCommand { + if (!source.getServer().isPublished()) { + throw ERROR_SINGLEPLAYER.create(); + } else { ++ boolean hasBot = false; // Leaves - disable kick + int i = 0; + + for (ServerPlayer serverPlayer : players) { ++ // Leaves start - disable kick ++ if (serverPlayer instanceof org.leavesmc.leaves.bot.ServerBot) { ++ source.sendFailure(Component.literal("Permission denied")); ++ hasBot = true; ++ continue; ++ } ++ // Leaves end - disable kick + if (!source.getServer().isSingleplayerOwner(serverPlayer.getGameProfile())) { + serverPlayer.connection.disconnect(reason, org.bukkit.event.player.PlayerKickEvent.Cause.KICK_COMMAND); // Paper - kick event cause + source.sendSuccess(() -> Component.translatable("commands.kick.success", serverPlayer.getDisplayName(), reason), true); +@@ -57,7 +65,13 @@ public class KickCommand { + } + + if (i == 0) { +- throw ERROR_KICKING_OWNER.create(); ++ // Leaves start - disable kick ++ if (hasBot) { ++ return i; ++ } else { ++ throw ERROR_KICKING_OWNER.create(); ++ } ++ // Leaves end - disable kick + } else { + return i; + } diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java index 414a8357a7498c69341fa634ada2e664e18ca03a..f85993fc507d699728e058b12bb49dcb7aaea44b 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java @@ -196,7 +295,7 @@ index 364d5e28646ea341034921622354c7b19644b343..c61c0b6d58f96955bfbdad0caaeb56f0 ServerLevel.this.updateSleepingPlayerList(); } diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index 8f94c963f2c59668d72d162f46f7505d6a6b06a5..e808b8059af035d09c24286b1e5893733906dca4 100644 +index 8f94c963f2c59668d72d162f46f7505d6a6b06a5..87c8c4c7ca52f7d804ddaff87aaf381552e1aee2 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java @@ -219,7 +219,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc @@ -208,6 +307,15 @@ index 8f94c963f2c59668d72d162f46f7505d6a6b06a5..e808b8059af035d09c24286b1e589373 private final PlayerAdvancements advancements; private final ServerStatsCounter stats; private float lastRecordedHealthAndAbsorption = Float.MIN_VALUE; +@@ -240,7 +240,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc + private Entity camera; + public boolean isChangingDimension; + public boolean seenCredits = false; +- private final ServerRecipeBook recipeBook; ++ protected ServerRecipeBook recipeBook; // Leaves - not final and private -> protected + @Nullable + private Vec3 levitationStartPos; + private int levitationStartTime; @@ -1454,6 +1454,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc this.lastSentHealth = -1.0F; this.lastSentFood = -1; @@ -220,6 +328,23 @@ index 8f94c963f2c59668d72d162f46f7505d6a6b06a5..e808b8059af035d09c24286b1e589373 // CraftBukkit start org.bukkit.event.player.PlayerChangedWorldEvent changeEvent = new org.bukkit.event.player.PlayerChangedWorldEvent(this.getBukkitEntity(), serverLevel.getWorld()); this.level().getCraftServer().getPluginManager().callEvent(changeEvent); +diff --git a/net/minecraft/server/players/GameProfileCache.java b/net/minecraft/server/players/GameProfileCache.java +index 066f84df5c31242ab542932f1e243369d0e766e2..52706e843923666940e679a83a302db7a243dd11 100644 +--- a/net/minecraft/server/players/GameProfileCache.java ++++ b/net/minecraft/server/players/GameProfileCache.java +@@ -125,6 +125,12 @@ public class GameProfileCache { + // Paper end + + public Optional get(String name) { ++ // Leaves start - fix bot ++ org.leavesmc.leaves.bot.ServerBot bot = org.leavesmc.leaves.bot.BotList.INSTANCE.getBotByName(name); ++ if (bot != null) { ++ return Optional.of(bot.getGameProfile()); ++ } ++ // Leaves end - fix bot + String string = name.toLowerCase(Locale.ROOT); + boolean stateLocked = true; try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency + GameProfileCache.GameProfileInfo gameProfileInfo = this.profilesByName.get(string); diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java index 2dffdc770529e048c4e8df7d70de59c94d3a77be..1135d32f1f275306792b95d10f76ac233e265e0d 100644 --- a/net/minecraft/server/players/PlayerList.java diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/BotRecipeBook.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/BotRecipeBook.java new file mode 100644 index 00000000..1ca36ca0 --- /dev/null +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/BotRecipeBook.java @@ -0,0 +1,56 @@ +package org.leavesmc.leaves.bot; + +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.stats.ServerRecipeBook; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeHolder; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.List; +import java.util.function.Predicate; + +public class BotRecipeBook extends ServerRecipeBook { + + public BotRecipeBook() { + super(($, $1) -> { + }); + } + + @Override + public void add(@NotNull ResourceKey> recipe) { + } + + @Override + public void remove(@NotNull ResourceKey> recipe) { + } + + @Override + public boolean contains(@NotNull ResourceKey> recipe) { + return false; + } + + @Override + public void removeHighlight(@NotNull ResourceKey> recipe) { + } + + @Override + public int addRecipes(@NotNull Collection> recipes, @NotNull ServerPlayer player) { + return 0; + } + + @Override + public int removeRecipes(@NotNull Collection> recipes, @NotNull ServerPlayer player) { + return 0; + } + + @Override + public void loadUntrusted(@NotNull Packed recipeBook, @NotNull Predicate>> predicate) { + } + + @Override + public @NotNull Packed pack() { + return new ServerRecipeBook.Packed(this.bookSettings.copy(), List.of(), List.of()); + } +} diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/ServerBot.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/ServerBot.java index 70734c9a..20e339ea 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/bot/ServerBot.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/ServerBot.java @@ -22,6 +22,7 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.ServerPlayerConnection; import net.minecraft.stats.ServerStatsCounter; +import net.minecraft.stats.Stat; import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; @@ -38,6 +39,7 @@ import net.minecraft.world.entity.projectile.ProjectileUtil; import net.minecraft.world.entity.vehicle.AbstractBoat; import net.minecraft.world.inventory.ChestMenu; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.Level; import net.minecraft.world.level.gameevent.GameEvent; @@ -71,6 +73,7 @@ import org.leavesmc.leaves.plugin.MinecraftInternalPlugin; import org.leavesmc.leaves.util.MathUtils; import java.util.ArrayList; +import java.util.Collection; import java.util.EnumSet; import java.util.List; import java.util.Map; @@ -110,6 +113,7 @@ public class ServerBot extends ServerPlayer { this.configs = configBuilder.build(); this.stats = new BotStatsCounter(server); + this.recipeBook = new BotRecipeBook(); this.container = new BotInventoryContainer(this.getInventory()); this.tracingRange = world.spigotConfig.playerTrackingRange * world.spigotConfig.playerTrackingRange; @@ -514,7 +518,7 @@ public class ServerBot extends ServerPlayer { } @Override - public boolean startRiding(Entity vehicle, boolean force) { + public boolean startRiding(@NotNull Entity vehicle, boolean force) { if (super.startRiding(vehicle, force)) { if (vehicle instanceof AbstractBoat) { this.setDeltaMovement(Vec3.ZERO); @@ -526,6 +530,32 @@ public class ServerBot extends ServerPlayer { } } + @Override + public int awardRecipes(@NotNull Collection> recipes) { + return 0; + } + + @Override + public int resetRecipes(@NotNull Collection> recipes) { + return 0; + } + + @Override + public void triggerRecipeCrafted(@NotNull RecipeHolder recipe, @NotNull List items) { + } + + @Override + public void awardKillScore(@NotNull Entity entity, @NotNull DamageSource damageSource) { + } + + @Override + public void awardStat(@NotNull Stat stat) { + } + + @Override + public void resetStat(@NotNull Stat stat) { + } + public void removeTab() { this.sendPacket(new ClientboundPlayerInfoRemovePacket(List.of(this.getUUID()))); } 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 29bd7aba..bf16fe7f 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 @@ -2,7 +2,6 @@ package org.leavesmc.leaves.bot; import net.kyori.adventure.text.Component; import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayerGameMode; import net.minecraft.world.InteractionHand; @@ -12,6 +11,7 @@ import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.GameMasterBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; @@ -52,36 +52,32 @@ public class ServerBotGameMode extends ServerPlayerGameMode { @Override public boolean destroyBlock(@NotNull BlockPos pos) { - BlockState iblockdata = this.level.getBlockState(pos); - BlockEntity tileentity = this.level.getBlockEntity(pos); - Block block = iblockdata.getBlock(); - - if (this.player.blockActionRestricted(this.level, pos, this.getGameModeForPlayer())) { + BlockState blockState = this.level.getBlockState(pos); + if (!this.player.getMainHandItem().canDestroyBlock(blockState, this.level, pos, this.player)) { return false; } else { - this.level.captureDrops = null; - 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); + BlockEntity blockEntity = this.level.getBlockEntity(pos); + Block block = blockState.getBlock(); + if (block instanceof GameMasterBlock) { + this.level.sendBlockUpdated(pos, blockState, blockState, 3); + return false; + } else { + BlockState blockState1 = org.leavesmc.leaves.command.subcommands.BlockUpdateCommand.isNoBlockUpdate() ? blockState : block.playerWillDestroy(this.level, pos, blockState, this.player); // Leaves - no block update + boolean flag = this.level.removeBlock(pos, false); + if (flag) { + block.destroy(this.level, pos, blockState1); + } - if (flag) { - block.destroy(this.level, pos, iblockdata1); + ItemStack mainHandItem = this.player.getMainHandItem(); + ItemStack itemStack = mainHandItem.copy(); + boolean hasCorrectToolForDrops = this.player.hasCorrectToolForDrops(blockState1); + mainHandItem.getItem().mineBlock(mainHandItem, this.level, blockState1, pos, this.player); + if (flag && hasCorrectToolForDrops) { + block.playerDestroy(this.level, this.player, pos, blockState1, blockEntity, itemStack, true, true); + } + + return true; } - - ItemStack itemstack = this.player.getMainHandItem(); - ItemStack itemstack1 = itemstack.copy(); - - boolean flag1 = this.player.hasCorrectToolForDrops(iblockdata1); - - itemstack.mineBlock(this.level, iblockdata1, pos, this.player); - if (flag && flag1) { - Block.dropResources(iblockdata1, this.level, pos, tileentity, this.player, itemstack1, true); - } - - if (flag) { - iblockdata.getBlock().popExperience(this.level, pos, block.getExpDrop(iblockdata, this.level, pos, itemstack, true), this.player); - } - - return true; } } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerBreakBlockAction.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerBreakBlockAction.java index a7d6b03b..470c62fb 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerBreakBlockAction.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerBreakBlockAction.java @@ -2,7 +2,11 @@ package org.leavesmc.leaves.bot.agent.actions; import net.minecraft.core.BlockPos; import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; import org.bukkit.block.Block; import org.bukkit.craftbukkit.block.CraftBlock; import org.jetbrains.annotations.NotNull; @@ -15,6 +19,7 @@ public class ServerBreakBlockAction extends ServerTimerBotAction 0) { + bot.level().destroyBlockProgress(bot.getId(), lastPos, -1); + } + lastItem = bot.getMainHandItem(); lastPos = pos; destroyProgressTime = 0; lastSentState = -1; - } - BlockState iblockdata = bot.level().getBlockState(pos); - if (!iblockdata.isAir()) { - bot.swing(InteractionHand.MAIN_HAND); - - if (iblockdata.getDestroyProgress(bot, bot.level(), pos) >= 1.0F) { - bot.gameMode.destroyAndAck(pos, 0, "insta mine"); - bot.level().destroyBlockProgress(bot.getId(), pos, -1); - bot.updateItemInHand(InteractionHand.MAIN_HAND); - finalBreak(); - return true; + if (!iblockdata.isAir()) { + bot.swing(InteractionHand.MAIN_HAND); + EnchantmentHelper.onHitBlock( + bot.level(), bot.getMainHandItem(), bot, bot, EquipmentSlot.MAINHAND, Vec3.atCenterOf(pos), iblockdata, + item -> bot.onEquippedItemBroken(item, EquipmentSlot.MAINHAND) + ); + iblockdata.attack(bot.level(), pos, bot); + float f = iblockdata.getDestroyProgress(bot, bot.level(), pos); + if (f >= 1.0F) { + bot.gameMode.destroyAndAck(pos, 0, "insta mine"); + bot.updateItemInHand(InteractionHand.MAIN_HAND); + finalBreak(); + return true; + } else { + destroyProgressTime++; + int k = (int) (f * 10.0F); + bot.level().destroyBlockProgress(bot.getId(), pos, k); + lastSentState = k; + } } - - float damage = this.incrementDestroyProgress(bot, iblockdata, pos); - if (damage >= 1.0F) { - bot.gameMode.destroyAndAck(pos, 0, "destroyed"); - bot.level().destroyBlockProgress(bot.getId(), pos, -1); - bot.updateItemInHand(InteractionHand.MAIN_HAND); - finalBreak(); - return true; + } else { + if (!iblockdata.isAir()) { + bot.swing(InteractionHand.MAIN_HAND); + float damage = this.incrementDestroyProgress(bot, iblockdata, pos); + if (damage >= 1.0F) { + bot.gameMode.destroyAndAck(pos, 0, "destroyed"); + bot.level().destroyBlockProgress(bot.getId(), pos, -1); + bot.updateItemInHand(InteractionHand.MAIN_HAND); + finalBreak(); + return true; + } } } + } else { + if (lastPos != null) { + bot.level().destroyBlockProgress(bot.getId(), lastPos, -1); + } + finalBreak(); } return false; } private void finalBreak() { lastPos = null; + lastItem = null; destroyProgressTime = 0; lastSentState = -1; }