diff --git a/li/cil/oc/CraftingHandler.scala b/li/cil/oc/CraftingHandler.scala index b96960f99..90d8f7cbf 100644 --- a/li/cil/oc/CraftingHandler.scala +++ b/li/cil/oc/CraftingHandler.scala @@ -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) { diff --git a/li/cil/oc/api/detail/DriverAPI.java b/li/cil/oc/api/detail/DriverAPI.java index f0775cc1c..24fb99667 100644 --- a/li/cil/oc/api/detail/DriverAPI.java +++ b/li/cil/oc/api/detail/DriverAPI.java @@ -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. + *
+ * 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. + * + * 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); } diff --git a/li/cil/oc/api/driver/Block.java b/li/cil/oc/api/driver/Block.java index 895a629bf..d59b4198c 100644 --- a/li/cil/oc/api/driver/Block.java +++ b/li/cil/oc/api/driver/Block.java @@ -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. + * + * 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. + * + * 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 true if the block is supported; false otherwise. + */ + boolean worksWith(ItemStack stack); + /** * Create a new managed environment interfacing the specified block. * diff --git a/li/cil/oc/api/package-info.java b/li/cil/oc/api/package-info.java index d44416266..f89f581fd 100644 --- a/li/cil/oc/api/package-info.java +++ b/li/cil/oc/api/package-info.java @@ -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; \ No newline at end of file diff --git a/li/cil/oc/common/tileentity/Adapter.scala b/li/cil/oc/common/tileentity/Adapter.scala index 8a342e45c..56910ca07 100644 --- a/li/cil/oc/common/tileentity/Adapter.scala +++ b/li/cil/oc/common/tileentity/Adapter.scala @@ -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() diff --git a/li/cil/oc/common/tileentity/Case.scala b/li/cil/oc/common/tileentity/Case.scala index 8646518a7..3f447cfa0 100644 --- a/li/cil/oc/common/tileentity/Case.scala +++ b/li/cil/oc/common/tileentity/Case.scala @@ -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 diff --git a/li/cil/oc/common/tileentity/ComponentInventory.scala b/li/cil/oc/common/tileentity/ComponentInventory.scala index 1a957b3ca..d46bdcac5 100644 --- a/li/cil/oc/common/tileentity/ComponentInventory.scala +++ b/li/cil/oc/common/tileentity/ComponentInventory.scala @@ -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. diff --git a/li/cil/oc/common/tileentity/DiskDrive.scala b/li/cil/oc/common/tileentity/DiskDrive.scala index 2c4e05a09..bc1c30ccc 100644 --- a/li/cil/oc/common/tileentity/DiskDrive.scala +++ b/li/cil/oc/common/tileentity/DiskDrive.scala @@ -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 } diff --git a/li/cil/oc/common/tileentity/Robot.scala b/li/cil/oc/common/tileentity/Robot.scala index 88544b646..6edd01ebe 100644 --- a/li/cil/oc/common/tileentity/Robot.scala +++ b/li/cil/oc/common/tileentity/Robot.scala @@ -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 diff --git a/li/cil/oc/server/component/UpgradeNavigation.scala b/li/cil/oc/server/component/UpgradeNavigation.scala index bc9bb1820..d390a1e92 100644 --- a/li/cil/oc/server/component/UpgradeNavigation.scala +++ b/li/cil/oc/server/component/UpgradeNavigation.scala @@ -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) + } } diff --git a/li/cil/oc/server/driver/Registry.scala b/li/cil/oc/server/driver/Registry.scala index 3bff9c0b3..f0426d0ad 100644 --- a/li/cil/oc/server/driver/Registry.scala +++ b/li/cil/oc/server/driver/Registry.scala @@ -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) diff --git a/li/cil/oc/server/driver/block/Carriage.scala b/li/cil/oc/server/driver/block/Carriage.scala index bdc195438..d2675565b 100644 --- a/li/cil/oc/server/driver/block/Carriage.scala +++ b/li/cil/oc/server/driver/block/Carriage.scala @@ -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) diff --git a/li/cil/oc/server/driver/block/CommandBlock.scala b/li/cil/oc/server/driver/block/CommandBlock.scala index 6d6049b10..d802382df 100644 --- a/li/cil/oc/server/driver/block/CommandBlock.scala +++ b/li/cil/oc/server/driver/block/CommandBlock.scala @@ -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) diff --git a/li/cil/oc/server/driver/block/NoteBlock.scala b/li/cil/oc/server/driver/block/NoteBlock.scala index 3f8606f0d..6ec9bfbec 100644 --- a/li/cil/oc/server/driver/block/NoteBlock.scala +++ b/li/cil/oc/server/driver/block/NoteBlock.scala @@ -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) diff --git a/li/cil/oc/server/driver/item/UpgradeNavigation.scala b/li/cil/oc/server/driver/item/UpgradeNavigation.scala index 2cc558c4a..5b01e1666 100644 --- a/li/cil/oc/server/driver/item/UpgradeNavigation.scala +++ b/li/cil/oc/server/driver/item/UpgradeNavigation.scala @@ -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 } diff --git a/li/cil/oc/util/mods/RedstoneInMotion.scala b/li/cil/oc/util/mods/RedstoneInMotion.scala index c2fd94f04..1625098d3 100644 --- a/li/cil/oc/util/mods/RedstoneInMotion.scala +++ b/li/cil/oc/util/mods/RedstoneInMotion.scala @@ -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 + } }