getRange callback for navigation upgrade to query area the upgrade works in; extended API for block drivers to allow querying for item stacks, used in adapter block to only allow adding filter for supported blocks

This commit is contained in:
Florian Nücke 2013-12-28 21:23:31 +01:00
parent 4d1f568db2
commit aa682750d0
16 changed files with 104 additions and 60 deletions

View File

@ -32,7 +32,7 @@ object CraftingHandler extends ICraftingHandler {
}
if (craftedStack.isItemEqual(Items.upgradeNavigation.createItemStack())) {
Registry.driverFor(craftedStack) match {
Registry.itemDriverFor(craftedStack) match {
case Some(driver) =>
var oldMap = None: Option[ItemStack]
for (i <- 0 to inventory.getSizeInventory) {

View File

@ -4,7 +4,24 @@ import li.cil.oc.api.driver.Block;
import li.cil.oc.api.driver.Item;
public interface DriverAPI {
/**
* Registers a new driver for a block component.
* <p/>
* Whenever the neighboring blocks of an Adapter block change, it checks if
* there exists a driver for the changed block, and if it is configured to
* interface that block type connects it to the component network.
*
* @param driver the driver for a block component.
*/
void add(Block driver);
/**
* Registers a new driver for an item component.
* <p/>
* Item components can inserted into a computers component slots. They have
* to specify their type, to determine into which slots they can fit.
*
* @param driver the driver for an item component.
*/
void add(Item driver);
}

View File

@ -1,6 +1,7 @@
package li.cil.oc.api.driver;
import li.cil.oc.api.network.ManagedEnvironment;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
/**
@ -39,6 +40,21 @@ public interface Block {
*/
boolean worksWith(World world, int x, int y, int z);
/**
* Used to determine the block types this driver handles.
* <p/>
* This is used to determine whether there is a driver for the specified
* block type when an Adapter block is being configured, i.e. when the
* player tries to place an item into the adapter's GUI.
* <p/>
* Note that the passed item stacks are not necessarily item blocks, they
* can be anything at all.
*
* @param stack the item stack to check.
* @return <tt>true</tt> if the block is supported; <tt>false</tt> otherwise.
*/
boolean worksWith(ItemStack stack);
/**
* Create a new managed environment interfacing the specified block.
* <p/>

View File

@ -37,5 +37,5 @@
@cpw.mods.fml.common.API(
owner = "OpenComputers",
provides = "OpenComputersAPI",
apiVersion = "1.0.0")
apiVersion = "1.1.0")
package li.cil.oc.api;

View File

@ -28,7 +28,7 @@ class Adapter extends Environment with Inventory {
def neighborChanged() = if (node != null && node.network != null) {
for (d <- ForgeDirection.VALID_DIRECTIONS) {
val (x, y, z) = (this.x + d.offsetX, this.y + d.offsetY, this.z + d.offsetZ)
driver.Registry.driverFor(world, x, y, z) match {
driver.Registry.blockDriverFor(world, x, y, z) match {
case Some(newDriver) => blocks(d.ordinal()) match {
case Some((oldEnvironment, driver)) =>
if (newDriver != driver || !isBlockSupported(x, y, z)) {
@ -84,6 +84,11 @@ class Adapter extends Environment with Inventory {
override def readFromNBT(nbt: NBTTagCompound) {
super.readFromNBT(nbt)
items(0) match {
case Some(stack) if driver.Registry.blockDriverFor(stack).isEmpty => setInventorySlotContents(0, null)
case _ =>
}
val blocksNbt = nbt.getTagList(Settings.namespace + "adapter.blocks")
(0 until (blocksNbt.tagCount min blocksData.length)).
map(blocksNbt.tagAt).
@ -129,10 +134,7 @@ class Adapter extends Environment with Inventory {
override def getInventoryStackRequired = 0
def isItemValidForSlot(i: Int, stack: ItemStack) =
stack != null && stack.stackSize > 0 && (stack.getItem match {
case block: ItemBlock => true
case _ => false
})
stack != null && stack.stackSize > 0 && driver.Registry.blockDriverFor(stack).isDefined
override def onInventoryChanged() {
super.onInventoryChanged()

View File

@ -41,21 +41,21 @@ class Case(var tier: Int, isRemote: Boolean) extends Computer(isRemote) {
}
def isItemValidForSlot(slot: Int, stack: ItemStack) = tier match {
case 0 => (slot, Registry.driverFor(stack)) match {
case 0 => (slot, Registry.itemDriverFor(stack)) match {
case (_, None) => false // Invalid item.
case (0 | 1, Some(driver)) => driver.slot(stack) == Slot.Card
case (2, Some(driver)) => driver.slot(stack) == Slot.Memory
case (3, Some(driver)) => driver.slot(stack) == Slot.HardDiskDrive
case _ => false // Invalid slot.
}
case 1 => (slot, Registry.driverFor(stack)) match {
case 1 => (slot, Registry.itemDriverFor(stack)) match {
case (_, None) => false // Invalid item.
case (0 | 1, Some(driver)) => driver.slot(stack) == Slot.Card
case (2 | 3, Some(driver)) => driver.slot(stack) == Slot.Memory
case (4 | 5, Some(driver)) => driver.slot(stack) == Slot.HardDiskDrive
case _ => false // Invalid slot.
}
case 2 => (slot, Registry.driverFor(stack)) match {
case 2 => (slot, Registry.itemDriverFor(stack)) match {
case (_, None) => false // Invalid item.
case (0 | 1 | 2, Some(driver)) => driver.slot(stack) == Slot.Card
case (3 | 4, Some(driver)) => driver.slot(stack) == Slot.Memory

View File

@ -18,7 +18,7 @@ trait ComponentInventory extends Inventory with network.Environment { self: MCTi
// ----------------------------------------------------------------------- //
def installedMemory = items.foldLeft(0)((sum, stack) => sum + (stack match {
case Some(item) => Registry.driverFor(item) match {
case Some(item) => Registry.itemDriverFor(item) match {
case Some(driver: driver.Memory) => driver.amount(item)
case _ => 0
}
@ -33,7 +33,7 @@ trait ComponentInventory extends Inventory with network.Environment { self: MCTi
for ((stack, slot) <- items.zipWithIndex collect {
case (Some(stack), slot) if slot >= 0 && slot < components.length => (stack, slot)
} if components(slot).isEmpty && isComponentSlot(slot)) {
components(slot) = Registry.driverFor(stack) match {
components(slot) = Registry.itemDriverFor(stack) match {
case Some(driver) =>
Option(driver.createEnvironment(stack, this)) match {
case Some(component) =>
@ -72,7 +72,7 @@ trait ComponentInventory extends Inventory with network.Environment { self: MCTi
case (stack, slot) => components(slot) match {
case Some(environment) =>
// We're guaranteed to have a driver for entries.
environment.save(dataTag(Registry.driverFor(stack).get, stack))
environment.save(dataTag(Registry.itemDriverFor(stack).get, stack))
case _ => // Nothing special to save.
}
}
@ -84,7 +84,7 @@ trait ComponentInventory extends Inventory with network.Environment { self: MCTi
def getInventoryStackLimit = 1
override protected def onItemAdded(slot: Int, stack: ItemStack) = if (isServer && isComponentSlot(slot)) {
Registry.driverFor(stack) match {
Registry.itemDriverFor(stack) match {
case Some(driver) => Option(driver.createEnvironment(stack, this)) match {
case Some(component) => this.synchronized {
components(slot) = Some(component)
@ -113,7 +113,7 @@ trait ComponentInventory extends Inventory with network.Environment { self: MCTi
components(slot) = None
updatingComponents -= component
component.node.remove()
Registry.driverFor(stack).foreach(driver =>
Registry.itemDriverFor(stack).foreach(driver =>
component.save(dataTag(driver, stack)))
}
case _ => // Nothing to do.

View File

@ -28,7 +28,7 @@ class DiskDrive extends Environment with ComponentInventory with Rotatable with
def getSizeInventory = 1
def isItemValidForSlot(slot: Int, stack: ItemStack) = (slot, Registry.driverFor(stack)) match {
def isItemValidForSlot(slot: Int, stack: ItemStack) = (slot, Registry.itemDriverFor(stack)) match {
case (0, Some(driver)) => driver.slot(stack) == Slot.Disk
case _ => false
}

View File

@ -43,7 +43,7 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w
case Some(environment) =>
val stack = getStackInSlot(3)
// We're guaranteed to have a driver for entries.
environment.save(dataTag(Registry.driverFor(stack).get, stack))
environment.save(dataTag(Registry.itemDriverFor(stack).get, stack))
ServerPacketSender.sendRobotEquippedUpgradeChange(this, stack)
case _ =>
}
@ -383,7 +383,7 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w
case Some(environment) =>
val stack = getStackInSlot(3)
// We're guaranteed to have a driver for entries.
environment.save(dataTag(Registry.driverFor(stack).get, stack))
environment.save(dataTag(Registry.itemDriverFor(stack).get, stack))
case _ => // See onConnect()
}
nbt.setNewCompoundTag("upgrade", getStackInSlot(3).writeToNBT)
@ -516,7 +516,7 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w
case _ => false
}
def isItemValidForSlot(slot: Int, stack: ItemStack) = (slot, Registry.driverFor(stack)) match {
def isItemValidForSlot(slot: Int, stack: ItemStack) = (slot, Registry.itemDriverFor(stack)) match {
case (0, _) => true // Allow anything in the tool slot.
case (1, Some(driver)) => driver.slot(stack) == Slot.Card
case (2, Some(driver)) => driver.slot(stack) == Slot.Disk

View File

@ -30,4 +30,9 @@ class UpgradeNavigation(val owner: MCTileEntity, val xCenter: Int, val zCenter:
def getFacing(context: RobotContext, args: Arguments): Array[AnyRef] = {
result(RotationHelper.fromYaw(context.player().rotationYaw).ordinal())
}
@LuaCallback("getRange")
def getRange(context: RobotContext, args: Arguments): Array[AnyRef] = {
result(size / 2)
}
}

View File

@ -21,65 +21,36 @@ import scala.collection.mutable.ArrayBuffer
* the computer, but may also provide context-free functions.
*/
private[oc] object Registry extends api.detail.DriverAPI {
/** The list of registered block drivers. */
private val blocks = ArrayBuffer.empty[api.driver.Block]
/** The list of registered item drivers. */
private val items = ArrayBuffer.empty[api.driver.Item]
/** Used to keep track of whether we're past the init phase. */
var locked = false
/**
* Registers a new driver for a block component.
*
* Whenever the neighboring blocks of a computer change, it checks if there
* exists a driver for the changed block, and if so installs it.
*
* @param driver the driver for that block type.
*/
def add(driver: api.driver.Block) {
if (locked) throw new IllegalStateException("Please register all drivers in the init phase.")
if (!blocks.contains(driver)) blocks += driver
}
/**
* Registers a new driver for an item component.
*
* Item components can inserted into a computers component slots. They have
* to specify their type, to determine into which slots they can fit.
*
* @param driver the driver for that item type.
*/
def add(driver: api.driver.Item) {
if (locked) throw new IllegalStateException("Please register all drivers in the init phase.")
if (!blocks.contains(driver)) items += driver
}
/**
* Used when a new block is placed next to a computer to see if we have a
* driver for it. If we have one, we'll return it.
*
* @param world the world in which the block to check lives.
* @param x the X coordinate of the block to check.
* @param y the Y coordinate of the block to check.
* @param z the Z coordinate of the block to check.
* @return the driver for that block if we have one.
*/
def driverFor(world: World, x: Int, y: Int, z: Int) =
def blockDriverFor(world: World, x: Int, y: Int, z: Int) =
blocks.find(_.worksWith(world, x, y, z)) match {
case None => None
case Some(driver) => Some(driver)
}
/**
* Used when an item component is added to a computer to see if we have a
* driver for it. If we have one, we'll return it.
*
* @param stack the type of item to check for a driver for.
* @return the driver for that item type if we have one.
*/
def driverFor(stack: ItemStack) =
def blockDriverFor(stack: ItemStack) =
blocks.find(_.worksWith(stack)) match {
case None => None
case Some(driver) => Some(driver)
}
def itemDriverFor(stack: ItemStack) =
if (stack != null) items.find(_.worksWith(stack)) match {
case None => None
case Some(driver) => Some(driver)

View File

@ -4,6 +4,8 @@ import li.cil.oc.api.driver
import li.cil.oc.server.component
import li.cil.oc.util.mods.RedstoneInMotion
import net.minecraft.world.World
import net.minecraft.block.Block
import net.minecraft.item.ItemStack
object Carriage extends driver.Block {
def worksWith(world: World, x: Int, y: Int, z: Int) =
@ -12,6 +14,8 @@ object Carriage extends driver.Block {
case _ => false
}
def worksWith(stack: ItemStack) = RedstoneInMotion.isCarriageController(stack)
def createEnvironment(world: World, x: Int, y: Int, z: Int) =
world.getBlockTileEntity(x, y, z) match {
case entity if RedstoneInMotion.isCarriageController(entity) => new component.Carriage(entity)

View File

@ -3,6 +3,7 @@ package li.cil.oc.server.driver.block
import li.cil.oc.api.driver
import li.cil.oc.server.component
import net.minecraft.block.Block
import net.minecraft.item.{ItemBlock, ItemStack}
import net.minecraft.tileentity.TileEntityCommandBlock
import net.minecraft.world.World
@ -10,6 +11,11 @@ object CommandBlock extends driver.Block {
def worksWith(world: World, x: Int, y: Int, z: Int) =
world.getBlockId(x, y, z) == Block.commandBlock.blockID
def worksWith(stack: ItemStack) = stack != null && (stack.getItem match {
case itemBlock: ItemBlock => itemBlock.getBlockID == Block.commandBlock.blockID
case _ => false
})
def createEnvironment(world: World, x: Int, y: Int, z: Int) =
world.getBlockTileEntity(x, y, z) match {
case block: TileEntityCommandBlock => new component.CommandBlock(block)

View File

@ -3,6 +3,7 @@ package li.cil.oc.server.driver.block
import li.cil.oc.api.driver
import li.cil.oc.server.component
import net.minecraft.block.Block
import net.minecraft.item.{ItemBlock, ItemStack}
import net.minecraft.tileentity.TileEntityNote
import net.minecraft.world.World
@ -10,6 +11,11 @@ object NoteBlock extends driver.Block {
def worksWith(world: World, x: Int, y: Int, z: Int) =
world.getBlockId(x, y, z) == Block.music.blockID
def worksWith(stack: ItemStack) = stack != null && (stack.getItem match {
case itemBlock: ItemBlock => itemBlock.getBlockID == Block.music.blockID
case _ => false
})
def createEnvironment(world: World, x: Int, y: Int, z: Int) =
world.getBlockTileEntity(x, y, z) match {
case block: TileEntityNote => new component.NoteBlock(block)

View File

@ -11,7 +11,7 @@ object UpgradeNavigation extends Item {
override def worksWith(stack: ItemStack) = isOneOf(stack, Items.upgradeNavigation)
override def createEnvironment(stack: ItemStack, container: MCTileEntity) = {
val nbt = Registry.driverFor(stack) match {
val nbt = Registry.itemDriverFor(stack) match {
case Some(driver) => driver.dataTag(stack)
case _ => null
}

View File

@ -1,14 +1,17 @@
package li.cil.oc.util.mods
import java.lang.reflect.InvocationTargetException
import net.minecraft.block.Block
import net.minecraft.item.{ItemBlock, ItemStack}
import scala.language.existentials
object RedstoneInMotion {
private val (controller, setup, move, motionException, obstructionException, obstructionX, obstructionY, obstructionZ, directions) = try {
private val (controller, setup, move, motionException, obstructionException, obstructionX, obstructionY, obstructionZ, directions, blocks) = try {
val controller = Class.forName("JAKJ.RedstoneInMotion.CarriageControllerEntity")
val motionException = Class.forName("JAKJ.RedstoneInMotion.CarriageMotionException")
val obstructionException = Class.forName("JAKJ.RedstoneInMotion.CarriageObstructionException")
val directions = Class.forName("JAKJ.RedstoneInMotion.Directions").getEnumConstants
val blocks = Class.forName("JAKJ.RedstoneInMotion.Blocks")
val methods = controller.getDeclaredMethods
val setup = methods.find(_.getName == "SetupMotion").get
@ -18,10 +21,10 @@ object RedstoneInMotion {
val obstructionY = obstructionException.getDeclaredField("Y")
val obstructionZ = obstructionException.getDeclaredField("Z")
(Option(controller), setup, move, motionException, obstructionException, obstructionX, obstructionY, obstructionZ, directions)
(Option(controller), setup, move, motionException, obstructionException, obstructionX, obstructionY, obstructionZ, directions, blocks)
}
catch {
case _: Throwable => (None, null, null, null, null, null, null, null, null)
case _: Throwable => (None, null, null, null, null, null, null, null, null, null)
}
def available = controller.isDefined
@ -31,6 +34,13 @@ object RedstoneInMotion {
case _ => false
}
def isCarriageController(stack: ItemStack) = available && stack != null && (stack.getItem match {
case itemBlock: ItemBlock =>
val block = Block.blocksList(itemBlock.getBlockID)
block != null && driveBlock != null && block.blockID == driveBlock.blockID && itemBlock.getMetadata(stack.getItemDamage) == 2
case _ => false
})
def move(controller: AnyRef, direction: Int, simulating: Boolean, anchored: Boolean): (Boolean, Array[AnyRef]) = {
if (!isCarriageController(controller))
throw new IllegalArgumentException("Not a carriage controller.")
@ -55,4 +65,11 @@ object RedstoneInMotion {
(false, Array(e.getMessage: AnyRef))
}
}
private def driveBlock = try {
blocks.getField("CarriageDrive").get(null).asInstanceOf[Block]
}
catch {
case _: Throwable => null
}
}