PhysicalConnectivity/src/main/kotlin/net/shadowfacts/phycon/network/block/miner/MinerBlockEntity.kt

147 lines
4.9 KiB
Kotlin
Raw Normal View History

2021-02-15 04:42:19 +00:00
package net.shadowfacts.phycon.network.block.miner
import alexiil.mc.lib.attributes.item.GroupedItemInvView
import alexiil.mc.lib.attributes.item.ItemStackUtil
import alexiil.mc.lib.attributes.item.filter.ItemFilter
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.item.ItemStack
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.world.World
import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.api.util.IPAddress
import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.network.DeviceBlockEntity
2021-02-18 03:39:37 +00:00
import net.shadowfacts.phycon.network.block.terminal.TerminalBlockEntity
import net.shadowfacts.phycon.network.component.NetworkStackDispatcher
2021-02-15 04:42:19 +00:00
import net.shadowfacts.phycon.network.component.NetworkStackProvider
2021-02-18 03:39:37 +00:00
import net.shadowfacts.phycon.network.component.handleItemStack
import net.shadowfacts.phycon.network.component.spawnItemStack
2021-02-15 04:42:19 +00:00
import net.shadowfacts.phycon.network.packet.*
import kotlin.math.min
/**
* @author shadowfacts
*/
class MinerBlockEntity: DeviceBlockEntity(PhyBlockEntities.MINER),
2021-02-18 03:39:37 +00:00
NetworkStackProvider,
NetworkStackDispatcher<MinerBlockEntity.PendingInsertion> {
2021-02-15 04:42:19 +00:00
private val facing: Direction
get() = cachedState[MinerBlock.FACING]
private val invProxy = MinerInvProxy(this)
2021-02-18 03:39:37 +00:00
override val pendingInsertions = mutableListOf<PendingInsertion>()
override val dispatchStackTimeout = TerminalBlockEntity.INSERTION_TIMEOUT
2021-02-15 04:42:19 +00:00
override fun handle(packet: Packet) {
when (packet) {
is RequestInventoryPacket -> handleRequestInventory(packet)
is LocateStackPacket -> handleLocateStack(packet)
is ExtractStackPacket -> handleExtractStack(packet)
2021-02-18 03:39:37 +00:00
is CapacityPacket -> handleCapacity(packet)
is ItemStackPacket -> handleItemStack(packet)
2021-02-15 04:42:19 +00:00
}
}
private fun handleRequestInventory(packet: RequestInventoryPacket) {
sendPacket(ReadInventoryPacket(invProxy, ipAddress, packet.source))
}
private fun handleLocateStack(packet: LocateStackPacket) {
val amount = invProxy.getAmount(packet.stack)
if (amount > 0) {
sendPacket(StackLocationPacket(packet.stack, amount, this, ipAddress, packet.source))
}
}
private fun handleExtractStack(packet: ExtractStackPacket) {
// always recalculate immediately before breaking
2021-02-18 03:39:37 +00:00
val drops = invProxy.getDrops(recalculate = true)
2021-02-15 04:42:19 +00:00
if (invProxy.getAmount(packet.stack) > 0) {
world!!.breakBlock(pos.offset(facing), false)
// send the requested amount back to the requester
var remaining = packet.amount
for (droppedStack in drops) {
if (remaining <= 0) {
break
}
if (!ItemStackUtil.areEqualIgnoreAmounts(droppedStack, packet.stack)) {
continue
}
val copy = droppedStack.copy()
val toDecr = min(droppedStack.count, remaining)
droppedStack.decrement(toDecr)
remaining -= toDecr
// todo: should this try to combine stacks and send as few packets as possible?
copy.count = toDecr
sendPacket(ItemStackPacket(copy, ipAddress, packet.source))
}
// dump any remaining drops into the network
for (droppedStack in drops) {
if (droppedStack.isEmpty) continue
2021-02-18 03:39:37 +00:00
dispatchItemStack(droppedStack)
2021-02-15 04:42:19 +00:00
}
}
}
2021-02-18 03:39:37 +00:00
override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
// miner can't receive stacks, so remaining is the entire packet stack
return packet.stack
}
override fun createPendingInsertion(stack: ItemStack) = PendingInsertion(stack, counter)
2021-02-15 04:42:19 +00:00
class MinerInvProxy(val miner: MinerBlockEntity): GroupedItemInvView {
private var cachedState: BlockState? = null
private var cachedDrops: List<ItemStack>? = null
private val world: World
get() = miner.world!!
private val pos: BlockPos
get() = miner.pos!!
private val facing: Direction
get() = miner.facing
fun getDrops(recalculate: Boolean = false): List<ItemStack> {
val targetPos = pos.offset(facing)
val realState = world.getBlockState(targetPos)
2021-02-18 03:39:37 +00:00
// todo: does BlockState.equals actually work or is reference equality fine for BlockStates?
2021-02-15 04:42:19 +00:00
if (cachedDrops == null || realState != cachedState || recalculate) {
cachedState = realState
val be = if (realState.block.hasBlockEntity()) world.getBlockEntity(targetPos) else null
cachedDrops = Block.getDroppedStacks(realState, world as ServerWorld, targetPos, be)
}
return cachedDrops!!
}
override fun getStoredStacks(): Set<ItemStack> {
return getDrops().toSet()
}
override fun getTotalCapacity(): Int {
return Int.MAX_VALUE
}
override fun getStatistics(filter: ItemFilter): GroupedItemInvView.ItemInvStatistic {
var totalCount = 0
for (s in getDrops()) {
if (filter.matches(s)) {
totalCount += s.count
}
}
return GroupedItemInvView.ItemInvStatistic(filter, totalCount, 0, Int.MAX_VALUE)
}
}
2021-02-18 03:39:37 +00:00
class PendingInsertion(stack: ItemStack, timestamp: Long): NetworkStackDispatcher.PendingInsertion<PendingInsertion>(stack, timestamp) {
}
2021-02-15 04:42:19 +00:00
}