diff --git a/src/main/java/net/knarcraft/stargate/SimpleVectorOperation.java b/src/main/java/net/knarcraft/stargate/SimpleVectorOperation.java new file mode 100644 index 0000000..31d207c --- /dev/null +++ b/src/main/java/net/knarcraft/stargate/SimpleVectorOperation.java @@ -0,0 +1,191 @@ +package net.knarcraft.stargate; + +import org.bukkit.Axis; +import org.bukkit.block.BlockFace; +import org.bukkit.util.BlockVector; +import org.bukkit.util.Vector; + +import java.util.HashMap; +import java.util.Map; + +/** + * A simpler version of the vector operation class, but with the same functionality + * + * @author Kristian Knarvik + */ +public class SimpleVectorOperation { + + private static final Map rotationAngles = new HashMap<>(); + private static final Map rotationAxes = new HashMap<>(); + private static final Map normalAxes = new HashMap<>(); + private static final BlockFace defaultDirection = BlockFace.SOUTH; + private static final Axis defaultVerticalAxis = Axis.Y; + + private final Axis normalAxis; + private boolean flipZAxis = false; + private final BlockFace facing; + + /** + * Instantiates a vector operation to rotate vectors in the direction of a sign face + * + *

Gate structures have their relative location represented by a vector where x = outwards, y = down and + * z = right. The vector operation rotates the given vectors so that "outwards" is going the same direction as the + * given sign face.

+ * + * @param signFace

The sign face of a gate's sign

+ */ + public SimpleVectorOperation(BlockFace signFace) { + if (normalAxes.isEmpty()) { + initializeIrisNormalAxes(); + initializeOperations(); + } + + this.facing = signFace; + this.normalAxis = normalAxes.get(signFace); + } + + /** + * Gets the block face of a sign given upon instantiation + * + * @return

The block face of a sign given upon instantiation

+ */ + public BlockFace getFacing() { + return facing; + } + + /** + * Gets the normal axis orthogonal to the opening plane + * + *

Said another way, get the axis going directly towards or away from a stargate's entrance.

+ * + * @return

The normal axis orthogonal to the iris plane

+ */ + public Axis getNormalAxis() { + return normalAxis; + } + + /** + * Sets whether to flip the Z- axis + * + * @param flipZAxis

Whether to flip the z-axis

+ */ + public void setFlipZAxis(boolean flipZAxis) { + this.flipZAxis = flipZAxis; + } + + /** + * Performs this vector operation on the given vector + * + *

Inverse operation of doInverse; A vector operation that rotates around the origin, and flips the z-axis. + * Does not permute input vector

+ * + * @param vector

The vector to perform the operation on

+ * @return vector

A new vector with the operation applied

+ */ + public Vector performOperation(Vector vector) { + Vector clone = vector.clone(); + clone.rotateAroundAxis(rotationAxes.get(facing), rotationAngles.get(facing)); + if (flipZAxis) { + clone.setZ(-clone.getZ()); + } + return clone; + } + + /** + * Performs the reverse of this vector operation on the given vector + * + *

Inverse operation of doOperation; A vector operation that rotates around + * the origin and flips the z-axis. Does not permute input vector

+ * + * @param vector

The vector to perform the inverse operation on

+ * @return vector

A new vector with the inverse operation applied

+ */ + public Vector performInverseOperation(Vector vector) { + Vector clone = vector.clone(); + if (flipZAxis) { + clone.setZ(-clone.getZ()); + } + return clone.rotateAroundAxis(rotationAxes.get(facing), -rotationAngles.get(facing)); + } + + /** + * Performs the reverse of this vector operation on the given vector + * + *

Inverse operation of doOperation; A vector operation that rotates around + * the origin and flips the z-axis. Does not permute input vector

+ * + * @param vector

The vector to perform the inverse operation on

+ * @return vector

A new vector with the inverse operation applied

+ */ + public BlockVector performInverseOperation(BlockVector vector) { + return performInverseOperation((Vector) vector).toBlockVector(); + } + + /** + * Initializes the operations used for rotating to each block-face + */ + private static void initializeOperations() { + Map axisVectors = new HashMap<>(); + axisVectors.put(Axis.Y, new Vector(0, 1, 0)); + axisVectors.put(Axis.X, new Vector(1, 0, 0)); + axisVectors.put(Axis.Z, new Vector(0, 0, 1)); + + //Use the cross product to find the correct axis + for (BlockFace face : normalAxes.keySet()) { + Vector crossProduct = face.getDirection().crossProduct(defaultDirection.getDirection()); + if (face == defaultDirection || face == defaultDirection.getOppositeFace()) { + rotationAxes.put(face, axisVectors.get(defaultVerticalAxis)); + } else if (Math.abs(crossProduct.getZ()) > 0) { + rotationAxes.put(face, axisVectors.get(Axis.Z)); + } else if (Math.abs(crossProduct.getY()) > 0) { + rotationAxes.put(face, axisVectors.get(Axis.Y)); + } else { + rotationAxes.put(face, axisVectors.get(Axis.X)); + } + } + + calculateRotations(); + } + + /** + * Calculates the required rotations based on the default rotation + */ + private static void calculateRotations() { + double halfRotation = Math.PI; + double quarterRotation = halfRotation / 2; + + Vector defaultDirectionVector = defaultDirection.getDirection(); + boolean defaultDirectionPositive = defaultDirectionVector.getX() + defaultDirectionVector.getY() + + defaultDirectionVector.getZ() > 0; + + for (BlockFace blockFace : normalAxes.keySet()) { + if (defaultDirection == blockFace) { + //The default direction requires no rotation + rotationAngles.put(blockFace, 0d); + } else if (defaultDirection.getOppositeFace() == blockFace) { + //The opposite direction requires a half rotation + rotationAngles.put(blockFace, halfRotation); + } else { + //All the other used directions require a quarter rotation + Vector faceDirectionVector = blockFace.getDirection(); + boolean faceDirectionPositive = faceDirectionVector.getX() + faceDirectionVector.getY() + + faceDirectionVector.getZ() > 0; + double rotation = defaultDirectionPositive && faceDirectionPositive ? quarterRotation : -quarterRotation; + rotationAngles.put(blockFace, rotation); + } + } + } + + /** + * Initializes the iris normal axes corresponding to each block face + */ + private static void initializeIrisNormalAxes() { + normalAxes.put(BlockFace.EAST, Axis.Z); + normalAxes.put(BlockFace.WEST, Axis.Z); + normalAxes.put(BlockFace.NORTH, Axis.X); + normalAxes.put(BlockFace.SOUTH, Axis.X); + normalAxes.put(BlockFace.UP, Axis.Y); + normalAxes.put(BlockFace.DOWN, Axis.Y); + } + +} diff --git a/src/main/java/net/knarcraft/stargate/container/RelativeBlockVector.java b/src/main/java/net/knarcraft/stargate/container/RelativeBlockVector.java index 925764d..81bddef 100644 --- a/src/main/java/net/knarcraft/stargate/container/RelativeBlockVector.java +++ b/src/main/java/net/knarcraft/stargate/container/RelativeBlockVector.java @@ -1,5 +1,7 @@ package net.knarcraft.stargate.container; +import org.bukkit.util.Vector; + /** * This stores a block location as a vector relative to a position * @@ -70,6 +72,15 @@ public class RelativeBlockVector { } } + /** + * Gets a relative vector in the real space representing this relative block vector + * + * @return

A vector representing this relative block vector

+ */ + public Vector toVector() { + return new Vector(this.right, -this.down, this.out); + } + /** * Gets a relative block vector which is this inverted (pointing in the opposite direction) * diff --git a/src/main/java/net/knarcraft/stargate/portal/Portal.java b/src/main/java/net/knarcraft/stargate/portal/Portal.java index 93e664f..6d1f159 100644 --- a/src/main/java/net/knarcraft/stargate/portal/Portal.java +++ b/src/main/java/net/knarcraft/stargate/portal/Portal.java @@ -1,5 +1,6 @@ package net.knarcraft.stargate.portal; +import net.knarcraft.stargate.SimpleVectorOperation; import net.knarcraft.stargate.container.BlockLocation; import net.knarcraft.stargate.container.RelativeBlockVector; import net.knarcraft.stargate.portal.property.PortalLocation; @@ -8,6 +9,7 @@ import net.knarcraft.stargate.portal.property.PortalOptions; import net.knarcraft.stargate.portal.property.PortalOwner; import net.knarcraft.stargate.portal.property.PortalStructure; import net.knarcraft.stargate.portal.property.gate.Gate; +import net.knarcraft.stargate.utility.DirectionHelper; import net.md_5.bungee.api.ChatColor; import org.bukkit.World; import org.bukkit.entity.Player; @@ -23,6 +25,7 @@ public class Portal { private final String cleanName; private final String network; private final String cleanNetwork; + private final SimpleVectorOperation vectorOperation; private final PortalOwner portalOwner; private boolean isRegistered; @@ -59,6 +62,7 @@ public class Portal { this.portalActivator = portalOpener.getPortalActivator(); this.cleanName = cleanString(name); this.cleanNetwork = cleanString(network); + this.vectorOperation = new SimpleVectorOperation(DirectionHelper.getBlockFaceFromYaw(portalLocation.getYaw())); } /** @@ -294,7 +298,7 @@ public class Portal { * @return

The block at the given relative position

*/ public BlockLocation getBlockAt(RelativeBlockVector vector) { - return getTopLeft().getRelativeLocation(vector, getYaw()); + return (BlockLocation) getTopLeft().clone().add(vectorOperation.performOperation(vector.toVector())); } /**