diff --git a/src/main/java/universalelectricity/api/vector/IRotation.java b/src/main/java/universalelectricity/api/vector/IRotation.java new file mode 100644 index 0000000..564c99b --- /dev/null +++ b/src/main/java/universalelectricity/api/vector/IRotation.java @@ -0,0 +1,13 @@ +package universalelectricity.api.vector; + +/** Simple interface to define that an object has rotation + * + * @author DarkGuardsman */ +public interface IRotation +{ + double yaw(); + + double pitch(); + + double roll(); +} \ No newline at end of file diff --git a/src/main/java/universalelectricity/api/vector/IVector2.java b/src/main/java/universalelectricity/api/vector/IVector2.java new file mode 100644 index 0000000..e18cc71 --- /dev/null +++ b/src/main/java/universalelectricity/api/vector/IVector2.java @@ -0,0 +1,11 @@ +package universalelectricity.api.vector; + +/** Useful interface to define that an object has a 2D location. + * + * @author DarkGuardsman */ +public interface IVector2 +{ + double x(); + + double y(); +} diff --git a/src/main/java/universalelectricity/api/vector/IVector3.java b/src/main/java/universalelectricity/api/vector/IVector3.java new file mode 100644 index 0000000..3caeb69 --- /dev/null +++ b/src/main/java/universalelectricity/api/vector/IVector3.java @@ -0,0 +1,9 @@ +package universalelectricity.api.vector; + +/** Useful interface to define that an object has a 3D location. + * + * @author DarkGuardsman */ +public interface IVector3 extends IVector2 +{ + double z(); +} diff --git a/src/main/java/universalelectricity/api/vector/IVectorWorld.java b/src/main/java/universalelectricity/api/vector/IVectorWorld.java new file mode 100644 index 0000000..732dfcb --- /dev/null +++ b/src/main/java/universalelectricity/api/vector/IVectorWorld.java @@ -0,0 +1,11 @@ +package universalelectricity.api.vector; + +import net.minecraft.world.World; + +/** Useful interface to define that an object has a 3D location, and a defined world. + * + * @author DarkGuardsman */ +public interface IVectorWorld extends IVector3 +{ + World world(); +} diff --git a/src/main/java/universalelectricity/core/vector/EulerAngle.java b/src/main/java/universalelectricity/core/vector/EulerAngle.java new file mode 100644 index 0000000..5b268e2 --- /dev/null +++ b/src/main/java/universalelectricity/core/vector/EulerAngle.java @@ -0,0 +1,241 @@ +package universalelectricity.core.vector; + +import net.minecraftforge.common.util.ForgeDirection; +import universalelectricity.api.vector.IRotation; +import universalelectricity.api.vector.IVector3; + +/** The euler angles describing a 3D rotation. The rotation always in degrees. + * + * Note: The rotational system Minecraft uses is non-standard. The angles and vector calculations + * have been calibrated to match. DEFINITIONS: + * + * Yaw: 0 Degrees - Looking at NORTH 90 - Looking at WEST 180 - Looking at SOUTH 270 - Looking at + * EAST + * + * Pitch: 0 Degrees - Looking straight forward towards the horizon. 90 Degrees - Looking straight up + * to the sky. -90 Degrees - Looking straight down to the void. + * + * Make sure all models are use the Techne Model loader, they will naturally follow this rule. + * + * @author Calclavia */ +public class EulerAngle implements IRotation, IVector3 +{ + /** Angles in degrees. */ + public double yaw, pitch, roll; + + public EulerAngle() + { + this(0, 0, 0); + } + + public EulerAngle(ForgeDirection dir) + { + switch (dir) + { + case DOWN: + pitch = -90; + break; + case UP: + pitch = 90; + break; + case NORTH: + yaw = 0; + break; + case SOUTH: + yaw = 180; + break; + case WEST: + yaw = 90; + break; + case EAST: + // or 270 degrees + yaw = -90; + break; + default: + break; + } + } + + public EulerAngle(double yaw, double pitch, double roll) + { + this.yaw = yaw; + this.pitch = pitch; + this.roll = roll; + } + + public EulerAngle(double[] angles) + { + this(angles[0], angles[1], angles[2]); + } + + public EulerAngle(EulerAngle angle) + { + this(angle.yaw(), angle.pitch(), angle.roll()); + } + + public EulerAngle(double yaw, double pitch) + { + this(yaw, pitch, 0); + } + + @Override + public double yaw() + { + return yaw; + } + + @Override + public double pitch() + { + return pitch; + } + + @Override + public double roll() + { + return roll; + } + + public double yawRadians() + { + return Math.toRadians(yaw()); + } + + public double pitchRadians() + { + return Math.toRadians(pitch()); + } + + public double rollRadians() + { + return Math.toRadians(roll()); + } + + @Override + public double x() + { + return -Math.sin(yawRadians()) * Math.cos(pitchRadians()); + } + + @Override + public double y() + { + return Math.sin(pitchRadians()); + } + + @Override + public double z() + { + return -Math.cos(yawRadians()) * Math.cos(pitchRadians()); + } + + public double[] toArray() + { + return new double[] { yaw(), pitch(), roll() }; + } + + public double[] toRadianArray() + { + return new double[] { yawRadians(), pitchRadians(), rollRadians() }; + } + + public EulerAngle set(int i, double value) + { + switch (i) + { + case 0: + yaw = value; + break; + case 1: + pitch = value; + break; + case 2: + roll = value; + break; + } + + return this; + } + + /** gets the difference in degrees between the two angles */ + public EulerAngle difference(EulerAngle other) + { + return new EulerAngle(yaw() - other.yaw(), pitch() - other.pitch(), roll() - other.roll()); + } + + public EulerAngle absoluteDifference(EulerAngle other) + { + return new EulerAngle(getAngleDifference(yaw(), other.yaw()), getAngleDifference(pitch(), other.pitch()), getAngleDifference(roll(), other.roll())); + } + + public boolean isWithin(EulerAngle other, double margin) + { + for (int i = 0; i < 3; i++) + if (absoluteDifference(other).toArray()[i] > margin) + return false; + + return true; + } + + public static double getAngleDifference(double angleA, double angleB) + { + return Math.abs(angleA - angleB); + } + + @Override + public EulerAngle clone() + { + return new EulerAngle(this.yaw(), this.pitch(), this.roll()); + } + + public static double clampAngleTo360(double var) + { + return clampAngle(var, -360, 360); + } + + public static double clampAngleTo180(double var) + { + return clampAngle(var, -180, 180); + } + + public static double clampAngle(double var, double min, double max) + { + while (var < min) + var += 360; + + while (var > max) + var -= 360; + + return var; + } + + @Override + public int hashCode() + { + long x = Double.doubleToLongBits(yaw()); + long y = Double.doubleToLongBits(pitch()); + long z = Double.doubleToLongBits(roll()); + int hash = (int) (x ^ (x >>> 32)); + hash = 31 * hash + (int) (y ^ (y >>> 32)); + hash = 31 * hash + (int) (z ^ (z >>> 32)); + return hash; + } + + @Override + public boolean equals(Object o) + { + if (o instanceof EulerAngle) + { + EulerAngle angle = (EulerAngle) o; + return yaw() == angle.yaw() && pitch() == angle.pitch() && roll() == angle.roll(); + } + + return false; + } + + @Override + public String toString() + { + return "Angle [" + this.yaw() + "," + this.pitch() + "," + this.roll() + "]"; + } +} diff --git a/src/main/java/universalelectricity/core/vector/Quaternion.java b/src/main/java/universalelectricity/core/vector/Quaternion.java new file mode 100644 index 0000000..67669b3 --- /dev/null +++ b/src/main/java/universalelectricity/core/vector/Quaternion.java @@ -0,0 +1,156 @@ +package universalelectricity.core.vector; + +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; + +public class Quaternion implements Cloneable +{ + public double x; + public double y; + public double z; + public double s; + public static final double SQRT2 = Math.sqrt(2D); + + public Quaternion() + { + s = 1; + x = 0; + y = 0; + z = 0; + } + + public Quaternion(Quaternion Quaternion) + { + x = Quaternion.x; + y = Quaternion.y; + z = Quaternion.z; + s = Quaternion.s; + } + + public Quaternion(double d, double d1, double d2, double d3) + { + x = d1; + y = d2; + z = d3; + s = d; + } + + public Quaternion set(Quaternion Quaternion) + { + x = Quaternion.x; + y = Quaternion.y; + z = Quaternion.z; + s = Quaternion.s; + + return this; + } + + public Quaternion set(double d, double d1, double d2, double d3) + { + x = d1; + y = d2; + z = d3; + s = d; + + return this; + } + + public static Quaternion aroundAxis(double ax, double ay, double az, double angle) + { + return new Quaternion().setAroundAxis(ax, ay, az, angle); + } + + public static Quaternion aroundAxis(Vector3 axis, double angle) + { + return aroundAxis(axis.x, axis.y, axis.z, angle); + } + + public Quaternion setAroundAxis(double ax, double ay, double az, double angle) + { + angle *= 0.5; + double d4 = Math.sin(angle); + return set(Math.cos(angle), ax * d4, ay * d4, az * d4); + } + + public Quaternion setAroundAxis(Vector3 axis, double angle) + { + return setAroundAxis(axis.x, axis.y, axis.z, angle); + } + + public Quaternion multiply(Quaternion Quaternion) + { + double d = s * Quaternion.s - x * Quaternion.x - y * Quaternion.y - z * Quaternion.z; + double d1 = s * Quaternion.x + x * Quaternion.s - y * Quaternion.z + z * Quaternion.y; + double d2 = s * Quaternion.y + x * Quaternion.z + y * Quaternion.s - z * Quaternion.x; + double d3 = s * Quaternion.z - x * Quaternion.y + y * Quaternion.x + z * Quaternion.s; + s = d; + x = d1; + y = d2; + z = d3; + + return this; + } + + public Quaternion rightMultiply(Quaternion Quaternion) + { + double d = s * Quaternion.s - x * Quaternion.x - y * Quaternion.y - z * Quaternion.z; + double d1 = s * Quaternion.x + x * Quaternion.s + y * Quaternion.z - z * Quaternion.y; + double d2 = s * Quaternion.y - x * Quaternion.z + y * Quaternion.s + z * Quaternion.x; + double d3 = s * Quaternion.z + x * Quaternion.y - y * Quaternion.x + z * Quaternion.s; + s = d; + x = d1; + y = d2; + z = d3; + + return this; + } + + public double mag() + { + return Math.sqrt(x * x + y * y + z * z + s * s); + } + + public Quaternion normalize() + { + double d = mag(); + if (d != 0) + { + d = 1 / d; + x *= d; + y *= d; + z *= d; + s *= d; + } + + return this; + } + + public Quaternion copy() + { + return new Quaternion(this); + } + + public void rotate(Vector3 vec) + { + double d = -x * vec.x - y * vec.y - z * vec.z; + double d1 = s * vec.x + y * vec.z - z * vec.y; + double d2 = s * vec.y - x * vec.z + z * vec.x; + double d3 = s * vec.z + x * vec.y - y * vec.x; + vec.x = d1 * s - d * x - d2 * z + d3 * y; + vec.y = d2 * s - d * y + d1 * z - d3 * x; + vec.z = d3 * s - d * z - d1 * y + d2 * x; + } + + @Override + public String toString() + { + MathContext cont = new MathContext(4, RoundingMode.HALF_UP); + return "Quaternion[" + new BigDecimal(s, cont) + ", " + new BigDecimal(x, cont) + ", " + new BigDecimal(y, cont) + ", " + new BigDecimal(z, cont) + "]"; + } + + public Rotation rotation() + { + return new Rotation(this); + } +} diff --git a/src/main/java/universalelectricity/core/vector/Rotation.java b/src/main/java/universalelectricity/core/vector/Rotation.java new file mode 100644 index 0000000..3b6aa88 --- /dev/null +++ b/src/main/java/universalelectricity/core/vector/Rotation.java @@ -0,0 +1,48 @@ +package universalelectricity.core.vector; + +public class Rotation +{ + public double angle; + public Vector3 axis; + private Quaternion quat; + + public Rotation(double angle, Vector3 axis) + { + this.angle = angle; + this.axis = axis; + } + + public Rotation(double angle, double x, double y, double z) + { + this(angle, new Vector3(x, y, z)); + } + + public Rotation(Quaternion quat) + { + this.quat = quat; + + angle = Math.acos(quat.s) * 2; + if (angle == 0) + { + axis = new Vector3(0, 1, 0); + } + else + { + double sa = Math.sin(angle * 0.5); + axis = new Vector3(quat.x / sa, quat.y / sa, quat.z / sa); + } + } + + public void apply(Vector3 vec) + { + if (quat == null) + quat = Quaternion.aroundAxis(axis, angle); + + vec.rotate(quat); + } + + public void applyN(Vector3 normal) + { + apply(normal); + } +} diff --git a/src/main/java/universalelectricity/core/vector/Vector2.java b/src/main/java/universalelectricity/core/vector/Vector2.java index 4b9e35f..420c409 100644 --- a/src/main/java/universalelectricity/core/vector/Vector2.java +++ b/src/main/java/universalelectricity/core/vector/Vector2.java @@ -1,101 +1,112 @@ package universalelectricity.core.vector; import net.minecraft.util.MathHelper; +import universalelectricity.api.vector.IVector2; -public class Vector2 implements Cloneable { +public class Vector2 implements Cloneable, IVector2 { public double x; public double y; public Vector2() { - this(0.0D, 0.0D); + this(0.0D, 0.0D); } public Vector2(double x, double y) { - this.x = x; - this.y = y; + this.x = x; + this.y = y; } public int intX() { - return (int)Math.floor(this.x); + return (int)Math.floor(this.x); } public int intY() { - return (int)Math.floor(this.y); + return (int)Math.floor(this.y); } public Vector2 clone() { - return new Vector2(this.x, this.y); + return new Vector2(this.x, this.y); } public static double distance(Vector2 point1, Vector2 point2) { - double xDifference = point1.x - point2.x; - double yDiference = point1.y - point2.y; - return (double)MathHelper.sqrt_double(xDifference * xDifference + yDiference * yDiference); + double xDifference = point1.x - point2.x; + double yDiference = point1.y - point2.y; + return (double)MathHelper.sqrt_double(xDifference * xDifference + yDiference * yDiference); } public static double slope(Vector2 point1, Vector2 point2) { - double xDifference = point1.x - point2.x; - double yDiference = point1.y - point2.y; - return yDiference / xDifference; + double xDifference = point1.x - point2.x; + double yDiference = point1.y - point2.y; + return yDiference / xDifference; } public double distanceTo(Vector2 target) { - double xDifference = this.x - target.x; - double yDifference = this.y - target.y; - return (double)MathHelper.sqrt_double(xDifference * xDifference + yDifference * yDifference); + double xDifference = this.x - target.x; + double yDifference = this.y - target.y; + return (double)MathHelper.sqrt_double(xDifference * xDifference + yDifference * yDifference); } public Vector2 add(Vector2 par1) { - this.x += par1.x; - this.y += par1.y; - return this; + this.x += par1.x; + this.y += par1.y; + return this; } public Vector2 add(double par1) { - this.x += par1; - this.y += par1; - return this; + this.x += par1; + this.y += par1; + return this; } public Vector2 invert() { - this.multiply(-1.0D); - return this; + this.multiply(-1.0D); + return this; } public Vector2 multiply(double amount) { - this.x *= amount; - this.y *= amount; - return this; + this.x *= amount; + this.y *= amount; + return this; } public Vector2 round() { - return new Vector2((double)Math.round(this.x), (double)Math.round(this.y)); + return new Vector2((double)Math.round(this.x), (double)Math.round(this.y)); } public Vector2 ceil() { - return new Vector2(Math.ceil(this.x), Math.ceil(this.y)); + return new Vector2(Math.ceil(this.x), Math.ceil(this.y)); } public Vector2 floor() { - return new Vector2(Math.floor(this.x), Math.floor(this.y)); + return new Vector2(Math.floor(this.x), Math.floor(this.y)); } public int hashCode() { - return ("X:" + this.x + "Y:" + this.y).hashCode(); + return ("X:" + this.x + "Y:" + this.y).hashCode(); } public boolean equals(Object o) { - if(!(o instanceof Vector2)) { - return false; - } else { - Vector2 vector = (Vector2)o; - return this.x == vector.x && this.y == vector.y; - } + if(!(o instanceof Vector2)) { + return false; + } else { + Vector2 vector = (Vector2)o; + return this.x == vector.x && this.y == vector.y; + } } public String toString() { - return "Vector2 [" + this.x + "," + this.y + "]"; + return "Vector2 [" + this.x + "," + this.y + "]"; + } + + @Override + public double x() { + return this.x; + } + + @Override + public double y() { + return this.y; } } diff --git a/src/main/java/universalelectricity/core/vector/Vector3.java b/src/main/java/universalelectricity/core/vector/Vector3.java index 87791e4..af10747 100644 --- a/src/main/java/universalelectricity/core/vector/Vector3.java +++ b/src/main/java/universalelectricity/core/vector/Vector3.java @@ -14,8 +14,9 @@ import net.minecraft.util.Vec3; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; +import universalelectricity.api.vector.IVector3; -public class Vector3 implements Cloneable { +public class Vector3 implements Cloneable, IVector3 { public double x; public double y; @@ -68,6 +69,17 @@ public class Vector3 implements Cloneable { this.z = (double)direction.offsetZ; } + public Vector3(double yaw, double pitch) + { + this(new EulerAngle(yaw, pitch)); + } + + public Vector3(IVector3 vec3) { + this.x = vec3.x(); + this.y = vec3.y(); + this.z = vec3.z(); + } + public int intX() { return (int)Math.floor(this.x); } @@ -283,4 +295,394 @@ public class Vector3 implements Cloneable { public String toString() { return "Vector3 [" + this.x + "," + this.y + "," + this.z + "]"; } + + @Override + public double x() { + return this.x; + } + + @Override + public double y() { + return this.y; + } + + @Override + public double z() { + return this.z; + } + + public EulerAngle toAngle() + { + return new EulerAngle(Math.toDegrees(Math.atan2(x, z)), Math.toDegrees(-Math.atan2(y, Math.hypot(z, x)))); + } + + public EulerAngle toAngle(IVector3 target) + { + return clone().difference(target).toAngle(); + } + + public static Vector3 UP() + { + return new Vector3(0, 1, 0); + } + + public static Vector3 DOWN() + { + return new Vector3(0, -1, 0); + } + + public static Vector3 NORTH() + { + return new Vector3(0, 0, -1); + } + + public static Vector3 SOUTH() + { + return new Vector3(0, 0, 1); + } + + public static Vector3 WEST() + { + return new Vector3(-1, 0, 0); + } + + public static Vector3 EAST() + { + return new Vector3(1, 0, 0); + } + + public static Vector3 ZERO() + { + return new Vector3(0, 0, 0); + } + + public static Vector3 CENTER() + { + return new Vector3(0.5, 0.5, 0.5); + } + + public Vector3 translate(ForgeDirection side, double amount) + { + return this.translate(new Vector3(side).scale(amount)); + } + + public Vector3 translate(ForgeDirection side) + { + return this.translate(side, 1); + } + + public Vector3 translate(IVector3 addition) + { + this.x += addition.x(); + this.y += addition.y(); + this.z += addition.z(); + return this; + } + + public Vector3 translate(double x, double y, double z) + { + this.x += x; + this.y += y; + this.z += z; + return this; + } + + public Vector3 translate(double addition) + { + this.x += addition; + this.y += addition; + this.z += addition; + return this; + } + + public static Vector3 translate(Vector3 first, IVector3 second) + { + return first.clone().translate(second); + } + + public static Vector3 translate(Vector3 translate, double addition) + { + return translate.clone().translate(addition); + } + + public Vector3 scale(double amount) + { + this.x *= amount; + this.y *= amount; + this.z *= amount; + return this; + } + + public Vector3 scale(double x, double y, double z) + { + this.x *= x; + this.y *= y; + this.z *= z; + return this; + } + + public Vector3 scale(Vector3 amount) + { + this.x *= amount.x; + this.y *= amount.y; + this.z *= amount.z; + return this; + } + + public static Vector3 scale(Vector3 vec, double amount) + { + return vec.scale(amount); + } + + public static Vector3 scale(Vector3 vec, Vector3 amount) + { + return vec.scale(amount); + } + + public Vector3 difference(IVector3 amount) + { + return this.translate(-amount.x(), -amount.y(), -amount.z()); + } + + public Vector3 difference(double amount) + { + return this.translate(-amount); + } + + public Vector3 difference(double x, double y, double z) + { + this.x -= x; + this.y -= y; + this.z -= z; + return this; + } + + /** + * RayTrace Code, retrieved from MachineMuse. + * + * @author MachineMuse + */ + public MovingObjectPosition rayTrace(World world, float rotationYaw, float rotationPitch, boolean collisionFlag, double reachDistance) + { + Vector3 lookVector = new Vector3(rotationYaw, rotationPitch); + Vector3 reachPoint = this.clone().translate(lookVector.clone().scale(reachDistance)); + return rayTrace(world, reachPoint, collisionFlag); + } + + public MovingObjectPosition rayTrace(World world, Vector3 reachPoint, boolean collisionFlag) + { + MovingObjectPosition pickedBlock = this.rayTraceBlocks(world, reachPoint.clone(), collisionFlag); + MovingObjectPosition pickedEntity = this.rayTraceEntities(world, reachPoint.clone()); + + if (pickedBlock == null) + { + return pickedEntity; + } + else if (pickedEntity == null) + { + return pickedBlock; + } + else + { + double dBlock = this.distanceTo(new Vector3(pickedBlock.hitVec)); + double dEntity = this.distanceTo(new Vector3(pickedEntity.hitVec)); + + if (dEntity < dBlock) + { + return pickedEntity; + } + else + { + return pickedBlock; + } + } + } + + public MovingObjectPosition rayTrace(World world, boolean collisionFlag, double reachDistance) + { + return rayTrace(world, 0, 0, collisionFlag, reachDistance); + } + + public MovingObjectPosition rayTraceBlocks(World world, float rotationYaw, float rotationPitch, boolean collisionFlag, double reachDistance) + { + Vector3 lookVector = new Vector3(rotationYaw, rotationPitch); + Vector3 reachPoint = this.clone().translate(lookVector.clone().scale(reachDistance)); + return rayTraceBlocks(world, reachPoint, collisionFlag); + } + + public MovingObjectPosition rayTraceBlocks(World world, Vector3 vec, boolean collisionFlag) + { + return world.rayTraceBlocks(this.toVec3(), vec.toVec3(), collisionFlag); + } + + @Deprecated + public MovingObjectPosition rayTraceEntities(World world, float rotationYaw, float rotationPitch, boolean collisionFlag, double reachDistance) + { + return this.rayTraceEntities(world, rotationYaw, rotationPitch, reachDistance); + } + + public MovingObjectPosition rayTraceEntities(World world, float rotationYaw, float rotationPitch, double reachDistance) + { + return this.rayTraceEntities(world, new Vector3(rotationYaw, rotationPitch).scale(reachDistance)); + } + + /** + * Does an entity raytrace. + * + * @param world - The world object. + * @param target - The rotation in terms of Vector3. Convert using + * getDeltaPositionFromRotation() + * @return The target hit. + */ + public MovingObjectPosition rayTraceEntities(World world, Vector3 target) + { + MovingObjectPosition pickedEntity = null; + Vec3 startingPosition = toVec3(); + Vec3 look = target.toVec3(); + double reachDistance = distanceTo(target); + //Vec3 reachPoint = Vec3.createVectorHelper(startingPosition.xCoord + look.xCoord * reachDistance, startingPosition.yCoord + look.yCoord * reachDistance, startingPosition.zCoord + look.zCoord * reachDistance); + + double checkBorder = 1.1 * reachDistance; + AxisAlignedBB boxToScan = AxisAlignedBB.getBoundingBox(-checkBorder, -checkBorder, -checkBorder, checkBorder, checkBorder, checkBorder).offset(this.x, this.y, this.z); + + @SuppressWarnings("unchecked") + List entitiesInBounds = world.getEntitiesWithinAABBExcludingEntity(null, boxToScan); + double closestEntity = reachDistance; + + if (entitiesInBounds == null || entitiesInBounds.isEmpty()) + { + return null; + } + for (Entity possibleHits : entitiesInBounds) + { + if (possibleHits != null && possibleHits.canBeCollidedWith() && possibleHits.boundingBox != null) + { + float border = possibleHits.getCollisionBorderSize(); + AxisAlignedBB aabb = possibleHits.boundingBox.expand(border, border, border); + MovingObjectPosition hitMOP = aabb.calculateIntercept(startingPosition, target.toVec3()); + + if (hitMOP != null) + { + if (aabb.isVecInside(startingPosition)) + { + if (0.0D < closestEntity || closestEntity == 0.0D) + { + pickedEntity = new MovingObjectPosition(possibleHits); + if (pickedEntity != null) + { + pickedEntity.hitVec = hitMOP.hitVec; + closestEntity = 0.0D; + } + } + } + else + { + double distance = startingPosition.distanceTo(hitMOP.hitVec); + + if (distance < closestEntity || closestEntity == 0.0D) + { + pickedEntity = new MovingObjectPosition(possibleHits); + pickedEntity.hitVec = hitMOP.hitVec; + closestEntity = distance; + } + } + } + } + } + return pickedEntity; + } + + public MovingObjectPosition rayTraceEntities(World world, Entity target) + { + return rayTraceEntities(world, new Vector3(target)); + } + + public Vector3 rotate(float angle, Vector3 axis) + { + return translateMatrix(getRotationMatrix(angle), this); + } + + public double[] getRotationMatrix(float angle) + { + double[] matrix = new double[16]; + Vector3 axis = this.clone().normalize(); + double x = axis.x; + double y = axis.y; + double z = axis.z; + angle *= 0.0174532925D; + float cos = (float) Math.cos(angle); + float ocos = 1.0F - cos; + float sin = (float) Math.sin(angle); + matrix[0] = (x * x * ocos + cos); + matrix[1] = (y * x * ocos + z * sin); + matrix[2] = (x * z * ocos - y * sin); + matrix[4] = (x * y * ocos - z * sin); + matrix[5] = (y * y * ocos + cos); + matrix[6] = (y * z * ocos + x * sin); + matrix[8] = (x * z * ocos + y * sin); + matrix[9] = (y * z * ocos - x * sin); + matrix[10] = (z * z * ocos + cos); + matrix[15] = 1.0F; + return matrix; + } + + public static Vector3 translateMatrix(double[] matrix, Vector3 translation) + { + double x = translation.x * matrix[0] + translation.y * matrix[1] + translation.z * matrix[2] + matrix[3]; + double y = translation.x * matrix[4] + translation.y * matrix[5] + translation.z * matrix[6] + matrix[7]; + double z = translation.x * matrix[8] + translation.y * matrix[9] + translation.z * matrix[10] + matrix[11]; + translation.x = x; + translation.y = y; + translation.z = z; + return translation; + } + + @Deprecated + public void rotate(double yaw, double pitch, double roll) + { + rotate(new EulerAngle(yaw, roll)); + } + + /** Rotates this Vector by a yaw, pitch and roll value. */ + public void rotate(EulerAngle angle) + { + double yawRadians = angle.yawRadians(); + double pitchRadians = angle.pitchRadians(); + double rollRadians = angle.rollRadians(); + + double x = this.x; + double y = this.y; + double z = this.z; + + this.x = x * Math.cos(yawRadians) * Math.cos(pitchRadians) + z * (Math.cos(yawRadians) * Math.sin(pitchRadians) * Math.sin(rollRadians) - Math.sin(yawRadians) * Math.cos(rollRadians)) + y * (Math.cos(yawRadians) * Math.sin(pitchRadians) * Math.cos(rollRadians) + Math.sin(yawRadians) * Math.sin(rollRadians)); + this.z = x * Math.sin(yawRadians) * Math.cos(pitchRadians) + z * (Math.sin(yawRadians) * Math.sin(pitchRadians) * Math.sin(rollRadians) + Math.cos(yawRadians) * Math.cos(rollRadians)) + y * (Math.sin(yawRadians) * Math.sin(pitchRadians) * Math.cos(rollRadians) - Math.cos(yawRadians) * Math.sin(rollRadians)); + this.y = -x * Math.sin(pitchRadians) + z * Math.cos(pitchRadians) * Math.sin(rollRadians) + y * Math.cos(pitchRadians) * Math.cos(rollRadians); + } + + /** Rotates a point by a yaw and pitch around the anchor 0,0 by a specific angle. */ + public void rotate(double yaw, double pitch) + { + rotate(new EulerAngle(yaw, pitch)); + } + + public void rotate(double yaw) + { + double yawRadians = Math.toRadians(yaw); + + double x = this.x; + double z = this.z; + + if (yaw != 0) + { + this.x = x * Math.cos(yawRadians) - z * Math.sin(yawRadians); + this.z = x * Math.sin(yawRadians) + z * Math.cos(yawRadians); + } + } + + public Vector3 rotate(Quaternion rotator) + { + rotator.rotate(this); + return this; + } + } diff --git a/src/main/java/universalelectricity/core/vector/VectorWorld.java b/src/main/java/universalelectricity/core/vector/VectorWorld.java new file mode 100644 index 0000000..99d4f00 --- /dev/null +++ b/src/main/java/universalelectricity/core/vector/VectorWorld.java @@ -0,0 +1,159 @@ +package universalelectricity.core.vector; + +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.world.World; +import universalelectricity.api.vector.IVector3; +import universalelectricity.api.vector.IVectorWorld; + +public class VectorWorld extends Vector3 implements IVectorWorld +{ + public World world; + + public VectorWorld(World world, double x, double y, double z) + { + super(x, y, z); + this.world = world; + } + + public VectorWorld(IVectorWorld vectorWorld) + { + this(vectorWorld.world(), vectorWorld.x(), vectorWorld.y(), vectorWorld.z()); + } + + public VectorWorld(Entity entity) + { + super(entity); + this.world = entity.worldObj; + } + + public VectorWorld(TileEntity tile) + { + super(tile); + this.world = tile.getWorldObj(); + } + + public VectorWorld(World world, IVector3 v) + { + this.x = v.x(); + this.y = v.y(); + this.z = v.z(); + this.world = world; + } + + @Override + public World world() + { + return this.world; + } + + @Override + public VectorWorld translate(double x, double y, double z) + { + this.x += x; + this.y += y; + this.z += z; + return this; + } + + @Override + public VectorWorld clone() + { + return new VectorWorld(world, x, y, z); + } + + @Override + public NBTTagCompound writeToNBT(NBTTagCompound nbt) + { + super.writeToNBT(nbt); + nbt.setInteger("d", this.world.provider.dimensionId); + return nbt; + } + + public Block getBlock() + { + return super.getBlock(this.world); + } + + public int getBlockMetadata() + { + return super.getBlockMetadata(this.world); + } + + public TileEntity getTileEntity() + { + // Ensure that the world object actually exists. + if (this.world != null) + { + return super.getTileEntity(this.world); + } + + return null; + } + + public boolean setBlock(Block id, int metadata, int notify) + { + return super.setBlock(this.world, id, metadata, notify); + } + + public boolean setBlock(Block id, int metadata) + { + return this.setBlock(id, metadata, 3); + } + + public boolean setBlock(Block id) + { + return this.setBlock(id, 0); + } + + public List getEntitiesWithin(Class par1Class) + { + return super.getEntitiesWithin(this.world, par1Class); + } + + public static VectorWorld fromCenter(Entity e) + { + return new VectorWorld(e.worldObj, e.posX, e.posY - e.yOffset + e.height / 2, e.posZ); + } + + public static VectorWorld fromCenter(TileEntity e) + { + return new VectorWorld(e.getWorldObj(), e.xCoord + 0.5, e.yCoord + 0.5, e.zCoord + 0.5); + } + + public MovingObjectPosition rayTraceEntities(VectorWorld target) + { + return super.rayTraceEntities(target.world(), target); + } + + public MovingObjectPosition rayTraceEntities(Entity target) + { + return super.rayTraceEntities(world, target); + } + + public MovingObjectPosition rayTraceEntities(Vector3 target) + { + return super.rayTraceEntities(world, target); + } + + @Override + public boolean equals(Object o) + { + if (o instanceof VectorWorld) + { + return super.equals(o) && this.world == ((VectorWorld) o).world; + } + return super.equals(o); + } + + @Override + public String toString() + { + return "VectorWorld [" + this.x + "," + this.y + "," + this.z + "," + this.world + "]"; + } +}