Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 5 additions & 11 deletions src/main/java/li/cil/oc2/api/util/RobotOperationSide.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,15 @@

import javax.annotation.Nullable;

import com.google.gson.annotations.SerializedName;

/**
* A more restrictive version of {@link Side}, intended for robot operation APIs.
*/
public enum RobotOperationSide {
FRONT(Direction.SOUTH),
front(FRONT),
f(FRONT),

UP(Direction.UP),
up(UP),
u(UP),

DOWN(Direction.DOWN),
down(DOWN),
d(DOWN),
@SerializedName(value="front", alternate={"FRONT", "f"}) FRONT(Direction.SOUTH),
@SerializedName(value="up", alternate={"TOP", "top", "UP", "u"}) UP(Direction.UP),
@SerializedName(value="down", alternate={"BOTTOM", "bottom", "DOWN", "d"}) DOWN(Direction.DOWN),
;

private final Direction direction;
Expand Down
197 changes: 152 additions & 45 deletions src/main/java/li/cil/oc2/api/util/Side.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,78 +3,185 @@
package li.cil.oc2.api.util;

import net.minecraft.core.Direction;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.core.BlockPos;

import javax.annotation.Nullable;
import com.google.gson.annotations.SerializedName;

/**
* This enum indicates a side of a block device.
* This enum indicates a side of a block device. It can be either a local side (eg. {@code FRONT}) or a global side
* (eg. {@code SOUTH}.
* <p>
* It is intended to be used by {@link li.cil.oc2.api.bus.device.rpc.RPCDevice} APIs,
* providing both convenience for the caller by providing a range of aliases, and also
* stability, in case Mojang decide to rename the enum fields of the {@link Direction}
* enum at some time in the future.
*/
public enum Side {
DOWN(Direction.DOWN),
down(DOWN),
d(DOWN),

UP(Direction.UP),
up(UP),
u(UP),

NORTH(Direction.NORTH),
north(NORTH),
n(NORTH),
BACK(NORTH),
back(NORTH),
b(NORTH),

SOUTH(Direction.SOUTH),
south(SOUTH),
s(SOUTH),
FRONT(SOUTH),
front(SOUTH),
f(SOUTH),

WEST(Direction.WEST),
west(WEST),
w(WEST),
LEFT(WEST),
left(WEST),
l(WEST),

EAST(Direction.EAST),
east(EAST),
e(EAST),
RIGHT(EAST),
right(EAST),
r(EAST),
// Vertical: Primarily global but also used for local
@SerializedName(value="down", alternate={"BOTTOM", "bottom", "DOWN", "d"}) DOWN(Direction.DOWN),
@SerializedName(value="up", alternate={"TOP", "top", "UP", "u"}) UP(Direction.UP),

// Horizontal, global only
@SerializedName(value="north", alternate={"NORTH", "n"}) NORTH(Direction.NORTH),
@SerializedName(value="south", alternate={"SOUTH", "s"}) SOUTH(Direction.SOUTH),
@SerializedName(value="west", alternate={"WEST", "w"}) WEST(Direction.WEST),
@SerializedName(value="east", alternate={"EAST", "e"}) EAST(Direction.EAST),

// Horizontal, local only
@SerializedName(value="back", alternate={"BACK", "b"}) BACK(Direction.NORTH, true),
@SerializedName(value="front", alternate={"FRONT", "f"}) FRONT(Direction.SOUTH, true),
@SerializedName(value="left", alternate={"LEFT", "l"}) LEFT(Direction.WEST, true),
@SerializedName(value="right", alternate={"RIGHT", "r"}) RIGHT(Direction.EAST, true),
;

@Nullable private final Side base;
// Static fields
public static final int VERTICAL_DIRECTION_COUNT = 2;
public static final int HORIZONTAL_DIRECTION_COUNT = 4;
public static final int GLOBAL_DIRECTION_COUNT = VERTICAL_DIRECTION_COUNT + HORIZONTAL_DIRECTION_COUNT;

// Note: Ideally these should be calculated not hardcoded
private static final Side[] BY_LOCAL_INDEX = {DOWN, UP, BACK, FRONT, LEFT, RIGHT};
private static final Side[] BY_GLOBAL_INDEX = {DOWN, UP, NORTH, SOUTH, WEST, EAST};
private static final Side[] BY_LOCAL_2D_INDEX = {FRONT, LEFT, BACK, RIGHT};

// Instance fields
private final Direction direction;
private final boolean local;

// Constructors
Side(final Direction direction) {
this.base = null;
this.direction = direction;
this(direction, false);
}

Side(final Side side) {
this.base = side;
this.direction = side.direction;
Side(final Direction direction, final boolean local) {
this.direction = direction;
this.local = local;
}

public Direction getDirection() {
// Getters
/**
* Get the base minecraft {@link Direction} this block {@code Side} is built from.
* <p>
* Note that this method does not understand rotation. If this is a relative {@code Side} (eg. {@code FRONT}), then
* the return value will only make sense for a block facing South.
*
* @return The base absolute direction this Side is built from.
*/
public Direction getBaseDirection() {
return direction;
}

/**
* Whether this specifies a local direction that changes with 2d orientation (eg {@code FRONT}, or a fixed global
* direction (eg {code #SOUTH}).
* <p>
* Note that {@code UP} and {@code DOWN} can usually be used as local directions but are technically global.
*/
public boolean isLocal() {
return local;
}

@Override
public String toString() {
return base != null ? base.toString() : super.toString();
return super.toString().toLowerCase();
}

// Global/local conversions
/**
* Given a global {@link Direction}, get the corresponding global block {@code Side}
*
* @see #toGlobal(BlockState)
* @param direction A global {@link Direction}
* @return A global Side corresponding to the same direction
*/
public static Side fromGlobal(Direction direction) {
return BY_GLOBAL_INDEX[direction.get3DDataValue()];
}

/**
* Given a local index value, get the corresponding local block {@code Side}. This is roughly equivalent to
* {@link Direction#from3DDataValue(int)} but for local instead of global sides.
* <p>
* The local index value can be used as an index into arrays for data that should be stored per local side of a
* block. The order of indices is down, up, back, front, left, right.
*
* @see #toLocalIndex(BlockState)
* @param index A number from 0-5 representing the local index of the side of a block
* @return the corresponding Side
*/
public static Side fromLocalIndex(int index) {
return BY_LOCAL_INDEX[index];
}

/**
* Given a block {@code Side} which might be global or local, return the equivalent local {@code Side}. As an
* example, if the {@code blockState} indicates a block facing west, then both {@code WEST} and {@code FRONT}
* would return {@code FRONT}.
*
* @param blockState The state of the local block, for converting global sides to local ones
* @return the indicated local side of the block
*/
public Side toLocal(BlockState blockState) {
if (direction.getAxis().isVertical() || local) {
// Already local
return this;
}
if (!blockState.hasProperty(HorizontalDirectionalBlock.FACING)) {
// No orientation data
return BY_LOCAL_INDEX[direction.get3DDataValue()];
}

final Direction facing = blockState.getValue(HorizontalDirectionalBlock.FACING);
final int index2d = direction.get2DDataValue();
final int toLocal2d = -facing.get2DDataValue();
final int rotatedIndex2d = (index2d + toLocal2d + HORIZONTAL_DIRECTION_COUNT) % HORIZONTAL_DIRECTION_COUNT;
return BY_LOCAL_2D_INDEX[rotatedIndex2d];
}

/**
* Given a block {@code Side} which might be global or local, return a local index value between 0 and 5. This is
* roughly equivalent to {@link Direction#get3DDataValue()} but for local instead of global sides. As an example,
* if the blockState indicates a block facing west, then both {@code WEST} and {@code FRONT} would return {@code 3},
* the index for front.
* <p>
* The local index value can be used as an index into arrays for data that should be stored per local side of a
* block. The order of indices is down, up, back, front, left, right.
*
* @see #fromLocalIndex(int)
* @param blockState The state of the local block, for converting global sides to local indices
* @return the indicated local index of the block
*/
public int toLocalIndex(BlockState blockState) {
return toLocal(blockState).direction.get3DDataValue();
}

/**
* Given a Side which might be global or local, return a global {@link Direction} representing it. As an example, if
* the {@code blockState} indicates a block facing west, then both {@code WEST} and {@code FRONT} would return
* {@link Direction#WEST}.
*
* @see #fromGlobal(Direction)
* @param blockState The state of the local block, for converting local sides to global directions
* @return the global direction corresponding to this block side
*/
public Direction toGlobal(BlockState blockState) {
if (direction.getAxis().isVertical() || !local) {
return direction;
}
if (!blockState.hasProperty(HorizontalDirectionalBlock.FACING)) {
return direction;
}

final Direction facing = blockState.getValue(HorizontalDirectionalBlock.FACING);
final int index = direction.get2DDataValue();
final int toGlobal = facing.get2DDataValue();
final int rotatedIndex = (index + toGlobal) % HORIZONTAL_DIRECTION_COUNT;
return Direction.from2DDataValue(rotatedIndex);
}

// Direction calculation
public static Direction relativeDirection(BlockPos from, BlockPos to) {
int dx = to.getX() - from.getX();
int dy = to.getY() - from.getY();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,9 @@ public <T> LazyOptional<T> getCapability(final Capability<T> capability, @Nullab
return optional;
}

final Direction localSide = HorizontalBlockUtils.toLocal(getBlockState(), side);
for (final Device device : virtualMachine.busController.getDevices()) {
if (device instanceof final ICapabilityProvider capabilityProvider) {
final LazyOptional<T> value = capabilityProvider.getCapability(capability, localSide);
final LazyOptional<T> value = capabilityProvider.getCapability(capability, side);
if (value.isPresent()) {
return value;
}
Expand Down
Loading