sided inventory for robots; drop can now place stuff from the robots inventory into some other inventory, if present

This commit is contained in:
Florian Nücke 2013-11-21 14:37:16 +01:00
parent 76efda0a7a
commit b3a5521dc1
5 changed files with 135 additions and 58 deletions

View File

@ -79,7 +79,7 @@ trait Inventory extends TileEntity with IInventory with Persistable {
}
}
private def spawnStackInWorld(stack: ItemStack, direction: ForgeDirection) {
def spawnStackInWorld(stack: ItemStack, direction: ForgeDirection) {
val rng = world.rand
val (tx, ty, tz) = (
0.1 * rng.nextGaussian + direction.offsetX * 0.45,

View File

@ -12,6 +12,7 @@ import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.{Blocks, Config, api, common}
import net.minecraft.client.Minecraft
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.inventory.ISidedInventory
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.ForgeDirection
@ -23,7 +24,7 @@ import scala.Some
// robot moves we only create a new proxy tile entity, hook the instance of this
// class that was held by the old proxy to it and can then safely forget the
// old proxy, which will be cleaned up by Minecraft like any other tile entity.
class Robot(isRemote: Boolean) extends Computer(isRemote) with Buffer with PowerInformation {
class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory with Buffer with PowerInformation {
def this() = this(false)
var proxy: RobotProxy = _
@ -282,40 +283,6 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with Buffer with Power
// ----------------------------------------------------------------------- //
override def installedMemory = 64 * 1024
def tier = 0
override def hasRedstoneCard = items(1).fold(false)(driver.item.RedstoneCard.worksWith)
@SideOnly(Side.CLIENT)
override protected def markForRenderUpdate() {
super.markForRenderUpdate()
currentGui.foreach(_.recompileDisplayLists())
}
// ----------------------------------------------------------------------- //
def getInvName = Config.namespace + "container.Robot"
def getSizeInventory = 19
override def getInventoryStackLimit = 64
override def isUseableByPlayer(player: EntityPlayer) =
world.getBlockTileEntity(x, y, z) match {
case t: RobotProxy if t == proxy => player.getDistanceSq(x + 0.5, y + 0.5, z + 0.5) <= 64
case _ => false
}
def isItemValidForSlot(slot: Int, item: ItemStack) = (slot, Registry.driverFor(item)) match {
case (0, _) => true // Allow anything in the tool slot.
case (1, Some(driver)) => driver.slot(item) == Slot.Card
case (2, Some(driver)) => driver.slot(item) == Slot.HardDiskDrive
case (i, _) if 3 until getSizeInventory contains i => true // Normal inventory.
case _ => false // Invalid slot.
}
override def onInventoryChanged() {
super.onInventoryChanged()
if (isServer) {
@ -350,4 +317,57 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with Buffer with Power
}
}
}
// ----------------------------------------------------------------------- //
override def installedMemory = 64 * 1024
def tier = 0
override def hasRedstoneCard = items(1).fold(false)(driver.item.RedstoneCard.worksWith)
@SideOnly(Side.CLIENT)
override protected def markForRenderUpdate() {
super.markForRenderUpdate()
currentGui.foreach(_.recompileDisplayLists())
}
// ----------------------------------------------------------------------- //
def getInvName = Config.namespace + "container.Robot"
def getSizeInventory = 19
override def getInventoryStackLimit = 64
override def isUseableByPlayer(player: EntityPlayer) =
world.getBlockTileEntity(x, y, z) match {
case t: RobotProxy if t == proxy => player.getDistanceSq(x + 0.5, y + 0.5, z + 0.5) <= 64
case _ => false
}
def isItemValidForSlot(slot: Int, item: ItemStack) = (slot, Registry.driverFor(item)) match {
case (0, _) => true // Allow anything in the tool slot.
case (1, Some(driver)) => driver.slot(item) == Slot.Card
case (2, Some(driver)) => driver.slot(item) == Slot.HardDiskDrive
case (i, _) if 3 until getSizeInventory contains i => true // Normal inventory.
case _ => false // Invalid slot.
}
// ----------------------------------------------------------------------- //
def canExtractItem(slot: Int, stack: ItemStack, side: Int) =
getAccessibleSlotsFromSide(side).contains(slot)
def canInsertItem(slot: Int, stack: ItemStack, side: Int) =
getAccessibleSlotsFromSide(side).contains(slot) &&
isItemValidForSlot(slot, stack)
def getAccessibleSlotsFromSide(side: Int) =
toLocal(ForgeDirection.getOrientation(side)) match {
case ForgeDirection.WEST => Array(0)
case ForgeDirection.EAST => Array(1)
case ForgeDirection.NORTH => Array(2)
case _ => (3 until getSizeInventory).toArray
}
}

View File

@ -8,11 +8,12 @@ import li.cil.oc.client.gui
import mods.immibis.redlogic.api.wiring.IWire
import net.minecraft.entity.Entity
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.inventory.ISidedInventory
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.ForgeDirection
class RobotProxy(val robot: Robot) extends Computer(robot.isClient) with Buffer with PowerInformation {
class RobotProxy(val robot: Robot) extends Computer(robot.isClient) with ISidedInventory with Buffer with PowerInformation {
def this() = this(new Robot(false))
// ----------------------------------------------------------------------- //
@ -203,6 +204,14 @@ class RobotProxy(val robot: Robot) extends Computer(robot.isClient) with Buffer
// ----------------------------------------------------------------------- //
def canExtractItem(slot: Int, stack: ItemStack, side: Int) = robot.canExtractItem(slot, stack, side)
def canInsertItem(slot: Int, stack: ItemStack, side: Int) = robot.canInsertItem(slot, stack, side)
def getAccessibleSlotsFromSide(side: Int) = robot.getAccessibleSlotsFromSide(side)
// ----------------------------------------------------------------------- //
override def computer = robot.computer
override def isOn = robot.isOn

View File

@ -7,6 +7,7 @@ import li.cil.oc.server.component.robot.ActivationType
import li.cil.oc.server.{PacketSender => ServerPacketSender}
import net.minecraft.block.{BlockFluid, Block}
import net.minecraft.entity.item.EntityItem
import net.minecraft.inventory.{IInventory, ISidedInventory}
import net.minecraft.item.{ItemStack, ItemBlock}
import net.minecraft.util.{MovingObjectPosition, EnumMovingObjectType, Vec3}
import net.minecraftforge.common.ForgeDirection
@ -125,12 +126,51 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) {
def drop(context: Context, args: Arguments): Array[AnyRef] = {
val facing = checkSideForAction(args, 0)
val count = checkOptionalItemCount(args, 1)
// TODO inventory, if available
// Don't drop using the fake player because he throws too far.
if (robot.dropSlot(actualSlot(selectedSlot), count, facing)) {
context.pause(Config.dropDelay)
result(true)
val dropped = robot.decrStackSize(actualSlot(selectedSlot), count)
if (dropped != null && dropped.stackSize > 0) {
def tryDropIntoInventory(inventory: IInventory, filter: (Int) => Boolean) = {
var success = false
val maxStackSize = inventory.getInventoryStackLimit min dropped.getMaxStackSize
val shouldTryMerge = !dropped.isItemStackDamageable && dropped.getMaxStackSize > 1 && inventory.getInventoryStackLimit > 1
if (shouldTryMerge) {
for (slot <- 0 until inventory.getSizeInventory if dropped.stackSize > 0 && filter(slot)) {
val existing = inventory.getStackInSlot(slot)
val shouldMerge = existing != null && existing.stackSize < maxStackSize &&
existing.isItemEqual(dropped) && ItemStack.areItemStackTagsEqual(existing, dropped)
if (shouldMerge) {
val space = maxStackSize - existing.stackSize
val amount = space min dropped.stackSize
assert(amount > 0)
success = true
existing.stackSize += amount
dropped.stackSize -= amount
}
}
}
def canDropIntoSlot(slot: Int) = filter(slot) && inventory.isItemValidForSlot(slot, dropped) && inventory.getStackInSlot(slot) == null
for (slot <- 0 until inventory.getSizeInventory if dropped.stackSize > 0 && canDropIntoSlot(slot)) {
val amount = maxStackSize min dropped.stackSize
inventory.setInventorySlotContents(slot, dropped.splitStack(amount))
success = true
}
if (success) {
inventory.onInventoryChanged()
}
robot.player().inventory.addItemStackToInventory(dropped)
result(success)
}
world.getBlockTileEntity(x + facing.offsetX, y + facing.offsetY, z + facing.offsetZ) match {
case inventory: ISidedInventory =>
tryDropIntoInventory(inventory, (slot) => inventory.canInsertItem(slot, dropped, facing.getOpposite.ordinal()))
case inventory: IInventory =>
tryDropIntoInventory(inventory, (slot) => true)
case _ =>
// Don't drop using the fake player because he throws too far.
// TODO make player's drop redirect to our dropSlot
robot.spawnStackInWorld(dropped, facing)
context.pause(Config.dropDelay)
result(true)
}
}
else result(false)
}
@ -175,15 +215,19 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) {
def suck(context: Context, args: Arguments): Array[AnyRef] = {
val facing = checkSideForAction(args, 0)
val count = checkOptionalItemCount(args, 1)
// TODO inventory, if available
for (entity <- robot.player().entitiesOnSide[EntityItem](facing) if !entity.isDead && entity.delayBeforeCanPickup <= 0) {
val stack = entity.getEntityItem
val size = stack.stackSize
entity.onCollideWithPlayer(robot.player())
if (stack.stackSize < size || entity.isDead) {
context.pause(Config.suckDelay)
return result(true)
}
world.getBlockTileEntity(x + facing.offsetX, y + facing.offsetY, z + facing.offsetZ) match {
case inventory: ISidedInventory => // TODO
case inventory: IInventory => // TODO
case _ =>
for (entity <- robot.player().entitiesOnSide[EntityItem](facing) if !entity.isDead && entity.delayBeforeCanPickup <= 0) {
val stack = entity.getEntityItem
val size = stack.stackSize
entity.onCollideWithPlayer(robot.player())
if (stack.stackSize < size || entity.isDead) {
context.pause(Config.suckDelay)
return result(true)
}
}
}
result(false)
}

View File

@ -273,9 +273,11 @@ class Player(val robot: Robot) extends FakePlayer(robot.world, "OpenComputers")
// ----------------------------------------------------------------------- //
override def swingItem() {
// TODO animation
}
override def openGui(mod: AnyRef, modGuiId: Int, world: World, x: Int, y: Int, z: Int) {}
override def closeScreen() {}
override def swingItem() {}
override def canAttackPlayer(player: EntityPlayer) =
Config.canAttackPlayers && super.canAttackPlayer(player)
@ -290,9 +292,7 @@ class Player(val robot: Robot) extends FakePlayer(robot.world, "OpenComputers")
override def setItemInUse(stack: ItemStack, maxItemUseDuration: Int) {}
override def openGui(mod: AnyRef, modGuiId: Int, world: World, x: Int, y: Int, z: Int) {}
override def closeScreen() {}
override def isEntityInvulnerable = true
override def heal(amount: Float) {}
@ -302,6 +302,10 @@ class Player(val robot: Robot) extends FakePlayer(robot.world, "OpenComputers")
override def onDeath(source: DamageSource) {}
override def onUpdate() {}
override def onLivingUpdate() {}
override def setCurrentItemOrArmor(slot: Int, stack: ItemStack) {}
override def setRevengeTarget(entity: EntityLivingBase) {}