Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
import net.minecraft.util.Vec3;
import net.minecraftforge.common.util.ForgeDirection;

import org.joml.Vector3i;

import com.gtnewhorizon.structurelib.alignment.enumerable.Direction;
import com.gtnewhorizon.structurelib.coords.CoordinateSystem;
import com.gtnewhorizon.structurelib.coords.Position;
import com.gtnewhorizon.structurelib.util.Vec3Impl;

public class IntegerAxisSwap {
Expand Down Expand Up @@ -91,4 +95,32 @@ public void inverseTranslate(double[] point, double[] out) {
out[1] = forFirstAxis.get1() * point[0] + forSecondAxis.get1() * point[1] + forThirdAxis.get1() * point[2];
out[2] = forFirstAxis.get2() * point[0] + forSecondAxis.get2() * point[1] + forThirdAxis.get2() * point[2];
}

public Vector3i translate(Vector3i point) {
return new Vector3i(
forFirstAxis.get0() * point.x() + forFirstAxis.get1() * point.y() + forFirstAxis.get2() * point.z(),
forSecondAxis.get0() * point.x() + forSecondAxis.get1() * point.y() + forSecondAxis.get2() * point.z(),
forThirdAxis.get0() * point.x() + forThirdAxis.get1() * point.y() + forThirdAxis.get2() * point.z());
}

public Vector3i inverseTranslate(Vector3i point) {
return new Vector3i(
forFirstAxis.get0() * point.x() + forSecondAxis.get0() * point.y() + forThirdAxis.get0() * point.z(),
forFirstAxis.get1() * point.x() + forSecondAxis.get1() * point.y() + forThirdAxis.get1() * point.z(),
forFirstAxis.get2() * point.x() + forSecondAxis.get2() * point.y() + forThirdAxis.get2() * point.z());
}

public <C extends CoordinateSystem<C, ?>> Position<C> translate(Position<?> point) {
return new Position<>(
forFirstAxis.get0() * point.x() + forFirstAxis.get1() * point.y() + forFirstAxis.get2() * point.z(),
forSecondAxis.get0() * point.x() + forSecondAxis.get1() * point.y() + forSecondAxis.get2() * point.z(),
forThirdAxis.get0() * point.x() + forThirdAxis.get1() * point.y() + forThirdAxis.get2() * point.z());
}

public <C extends CoordinateSystem<C, ?>> Position<C> inverseTranslate(Position<?> point) {
return new Position<>(
forFirstAxis.get0() * point.x() + forSecondAxis.get0() * point.y() + forThirdAxis.get0() * point.z(),
forFirstAxis.get1() * point.x() + forSecondAxis.get1() * point.y() + forThirdAxis.get1() * point.z(),
forFirstAxis.get2() * point.x() + forSecondAxis.get2() * point.y() + forThirdAxis.get2() * point.z());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.google.common.collect.ImmutableSet;
import com.gtnewhorizon.structurelib.alignment.IAlignment;
import com.gtnewhorizon.structurelib.alignment.IntegerAxisSwap;
import com.gtnewhorizon.structurelib.coords.StructureRelativeCoords;
import com.gtnewhorizon.structurelib.util.Vec3Impl;

public enum ExtendedFacing {
Expand Down Expand Up @@ -166,6 +167,7 @@ public enum ExtendedFacing {

private final String name;
private final IntegerAxisSwap integerAxisSwap;
private final StructureRelativeCoords coordinateSystem;

ExtendedFacing(String name) {
this.name = name;
Expand Down Expand Up @@ -247,6 +249,7 @@ public enum ExtendedFacing {
this.b = b;
this.c = c;
integerAxisSwap = new IntegerAxisSwap(a, b, c);
coordinateSystem = new StructureRelativeCoords(integerAxisSwap);
}

public static ExtendedFacing of(ForgeDirection direction, Rotation rotation, Flip flip) {
Expand Down Expand Up @@ -437,4 +440,8 @@ public ForgeDirection getRelativeBackInWorld() {
public ForgeDirection getRelativeForwardInWorld() {
return c.getOpposite();
}

public StructureRelativeCoords asCoordinateSystem() {
return coordinateSystem;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.gtnewhorizon.structurelib.coords;

/**
* Controller-relative coordinates. The controller is at 0,0,0. No axis swapping takes place, each axis points in the
* same directions as the matching world axis.
*/
public class ControllerRelativeCoords implements CoordinateSystem<ControllerRelativeCoords, WorldCoords> {

public final int controllerX, controllerY, controllerZ;

public ControllerRelativeCoords(int controllerX, int controllerY, int controllerZ) {
this.controllerX = controllerX;
this.controllerY = controllerY;
this.controllerZ = controllerZ;
}

@Override
public Position<ControllerRelativeCoords> translate(Position<WorldCoords> position) {
return translate(position, controllerX, controllerY, controllerZ);
}

@Override
public Position<WorldCoords> translateInverse(Position<ControllerRelativeCoords> position) {
return translateInverse(position, controllerX, controllerY, controllerZ);
}

public static Position<ControllerRelativeCoords> translate(Position<WorldCoords> position, int controllerX,
int controllerY, int controllerZ) {
position.sub(controllerX, controllerY, controllerZ);

return CoordinateSystem.transmute(position);
}

public static Position<WorldCoords> translateInverse(Position<ControllerRelativeCoords> position, int controllerX,
int controllerY, int controllerZ) {
position.add(controllerX, controllerY, controllerZ);

return CoordinateSystem.transmute(position);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.gtnewhorizon.structurelib.coords;

import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;

/**
* A coordinate system is a statically-checked helper for determining which coordinates a {@link Position} has.
* Translation methods never copy a {@link Position} - if a position must remain unchanged, it must be copied
* separately. Most coordinate systems will have static methods that allow you to avoid allocations, though some (such
* as the ones provided by {@link ExtendedFacing#asCoordinateSystem()}) have no reason to be static.
*
* @param <Self>
* @param <Parent>
*/
public interface CoordinateSystem<Self extends CoordinateSystem<Self, Parent>, Parent extends CoordinateSystem<Parent, ?>> {

/**
* Translates a position from the parent coordinate system into this one.
*/
Position<Self> translate(Position<Parent> position);

/**
* Translates a position from this coordinate system into the parent.
*/
Position<Parent> translateInverse(Position<Self> position);

/**
* Helper method that converts a position's coordinate system. Should not be used unless you know it's correct.
*/
static <P1 extends CoordinateSystem<P1, ?>, P2 extends CoordinateSystem<P2, ?>> Position<P1> transmute(
Position<P2> pos) {
// noinspection unchecked
return (Position<P1>) pos;
}
}
73 changes: 73 additions & 0 deletions src/main/java/com/gtnewhorizon/structurelib/coords/Position.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.gtnewhorizon.structurelib.coords;

import net.minecraft.util.MathHelper;
import net.minecraft.util.Vec3;
import net.minecraft.world.ChunkPosition;

import org.joml.Vector3f;
import org.joml.Vector3i;

import com.gtnewhorizon.gtnhlib.blockpos.BlockPos;
import com.gtnewhorizon.structurelib.util.Vec3Impl;

/**
* A {@link BlockPos} with a statically-checked coordinate system.
*/
public class Position<C extends CoordinateSystem<C, ?>> extends BlockPos {

public Position() {

}

public Position(int x, int y, int z) {
super(x, y, z);
}

public Position(float x, float y, float z) {
super(MathHelper.floor_float(x), MathHelper.floor_float(y), MathHelper.floor_float(z));
}

public Position(double x, double y, double z) {
super(MathHelper.floor_double(x), MathHelper.floor_double(y), MathHelper.floor_double(z));
}

public Position(ChunkPosition chunkPosition) {
super(chunkPosition);
}

public Position(Vector3i v) {
super(v.x, v.y, v.z);
}

public Position(Vector3f v) {
this(v.x, v.y, v.z);
}

public Position(Vec3 v) {
this(v.xCoord, v.yCoord, v.zCoord);
}

public Position(Vec3Impl v) {
this(v.get0(), v.get1(), v.get2());
}

public Position<C> copy() {
return new Position<>(x, y, z);
}

public Vector3i toVector3i() {
return new Vector3i(x, y, z);
}

public Vector3f toVector3f() {
return new Vector3f(x, y, z);
}

public Vec3 toVec3() {
return Vec3.createVectorHelper(x, y, z);
}

public Vec3Impl toVec3Impl() {
return new Vec3Impl(x, y, z);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.gtnewhorizon.structurelib.coords;

/// The structure definition-local coords. 0,0,0 is the front-most left-most top-most element. Coordinates increase as
/// you go down, right, or back.
public class StructureDefinitionCoords implements CoordinateSystem<StructureDefinitionCoords, StructureRelativeCoords> {

public final int offsetX, offsetY, offsetZ;

public StructureDefinitionCoords(int offsetX, int offsetY, int offsetZ) {
this.offsetX = offsetX;
this.offsetY = offsetY;
this.offsetZ = offsetZ;
}

@Override
public Position<StructureDefinitionCoords> translate(Position<StructureRelativeCoords> position) {
return translate(position, offsetX, offsetY, offsetZ);
}

@Override
public Position<StructureRelativeCoords> translateInverse(Position<StructureDefinitionCoords> position) {
return translateInverse(position, offsetX, offsetY, offsetZ);
}

public static Position<StructureDefinitionCoords> translate(Position<StructureRelativeCoords> position, int offsetX,
int offsetY, int offsetZ) {
position.add(offsetX, offsetY, offsetZ);

return CoordinateSystem.transmute(position);
}

public static Position<StructureRelativeCoords> translateInverse(Position<StructureDefinitionCoords> position,
int offsetX, int offsetY, int offsetZ) {
position.sub(offsetX, offsetY, offsetZ);

return CoordinateSystem.transmute(position);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.gtnewhorizon.structurelib.coords;

import com.gtnewhorizon.structurelib.alignment.IntegerAxisSwap;

/**
* Coordinates relative to the structure. 0,0,0 is the controller. 0,0,1 is the block immediately behind the controller
* (looking at it from its face). 1,0,0 is the block to the right of the controller. 0,1,0 is the block below the
* controller.
*/
public class StructureRelativeCoords implements CoordinateSystem<StructureRelativeCoords, ControllerRelativeCoords> {

public final IntegerAxisSwap axisSwap;

public StructureRelativeCoords(IntegerAxisSwap axisSwap) {
this.axisSwap = axisSwap;
}

@Override
public Position<StructureRelativeCoords> translate(Position<ControllerRelativeCoords> position) {
position.set(axisSwap.translate(position));

return CoordinateSystem.transmute(position);
}

@Override
public Position<ControllerRelativeCoords> translateInverse(Position<StructureRelativeCoords> position) {
position.set(axisSwap.inverseTranslate(position));

return CoordinateSystem.transmute(position);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.gtnewhorizon.structurelib.coords;

/**
* World block coordinates
*/
public class WorldCoords implements CoordinateSystem<WorldCoords, WorldCoords> {

public static final WorldCoords INSTANCE = new WorldCoords();

private WorldCoords() {}

@Override
public Position<WorldCoords> translate(Position<WorldCoords> position) {
return position;
}

@Override
public Position<WorldCoords> translateInverse(Position<WorldCoords> position) {
return position;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import static com.gtnewhorizon.structurelib.structure.IStructureWalker.ignoreBlockUnloaded;
import static com.gtnewhorizon.structurelib.structure.IStructureWalker.skipBlockUnloaded;

import java.util.List;
import java.util.function.Function;

import javax.annotation.Nonnull;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
Expand All @@ -15,6 +18,8 @@
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable;
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
import com.gtnewhorizon.structurelib.coords.Position;
import com.gtnewhorizon.structurelib.coords.StructureDefinitionCoords;

/**
* This is the structure definition of your multi. You will have one of these for each multi.
Expand Down Expand Up @@ -335,6 +340,49 @@ default void iterate(String piece, World world, ExtendedFacing extendedFacing, i
"customIterate");
}

/**
* Gets the controller position for a piece. Controller positions are denoted by a tilde.
*
* @param piece The piece name
* @return The controller position, or null if it doesn't exist for the given piece
*/
Position<StructureDefinitionCoords> getControllerPosition(String piece);

/**
* Gets the coordinate system for a piece. This is used to translate structure definition coordinates into structure
* relative coordinates.
*
* @param piece The piece
* @return The coordinate system
* @throws IllegalArgumentException When the piece does not exist
*/
StructureDefinitionCoords getCoordinateSystem(String piece);

/**
* Gets a socket from a piece.
*
* @param piece The piece name
* @param socket The socket character
* @return The socket's position
* @throws IllegalArgumentException When the piece does not exist
* @throws IllegalArgumentException When the socket does not exist
* @throws IllegalStateException When more than one socket exists with this character
* @see StructureDefinition.Builder#addSocket(char, char)
*/
Position<StructureDefinitionCoords> getSocket(String piece, char socket);

/**
* Gets all sockets with a given character for a piece.
*
* @param piece The piece name
* @param socket The socket character
* @return The list of socket positions, or an empty list if the socket is not present
* @throws IllegalArgumentException When the piece does not exist
* @see StructureDefinition.Builder#addSocket(char, char)
*/
@Nonnull
List<Position<StructureDefinitionCoords>> getAllSockets(String piece, char socket);

/**
* Low level utility.
*
Expand Down
Loading
Loading