From 0ba103351812c03589f22716cdce1a66d6e99963 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 14 Jul 2024 14:58:33 -0700 Subject: [PATCH] Convert Miner to fabric transfer API --- .../phycon/block/miner/MinerBlockEntity.kt | 106 +++++++++++++----- 1 file changed, 75 insertions(+), 31 deletions(-) diff --git a/src/main/kotlin/net/shadowfacts/phycon/block/miner/MinerBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/block/miner/MinerBlockEntity.kt index e47a14b..052092e 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/block/miner/MinerBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/block/miner/MinerBlockEntity.kt @@ -1,7 +1,10 @@ package net.shadowfacts.phycon.block.miner -import alexiil.mc.lib.attributes.item.GroupedItemInvView -import alexiil.mc.lib.attributes.item.filter.ItemFilter +import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant +import net.fabricmc.fabric.api.transfer.v1.storage.StorageView +import net.fabricmc.fabric.api.transfer.v1.storage.base.ExtractionOnlyStorage +import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext +import net.fabricmc.fabric.api.transfer.v1.transaction.base.SnapshotParticipant import net.minecraft.block.Block import net.minecraft.block.BlockState import net.minecraft.item.ItemStack @@ -36,7 +39,7 @@ class MinerBlockEntity(pos: BlockPos, state: BlockState) : DeviceBlockEntity(Phy private val facing: Direction get() = cachedState[MinerBlock.FACING] - private val invProxy = MinerInvProxy(this) + private val invProxy = MinerStorageProxy(this) override val pendingInsertions = mutableListOf() override val dispatchStackTimeout = AbstractTerminalBlockEntity.INSERTION_TIMEOUT @@ -60,16 +63,16 @@ class MinerBlockEntity(pos: BlockPos, state: BlockState) : DeviceBlockEntity(Phy if (minerMode != MinerMode.ON_DEMAND || packet.kind != RequestInventoryPacket.Kind.GROUPED) { return } - sendPacket(ReadGroupedInventoryPacket(invProxy, ipAddress, packet.source)) + sendPacket(ReadItemStoragePacket(invProxy, ipAddress, packet.source)) } private fun handleLocateStack(packet: LocateStackPacket) { if (minerMode != MinerMode.ON_DEMAND) { return } - val amount = invProxy.getAmount(packet.stack) + val amount = invProxy.simulateExtract(ItemVariant.of(packet.stack), Long.MAX_VALUE, null) if (amount > 0) { - sendPacket(StackLocationPacket(packet.stack, amount, this, ipAddress, packet.source)) + sendPacket(StackLocationPacket(packet.stack, amount.toInt(), this, ipAddress, packet.source)) } } @@ -80,7 +83,8 @@ class MinerBlockEntity(pos: BlockPos, state: BlockState) : DeviceBlockEntity(Phy // always recalculate immediately before breaking val drops = invProxy.getDrops(recalculate = true) - if (invProxy.getAmount(packet.stack) > 0) { + val amount = invProxy.simulateExtract(ItemVariant.of(packet.stack), packet.amount.toLong(), null) + if (amount > 0) { world!!.breakBlock(pos.offset(facing), false) // send the requested amount back to the requester @@ -184,13 +188,15 @@ class MinerBlockEntity(pos: BlockPos, state: BlockState) : DeviceBlockEntity(Phy val friendlyName = TranslatableText("gui.phycon.miner_mode.${name.lowercase()}") } - class MinerInvProxy(val miner: MinerBlockEntity) : GroupedItemInvView { + class MinerStorageProxy(val miner: MinerBlockEntity) : + SnapshotParticipant>?>(), + ExtractionOnlyStorage + { companion object { val TOOL = ItemStack(Items.DIAMOND_PICKAXE) } - private var cachedState: BlockState? = null - private var cachedDrops: List? = null + private var cache: Pair>? = null private val world: World get() = miner.world!! @@ -202,35 +208,73 @@ class MinerBlockEntity(pos: BlockPos, state: BlockState) : DeviceBlockEntity(Phy fun getDrops(recalculate: Boolean = false): List { val targetPos = pos.offset(facing) val realState = world.getBlockState(targetPos) + val cache = this.cache // todo: does BlockState.equals actually work or is reference equality fine for BlockStates? - if (cachedDrops == null || realState != cachedState || recalculate) { - cachedState = realState - + if (cache == null || realState != cache.first || recalculate) { val be = if (realState.hasBlockEntity()) world.getBlockEntity(targetPos) else null - cachedDrops = Block.getDroppedStacks(realState, world as ServerWorld, targetPos, be, null, TOOL) + val drops = Block.getDroppedStacks(realState, world as ServerWorld, targetPos, be, null, TOOL) + this.cache = Pair(realState, drops) + return drops } - return cachedDrops!! + return cache.second } - override fun getStoredStacks(): Set { - if (miner.minerMode != MinerMode.ON_DEMAND) { - return setOf() + override fun createSnapshot(): Pair>? { + return cache + } + + override fun readSnapshot(snapshot: Pair>?) { + cache = snapshot + } + + override fun extract(resource: ItemVariant, maxAmount: Long, transaction: TransactionContext): Long { + val drops = getDrops() + val (matched, unmatched) = drops.partition { resource.matches(it) } + if (matched.isEmpty()) { + return 0 } - return getDrops().toSet() - } - - override fun getTotalCapacity(): Int { - return Int.MAX_VALUE - } - - override fun getStatistics(filter: ItemFilter): GroupedItemInvView.ItemInvStatistic { - var totalCount = 0 - for (s in storedStacks) { - if (filter.matches(s)) { - totalCount += s.count + val matchedCount = matched.sumOf { it.count }.toLong() + val extracted = min(maxAmount, matchedCount) + transaction.addCloseCallback { context, result -> + if (result.wasCommitted()) { + world.breakBlock(pos.offset(facing), false) + // send any un-extracted drops to the network + if (matchedCount > extracted) { + miner.dispatchItemStack(resource.toStack().copyWithCount((matchedCount - extracted).toInt())) + } + for (stack in unmatched) { + miner.dispatchItemStack(stack) + } } } - return GroupedItemInvView.ItemInvStatistic(filter, totalCount, 0, Int.MAX_VALUE) + return extracted + } + + override fun iterator(transaction: TransactionContext): Iterator> { + return getDrops().map { View(it, this) }.iterator() + } + + class View(val stack: ItemStack, val proxy: MinerStorageProxy) : StorageView { + override fun extract(resource: ItemVariant, maxAmount: Long, transaction: TransactionContext): Long { + return proxy.extract(resource, maxAmount, transaction) + } + + override fun isResourceBlank(): Boolean { + return false + } + + override fun getResource(): ItemVariant { + return ItemVariant.of(stack) + } + + override fun getAmount(): Long { + return stack.count.toLong() + } + + override fun getCapacity(): Long { + // TODO: ehh? we have stuff stored, but nothing can be inserted, so... + return 0 + } } }