diff --git a/README.md b/README.md index 85f3898..1a562ea 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,9 @@ + /fp config get - 查看个性化配置 + /fp drop - 丢弃手上物品 + /fp dropinv - 丢弃背包物品 ++ /fp look - 让假人看向指定位置 ++ /fp move - 让家人移动 ++ /fp jump - 让假人跳跃 + /fp attack - 让假人点击鼠标左键 **(实验性)** + /fp use - 让假人点击鼠标右键 **(实验性)** + /fp cmd - 让假人执行他有权限执行的命令 diff --git a/src/main/java/io/github/hello09x/fakeplayer/command/AbstractCommand.java b/src/main/java/io/github/hello09x/fakeplayer/command/AbstractCommand.java index 953ccd9..7a84ba7 100644 --- a/src/main/java/io/github/hello09x/fakeplayer/command/AbstractCommand.java +++ b/src/main/java/io/github/hello09x/fakeplayer/command/AbstractCommand.java @@ -21,7 +21,7 @@ public abstract class AbstractCommand { protected final FakeplayerManager fakeplayerManager = FakeplayerManager.instance; - public static Argument targetArgument(@NotNull String nodeName) { + public static Argument target(@NotNull String nodeName) { return new CustomArgument<>(new StringArgument(nodeName), info -> { var sender = info.sender(); return sender.isOp() @@ -44,7 +44,7 @@ public abstract class AbstractCommand { })); } - public static Argument> multiTargetArgument(@NotNull String nodeName) { + public static Argument> targets(@NotNull String nodeName) { return new CustomArgument, String>(new StringArgument(nodeName), info -> { var sender = info.sender(); var arg = info.currentInput(); diff --git a/src/main/java/io/github/hello09x/fakeplayer/command/ActionCommand.java b/src/main/java/io/github/hello09x/fakeplayer/command/ActionCommand.java index eb85968..b36f266 100644 --- a/src/main/java/io/github/hello09x/fakeplayer/command/ActionCommand.java +++ b/src/main/java/io/github/hello09x/fakeplayer/command/ActionCommand.java @@ -2,10 +2,19 @@ package io.github.hello09x.fakeplayer.command; import dev.jorel.commandapi.exceptions.WrapperCommandSyntaxException; import dev.jorel.commandapi.executors.CommandArguments; +import dev.jorel.commandapi.executors.CommandExecutor; import io.github.hello09x.fakeplayer.entity.action.Action; import io.github.hello09x.fakeplayer.entity.action.ActionSetting; import io.github.hello09x.fakeplayer.entity.action.PlayerActionManager; +import io.github.hello09x.fakeplayer.util.MathUtils; +import io.github.hello09x.fakeplayer.util.Unwrapper; +import io.papermc.paper.entity.LookAnchor; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerPlayer; +import org.apache.commons.lang3.StringUtils; +import org.bukkit.Location; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import static net.kyori.adventure.text.Component.text; @@ -19,9 +28,36 @@ public class ActionCommand extends AbstractCommand { private final PlayerActionManager actionManager = PlayerActionManager.instance; + private static String toLocationString(@NotNull Location location) { + return StringUtils.joinWith(", ", + MathUtils.round(location.getX(), 0.5), + MathUtils.round(location.getY(), 0.5), + MathUtils.round(location.getZ(), 0.5)); + } + + public CommandExecutor action(@NotNull Action action, @NotNull ActionSetting setting) { + return (sender, args) -> action(sender, args, action, setting.clone()); + } + public void action(@NotNull CommandSender sender, @NotNull CommandArguments args, @NotNull Action action, @NotNull ActionSetting setting) throws WrapperCommandSyntaxException { var target = getTarget(sender, args); actionManager.setAction(target, action, setting); + + String desc; + if (setting.equals(ActionSetting.stop())) { + desc = " 已停止"; + } else if (setting.equals(ActionSetting.once())) { + desc = ""; + } else { + desc = " 开始"; + } + + sender.sendMessage(textOfChildren( + text(target.getName()), + text(desc, GRAY), + text(" "), + text(action.name, GRAY) + )); } public void sneak(@NotNull CommandSender sender, @NotNull CommandArguments args) throws WrapperCommandSyntaxException { @@ -36,10 +72,77 @@ public class ActionCommand extends AbstractCommand { sender.sendMessage(textOfChildren( text(target.getName(), WHITE), - text("现在", GRAY), + text(" 现在", GRAY), text(sneaking ? "潜行中" : "取消了潜行", GRAY) )); + } + public void lookAt(@NotNull CommandSender sender, @NotNull CommandArguments args) throws WrapperCommandSyntaxException { + var target = getTarget(sender, args); + var location = (Location) args.get("location"); + target.lookAt(location, LookAnchor.EYES); + sender.sendMessage(textOfChildren( + text(target.getName(), WHITE), + text(" 正在看向 ", GRAY), + text(toLocationString(location), GRAY) + )); + } + + public CommandExecutor look(@NotNull Direction direction) { + return (sender, args) -> { + var target = getTarget(sender, args); + look(target, direction); + sender.sendMessage(textOfChildren( + text(target.getName(), WHITE), + text(" 看向 ", GRAY), + text(switch (direction) { + case DOWN -> "下方"; + case UP -> "上方"; + case NORTH -> "北边"; + case SOUTH -> "南边"; + case WEST -> "西边"; + case EAST -> "东边"; + }, GRAY) + )); + }; + } + + private void look( + @NotNull Player target, + @NotNull Direction direction + ) { + var player = Unwrapper.getServerPlayer(target); + switch (direction) { + case NORTH -> look(player, 180, 0); + case SOUTH -> look(player, 0, 0); + case EAST -> look(player, -90, 0); + case WEST -> look(player, 90, 0); + case UP -> look(player, player.getYRot(), -90); + case DOWN -> look(player, player.getYRot(), 90); + } + } + + private void look(@NotNull ServerPlayer player, float yaw, float pitch) { + player.setYRot(yaw % 360); + player.setXRot(MathUtils.clamp(pitch, -90, 90)); + } + + public CommandExecutor move(float forward, float strafing) { + return (sender, args) -> { + var target = getTarget(sender, args); + var player = Unwrapper.getServerPlayer(target); + float vel = target.isSneaking() ? 0.3F : 1.0F; + if (forward != 0.0F) { + player.zza = vel * forward; + } + if (strafing != 0.0F) { + player.xxa = vel * strafing; + } + sender.sendMessage(textOfChildren( + text(target.getName()), + text(" 动了一下", GRAY) + )); + }; } } diff --git a/src/main/java/io/github/hello09x/fakeplayer/command/CmdCommand.java b/src/main/java/io/github/hello09x/fakeplayer/command/CmdCommand.java index beca810..be37233 100644 --- a/src/main/java/io/github/hello09x/fakeplayer/command/CmdCommand.java +++ b/src/main/java/io/github/hello09x/fakeplayer/command/CmdCommand.java @@ -9,12 +9,17 @@ import org.jetbrains.annotations.NotNull; import java.util.Objects; import static net.kyori.adventure.text.Component.text; -import static net.kyori.adventure.text.format.NamedTextColor.RED; +import static net.kyori.adventure.text.Component.textOfChildren; +import static net.kyori.adventure.text.format.NamedTextColor.*; public class CmdCommand extends AbstractCommand { public final static CmdCommand instance = new CmdCommand(); + private static String toCommandString(@NotNull CommandResult command) { + return "/" + command.command().getName() + String.join(" ", command.args()); + } + public void cmd(@NotNull CommandSender sender, @NotNull CommandArguments args) throws WrapperCommandSyntaxException { var target = getTarget(sender, args); var cmd = Objects.requireNonNull((CommandResult) args.get("command")); @@ -25,7 +30,20 @@ public class CmdCommand extends AbstractCommand { return; } - cmd.execute(target); + if (!cmd.execute(target)) { + sender.sendMessage(textOfChildren( + text(target.getName(), WHITE), + text(" 执行命令失败: ", GRAY), + text(toCommandString(cmd), RED), + text(" , 请检查命令是否正确以及假人是否有权限", GRAY) + )); + } + + sender.sendMessage(textOfChildren( + text(target.getName(), WHITE), + text(" 成功执行了命令: ", GRAY), + text(toCommandString(cmd), YELLOW) + )); } } diff --git a/src/main/java/io/github/hello09x/fakeplayer/command/Commands.java b/src/main/java/io/github/hello09x/fakeplayer/command/Commands.java index b1dd529..82d1631 100644 --- a/src/main/java/io/github/hello09x/fakeplayer/command/Commands.java +++ b/src/main/java/io/github/hello09x/fakeplayer/command/Commands.java @@ -8,12 +8,15 @@ import dev.jorel.commandapi.arguments.MultiLiteralArgument; import dev.jorel.commandapi.executors.CommandExecutor; import io.github.hello09x.fakeplayer.entity.action.Action; import io.github.hello09x.fakeplayer.entity.action.ActionSetting; +import net.minecraft.core.Direction; import org.jetbrains.annotations.NotNull; -import java.util.List; +import java.util.Arrays; -import static io.github.hello09x.fakeplayer.command.AbstractCommand.multiTargetArgument; -import static io.github.hello09x.fakeplayer.command.AbstractCommand.targetArgument; +import static io.github.hello09x.fakeplayer.command.AbstractCommand.target; +import static io.github.hello09x.fakeplayer.command.AbstractCommand.targets; +import static io.github.hello09x.fakeplayer.command.ConfigCommand.config; +import static io.github.hello09x.fakeplayer.command.ConfigCommand.configValue; public class Commands { @@ -28,11 +31,11 @@ public class Commands { private final static String PERMISSION_CMD = "fakeplayer.cmd"; public static void register() { - new CommandAPICommand("fakeplayer") + command("fakeplayer") .withAliases("fp") .withHelp( - "假人相关命令", - "fakeplayer 可以用来创建一个模拟为玩家的假人, 能保持附近区块的刷新、触发怪物生成。同时还提供了一些操作命令让你控制假人的物品、动作等等。" + "假人", + "可以创建模拟玩家的假人, 能保持附近区块的刷新、触发怪物生成。同时还提供了一些操作命令让你控制假人的物品、动作等等。" ) .withUsage( "§6/fp spawn §7- §f创建假人", @@ -47,133 +50,179 @@ public class Commands { "§6/fp health [假人] §7- §f查看生命值", "§6/fp exp [假人] §7- §f查看经验值", "§6/fp expme [假人] §7- §f转移经验值", + "§6/fp attack [假人] §7- §攻击/破坏", + "§6/fp use [假人] §7- §f使用/交互/放置", + "§6/fp jump [假人] §7- §f跳跃", "§6/fp drop [假人] [-a|--all] §7- §f丢弃手上物品", "§6/fp dropinv [假人] §7- §f丢弃背包物品", - "§6/fp sneak [假人] §7- §f开启/取消潜行", - "§6/fp attack [假人] §7- §f模拟鼠标左键", - "§6/fp use [假人] §7- §f模拟鼠标右键", - "§6/fp cmd §7- §f让假人执行命令", + "§6/fp look §7- §f看向指定位置", + "§6/fp move §7- §f移动假人", + "§6/fp cmd §7- §f执行命令", "§6/fp reload §7- §f重载配置文件" ) .withSubcommands( - new CommandAPICommand("help") + command("help") .withAliases("?") .withOptionalArguments(new IntegerArgument("page", 1)) .executesPlayer(HelpCommand.instance::help), - new CommandAPICommand("spawn") + command("spawn") .withPermission(PERMISSION_SPAWN) - .withOptionalArguments(new LocationArgument("location").withPermission(PERMISSION_SPAWN_LOCATION)) + .withOptionalArguments(location("location").withPermission(PERMISSION_SPAWN_LOCATION)) .executes(SpawnCommand.instance::spawn), - new CommandAPICommand("kill") + command("kill") .withPermission(PERMISSION_SPAWN) - .withOptionalArguments(multiTargetArgument("targets")) + .withOptionalArguments(targets("targets")) .executes(SpawnCommand.instance::kill), - new CommandAPICommand("list") + command("list") .withPermission(PERMISSION_SPAWN) - .withOptionalArguments(new IntegerArgument("page", 1), new IntegerArgument("size", 1)) + .withOptionalArguments(integer("page", 1), integer("size", 1)) .executes(SpawnCommand.instance::list), - new CommandAPICommand("distance") + command("distance") .withPermission(PERMISSION_SPAWN) - .withOptionalArguments(targetArgument("target")) + .withOptionalArguments(target("target")) .executesPlayer(SpawnCommand.instance::distance), - new CommandAPICommand("exp") + command("exp") .withPermission(PERMISSION_PROFILE) - .withOptionalArguments(targetArgument("target")) + .withOptionalArguments(target("target")) .executes(ProfileCommand.instance::exp), - new CommandAPICommand("health") + command("health") .withPermission(PERMISSION_PROFILE) - .withOptionalArguments(targetArgument("target")) + .withOptionalArguments(target("target")) .executes(ProfileCommand.instance::health), - new CommandAPICommand("tp") + command("tp") .withPermission(PERMISSION_TP) - .withOptionalArguments(targetArgument("target")) + .withOptionalArguments(target("target")) .executesPlayer(TpCommand.instance::tp), - new CommandAPICommand("tphere") + command("tphere") .withPermission(PERMISSION_TP) - .withOptionalArguments(targetArgument("target")) + .withOptionalArguments(target("target")) .executesPlayer(TpCommand.instance::tphere), - new CommandAPICommand("tps") + command("tps") .withPermission(PERMISSION_TP) - .withOptionalArguments(targetArgument("target")) + .withOptionalArguments(target("target")) .executesPlayer(TpCommand.instance::tps), - new CommandAPICommand("config") + command("config") .withSubcommands( - new CommandAPICommand("get") - .withArguments(ConfigCommand.configArgument("config")) + command("get") + .withArguments(config("config")) .executesPlayer(ConfigCommand.instance::getConfig), - new CommandAPICommand("set") + command("set") .withArguments( - ConfigCommand.configArgument("config"), - ConfigCommand.configValueArgument("config", "value")) + config("config"), + configValue("config", "value")) .executesPlayer(ConfigCommand.instance::setConfig) ), - new CommandAPICommand("attack") + command("attack") .withPermission(PERMISSION_EXPERIMENTAL_ACTION) - .withSubcommands(buildActionCommand(Action.ATTACK)), - new CommandAPICommand("use") + .withSubcommands(action(Action.ATTACK)), + command("use") .withPermission(PERMISSION_EXPERIMENTAL_ACTION) - .withSubcommands(buildActionCommand(Action.USE)), - new CommandAPICommand("drop") + .withSubcommands(action(Action.USE)), + command("jump") + .withPermission(PERMISSION_ACTION) + .withSubcommands(action(Action.JUMP)), + command("drop") .withPermission(PERMISSION_ACTION) .withOptionalArguments( - targetArgument("target"), - new MultiLiteralArgument("all", List.of("-a", "--all"))) + target("target"), + literals("all", "-a", "--all")) .executes((CommandExecutor) (sender, args) -> ActionCommand.instance.action( sender, args, args.getOptional("all").isPresent() ? Action.DROP_STACK : Action.DROP_ITEM, ActionSetting.once())), - new CommandAPICommand("dropinv") + command("dropinv") .withPermission(PERMISSION_ACTION) - .withOptionalArguments(targetArgument("target")) - .executes((CommandExecutor) (sender, args) -> ActionCommand.instance.action(sender, args, Action.DROP_INVENTORY, ActionSetting.once())), - new CommandAPICommand("sneak") + .withOptionalArguments(target("target")) + .executes(ActionCommand.instance.action(Action.DROP_INVENTORY, ActionSetting.once())), + command("sneak") .withPermission(PERMISSION_ACTION) - .withOptionalArguments(targetArgument("target")) - .withOptionalArguments(new MultiLiteralArgument("sneaking", List.of("true", "false"))) + .withOptionalArguments(target("target")) + .withOptionalArguments(literals("sneaking", "true", "false")) .executes(ActionCommand.instance::sneak), + command("look") + .withPermission(PERMISSION_ACTION) + .withSubcommands( + command("north") + .withOptionalArguments(target("target")) + .executes(ActionCommand.instance.look(Direction.NORTH)), + command("south") + .withOptionalArguments(target("target")) + .executes(ActionCommand.instance.look(Direction.SOUTH)), + command("west") + .withOptionalArguments(target("target")) + .executes(ActionCommand.instance.look(Direction.WEST)), + command("east") + .withOptionalArguments(target("target")) + .executes(ActionCommand.instance.look(Direction.EAST)), + command("up") + .withOptionalArguments(target("target")) + .executes(ActionCommand.instance.look(Direction.UP)), + command("down") + .withOptionalArguments(target("target")) + .executes(ActionCommand.instance.look(Direction.DOWN)), + command("at") + .withArguments(new LocationArgument("location")) + .withOptionalArguments(target("target")) + .executes(ActionCommand.instance::lookAt) + ), + command("move") + .withPermission(PERMISSION_ACTION) + .withSubcommands( + command("forward") + .withOptionalArguments(target("target")) + .executes(ActionCommand.instance.move(1, 0)), + command("backward") + .withOptionalArguments(target("target")) + .executes(ActionCommand.instance.move(-1, 0)), + command("left") + .withOptionalArguments(target("target")) + .executes(ActionCommand.instance.move(0, 1)), + command("right") + .withOptionalArguments(target("target")) + .executes(ActionCommand.instance.move(0, -1)) + ), - new CommandAPICommand("expme") + command("expme") .withPermission(PERMISSION_EXP) - .withOptionalArguments(targetArgument("target")) + .withOptionalArguments(target("target")) .executesPlayer(ExpCommand.instance::expme), - new CommandAPICommand("cmd") + command("cmd") .withPermission(PERMISSION_CMD) .withArguments( - targetArgument("target"), + target("target"), new CommandArgument("command")) .executes(CmdCommand.instance::cmd), - new CommandAPICommand("reload") + command("reload") .withPermission(PERMISSION_ADMIN) .executes(ReloadCommand.instance::reload) ).register(); } - private static CommandAPICommand[] buildActionCommand(@NotNull Action action) { + private static CommandAPICommand[] action(@NotNull Action action) { return new CommandAPICommand[]{ - new CommandAPICommand("once") - .withOptionalArguments(targetArgument("target")) - .executes((CommandExecutor) (sender, args) -> ActionCommand.instance.action(sender, args, action, ActionSetting.once()) + command("once") + .withOptionalArguments(target("target")) + .executes(ActionCommand.instance.action(action, ActionSetting.once()) ), - new CommandAPICommand("continuous") - .withOptionalArguments(targetArgument("target")) - .executes((CommandExecutor) (sender, args) -> ActionCommand.instance.action(sender, args, action, ActionSetting.continuous()) + command("continuous") + .withOptionalArguments(target("target")) + .executes(ActionCommand.instance.action(action, ActionSetting.continuous())), + command("stop") + .withOptionalArguments(target("target")) + .executes(ActionCommand.instance.action(action, ActionSetting.stop()) ), - new CommandAPICommand("stop") - .withOptionalArguments(targetArgument("target")) - .executes((CommandExecutor) (sender, args) -> ActionCommand.instance.action(sender, args, action, ActionSetting.stop()) - ), - new CommandAPICommand("interval") + command("interval") .withOptionalArguments( - new IntegerArgument("interval", 1), - targetArgument("target")) + integer("interval", 1), + target("target")) .executes((sender, args) -> { int interval = (int) args.getOptional("interval").orElse(1); ActionCommand.instance.action(sender, args, action, ActionSetting.interval(interval)); @@ -181,5 +230,21 @@ public class Commands { }; } + private static CommandAPICommand command(@NotNull String name) { + return new CommandAPICommand(name); + } + + public static IntegerArgument integer(String name, int min) { + return new IntegerArgument(name, min); + } + + public static LocationArgument location(String name) { + return new LocationArgument(name); + } + + public static MultiLiteralArgument literals(String name, String... literals) { + return new MultiLiteralArgument(name, Arrays.asList(literals)); + } + } diff --git a/src/main/java/io/github/hello09x/fakeplayer/command/ConfigCommand.java b/src/main/java/io/github/hello09x/fakeplayer/command/ConfigCommand.java index f0ef199..e2575a6 100644 --- a/src/main/java/io/github/hello09x/fakeplayer/command/ConfigCommand.java +++ b/src/main/java/io/github/hello09x/fakeplayer/command/ConfigCommand.java @@ -24,7 +24,7 @@ public class ConfigCommand extends AbstractCommand { private final UserConfigRepository repository = UserConfigRepository.instance; - public static Argument> configArgument(String nodeName) { + public static Argument> config(String nodeName) { return new CustomArgument<>(new StringArgument(nodeName), info -> { var arg = info.currentInput(); try { @@ -35,7 +35,7 @@ public class ConfigCommand extends AbstractCommand { }).replaceSuggestions(ArgumentSuggestions.strings(Arrays.stream(Configs.values()).map(Config::name).toList())); } - public static Argument configValueArgument(String configNodeName, String nodeName) { + public static Argument configValue(String configNodeName, String nodeName) { return new CustomArgument<>(new StringArgument(nodeName), info -> { @SuppressWarnings("unchecked") var config = Objects.requireNonNull((Config) info.previousArgs().get(configNodeName)); diff --git a/src/main/java/io/github/hello09x/fakeplayer/command/SpawnCommand.java b/src/main/java/io/github/hello09x/fakeplayer/command/SpawnCommand.java index 946d8a4..9572cf6 100644 --- a/src/main/java/io/github/hello09x/fakeplayer/command/SpawnCommand.java +++ b/src/main/java/io/github/hello09x/fakeplayer/command/SpawnCommand.java @@ -26,12 +26,11 @@ public class SpawnCommand extends AbstractCommand { private static String toLocationString(@NotNull Location location) { return location.getWorld().getName() - + " 世界: " + + ": " + StringUtils.joinWith(", ", MathUtils.round(location.getX(), 0.5), MathUtils.round(location.getY(), 0.5), MathUtils.round(location.getZ(), 0.5)); - } public void spawn(@NotNull CommandSender sender, CommandArguments args) { @@ -131,9 +130,9 @@ public class SpawnCommand extends AbstractCommand { var distance = location1.distance(location2); sender.sendMessage(textOfChildren( - text("你与 "), + text("你与 ", GRAY), text(target.getName()), - text(" 相距 "), + text(" 相距 ", GRAY), text(MathUtils.round(distance, 0.5), WHITE) )); } diff --git a/src/main/java/io/github/hello09x/fakeplayer/entity/FakePlayer.java b/src/main/java/io/github/hello09x/fakeplayer/entity/FakePlayer.java index 08b70f2..0e91455 100644 --- a/src/main/java/io/github/hello09x/fakeplayer/entity/FakePlayer.java +++ b/src/main/java/io/github/hello09x/fakeplayer/entity/FakePlayer.java @@ -130,6 +130,7 @@ public class FakePlayer { bukkitPlayer.setInvulnerable(invulnerable); bukkitPlayer.setCollidable(collidable); bukkitPlayer.setCanPickupItems(pickupItems); + bukkitPlayer.getInventory().clear(); // 一些同步背包的插件可能在 JOIN 的时候恢复背包, 这个时候清空掉防止物品被复制了 new BukkitRunnable() { @Override public void run() { diff --git a/src/main/java/io/github/hello09x/fakeplayer/entity/action/Action.java b/src/main/java/io/github/hello09x/fakeplayer/entity/action/Action.java index b342a0a..868f2b9 100644 --- a/src/main/java/io/github/hello09x/fakeplayer/entity/action/Action.java +++ b/src/main/java/io/github/hello09x/fakeplayer/entity/action/Action.java @@ -1,7 +1,7 @@ package io.github.hello09x.fakeplayer.entity.action; import io.github.hello09x.fakeplayer.util.Tracer; -import net.minecraft.core.BlockPos; +import lombok.AllArgsConstructor; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; @@ -13,14 +13,15 @@ import org.jetbrains.annotations.NotNull; import static net.minecraft.network.protocol.game.ServerboundPlayerActionPacket.Action.*; +@AllArgsConstructor public enum Action { - USE { + USE("交互/使用/放置") { @Override @SuppressWarnings("resource") - public boolean tick(@NotNull ActionPack ap) { - if (ap.itemUseFreeze > 0) { - ap.itemUseFreeze--; + public boolean tick(@NotNull ActionPack ap, @NotNull ActionSetting setting) { + if (ap.use.freeze > 0) { + ap.use.freeze--; return false; } @@ -42,7 +43,7 @@ public enum Action { var result = player.gameMode.useItemOn(player, world, player.getItemInHand(hand), hand, blockHit); if (result.consumesAction()) { player.swing(hand); - ap.itemUseFreeze = 3; + ap.use.freeze = 3; return true; } } @@ -55,18 +56,18 @@ public enum Action { boolean itemFrameEmpty = (entity instanceof ItemFrame) && ((ItemFrame) entity).getItem().isEmpty(); var pos = entityHit.getLocation().subtract(entity.getX(), entity.getY(), entity.getZ()); if (entity.interactAt(player, pos, hand).consumesAction()) { - ap.itemUseFreeze = 3; + ap.use.freeze = 3; return true; } if (player.interactOn(entity, hand).consumesAction() && !(handWasEmpty && itemFrameEmpty)) { - ap.itemUseFreeze = 3; + ap.use.freeze = 3; return true; } } } var handItem = player.getItemInHand(hand); if (player.gameMode.useItem(player, player.level(), handItem, hand).consumesAction()) { - ap.itemUseFreeze = 3; + ap.use.freeze = 3; return true; } } @@ -74,16 +75,16 @@ public enum Action { } @Override - public void stop(@NotNull ActionPack ap) { - ap.itemUseFreeze = 0; + public void stop(@NotNull ActionPack ap, @NotNull ActionSetting setting) { + ap.use.freeze = 0; ap.player.releaseUsingItem(); } }, - ATTACK { + ATTACK("攻击/破坏") { @Override @SuppressWarnings("resource") - public boolean tick(@NotNull ActionPack ap) { + public boolean tick(@NotNull ActionPack ap, @NotNull ActionSetting setting) { var player = ap.player; var hit = getTarget(player); switch (hit.getType()) { @@ -96,8 +97,8 @@ public enum Action { return true; } case BLOCK -> { - if (ap.blockHitFreeze > 0) { - ap.blockHitFreeze--; + if (ap.attack.freeze > 0) { + ap.attack.freeze--; return false; } @@ -109,8 +110,8 @@ public enum Action { return false; } - if (ap.curBlockPos != null && player.level().getBlockState(ap.curBlockPos).isAir()) { - ap.curBlockPos = null; + if (ap.attack.pos != null && player.level().getBlockState(ap.attack.pos).isAir()) { + ap.attack.pos = null; return false; } @@ -124,11 +125,11 @@ public enum Action { player.level().getMaxBuildHeight(), -1 ); - ap.blockHitFreeze = 5; - } else if (ap.curBlockPos == null || !ap.curBlockPos.equals(pos)) { - if (ap.curBlockPos != null) { + ap.attack.freeze = 5; + } else if (ap.attack.pos == null || !ap.attack.pos.equals(pos)) { + if (ap.attack.pos != null) { player.gameMode.handleBlockBreakAction( - ap.curBlockPos, + ap.attack.pos, ABORT_DESTROY_BLOCK, side, player.level().getMaxBuildHeight(), @@ -144,20 +145,20 @@ public enum Action { -1 ); - if (!state.isAir() && ap.curBlockPgs == 0) { + if (!state.isAir() && ap.attack.progress == 0) { state.attack(player.level(), pos, player); } if (!state.isAir() && state.getDestroyProgress(player, player.level(), pos) >= 1) { - ap.curBlockPos = null; + ap.attack.pos = null; broken = true; } else { - ap.curBlockPos = pos; - ap.curBlockPgs = 0; + ap.attack.pos = pos; + ap.attack.progress = 0; } } else { - ap.curBlockPgs += state.getDestroyProgress(player, player.level(), pos); - if (ap.curBlockPgs >= 1) { + ap.attack.progress += state.getDestroyProgress(player, player.level(), pos); + if (ap.attack.progress >= 1) { player.gameMode.handleBlockBreakAction( pos, STOP_DESTROY_BLOCK, @@ -165,11 +166,11 @@ public enum Action { player.level().getMaxBuildHeight(), -1 ); - ap.curBlockPos = null; - ap.blockHitFreeze = 5; + ap.attack.pos = null; + ap.attack.freeze = 5; broken = true; } - player.level().destroyBlockProgress(-1, pos, (int) (ap.curBlockPgs * 10)); + player.level().destroyBlockProgress(-1, pos, (int) (ap.attack.progress * 10)); } player.resetLastActionTime(); @@ -181,30 +182,52 @@ public enum Action { } @Override - public void stop(@NotNull ActionPack ap) { - if (ap.curBlockPos == null) { + @SuppressWarnings("resource") + public void stop(@NotNull ActionPack ap, @NotNull ActionSetting setting) { + if (ap.attack.pos == null) { return; } var player = ap.player; - player.level().destroyBlockProgress(-1, ap.curBlockPos, -1); + player.level().destroyBlockProgress(-1, ap.attack.pos, -1); player.gameMode.handleBlockBreakAction( - ap.curBlockPos, + ap.attack.pos, ABORT_DESTROY_BLOCK, Direction.DOWN, player.level().getMaxBuildHeight(), -1 ); - ap.curBlockPos = null; - ap.blockHitFreeze = 0; - ap.curBlockPgs = 0; + ap.attack.pos = null; + ap.attack.freeze = 0; + ap.attack.progress = 0; + } + }, + + JUMP("跳") { + @Override + public boolean tick(@NotNull ActionPack ap, @NotNull ActionSetting setting) { + var player = ap.player; + if (setting.limit == 1) { + if (player.onGround()) { + player.jumpFromGround(); + return true; + } + } + + player.setJumping(true); + return true; + } + + @Override + public void inactiveTick(@NotNull ActionPack ap, @NotNull ActionSetting setting) { + ap.player.setJumping(false); } }, - DROP_ITEM { + DROP_ITEM("丢弃手上物品") { @Override - public boolean tick(@NotNull ActionPack ap) { + public boolean tick(@NotNull ActionPack ap, @NotNull ActionSetting setting) { var player = ap.player; player.resetLastActionTime(); player.drop(false); @@ -212,9 +235,9 @@ public enum Action { } }, - DROP_STACK { + DROP_STACK("丢弃手上整组物品") { @Override - public boolean tick(@NotNull ActionPack ap) { + public boolean tick(@NotNull ActionPack ap, @NotNull ActionSetting setting) { var player = ap.player; player.resetLastActionTime(); player.drop(true); @@ -222,9 +245,9 @@ public enum Action { } }, - DROP_INVENTORY { + DROP_INVENTORY("丢弃背包物品") { @Override - public boolean tick(@NotNull ActionPack ap) { + public boolean tick(@NotNull ActionPack ap, @NotNull ActionSetting setting) { var player = ap.player; dropInventory(player); return true; @@ -232,6 +255,8 @@ public enum Action { }; + public final String name; + static HitResult getTarget(ServerPlayer player) { double reach = player.gameMode.isCreative() ? 5 : 4.5f; return Tracer.rayTrace(player, 1, reach, false); @@ -244,31 +269,13 @@ public enum Action { } } - public abstract boolean tick(@NotNull ActionPack ap); - public void stop(@NotNull ActionPack ap) {} + public abstract boolean tick(@NotNull ActionPack ap, @NotNull ActionSetting setting); - public void inactiveTick(@NotNull ActionPack ap) { - this.stop(ap); - } - - public static class ActionPack { - - public final ServerPlayer player; - - // attack - public BlockPos curBlockPos; - public float curBlockPgs; - public int blockHitFreeze; - - - // use - public int itemUseFreeze; - - public ActionPack(ServerPlayer player) { - this.player = player; - } + public void stop(@NotNull ActionPack ap, @NotNull ActionSetting setting) {} + public void inactiveTick(@NotNull ActionPack ap, @NotNull ActionSetting setting) { + this.stop(ap, setting); } diff --git a/src/main/java/io/github/hello09x/fakeplayer/entity/action/ActionManager.java b/src/main/java/io/github/hello09x/fakeplayer/entity/action/ActionManager.java index e19ee3d..9c33104 100644 --- a/src/main/java/io/github/hello09x/fakeplayer/entity/action/ActionManager.java +++ b/src/main/java/io/github/hello09x/fakeplayer/entity/action/ActionManager.java @@ -5,13 +5,13 @@ import net.minecraft.server.level.ServerPlayer; public class ActionManager { public final Action action; - public final Action.ActionPack actionPack; + public final ActionPack actionPack; public ActionSetting setting; public ActionManager(ServerPlayer player, Action action, ActionSetting setting) { this.action = action; this.setting = setting; - this.actionPack = new Action.ActionPack(player); + this.actionPack = new ActionPack(player); } public void tick() { @@ -26,7 +26,7 @@ public class ActionManager { return; } - var done = action.tick(this.actionPack); + var done = action.tick(this.actionPack, this.setting); if (done) { if (setting.times > 0) { setting.times--; @@ -36,11 +36,11 @@ public class ActionManager { } public void inactiveTick() { - action.inactiveTick(this.actionPack); + action.inactiveTick(this.actionPack, this.setting); } public void stop() { - action.stop(this.actionPack); + action.stop(this.actionPack, this.setting); } diff --git a/src/main/java/io/github/hello09x/fakeplayer/entity/action/ActionPack.java b/src/main/java/io/github/hello09x/fakeplayer/entity/action/ActionPack.java new file mode 100644 index 0000000..fb86788 --- /dev/null +++ b/src/main/java/io/github/hello09x/fakeplayer/entity/action/ActionPack.java @@ -0,0 +1,28 @@ +package io.github.hello09x.fakeplayer.entity.action; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; + +public class ActionPack { + + public final ServerPlayer player; + + public final AttackActionPack attack = new AttackActionPack(); + + public final UseActionPack use = new UseActionPack(); + + public ActionPack(ServerPlayer player) { + this.player = player; + } + + public final static class AttackActionPack { + public BlockPos pos; + public float progress; + public int freeze; + } + + public final static class UseActionPack { + public int freeze; + } + +} diff --git a/src/main/java/io/github/hello09x/fakeplayer/entity/action/ActionSetting.java b/src/main/java/io/github/hello09x/fakeplayer/entity/action/ActionSetting.java index f57cbcc..2491169 100644 --- a/src/main/java/io/github/hello09x/fakeplayer/entity/action/ActionSetting.java +++ b/src/main/java/io/github/hello09x/fakeplayer/entity/action/ActionSetting.java @@ -1,9 +1,17 @@ package io.github.hello09x.fakeplayer.entity.action; -public class ActionSetting { +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode +public class ActionSetting implements Cloneable { /** - * 次数 + * 总次数 + */ + public final int limit; + + /** + * 剩余次数 */ public int times; @@ -18,31 +26,38 @@ public class ActionSetting { public int wait; public ActionSetting(int times, int interval) { - this.times = times; - this.interval = interval; - this.wait = 0; + this(times, interval, 0); } public ActionSetting(int times, int interval, int wait) { + this.limit = times; this.times = times; this.interval = interval; this.wait = wait; } public static ActionSetting once() { - return new ActionSetting(1, 1, 0); + return new ActionSetting(1, 1 ); } public static ActionSetting stop() { - return new ActionSetting(0, 1, 0); + return new ActionSetting(0, 1); } public static ActionSetting interval(int interval) { - return new ActionSetting(-1, interval, 0); + return new ActionSetting(-1, interval); } public static ActionSetting continuous() { - return new ActionSetting(-1, 1, 0); + return new ActionSetting(-1, 1); } + @Override + public ActionSetting clone() { + return new ActionSetting( + this.times, + this.interval, + this.wait + ); + } } diff --git a/src/main/java/io/github/hello09x/fakeplayer/listener/PlayerListeners.java b/src/main/java/io/github/hello09x/fakeplayer/listener/PlayerListeners.java index 6413ae9..23c45be 100644 --- a/src/main/java/io/github/hello09x/fakeplayer/listener/PlayerListeners.java +++ b/src/main/java/io/github/hello09x/fakeplayer/listener/PlayerListeners.java @@ -32,7 +32,7 @@ public class PlayerListeners implements Listener { * 拒绝假人用过的 ID 上线 */ @EventHandler(ignoreCancelled = true) - public void handleUsedIdLogin(@NotNull AsyncPlayerPreLoginEvent event) { + public void onLogin(@NotNull AsyncPlayerPreLoginEvent event) { if (event.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) { return; } @@ -49,7 +49,7 @@ public class PlayerListeners implements Listener { * 死亡退出游戏 */ @EventHandler(ignoreCancelled = true) - public void handlePlayerDeath(@NotNull PlayerDeathEvent event) { + public void onDead(@NotNull PlayerDeathEvent event) { var player = event.getPlayer(); if (!manager.isFake(player)) { return; @@ -63,7 +63,7 @@ public class PlayerListeners implements Listener { * 退出游戏掉落背包 */ @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) - public void handlePlayerQuit(@NotNull PlayerQuitEvent event) { + public void onQuit(@NotNull PlayerQuitEvent event) { var player = event.getPlayer(); if (!manager.isFake(player)) { return; diff --git a/src/main/java/io/github/hello09x/fakeplayer/manager/FakeplayerManager.java b/src/main/java/io/github/hello09x/fakeplayer/manager/FakeplayerManager.java index 7473fec..4691424 100644 --- a/src/main/java/io/github/hello09x/fakeplayer/manager/FakeplayerManager.java +++ b/src/main/java/io/github/hello09x/fakeplayer/manager/FakeplayerManager.java @@ -122,7 +122,7 @@ public class FakeplayerManager { usedIdRepository.add(bukkitPlayer.getUniqueId()); dispatchCommands(bukkitPlayer, properties.getPreparingCommands()); - performCommands(bukkitPlayer); + performCommands(bukkitPlayer, properties.getSelfCommands()); bukkitPlayer.teleport(spawnAt); // 当前 tick 必须传到出生点否则无法触发区块刷新 spawnAt.getWorld().playSound(spawnAt, Sound.ENTITY_ENDERMAN_TELEPORT, 1.0F, 1.0F); @@ -239,9 +239,7 @@ public class FakeplayerManager { Metadatas.NAME_SEQUENCE.get(fakePlayer).asInt() ); Arrays.stream(Metadatas.values()).forEach(meta -> meta.remove(fakePlayer)); - if (properties.isDropInventoryOnQuiting()) { - Action.dropInventory(Unwrapper.getServerPlayer(fakePlayer)); - } + Action.dropInventory(Unwrapper.getServerPlayer(fakePlayer)); } /** @@ -298,12 +296,15 @@ public class FakeplayerManager { return uuid; } - public void performCommands(@NotNull Player player) { + public void performCommands(@NotNull Player player, @NotNull List commands) { + if (commands.isEmpty()) { + return; + } if (!isFake(player)) { return; } - for (var cmd : properties.getSelfCommands()) { + for (var cmd : commands) { cmd = cmd.trim(); if (cmd.startsWith("/")) { cmd = cmd.substring(1); @@ -327,7 +328,7 @@ public class FakeplayerManager { var server = Bukkit.getServer(); var sender = Bukkit.getConsoleSender(); - for (var cmd : properties.getPreparingCommands()) { + for (var cmd : commands) { cmd = cmd.trim(); if (cmd.startsWith("/")) { cmd = cmd.substring(1); diff --git a/src/main/java/io/github/hello09x/fakeplayer/properties/FakeplayerProperties.java b/src/main/java/io/github/hello09x/fakeplayer/properties/FakeplayerProperties.java index d85cd6a..f4673e9 100644 --- a/src/main/java/io/github/hello09x/fakeplayer/properties/FakeplayerProperties.java +++ b/src/main/java/io/github/hello09x/fakeplayer/properties/FakeplayerProperties.java @@ -77,11 +77,6 @@ public class FakeplayerProperties extends AbstractProperties