package com.thebrokenrail.energonrelics.structure; import com.thebrokenrail.energonrelics.util.MissingCaseException; import net.minecraft.block.BlockState; import net.minecraft.state.property.Properties; import net.minecraft.util.BlockMirror; import net.minecraft.util.BlockRotation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.world.World; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public abstract class StructurePart { public interface Transformation { BlockPos transform(BlockPos pos); BlockState transform(BlockState state); } private final T state; protected T getState() { return state; } public StructurePart(T state, List list) { this.state = state; transformations.addAll(list); } private final Map blocks = new HashMap<>(); private final List transformations = new ArrayList<>(); protected static final Transformation NONE = new Transformation() { @Override public BlockPos transform(BlockPos pos) { return pos; } @Override public BlockState transform(BlockState state) { return state; } }; protected static final Transformation CLOCKWISE_90 = new Transformation() { @Override public BlockPos transform(BlockPos pos) { return new BlockPos(-pos.getZ(), pos.getY(), pos.getX()); } @Override public BlockState transform(BlockState state) { return state.rotate(BlockRotation.CLOCKWISE_90); } }; protected static final Transformation CLOCKWISE_180 = new Transformation() { @Override public BlockPos transform(BlockPos pos) { return new BlockPos(-pos.getX(), pos.getY(), -pos.getZ()); } @Override public BlockState transform(BlockState state) { return state.rotate(BlockRotation.CLOCKWISE_180); } }; protected static final Transformation COUNTERCLOCKWISE_90 = new Transformation() { @Override public BlockPos transform(BlockPos pos) { return new BlockPos(pos.getZ(), pos.getY(), -pos.getX()); } @Override public BlockState transform(BlockState state) { return state.rotate(BlockRotation.COUNTERCLOCKWISE_90); } }; protected static final Transformation MIRROR_DEPTH = new Transformation() { @Override public BlockPos transform(BlockPos pos) { return new BlockPos(pos.getX(), pos.getY(), -pos.getZ()); } @Override public BlockState transform(BlockState state) { state = state.mirror(BlockMirror.LEFT_RIGHT); if (state.contains(Properties.CHEST_TYPE)) { state = state.with(Properties.CHEST_TYPE, state.get(Properties.CHEST_TYPE).getOpposite()); } return state; } }; protected abstract void build(StructureContext context); private BlockPos transform(BlockPos pos) { for (Transformation transformation : transformations) { pos = transformation.transform(pos); } return pos; } private BlockState transform(BlockState state) { for (Transformation transformation : transformations) { state = transformation.transform(state); } return state; } protected void set(BlockPos originalPos, BlockState state) { BlockPos pos = transform(originalPos); blocks.put(pos.asLong(), transform(state)); } protected void rect(BlockPos pos, int width, int height, int depth, BlockState state) { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { for (int z = 0; z < depth; z++) { set(pos.add(x, y, z), state); } } } } protected void rotate(Transformation[] functions, Runnable action) { for (Transformation function : functions) { transformations.add(function); action.run(); transformations.remove(transformations.size() - 1); } } protected void rotate(Runnable action) { rotate(new Transformation[]{NONE, CLOCKWISE_90, CLOCKWISE_180, COUNTERCLOCKWISE_90}, action); } public void place(World world, BlockPos pos) { for (Map.Entry entry : blocks.entrySet()) { BlockState state = entry.getValue(); BlockPos newPos = pos.add(BlockPos.fromLong(entry.getKey())); world.removeBlockEntity(newPos); world.setBlockState(newPos, state); handleBlockPlace(world, newPos, state); } } protected abstract void handleBlockPlace(World world, BlockPos pos, BlockState state); public static Transformation directionToTransformation(Direction direction) { switch (direction) { case NORTH: { return NONE; } case EAST: { return CLOCKWISE_90; } case SOUTH: { return CLOCKWISE_180; } case WEST: { return COUNTERCLOCKWISE_90; } default: { throw new MissingCaseException(direction); } } } public static Direction blockRotationToDirection(BlockRotation rotation) { switch (rotation) { case NONE: { return Direction.NORTH; } case CLOCKWISE_90: { return Direction.EAST; } case CLOCKWISE_180: { return Direction.SOUTH; } case COUNTERCLOCKWISE_90: { return Direction.WEST; } default: { throw new MissingCaseException(rotation); } } } protected void part(StructureContext context, BlockPos originalPos, StructurePart part) { BlockPos pos = transform(originalPos); context.addPart(pos.getX(), pos.getY(), pos.getZ(), part); } protected List getTransformations() { return transformations; } private BlockPos pos = null; private BlockPos getPos() { return pos; } protected BlockPos getPosFromOrigin(BlockPos pos) { return transform(pos).add(getPos()); } void setPos(BlockPos pos) { this.pos = pos; } }