package net.shadowfacts.phycon.network import net.minecraft.block.Block import net.minecraft.block.BlockState import net.minecraft.block.ShapeContext import net.minecraft.item.ItemPlacementContext import net.minecraft.state.StateManager import net.minecraft.state.property.EnumProperty import net.minecraft.state.property.Properties import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction import net.minecraft.util.shape.VoxelShape import net.minecraft.util.shape.VoxelShapes import net.minecraft.world.BlockView import net.minecraft.world.World import net.minecraft.world.WorldAccess import net.shadowfacts.phycon.api.Interface import net.shadowfacts.phycon.api.NetworkComponentBlock import net.shadowfacts.phycon.network.block.cable.CableBlock import java.util.* /** * @author shadowfacts */ abstract class FaceDeviceBlock(settings: Settings): DeviceBlock(settings) { companion object { val FACING = Properties.FACING val CABLE_CONNECTION = EnumProperty.of("cable_connection", Direction::class.java) } protected abstract val faceThickness: Double protected abstract val faceShapes: Map private val centerShapes: Map by lazy { mapOf( Direction.DOWN to createCuboidShape(6.0, faceThickness, 6.0, 10.0, 10.0, 10.0), Direction.UP to createCuboidShape(6.0, 6.0, 6.0, 10.0, 16.0 - faceThickness, 10.0), Direction.NORTH to createCuboidShape(6.0, 6.0, faceThickness, 10.0, 10.0, 10.0), Direction.SOUTH to createCuboidShape(6.0, 6.0, 6.0, 10.0, 10.0, 16.0 - faceThickness), Direction.WEST to createCuboidShape(faceThickness, 6.0, 6.0, 10.0, 10.0, 10.0), Direction.EAST to createCuboidShape(6.0, 6.0, 6.0, 16.0 - faceThickness, 10.0, 10.0) ) } private val shapeCache = mutableMapOf, VoxelShape>() fun getShape(facing: Direction, cableConnection: Direction): VoxelShape { return shapeCache.getOrPut(facing to cableConnection) { VoxelShapes.union( faceShapes[facing], centerShapes[facing], CableBlock.SIDE_SHAPES[cableConnection] ) } } override fun getNetworkConnectedSides(state: BlockState, world: WorldAccess, pos: BlockPos): Collection { return EnumSet.of(state[CABLE_CONNECTION]) } override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: WorldAccess, pos: BlockPos): Interface? { return if (side == state[FACING]) { null } else { getBlockEntity(world, pos) } } override fun appendProperties(builder: StateManager.Builder) { super.appendProperties(builder) builder.add(FACING) builder.add(CABLE_CONNECTION) } override fun getPlacementState(context: ItemPlacementContext): BlockState? { val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite val cableConnection = getCableConnectedSide(context.world, context.blockPos) ?: facing.opposite return defaultState .with(FACING, facing) .with(CABLE_CONNECTION, cableConnection) } protected fun getCableConnectedSide(world: World, pos: BlockPos): Direction? { for (side in Direction.values()) { val offsetPos = pos.offset(side) if (world.getBlockState(offsetPos) is NetworkComponentBlock) { return side } } return null } override fun getStateForNeighborUpdate(state: BlockState, side: Direction, neighborState: BlockState, world: WorldAccess, pos: BlockPos, neighborPos: BlockPos): BlockState { if (neighborState.block is NetworkComponentBlock && world.getBlockState(pos.offset(state[CABLE_CONNECTION])).block !is NetworkComponentBlock) { return state.with(CABLE_CONNECTION, side) } return state } override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape { return getShape(state[FACING], state[CABLE_CONNECTION]) } }