PhysicalConnectivity/src/main/kotlin/net/shadowfacts/phycon/block/FaceDeviceBlock.kt

173 lines
6.3 KiB
Kotlin
Raw Normal View History

2021-02-28 18:48:39 +00:00
package net.shadowfacts.phycon.block
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.block.ShapeContext
import net.minecraft.item.ItemPlacementContext
import net.minecraft.item.ItemStack
import net.minecraft.server.world.ServerWorld
import net.minecraft.state.StateManager
import net.minecraft.state.property.EnumProperty
import net.minecraft.state.property.Properties
2021-03-15 22:30:35 +00:00
import net.minecraft.util.DyeColor
2021-03-06 20:01:22 +00:00
import net.minecraft.util.StringIdentifiable
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.WorldAccess
import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.api.NetworkComponentBlock
2021-02-28 18:48:39 +00:00
import net.shadowfacts.phycon.block.cable.CableBlock
import net.shadowfacts.phycon.init.PhyItems
import java.util.*
/**
* @author shadowfacts
*/
abstract class FaceDeviceBlock<T: DeviceBlockEntity>(settings: Settings): DeviceBlock<T>(settings) {
companion object {
val FACING = Properties.FACING
2021-03-06 20:01:22 +00:00
val CABLE_CONNECTION = EnumProperty.of("cable_connection", FaceCableConnection::class.java)
2021-03-15 22:30:35 +00:00
val COLOR = EnumProperty.of("color", DyeColor::class.java)
2021-03-06 20:01:22 +00:00
}
enum class FaceCableConnection : StringIdentifiable {
NONE, DOWN, UP, NORTH, SOUTH, WEST, EAST;
companion object {
fun from(dir: Direction?) = when (dir) {
null -> NONE
Direction.DOWN -> DOWN
Direction.UP -> UP
Direction.NORTH -> NORTH
Direction.SOUTH -> SOUTH
Direction.WEST -> WEST
Direction.EAST -> EAST
}
}
val direction: Direction?
get() = when (this) {
NONE -> null
DOWN -> Direction.DOWN
UP -> Direction.UP
NORTH -> Direction.NORTH
SOUTH -> Direction.SOUTH
WEST -> Direction.WEST
EAST -> Direction.EAST
}
override fun asString() = name.toLowerCase()
}
protected abstract val faceThickness: Double
2021-03-07 15:38:22 +00:00
abstract val faceShapes: Map<Direction, VoxelShape>
private val centerShapes: Map<Direction, VoxelShape> 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)
)
}
2021-03-06 20:01:22 +00:00
private val shapeCache = mutableMapOf<Pair<Direction, FaceCableConnection>, VoxelShape>()
2021-03-06 20:01:22 +00:00
private fun getShape(facing: Direction, cableConnection: FaceCableConnection): VoxelShape {
return shapeCache.getOrPut(facing to cableConnection) {
2021-03-06 20:01:22 +00:00
if (cableConnection == FaceCableConnection.NONE) {
VoxelShapes.union(faceShapes[facing], centerShapes[facing])
} else {
VoxelShapes.union(faceShapes[facing], centerShapes[facing], CableBlock.SIDE_SHAPES[cableConnection.direction])
}
}
}
override fun getNetworkConnectedSides(state: BlockState, world: WorldAccess, pos: BlockPos): Collection<Direction> {
2021-03-06 20:01:22 +00:00
val direction = state[CABLE_CONNECTION].direction
return if (direction != null) EnumSet.of(direction) else setOf()
}
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<Block, BlockState>) {
super.appendProperties(builder)
builder.add(FACING)
builder.add(CABLE_CONNECTION)
2021-03-15 22:30:35 +00:00
builder.add(COLOR)
}
2021-02-24 03:05:05 +00:00
override fun getPlacementState(context: ItemPlacementContext): BlockState {
val facing = if (context.player?.isSneaking == true) context.side.opposite else context.playerLookDirection.opposite
2021-03-15 22:30:35 +00:00
// todo: this should never be called
val cableConnection = FaceCableConnection.from(getCableConnectedSide(context.world, context.blockPos, facing, DyeColor.BLUE))
return defaultState
.with(FACING, facing)
.with(CABLE_CONNECTION, cableConnection)
}
2021-03-15 22:30:35 +00:00
private fun getCableConnectedSide(world: WorldAccess, pos: BlockPos, facing: Direction, color: DyeColor): Direction? {
for (side in Direction.values()) {
2021-02-24 03:05:05 +00:00
if (side == facing) {
continue
}
val offsetPos = pos.offset(side)
2021-02-24 03:05:05 +00:00
val state = world.getBlockState(offsetPos)
2021-03-15 22:30:35 +00:00
if (canConnectTo(world, side, state, offsetPos, color)) {
return side
}
}
return null
}
2021-03-15 22:30:35 +00:00
private fun canConnectTo(world: WorldAccess, side: Direction, candidateState: BlockState, candidatePos: BlockPos, myColor: DyeColor): Boolean {
val block = candidateState.block
return if (block is FaceDeviceBlock<*> && candidateState[COLOR] == myColor) {
true
} else if (block is CableBlock && block.color == myColor) {
true
} else {
block is NetworkComponentBlock && block.getNetworkConnectedSides(candidateState, world, candidatePos).contains(side.opposite)
}
}
override fun getStateForNeighborUpdate(state: BlockState, side: Direction, neighborState: BlockState, world: WorldAccess, pos: BlockPos, neighborPos: BlockPos): BlockState {
2021-03-06 20:01:22 +00:00
val current = state[CABLE_CONNECTION]
var newConnection = current
if (current == FaceCableConnection.NONE) {
2021-03-15 22:30:35 +00:00
if (canConnectTo(world, side, neighborState, neighborPos, state[COLOR])) {
2021-03-06 20:01:22 +00:00
newConnection = FaceCableConnection.from(side)
}
} else {
val currentConnectedPos = pos.offset(current.direction)
if (neighborPos == currentConnectedPos && neighborState.block !is NetworkComponentBlock) {
// the old cable connection is no longer correct, try to find another
2021-03-15 22:30:35 +00:00
newConnection = FaceCableConnection.from(getCableConnectedSide(world, pos, state[FACING], state[COLOR]))
2021-03-06 20:01:22 +00:00
}
}
2021-03-06 20:01:22 +00:00
return state.with(CABLE_CONNECTION, newConnection)
}
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
return getShape(state[FACING], state[CABLE_CONNECTION])
}
override fun onStacksDropped(state: BlockState, world: ServerWorld, pos: BlockPos, stack: ItemStack) {
super.onStacksDropped(state, world, pos, stack)
val cableStack = ItemStack(PhyItems.CABLES[state[COLOR]])
dropStack(world, pos, cableStack)
}
2021-02-24 03:05:05 +00:00
}