diff --git a/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala b/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala
index e82090706..94c67f978 100644
--- a/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala
+++ b/src/main/scala/li/cil/oc/server/component/traits/WorldInventoryAnalytics.scala
@@ -6,12 +6,12 @@ import li.cil.oc.api.machine.Callback
import li.cil.oc.api.machine.Context
import li.cil.oc.api.prefab.ItemStackArrayValue
import li.cil.oc.server.component.result
-import li.cil.oc.util.{BlockPosition, DatabaseAccess, InventoryUtils}
+import li.cil.oc.util.{BlockInventorySource, BlockPosition, DatabaseAccess, EntityInventorySource, InventorySource, InventoryUtils}
import li.cil.oc.util.ExtendedWorld._
import li.cil.oc.util.ExtendedArguments._
-import li.cil.oc.util.InventoryUtils
import net.minecraft.inventory.IInventory
import net.minecraft.block.Block
+import net.minecraft.entity.EntityList
import net.minecraft.item.ItemStack
import net.minecraftforge.common.util.ForgeDirection
import net.minecraftforge.oredict.OreDictionary
@@ -102,8 +102,12 @@ trait WorldInventoryAnalytics extends WorldAware with SideRestricted with Networ
}
case _ => None
}
- withInventory(facing, inventory => blockAt(position.offset(facing)) match {
- case Some(block) => result(block.getUnlocalizedName)
+ withInventorySource(facing, {
+ case BlockInventorySource(position, _) => blockAt(position) match {
+ case Some(block) => result(block.getUnlocalizedName)
+ case _ => result(Unit, "Unknown")
+ }
+ case EntityInventorySource(entity, _) => result(EntityList.getEntityString(entity))
case _ => result(Unit, "Unknown")
})
}
@@ -122,9 +126,20 @@ trait WorldInventoryAnalytics extends WorldAware with SideRestricted with Networ
withInventory(facing, inventory => store(inventory.getStackInSlot(args.checkSlot(inventory, 1))))
}
- private def withInventory(side: ForgeDirection, f: IInventory => Array[AnyRef]) =
- InventoryUtils.inventoryAt(position.offset(side)) match {
- case Some(inventory) if inventory.isUseableByPlayer(fakePlayer) && mayInteract(position.offset(side), side.getOpposite) => f(inventory)
+ private def mayInteract(side: ForgeDirection, f: InventorySource): Boolean = {
+ if (!f.inventory.isUseableByPlayer(fakePlayer)) false
+ else f match {
+ case BlockInventorySource(pos, _) => mayInteract(pos, side.getOpposite)
+ case _ => true
+ }
+ }
+
+ private def withInventorySource(side: ForgeDirection, f: InventorySource => Array[AnyRef]) =
+ InventoryUtils.inventorySourceAt(position.offset(side)) match {
+ case Some(is) if mayInteract(side, is) => f(is)
case _ => result(Unit, "no inventory")
}
+
+ private def withInventory(side: ForgeDirection, f: IInventory => Array[AnyRef]) =
+ withInventorySource(side, is => f(is.inventory))
}
diff --git a/src/main/scala/li/cil/oc/util/InventoryUtils.scala b/src/main/scala/li/cil/oc/util/InventoryUtils.scala
index cc0a07a4a..e54030264 100644
--- a/src/main/scala/li/cil/oc/util/InventoryUtils.scala
+++ b/src/main/scala/li/cil/oc/util/InventoryUtils.scala
@@ -2,6 +2,7 @@ package li.cil.oc.util
import li.cil.oc.util.ExtendedWorld._
import net.minecraft.block.BlockChest
+import net.minecraft.entity.Entity
import net.minecraft.entity.item.EntityItem
import net.minecraft.entity.item.EntityMinecartContainer
import net.minecraft.entity.player.EntityPlayer
@@ -25,22 +26,34 @@ object InventoryUtils {
(!stackA.getHasSubtypes || stackA.getItemDamage == stackB.getItemDamage) &&
(!checkNBT || ItemStack.areItemStackTagsEqual(stackA, stackB))
+ /**
+ * Retrieves an actual inventory implementation for a specified world coordinate,
+ * complete with a reference to the source of said implementation.
+ *
+ * This performs special handling for (double-)chests and also checks for
+ * mine carts with chests.
+ */
+ def inventorySourceAt(position: BlockPosition): Option[InventorySource] = position.world match {
+ case Some(world) if world.blockExists(position) => (world.getBlock(position), world.getTileEntity(position)) match {
+ case (block: BlockChest, chest: TileEntityChest) => Option(block.func_149951_m(world, chest.xCoord, chest.yCoord, chest.zCoord)).
+ map(a => BlockInventorySource(position, a))
+ case (_, inventory: IInventory) => Some(BlockInventorySource(position, inventory))
+ case _ => world.getEntitiesWithinAABB(classOf[EntityMinecartContainer], position.bounds).
+ map(_.asInstanceOf[EntityMinecartContainer]).
+ find(!_.isDead).
+ map(a => EntityInventorySource(a, a))
+ }
+ case _ => None
+ }
+
/**
* Retrieves an actual inventory implementation for a specified world coordinate.
*
* This performs special handling for (double-)chests and also checks for
* mine carts with chests.
*/
- def inventoryAt(position: BlockPosition): Option[IInventory] = position.world match {
- case Some(world) if world.blockExists(position) => (world.getBlock(position), world.getTileEntity(position)) match {
- case (block: BlockChest, chest: TileEntityChest) => Option(block.func_149951_m(world, chest.xCoord, chest.yCoord, chest.zCoord))
- case (_, inventory: IInventory) => Some(inventory)
- case _ => world.getEntitiesWithinAABB(classOf[EntityMinecartContainer], position.bounds).
- map(_.asInstanceOf[EntityMinecartContainer]).
- find(!_.isDead)
- }
- case _ => None
- }
+ def inventoryAt(position: BlockPosition): Option[IInventory] = inventorySourceAt(position).
+ map(a => a.inventory)
/**
* Inserts a stack into an inventory.
@@ -408,3 +421,9 @@ object InventoryUtils {
case _ => null
}
}
+
+sealed trait InventorySource {
+ def inventory: IInventory
+}
+final case class BlockInventorySource(position: BlockPosition, inventory: IInventory) extends InventorySource
+final case class EntityInventorySource(entity: Entity, inventory: IInventory) extends InventorySource