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
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<PendingInsertion>()
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<Pair<BlockState, List<ItemStack>>?>(),
ExtractionOnlyStorage<ItemVariant>
{
companion object {
val TOOL = ItemStack(Items.DIAMOND_PICKAXE)
}
private var cachedState: BlockState? = null
private var cachedDrops: List<ItemStack>? = null
private var cache: Pair<BlockState, List<ItemStack>>? = 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<ItemStack> {
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<ItemStack> {
if (miner.minerMode != MinerMode.ON_DEMAND) {
return setOf()
override fun createSnapshot(): Pair<BlockState, List<ItemStack>>? {
return cache
}
override fun readSnapshot(snapshot: Pair<BlockState, List<ItemStack>>?) {
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<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
}
}
}