mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-19 12:17:17 -04:00
API ADDITION: added check/opt/isItemStack to Arguments interface. This is for convenience when converting tables representing item stacks in the format they are pushed by the built-in item stack converter.
Finished AE2 export bus driver. Can now be used to get and set the configuration (i.e. the stacks configured in the bus), and to trigger an export operation into a specific slot of the target inventory. This behaves as closely to a normal export operation as possible, i.e. it tries all configurations, exports as many items as defined by the number of speed upgrades in the bus, and respects the fuzzy configuration of the bus. It also uses energy like a normal export operation would, drawing energy from the ME network the export bus is in.
This commit is contained in:
parent
8a1435c167
commit
bd0ae24a32
@ -11,7 +11,7 @@ import li.cil.oc.api.detail.*;
|
||||
*/
|
||||
public class API {
|
||||
public static final String ID_OWNER = "OpenComputers|Core";
|
||||
public static final String VERSION = "4.0.0-alpha.1";
|
||||
public static final String VERSION = "4.0.0-alpha.2";
|
||||
|
||||
public static DriverAPI driver = null;
|
||||
public static FileSystemAPI fileSystem = null;
|
||||
|
@ -1,5 +1,7 @@
|
||||
package li.cil.oc.api.machine;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -117,6 +119,21 @@ public interface Arguments extends Iterable<Object> {
|
||||
*/
|
||||
Map checkTable(int index);
|
||||
|
||||
/**
|
||||
* Try to get an item stack representation at the specified index.
|
||||
* <p/>
|
||||
* This is a utility method provided to convert tables to item stacks, with
|
||||
* the tables being of a compatible format to that of tables generated by
|
||||
* the built-in item stack converter. In particular, this takes care of
|
||||
* restoring NBT data attached to the item stack.
|
||||
* <p/>
|
||||
* Throws an error if there are too few arguments.
|
||||
*
|
||||
* @param index the index from which to get the argument.
|
||||
* @return the item stack at the specified index.
|
||||
*/
|
||||
ItemStack checkItemStack(int index);
|
||||
|
||||
/**
|
||||
* Get whatever is at the specified index.
|
||||
* <p/>
|
||||
@ -219,6 +236,19 @@ public interface Arguments extends Iterable<Object> {
|
||||
*/
|
||||
Map optTable(int index, Map def);
|
||||
|
||||
/**
|
||||
* Try to get an item stack at the specified index.
|
||||
* <p/>
|
||||
* Return the specified default value if there is no such element, behaves
|
||||
* like {@link #checkItemStack(int)} otherwise.
|
||||
*
|
||||
* @param index the index from which to get the argument.
|
||||
* @return the item stack at the specified index.
|
||||
* @throws IllegalArgumentException if there is no argument at that index,
|
||||
* or if the argument is not an item stack.
|
||||
*/
|
||||
ItemStack optItemStack(int index, ItemStack def);
|
||||
|
||||
/**
|
||||
* Tests whether the argument at the specified index is a boolean value.
|
||||
* <p/>
|
||||
@ -281,10 +311,21 @@ public interface Arguments extends Iterable<Object> {
|
||||
* index, i.e. if there are too few arguments.
|
||||
*
|
||||
* @param index the index to check.
|
||||
* @return true if the argument is a string; false otherwise.
|
||||
* @return true if the argument is a table; false otherwise.
|
||||
*/
|
||||
boolean isTable(int index);
|
||||
|
||||
/**
|
||||
* Tests whether the argument at the specified index is an item stack.
|
||||
* <p/>
|
||||
* This will return false if there is <em>no</em> argument at the specified
|
||||
* index, i.e. if there are too few arguments.
|
||||
*
|
||||
* @param index the index to check.
|
||||
* @return true if the argument is an item stack; false otherwise.
|
||||
*/
|
||||
boolean isItemStack(int index);
|
||||
|
||||
/**
|
||||
* Converts the argument list to a standard Java array, converting byte
|
||||
* arrays to strings automatically, since this is usually what others
|
||||
|
@ -1,6 +1,13 @@
|
||||
package li.cil.oc.integration.appeng
|
||||
|
||||
import appeng.api.config.Actionable
|
||||
import appeng.api.config.FuzzyMode
|
||||
import appeng.api.config.Settings
|
||||
import appeng.api.config.Upgrades
|
||||
import appeng.api.networking.security.MachineSource
|
||||
import appeng.parts.automation.PartExportBus
|
||||
import appeng.util.Platform
|
||||
import appeng.util.item.AEItemStack
|
||||
import li.cil.oc.api.driver
|
||||
import li.cil.oc.api.driver.NamedBlock
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
@ -8,10 +15,13 @@ import li.cil.oc.api.machine.Callback
|
||||
import li.cil.oc.api.machine.Context
|
||||
import li.cil.oc.integration.ManagedTileEntityEnvironment
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import li.cil.oc.util.InventoryUtils
|
||||
import li.cil.oc.util.ResultWrapper._
|
||||
import net.minecraft.world.World
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
import scala.collection.convert.WrapAsScala._
|
||||
|
||||
object DriverExportBus extends driver.Block {
|
||||
type ExportBusTile = appeng.api.parts.IPartHost
|
||||
|
||||
@ -23,22 +33,94 @@ object DriverExportBus extends driver.Block {
|
||||
|
||||
override def createEnvironment(world: World, x: Int, y: Int, z: Int) = new Environment(world.getTileEntity(x, y, z).asInstanceOf[ExportBusTile])
|
||||
|
||||
class Environment(tileEntity: ExportBusTile) extends ManagedTileEntityEnvironment[ExportBusTile](tileEntity, "me_exportbus") with NamedBlock {
|
||||
class Environment(host: ExportBusTile) extends ManagedTileEntityEnvironment[ExportBusTile](host, "me_exportbus") with NamedBlock {
|
||||
override def preferredName = "me_exportbus"
|
||||
|
||||
override def priority = 0
|
||||
|
||||
@Callback(doc = "function(side:number, stack:table):boolean -- Configure the export bus point in the specified direction to export an item stack matching the specified descriptor.")
|
||||
def configure(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
@Callback(doc = "function(side:number, [ slot:number]):boolean -- Get the configuration of the export bus pointing in the specified direction.")
|
||||
def getConfiguration(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val side = args.checkSide(0, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
tileEntity.getPart(side) match {
|
||||
host.getPart(side) match {
|
||||
case export: PartExportBus =>
|
||||
val stack = args.checkItemStack(1)
|
||||
export.getInventoryByName("config").setInventorySlotContents(0, stack)
|
||||
val config = export.getInventoryByName("config")
|
||||
val slot = args.optSlot(config, 2, 0)
|
||||
val stack = config.getStackInSlot(slot)
|
||||
result(stack)
|
||||
case _ => result(Unit, "no export bus")
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = "function(side:number, stack:table,[ slot:number]):boolean -- Configure the export bus pointing in the specified direction to export item stacks matching the specified descriptor.")
|
||||
def setConfiguration(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val side = args.checkSide(0, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
host.getPart(side) match {
|
||||
case export: PartExportBus =>
|
||||
val stack = if (args.optAny(1, null) == null) null else args.checkItemStack(1)
|
||||
val config = export.getInventoryByName("config")
|
||||
val slot = args.optSlot(config, 2, 0)
|
||||
config.setInventorySlotContents(slot, stack)
|
||||
context.pause(0.5)
|
||||
result(true)
|
||||
case _ => result(Unit, "no export bus")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Callback(doc = "function(side:number, slot:number):boolean -- Make the export bus facing the specified direction perform a single export operation into the specified slot.")
|
||||
def exportIntoSlot(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
val side = args.checkSide(0, ForgeDirection.VALID_DIRECTIONS: _*)
|
||||
host.getPart(side) match {
|
||||
case export: PartExportBus =>
|
||||
val location = host.getLocation
|
||||
InventoryUtils.inventoryAt(location.getWorld, location.x + side.offsetX, location.y + side.offsetY, location.z + side.offsetZ) match {
|
||||
case Some(inventory) =>
|
||||
val targetSlot = args.checkSlot(inventory, 1)
|
||||
val config = export.getInventoryByName("config")
|
||||
val itemStorage = export.getProxy.getStorage.getItemInventory
|
||||
var count = export.getInstalledUpgrades(Upgrades.SPEED) match {
|
||||
case 1 => 8
|
||||
case 2 => 32
|
||||
case 3 => 64
|
||||
case 4 => 96
|
||||
case _ => 1
|
||||
}
|
||||
val fuzzyMode = export.getConfigManager.getSetting(Settings.FUZZY_MODE).asInstanceOf[FuzzyMode]
|
||||
val source = new MachineSource(export)
|
||||
var didSomething = false
|
||||
for (slot <- 0 until config.getSizeInventory if count > 0) {
|
||||
val filter = AEItemStack.create(config.getStackInSlot(slot))
|
||||
val stacks =
|
||||
if (export.getInstalledUpgrades(Upgrades.FUZZY) > 0)
|
||||
itemStorage.getStorageList.findFuzzy(filter, fuzzyMode).toSeq
|
||||
else
|
||||
Seq(itemStorage.getStorageList.findPrecise(filter))
|
||||
for (ais <- stacks if count > 0 && ais != null) {
|
||||
val is = ais.getItemStack
|
||||
is.stackSize = count
|
||||
if (InventoryUtils.insertIntoInventorySlot(is, inventory, side.getOpposite, targetSlot, count, simulate = true)) {
|
||||
ais.setStackSize(count - is.stackSize)
|
||||
val eais = Platform.poweredExtraction(export.getProxy.getEnergy, itemStorage, ais, source)
|
||||
if (eais != null) {
|
||||
val eis = eais.getItemStack
|
||||
count -= eis.stackSize
|
||||
didSomething = true
|
||||
InventoryUtils.insertIntoInventorySlot(eis, inventory, side.getOpposite, targetSlot)
|
||||
if (eis.stackSize > 0) {
|
||||
eais.setStackSize(eis.stackSize)
|
||||
itemStorage.injectItems(ais, Actionable.MODULATE, source)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (didSomething) {
|
||||
context.pause(0.25)
|
||||
}
|
||||
result(didSomething)
|
||||
case _ => result(Unit, "no inventory")
|
||||
}
|
||||
case _ => result(Unit, "no export bus")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,11 @@ import java.util
|
||||
|
||||
import com.google.common.base.Charsets
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.CompressedStreamTools
|
||||
import net.minecraft.nbt.NBTSizeTracker
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
|
||||
import scala.collection.convert.WrapAsJava._
|
||||
import scala.collection.mutable
|
||||
@ -108,6 +113,29 @@ class ArgumentsImpl(val args: Seq[AnyRef]) extends Arguments {
|
||||
else checkTable(index)
|
||||
}
|
||||
|
||||
def checkItemStack(index: Int) = {
|
||||
val map = checkTable(index)
|
||||
map.get("name") match {
|
||||
case name: String =>
|
||||
val damage = map.get("damage") match {
|
||||
case number: Number => number.intValue()
|
||||
case _ => 0
|
||||
}
|
||||
val tag = map.get("tag") match {
|
||||
case ba: Array[Byte] => toNbtTagCompound(ba)
|
||||
case s: String => toNbtTagCompound(s.getBytes(Charsets.UTF_8))
|
||||
case _ => None
|
||||
}
|
||||
makeStack(name, damage, tag)
|
||||
case _ => throw new IllegalArgumentException("invalid item stack")
|
||||
}
|
||||
}
|
||||
|
||||
def optItemStack(index: Int, default: ItemStack) = {
|
||||
if (!isDefined(index)) default
|
||||
else checkItemStack(index)
|
||||
}
|
||||
|
||||
def isBoolean(index: Int) =
|
||||
index >= 0 && index < count && (args(index) match {
|
||||
case value: java.lang.Boolean => true
|
||||
@ -149,6 +177,16 @@ class ArgumentsImpl(val args: Seq[AnyRef]) extends Arguments {
|
||||
case _ => false
|
||||
})
|
||||
|
||||
def isItemStack(index: Int) =
|
||||
isTable(index) && {
|
||||
val map = checkTable(index)
|
||||
map.get("name") match {
|
||||
case value: String => true
|
||||
case value: Array[Byte] => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
def toArray = args.map {
|
||||
case value: Array[Byte] => new String(value, Charsets.UTF_8)
|
||||
case value => value
|
||||
@ -178,4 +216,16 @@ class ArgumentsImpl(val args: Seq[AnyRef]) extends Arguments {
|
||||
case value: mutable.Map[_, _] => "table"
|
||||
case _ => value.getClass.getSimpleName
|
||||
}
|
||||
|
||||
private def makeStack(name: String, damage: Int, tag: Option[NBTTagCompound]) = {
|
||||
Item.itemRegistry.getObject(name) match {
|
||||
case item: Item =>
|
||||
val stack = new ItemStack(item, 1, damage)
|
||||
tag.foreach(stack.setTagCompound)
|
||||
stack
|
||||
case _ => throw new IllegalArgumentException("invalid item stack")
|
||||
}
|
||||
}
|
||||
|
||||
private def toNbtTagCompound(data: Array[Byte]) = Option(CompressedStreamTools.func_152457_a(data, NBTSizeTracker.field_152451_a))
|
||||
}
|
||||
|
@ -1,14 +1,8 @@
|
||||
package li.cil.oc.util
|
||||
|
||||
import com.google.common.base.Charsets
|
||||
import li.cil.oc.api.internal.Robot
|
||||
import li.cil.oc.api.machine.Arguments
|
||||
import net.minecraft.inventory.IInventory
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.CompressedStreamTools
|
||||
import net.minecraft.nbt.NBTSizeTracker
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import net.minecraftforge.common.util.ForgeDirection
|
||||
|
||||
import scala.language.implicitConversions
|
||||
@ -38,6 +32,11 @@ object ExtendedArguments {
|
||||
slot
|
||||
}
|
||||
|
||||
def optSlot(inventory: IInventory, n: Int, default: Int) = {
|
||||
if (n >= 0 && n < args.count()) checkSlot(inventory, n)
|
||||
else default
|
||||
}
|
||||
|
||||
def checkSlot(robot: Robot, n: Int) = {
|
||||
val slot = args.checkInteger(n) - 1
|
||||
if (slot < 0 || slot >= robot.inventorySize) {
|
||||
@ -69,35 +68,6 @@ object ExtendedArguments {
|
||||
if (allowed.isEmpty || (allowed contains direction)) direction
|
||||
else throw new IllegalArgumentException("unsupported side")
|
||||
}
|
||||
|
||||
def checkItemStack(n: Int) = {
|
||||
val map = args.checkTable(n)
|
||||
map.get("name") match {
|
||||
case name: String =>
|
||||
val damage = map.get("damage") match {
|
||||
case number: Number => number.intValue()
|
||||
case _ => 0
|
||||
}
|
||||
val tag = map.get("tag") match {
|
||||
case ba: Array[Byte] => toNbtTagCompound(ba)
|
||||
case s: String => toNbtTagCompound(s.getBytes(Charsets.UTF_8))
|
||||
case _ => None
|
||||
}
|
||||
makeStack(name, damage, tag)
|
||||
case _ => throw new IllegalArgumentException("invalid item stack")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def makeStack(name: String, damage: Int, tag: Option[NBTTagCompound]) = {
|
||||
Item.itemRegistry.getObject(name) match {
|
||||
case item: Item =>
|
||||
val stack = new ItemStack(item, 1, damage)
|
||||
tag.foreach(stack.setTagCompound)
|
||||
stack
|
||||
case _ => throw new IllegalArgumentException("invalid item stack")
|
||||
}
|
||||
}
|
||||
|
||||
private def toNbtTagCompound(data: Array[Byte]) = Option(CompressedStreamTools.func_152457_a(data, NBTSizeTracker.field_152451_a))
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ object InventoryUtils {
|
||||
* The number of items inserted can be limited, to avoid unnecessary
|
||||
* changes to the inventory the stack may come from, for example.
|
||||
*/
|
||||
def insertIntoInventorySlot(stack: ItemStack, inventory: IInventory, side: ForgeDirection, slot: Int, limit: Int = 64) =
|
||||
def insertIntoInventorySlot(stack: ItemStack, inventory: IInventory, side: ForgeDirection, slot: Int, limit: Int = 64, simulate: Boolean = false) =
|
||||
(stack != null && limit > 0) && {
|
||||
val isSideValidForSlot = inventory match {
|
||||
case inventory: ISidedInventory => inventory.canInsertItem(slot, stack, side.ordinal)
|
||||
@ -64,15 +64,22 @@ object InventoryUtils {
|
||||
if (shouldMerge) {
|
||||
val space = maxStackSize - existing.stackSize
|
||||
val amount = math.min(space, math.min(stack.stackSize, limit))
|
||||
existing.stackSize += amount
|
||||
stack.stackSize -= amount
|
||||
inventory.markDirty()
|
||||
true
|
||||
if (simulate) amount > 0
|
||||
else {
|
||||
existing.stackSize += amount
|
||||
inventory.markDirty()
|
||||
true
|
||||
}
|
||||
}
|
||||
else (existing == null) && {
|
||||
val amount = math.min(maxStackSize, math.min(stack.stackSize, limit))
|
||||
inventory.setInventorySlotContents(slot, stack.splitStack(amount))
|
||||
true
|
||||
val inserted = stack.splitStack(amount)
|
||||
if (simulate) amount > 0
|
||||
else {
|
||||
inventory.setInventorySlotContents(slot, inserted)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -142,7 +149,7 @@ object InventoryUtils {
|
||||
* item stack will be adjusted to reflect the number items inserted, by
|
||||
* having its size decremented accordingly.
|
||||
*/
|
||||
def insertIntoInventory(stack: ItemStack, inventory: IInventory, side: ForgeDirection, limit: Int = 64) =
|
||||
def insertIntoInventory(stack: ItemStack, inventory: IInventory, side: ForgeDirection, limit: Int = 64, simulate: Boolean = false) =
|
||||
(stack != null && limit > 0) && {
|
||||
var success = false
|
||||
var remaining = limit
|
||||
@ -151,7 +158,7 @@ object InventoryUtils {
|
||||
if (shouldTryMerge) {
|
||||
for (slot <- 0 until inventory.getSizeInventory) {
|
||||
val stackSize = stack.stackSize
|
||||
if ((inventory.getStackInSlot(slot) != null) && insertIntoInventorySlot(stack, inventory, side, slot, remaining)) {
|
||||
if ((inventory.getStackInSlot(slot) != null) && insertIntoInventorySlot(stack, inventory, side, slot, remaining, simulate)) {
|
||||
remaining -= stackSize - stack.stackSize
|
||||
success = true
|
||||
}
|
||||
@ -160,7 +167,7 @@ object InventoryUtils {
|
||||
|
||||
for (slot <- 0 until inventory.getSizeInventory) {
|
||||
val stackSize = stack.stackSize
|
||||
if ((inventory.getStackInSlot(slot) == null) && insertIntoInventorySlot(stack, inventory, side, slot, remaining)) {
|
||||
if ((inventory.getStackInSlot(slot) == null) && insertIntoInventorySlot(stack, inventory, side, slot, remaining, simulate)) {
|
||||
remaining -= stackSize - stack.stackSize
|
||||
success = true
|
||||
}
|
||||
@ -187,8 +194,8 @@ object InventoryUtils {
|
||||
* Utility method for calling <tt>insertIntoInventory</tt> on an inventory
|
||||
* in the world.
|
||||
*/
|
||||
def insertIntoInventoryAt(stack: ItemStack, world: World, x: Int, y: Int, z: Int, side: ForgeDirection, limit: Int = 64): Boolean =
|
||||
inventoryAt(world, x, y, z).exists(insertIntoInventory(stack, _, side, limit))
|
||||
def insertIntoInventoryAt(stack: ItemStack, world: World, x: Int, y: Int, z: Int, side: ForgeDirection, limit: Int = 64, simulate: Boolean = false): Boolean =
|
||||
inventoryAt(world, x, y, z).exists(insertIntoInventory(stack, _, side, limit, simulate))
|
||||
|
||||
/**
|
||||
* Utility method for calling <tt>extractFromInventory</tt> on an inventory
|
||||
|
Loading…
x
Reference in New Issue
Block a user