package com.thebrokenrail.energonrelics.structure; import com.thebrokenrail.energonrelics.util.MissingCaseException; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.util.BlockRotation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; 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 { protected interface Transformation { Vec3d transform(Vec3d vec); 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 Vec3d transform(Vec3d vec) { return vec; } @Override public BlockState transform(BlockState state) { return state; } }; protected static final Transformation CLOCKWISE_90 = new Transformation() { @Override public Vec3d transform(Vec3d vec) { return new Vec3d(-vec.getZ(), vec.getY(), vec.getX()); } @Override public BlockState transform(BlockState state) { return state.rotate(BlockRotation.CLOCKWISE_90); } }; protected static final Transformation CLOCKWISE_180 = new Transformation() { @Override public Vec3d transform(Vec3d vec) { return new Vec3d(-vec.getX(), vec.getY(), -vec.getZ()); } @Override public BlockState transform(BlockState state) { return state.rotate(BlockRotation.CLOCKWISE_180); } }; protected static final Transformation COUNTERCLOCKWISE_90 = new Transformation() { @Override public Vec3d transform(Vec3d vec) { return new Vec3d(vec.getZ(), vec.getY(), -vec.getX()); } @Override public BlockState transform(BlockState state) { return state.rotate(BlockRotation.COUNTERCLOCKWISE_90); } }; protected abstract int getHeight(); protected abstract int getWidth(); protected abstract int getDepth(); protected abstract void build(StructureContext context); private Vec3d getOffset() { return new Vec3d(getWidth() / 2f, getHeight() / 2f, getDepth() / 2f); } private Vec3d transform(Vec3d pos) { pos = pos.subtract(getOffset()); 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(int x, int y, int z, BlockState state) { Vec3d vec = transform(new Vec3d(x, y, z)); blocks.put(new BlockPos(vec.getX(), vec.getY(), vec.getZ()).asLong(), transform(state)); } protected void rect(int xPos, int yPos, int zPos, 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(x + xPos, y + yPos, z + zPos, state); } } } } protected void repeat(Transformation[] functions, Runnable action) { for (Transformation function : functions) { transformations.add(function); action.run(); transformations.remove(transformations.size() - 1); } } protected void repeat(Runnable action) { repeat(new Transformation[]{NONE, CLOCKWISE_90, CLOCKWISE_180, COUNTERCLOCKWISE_90}, action); } public void place(World world, BlockPos pos) { Vec3d offset = getOffset(); BlockPos offsetPos = new BlockPos(offset.getX(), offset.getY(), offset.getZ()); for (Map.Entry entry : blocks.entrySet()) { BlockState state = entry.getValue(); if (state.getBlock() != Blocks.VOID_AIR) { BlockPos newPos = pos.add(BlockPos.fromLong(entry.getKey()).add(offsetPos)); world.removeBlockEntity(newPos); world.setBlockState(newPos, state); handleBlockPlace(world, newPos, state); } } } protected abstract void handleBlockPlace(World world, BlockPos pos, BlockState state); public static Transformation getTransformationFromBlockRotation(BlockRotation rotation) { switch (rotation) { case NONE: { return NONE; } case CLOCKWISE_90: { return CLOCKWISE_90; } case CLOCKWISE_180: { return CLOCKWISE_180; } case COUNTERCLOCKWISE_90: { return COUNTERCLOCKWISE_90; } default: { throw new MissingCaseException(rotation); } } } protected void part(StructureContext context, int x, int y, int z, StructurePart part) { Vec3d vec = transform(new Vec3d(x, y, z)); context.addPart((int) vec.getX(), (int) vec.getY(), (int) vec.getZ(), part); } protected List getTransformations() { return transformations; } }