diff --git a/src/main/java/emu/grasscutter/command/CommandHelpers.java b/src/main/java/emu/grasscutter/command/CommandHelpers.java index c723a770e..d53854667 100644 --- a/src/main/java/emu/grasscutter/command/CommandHelpers.java +++ b/src/main/java/emu/grasscutter/command/CommandHelpers.java @@ -1,5 +1,7 @@ package emu.grasscutter.command; +import emu.grasscutter.game.world.Position; + import java.util.*; import java.util.function.BiConsumer; import java.util.regex.*; @@ -65,4 +67,62 @@ public class CommandHelpers { } return current; } + + public static Position parsePosition(String inputX, String inputY, String inputZ, Position curPos, Position curRot) { + Position offset = new Position(); + Position target = new Position(curPos); + if (inputX.contains("~")) { // Relative + if (!inputX.equals("~")) { // Relative with offset + target.addX(Float.parseFloat(inputX.replace("~", ""))); + } + } else if (inputX.contains("^")) { + if (!inputX.equals("^")) { + offset.setX(Float.parseFloat(inputX.replace("^", ""))); + } + } else { // Absolute + target.setX(Float.parseFloat(inputX)); + } + + if (inputY.contains("~")) { // Relative + if (!inputY.equals("~")) { // Relative with offset + target.addY(Float.parseFloat(inputY.replace("~", ""))); + } + } else if (inputY.contains("^")) { + if (!inputY.equals("^")) { + offset.setY(Float.parseFloat(inputY.replace("^", ""))); + } + } else { // Absolute + target.setY(Float.parseFloat(inputY)); + } + + if (inputZ.contains("~")) { // Relative + if (!inputZ.equals("~")) { // Relative with offset + target.addZ(Float.parseFloat(inputZ.replace("~", ""))); + } + } else if (inputZ.contains("^")) { + if (!inputZ.equals("^")) { + offset.setZ(Float.parseFloat(inputZ.replace("^", ""))); + } + } else { // Absolute + target.setZ(Float.parseFloat(inputZ)); + } + + if (!offset.equal3d(Position.ZERO)) { + return calculateOffset(target, curRot, offset); + } else { + return target; + } + } + + public static Position calculateOffset(Position pos, Position rot, Position offset) { + // Degrees to radians + float angleZ = (float) Math.toRadians(rot.getY()); + float angleX = (float) Math.toRadians(rot.getY() + 90); + + // Calculate offset based on current position and rotation + return new Position( + pos.getX() + offset.getZ() * (float)Math.sin(angleZ) + offset.getX() * (float)Math.sin(angleX), + pos.getY() + offset.getY(), + pos.getZ() + offset.getZ() * (float)Math.cos(angleZ) + offset.getX() * (float)Math.cos(angleX)); + } } diff --git a/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java b/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java index f47de0d19..d62f8b854 100644 --- a/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java @@ -54,8 +54,8 @@ public final class SpawnCommand implements CommandHandler { throw new IllegalArgumentException(); } - Position pos = targetPlayer.getPosition(); - Position rot = targetPlayer.getRotation(); + Position pos = new Position(targetPlayer.getPosition()); + Position rot = new Position(targetPlayer.getRotation()); switch (args.size()) { case 7: @@ -69,9 +69,7 @@ public final class SpawnCommand implements CommandHandler { } // Fallthrough case 4: try { - pos.setX(CommandHelpers.parseRelative(args.get(1), pos.getX())); - pos.setY(CommandHelpers.parseRelative(args.get(2), pos.getY())); - pos.setZ(CommandHelpers.parseRelative(args.get(3), pos.getZ())); + pos = CommandHelpers.parsePosition(args.get(1), args.get(2), args.get(3), pos, rot); } catch (NumberFormatException ignored) { CommandHandler.sendMessage( sender, translate(sender, "commands.execution.argument_error")); diff --git a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java index 110b4f199..8d615f245 100644 --- a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java @@ -6,6 +6,8 @@ import emu.grasscutter.command.*; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.world.Position; import emu.grasscutter.server.event.player.PlayerTeleportEvent.TeleportType; +import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify; + import java.util.List; @Command( @@ -18,10 +20,8 @@ public final class TeleportCommand implements CommandHandler { @Override public void execute(Player sender, Player targetPlayer, List args) { - Position pos = targetPlayer.getPosition(); - float x = pos.getX(); - float y = pos.getY(); - float z = pos.getZ(); + Position pos = new Position(targetPlayer.getPosition()); + Position rot = new Position(targetPlayer.getRotation()); int sceneId = targetPlayer.getSceneId(); switch (args.size()) { @@ -34,9 +34,7 @@ public final class TeleportCommand implements CommandHandler { } // Fallthrough case 3: try { - x = CommandHelpers.parseRelative(args.get(0), x); - y = CommandHelpers.parseRelative(args.get(1), y); - z = CommandHelpers.parseRelative(args.get(2), z); + pos = CommandHelpers.parsePosition(args.get(0), args.get(1), args.get(2), pos, rot); } catch (NumberFormatException ignored) { CommandHandler.sendMessage( sender, translate(sender, "commands.teleport.invalid_position")); @@ -47,19 +45,20 @@ public final class TeleportCommand implements CommandHandler { return; } - Position target_pos = new Position(x, y, z); boolean result = targetPlayer .getWorld() - .transferPlayerToScene(targetPlayer, sceneId, TeleportType.COMMAND, target_pos); + .transferPlayerToScene(targetPlayer, sceneId, TeleportType.COMMAND, pos); if (!result) { CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error")); } else { CommandHandler.sendMessage( + sender, + translate( sender, - translate( - sender, "commands.teleport.success", targetPlayer.getNickname(), x, y, z, sceneId)); + "commands.teleport.success", + targetPlayer.getNickname(), pos.getX(), pos.getY(), pos.getZ(), sceneId)); } } }