diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java
index 508fe4e32..e2067fd90 100644
--- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java
+++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitCommandSender.java
@@ -19,17 +19,12 @@
package com.sk89q.worldedit.bukkit;
+import com.sk89q.worldedit.*;
+import com.sk89q.worldedit.extent.inventory.BlockBag;
+import com.sk89q.worldedit.util.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
-import com.sk89q.worldedit.LocalPlayer;
-import com.sk89q.worldedit.LocalWorld;
-import com.sk89q.worldedit.PlayerNeededException;
-import com.sk89q.worldedit.ServerInterface;
-import com.sk89q.worldedit.Vector;
-import com.sk89q.worldedit.WorldVector;
-import com.sk89q.worldedit.extent.inventory.BlockBag;
-
public class BukkitCommandSender extends LocalPlayer {
private CommandSender sender;
private WorldEditPlugin plugin;
@@ -97,6 +92,11 @@ public class BukkitCommandSender extends LocalPlayer {
throw new PlayerNeededException();
}
+ @Override
+ public Location getLocation() {
+ throw new PlayerNeededException();
+ }
+
@Override
public WorldVector getPosition() {
throw new PlayerNeededException();
diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java
index 2bbc55a71..1499cd09f 100644
--- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java
+++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java
@@ -21,6 +21,7 @@ package com.sk89q.worldedit.bukkit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
+import com.sk89q.worldedit.util.Vectors;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.Player;
@@ -168,4 +169,12 @@ public class BukkitPlayer extends LocalPlayer {
setPosition(new Vector(x + 0.5, y, z + 0.5));
player.setFlying(true);
}
+
+ @Override
+ public com.sk89q.worldedit.util.Location getLocation() {
+ Location nativeLocation = player.getLocation();
+ Vector position = BukkitUtil.toVector(nativeLocation);
+ Vector direction = Vectors.fromEulerDeg(nativeLocation.getYaw(), nativeLocation.getPitch());
+ return new com.sk89q.worldedit.util.Location(getWorld(), position, direction);
+ }
}
diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java b/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java
index dec4dd7b6..01e178f71 100644
--- a/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java
+++ b/src/forge/java/com/sk89q/worldedit/forge/ForgePlayer.java
@@ -27,6 +27,8 @@ import com.sk89q.worldedit.WorldVector;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.internal.LocalWorldAdapter;
import com.sk89q.worldedit.internal.cui.CUIEvent;
+import com.sk89q.worldedit.util.Location;
+import com.sk89q.worldedit.util.Vectors;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.network.packet.Packet250CustomPayload;
@@ -49,6 +51,13 @@ public class ForgePlayer extends LocalPlayer {
return this.player.username;
}
+ @Override
+ public Location getLocation() {
+ Vector position = new Vector(this.player.posX, this.player.posY, this.player.posZ);
+ Vector direction = Vectors.fromEulerDeg(this.player.cameraYaw, this.player.cameraPitch);
+ return new Location(ForgeWorldEdit.inst.getWorld(this.player.worldObj), position, direction);
+ }
+
public WorldVector getPosition() {
return new WorldVector(LocalWorldAdapter.wrap(ForgeWorldEdit.inst.getWorld(this.player.worldObj)), this.player.posX, this.player.posY, this.player.posZ);
}
diff --git a/src/main/java/com/sk89q/worldedit/Location.java b/src/main/java/com/sk89q/worldedit/Location.java
index ccf3a338d..5097fa414 100644
--- a/src/main/java/com/sk89q/worldedit/Location.java
+++ b/src/main/java/com/sk89q/worldedit/Location.java
@@ -19,6 +19,10 @@
package com.sk89q.worldedit;
+/**
+ * @deprecated Use {@link com.sk89q.worldedit.util.Location} wherever possible
+ */
+@Deprecated
public class Location {
private final LocalWorld world;
private final Vector position;
diff --git a/src/main/java/com/sk89q/worldedit/WorldVector.java b/src/main/java/com/sk89q/worldedit/WorldVector.java
index 090358769..2e901f823 100644
--- a/src/main/java/com/sk89q/worldedit/WorldVector.java
+++ b/src/main/java/com/sk89q/worldedit/WorldVector.java
@@ -20,10 +20,9 @@
package com.sk89q.worldedit;
/**
- * A vector with a world component.
- *
- * @author sk89q
+ * @deprecated Use {@link com.sk89q.worldedit.util.Location} wherever possible
*/
+@Deprecated
public class WorldVector extends Vector {
/**
* Represents the world.
diff --git a/src/main/java/com/sk89q/worldedit/entity/Entity.java b/src/main/java/com/sk89q/worldedit/entity/Entity.java
index 73fc3a56e..950557bc3 100644
--- a/src/main/java/com/sk89q/worldedit/entity/Entity.java
+++ b/src/main/java/com/sk89q/worldedit/entity/Entity.java
@@ -19,8 +19,12 @@
package com.sk89q.worldedit.entity;
-import com.sk89q.worldedit.*;
+import com.sk89q.worldedit.PlayerDirection;
+import com.sk89q.worldedit.Vector;
+import com.sk89q.worldedit.WorldVector;
+import com.sk89q.worldedit.WorldVectorFace;
import com.sk89q.worldedit.extent.Extent;
+import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.World;
/**
@@ -166,6 +170,13 @@ public interface Entity {
*/
PlayerDirection getCardinalDirection();
+ /**
+ * Get the location of this entity.
+ *
+ * @return the location of the entity
+ */
+ Location getLocation();
+
/**
* Get the actor's position.
*
diff --git a/src/main/java/com/sk89q/worldedit/util/Location.java b/src/main/java/com/sk89q/worldedit/util/Location.java
new file mode 100644
index 000000000..e5ae26909
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/util/Location.java
@@ -0,0 +1,300 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.util;
+
+import com.sk89q.worldedit.Vector;
+import com.sk89q.worldedit.world.World;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Represents a location in a world with has a direction.
+ *
+ * Like {@code Vectors}, {@code Locations} are immutable and mutator methods
+ * will create a new copy.
+ *
+ * At the moment, but this may change in the future, {@link #hashCode()} and
+ * {@link #equals(Object)} are subject to minor differences caused by
+ * floating point errors.
+ */
+public class Location {
+
+ private final World world;
+ private final Vector position;
+ private final Vector direction;
+
+ /**
+ * Create a new instance in the given world at 0, 0, 0 with a
+ * direction vector of 0, 0, 0.
+ *
+ * @param world the world
+ */
+ public Location(World world) {
+ this(world, new Vector(), new Vector());
+ }
+
+ /**
+ * Create a new instance in the given world with the given coordinates
+ * with a direction vector of 0, 0, 0.
+ *
+ * @param world the world
+ * @param x the X coordinate
+ * @param y the Y coordinate
+ * @param z the Z coordinate
+ */
+ public Location(World world, double x, double y, double z) {
+ this(world, new Vector(x, y, z), new Vector());
+ }
+
+ /**
+ * Create a new instance in the given world with the given position
+ * vector and a direction vector of 0, 0, 0.
+ *
+ * @param world the world
+ * @param position the position vector
+ */
+ public Location(World world, Vector position) {
+ this(world, position, new Vector());
+ }
+
+ /**
+ * Create a new instance in the given world with the given coordinates
+ * and the given direction vector.
+ *
+ * @param world the world
+ * @param x the X coordinate
+ * @param y the Y coordinate
+ * @param z the Z coordinate
+ * @param direction the direction vector
+ */
+ public Location(World world, double x, double y, double z, Vector direction) {
+ this(world, new Vector(x, y, z), direction);
+ }
+
+ /**
+ * Create a new instance in the given world with the given position vector
+ * and the given direction vector.
+ *
+ * @param world the world
+ * @param position the position vector
+ * @param direction the direction vector
+ */
+ public Location(World world, Vector position, Vector direction) {
+ checkNotNull(world);
+ checkNotNull(position);
+ checkNotNull(direction);
+ this.world = world;
+ this.position = position;
+ this.direction = direction;
+ }
+
+ /**
+ * Get the world.
+ *
+ * @return the world
+ */
+ public World getWorld() {
+ return world;
+ }
+
+ /**
+ * Create a clone of this object with the given world.
+ *
+ * @param world the new world
+ * @return the new instance
+ */
+ public Location setWorld(World world) {
+ return new Location(world, position, getDirection());
+ }
+
+ /**
+ * Get the direction.
+ *
+ * The direction vector may be a null vector. It may or may not
+ * be a unit vector.
+ *
+ * @return the direction
+ */
+ public Vector getDirection() {
+ return direction;
+ }
+
+ /**
+ * Create a clone of this object with the given direction.
+ *
+ * @param direction the new direction
+ * @return the new instance
+ */
+ public Location setDirection(Vector direction) {
+ return new Location(world, position, direction);
+ }
+
+ /**
+ * Get a {@link Vector} form of this location's position.
+ *
+ * @return a vector
+ */
+ public Vector toVector() {
+ return position;
+ }
+
+ /**
+ * Get the X component of the position vector.
+ *
+ * @return the X component
+ */
+ public double getX() {
+ return position.getX();
+ }
+
+ /**
+ * Get the rounded X component of the position vector.
+ *
+ * @return the rounded X component
+ */
+ public int getBlockX() {
+ return position.getBlockX();
+ }
+
+ /**
+ * Return a copy of this object with the X component of the new object
+ * set to the given value.
+ *
+ * @param x the new value for the X component
+ * @return a new immutable instance
+ */
+ public Location setX(double x) {
+ return new Location(world, position.setX(x), direction);
+ }
+
+ /**
+ * Return a copy of this object with the X component of the new object
+ * set to the given value.
+ *
+ * @param x the new value for the X component
+ * @return a new immutable instance
+ */
+ public Location setX(int x) {
+ return new Location(world, position.setX(x), direction);
+ }
+
+ /**
+ * Get the Y component of the position vector.
+ *
+ * @return the Y component
+ */
+ public double getY() {
+ return position.getY();
+ }
+
+ /**
+ * Get the rounded Y component of the position vector.
+ *
+ * @return the rounded Y component
+ */
+ public int getBlockY() {
+ return position.getBlockY();
+ }
+
+ /**
+ * Return a copy of this object with the Y component of the new object
+ * set to the given value.
+ *
+ * @param y the new value for the Y component
+ * @return a new immutable instance
+ */
+ public Location setY(double y) {
+ return new Location(world, position.setY(y), direction);
+ }
+
+ /**
+ * Return a copy of this object with the Y component of the new object
+ * set to the given value.
+ *
+ * @param y the new value for the Y component
+ * @return a new immutable instance
+ */
+ public Location setY(int y) {
+ return new Location(world, position.setY(y), direction);
+ }
+
+ /**
+ * Get the Z component of the position vector.
+ *
+ * @return the Z component
+ */
+ public double getZ() {
+ return position.getZ();
+ }
+
+ /**
+ * Get the rounded Z component of the position vector.
+ *
+ * @return the rounded Z component
+ */
+ public int getBlockZ() {
+ return position.getBlockZ();
+ }
+
+ /**
+ * Return a copy of this object with the Z component of the new object
+ * set to the given value.
+ *
+ * @param z the new value for the Y component
+ * @return a new immutable instance
+ */
+ public Location setZ(double z) {
+ return new Location(world, position.setZ(z), direction);
+ }
+
+ /**
+ * Return a copy of this object with the Z component of the new object
+ * set to the given value.
+ *
+ * @param z the new value for the Y component
+ * @return a new immutable instance
+ */
+ public Location setZ(int z) {
+ return new Location(world, position.setZ(z), direction);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Location location = (Location) o;
+
+ if (!direction.equals(location.direction)) return false;
+ if (!position.equals(location.position)) return false;
+ if (!world.equals(location.world)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = world.hashCode();
+ result = 31 * result + position.hashCode();
+ result = 31 * result + direction.hashCode();
+ return result;
+ }
+
+}
diff --git a/src/main/java/com/sk89q/worldedit/util/Vectors.java b/src/main/java/com/sk89q/worldedit/util/Vectors.java
new file mode 100644
index 000000000..277bf9c3d
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/util/Vectors.java
@@ -0,0 +1,65 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.util;
+
+import com.sk89q.worldedit.Vector;
+
+/**
+ * Utility methods for {@link Vector}s.
+ */
+public final class Vectors {
+
+ private Vectors() {
+ }
+
+ /**
+ * Create a new {@link Vector} using Euler angles specified in degrees,
+ * but with no roll.
+ *
+ * @param yaw the yaw
+ * @param pitch the pitch
+ * @return a new {@link Vector}
+ */
+ public static Vector fromEulerDeg(double yaw, double pitch) {
+ final double yawRadians = Math.toRadians(yaw);
+ final double pitchRadians = Math.toRadians(pitch);
+ return fromEulerRad(yawRadians, pitchRadians);
+ }
+
+ /**
+ * Create a new {@link Vector} using Euler angles specified in radians,
+ * but with no roll.
+ *
+ * @param yaw the yaw
+ * @param pitch the pitch
+ * @return a new {@link Vector}
+ */
+ public static Vector fromEulerRad(double yaw, double pitch) {
+ final double y = -Math.sin(pitch);
+
+ final double h = Math.cos(pitch);
+
+ final double x = -h * Math.sin(yaw);
+ final double z = h * Math.cos(yaw);
+
+ return new Vector(x, y, z);
+ }
+
+}
diff --git a/src/test/java/com/sk89q/worldedit/util/LocationTest.java b/src/test/java/com/sk89q/worldedit/util/LocationTest.java
new file mode 100644
index 000000000..ecf3bc327
--- /dev/null
+++ b/src/test/java/com/sk89q/worldedit/util/LocationTest.java
@@ -0,0 +1,156 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.util;
+
+import com.sk89q.worldedit.Vector;
+import com.sk89q.worldedit.world.World;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests {@link Location}.
+ */
+public class LocationTest {
+
+ private static final int TEST_VALUE = 10;
+ private static final double EPSILON = 0.0001;
+
+ @Test
+ public void testGetWorld() throws Exception {
+ World world = mock(World.class);
+ Location location = new Location(world);
+ assertEquals(world, location.getWorld());
+ }
+
+ @Test
+ public void testSetWorld() throws Exception {
+ World world1 = mock(World.class);
+ World world2 = mock(World.class);
+ Location location1 = new Location(world1);
+ Location location2 = location1.setWorld(world2);
+ assertEquals(world1, location1.getWorld());
+ assertEquals(world2, location2.getWorld());
+ }
+
+ @Test
+ public void testGetDirection() throws Exception {
+ World world = mock(World.class);
+ Vector direction = new Vector(1, 1, 1);
+ Location location = new Location(world, new Vector(), direction);
+ assertEquals(direction, location.getDirection());
+ }
+
+ @Test
+ public void testSetDirection() throws Exception {
+ World world = mock(World.class);
+ Vector direction1 = new Vector(1, 1, 1);
+ Vector direction2 = new Vector(2, 2, 2);
+ Location location1 = new Location(world, new Vector(), direction1);
+ Location location2 = location1.setDirection(direction2);
+ assertEquals(direction1, location1.getDirection());
+ assertEquals(direction2, location2.getDirection());
+ }
+
+ @Test
+ public void testToVector() throws Exception {
+ World world = mock(World.class);
+ Vector position = new Vector(1, 1, 1);
+ Location location = new Location(world, position);
+ assertEquals(position, location.toVector());
+ }
+
+ @Test
+ public void testGetX() throws Exception {
+ World world = mock(World.class);
+ Location location = new Location(world, new Vector(TEST_VALUE, 0, 0));
+ assertEquals(TEST_VALUE, location.getX(), EPSILON);
+ }
+
+ @Test
+ public void testGetBlockX() throws Exception {
+ World world = mock(World.class);
+ Location location = new Location(world, new Vector(TEST_VALUE, 0, 0));
+ assertEquals(TEST_VALUE, location.getBlockX());
+ }
+
+ @Test
+ public void testSetX() throws Exception {
+ World world = mock(World.class);
+ Location location1 = new Location(world, new Vector());
+ Location location2 = location1.setX(TEST_VALUE);
+ assertEquals(0, location1.getX(), EPSILON);
+ assertEquals(TEST_VALUE, location2.getX(), EPSILON);
+ assertEquals(0, location2.getY(), EPSILON);
+ assertEquals(0, location2.getZ(), EPSILON);
+ }
+
+ @Test
+ public void testGetY() throws Exception {
+ World world = mock(World.class);
+ Location location = new Location(world, new Vector(0, TEST_VALUE, 0));
+ assertEquals(TEST_VALUE, location.getY(), EPSILON);
+ }
+
+ @Test
+ public void testGetBlockY() throws Exception {
+ World world = mock(World.class);
+ Location location = new Location(world, new Vector(0, TEST_VALUE, 0));
+ assertEquals(TEST_VALUE, location.getBlockY());
+ }
+
+ @Test
+ public void testSetY() throws Exception {
+ World world = mock(World.class);
+ Location location1 = new Location(world, new Vector());
+ Location location2 = location1.setY(TEST_VALUE);
+ assertEquals(0, location1.getY(), EPSILON);
+ assertEquals(0, location2.getX(), EPSILON);
+ assertEquals(TEST_VALUE, location2.getY(), EPSILON);
+ assertEquals(0, location2.getZ(), EPSILON);
+ }
+
+ @Test
+ public void testGetZ() throws Exception {
+ World world = mock(World.class);
+ Location location = new Location(world, new Vector(0, 0, TEST_VALUE));
+ assertEquals(TEST_VALUE, location.getZ(), EPSILON);
+ }
+
+ @Test
+ public void testGetBlockZ() throws Exception {
+ World world = mock(World.class);
+ Location location = new Location(world, new Vector(0, 0, TEST_VALUE));
+ assertEquals(TEST_VALUE, location.getBlockZ());
+ }
+
+ @Test
+ public void testSetZ() throws Exception {
+ World world = mock(World.class);
+ Location location1 = new Location(world, new Vector());
+ Location location2 = location1.setZ(TEST_VALUE);
+ assertEquals(0, location1.getZ(), EPSILON);
+ assertEquals(0, location2.getX(), EPSILON);
+ assertEquals(0, location2.getY(), EPSILON);
+ assertEquals(TEST_VALUE, location2.getZ(), EPSILON);
+ }
+
+}