PhysicalConnectivity/src/main/kotlin/net/shadowfacts/phycon/block/cable/CableBlock.kt

213 lines
7.6 KiB
Kotlin
Raw Normal View History

2021-02-28 18:48:39 +00:00
package net.shadowfacts.phycon.block.cable
2019-10-28 15:53:47 +00:00
2021-03-07 15:38:09 +00:00
import net.fabricmc.fabric.api.`object`.builder.v1.block.FabricBlockSettings
2019-10-28 15:53:47 +00:00
import net.minecraft.block.*
import net.minecraft.entity.player.PlayerEntity
2019-10-28 15:53:47 +00:00
import net.minecraft.item.ItemPlacementContext
2021-02-10 23:55:49 +00:00
import net.minecraft.state.StateManager
import net.minecraft.state.property.EnumProperty
2021-02-10 23:55:49 +00:00
import net.minecraft.util.ActionResult
2021-03-14 19:48:09 +00:00
import net.minecraft.util.DyeColor
import net.minecraft.util.Hand
2019-10-28 15:53:47 +00:00
import net.minecraft.util.Identifier
import net.minecraft.util.hit.BlockHitResult
2019-10-28 15:53:47 +00:00
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.util.math.Vec3d
2019-10-28 15:53:47 +00:00
import net.minecraft.util.shape.VoxelShape
import net.minecraft.util.shape.VoxelShapes
import net.minecraft.world.BlockView
import net.minecraft.world.World
2021-02-10 23:55:49 +00:00
import net.minecraft.world.WorldAccess
2019-10-28 15:53:47 +00:00
import net.shadowfacts.phycon.PhysicalConnectivity
2021-02-13 23:24:36 +00:00
import net.shadowfacts.phycon.api.Interface
import net.shadowfacts.phycon.api.NetworkCableBlock
import net.shadowfacts.phycon.api.NetworkComponentBlock
2023-03-13 02:18:34 +00:00
import net.shadowfacts.phycon.block.DeviceBlockEntity
import net.shadowfacts.phycon.init.PhyItems
2021-03-07 15:38:22 +00:00
import net.shadowfacts.phycon.item.FaceDeviceBlockItem
import net.shadowfacts.phycon.util.CableConnection
2023-03-13 02:18:34 +00:00
import net.shadowfacts.phycon.util.NetworkUtil
2021-03-07 15:38:22 +00:00
import net.shadowfacts.phycon.util.containsInclusive
2019-10-28 15:53:47 +00:00
import java.util.*
/**
* @author shadowfacts
*/
2021-03-14 19:48:09 +00:00
class CableBlock(
val color: DyeColor,
): Block(
2021-03-07 15:38:09 +00:00
FabricBlockSettings.of(CABLE_MATERIAL)
.strength(0.3f)
2021-02-10 23:55:49 +00:00
.nonOpaque()
2021-02-13 23:24:36 +00:00
), NetworkCableBlock {
2019-10-28 15:53:47 +00:00
companion object {
val ID = Identifier(PhysicalConnectivity.MODID, "cable")
2021-12-22 23:59:51 +00:00
val CABLE_MATERIAL = Material.Builder(MapColor.BLUE).build()
2019-10-28 15:53:47 +00:00
val CENTER_SHAPE = createCuboidShape(6.0, 6.0, 6.0, 10.0, 10.0, 10.0)
val SIDE_SHAPES = mapOf<Direction, VoxelShape>(
Direction.DOWN to createCuboidShape(6.0, 0.0, 6.0, 10.0, 6.0, 10.0),
Direction.UP to createCuboidShape(6.0, 10.0, 6.0, 10.0, 16.0, 10.0),
Direction.NORTH to createCuboidShape(6.0, 6.0, 0.0, 10.0, 10.0, 6.0),
Direction.SOUTH to createCuboidShape(6.0, 6.0, 10.0, 10.0, 10.0, 16.0),
Direction.WEST to createCuboidShape(0.0, 6.0, 6.0, 6.0, 10.0, 10.0),
Direction.EAST to createCuboidShape(10.0, 6.0, 6.0, 16.0, 10.0, 10.0)
)
private val SHAPE_CACHE = Array<VoxelShape>(64) { key ->
val connectedSides = Direction.values().filterIndexed { index, _ ->
((key shr index) and 1) == 1
}
connectedSides.fold(CENTER_SHAPE) { acc, side ->
VoxelShapes.union(acc, SIDE_SHAPES[side])
}
}
val CONNECTIONS: Map<Direction, EnumProperty<CableConnection>> = Direction.values().associate { it to EnumProperty.of(it.name.toLowerCase(), CableConnection::class.java) }
2019-10-28 15:53:47 +00:00
fun getShape(state: BlockState): VoxelShape {
val key = Direction.values().foldIndexed(0) { i, acc, dir ->
if (state[CONNECTIONS[dir]] == CableConnection.ON) {
acc or (1 shl i)
} else {
acc
2019-10-28 15:53:47 +00:00
}
}
return SHAPE_CACHE[key]
2019-10-28 15:53:47 +00:00
}
}
init {
2021-02-10 23:55:49 +00:00
defaultState = CONNECTIONS.values.fold(stateManager.defaultState) { acc, prop ->
acc.with(prop, CableConnection.OFF)
2019-10-28 15:53:47 +00:00
}
}
override fun getNetworkConnectedSides(state: BlockState, world: WorldAccess, pos: BlockPos): Collection<Direction> {
val set = EnumSet.noneOf(Direction::class.java)
for ((side, prop) in CONNECTIONS) {
if (state[prop] == CableConnection.ON) {
set.add(side)
}
}
return set
}
2021-02-10 23:55:49 +00:00
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
2019-10-28 15:53:47 +00:00
super.appendProperties(builder)
CONNECTIONS.values.forEach {
builder.add(it)
}
}
2021-03-07 15:38:22 +00:00
fun getInitialState(world: World, pos: BlockPos): BlockState {
2019-10-28 15:53:47 +00:00
return CONNECTIONS.entries.fold(defaultState, { acc, (dir, prop) ->
2021-03-07 15:38:22 +00:00
acc.with(prop, getConnectionStateInDirection(world, pos, dir))
2019-10-28 15:53:47 +00:00
})
}
2021-03-07 15:38:22 +00:00
override fun getPlacementState(context: ItemPlacementContext): BlockState {
return getInitialState(context.world, context.blockPos)
}
2021-02-10 23:55:49 +00:00
override fun getStateForNeighborUpdate(state: BlockState, side: Direction, neighborState: BlockState, world: WorldAccess, blockPos_1: BlockPos, blockPos_2: BlockPos): BlockState {
val prop = CONNECTIONS[side]
val current = state[prop]
return when (current) {
CableConnection.DISABLED -> state
else -> state.with(prop, getConnectionStateInDirection(world, blockPos_1, side))
}
2019-10-28 15:53:47 +00:00
}
2021-02-10 23:55:49 +00:00
private fun getConnectionStateInDirection(world: WorldAccess, pos: BlockPos, direction: Direction): CableConnection {
val offsetPos = pos.offset(direction)
val state = world.getBlockState(offsetPos)
val block = state.block
2021-03-14 19:48:09 +00:00
return if (block == this) {
val prop = CONNECTIONS[direction.opposite]
when (state[prop]) {
CableConnection.DISABLED -> CableConnection.DISABLED
else -> CableConnection.ON
}
2021-03-14 19:48:09 +00:00
} else if (block is NetworkComponentBlock && block !is CableBlock) {
if (block.getNetworkConnectedSides(state, world, offsetPos).contains(direction.opposite)) {
CableConnection.ON
} else {
CableConnection.OFF
}
2021-03-14 19:48:09 +00:00
} else {
CableConnection.OFF
}
2019-10-28 15:53:47 +00:00
}
override fun getNetworkInterfaceForSide(side: Direction, state: BlockState, world: WorldAccess, pos: BlockPos): Interface? {
2021-02-13 23:24:36 +00:00
// cables don't have network interfaces
return null
}
2021-02-10 23:55:49 +00:00
override fun onUse(
state: BlockState,
world: World,
pos: BlockPos,
player: PlayerEntity,
hand: Hand,
hitResult: BlockHitResult
): ActionResult {
if (player.getStackInHand(hand).item == PhyItems.SCREWDRIVER) {
val hitPos = Vec3d(hitResult.pos.x - pos.x, hitResult.pos.y - pos.y, hitResult.pos.z - pos.z)
val hitConnection = SIDE_SHAPES.entries.firstOrNull { (_, shape) ->
2021-03-07 15:38:22 +00:00
shape.boundingBox.containsInclusive(hitPos)
}
if (hitConnection != null) {
val side = hitConnection.key
val prop = CONNECTIONS[side]
val newState = when (state[prop]) {
CableConnection.DISABLED -> {
// if the block this cable is connecting to on the side that will be re-enabled is a cable that
// is disabled on the side that connects it to us, we also re-enable that cable to make sure both
// "halves" of the connection are in the same state
val connectedToPos = pos.offset(side)
val connectedTo = world.getBlockState(connectedToPos)
if (connectedTo.block == this && connectedTo[CONNECTIONS[side.opposite]] == CableConnection.DISABLED) {
world.setBlockState(connectedToPos, connectedTo.with(CONNECTIONS[side.opposite], CableConnection.ON))
}
2021-02-13 23:24:36 +00:00
state.with(prop, if (connectedTo.block is NetworkComponentBlock) CableConnection.ON else CableConnection.OFF)
}
else -> state.with(prop, CableConnection.DISABLED)
}
world.setBlockState(pos, newState)
}
2021-02-10 23:55:49 +00:00
return ActionResult.SUCCESS
}
2021-02-10 23:55:49 +00:00
return ActionResult.PASS
2019-10-28 15:53:47 +00:00
}
2021-03-07 15:38:22 +00:00
override fun canReplace(state: BlockState, context: ItemPlacementContext): Boolean {
return context.stack.item is FaceDeviceBlockItem
}
2019-10-28 15:53:47 +00:00
override fun isTranslucent(blockState_1: BlockState?, blockView_1: BlockView?, blockPos_1: BlockPos?): Boolean {
return true
}
2021-02-10 23:55:49 +00:00
// override fun isSimpleFullBlock(blockState_1: BlockState?, blockView_1: BlockView?, blockPos_1: BlockPos?): Boolean {
// return false
// }
2019-10-28 15:53:47 +00:00
2021-02-10 23:55:49 +00:00
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
2019-10-28 15:53:47 +00:00
return getShape(state)
}
2023-03-13 02:18:34 +00:00
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) {
super.onBreak(world, pos, state, player)
if (!world.isClient) {
// notify devices on either end that the connection was broken (i.e., unset the cached receivers)
val connectedSides = getNetworkConnectedSides(state, world, pos)
for (side in connectedSides) {
val dest = NetworkUtil.findConnectedInterface(world, pos, side)
dest?.cableDisconnected()
}
}
}
2019-10-28 15:53:47 +00:00
}