diff --git a/src/main/java/li/cil/oc/api/Driver.java b/src/main/java/li/cil/oc/api/Driver.java index 6b1398641..7051b20e6 100644 --- a/src/main/java/li/cil/oc/api/Driver.java +++ b/src/main/java/li/cil/oc/api/Driver.java @@ -4,6 +4,8 @@ import li.cil.oc.api.detail.DriverAPI; import li.cil.oc.api.driver.Block; import li.cil.oc.api.driver.Converter; import li.cil.oc.api.driver.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; /** * This API allows registering new drivers with the mod. @@ -68,6 +70,43 @@ public final class Driver { instance.add(converter); } + /** + * Looks up a driver for the block at the specified position in the + * specified world. + *
+ * Note that several drivers for a single block can exist. Because of this + * block drivers are always encapsulated in a 'compound' driver, which is + * what will be returned here. In other words, you should will not + * get actual instances of drivers registered via {@link #add(li.cil.oc.api.driver.Block)}. + * + * @param world the world containing the block. + * @param x the X coordinate of the block. + * @param y the Y coordinate of the block. + * @param z the Z coordinate of the block. + * @return a driver for the block, or null if there is none. + */ + public static Block driverFor(World world, int x, int y, int z) { + if (instance != null) + return instance.driverFor(world, x, y, z); + return null; + } + + /** + * Looks up a driver for the specified item stack. + * + * Note that unlike for blocks, there can always only be one item driver + * per item. If there are multiple ones, the first one that was registered + * will be used. + * + * @param stack the item stack to get a driver for. + * @return a driver for the item, or null if there is none. + */ + public static Item driverFor(ItemStack stack) { + if (instance != null) + return instance.driverFor(stack); + return null; + } + // ----------------------------------------------------------------------- // private Driver() { diff --git a/src/main/java/li/cil/oc/api/detail/DriverAPI.java b/src/main/java/li/cil/oc/api/detail/DriverAPI.java index 3d4549c7b..defca3433 100644 --- a/src/main/java/li/cil/oc/api/detail/DriverAPI.java +++ b/src/main/java/li/cil/oc/api/detail/DriverAPI.java @@ -3,6 +3,8 @@ package li.cil.oc.api.detail; import li.cil.oc.api.driver.Block; import li.cil.oc.api.driver.Converter; import li.cil.oc.api.driver.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; public interface DriverAPI { /** @@ -44,4 +46,33 @@ public interface DriverAPI { * @param converter the converter to register. */ void add(Converter converter); + + /** + * Looks up a driver for the block at the specified position in the + * specified world. + * + * Note that several drivers for a single block can exist. Because of this + * block drivers are always encapsulated in a 'compound' driver, which is + * what will be returned here. In other words, you should will not + * get actual instances of drivers registered via {@link #add(li.cil.oc.api.driver.Block)}. + * + * @param world the world containing the block. + * @param x the X coordinate of the block. + * @param y the Y coordinate of the block. + * @param z the Z coordinate of the block. + * @return a driver for the block, or null if there is none. + */ + Block driverFor(World world, int x, int y, int z); + + /** + * Looks up a driver for the specified item stack. + * + * Note that unlike for blocks, there can always only be one item driver + * per item. If there are multiple ones, the first one that was registered + * will be used. + * + * @param stack the item stack to get a driver for. + * @return a driver for the item, or null if there is none. + */ + Item driverFor(ItemStack stack); } diff --git a/src/main/scala/li/cil/oc/CraftingHandler.scala b/src/main/scala/li/cil/oc/CraftingHandler.scala index d6448bc24..96d21160b 100644 --- a/src/main/scala/li/cil/oc/CraftingHandler.scala +++ b/src/main/scala/li/cil/oc/CraftingHandler.scala @@ -1,7 +1,6 @@ package li.cil.oc import cpw.mods.fml.common.ICraftingHandler -import li.cil.oc.server.driver.Registry import net.minecraft.entity.player.EntityPlayer import net.minecraft.inventory.IInventory import net.minecraft.item.{Item, ItemStack} @@ -35,21 +34,18 @@ object CraftingHandler extends ICraftingHandler { } if (api.Items.get(craftedStack) == navigationUpgrade) { - Registry.itemDriverFor(craftedStack) match { - case Some(driver) => - for (i <- 0 until inventory.getSizeInventory) { - val stack = inventory.getStackInSlot(i) - if (stack != null && api.Items.get(stack) == navigationUpgrade) { - // Restore the map currently used in the upgrade. - val nbt = driver.dataTag(stack) - val map = ItemStack.loadItemStackFromNBT(nbt.getCompoundTag(Settings.namespace + "map")) - if (!player.inventory.addItemStackToInventory(map)) { - player.dropPlayerItemWithRandomChoice(map, false) - } + Option(api.Driver.driverFor(craftedStack)).foreach(driver => + for (i <- 0 until inventory.getSizeInventory) { + val stack = inventory.getStackInSlot(i) + if (stack != null && api.Items.get(stack) == navigationUpgrade) { + // Restore the map currently used in the upgrade. + val nbt = driver.dataTag(stack) + val map = ItemStack.loadItemStackFromNBT(nbt.getCompoundTag(Settings.namespace + "map")) + if (!player.inventory.addItemStackToInventory(map)) { + player.dropPlayerItemWithRandomChoice(map, false) } } - case _ => - } + }) } } diff --git a/src/main/scala/li/cil/oc/common/inventory/ComponentInventory.scala b/src/main/scala/li/cil/oc/common/inventory/ComponentInventory.scala index bd82f7081..c2dfcb09e 100644 --- a/src/main/scala/li/cil/oc/common/inventory/ComponentInventory.scala +++ b/src/main/scala/li/cil/oc/common/inventory/ComponentInventory.scala @@ -2,10 +2,10 @@ package li.cil.oc.common.inventory import java.util.logging.Level import li.cil.oc.OpenComputers +import li.cil.oc.api.Driver import li.cil.oc.api.driver.{Item => ItemDriver} import li.cil.oc.api.network import li.cil.oc.api.network.{Node, ManagedEnvironment} -import li.cil.oc.server.driver.Registry import li.cil.oc.server.driver.item.Item import net.minecraft.item.ItemStack import net.minecraft.nbt.{NBTBase, NBTTagCompound} @@ -37,21 +37,22 @@ trait ComponentInventory extends Inventory with network.Environment { 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.itemDriverFor(stack) match { + components(slot) = Option(Driver.driverFor(stack)) match { case Some(driver) => - Option(driver.createEnvironment(stack, componentContainer)) match { - case Some(component) => - try { - component.load(dataTag(driver, stack)) - } catch { - case e: Throwable => OpenComputers.log.log(Level.WARNING, "An item component of type '%s' (provided by driver '%s') threw an error while loading.".format(component.getClass.getName, driver.getClass.getName), e) - } - if (component.canUpdate) { - assert(!updatingComponents.contains(component)) - updatingComponents += component - } - Some(component) - case _ => None + Option(driver.createEnvironment(stack, componentContainer)) match { + case Some(component) => + try { + component.load(dataTag(driver, stack)) + } + catch { + case e: Throwable => OpenComputers.log.log(Level.WARNING, "An item component of type '%s' (provided by driver '%s') threw an error while loading.".format(component.getClass.getName, driver.getClass.getName), e) + } + if (component.canUpdate) { + assert(!updatingComponents.contains(component)) + updatingComponents += component + } + Some(component) + case _ => None } case _ => None } @@ -76,7 +77,7 @@ trait ComponentInventory extends Inventory with network.Environment { case (stack, slot) => components(slot) match { case Some(component) => // We're guaranteed to have a driver for entries. - save(component, Registry.itemDriverFor(stack).get, stack) + save(component, Driver.driverFor(stack), stack) case _ => // Nothing special to save. } } @@ -88,8 +89,8 @@ trait ComponentInventory extends Inventory with network.Environment { override def getInventoryStackLimit = 1 override protected def onItemAdded(slot: Int, stack: ItemStack) = if (isComponentSlot(slot)) { - Registry.itemDriverFor(stack) match { - case Some(driver) => Option(driver.createEnvironment(stack, componentContainer)) match { + Option(Driver.driverFor(stack)).foreach(driver => + Option(driver.createEnvironment(stack, componentContainer)) match { case Some(component) => this.synchronized { components(slot) = Some(component) try { @@ -105,9 +106,7 @@ trait ComponentInventory extends Inventory with network.Environment { save(component, driver, stack) } case _ => // No environment (e.g. RAM). - } - case _ => // No driver. - } + }) } override protected def onItemRemoved(slot: Int, stack: ItemStack) { @@ -121,7 +120,7 @@ trait ComponentInventory extends Inventory with network.Environment { components(slot) = None updatingComponents -= component component.node.remove() - Registry.itemDriverFor(stack).foreach(driver => save(component, driver, stack)) + Option(Driver.driverFor(stack)).foreach(save(component, _, stack)) } case _ => // Nothing to do. } diff --git a/src/main/scala/li/cil/oc/common/inventory/ServerInventory.scala b/src/main/scala/li/cil/oc/common/inventory/ServerInventory.scala index e09cdce5d..7cc911067 100644 --- a/src/main/scala/li/cil/oc/common/inventory/ServerInventory.scala +++ b/src/main/scala/li/cil/oc/common/inventory/ServerInventory.scala @@ -1,10 +1,10 @@ package li.cil.oc.common.inventory import li.cil.oc.Settings -import li.cil.oc.server.driver.Registry +import li.cil.oc.api.Driver +import li.cil.oc.common.InventorySlots import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack -import li.cil.oc.common.InventorySlots trait ServerInventory extends ItemStackInventory { def tier: Int @@ -22,10 +22,8 @@ trait ServerInventory extends ItemStackInventory { override def isUseableByPlayer(player: EntityPlayer) = false override def isItemValidForSlot(slot: Int, stack: ItemStack) = - Registry.itemDriverFor(stack) match { - case Some(driver) => - val provided = InventorySlots.server(tier)(slot) - driver.slot(stack) == provided.slot && driver.tier(stack) <= provided.tier - case _ => false // Invalid item. - } + Option(Driver.driverFor(stack)).fold(false)(driver => { + val provided = InventorySlots.server(tier)(slot) + driver.slot(stack) == provided.slot && driver.tier(stack) <= provided.tier + }) } diff --git a/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala b/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala index 9bcd03286..48dd2f469 100644 --- a/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala +++ b/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala @@ -1,12 +1,11 @@ package li.cil.oc.common.recipe -import net.minecraft.item.{Item, ItemStack} -import li.cil.oc.{Settings, api} -import li.cil.oc.server.driver.Registry -import li.cil.oc.util.ExtendedNBT._ import cpw.mods.fml.common.FMLCommonHandler import java.util.UUID +import li.cil.oc.{Settings, api} +import li.cil.oc.util.ExtendedNBT._ import net.minecraft.inventory.InventoryCrafting +import net.minecraft.item.{Item, ItemStack} object ExtendedRecipe { private lazy val navigationUpgrade = api.Items.get("navigationUpgrade") @@ -14,27 +13,22 @@ object ExtendedRecipe { def addNBTToResult(craftedStack: ItemStack, inventory: InventoryCrafting) = { if (api.Items.get(craftedStack) == navigationUpgrade) { - Registry.itemDriverFor(craftedStack) match { - case Some(driver) => - for (i <- 0 until inventory.getSizeInventory) { - val stack = inventory.getStackInSlot(i) - if (stack != null && stack.getItem == Item.map) { - // Store information of the map used for crafting in the result. - val nbt = driver.dataTag(craftedStack) - nbt.setNewCompoundTag(Settings.namespace + "map", stack.writeToNBT) - } + Option(api.Driver.driverFor(craftedStack)).foreach(driver => + for (i <- 0 until inventory.getSizeInventory) { + val stack = inventory.getStackInSlot(i) + if (stack != null && stack.getItem == Item.map) { + // Store information of the map used for crafting in the result. + val nbt = driver.dataTag(craftedStack) + nbt.setNewCompoundTag(Settings.namespace + "map", stack.writeToNBT) } - case _ => - } + }) } if (api.Items.get(craftedStack) == linkedCard && FMLCommonHandler.instance.getEffectiveSide.isServer) { - Registry.itemDriverFor(craftedStack) match { - case Some(driver) => - val nbt = driver.dataTag(craftedStack) - nbt.setString(Settings.namespace + "tunnel", UUID.randomUUID().toString) - case _ => - } + Option(api.Driver.driverFor(craftedStack)).foreach(driver => { + val nbt = driver.dataTag(craftedStack) + nbt.setString(Settings.namespace + "tunnel", UUID.randomUUID().toString) + }) } craftedStack diff --git a/src/main/scala/li/cil/oc/common/tileentity/Adapter.scala b/src/main/scala/li/cil/oc/common/tileentity/Adapter.scala index 129c25af7..1023d7779 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Adapter.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Adapter.scala @@ -47,7 +47,7 @@ class Adapter extends traits.Environment with Analyzable { // but the only 'downside' is that it can't be used to manipulate // inventories, which I actually consider a plus :P case _ => - driver.Registry.blockDriverFor(world, x, y, z) match { + Option(api.Driver.driverFor(world, x, y, z)) match { case Some(newDriver) => blocks(d.ordinal()) match { case Some((oldEnvironment, driver)) => if (newDriver != driver) { diff --git a/src/main/scala/li/cil/oc/common/tileentity/Case.scala b/src/main/scala/li/cil/oc/common/tileentity/Case.scala index 0fda556e1..b6d164d06 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Case.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Case.scala @@ -1,10 +1,9 @@ package li.cil.oc.common.tileentity import cpw.mods.fml.relauncher.{SideOnly, Side} -import li.cil.oc.api.driver +import li.cil.oc.api.{Driver, driver} import li.cil.oc.api.driver.Slot import li.cil.oc.api.network.Connector -import li.cil.oc.server.driver.Registry import li.cil.oc.Settings import li.cil.oc.util.Color import net.minecraft.entity.player.EntityPlayer @@ -29,7 +28,7 @@ class Case(var tier: Int, val isRemote: Boolean) extends traits.PowerAcceptor wi def recomputeMaxComponents() { maxComponents = items.foldLeft(0)((sum, stack) => sum + (stack match { - case Some(item) => Registry.itemDriverFor(item) match { + case Some(item) => Option(Driver.driverFor(item)) match { case Some(driver: driver.Processor) => driver.supportedComponents(item) case _ => 0 } @@ -38,7 +37,7 @@ class Case(var tier: Int, val isRemote: Boolean) extends traits.PowerAcceptor wi } override def installedMemory = items.foldLeft(0)((sum, stack) => sum + (stack match { - case Some(item) => Registry.itemDriverFor(item) match { + case Some(item) => Option(Driver.driverFor(item)) match { case Some(driver: driver.Memory) => driver.amount(item) case _ => 0 } @@ -46,7 +45,7 @@ class Case(var tier: Int, val isRemote: Boolean) extends traits.PowerAcceptor wi })) def hasCPU = items.exists { - case Some(stack) => Registry.itemDriverFor(stack) match { + case Some(stack) => Option(Driver.driverFor(stack)) match { case Some(driver) => driver.slot(stack) == Slot.Processor case _ => false } @@ -102,10 +101,8 @@ class Case(var tier: Int, val isRemote: Boolean) extends traits.PowerAcceptor wi } override def isItemValidForSlot(slot: Int, stack: ItemStack) = - Registry.itemDriverFor(stack) match { - case Some(driver) => - val provided = InventorySlots.computer(tier)(slot) - driver.slot(stack) == provided.slot && driver.tier(stack) <= provided.tier - case _ => false // Invalid item. - } + Option(Driver.driverFor(stack)).fold(false)(driver => { + val provided = InventorySlots.computer(tier)(slot) + driver.slot(stack) == provided.slot && driver.tier(stack) <= provided.tier + }) } \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/common/tileentity/DiskDrive.scala b/src/main/scala/li/cil/oc/common/tileentity/DiskDrive.scala index 092fddd2b..3277253f1 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/DiskDrive.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/DiskDrive.scala @@ -1,9 +1,9 @@ package li.cil.oc.common.tileentity +import li.cil.oc.api.Driver import li.cil.oc.api.driver.Slot import li.cil.oc.api.network.{Analyzable, Component, Visibility} import li.cil.oc.common.Sound -import li.cil.oc.server.driver.Registry import li.cil.oc.{api, Settings} import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack @@ -27,7 +27,7 @@ class DiskDrive extends traits.Environment with traits.ComponentInventory with t override def getSizeInventory = 1 - override def isItemValidForSlot(slot: Int, stack: ItemStack) = (slot, Registry.itemDriverFor(stack)) match { + override def isItemValidForSlot(slot: Int, stack: ItemStack) = (slot, Option(Driver.driverFor(stack))) match { case (0, Some(driver)) => driver.slot(stack) == Slot.Disk case _ => false } diff --git a/src/main/scala/li/cil/oc/common/tileentity/Robot.scala b/src/main/scala/li/cil/oc/common/tileentity/Robot.scala index 8c24e3b4c..99a717fcb 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Robot.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Robot.scala @@ -3,12 +3,12 @@ package li.cil.oc.common.tileentity import cpw.mods.fml.relauncher.{SideOnly, Side} import java.util.logging.Level import li.cil.oc._ +import li.cil.oc.api.Driver import li.cil.oc.api.driver.Slot import li.cil.oc.api.network._ import li.cil.oc.common.block.Delegator import li.cil.oc.server.component.GraphicsCard import li.cil.oc.server.component.robot -import li.cil.oc.server.driver.Registry import li.cil.oc.server.{PacketSender => ServerPacketSender, driver, component} import li.cil.oc.util.ExtendedNBT._ import net.minecraft.block.{BlockFlowing, Block} @@ -61,7 +61,7 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.TextBuffe case Some(environment) => val stack = getStackInSlot(3) // We're guaranteed to have a driver for entries. - environment.save(dataTag(Registry.itemDriverFor(stack).get, stack)) + environment.save(dataTag(Driver.driverFor(stack), stack)) ServerPacketSender.sendRobotEquippedUpgradeChange(this, stack) case _ => } @@ -452,7 +452,7 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.TextBuffe case Some(environment) => val stack = getStackInSlot(3) // We're guaranteed to have a driver for entries. - environment.save(dataTag(Registry.itemDriverFor(stack).get, stack)) + environment.save(dataTag(Driver.driverFor(stack), stack)) case _ => // See onConnect() } nbt.setNewCompoundTag("upgrade", getStackInSlot(3).writeToNBT) @@ -557,7 +557,7 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.TextBuffe // ----------------------------------------------------------------------- // override def installedMemory = Settings.get.ramSizes(1) * 1024 + (items(3) match { - case Some(stack) => Registry.itemDriverFor(stack) match { + case Some(stack) => Option(Driver.driverFor(stack)) match { case Some(driver: api.driver.Memory) => driver.amount(stack) case _ => 0 } @@ -601,7 +601,7 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.TextBuffe case _ => false } - override def isItemValidForSlot(slot: Int, stack: ItemStack) = (slot, Registry.itemDriverFor(stack)) match { + override def isItemValidForSlot(slot: Int, stack: ItemStack) = (slot, Option(Driver.driverFor(stack))) match { case (0, _) => true // Allow anything in the tool slot. case (1, Some(driver)) => driver.slot(stack) == Slot.Card && driver.tier(stack) < 2 case (2, Some(driver)) => driver.slot(stack) == Slot.Disk diff --git a/src/main/scala/li/cil/oc/server/component/Server.scala b/src/main/scala/li/cil/oc/server/component/Server.scala index b674830fd..d3c89839e 100644 --- a/src/main/scala/li/cil/oc/server/component/Server.scala +++ b/src/main/scala/li/cil/oc/server/component/Server.scala @@ -4,7 +4,7 @@ import li.cil.oc.Items import li.cil.oc.api.driver.Slot import li.cil.oc.api.machine.Owner import li.cil.oc.api.network.{Message, Node} -import li.cil.oc.api.{Machine, driver} +import li.cil.oc.api.{Driver, Machine, driver} import li.cil.oc.common.inventory.ComponentInventory import li.cil.oc.common.inventory.ServerInventory import li.cil.oc.common.item @@ -45,7 +45,7 @@ class Server(val rack: tileentity.Rack, val number: Int) extends Owner { // ----------------------------------------------------------------------- // override def installedMemory = inventory.items.foldLeft(0)((sum, stack) => sum + (stack match { - case Some(item) => Registry.itemDriverFor(item) match { + case Some(item) => Option(Driver.driverFor(item)) match { case Some(driver: driver.Memory) => driver.amount(item) case _ => 0 } @@ -53,7 +53,7 @@ class Server(val rack: tileentity.Rack, val number: Int) extends Owner { })) lazy val maxComponents = inventory.items.foldLeft(0)((sum, stack) => sum + (stack match { - case Some(item) => Registry.itemDriverFor(item) match { + case Some(item) => Option(Driver.driverFor(item)) match { case Some(driver: driver.Processor) => driver.supportedComponents(item) case _ => 0 } @@ -61,7 +61,7 @@ class Server(val rack: tileentity.Rack, val number: Int) extends Owner { })) def hasCPU = inventory.items.exists { - case Some(stack) => Registry.itemDriverFor(stack) match { + case Some(stack) => Option(Driver.driverFor(stack)) match { case Some(driver) => driver.slot(stack) == Slot.Processor case _ => false } 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 7a5aacb67..e487e0a6e 100644 --- a/src/main/scala/li/cil/oc/server/driver/Registry.scala +++ b/src/main/scala/li/cil/oc/server/driver/Registry.scala @@ -49,20 +49,15 @@ private[oc] object Registry extends api.detail.DriverAPI { if (!converters.contains(converter)) converters += converter } - // TODO Move this into the API? - def blockDriverFor(world: World, x: Int, y: Int, z: Int) = + def driverFor(world: World, x: Int, y: Int, z: Int) = blocks.filter(_.worksWith(world, x, y, z)) match { - case drivers if !drivers.isEmpty => Some(new CompoundBlockDriver(drivers: _*)) - case _ => None + case drivers if !drivers.isEmpty => new CompoundBlockDriver(drivers: _*) + case _ => null } - // TODO Move this into the API? - def itemDriverFor(stack: ItemStack) = - if (stack != null) items.find(_.worksWith(stack)) match { - case None => None - case Some(driver) => Some(driver) - } - else None + def driverFor(stack: ItemStack) = + if (stack != null) items.find(_.worksWith(stack)).orNull + else null def convert(value: Array[AnyRef]) = if (value != null) value.map(convertRecursively) else null