fix #3182 by passing inventory source to transposer.getInventoryName

This commit is contained in:
Adrian Siekierka 2022-06-12 13:13:24 +02:00 committed by payonel
parent b2831fc2e0
commit 352e75603c
2 changed files with 51 additions and 17 deletions

View File

@ -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))
}

View File

@ -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.
* <br>
* 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.
* <br>
* 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