package net.shadowfacts.phycon.network.block.netinterface import alexiil.mc.lib.attributes.AttributeList import alexiil.mc.lib.attributes.AttributeProvider import net.minecraft.block.* import net.minecraft.entity.LivingEntity import net.minecraft.item.ItemPlacementContext import net.minecraft.item.ItemStack import net.minecraft.state.StateManager import net.minecraft.state.property.EnumProperty import net.minecraft.state.property.Properties import net.minecraft.util.Identifier 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.PhysicalConnectivity import net.shadowfacts.phycon.api.NetworkComponentBlock import net.shadowfacts.phycon.api.Interface import net.shadowfacts.phycon.network.DeviceBlock import net.shadowfacts.phycon.network.block.cable.CableBlock import java.util.* /** * @author shadowfacts */ class InterfaceBlock: DeviceBlock(Settings.of(Material.METAL)), NetworkComponentBlock, AttributeProvider { companion object { val ID = Identifier(PhysicalConnectivity.MODID, "network_interface") val FACING = Properties.FACING val CABLE_CONNECTION = EnumProperty.of("cable_connection", Direction::class.java) private val SIDE_SHAPES = mapOf( Direction.DOWN to createCuboidShape(2.0, 0.0, 2.0, 14.0, 2.0, 14.0), Direction.UP to createCuboidShape(2.0, 14.0, 2.0, 14.0, 16.0, 14.0), Direction.NORTH to createCuboidShape(2.0, 2.0, 0.0, 14.0, 14.0, 2.0), Direction.SOUTH to createCuboidShape(2.0, 2.0, 14.0, 14.0, 14.0, 16.0), Direction.WEST to createCuboidShape(0.0, 2.0, 2.0, 2.0, 14.0, 14.0), Direction.EAST to createCuboidShape(14.0, 2.0, 2.0, 16.0, 14.0, 14.0) ) private val CENTER_SHAPES = mapOf( Direction.DOWN to createCuboidShape(6.0, 2.0, 6.0, 10.0, 10.0, 10.0), Direction.UP to createCuboidShape(6.0, 6.0, 6.0, 10.0, 14.0, 10.0), Direction.NORTH to createCuboidShape(6.0, 6.0, 2.0, 10.0, 10.0, 10.0), Direction.SOUTH to createCuboidShape(6.0, 6.0, 6.0, 10.0, 10.0, 14.0), Direction.WEST to createCuboidShape(2.0, 6.0, 6.0, 10.0, 10.0, 10.0), Direction.EAST to createCuboidShape(6.0, 6.0, 6.0, 14.0, 10.0, 10.0) ) private val shapeCache = mutableMapOf, VoxelShape>() fun getShape(facing: Direction, cableConnection: Direction): VoxelShape { return shapeCache.getOrPut(facing to cableConnection) { VoxelShapes.union( VoxelShapes.union(SIDE_SHAPES[facing], CENTER_SHAPES[facing]), CableBlock.SIDE_SHAPES[cableConnection] ) } } } override fun getNetworkConnectedSides(state: BlockState, world: WorldAccess, pos: BlockPos): Collection { val set = EnumSet.of(state[CABLE_CONNECTION]) set.remove(state[FACING]) return set } 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 createBlockEntity(world: BlockView) = InterfaceBlockEntity() override fun getPlacementState(context: ItemPlacementContext): BlockState { val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerFacing.opposite val cableConnection = getCableConnectionSide(context.world, context.blockPos) ?: facing.opposite return defaultState.with(FACING, facing).with(CABLE_CONNECTION, cableConnection) } private fun getCableConnectionSide(world: World, pos: BlockPos): Direction? { for (side in Direction.values()) { val offsetPos = pos.offset(side) if (world.getBlockState(offsetPos).block is NetworkComponentBlock) { return side } } return null } override fun onPlaced(world: World, pos: BlockPos, state: BlockState, placer: LivingEntity?, stack: ItemStack) { if (!world.isClient) { getBlockEntity(world, pos)!!.updateInventory() } } override fun neighborUpdate(state: BlockState, world: World, pos: BlockPos, neighborBlock: Block, neighborPos: BlockPos, boolean_1: Boolean) { if (!world.isClient) { getBlockEntity(world, pos)!!.updateInventory() } } 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 addAllAttributes(world: World, pos: BlockPos, state: BlockState, to: AttributeList<*>) { to.offer(getBlockEntity(world, pos)) } override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape { return getShape(state[FACING], state[CABLE_CONNECTION]) } }