From dbb710b708203261daf53be895120b6e0976774b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 16 Dec 2015 21:17:38 +0100 Subject: [PATCH] Rudimentary system for interacting with item inventories (via inv controller in robots and drones). Very basic for now, partially because I can't come up with non-terrible names for the methods. --- .../cil/oc/api/driver/InventoryProvider.java | 25 ++++++++--- .../scala/li/cil/oc/client/GuiHandler.scala | 2 - .../scala/li/cil/oc/common/GuiHandler.scala | 2 - .../common/inventory/DatabaseInventory.scala | 3 +- .../opencomputers/DriverUpgradeDatabase.scala | 2 - ....scala => EnvironmentProviderBlocks.scala} | 2 +- .../InventoryProviderDatabase.scala | 17 +++++++ .../InventoryProviderServer.scala | 15 +++++++ .../opencomputers/ModOpenComputers.scala | 5 ++- .../UpgradeInventoryController.scala | 6 +-- .../component/traits/InventoryAware.scala | 3 ++ .../traits/ItemInventoryControl.scala | 45 +++++++++++++++++++ .../li/cil/oc/server/driver/Registry.scala | 6 +-- 13 files changed, 113 insertions(+), 20 deletions(-) rename src/main/scala/li/cil/oc/integration/opencomputers/{BlockEnvironmentProvider.scala => EnvironmentProviderBlocks.scala} (97%) create mode 100644 src/main/scala/li/cil/oc/integration/opencomputers/InventoryProviderDatabase.scala create mode 100644 src/main/scala/li/cil/oc/integration/opencomputers/InventoryProviderServer.scala create mode 100644 src/main/scala/li/cil/oc/server/component/traits/ItemInventoryControl.scala diff --git a/src/main/java/li/cil/oc/api/driver/InventoryProvider.java b/src/main/java/li/cil/oc/api/driver/InventoryProvider.java index 384013152..4308b454a 100644 --- a/src/main/java/li/cil/oc/api/driver/InventoryProvider.java +++ b/src/main/java/li/cil/oc/api/driver/InventoryProvider.java @@ -1,5 +1,6 @@ package li.cil.oc.api.driver; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; @@ -11,17 +12,31 @@ import net.minecraft.item.ItemStack; * allow agents (robots, drones) to interact with such inventories using * the inventory controller upgrade, for example. *

- * Implementations returned by {@link #getInventory(ItemStack)} should - * save changes back to the item stack when {@link IInventory#markDirty()} - * is called. Return null if the specified stack is not supported. + * Implementations returned by {@link #getInventory} should save changes + * back to the item stack when {@link IInventory#markDirty()} is called. + * Return null if the specified stack is not supported. */ public interface InventoryProvider { + /** + * Checks whether this provider works for the specified item stack. + * + * @param stack the item stack to check for. + * @param player the player holding the item, may be null. + * @return true if the stack is supported, false otherwise. + */ + boolean worksWith(ItemStack stack, EntityPlayer player); + /** * Get an inventory implementation that allows interfacing with the * item inventory represented by the specified item stack. + *

+ * Note that the specified player may be null, but will + * usually be the fake player of the agent using the + * inventory controller upgrade to access the item inventory. * - * @param stack the item stack to get the inventory for. + * @param stack the item stack to get the inventory for. + * @param player the player holding the item, may be null. * @return the inventory representing the contents, or null. */ - IInventory getInventory(ItemStack stack); + IInventory getInventory(ItemStack stack, EntityPlayer player); } diff --git a/src/main/scala/li/cil/oc/client/GuiHandler.scala b/src/main/scala/li/cil/oc/client/GuiHandler.scala index 9d2b2a162..a33fe5158 100644 --- a/src/main/scala/li/cil/oc/client/GuiHandler.scala +++ b/src/main/scala/li/cil/oc/client/GuiHandler.scala @@ -71,8 +71,6 @@ object GuiHandler extends CommonGuiHandler { new gui.Drive(player.inventory, () => player.getHeldItem) case Some(database: item.UpgradeDatabase) if id == GuiType.Database.id => new gui.Database(player.inventory, new DatabaseInventory { - override def tier = database.tier - override def container = player.getHeldItem override def isUseableByPlayer(player: EntityPlayer) = player == player diff --git a/src/main/scala/li/cil/oc/common/GuiHandler.scala b/src/main/scala/li/cil/oc/common/GuiHandler.scala index 80bbf946d..8fda2b1e7 100644 --- a/src/main/scala/li/cil/oc/common/GuiHandler.scala +++ b/src/main/scala/li/cil/oc/common/GuiHandler.scala @@ -53,8 +53,6 @@ abstract class GuiHandler extends IGuiHandler { Delegator.subItem(player.getHeldItem) match { case Some(database: item.UpgradeDatabase) if id == GuiType.Database.id => new container.Database(player.inventory, new DatabaseInventory { - override def tier = database.tier - override def container = player.getHeldItem override def isUseableByPlayer(player: EntityPlayer) = player == player diff --git a/src/main/scala/li/cil/oc/common/inventory/DatabaseInventory.scala b/src/main/scala/li/cil/oc/common/inventory/DatabaseInventory.scala index 1dbbb729c..f49ae53b5 100644 --- a/src/main/scala/li/cil/oc/common/inventory/DatabaseInventory.scala +++ b/src/main/scala/li/cil/oc/common/inventory/DatabaseInventory.scala @@ -1,10 +1,11 @@ package li.cil.oc.common.inventory import li.cil.oc.Settings +import li.cil.oc.integration.opencomputers.DriverUpgradeDatabase import net.minecraft.item.ItemStack trait DatabaseInventory extends ItemStackInventory { - def tier: Int + def tier: Int = DriverUpgradeDatabase.tier(container) override def getSizeInventory = Settings.get.databaseEntriesPerTier(tier) diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverUpgradeDatabase.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverUpgradeDatabase.scala index df84dafe1..2193da500 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/DriverUpgradeDatabase.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverUpgradeDatabase.scala @@ -21,8 +21,6 @@ object DriverUpgradeDatabase extends Item with api.driver.item.HostAware { override def createEnvironment(stack: ItemStack, host: api.network.EnvironmentHost) = if (host.world.isRemote) null else new component.UpgradeDatabase(new DatabaseInventory { - override def tier = DriverUpgradeDatabase.tier(stack) - override def container = stack override def isUseableByPlayer(player: EntityPlayer) = false diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/BlockEnvironmentProvider.scala b/src/main/scala/li/cil/oc/integration/opencomputers/EnvironmentProviderBlocks.scala similarity index 97% rename from src/main/scala/li/cil/oc/integration/opencomputers/BlockEnvironmentProvider.scala rename to src/main/scala/li/cil/oc/integration/opencomputers/EnvironmentProviderBlocks.scala index 31bf65266..9e0e2a84d 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/BlockEnvironmentProvider.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/EnvironmentProviderBlocks.scala @@ -19,7 +19,7 @@ import net.minecraft.item.ItemStack * all blocks are present here, because some also serve as upgrades * and therefore have item drivers. */ -object BlockEnvironmentProvider extends EnvironmentProvider { +object EnvironmentProviderBlocks extends EnvironmentProvider { override def getEnvironment(stack: ItemStack): Class[_] = stack.getItem match { case block: ItemBlock if block.field_150939_a != null => if (isOneOf(block.field_150939_a, Constants.BlockName.AccessPoint)) classOf[tileentity.AccessPoint] diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/InventoryProviderDatabase.scala b/src/main/scala/li/cil/oc/integration/opencomputers/InventoryProviderDatabase.scala new file mode 100644 index 000000000..54ec36265 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/opencomputers/InventoryProviderDatabase.scala @@ -0,0 +1,17 @@ +package li.cil.oc.integration.opencomputers + +import li.cil.oc.api.driver.InventoryProvider +import li.cil.oc.common.inventory.DatabaseInventory +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.inventory.IInventory +import net.minecraft.item.ItemStack + +object InventoryProviderDatabase extends InventoryProvider { + override def worksWith(stack: ItemStack, player: EntityPlayer): Boolean = DriverUpgradeDatabase.worksWith(stack) + + override def getInventory(stack: ItemStack, player: EntityPlayer): IInventory = new DatabaseInventory { + override def container: ItemStack = stack + + override def isUseableByPlayer(player: EntityPlayer): Boolean = player == player + } +} diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/InventoryProviderServer.scala b/src/main/scala/li/cil/oc/integration/opencomputers/InventoryProviderServer.scala new file mode 100644 index 000000000..d7e30f1cd --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/opencomputers/InventoryProviderServer.scala @@ -0,0 +1,15 @@ +package li.cil.oc.integration.opencomputers + +import li.cil.oc.api.driver.InventoryProvider +import li.cil.oc.common.inventory.ServerInventory +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.inventory.IInventory +import net.minecraft.item.ItemStack + +object InventoryProviderServer extends InventoryProvider { + override def worksWith(stack: ItemStack, player: EntityPlayer): Boolean = DriverServer.worksWith(stack) + + override def getInventory(stack: ItemStack, player: EntityPlayer): IInventory = new ServerInventory { + override def container: ItemStack = stack + } +} diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala index 7b7348ef6..7ce829940 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala @@ -173,7 +173,10 @@ object ModOpenComputers extends ModProxy { api.Driver.add(DriverUpgradeTankController.Provider) api.Driver.add(DriverUpgradeTractorBeam.Provider) - api.Driver.add(BlockEnvironmentProvider) + api.Driver.add(EnvironmentProviderBlocks) + + api.Driver.add(InventoryProviderDatabase) + api.Driver.add(InventoryProviderServer) blacklistHost(classOf[internal.Adapter], Constants.BlockName.Geolyzer, diff --git a/src/main/scala/li/cil/oc/server/component/UpgradeInventoryController.scala b/src/main/scala/li/cil/oc/server/component/UpgradeInventoryController.scala index 1781367e2..4eeccdc62 100644 --- a/src/main/scala/li/cil/oc/server/component/UpgradeInventoryController.scala +++ b/src/main/scala/li/cil/oc/server/component/UpgradeInventoryController.scala @@ -1,11 +1,11 @@ package li.cil.oc.server.component import li.cil.oc.api.Network -import li.cil.oc.api.network.EnvironmentHost import li.cil.oc.api.internal import li.cil.oc.api.machine.Arguments import li.cil.oc.api.machine.Callback import li.cil.oc.api.machine.Context +import li.cil.oc.api.network.EnvironmentHost import li.cil.oc.api.network._ import li.cil.oc.api.prefab import li.cil.oc.common.tileentity @@ -26,7 +26,7 @@ object UpgradeInventoryController { override protected def checkSideForAction(args: Arguments, n: Int) = args.checkSideAny(n) } - class Drone(val host: EnvironmentHost with internal.Agent) extends prefab.ManagedEnvironment with traits.InventoryAnalytics with traits.InventoryWorldControlMk2 with traits.WorldInventoryAnalytics { + class Drone(val host: EnvironmentHost with internal.Agent) extends prefab.ManagedEnvironment with traits.InventoryAnalytics with traits.InventoryWorldControlMk2 with traits.WorldInventoryAnalytics with traits.ItemInventoryControl { override val node = Network.newNode(this, Visibility.Network). withComponent("inventory_controller", Visibility.Neighbors). create() @@ -44,7 +44,7 @@ object UpgradeInventoryController { override protected def checkSideForAction(args: Arguments, n: Int) = args.checkSideAny(n) } - class Robot(val host: EnvironmentHost with tileentity.Robot) extends prefab.ManagedEnvironment with traits.InventoryAnalytics with traits.InventoryWorldControlMk2 with traits.WorldInventoryAnalytics { + class Robot(val host: EnvironmentHost with tileentity.Robot) extends prefab.ManagedEnvironment with traits.InventoryAnalytics with traits.InventoryWorldControlMk2 with traits.WorldInventoryAnalytics with traits.ItemInventoryControl { override val node = Network.newNode(this, Visibility.Network). withComponent("inventory_controller", Visibility.Neighbors). create() diff --git a/src/main/scala/li/cil/oc/server/component/traits/InventoryAware.scala b/src/main/scala/li/cil/oc/server/component/traits/InventoryAware.scala index 816ab6f35..b8a2d2970 100644 --- a/src/main/scala/li/cil/oc/server/component/traits/InventoryAware.scala +++ b/src/main/scala/li/cil/oc/server/component/traits/InventoryAware.scala @@ -2,9 +2,12 @@ package li.cil.oc.server.component.traits import li.cil.oc.api.machine.Arguments import li.cil.oc.util.ExtendedArguments._ +import net.minecraft.entity.player.EntityPlayer import net.minecraft.inventory.IInventory trait InventoryAware { + def fakePlayer: EntityPlayer + def inventory: IInventory def selectedSlot: Int diff --git a/src/main/scala/li/cil/oc/server/component/traits/ItemInventoryControl.scala b/src/main/scala/li/cil/oc/server/component/traits/ItemInventoryControl.scala new file mode 100644 index 000000000..8d3c2c433 --- /dev/null +++ b/src/main/scala/li/cil/oc/server/component/traits/ItemInventoryControl.scala @@ -0,0 +1,45 @@ +package li.cil.oc.server.component.traits + +import li.cil.oc.api +import li.cil.oc.api.machine.Arguments +import li.cil.oc.api.machine.Callback +import li.cil.oc.api.machine.Context +import li.cil.oc.util.ExtendedArguments._ +import li.cil.oc.util.InventoryUtils +import li.cil.oc.util.ResultWrapper.result +import net.minecraft.inventory.IInventory +import net.minecraft.item.ItemStack +import net.minecraftforge.common.util.ForgeDirection + +trait ItemInventoryControl extends InventoryAware { + @Callback(doc = "function(slot:number):number -- The size of an item inventory in the specified slot.") + def getItemInventorySize(context: Context, args: Arguments): Array[AnyRef] = { + withItemInventory(args.checkSlot(inventory, 0), itemInventory => result(itemInventory.getSizeInventory)) + } + + @Callback(doc = "function(inventorySlot:number, slot:number[, count:number=64]):number -- The size of an item inventory in the specified slot.") + def dropIntoItemInventory(context: Context, args: Arguments): Array[AnyRef] = { + withItemInventory(args.checkSlot(inventory, 0), itemInventory => { + val count = args.optItemCount(1) + result(InventoryUtils.extractFromInventory(InventoryUtils.insertIntoInventory(_, itemInventory), inventory, ForgeDirection.UNKNOWN, count)) + }) + } + + @Callback(doc = "function(inventorySlot:number, slot:number[, count:number=64]):number -- The size of an item inventory in the specified slot.") + def suckFromItemInventory(context: Context, args: Arguments): Array[AnyRef] = { + withItemInventory(args.checkSlot(inventory, 0), itemInventory => { + val count = args.optItemCount(1) + result(InventoryUtils.extractFromInventory(InventoryUtils.insertIntoInventory(_, inventory, slots = Option(insertionSlots)), itemInventory, ForgeDirection.UNKNOWN, count)) + }) + } + + private def withItemInventory(slot: Int, f: IInventory => Array[AnyRef]): Array[AnyRef] = { + inventory.getStackInSlot(slot) match { + case stack: ItemStack => api.Driver.inventoryFor(stack, fakePlayer) match { + case inventory: IInventory => f(inventory) + case _ => result(0, "no item inventory") + } + case _ => result(0, "no item inventory") + } + } +} diff --git a/src/main/scala/li/cil/oc/server/driver/Registry.scala b/src/main/scala/li/cil/oc/server/driver/Registry.scala index 06333068e..3a1d54482 100644 --- a/src/main/scala/li/cil/oc/server/driver/Registry.scala +++ b/src/main/scala/li/cil/oc/server/driver/Registry.scala @@ -119,9 +119,9 @@ private[oc] object Registry extends api.detail.DriverAPI { } override def inventoryFor(stack: ItemStack, player: EntityPlayer): IInventory = { - inventoryProviders.map(provider => provider.getInventory(stack)).collectFirst { - case inventory: IInventory => inventory - }.orNull + inventoryProviders.find(provider => provider.worksWith(stack, player)). + map(provider => provider.getInventory(stack, player)). + orNull } override def blockDrivers = blocks.toSeq