Send remainder of partially-inserted stacks back to source

This commit is contained in:
Shadowfacts 2021-02-11 23:11:50 -05:00
parent d61ed8b7cc
commit 26134cea9d
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
6 changed files with 67 additions and 30 deletions

View File

@ -0,0 +1,15 @@
package net.shadowfacts.phycon.api;
import net.shadowfacts.phycon.api.packet.Packet;
/**
* @author shadowfacts
*/
public interface PacketSource {
// todo: better name for this
void sendToSingle(Packet packet);
void sendToAll(Packet packet);
void sendToAll(Packet packet, Iterable<PacketSink> destinations);
}

View File

@ -4,18 +4,16 @@ import net.minecraft.block.BlockState
import net.minecraft.block.entity.BlockEntity import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityType import net.minecraft.block.entity.BlockEntityType
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.util.Tickable
import net.shadowfacts.phycon.api.PacketSink import net.shadowfacts.phycon.api.PacketSink
import net.shadowfacts.phycon.api.PacketSource
import net.shadowfacts.phycon.api.packet.Packet import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.api.util.MACAddress
import net.shadowfacts.phycon.network.packet.DeviceRemovedPacket import net.shadowfacts.phycon.network.packet.DeviceRemovedPacket
import java.lang.ref.WeakReference
import java.util.*
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), PacketSink { abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), PacketSink, PacketSource {
var macAddress = MACAddress.random() var macAddress = MACAddress.random()
protected set protected set
@ -48,8 +46,7 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), P
destination.handle(packet) destination.handle(packet)
} }
// todo: better name for this override fun sendToSingle(packet: Packet) {
fun sendToSingle(packet: Packet) {
val destinations = NetworkUtil.findDestinations(world!!, pos) val destinations = NetworkUtil.findDestinations(world!!, pos)
if (destinations.size != 1) { if (destinations.size != 1) {
// todo: handle this better // todo: handle this better
@ -59,11 +56,11 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>): BlockEntity(type), P
send(packet, destinations.first()) send(packet, destinations.first())
} }
fun sendToAll(packet: Packet) { override fun sendToAll(packet: Packet) {
sendToAll(packet, NetworkUtil.findDestinations(world!!, pos)) sendToAll(packet, NetworkUtil.findDestinations(world!!, pos))
} }
fun sendToAll(packet: Packet, destinations: Iterable<PacketSink>) { override fun sendToAll(packet: Packet, destinations: Iterable<PacketSink>) {
destinations.forEach { destinations.forEach {
it.handle(packet) it.handle(packet)
} }

View File

@ -4,17 +4,19 @@ import alexiil.mc.lib.attributes.SearchOptions
import alexiil.mc.lib.attributes.Simulation import alexiil.mc.lib.attributes.Simulation
import alexiil.mc.lib.attributes.item.GroupedItemInv import alexiil.mc.lib.attributes.item.GroupedItemInv
import alexiil.mc.lib.attributes.item.ItemAttributes import alexiil.mc.lib.attributes.item.ItemAttributes
import net.minecraft.entity.ItemEntity import net.minecraft.item.ItemStack
import net.minecraft.util.math.Direction import net.minecraft.util.math.Direction
import net.shadowfacts.phycon.api.packet.Packet import net.shadowfacts.phycon.api.packet.Packet
import net.shadowfacts.phycon.init.PhyBlockEntities import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.network.DeviceBlockEntity import net.shadowfacts.phycon.network.DeviceBlockEntity
import net.shadowfacts.phycon.network.component.ItemStackPacketHandler
import net.shadowfacts.phycon.network.component.handleItemStack
import net.shadowfacts.phycon.network.packet.* import net.shadowfacts.phycon.network.packet.*
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE) { class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE), ItemStackPacketHandler {
private val facing: Direction private val facing: Direction
get() = world!!.getBlockState(pos)[InterfaceBlock.FACING] get() = world!!.getBlockState(pos)[InterfaceBlock.FACING]
@ -73,21 +75,14 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE) {
} }
} }
private fun handleItemStack(packet: ItemStackPacket) { override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
val inventory = getInventory() val inventory = getInventory()
if (inventory != null) { if (inventory != null) {
val remaining = inventory.insert(packet.stack) val remaining = inventory.insert(packet.stack)
if (!remaining.isEmpty) { // whatever could not be inserted will be sent back to the packet's source
// todo: should this send whatever was left back to the terminal instead of dropping it? return remaining
// todo: calculate entity spawn point by finding non-obstructed location
val entity = ItemEntity(world!!, pos.x.toDouble(), pos.y + 1.0, pos.z.toDouble(), remaining)
world!!.spawnEntity(entity)
}
} else { } else {
// todo: should the stack back to the terminal instead of dropping it? return packet.stack
// todo: calculate entity spawn point by finding non-obstructed location
val entity = ItemEntity(world!!, pos.x.toDouble(), pos.y + 1.0, pos.z.toDouble(), packet.stack)
world!!.spawnEntity(entity)
} }
} }

View File

@ -7,7 +7,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.entity.ItemEntity
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.inventory.Inventory import net.minecraft.inventory.Inventory
@ -25,6 +24,8 @@ import net.shadowfacts.phycon.api.util.MACAddress
import net.shadowfacts.phycon.init.PhyBlockEntities import net.shadowfacts.phycon.init.PhyBlockEntities
import net.shadowfacts.phycon.network.DeviceBlockEntity import net.shadowfacts.phycon.network.DeviceBlockEntity
import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity import net.shadowfacts.phycon.network.block.netinterface.InterfaceBlockEntity
import net.shadowfacts.phycon.network.component.ItemStackPacketHandler
import net.shadowfacts.phycon.network.component.handleItemStack
import net.shadowfacts.phycon.network.packet.* import net.shadowfacts.phycon.network.packet.*
import java.util.* import java.util.*
import kotlin.math.min import kotlin.math.min
@ -32,7 +33,7 @@ import kotlin.math.min
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), InventoryChangedListener, BlockEntityClientSerializable, Tickable { class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), InventoryChangedListener, BlockEntityClientSerializable, Tickable, ItemStackPacketHandler {
companion object { companion object {
val LOCATE_REQUEST_TIMEOUT = 40 // ticks val LOCATE_REQUEST_TIMEOUT = 40 // ticks
@ -89,18 +90,15 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), Invento
} }
} }
private fun handleItemStack(packet: ItemStackPacket) { override fun doHandleItemStack(packet: ItemStackPacket): ItemStack {
val remaining = internalBuffer.insertFromNetwork(packet.stack) val remaining = internalBuffer.insertFromNetwork(packet.stack)
if (!remaining.isEmpty) {
// todo: calculate entity spawn point by finding non-obstructed location
val entity = ItemEntity(world!!, pos.x.toDouble(), pos.y + 1.0, pos.z.toDouble(), remaining)
world!!.spawnEntity(entity)
}
// this happens outside the normal update loop because by receiving the item stack packet // this happens outside the normal update loop because by receiving the item stack packet
// we "know" how much the count in the source inventory has changed // we "know" how much the count in the source inventory has changed
updateNetItems() updateNetItems()
sync() sync()
return remaining
} }
private fun handleCapacity(packet: CapacityPacket) { private fun handleCapacity(packet: CapacityPacket) {

View File

@ -0,0 +1,31 @@
package net.shadowfacts.phycon.network.component
import net.minecraft.block.entity.BlockEntity
import net.minecraft.entity.ItemEntity
import net.minecraft.item.ItemStack
import net.shadowfacts.phycon.api.PacketSink
import net.shadowfacts.phycon.api.PacketSource
import net.shadowfacts.phycon.network.packet.ItemStackPacket
/**
* @author shadowfacts
*/
interface ItemStackPacketHandler: PacketSink, PacketSource {
fun doHandleItemStack(packet: ItemStackPacket): ItemStack
}
fun <BE> BE.handleItemStack(packet: ItemStackPacket) where BE: BlockEntity, BE: ItemStackPacketHandler {
// todo: is 5 a good number?
// the max bounce count should always be odd, so the item is spawned in-world at the
if (packet.bounceCount == 5) {
// todo: calculate entity spawn point by finding non-obstructed location
val entity = ItemEntity(world!!, pos.x.toDouble(), pos.y + 1.0, pos.z.toDouble(), packet.stack)
world!!.spawnEntity(entity)
return
}
val remainder = doHandleItemStack(packet)
// if there are any items remaining, send them back to the source with incremented bounce count
if (!remainder.isEmpty) {
sendToSingle(ItemStackPacket(remainder, packet.bounceCount + 1, macAddress, packet.source))
}
}

View File

@ -6,5 +6,6 @@ import net.shadowfacts.phycon.api.util.MACAddress
/** /**
* @author shadowfacts * @author shadowfacts
*/ */
class ItemStackPacket(val stack: ItemStack, source: MACAddress, destination: MACAddress): BasePacket(source, destination) { class ItemStackPacket(val stack: ItemStack, val bounceCount: Int, source: MACAddress, destination: MACAddress): BasePacket(source, destination) {
constructor(stack: ItemStack, source: MACAddress, destination: MACAddress): this(stack, 0, source, destination)
} }