Convert Miner to fabric transfer API

This commit is contained in:
Shadowfacts 2024-07-14 14:58:33 -07:00
parent dbf450e487
commit 0ba1033518
1 changed files with 75 additions and 31 deletions

View File

@ -1,7 +1,10 @@
package net.shadowfacts.phycon.block.miner package net.shadowfacts.phycon.block.miner
import alexiil.mc.lib.attributes.item.GroupedItemInvView import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
import alexiil.mc.lib.attributes.item.filter.ItemFilter 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.Block
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
@ -36,7 +39,7 @@ class MinerBlockEntity(pos: BlockPos, state: BlockState) : DeviceBlockEntity(Phy
private val facing: Direction private val facing: Direction
get() = cachedState[MinerBlock.FACING] get() = cachedState[MinerBlock.FACING]
private val invProxy = MinerInvProxy(this) private val invProxy = MinerStorageProxy(this)
override val pendingInsertions = mutableListOf<PendingInsertion>() override val pendingInsertions = mutableListOf<PendingInsertion>()
override val dispatchStackTimeout = AbstractTerminalBlockEntity.INSERTION_TIMEOUT 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) { if (minerMode != MinerMode.ON_DEMAND || packet.kind != RequestInventoryPacket.Kind.GROUPED) {
return return
} }
sendPacket(ReadGroupedInventoryPacket(invProxy, ipAddress, packet.source)) sendPacket(ReadItemStoragePacket(invProxy, ipAddress, packet.source))
} }
private fun handleLocateStack(packet: LocateStackPacket) { private fun handleLocateStack(packet: LocateStackPacket) {
if (minerMode != MinerMode.ON_DEMAND) { if (minerMode != MinerMode.ON_DEMAND) {
return return
} }
val amount = invProxy.getAmount(packet.stack) val amount = invProxy.simulateExtract(ItemVariant.of(packet.stack), Long.MAX_VALUE, null)
if (amount > 0) { 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 // always recalculate immediately before breaking
val drops = invProxy.getDrops(recalculate = true) 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) world!!.breakBlock(pos.offset(facing), false)
// send the requested amount back to the requester // 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()}") val friendlyName = TranslatableText("gui.phycon.miner_mode.${name.lowercase()}")
} }
class MinerInvProxy(val miner: MinerBlockEntity) : GroupedItemInvView { class MinerStorageProxy(val miner: MinerBlockEntity) :
SnapshotParticipant<Pair<BlockState, List<ItemStack>>?>(),
ExtractionOnlyStorage<ItemVariant>
{
companion object { companion object {
val TOOL = ItemStack(Items.DIAMOND_PICKAXE) val TOOL = ItemStack(Items.DIAMOND_PICKAXE)
} }
private var cachedState: BlockState? = null private var cache: Pair<BlockState, List<ItemStack>>? = null
private var cachedDrops: List<ItemStack>? = null
private val world: World private val world: World
get() = miner.world!! get() = miner.world!!
@ -202,35 +208,73 @@ class MinerBlockEntity(pos: BlockPos, state: BlockState) : DeviceBlockEntity(Phy
fun getDrops(recalculate: Boolean = false): List<ItemStack> { fun getDrops(recalculate: Boolean = false): List<ItemStack> {
val targetPos = pos.offset(facing) val targetPos = pos.offset(facing)
val realState = world.getBlockState(targetPos) val realState = world.getBlockState(targetPos)
val cache = this.cache
// todo: does BlockState.equals actually work or is reference equality fine for BlockStates? // todo: does BlockState.equals actually work or is reference equality fine for BlockStates?
if (cachedDrops == null || realState != cachedState || recalculate) { if (cache == null || realState != cache.first || recalculate) {
cachedState = realState
val be = if (realState.hasBlockEntity()) world.getBlockEntity(targetPos) else null 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<ItemStack> { override fun createSnapshot(): Pair<BlockState, List<ItemStack>>? {
if (miner.minerMode != MinerMode.ON_DEMAND) { return cache
return setOf()
}
return getDrops().toSet()
} }
override fun getTotalCapacity(): Int { override fun readSnapshot(snapshot: Pair<BlockState, List<ItemStack>>?) {
return Int.MAX_VALUE cache = snapshot
} }
override fun getStatistics(filter: ItemFilter): GroupedItemInvView.ItemInvStatistic { override fun extract(resource: ItemVariant, maxAmount: Long, transaction: TransactionContext): Long {
var totalCount = 0 val drops = getDrops()
for (s in storedStacks) { val (matched, unmatched) = drops.partition { resource.matches(it) }
if (filter.matches(s)) { if (matched.isEmpty()) {
totalCount += s.count return 0
}
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<StorageView<ItemVariant>> {
return getDrops().map { View(it, this) }.iterator()
}
class View(val stack: ItemStack, val proxy: MinerStorageProxy) : StorageView<ItemVariant> {
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
}
} }
} }