package net.shadowfacts.phycon.block.netinterface import alexiil.mc.lib.attributes.SearchOptions import alexiil.mc.lib.attributes.Simulation import alexiil.mc.lib.attributes.item.GroupedItemInv import alexiil.mc.lib.attributes.item.ItemAttributes import net.minecraft.block.BlockState import net.minecraft.item.ItemStack import net.minecraft.nbt.NbtCompound import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Direction import net.shadowfacts.phycon.api.packet.Packet import net.shadowfacts.phycon.init.PhyBlockEntities import net.shadowfacts.phycon.block.DeviceBlockEntity import net.shadowfacts.phycon.block.FaceDeviceBlock import net.shadowfacts.phycon.component.ItemStackPacketHandler import net.shadowfacts.phycon.component.NetworkStackProvider import net.shadowfacts.phycon.component.NetworkStackReceiver import net.shadowfacts.phycon.component.handleItemStack import net.shadowfacts.phycon.packet.* import net.shadowfacts.phycon.util.ClientConfigurableDevice import kotlin.math.min /** * @author shadowfacts */ class InterfaceBlockEntity(pos: BlockPos, state: BlockState): DeviceBlockEntity(PhyBlockEntities.INTERFACE, pos, state), ItemStackPacketHandler, NetworkStackProvider, NetworkStackReceiver, ClientConfigurableDevice { private val facing: Direction get() = cachedState[FaceDeviceBlock.FACING] override var providerPriority = 0 override var receiverPriority = 0 var syncPriorities = true // todo: should this be a weak ref? private var inventory: GroupedItemInv? = null fun updateInventory() { val offsetPos = pos.offset(facing) val option = SearchOptions.inDirection(facing) inventory = ItemAttributes.GROUPED_INV.getFirstOrNull(world, offsetPos, option) } private fun getInventory(): GroupedItemInv? { // if we don't have an inventory, try to get one // this happens when readAll is called before a neighbor state changes, such as immediately after world load if (inventory == null) updateInventory() return inventory } override fun handle(packet: Packet) { when (packet) { is RequestInventoryPacket -> handleRequestInventory(packet) is LocateStackPacket -> handleLocateStack(packet) is ExtractStackPacket -> handleExtractStack(packet) is CheckCapacityPacket -> handleCheckCapacity(packet) is ItemStackPacket -> handleItemStack(packet) } } private fun handleRequestInventory(packet: RequestInventoryPacket) { getInventory()?.also { inv -> sendPacket(ReadInventoryPacket(inv, ipAddress, packet.source)) } } private fun handleLocateStack(packet: LocateStackPacket) { getInventory()?.also { inv -> val amount = inv.getAmount(packet.stack) sendPacket(StackLocationPacket(packet.stack, amount, this, ipAddress, packet.source)) } } private fun handleExtractStack(packet: ExtractStackPacket) { getInventory()?.also { inv -> var amount = packet.amount while (amount > 0) { val extracted = inv.extract(packet.stack, min(amount, packet.stack.maxCount)) if (extracted.isEmpty) { break } else { amount -= extracted.count sendPacket(ItemStackPacket(extracted, ipAddress, packet.source)) } } } } private fun handleCheckCapacity(packet: CheckCapacityPacket) { getInventory()?.also { inv -> val remaining = inv.attemptInsertion(packet.stack, Simulation.SIMULATE) val couldAccept = packet.stack.count - remaining.count sendPacket(CapacityPacket(packet.stack, couldAccept, this, ipAddress, packet.source)) } } override fun doHandleItemStack(packet: ItemStackPacket): ItemStack { val inventory = getInventory() if (inventory != null) { val remaining = inventory.insert(packet.stack) // whatever could not be inserted will be sent back to the packet's source return remaining } else { return packet.stack } } override fun toCommonTag(tag: NbtCompound) { super.toCommonTag(tag) writeDeviceConfiguration(tag) } override fun fromCommonTag(tag: NbtCompound) { super.fromCommonTag(tag) loadDeviceConfiguration(tag) } override fun writeDeviceConfiguration(tag: NbtCompound) { tag.putInt("ProviderPriority", providerPriority) tag.putInt("ReceiverPriority", receiverPriority) tag.putBoolean("SyncPriorities", syncPriorities) } override fun loadDeviceConfiguration(tag: NbtCompound) { providerPriority = tag.getInt("ProviderPriority") receiverPriority = tag.getInt("ReceiverPriority") syncPriorities = tag.getBoolean("SyncPriorities") } }