From 13e1b22101689e3f924ccf5340ff1eb31d8ec6cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 14 May 2015 20:45:19 +0200 Subject: [PATCH] Added API entry to allow mods to register their own loot disks and EEPROMs. Reworked loot disk logic a bit, using factory callbacks producing file systems now. --- src/main/java/li/cil/oc/api/API.java | 2 +- src/main/java/li/cil/oc/api/Items.java | 50 ++++++++ .../java/li/cil/oc/api/detail/ItemAPI.java | 47 ++++++++ .../assets/opencomputers/loot/loot.properties | 2 +- .../opencomputers/recipes/default.recipes | 1 - src/main/scala/li/cil/oc/Constants.scala | 1 + .../scala/li/cil/oc/common/Achievement.scala | 2 +- src/main/scala/li/cil/oc/common/Loot.scala | 86 +++++++++----- .../scala/li/cil/oc/common/init/Items.scala | 109 ++++++++++++++---- .../cil/oc/common/recipe/ExtendedRecipe.scala | 5 +- .../li/cil/oc/common/recipe/Recipes.scala | 9 +- .../opencomputers/DriverFileSystem.scala | 35 ++++-- .../opencomputers/DriverLootDisk.scala | 3 + 13 files changed, 279 insertions(+), 73 deletions(-) diff --git a/src/main/java/li/cil/oc/api/API.java b/src/main/java/li/cil/oc/api/API.java index 5e277005b..3497915e9 100644 --- a/src/main/java/li/cil/oc/api/API.java +++ b/src/main/java/li/cil/oc/api/API.java @@ -12,7 +12,7 @@ import li.cil.oc.api.detail.*; */ public class API { public static final String ID_OWNER = "OpenComputers|Core"; - public static final String VERSION = "5.4.0"; + public static final String VERSION = "5.5.0"; public static DriverAPI driver = null; public static FileSystemAPI fileSystem = null; diff --git a/src/main/java/li/cil/oc/api/Items.java b/src/main/java/li/cil/oc/api/Items.java index a10182d6c..7a0d5657e 100644 --- a/src/main/java/li/cil/oc/api/Items.java +++ b/src/main/java/li/cil/oc/api/Items.java @@ -3,6 +3,8 @@ package li.cil.oc.api; import li.cil.oc.api.detail.ItemInfo; import net.minecraft.item.ItemStack; +import java.util.concurrent.Callable; + /** * Access to item definitions for all blocks and items provided by * OpenComputers. @@ -44,6 +46,54 @@ public final class Items { return null; } + /** + * Register a single loot floppy disk. + *

+ * The disk will be listed in the creative tab of OpenComputers. + *

+ * The specified factory callable will be used to generate a new file + * system when the loot disk is used as a component. The specified name + * will be used as the label for the loot disk, as well as the identifier + * to select the corresponding factory method, so choose wisely. + *

+ * To use some directory in your mod JAR as the directory provided by the + * loot disk, use {@link FileSystem#fromClass} in your callable. + * + * @param name the label and identifier to use for the loot disk. + * @param color the color of the disk, as a Minecraft color (so 0-15, + * with 0 being black, 1 red and so on). + * @param factory the callable to call for creating file system instances. + * @return an item stack representing the registered loot disk, to allow + * adding a recipe for your loot disk, for example. + */ + public static ItemStack registerFloppy(String name, int color, Callable factory) { + if (API.items != null) + return API.items.registerFloppy(name, color, factory); + return null; + } + + /** + * Register a single custom EEPROM. + *

+ * The EEPROM will be listed in the creative tab of OpenComputers. + *

+ * The EEPROM will be initialized with the specified code and data byte + * arrays. For script code (e.g. a Lua script) use String.getBytes("UTF-8"). + * You can omit any of the arguments by passing null. + * + * @param name the label of the EEPROM. + * @param code the code section of the EEPROM. + * @param data the data section of the EEPROM. + * @param readonly whether the code section is read-only. + * @return an item stack representing the registered EEPROM, to allow + * adding a recipe for your custom BIOS, for example. + */ + public static ItemStack registerEEPROM(String name, byte[] code, byte[] data, boolean readonly) { + if (API.items != null) + return API.items.registerEEPROM(name, code, data, readonly); + return null; + } + // ----------------------------------------------------------------------- // private Items() { diff --git a/src/main/java/li/cil/oc/api/detail/ItemAPI.java b/src/main/java/li/cil/oc/api/detail/ItemAPI.java index 8ae9f334d..0de2b2f3d 100644 --- a/src/main/java/li/cil/oc/api/detail/ItemAPI.java +++ b/src/main/java/li/cil/oc/api/detail/ItemAPI.java @@ -1,7 +1,10 @@ package li.cil.oc.api.detail; +import li.cil.oc.api.FileSystem; import net.minecraft.item.ItemStack; +import java.util.concurrent.Callable; + public interface ItemAPI { /** * Get a descriptor object for the block or item with the specified name. @@ -26,4 +29,48 @@ public interface ItemAPI { * if the stack is not a valid OpenComputers item or block. */ ItemInfo get(ItemStack stack); + + /** + * Register a single loot floppy disk. + *

+ * The disk will be listed in the creative tab of OpenComputers. + *

+ * The specified factory callable will be used to generate a new file + * system when the loot disk is used as a component. The specified name + * will be used as the label for the loot disk, as well as the identifier + * to select the corresponding factory method, so choose wisely. + *

+ * To use some directory in your mod JAR as the directory provided by the + * loot disk, use {@link FileSystem#fromClass} in your callable. + *

+ * Call this in the init phase or later, not in pre-init. + * + * @param name the label and identifier to use for the loot disk. + * @param color the color of the disk, as a Minecraft color (so 0-15, + * with 0 being black, 1 red and so on). + * @param factory the callable to call for creating file system instances. + * @return an item stack representing the registered loot disk, to allow + * adding a recipe for your loot disk, for example. + */ + ItemStack registerFloppy(String name, int color, Callable factory); + + /** + * Register a single custom EEPROM. + *

+ * The EEPROM will be listed in the creative tab of OpenComputers. + *

+ * The EEPROM will be initialized with the specified code and data byte + * arrays. For script code (e.g. a Lua script) use String.getBytes("UTF-8"). + * You can omit any of the arguments by passing null. + *

+ * Call this in the init phase or later, not in pre-init. + * + * @param name the label of the EEPROM. + * @param code the code section of the EEPROM. + * @param data the data section of the EEPROM. + * @param readonly whether the code section is read-only. + * @return an item stack representing the registered EEPROM, to allow + * adding a recipe for your custom BIOS, for example. + */ + ItemStack registerEEPROM(String name, byte[] code, byte[] data, boolean readonly); } diff --git a/src/main/resources/assets/opencomputers/loot/loot.properties b/src/main/resources/assets/opencomputers/loot/loot.properties index 95e955686..b7f6a3b68 100644 --- a/src/main/resources/assets/opencomputers/loot/loot.properties +++ b/src/main/resources/assets/opencomputers/loot/loot.properties @@ -10,7 +10,7 @@ MazeGen=maze:1:dyeOrange Network=network:1:dyeLime OpenIRC=irc:1:dyeLightBlue OpenLoader=openloader:1:dyeMagenta -OpenOS=openos:0:dyeGreen +OpenOS=openOS:0:dyeGreen OPPM=oppm:0:dyeCyan # Higher chance to find the dig program, because it has the most immediate # use - OpenOS is craftable and IRC can be downloaded once an internet card diff --git a/src/main/resources/assets/opencomputers/recipes/default.recipes b/src/main/resources/assets/opencomputers/recipes/default.recipes index b5399f3e0..9166abbe5 100644 --- a/src/main/resources/assets/opencomputers/recipes/default.recipes +++ b/src/main/resources/assets/opencomputers/recipes/default.recipes @@ -364,7 +364,6 @@ chameliumBlock { ["oc:chamelium", "oc:chamelium", "oc:chamelium"], ["oc:chamelium", "oc:chamelium", "oc:chamelium"]] } - endstone { input: [[enderPearl, "oc:chameliumBlock", enderPearl] ["oc:chameliumBlock", enderPearl, "oc:chameliumBlock"] diff --git a/src/main/scala/li/cil/oc/Constants.scala b/src/main/scala/li/cil/oc/Constants.scala index cb00dea32..0eaa9d9ff 100644 --- a/src/main/scala/li/cil/oc/Constants.scala +++ b/src/main/scala/li/cil/oc/Constants.scala @@ -113,6 +113,7 @@ object Constants { final val NavigationUpgrade = "navigationUpgrade" final val NetworkCard = "lanCard" final val NumPad = "numPad" + final val OpenOS = "openOS" final val PistonUpgrade = "pistonUpgrade" final val Present = "present" final val PrintedCircuitBoard = "printedCircuitBoard" diff --git a/src/main/scala/li/cil/oc/common/Achievement.scala b/src/main/scala/li/cil/oc/common/Achievement.scala index 1fd7c6a93..d4fe9c3c7 100644 --- a/src/main/scala/li/cil/oc/common/Achievement.scala +++ b/src/main/scala/li/cil/oc/common/Achievement.scala @@ -163,7 +163,7 @@ object Achievement { val OpenOS = newAchievement("openOS"). at(10, 9). withParent(Floppy). - whenCrafting(Items.createOpenOS()). + whenCrafting(Constants.ItemName.OpenOS). add() val Raid = newAchievement("raid"). at(8, 10). diff --git a/src/main/scala/li/cil/oc/common/Loot.scala b/src/main/scala/li/cil/oc/common/Loot.scala index 641769c5d..0a3c3a049 100644 --- a/src/main/scala/li/cil/oc/common/Loot.scala +++ b/src/main/scala/li/cil/oc/common/Loot.scala @@ -2,11 +2,15 @@ package li.cil.oc.common import java.io import java.util.Random +import java.util.concurrent.Callable +import cpw.mods.fml.common.Loader import cpw.mods.fml.common.eventhandler.SubscribeEvent import li.cil.oc.Constants import li.cil.oc.OpenComputers import li.cil.oc.Settings +import li.cil.oc.api +import li.cil.oc.api.fs.FileSystem import li.cil.oc.common.init.Items import li.cil.oc.util.Color import net.minecraft.inventory.IInventory @@ -28,11 +32,38 @@ object Loot extends WeightedRandomChestContent(new ItemStack(null: Item), 1, 1, ChestGenHooks.PYRAMID_JUNGLE_CHEST, ChestGenHooks.STRONGHOLD_LIBRARY) - val builtInDisks = mutable.Map.empty[String, (ItemStack, Int)] + val factories = mutable.Map.empty[String, Callable[FileSystem]] + + val globalDisks = mutable.Map.empty[String, (ItemStack, Int)] val worldDisks = mutable.Map.empty[String, (ItemStack, Int)] - val disks = mutable.ArrayBuffer.empty[ItemStack] + val disksForSampling = mutable.ArrayBuffer.empty[ItemStack] + + def registerLootDisk(name: String, color: Int, factory: Callable[FileSystem]): ItemStack = { + val mod = Loader.instance.activeModContainer.getModId + + OpenComputers.log.info(s"Registering loot disk '$name' from mod $mod.") + + val modSpecificName = mod + ":" + name + + val data = new NBTTagCompound() + data.setString(Settings.namespace + "fs.label", name) + + val nbt = new NBTTagCompound() + nbt.setTag(Settings.namespace + "data", data) + + // Store this top level, so it won't get wiped on save. + nbt.setString(Settings.namespace + "lootFactory", modSpecificName) + nbt.setInteger(Settings.namespace + "color", color max 0 min 15) + + val stack = Items.get(Constants.ItemName.Floppy).createItemStack(1) + stack.setTagCompound(nbt) + + Loot.factories += modSpecificName -> factory + + stack.copy() + } def init() { for (container <- containers) { @@ -43,13 +74,13 @@ object Loot extends WeightedRandomChestContent(new ItemStack(null: Item), 1, 1, val listStream = getClass.getResourceAsStream("/assets/" + Settings.resourceDomain + "/loot/loot.properties") list.load(listStream) listStream.close() - parseLootDisks(list, builtInDisks) + parseLootDisks(list, globalDisks, external = false) } @SubscribeEvent - def initForWorld(e: WorldEvent.Load) { + def initForWorld(e: WorldEvent.Load): Unit = { worldDisks.clear() - disks.clear() + disksForSampling.clear() val path = new io.File(DimensionManager.getCurrentSaveRootDirectory, Settings.savePath + "loot/") if (path.exists && path.isDirectory) { val listFile = new io.File(path, "loot.properties") @@ -59,33 +90,33 @@ object Loot extends WeightedRandomChestContent(new ItemStack(null: Item), 1, 1, val list = new java.util.Properties() list.load(listStream) listStream.close() - parseLootDisks(list, worldDisks) + parseLootDisks(list, worldDisks, external = true) } catch { case t: Throwable => OpenComputers.log.warn("Failed opening loot descriptor file in saves folder.") } } } - for ((name, entry) <- builtInDisks if !worldDisks.contains(name)) { + for ((name, entry) <- globalDisks if !worldDisks.contains(name)) { worldDisks += name -> entry } for ((_, (stack, count)) <- worldDisks) { for (i <- 0 until count) { - disks += stack + disksForSampling += stack } } } - private def parseLootDisks(list: java.util.Properties, acc: mutable.Map[String, (ItemStack, Int)]) { + private def parseLootDisks(list: java.util.Properties, acc: mutable.Map[String, (ItemStack, Int)], external: Boolean) { for (key <- list.stringPropertyNames) { val value = list.getProperty(key) try value.split(":") match { case Array(name, count, color) => - acc += key -> ((createLootDisk(name, key, Some(color)), count.toInt)) + acc += key -> ((createLootDisk(name, key, external, Some(Color.dyes.indexOf(color))), count.toInt)) case Array(name, count) => - acc += key -> ((createLootDisk(name, key), count.toInt)) + acc += key -> ((createLootDisk(name, key, external), count.toInt)) case _ => - acc += key -> ((createLootDisk(value, key), 1)) + acc += key -> ((createLootDisk(value, key, external), 1)) } catch { case t: Throwable => OpenComputers.log.warn("Bad loot descriptor: " + value, t) @@ -93,29 +124,22 @@ object Loot extends WeightedRandomChestContent(new ItemStack(null: Item), 1, 1, } } - def createLootDisk(name: String, path: String, color: Option[String] = None) = { - val data = new NBTTagCompound() - data.setString(Settings.namespace + "fs.label", name) - - val tag = new NBTTagCompound() - tag.setTag(Settings.namespace + "data", data) - // Store this top level, so it won't get wiped on save. - tag.setString(Settings.namespace + "lootPath", path) - color match { - case Some(oreDictName) => - tag.setInteger(Settings.namespace + "color", Color.dyes.indexOf(oreDictName)) - case _ => + def createLootDisk(name: String, path: String, external: Boolean, color: Option[Int] = None) = { + val callable = if (external) new Callable[FileSystem] { + override def call(): FileSystem = api.FileSystem.fromSaveDirectory("loot/" + path, 0, false) + } else new Callable[FileSystem] { + override def call(): FileSystem = api.FileSystem.fromClass(OpenComputers.getClass, Settings.resourceDomain, "loot/" + path) } - - val disk = Items.get(Constants.ItemName.LootDisk).createItemStack(1) - disk.setTagCompound(tag) - - disk + val stack = registerLootDisk(name, color.getOrElse(8), callable) + if (!external) { + Items.registerStack(stack, name) + } + stack } override def generateChestContent(random: Random, newInventory: IInventory) = - if (disks.length > 0) - ChestGenHooks.generateStacks(random, disks(random.nextInt(disks.length)), + if (disksForSampling.length > 0) + ChestGenHooks.generateStacks(random, disksForSampling(random.nextInt(disksForSampling.length)), theMinimumChanceToGenerateItem, theMaximumChanceToGenerateItem) else Array.empty[ItemStack] } diff --git a/src/main/scala/li/cil/oc/common/init/Items.scala b/src/main/scala/li/cil/oc/common/init/Items.scala index 4b30ae26d..9f346874d 100644 --- a/src/main/scala/li/cil/oc/common/init/Items.scala +++ b/src/main/scala/li/cil/oc/common/init/Items.scala @@ -1,11 +1,14 @@ package li.cil.oc.common.init +import java.util.concurrent.Callable + import cpw.mods.fml.common.registry.GameRegistry import li.cil.oc.Constants import li.cil.oc.OpenComputers import li.cil.oc.Settings import li.cil.oc.api.detail.ItemAPI import li.cil.oc.api.detail.ItemInfo +import li.cil.oc.api.fs.FileSystem import li.cil.oc.common import li.cil.oc.common.Loot import li.cil.oc.common.Tier @@ -103,6 +106,24 @@ object Items extends ItemAPI { instance } + def registerStack(stack: ItemStack, id: String) = { + val immutableStack = stack.copy() + descriptors += id -> new ItemInfo { + override def name = id + + override def block = null + + override def createItemStack(size: Int): ItemStack = { + val copy = immutableStack.copy() + copy.stackSize = size + copy + } + + override def item = immutableStack.getItem + } + stack + } + private def getBlockOrItem(stack: ItemStack): Any = if (stack == null) null else Delegator.subItem(stack).getOrElse(stack.getItem match { @@ -112,24 +133,60 @@ object Items extends ItemAPI { // ----------------------------------------------------------------------- // - def createOpenOS(amount: Int = 1) = { - Loot.builtInDisks.get("OpenOS").map(_._1.copy()).orNull + val registeredItems = mutable.ArrayBuffer.empty[ItemStack] + + override def registerFloppy(name: String, color: Int, factory: Callable[FileSystem]): ItemStack = { + val stack = Loot.registerLootDisk(name, color, factory) + + registeredItems += stack + + stack.copy() } - def createLuaBios(amount: Int = 1) = { - val data = new NBTTagCompound() - val code = new Array[Byte](4 * 1024) - val count = OpenComputers.getClass.getResourceAsStream(Settings.scriptPath + "bios.lua").read(code) - data.setByteArray(Settings.namespace + "eeprom", code.take(count)) - data.setString(Settings.namespace + "label", "EEPROM (Lua BIOS)") - + override def registerEEPROM(name: String, code: Array[Byte], data: Array[Byte], readonly: Boolean): ItemStack = { val nbt = new NBTTagCompound() - nbt.setTag(Settings.namespace + "data", data) + if (name != null) { + nbt.setString(Settings.namespace + "label", name.trim.take(16)) + } + if (code != null) { + nbt.setByteArray(Settings.namespace + "eeprom", code.take(Settings.get.eepromSize)) + } + if (data != null) { + nbt.setByteArray(Settings.namespace + "userdata", data.take(Settings.get.eepromDataSize)) + } + nbt.setBoolean(Settings.namespace + "readonly", readonly) - val stack = get(Constants.ItemName.EEPROM).createItemStack(amount) - stack.setTagCompound(nbt) + val stackNbt = new NBTTagCompound() + stackNbt.setTag(Settings.namespace + "data", nbt) - stack + val stack = get(Constants.ItemName.EEPROM).createItemStack(1) + stack.setTagCompound(stackNbt) + + registeredItems += stack + + stack.copy() + } + + // ----------------------------------------------------------------------- // + + // Nobody should use this anyway, since it's internal, but IIRC some people do, so let's be nice... + // TODO remove in OC 1.6 + /** + * @deprecated use api.Items.get("openOS").createItemStack(amount) instead. + */ + @Deprecated + def createOpenOS(amount: Int = 1) = { + get(Constants.ItemName.OpenOS).createItemStack(amount) + } + + // Nobody should use this anyway, since it's internal, but IIRC some people do, so let's be nice... + // TODO remove in OC 1.6 + /** + * @deprecated use api.Items.get("luaBios").createItemStack(amount) instead. + */ + @Deprecated + def createLuaBios(amount: Int = 1) = { + get(Constants.ItemName.LuaBios).createItemStack(amount) } def createConfiguredDrone() = { @@ -204,8 +261,8 @@ object Items extends ItemAPI { get(Constants.ItemName.RAMTier6).createItemStack(1), get(Constants.ItemName.RAMTier6).createItemStack(1), - createLuaBios(), - createOpenOS(), + get(Constants.ItemName.LuaBios).createItemStack(1), + get(Constants.ItemName.OpenOS).createItemStack(1), get(Constants.ItemName.HDDTier3).createItemStack(1) ) data.containers = Array( @@ -238,10 +295,10 @@ object Items extends ItemAPI { Option(get(Constants.ItemName.RAMTier6).createItemStack(1)), Option(get(Constants.ItemName.RAMTier6).createItemStack(1)), - Option(createLuaBios()), + Option(get(Constants.ItemName.LuaBios).createItemStack(1)), Option(get(Constants.ItemName.HDDTier3).createItemStack(1)) ).padTo(32, None) - data.items(31) = Option(createOpenOS()) + data.items(31) = Option(get(Constants.ItemName.OpenOS).createItemStack(1)) data.container = Option(get(Constants.BlockName.DiskDrive).createItemStack(1)) val stack = get(Constants.ItemName.Tablet).createItemStack(1) @@ -255,20 +312,19 @@ object Items extends ItemAPI { def init() { val multi = new item.Delegator() { - def configuredItems = Array( - createLuaBios(), + def additionalItems = Array( createConfiguredDrone(), createConfiguredMicrocontroller(), createConfiguredRobot(), createConfiguredTablet() - ) + ) ++ registeredItems override def getSubItems(item: Item, tab: CreativeTabs, list: java.util.List[_]) { // Workaround for MC's untyped lists... def add[T](list: java.util.List[T], value: Any) = list.add(value.asInstanceOf[T]) super.getSubItems(item, tab, list) Loot.worldDisks.values.foreach(entry => add(list, entry._1)) - configuredItems.foreach(add(list, _)) + additionalItems.foreach(add(list, _)) } } @@ -369,7 +425,7 @@ object Items extends ItemAPI { new item.FloppyDisk(multi) { showInItemList = false - override def createItemStack(amount: Int) = createOpenOS(amount) + override def createItemStack(amount: Int) = get(Constants.ItemName.OpenOS).createItemStack(1) override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer) = { if (player.isSneaking) get(Constants.ItemName.Floppy).createItemStack(1) @@ -414,7 +470,13 @@ object Items extends ItemAPI { // 1.4.2 val eeprom = new item.EEPROM() Recipes.addItem(eeprom, Constants.ItemName.EEPROM, "oc:eeprom") - Recipes.addRecipe(createLuaBios(), Constants.ItemName.LuaBios) + val luaBios = { + val code = new Array[Byte](4 * 1024) + val count = OpenComputers.getClass.getResourceAsStream(Settings.scriptPath + "bios.lua").read(code) + registerEEPROM("EEPROM (Lua BIOS)", code.take(count), null, readonly = false) + } + Recipes.addStack(luaBios, Constants.ItemName.LuaBios) + Recipes.addSubItem(new item.MicrocontrollerCase(multi, Tier.One), Constants.ItemName.MicrocontrollerCaseTier1, "oc:microcontrollerCase1") // 1.4.3 @@ -452,6 +514,5 @@ object Items extends ItemAPI { // 1.5.8 Recipes.addSubItem(new item.UpgradeHover(multi, Tier.One), Constants.ItemName.HoverUpgradeTier1, "oc:hoverUpgrade1") Recipes.addSubItem(new item.UpgradeHover(multi, Tier.Two), Constants.ItemName.HoverUpgradeTier2, "oc:hoverUpgrade2") - } } 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 c2fc0266f..a459acd10 100644 --- a/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala +++ b/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala @@ -6,7 +6,6 @@ import li.cil.oc.Constants import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.detail.ItemInfo -import li.cil.oc.common.init.Items import li.cil.oc.common.item.data.DroneData import li.cil.oc.common.item.data.MicrocontrollerData import li.cil.oc.common.item.data.PrintData @@ -28,7 +27,7 @@ import scala.util.control.Breaks._ object ExtendedRecipe { private lazy val drone = api.Items.get(Constants.ItemName.Drone) private lazy val eeprom = api.Items.get(Constants.ItemName.EEPROM) - private lazy val luaBios = Items.createLuaBios() + private lazy val luaBios = api.Items.get(Constants.ItemName.LuaBios) private lazy val mcu = api.Items.get(Constants.BlockName.Microcontroller) private lazy val navigationUpgrade = api.Items.get(Constants.ItemName.NavigationUpgrade) private lazy val linkedCard = api.Items.get(Constants.ItemName.LinkedCard) @@ -159,7 +158,7 @@ object ExtendedRecipe { // EEPROM copying. if (api.Items.get(craftedStack) == eeprom && - !ItemStack.areItemStackTagsEqual(craftedStack, luaBios) && + api.Items.get(craftedStack) != luaBios && recipe.isInstanceOf[ExtendedShapelessOreRecipe] && recipe.asInstanceOf[ExtendedShapelessOreRecipe].getInput != null && recipe.asInstanceOf[ExtendedShapelessOreRecipe].getInput.size == 2) breakable { diff --git a/src/main/scala/li/cil/oc/common/recipe/Recipes.scala b/src/main/scala/li/cil/oc/common/recipe/Recipes.scala index 3f5c764f2..a52c321c5 100644 --- a/src/main/scala/li/cil/oc/common/recipe/Recipes.scala +++ b/src/main/scala/li/cil/oc/common/recipe/Recipes.scala @@ -68,6 +68,13 @@ object Recipes { instance } + def addStack(stack: ItemStack, name: String, oreDict: String*) = { + Items.registerStack(stack, name) + addRecipe(stack, name) + register(stack, oreDict: _*) + stack + } + def addRecipe(stack: ItemStack, name: String) { list += stack -> name } @@ -149,7 +156,7 @@ object Recipes { val lootRecipes = recipes.getConfigList("lootDisks") for (recipe <- lootRecipes) { val name = recipe.getString("name") - Loot.builtInDisks.get(name) match { + Loot.globalDisks.get(name) match { case Some((stack, _)) => addRecipe(stack, recipe, s"loot disk '$name'") case _ => OpenComputers.log.warn(s"Failed adding recipe for loot disk '$name': No such global loot disk.") diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverFileSystem.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverFileSystem.scala index 824d04533..9d8b9b966 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/DriverFileSystem.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverFileSystem.scala @@ -5,6 +5,7 @@ import li.cil.oc.Constants import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.driver.EnvironmentHost +import li.cil.oc.common.Loot import li.cil.oc.common.Slot import li.cil.oc.common.item.Delegator import li.cil.oc.common.item.FloppyDisk @@ -41,17 +42,31 @@ object DriverFileSystem extends Item { } private def createEnvironment(stack: ItemStack, capacity: Int, host: EnvironmentHost, speed: Int) = { - // We have a bit of a chicken-egg problem here, because we want to use the - // node's address as the folder name... so we generate the address here, - // if necessary. No one will know, right? Right!? - val address = addressFromTag(dataTag(stack)) - val isFloppy = api.Items.get(stack) == api.Items.get(Constants.ItemName.Floppy) - val fs = oc.api.FileSystem.fromSaveDirectory(address, capacity, Settings.get.bufferChanges) - val environment = oc.api.FileSystem.asManagedEnvironment(fs, new ReadWriteItemLabel(stack), host, Settings.resourceDomain + ":" + (if (isFloppy) "floppy_access" else "hdd_access"), speed) - if (environment != null && environment.node != null) { - environment.node.asInstanceOf[oc.server.network.Node].address = address + if (stack.hasTagCompound && stack.getTagCompound.hasKey(Settings.namespace + "lootFactory")) { + // Loot disk, create file system using factory callback. + Loot.factories.get(stack.getTagCompound.getString(Settings.namespace + "lootFactory")) match { + case Some(factory) => + val label = + if (dataTag(stack).hasKey(Settings.namespace + "fs.label")) + dataTag(stack).getString(Settings.namespace + "fs.label") + else null + api.FileSystem.asManagedEnvironment(factory.call(), label, host, Settings.resourceDomain + ":floppy_access") + case _ => null // Invalid loot disk. + } + } + else { + // We have a bit of a chicken-egg problem here, because we want to use the + // node's address as the folder name... so we generate the address here, + // if necessary. No one will know, right? Right!? + val address = addressFromTag(dataTag(stack)) + val isFloppy = api.Items.get(stack) == api.Items.get(Constants.ItemName.Floppy) + val fs = oc.api.FileSystem.fromSaveDirectory(address, capacity, Settings.get.bufferChanges) + val environment = oc.api.FileSystem.asManagedEnvironment(fs, new ReadWriteItemLabel(stack), host, Settings.resourceDomain + ":" + (if (isFloppy) "floppy_access" else "hdd_access"), speed) + if (environment != null && environment.node != null) { + environment.node.asInstanceOf[oc.server.network.Node].address = address + } + environment } - environment } private def addressFromTag(tag: NBTTagCompound) = diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverLootDisk.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverLootDisk.scala index ef00c1138..fe1cf718a 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/DriverLootDisk.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverLootDisk.scala @@ -11,6 +11,9 @@ import li.cil.oc.common.Slot import net.minecraft.item.ItemStack import net.minecraftforge.common.DimensionManager +// This is deprecated and kept for compatibility with old saves. +// As of OC 1.5.10, loot disks are generated using normal floppies, and using +// a factory system that allows third-party mods to register loot disks. object DriverLootDisk extends Item { override def worksWith(stack: ItemStack) = isOneOf(stack, api.Items.get(Constants.ItemName.LootDisk))