142 lines
4.6 KiB
Kotlin
142 lines
4.6 KiB
Kotlin
package net.shadowfacts.phycon.block.terminal
|
|
|
|
import alexiil.mc.lib.attributes.item.ItemStackCollections
|
|
import alexiil.mc.lib.attributes.item.ItemStackUtil
|
|
import it.unimi.dsi.fastutil.objects.Object2IntMap
|
|
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
|
|
import net.minecraft.entity.player.PlayerEntity
|
|
import net.minecraft.entity.player.PlayerInventory
|
|
import net.minecraft.inventory.CraftingInventory
|
|
import net.minecraft.inventory.SimpleInventory
|
|
import net.minecraft.item.ItemStack
|
|
import net.minecraft.nbt.CompoundTag
|
|
import net.minecraft.network.PacketByteBuf
|
|
import net.minecraft.screen.ScreenHandler
|
|
import net.minecraft.server.network.ServerPlayerEntity
|
|
import net.minecraft.text.Text
|
|
import net.minecraft.text.TranslatableText
|
|
import net.shadowfacts.phycon.init.PhyBlockEntities
|
|
import net.shadowfacts.phycon.packet.ItemStackPacket
|
|
import net.shadowfacts.phycon.packet.LocateStackPacket
|
|
import net.shadowfacts.phycon.packet.RequestInventoryPacket
|
|
import net.shadowfacts.phycon.util.fromTag
|
|
import net.shadowfacts.phycon.util.toTag
|
|
import java.util.LinkedList
|
|
import kotlin.math.min
|
|
|
|
/**
|
|
* @author shadowfacts
|
|
*/
|
|
class CraftingTerminalBlockEntity: AbstractTerminalBlockEntity(PhyBlockEntities.CRAFTING_TERMINAL) {
|
|
|
|
val craftingInv = SimpleInventory(9)
|
|
|
|
private val completedCraftingStackRequests = LinkedList<CraftingStackLocateRequest>()
|
|
|
|
override fun onActivate(player: PlayerEntity) {
|
|
if (!world!!.isClient) {
|
|
updateAndSync()
|
|
|
|
inventoryCache.clear()
|
|
sendPacket(RequestInventoryPacket(ipAddress))
|
|
val factory = object: ExtendedScreenHandlerFactory {
|
|
override fun createMenu(syncId: Int, playerInv: PlayerInventory, player: PlayerEntity): ScreenHandler? {
|
|
return CraftingTerminalScreenHandler(syncId, playerInv, this@CraftingTerminalBlockEntity)
|
|
}
|
|
|
|
override fun getDisplayName() = TranslatableText("block.phycon.crafting_terminal")
|
|
|
|
override fun writeScreenOpeningData(player: ServerPlayerEntity, buf: PacketByteBuf) {
|
|
buf.writeBlockPos(this@CraftingTerminalBlockEntity.pos)
|
|
}
|
|
}
|
|
player.openHandledScreen(factory)
|
|
}
|
|
}
|
|
|
|
fun requestItemsForCrafting(maxAmount: Int) {
|
|
val amounts = ItemStackCollections.map<IntArray>()
|
|
|
|
for (i in 0 until craftingInv.size()) {
|
|
val craftingInvStack = craftingInv.getStack(i)
|
|
if (craftingInvStack.isEmpty) continue
|
|
if (craftingInvStack.count >= craftingInvStack.maxCount) continue
|
|
|
|
if (craftingInvStack !in amounts) amounts[craftingInvStack] = IntArray(9) { 0 }
|
|
amounts[craftingInvStack]!![i] = min(maxAmount, craftingInvStack.maxCount - craftingInvStack.count)
|
|
}
|
|
|
|
for ((stack, amountPerSlot) in amounts) {
|
|
val total = amountPerSlot.sum()
|
|
val request = CraftingStackLocateRequest(stack, total, counter, amountPerSlot)
|
|
pendingRequests.add(request)
|
|
sendPacket(LocateStackPacket(stack, ipAddress))
|
|
}
|
|
}
|
|
|
|
override fun stackLocateRequestCompleted(request: StackLocateRequest) {
|
|
if (request is CraftingStackLocateRequest) {
|
|
completedCraftingStackRequests.add(request)
|
|
}
|
|
|
|
super.stackLocateRequestCompleted(request)
|
|
}
|
|
|
|
override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
|
|
val craftingReq = completedCraftingStackRequests.find { ItemStackUtil.areEqualIgnoreAmounts(it.stack, packet.stack) }
|
|
if (craftingReq != null) {
|
|
var remaining = packet.stack.copy()
|
|
|
|
for (i in 0 until craftingInv.size()) {
|
|
val currentStack = craftingInv.getStack(i)
|
|
if (currentStack.count >= currentStack.maxCount) continue
|
|
if (!ItemStackUtil.areEqualIgnoreAmounts(currentStack, remaining)) continue
|
|
|
|
val toInsert = minOf(remaining.count, currentStack.maxCount - currentStack.count, craftingReq.amountPerSlot[i])
|
|
currentStack.count += toInsert
|
|
remaining.count -= toInsert
|
|
craftingReq.amountPerSlot[i] -= toInsert
|
|
craftingReq.received += toInsert
|
|
|
|
if (remaining.isEmpty) {
|
|
break
|
|
}
|
|
}
|
|
|
|
if (craftingReq.amountPerSlot.sum() == 0 || craftingReq.received >= craftingReq.totalResultAmount) {
|
|
completedCraftingStackRequests.remove(craftingReq)
|
|
}
|
|
|
|
if (!remaining.isEmpty) {
|
|
remaining = internalBuffer.insert(remaining, TerminalBufferInventory.Mode.FROM_NETWORK)
|
|
}
|
|
|
|
updateAndSync()
|
|
|
|
return remaining
|
|
} else {
|
|
return super.doHandleItemStack(packet)
|
|
}
|
|
}
|
|
|
|
override fun toCommonTag(tag: CompoundTag) {
|
|
super.toCommonTag(tag)
|
|
tag.put("CraftingInv", craftingInv.toTag())
|
|
}
|
|
|
|
override fun fromCommonTag(tag: CompoundTag) {
|
|
super.fromCommonTag(tag)
|
|
craftingInv.fromTag(tag.getList("CraftingInv", 10))
|
|
}
|
|
|
|
class CraftingStackLocateRequest(
|
|
stack: ItemStack,
|
|
amount: Int,
|
|
timestamp: Long,
|
|
val amountPerSlot: IntArray,
|
|
): StackLocateRequest(stack, amount, timestamp) {
|
|
var received: Int = 0
|
|
}
|
|
|
|
}
|