From b7d40e0eac2cafdc3b8c80882ec00ad6d95503f2 Mon Sep 17 00:00:00 2001 From: violetc <58360096+s-yh-china@users.noreply.github.com> Date: Thu, 22 Feb 2024 19:30:54 +0800 Subject: [PATCH] Update Fakeplayer - Add action | config's event and config - Add simulation_distance config - Ignore PlayerEvent from ServerBot - Rewrite ServerBotGameMode --- patches/api/0003-Add-fakeplayer-api.patch | 102 +++++ patches/server/0010-Fakeplayer-support.patch | 434 ++++++++++++++----- 2 files changed, 435 insertions(+), 101 deletions(-) diff --git a/patches/api/0003-Add-fakeplayer-api.patch b/patches/api/0003-Add-fakeplayer-api.patch index c6b0a636..c9fed5c7 100644 --- a/patches/api/0003-Add-fakeplayer-api.patch +++ b/patches/api/0003-Add-fakeplayer-api.patch @@ -326,6 +326,108 @@ index 0000000000000000000000000000000000000000..e298722319ff0cfd52e531693ea3767e + return name; + } +} +diff --git a/src/main/java/top/leavesmc/leaves/event/bot/BotActionEvent.java b/src/main/java/top/leavesmc/leaves/event/bot/BotActionEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4b990013537337c069d8e7326ba979b1f79fb232 +--- /dev/null ++++ b/src/main/java/top/leavesmc/leaves/event/bot/BotActionEvent.java +@@ -0,0 +1,45 @@ ++package top.leavesmc.leaves.event.bot; ++ ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.NotNull; ++import top.leavesmc.leaves.entity.Bot; ++ ++public class BotActionEvent extends BotEvent implements Cancellable { ++ private static final HandlerList handlers = new HandlerList(); ++ ++ private final String actionName; ++ private final String[] actionArgs; ++ private boolean cancel = false; ++ ++ public BotActionEvent(@NotNull Bot who, String actionName, String[] actionArgs) { ++ super(who); ++ this.actionArgs = actionArgs; ++ this.actionName = actionName; ++ } ++ ++ @NotNull ++ public String[] getActionArgs() { ++ return actionArgs; ++ } ++ ++ @NotNull ++ public String getActionName() { ++ return actionName; ++ } ++ ++ @Override ++ public @NotNull HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return cancel; ++ } ++ ++ @Override ++ public void setCancelled(boolean cancel) { ++ this.cancel = cancel; ++ } ++} +diff --git a/src/main/java/top/leavesmc/leaves/event/bot/BotConfigModifyEvent.java b/src/main/java/top/leavesmc/leaves/event/bot/BotConfigModifyEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b56944006c8c6c09e155dfad321b307e1cb4d484 +--- /dev/null ++++ b/src/main/java/top/leavesmc/leaves/event/bot/BotConfigModifyEvent.java +@@ -0,0 +1,45 @@ ++package top.leavesmc.leaves.event.bot; ++ ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.jetbrains.annotations.NotNull; ++import top.leavesmc.leaves.entity.Bot; ++ ++public class BotConfigModifyEvent extends BotEvent implements Cancellable { ++ private static final HandlerList handlers = new HandlerList(); ++ ++ private final String configName; ++ private final String configValue; ++ private boolean cancel; ++ ++ public BotConfigModifyEvent(@NotNull Bot who, String configName, String configValue) { ++ super(who); ++ this.configName = configName; ++ this.configValue = configValue; ++ } ++ ++ @NotNull ++ public String getConfigName() { ++ return configName; ++ } ++ ++ @NotNull ++ public String getConfigValue() { ++ return configValue; ++ } ++ ++ @Override ++ public @NotNull HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return cancel; ++ } ++ ++ @Override ++ public void setCancelled(boolean cancel) { ++ this.cancel = cancel; ++ } ++} diff --git a/src/main/java/top/leavesmc/leaves/event/bot/BotCreateEvent.java b/src/main/java/top/leavesmc/leaves/event/bot/BotCreateEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..7cf1eb4eb3d2fe9310f9272ec53208632b87b49b diff --git a/patches/server/0010-Fakeplayer-support.patch b/patches/server/0010-Fakeplayer-support.patch index 88b3a769..b735a9eb 100644 --- a/patches/server/0010-Fakeplayer-support.patch +++ b/patches/server/0010-Fakeplayer-support.patch @@ -4,6 +4,23 @@ Date: Thu, 3 Feb 2022 12:28:15 +0800 Subject: [PATCH] Fakeplayer support +diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java +index a1c9726d25479b5326fe2fa2b0f5a98d6b2da4c5..ee17f012497fa75e152bc279cb3f7778342c49d4 100644 +--- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java ++++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java +@@ -41,6 +41,12 @@ class PaperEventManager { + throw new IllegalStateException(event.getEventName() + " may only be triggered synchronously."); + } + ++ // Leaves start - skip bot ++ if (event instanceof org.bukkit.event.player.PlayerEvent playerEvent && playerEvent.getPlayer() instanceof top.leavesmc.leaves.entity.Bot) { ++ return; ++ } ++ // Leaves end - skip bot ++ + HandlerList handlers = event.getHandlers(); + RegisteredListener[] listeners = handlers.getRegisteredListeners(); + diff --git a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java b/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java index a327973e37b5b8d4e15683ef24548482ac3dc3d5..65d82963d611a6dbbd7ca58d363854e4fad59230 100644 --- a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java @@ -91,7 +108,7 @@ index 78f02c2e068a63648f6d650a48a1cf21c5da1545..85be9376fe30f18fe4fea437955f1a60 } diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 58591bf2f63b9c5e97d9ce4188dff3366968a178..f961fc365118a06b140cac780d5618ea33c5d57a 100644 +index 58591bf2f63b9c5e97d9ce4188dff3366968a178..42b5d67e17cc62eb830ae4b3a930b48ae64dd11e 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -186,6 +186,7 @@ import org.bukkit.event.player.PlayerTeleportEvent; @@ -102,6 +119,15 @@ index 58591bf2f63b9c5e97d9ce4188dff3366968a178..f961fc365118a06b140cac780d5618ea // CraftBukkit end public class ServerPlayer extends Player { +@@ -197,7 +198,7 @@ public class ServerPlayer extends Player { + private static final int FLY_STAT_RECORDING_SPEED = 25; + public ServerGamePacketListenerImpl connection; + public final MinecraftServer server; +- public final ServerPlayerGameMode gameMode; ++ public ServerPlayerGameMode gameMode; // Leaves - final -> null + private final PlayerAdvancements advancements; + private final ServerStatsCounter stats; + private float lastRecordedHealthAndAbsorption = Float.MIN_VALUE; @@ -729,16 +730,20 @@ public class ServerPlayer extends Player { --this.invulnerableTime; } @@ -413,12 +439,29 @@ index bb9383f1a457433f9db3e78d7913616280925200..55b41ca7630db143d70137324a9de871 /** * The start ID for the counter. */ +diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +index cb427686bf77366ddc9ad133b08f42b6b34fb0f5..19ee86e42d92c33cb7e35ba07927883d4c979913 100644 +--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java ++++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +@@ -204,6 +204,12 @@ public final class LeavesConfig { + } + } + ++ @GlobalConfig(name = "use-action", category = {"modify", "fakeplayer"}) ++ public static boolean fakeplayerUseAction = true; ++ ++ @GlobalConfig(name = "modify-config", category = {"modify", "fakeplayer"}) ++ public static boolean fakeplayerModifyConfig = false; ++ + // Leaves end - modify - fakeplayer + + // Leaves start - modify - minecraft-old diff --git a/src/main/java/top/leavesmc/leaves/bot/BotCommand.java b/src/main/java/top/leavesmc/leaves/bot/BotCommand.java new file mode 100644 -index 0000000000000000000000000000000000000000..25129195532cf2f22c758407580599332035e9c0 +index 0000000000000000000000000000000000000000..fd8a1306f3179d0729a4a543405ac210acefe8d9 --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/bot/BotCommand.java -@@ -0,0 +1,331 @@ +@@ -0,0 +1,405 @@ +package top.leavesmc.leaves.bot; + +import org.bukkit.Bukkit; @@ -440,18 +483,22 @@ index 0000000000000000000000000000000000000000..25129195532cf2f22c75840758059933 +import top.leavesmc.leaves.bot.agent.BotAction; +import top.leavesmc.leaves.bot.agent.actions.CraftCustomBotAction; +import top.leavesmc.leaves.entity.Bot; ++import top.leavesmc.leaves.event.bot.BotActionEvent; ++import top.leavesmc.leaves.event.bot.BotConfigModifyEvent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; ++import java.util.Locale; +import java.util.Map; ++import java.util.stream.Stream; + +public class BotCommand extends Command { + + public BotCommand(String name) { + super(name); + this.description = "FakePlayer Command"; -+ this.usageMessage = "/bot [create | remove | action | list]"; ++ this.usageMessage = "/bot [create | remove | action | list | config]"; + this.setPermission("bukkit.command.bot"); + final PluginManager pluginManager = Bukkit.getServer().getPluginManager(); + if (pluginManager.getPermission("bukkit.command.bot") == null) { @@ -466,16 +513,19 @@ index 0000000000000000000000000000000000000000..25129195532cf2f22c75840758059933 + if (args.length <= 1) { + list.add("create"); + list.add("remove"); -+ list.add("action"); -+ list.add("config"); ++ if (LeavesConfig.fakeplayerUseAction) { ++ list.add("action"); ++ } ++ if (LeavesConfig.fakeplayerModifyConfig) { ++ list.add("config"); ++ } + list.add("list"); + } + + if (args.length == 2) { + switch (args[0]) { + case "create" -> list.add(""); -+ case "remove", "action", "config" -> -+ list.addAll(ServerBot.getBots().stream().map(e -> e.getName().getString()).toList()); ++ case "remove", "action", "config" -> list.addAll(ServerBot.getBots().stream().map(e -> e.getName().getString()).toList()); + case "list" -> list.addAll(Bukkit.getWorlds().stream().map(WorldInfo::getName).toList()); + } + } @@ -494,8 +544,14 @@ index 0000000000000000000000000000000000000000..25129195532cf2f22c75840758059933 + if (args.length == 4) { + switch (args[0]) { + case "config" -> { -+ list.add("true"); -+ list.add("false"); ++ if (args[2].equals(BotConfig.SIMULATION_DISTANCE.configName)) { ++ list.add("10"); ++ list.add("2"); ++ list.add(""); ++ } else { ++ list.add("true"); ++ list.add("false"); ++ } + } + } + } @@ -611,6 +667,10 @@ index 0000000000000000000000000000000000000000..25129195532cf2f22c75840758059933 + } + + private void onAction(CommandSender sender, String @NotNull [] args) { ++ if (!LeavesConfig.fakeplayerUseAction) { ++ return; ++ } ++ + if (args.length < 3) { + sender.sendMessage(ChatColor.RED + "Use /bot action to make fakeplayer do action"); + return; @@ -643,15 +703,16 @@ index 0000000000000000000000000000000000000000..25129195532cf2f22c75840758059933 + player = bot.getBukkitEntity(); + } + ++ String[] realArgs = new String[args.length - 3]; ++ if (realArgs.length != 0) { ++ System.arraycopy(args, 3, realArgs, 0, realArgs.length); ++ } ++ + BotAction newAction; + if (action instanceof CraftCustomBotAction customBotAction) { -+ String[] realArgs = new String[args.length - 3]; -+ if (realArgs.length != 0) { -+ System.arraycopy(args, 3, realArgs, 0, realArgs.length); -+ } + newAction = customBotAction.getNew(player, realArgs); + } else { -+ newAction = action.getNew(player.getHandle(), action.getArgument().parse(3, args)); ++ newAction = action.getNew(player.getHandle(), action.getArgument().parse(0, realArgs)); + } + + if (newAction == null) { @@ -659,13 +720,32 @@ index 0000000000000000000000000000000000000000..25129195532cf2f22c75840758059933 + return; + } + -+ bot.setBotAction(newAction); -+ sender.sendMessage("Action " + action.getName() + " has been issued to " + bot.getName().getString()); ++ BotActionEvent event = new BotActionEvent(bot.getBukkitEntity(), newAction.getName(), realArgs); ++ Bukkit.getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ bot.setBotAction(newAction); ++ sender.sendMessage("Action " + action.getName() + " has been issued to " + bot.getName().getString()); ++ } ++ } ++ ++ public enum BotConfig { ++ SKIP_SLEEP, SPAWN_PHANTOM, ALWAYS_SEND_DATA, SIMULATION_DISTANCE; ++ ++ public final String configName; ++ ++ BotConfig() { ++ this.configName = this.name().toLowerCase(Locale.ROOT); ++ } + } + -+ private static final List acceptConfig = List.of("skip_sleep", "spawn_phantom", "always_send_data"); ++ private static final List acceptConfig = Stream.of(BotConfig.values()).map(config -> config.configName).toList(); + + private void onConfig(CommandSender sender, String @NotNull [] args) { ++ if (!LeavesConfig.fakeplayerModifyConfig) { ++ return; ++ } ++ + if (args.length < 3) { + sender.sendMessage(ChatColor.RED + "Use /bot config to modify fakeplayer's config"); + return; @@ -682,26 +762,63 @@ index 0000000000000000000000000000000000000000..25129195532cf2f22c75840758059933 + return; + } + ++ BotConfig config = BotConfig.valueOf(args[2].toUpperCase(Locale.ROOT)); + if (args.length < 4) { -+ switch (args[2]) { -+ case "skip_sleep" -> sender.sendMessage(bot.getScoreboardName() + "'s skip_sleep: " + bot.fauxSleeping); -+ case "spawn_phantom" -> { ++ String value = null; ++ switch (config) { ++ case SKIP_SLEEP -> value = String.valueOf(bot.fauxSleeping); ++ case SPAWN_PHANTOM -> { + sender.sendMessage(bot.getScoreboardName() + "'s spawn_phantom: " + bot.spawnPhantom); + if (bot.spawnPhantom) { + sender.sendMessage(bot.getScoreboardName() + "'s not_sleeping_ticks: " + bot.notSleepTicks); + } ++ return; + } -+ case "always_send_data" -> -+ sender.sendMessage(bot.getScoreboardName() + "'s always_send_data: " + bot.alwaysSendData); ++ case ALWAYS_SEND_DATA -> value = String.valueOf(bot.alwaysSendData); ++ case SIMULATION_DISTANCE -> value = String.valueOf(bot.getBukkitEntity().getSimulationDistance()); + } ++ sender.sendMessage(bot.getScoreboardName() + "'s " + config.configName + ": " + value); + } else { -+ boolean value = args[3].equals("true"); -+ switch (args[2]) { -+ case "skip_sleep" -> bot.fauxSleeping = value; -+ case "spawn_phantom" -> bot.spawnPhantom = value; -+ case "always_send_data" -> bot.alwaysSendData = value; ++ String value = args[3]; ++ ++ BotConfigModifyEvent event = new BotConfigModifyEvent(bot.getBukkitEntity(), config.configName, value); ++ Bukkit.getPluginManager().callEvent(event); ++ ++ if (event.isCancelled()) { ++ return; ++ } ++ ++ switch (config) { ++ case SKIP_SLEEP -> { ++ boolean realValue = value.equals("true"); ++ bot.fauxSleeping = realValue; ++ value = String.valueOf(realValue); ++ } ++ case SPAWN_PHANTOM -> { ++ boolean realValue = value.equals("true"); ++ bot.spawnPhantom = realValue; ++ value = String.valueOf(realValue); ++ } ++ case ALWAYS_SEND_DATA -> { ++ boolean realValue = value.equals("true"); ++ bot.alwaysSendData = realValue; ++ value = String.valueOf(realValue); ++ } ++ case SIMULATION_DISTANCE -> { ++ try { ++ int realValue = Integer.parseInt(value); ++ if (realValue < 2 || realValue > 32) { ++ sender.sendMessage("simulation_distance must be a number between 2 and 32, got: " + value); ++ return; ++ } ++ bot.getBukkitEntity().setSimulationDistance(realValue); ++ } catch (NumberFormatException e) { ++ sender.sendMessage("simulation_distance must be a number between 2 and 32, got: " + value); ++ return; ++ } ++ } + } -+ sender.sendMessage(bot.getScoreboardName() + "'s " + args[2] + " changed: " + value); ++ sender.sendMessage(bot.getScoreboardName() + "'s " + config.configName + " changed: " + value); + } + } + @@ -1218,10 +1335,10 @@ index 0000000000000000000000000000000000000000..daaece30b2a3983f1cc9ee9a851e8f37 +} diff --git a/src/main/java/top/leavesmc/leaves/bot/ServerBot.java b/src/main/java/top/leavesmc/leaves/bot/ServerBot.java new file mode 100644 -index 0000000000000000000000000000000000000000..c95adbad75fb1dca94a53990b5ad522795783748 +index 0000000000000000000000000000000000000000..a2dbfe898adf918a52ae639b0e0985e756ca826a --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/bot/ServerBot.java -@@ -0,0 +1,735 @@ +@@ -0,0 +1,716 @@ +package top.leavesmc.leaves.bot; + +import com.google.common.collect.Lists; @@ -1334,6 +1451,7 @@ index 0000000000000000000000000000000000000000..c95adbad75fb1dca94a53990b5ad5227 + this.entityData.set(new EntityDataAccessor<>(16, EntityDataSerializers.INT), 0xFF); + this.entityData.set(Player.DATA_PLAYER_MODE_CUSTOMISATION, (byte) -2); + ++ this.gameMode = new ServerBotGameMode(this); + this.velocity = new Vec3(this.xxa, this.yya, this.zza); + this.noFallTicks = 60; + this.fireTicks = 0; @@ -1617,39 +1735,19 @@ index 0000000000000000000000000000000000000000..c95adbad75fb1dca94a53990b5ad5227 + @Override + public void onItemPickup(@NotNull ItemEntity item) { + super.onItemPickup(item); -+ this.updateItemInMainHand(); -+ } -+ -+ public void updateItemInMainHand() { -+ tryReplenishOrReplaceInMainHand(); -+ detectEquipmentUpdatesPublic(); -+ } -+ -+ public void updateItemInOffHand() { -+ tryReplenishOrReplaceInOffHand(); -+ detectEquipmentUpdatesPublic(); -+ } -+ -+ public void tryReplenishOrReplaceInOffHand() { -+ net.minecraft.world.item.ItemStack offhand = getOffhandItem(); -+ -+ if (!offhand.isEmpty()) { -+ BotUtil.replenishment(offhand, getInventory().items); -+ if (BotUtil.isDamage(offhand, 10)) { -+ BotUtil.replaceTool(EquipmentSlot.OFFHAND, this); -+ } -+ } ++ this.updateItemInHand(InteractionHand.MAIN_HAND); + } + -+ public void tryReplenishOrReplaceInMainHand() { -+ net.minecraft.world.item.ItemStack mainHand = getMainHandItem(); ++ public void updateItemInHand(InteractionHand hand) { ++ net.minecraft.world.item.ItemStack item = getItemInHand(hand); + -+ if (!mainHand.isEmpty()) { -+ BotUtil.replenishment(mainHand, getInventory().items); -+ if (BotUtil.isDamage(mainHand, 10)) { -+ BotUtil.replaceTool(EquipmentSlot.MAINHAND, this); ++ if (!item.isEmpty()) { ++ BotUtil.replenishment(item, getInventory().items); ++ if (BotUtil.isDamage(item, 10)) { ++ BotUtil.replaceTool(hand == InteractionHand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND, this); + } + } ++ detectEquipmentUpdatesPublic(); + } + + @Override @@ -1687,7 +1785,7 @@ index 0000000000000000000000000000000000000000..c95adbad75fb1dca94a53990b5ad5227 + } + + @Override -+ public void knockback(double strength, double x, double z, @NotNull Entity knockingBackEntity, EntityKnockbackEvent.KnockbackCause cause) { ++ public void knockback(double strength, double x, double z, @Nullable Entity knockingBackEntity, EntityKnockbackEvent.@NotNull KnockbackCause cause) { + strength *= 1.0D - this.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE); + if (strength > 0.0D) { + this.hasImpulse = true; @@ -1731,15 +1829,12 @@ index 0000000000000000000000000000000000000000..c95adbad75fb1dca94a53990b5ad5227 + this.getBukkitEntity().setRotation(yaw, pitch); + } + -+ public void punch() { -+ swing(InteractionHand.MAIN_HAND); -+ } -+ + public void attack(@NotNull Entity target) { + super.attack(target); -+ punch(); ++ swing(InteractionHand.MAIN_HAND); + } + ++ @Override + public void jumpFromGround() { + double jumpPower = (double) this.getJumpPower() + this.getJumpBoostPower(); + this.addDeltaMovement(new Vec3(0, jumpPower, 0)); @@ -1751,6 +1846,9 @@ index 0000000000000000000000000000000000000000..c95adbad75fb1dca94a53990b5ad5227 + } + + public void setBotAction(BotAction action) { ++ if (!LeavesConfig.fakeplayerUseAction) { ++ return; ++ } + if (action instanceof StopAction) { + this.actions.clear(); + } @@ -1957,6 +2055,142 @@ index 0000000000000000000000000000000000000000..c95adbad75fb1dca94a53990b5ad5227 + } + } +} +diff --git a/src/main/java/top/leavesmc/leaves/bot/ServerBotGameMode.java b/src/main/java/top/leavesmc/leaves/bot/ServerBotGameMode.java +new file mode 100644 +index 0000000000000000000000000000000000000000..289894276faefac6c8410f5c78b5dafc15df5b4f +--- /dev/null ++++ b/src/main/java/top/leavesmc/leaves/bot/ServerBotGameMode.java +@@ -0,0 +1,130 @@ ++package top.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; ++import net.minecraft.world.InteractionResult; ++import net.minecraft.world.item.ItemStack; ++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.entity.BlockEntity; ++import net.minecraft.world.level.block.state.BlockState; ++import net.minecraft.world.phys.BlockHitResult; ++import org.bukkit.event.player.PlayerGameModeChangeEvent; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public class ServerBotGameMode extends ServerPlayerGameMode { ++ ++ public ServerBotGameMode(ServerBot bot) { ++ super(bot); ++ super.setGameModeForPlayer(GameType.SURVIVAL, null); ++ } ++ ++ @Override ++ public boolean changeGameModeForPlayer(@NotNull GameType gameMode) { ++ return false; ++ } ++ ++ @Nullable ++ @Override ++ public PlayerGameModeChangeEvent changeGameModeForPlayer(@NotNull GameType gameMode, PlayerGameModeChangeEvent.@NotNull Cause cause, @Nullable Component cancelMessage) { ++ return null; ++ } ++ ++ @Override ++ protected void setGameModeForPlayer(@NotNull GameType gameMode, @Nullable GameType previousGameMode) { ++ } ++ ++ @Override ++ public void tick() { ++ } ++ ++ @Override ++ public void destroyAndAck(@NotNull BlockPos pos, int sequence, @NotNull String reason) { ++ this.destroyBlock(pos); ++ } ++ ++ @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())) { ++ return false; ++ } else { ++ this.level.captureDrops = null; ++ BlockState iblockdata1 = block.playerWillDestroy(this.level, pos, iblockdata, this.player); ++ boolean flag = this.level.removeBlock(pos, false); ++ ++ if (flag) { ++ block.destroy(this.level, pos, iblockdata1); ++ } ++ ++ 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; ++ } ++ } ++ ++ @NotNull ++ @Override ++ public InteractionResult useItemOn(@NotNull ServerPlayer player, Level world, @NotNull ItemStack stack, @NotNull InteractionHand hand, BlockHitResult hitResult) { ++ BlockPos blockposition = hitResult.getBlockPos(); ++ BlockState iblockdata = world.getBlockState(blockposition); ++ InteractionResult enuminteractionresult = InteractionResult.PASS; ++ ++ if (!iblockdata.getBlock().isEnabled(world.enabledFeatures())) { ++ return InteractionResult.FAIL; ++ } ++ ++ if (player.getCooldowns().isOnCooldown(stack.getItem())) { ++ return InteractionResult.PASS; ++ } ++ ++ this.firedInteract = true; ++ this.interactResult = false; ++ this.interactPosition = blockposition.immutable(); ++ this.interactHand = hand; ++ this.interactItemStack = stack.copy(); ++ ++ boolean flag = !player.getMainHandItem().isEmpty() || !player.getOffhandItem().isEmpty(); ++ boolean flag1 = player.isSecondaryUseActive() && flag; ++ ++ if (!flag1) { ++ enuminteractionresult = iblockdata.use(world, player, hand, hitResult); ++ ++ if (enuminteractionresult.consumesAction()) { ++ return enuminteractionresult; ++ } ++ } ++ ++ if (!stack.isEmpty() && enuminteractionresult != InteractionResult.SUCCESS && !this.interactResult) { ++ UseOnContext itemactioncontext = new UseOnContext(player, hand, hitResult); ++ return stack.useOn(itemactioncontext); ++ } ++ return enuminteractionresult; ++ } ++ ++ @Override ++ public void setLevel(@NotNull ServerLevel world) { ++ } ++} diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/Actions.java b/src/main/java/top/leavesmc/leaves/bot/agent/Actions.java new file mode 100644 index 0000000000000000000000000000000000000000..a7e98848e400641077ac567d9ea9a58c32123c98 @@ -2172,10 +2406,10 @@ index 0000000000000000000000000000000000000000..609605b21cfe5af8876f76ea4922e379 +} diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/AttackSelfAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/AttackSelfAction.java new file mode 100644 -index 0000000000000000000000000000000000000000..5a0e5626751d0b6ea12a6074b5626937b6668608 +index 0000000000000000000000000000000000000000..8543709b07ea4e598764d20b3ea4a6409496c890 --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/AttackSelfAction.java -@@ -0,0 +1,42 @@ +@@ -0,0 +1,39 @@ +package top.leavesmc.leaves.bot.agent.actions; + +import com.google.common.base.Predicates; @@ -2205,14 +2439,11 @@ index 0000000000000000000000000000000000000000..5a0e5626751d0b6ea12a6074b5626937 + + @Override + public boolean doTick(@NotNull ServerBot bot) { -+ List entities = bot.level().getEntities((Entity) null, bot.getBoundingBox(), Predicates.alwaysTrue()); ++ List entities = bot.level().getEntities((Entity) null, bot.getBoundingBox(), (entity -> entity != bot)); + if (!entities.isEmpty()) { -+ for (int i = 0; i < entities.size(); i++) { -+ Entity entity = entities.get(i); -+ if (entity != bot) { -+ bot.attack(entity); -+ return true; -+ } ++ for (Entity entity : entities) { ++ bot.attack(entity); ++ return true; + } + } + return false; @@ -2220,14 +2451,15 @@ index 0000000000000000000000000000000000000000..5a0e5626751d0b6ea12a6074b5626937 +} diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/BreakBlockAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/BreakBlockAction.java new file mode 100644 -index 0000000000000000000000000000000000000000..2a3ca671b43fec658bf5cd8a6eb08b476a766c29 +index 0000000000000000000000000000000000000000..12af5b8f2bb1a2c8718e3e26e17189609bb5268f --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/BreakBlockAction.java -@@ -0,0 +1,104 @@ +@@ -0,0 +1,105 @@ +package top.leavesmc.leaves.bot.agent.actions; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; ++import net.minecraft.world.InteractionHand; +import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.block.Block; +import org.bukkit.craftbukkit.block.CraftBlock; @@ -2286,12 +2518,12 @@ index 0000000000000000000000000000000000000000..2a3ca671b43fec658bf5cd8a6eb08b47 + + BlockState iblockdata = bot.level().getBlockState(pos); + if (!iblockdata.isAir()) { -+ bot.punch(); ++ 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.updateItemInMainHand(); ++ bot.updateItemInHand(InteractionHand.MAIN_HAND); + finalBreak(); + return true; + } @@ -2300,7 +2532,7 @@ index 0000000000000000000000000000000000000000..2a3ca671b43fec658bf5cd8a6eb08b47 + if (damage >= 1.0F) { + bot.gameMode.destroyAndAck(pos, 0, "destroyed"); + bot.level().destroyBlockProgress(bot.getId(), pos, -1); -+ bot.updateItemInMainHand(); ++ bot.updateItemInHand(InteractionHand.MAIN_HAND); + finalBreak(); + return true; + } @@ -2724,7 +2956,7 @@ index 0000000000000000000000000000000000000000..58c815bd0ebfd455fcf4903ee5ced6b8 +} diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemAction.java new file mode 100644 -index 0000000000000000000000000000000000000000..5dc3fbf8e62ccffc8291962c835a568efd65d7af +index 0000000000000000000000000000000000000000..eb81cdc139814d3374f97ed368c4a59676ca25e5 --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemAction.java @@ -0,0 +1,33 @@ @@ -2756,14 +2988,14 @@ index 0000000000000000000000000000000000000000..5dc3fbf8e62ccffc8291962c835a568e + + @Override + public boolean doTick(@NotNull ServerBot bot) { -+ bot.punch(); -+ bot.updateItemInMainHand(); -+ return bot.getInventory().getSelected().use(bot.level(), bot, InteractionHand.MAIN_HAND).getResult().consumesAction(); ++ bot.swing(InteractionHand.MAIN_HAND); ++ bot.updateItemInHand(InteractionHand.MAIN_HAND); ++ return bot.gameMode.useItem(bot, bot.level(), bot.getItemInHand(InteractionHand.MAIN_HAND), InteractionHand.MAIN_HAND).consumesAction(); + } +} diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOffHandAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOffHandAction.java new file mode 100644 -index 0000000000000000000000000000000000000000..345932e779f5187355ca722c2bb9b05f384660a1 +index 0000000000000000000000000000000000000000..00c85bae0a278d3aad793635aa80859d94101f49 --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOffHandAction.java @@ -0,0 +1,33 @@ @@ -2795,14 +3027,14 @@ index 0000000000000000000000000000000000000000..345932e779f5187355ca722c2bb9b05f + + @Override + public boolean doTick(@NotNull ServerBot bot) { -+ bot.punch(); -+ bot.updateItemInOffHand(); -+ return bot.getInventory().getSelected().use(bot.level(), bot, InteractionHand.OFF_HAND).getResult().consumesAction(); ++ bot.swing(InteractionHand.OFF_HAND); ++ bot.updateItemInHand(InteractionHand.OFF_HAND); ++ return bot.gameMode.useItem(bot, bot.level(), bot.getItemInHand(InteractionHand.OFF_HAND), InteractionHand.OFF_HAND).consumesAction(); + } +} diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOnAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOnAction.java new file mode 100644 -index 0000000000000000000000000000000000000000..f4837f60909763df89ea7474f70dd0236360e657 +index 0000000000000000000000000000000000000000..9731e1c3717c344d3a739e90f28a5d24243f7661 --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOnAction.java @@ -0,0 +1,56 @@ @@ -2846,7 +3078,7 @@ index 0000000000000000000000000000000000000000..f4837f60909763df89ea7474f70dd023 + HitResult result = bot.getRayTrace(5, ClipContext.Fluid.NONE); + if (result instanceof BlockHitResult blockHitResult) { + BlockState state = bot.serverLevel().getBlockState(blockHitResult.getBlockPos()); -+ bot.punch(); ++ bot.swing(InteractionHand.MAIN_HAND); + if (state.getBlock() == Blocks.TRAPPED_CHEST) { + BlockEntity entity = bot.serverLevel().getBlockEntity(blockHitResult.getBlockPos()); + if (entity instanceof TrappedChestBlockEntity chestBlockEntity) { @@ -2855,7 +3087,7 @@ index 0000000000000000000000000000000000000000..f4837f60909763df89ea7474f70dd023 + return true; + } + } else { -+ bot.updateItemInMainHand(); ++ bot.updateItemInHand(InteractionHand.MAIN_HAND); + return bot.gameMode.useItemOn(bot, bot.level(), bot.getItemInHand(InteractionHand.MAIN_HAND), InteractionHand.MAIN_HAND, (BlockHitResult) result).consumesAction(); + } + } @@ -2864,7 +3096,7 @@ index 0000000000000000000000000000000000000000..f4837f60909763df89ea7474f70dd023 +} diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOnOffhandAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOnOffhandAction.java new file mode 100644 -index 0000000000000000000000000000000000000000..4ab84fba3624a8e8c4d345c03fe678a012a5c367 +index 0000000000000000000000000000000000000000..f3104e0a4ee367ac4af0e093bcbbff2c997fc734 --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOnOffhandAction.java @@ -0,0 +1,56 @@ @@ -2908,7 +3140,7 @@ index 0000000000000000000000000000000000000000..4ab84fba3624a8e8c4d345c03fe678a0 + HitResult result = bot.getRayTrace(5, ClipContext.Fluid.NONE); + if (result instanceof BlockHitResult blockHitResult) { + BlockState state = bot.serverLevel().getBlockState(blockHitResult.getBlockPos()); -+ bot.punch(); ++ bot.swing(InteractionHand.OFF_HAND); + if (state.getBlock() == Blocks.TRAPPED_CHEST) { + BlockEntity entity = bot.serverLevel().getBlockEntity(blockHitResult.getBlockPos()); + if (entity instanceof TrappedChestBlockEntity chestBlockEntity) { @@ -2917,7 +3149,7 @@ index 0000000000000000000000000000000000000000..4ab84fba3624a8e8c4d345c03fe678a0 + return true; + } + } else { -+ bot.updateItemInMainHand(); ++ bot.updateItemInHand(InteractionHand.OFF_HAND); + return bot.gameMode.useItemOn(bot, bot.level(), bot.getItemInHand(InteractionHand.OFF_HAND), InteractionHand.OFF_HAND, (BlockHitResult) result).consumesAction(); + } + } @@ -2926,7 +3158,7 @@ index 0000000000000000000000000000000000000000..4ab84fba3624a8e8c4d345c03fe678a0 +} diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemToAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemToAction.java new file mode 100644 -index 0000000000000000000000000000000000000000..cc8689ee726144f220e4ccc5cd418b79a29b79ab +index 0000000000000000000000000000000000000000..f9a2da353114cfb8a5fd70671c0baefd9aaac627 --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemToAction.java @@ -0,0 +1,38 @@ @@ -2961,16 +3193,16 @@ index 0000000000000000000000000000000000000000..cc8689ee726144f220e4ccc5cd418b79 + public boolean doTick(@NotNull ServerBot bot) { + EntityHitResult result = bot.getTargetEntity(3); + if (result != null) { -+ bot.punch(); -+ bot.updateItemInMainHand(); -+ return result.getEntity().interact(bot, InteractionHand.MAIN_HAND).consumesAction(); ++ bot.swing(InteractionHand.MAIN_HAND); ++ bot.updateItemInHand(InteractionHand.MAIN_HAND); ++ return bot.interactOn(result.getEntity(), InteractionHand.MAIN_HAND).consumesAction(); + } + return false; + } +} diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemToOffhandAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemToOffhandAction.java new file mode 100644 -index 0000000000000000000000000000000000000000..1fde496c993ec0c961a63b32a8088479da88c91d +index 0000000000000000000000000000000000000000..1398b7d07e5c510fffce81dc2d103f9686ccd7df --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemToOffhandAction.java @@ -0,0 +1,38 @@ @@ -3005,9 +3237,9 @@ index 0000000000000000000000000000000000000000..1fde496c993ec0c961a63b32a8088479 + public boolean doTick(@NotNull ServerBot bot) { + EntityHitResult result = bot.getTargetEntity(3); + if (result != null) { -+ bot.punch(); -+ bot.updateItemInOffHand(); -+ return result.getEntity().interact(bot, InteractionHand.OFF_HAND).consumesAction(); ++ bot.swing(InteractionHand.OFF_HAND); ++ bot.updateItemInHand(InteractionHand.OFF_HAND); ++ return bot.interactOn(result.getEntity(), InteractionHand.OFF_HAND).consumesAction(); + } + return false; + }