diff --git a/src/main/java/net/minestom/server/command/builder/arguments/relative/ArgumentRelativeVec.java b/src/main/java/net/minestom/server/command/builder/arguments/relative/ArgumentRelativeVec.java index 6ab1a294f..ed8460764 100644 --- a/src/main/java/net/minestom/server/command/builder/arguments/relative/ArgumentRelativeVec.java +++ b/src/main/java/net/minestom/server/command/builder/arguments/relative/ArgumentRelativeVec.java @@ -7,6 +7,7 @@ import net.minestom.server.utils.StringUtils; import net.minestom.server.utils.location.RelativeVec; import org.jetbrains.annotations.NotNull; +import java.util.Set; import java.util.function.Function; /** @@ -14,10 +15,13 @@ import java.util.function.Function; */ abstract class ArgumentRelativeVec extends Argument { - public static final String RELATIVE_CHAR = "~"; + public static final char RELATIVE_CHAR = '~'; + public static final char LOCAL_CHAR = '^'; + public static final Set MODIFIER_CHARS = Set.of(RELATIVE_CHAR, LOCAL_CHAR); public static final int INVALID_NUMBER_COUNT_ERROR = 1; public static final int INVALID_NUMBER_ERROR = 2; + public static final int MIXED_TYPE_ERROR = 3; private final int numberCount; @@ -39,13 +43,21 @@ abstract class ArgumentRelativeVec extends Argument { double[] coordinates = new double[split.length]; boolean[] isRelative = new boolean[split.length]; + Type type = Type.UNDEFINED; for (int i = 0; i < split.length; i++) { final String element = split[i]; try { - if (element.startsWith(RELATIVE_CHAR)) { + final char modifierChar = element.charAt(0); + if (MODIFIER_CHARS.contains(modifierChar)) { isRelative[i] = true; - if (element.length() != RELATIVE_CHAR.length()) { + if (type == Type.UNDEFINED) { + type = modifierChar == LOCAL_CHAR ? Type.LOCAL : Type.RELATIVE; + } else if (type != (modifierChar == LOCAL_CHAR ? Type.LOCAL : Type.RELATIVE)) { + throw new ArgumentSyntaxException("Cannot mix world & local coordinates (everything must either use ^ or not)", input, MIXED_TYPE_ERROR); + } + + if (element.length() > 1) { final String potentialNumber = element.substring(1); coordinates[i] = getRelativeNumberParser().apply(potentialNumber).doubleValue(); } @@ -53,12 +65,12 @@ abstract class ArgumentRelativeVec extends Argument { coordinates[i] = getAbsoluteNumberParser().apply(element).doubleValue(); } } catch (NumberFormatException e) { - throw new ArgumentSyntaxException("Invalid number", String.join(StringUtils.SPACE, split), INVALID_NUMBER_ERROR); + throw new ArgumentSyntaxException("Invalid number", input, INVALID_NUMBER_ERROR); } } return new RelativeVec(split.length == 3 ? new Vec(coordinates[0], coordinates[1], coordinates[2]) : new Vec(coordinates[0], coordinates[1]), - isRelative[0], split.length == 3 && isRelative[1], isRelative[split.length == 3 ? 2 : 1]); + isRelative, type == Type.LOCAL); } /** @@ -69,4 +81,10 @@ abstract class ArgumentRelativeVec extends Argument { public int getNumberCount() { return numberCount; } + + private enum Type { + RELATIVE, + LOCAL, + UNDEFINED + } } diff --git a/src/main/java/net/minestom/server/utils/location/RelativeVec.java b/src/main/java/net/minestom/server/utils/location/RelativeVec.java index cece78310..b9704eae6 100644 --- a/src/main/java/net/minestom/server/utils/location/RelativeVec.java +++ b/src/main/java/net/minestom/server/utils/location/RelativeVec.java @@ -18,7 +18,9 @@ import java.util.Objects; public final class RelativeVec { private final Vec vec; - private final boolean relativeX, relativeY, relativeZ; + private boolean relativeX, relativeY, relativeZ; + private boolean[] relative; + private boolean isLocal; public RelativeVec(@NotNull Vec vec, boolean relativeX, boolean relativeY, boolean relativeZ) { this.vec = vec; @@ -27,6 +29,12 @@ public final class RelativeVec { this.relativeZ = relativeZ; } + public RelativeVec(Vec vec, boolean[] relative, boolean isLocal) { + this.vec = vec; + this.relative = relative; + this.isLocal = isLocal; + } + /** * Gets the location based on the relative fields and {@code position}. * @@ -62,8 +70,9 @@ public final class RelativeVec { * @return the location */ public @NotNull Vec from(@Nullable Entity entity) { - final var entityPosition = entity != null ? entity.getPosition() : Pos.ZERO; - return from(entityPosition); + return isLocal ? toGlobal(vec, entity.getPosition(), relative) : toGlobal(vec, entity.getPosition().asVec(), relative); +// final var entityPosition = entity != null ? entity.getPosition() : Pos.ZERO; +// return from(entityPosition); } public @NotNull Vec fromSender(@Nullable CommandSender sender) { @@ -104,4 +113,30 @@ public final class RelativeVec { return relativeZ; } + public static Vec toGlobal(Vec local, Pos origin, boolean[] axis) { + double double5 = Math.cos(Math.toRadians(origin.yaw() + 90.0f)); + double double6 = Math.sin(Math.toRadians(origin.yaw() + 90.0f)); + double double7 = Math.cos(Math.toRadians(-origin.pitch())); + double double8 = Math.sin(Math.toRadians(-origin.pitch())); + double double9 = Math.cos(Math.toRadians(-origin.pitch() + 90.0f)); + double double10 = Math.sin(Math.toRadians(-origin.pitch() + 90.0f)); + Vec dna11 = new Vec(double5 * double7, double8, double6 * double7); + Vec dna12 = new Vec(double5 * double9, double10, double6 * double9); + Vec dna13 = dna11.cross(dna12).mul(-1); + double double14 = dna11.x() * local.z() + dna12.x() * local.y() + dna13.x() * local.x(); + double double16 = dna11.y() * local.z() + dna12.y() * local.y() + dna13.y() * local.x(); + double double18 = dna11.z() * local.z() + dna12.z() * local.y() + dna13.z() * local.x(); + return new Vec(double14 + (axis[0] ? origin.x() : 0), double16 + (axis[1] ? origin.y() : 0), double18 + (axis[2] ? origin.z() : 0)); + } + + public static Vec toGlobal(Vec relative, Vec origin, boolean[] axis) { + if (!axis[0] && !axis[1] && !axis[2]) { + return relative; + } + final var absolute = Objects.requireNonNullElse(origin, Vec.ZERO); + final double x = relative.x() + (axis[0] ? absolute.x() : 0); + final double y = relative.y() + (axis[1] ? absolute.y() : 0); + final double z = relative.z() + (axis[2] ? absolute.z() : 0); + return new Vec(x, y, z); + } } diff --git a/src/test/java/demo/commands/TeleportCommand.java b/src/test/java/demo/commands/TeleportCommand.java index f70313a36..49c9572aa 100644 --- a/src/test/java/demo/commands/TeleportCommand.java +++ b/src/test/java/demo/commands/TeleportCommand.java @@ -39,8 +39,8 @@ public class TeleportCommand extends Command { final Player player = sender.asPlayer(); final RelativeVec relativeVec = context.get("pos"); - final Vec position = relativeVec.from(player); - player.teleport(new Pos(position)); + final Pos position = player.getPosition().withCoord(relativeVec.from(player)); + player.teleport(position); player.sendMessage(Component.text("You have been teleported to " + position)); } }