Remove LibBlockAttributes ItemStackCollections use

This commit is contained in:
Shadowfacts 2024-07-14 15:43:56 -07:00
parent d782d43e1b
commit 7e71a1e03d
8 changed files with 66 additions and 43 deletions

View File

@ -1,6 +1,6 @@
package net.shadowfacts.phycon.block.terminal package net.shadowfacts.phycon.block.terminal
import alexiil.mc.lib.attributes.item.ItemStackCollections import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
import net.fabricmc.fabric.api.transfer.v1.storage.Storage import net.fabricmc.fabric.api.transfer.v1.storage.Storage
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction
@ -52,8 +52,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>, pos: BlockP
override val pendingInsertions = mutableListOf<PendingInsertion>() override val pendingInsertions = mutableListOf<PendingInsertion>()
override val dispatchStackTimeout = INSERTION_TIMEOUT override val dispatchStackTimeout = INSERTION_TIMEOUT
// TODO: need a ItemVariant -> Int/Long map val cachedNetItems = Object2IntOpenHashMap<ItemVariant>()
val cachedNetItems = ItemStackCollections.intMap()
private var requestInventoryTimestamp: Long? = null private var requestInventoryTimestamp: Long? = null
// todo: multiple players could have the terminal open simultaneously // todo: multiple players could have the terminal open simultaneously
@ -142,7 +141,7 @@ abstract class AbstractTerminalBlockEntity(type: BlockEntityType<*>, pos: BlockP
val transaction = Transaction.openOuter() val transaction = Transaction.openOuter()
for (view in inventory.iterator(transaction)) { for (view in inventory.iterator(transaction)) {
val amount = view.amount.toInt() val amount = view.amount.toInt()
cachedNetItems.mergeInt(view.resource.toStack(), amount, IntBinaryOperator { a, b -> a + b }) cachedNetItems.mergeInt(view.resource, amount, IntBinaryOperator { a, b -> a + b })
} }
transaction.close() transaction.close()
} }

View File

@ -1,24 +1,20 @@
package net.shadowfacts.phycon.block.terminal package net.shadowfacts.phycon.block.terminal
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
import net.minecraft.screen.slot.Slot import net.minecraft.screen.slot.Slot
import net.minecraft.screen.slot.SlotActionType import net.minecraft.screen.slot.SlotActionType
import net.minecraft.entity.player.PlayerEntity import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory import net.minecraft.entity.player.PlayerInventory
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.network.PacketByteBuf
import net.minecraft.screen.ScreenHandler import net.minecraft.screen.ScreenHandler
import net.minecraft.screen.ScreenHandlerType import net.minecraft.screen.ScreenHandlerType
import net.minecraft.server.network.ServerPlayerEntity import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import net.minecraft.util.registry.Registry import net.minecraft.util.registry.Registry
import net.shadowfacts.phycon.DefaultPlugin import net.shadowfacts.phycon.DefaultPlugin
import net.shadowfacts.phycon.PhysicalConnectivity
import net.shadowfacts.phycon.init.PhyBlocks
import net.shadowfacts.phycon.init.PhyScreens
import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems import net.shadowfacts.phycon.networking.S2CTerminalUpdateDisplayedItems
import net.shadowfacts.phycon.util.SortMode import net.shadowfacts.phycon.util.SortMode
import net.shadowfacts.phycon.util.TerminalSettings import net.shadowfacts.phycon.util.TerminalSettings
import net.shadowfacts.phycon.util.copyWithCount import net.shadowfacts.phycon.util.name
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.max import kotlin.math.max
@ -49,7 +45,7 @@ abstract class AbstractTerminalScreenHandler<T : AbstractTerminalBlockEntity>(
field = value field = value
if (terminal.world!!.isClient) { if (terminal.world!!.isClient) {
itemsForDisplay = value.map { itemsForDisplay = value.map {
it.stack.copyWithCount(it.amount) it.variant.toStack(it.amount)
} }
} }
} }
@ -106,6 +102,8 @@ abstract class AbstractTerminalScreenHandler<T : AbstractTerminalBlockEntity>(
return@filter true return@filter true
} }
} }
// TODO: this is happening on the logical server, won't work with localization
// should filtering happen on the client?
it.key.name.string.contains(searchQuery, true) it.key.name.string.contains(searchQuery, true)
} }
@ -273,5 +271,5 @@ abstract class AbstractTerminalScreenHandler<T : AbstractTerminalBlockEntity>(
fun isBufferSlot(id: Int) = id in bufferSlotsStart until playerSlotsStart fun isBufferSlot(id: Int) = id in bufferSlotsStart until playerSlotsStart
fun isPlayerSlot(id: Int) = id >= playerSlotsStart fun isPlayerSlot(id: Int) = id >= playerSlotsStart
data class Entry(val stack: ItemStack, val amount: Int) data class Entry(val variant: ItemVariant, val amount: Int)
} }

View File

@ -1,7 +1,9 @@
package net.shadowfacts.phycon.block.terminal package net.shadowfacts.phycon.block.terminal
import alexiil.mc.lib.attributes.item.ItemStackCollections import it.unimi.dsi.fastutil.ints.IntBinaryOperator
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.entity.player.PlayerEntity import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory import net.minecraft.entity.player.PlayerInventory
@ -20,7 +22,6 @@ import net.shadowfacts.phycon.util.equalsIgnoringAmount
import net.shadowfacts.phycon.util.fromTag import net.shadowfacts.phycon.util.fromTag
import net.shadowfacts.phycon.util.toTag import net.shadowfacts.phycon.util.toTag
import java.util.LinkedList import java.util.LinkedList
import kotlin.math.min
/** /**
* @author shadowfacts * @author shadowfacts
@ -52,20 +53,23 @@ class CraftingTerminalBlockEntity(pos: BlockPos, state: BlockState) :
} }
fun requestItemsForCrafting(maxAmount: Int) { fun requestItemsForCrafting(maxAmount: Int) {
val amounts = ItemStackCollections.map<IntArray>() // use an array map because we have at most 9 items
// values are bitfields of which slots contain the item
val stackToSlotsMap = Object2IntArrayMap<ItemVariant>()
val or = IntBinaryOperator { a, b -> a or b }
for (i in 0 until craftingInv.size()) { for (i in 0 until craftingInv.size()) {
val craftingInvStack = craftingInv.getStack(i) val craftingInvStack = craftingInv.getStack(i)
if (craftingInvStack.isEmpty) continue if (craftingInvStack.isEmpty) continue
if (craftingInvStack.count >= craftingInvStack.maxCount) continue if (craftingInvStack.count >= craftingInvStack.maxCount) continue
if (craftingInvStack !in amounts) amounts[craftingInvStack] = IntArray(9) { 0 } stackToSlotsMap.mergeInt(ItemVariant.of(craftingInvStack), 1 shl i, or)
amounts[craftingInvStack]!![i] = min(maxAmount, craftingInvStack.maxCount - craftingInvStack.count)
} }
for ((stack, amountPerSlot) in amounts) { for ((variant, slots) in stackToSlotsMap) {
val total = amountPerSlot.sum() val total = slots.countOneBits()
val request = CraftingStackLocateRequest(stack, total, counter, amountPerSlot) val stack = variant.toStack()
val request = CraftingStackLocateRequest(stack, total, counter, slots)
pendingRequests.add(request) pendingRequests.add(request)
sendPacket(LocateStackPacket(stack, ipAddress)) sendPacket(LocateStackPacket(stack, ipAddress))
} }
@ -90,19 +94,19 @@ class CraftingTerminalBlockEntity(pos: BlockPos, state: BlockState) :
if (currentStack.count >= currentStack.maxCount) continue if (currentStack.count >= currentStack.maxCount) continue
if (!currentStack.equalsIgnoringAmount(remaining)) continue if (!currentStack.equalsIgnoringAmount(remaining)) continue
val toInsert = currentStack.count += 1
minOf(remaining.count, currentStack.maxCount - currentStack.count, craftingReq.amountPerSlot[i]) remaining.count -= 1
currentStack.count += toInsert
remaining.count -= toInsert craftingReq.slots = craftingReq.slots and (1 shl i).inv()
craftingReq.amountPerSlot[i] -= toInsert craftingReq.received += 1
craftingReq.received += toInsert
if (remaining.isEmpty) { if (remaining.isEmpty) {
break break
} }
} }
if (craftingReq.amountPerSlot.sum() == 0 || craftingReq.received >= craftingReq.totalResultAmount) { // if slots == 0, there are no more slots needing items for this request
if (craftingReq.slots == 0 || craftingReq.received >= craftingReq.totalResultAmount) {
completedCraftingStackRequests.remove(craftingReq) completedCraftingStackRequests.remove(craftingReq)
} }
@ -132,7 +136,10 @@ class CraftingTerminalBlockEntity(pos: BlockPos, state: BlockState) :
stack: ItemStack, stack: ItemStack,
amount: Int, amount: Int,
timestamp: Long, timestamp: Long,
val amountPerSlot: IntArray, /**
* Values are bitfields of which slots in the crafting inventory this request is for.
*/
var slots: Int,
) : StackLocateRequest(stack, amount, timestamp) { ) : StackLocateRequest(stack, amount, timestamp) {
var received: Int = 0 var received: Int = 0
} }

View File

@ -10,9 +10,7 @@ import net.minecraft.network.PacketByteBuf
import net.shadowfacts.phycon.PhysicalConnectivityClient import net.shadowfacts.phycon.PhysicalConnectivityClient
import net.shadowfacts.phycon.block.terminal.AbstractTerminalBlockEntity import net.shadowfacts.phycon.block.terminal.AbstractTerminalBlockEntity
import net.shadowfacts.phycon.block.terminal.AbstractTerminalScreenHandler import net.shadowfacts.phycon.block.terminal.AbstractTerminalScreenHandler
import net.shadowfacts.phycon.util.TerminalSettings import net.shadowfacts.phycon.util.*
import net.shadowfacts.phycon.util.readItemStackWithoutCount
import net.shadowfacts.phycon.util.writeItemStackWithoutCount
/** /**
* @author shadowfacts * @author shadowfacts
@ -35,7 +33,7 @@ object S2CTerminalUpdateDisplayedItems : ClientReceiver {
buf.writeVarInt(entries.size) buf.writeVarInt(entries.size)
for (e in entries) { for (e in entries) {
buf.writeItemStackWithoutCount(e.stack) buf.writeItemVariant(e.variant)
buf.writeVarInt(e.amount) buf.writeVarInt(e.amount)
} }
@ -58,7 +56,7 @@ object S2CTerminalUpdateDisplayedItems : ClientReceiver {
val entryCount = buf.readVarInt() val entryCount = buf.readVarInt()
val entries = ArrayList<AbstractTerminalScreenHandler.Entry>(entryCount) val entries = ArrayList<AbstractTerminalScreenHandler.Entry>(entryCount)
for (i in 0 until entryCount) { for (i in 0 until entryCount) {
entries.add(AbstractTerminalScreenHandler.Entry(buf.readItemStackWithoutCount(), buf.readVarInt())) entries.add(AbstractTerminalScreenHandler.Entry(buf.readItemVariant(), buf.readVarInt()))
} }
val query = buf.readString() val query = buf.readString()
PhysicalConnectivityClient.terminalSettings.fromTag(buf.readNbt()!!) PhysicalConnectivityClient.terminalSettings.fromTag(buf.readNbt()!!)

View File

@ -1,10 +0,0 @@
package net.shadowfacts.phycon.util
import net.minecraft.item.ItemStack
/**
* @author shadowfacts
*/
fun ItemStack.copyWithCount(count: Int): ItemStack {
return copy().also { it.count = count }
}

View File

@ -6,6 +6,10 @@ import net.minecraft.item.ItemStack
* @author shadowfacts * @author shadowfacts
*/ */
fun ItemStack.copyWithCount(count: Int): ItemStack {
return copy().also { it.count = count }
}
fun ItemStack.equalsIgnoringAmount(other: ItemStack): Boolean { fun ItemStack.equalsIgnoringAmount(other: ItemStack): Boolean {
if (this.isEmpty) return other.isEmpty if (this.isEmpty) return other.isEmpty
if (other.isEmpty) return false if (other.isEmpty) return false

View File

@ -0,0 +1,18 @@
package net.shadowfacts.phycon.util
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
import net.minecraft.item.ItemStack
import net.minecraft.text.Text
/**
* @author shadowfacts
*/
val ItemVariant.name: Text
get() {
// don't use toStack because that copies the NBT
// we assume that items don't mutate NBT in getName
val stack = ItemStack(this.item, 1)
stack.nbt = this.nbt
return item.getName(stack)
}

View File

@ -1,5 +1,6 @@
package net.shadowfacts.phycon.util package net.shadowfacts.phycon.util
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant
import net.minecraft.item.Item import net.minecraft.item.Item
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.nbt.NbtCompound import net.minecraft.nbt.NbtCompound
@ -35,3 +36,11 @@ fun PacketByteBuf.readItemStackWithoutCount(): ItemStack {
stack stack
} }
} }
fun PacketByteBuf.writeItemVariant(variant: ItemVariant) {
variant.toPacket(this)
}
fun PacketByteBuf.readItemVariant(): ItemVariant {
return ItemVariant.fromPacket(this)
}