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.
This commit is contained in:
Florian Nücke 2015-05-14 20:45:19 +02:00
parent 611f76c158
commit 13e1b22101
13 changed files with 279 additions and 73 deletions

View File

@ -12,7 +12,7 @@ import li.cil.oc.api.detail.*;
*/ */
public class API { public class API {
public static final String ID_OWNER = "OpenComputers|Core"; 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 DriverAPI driver = null;
public static FileSystemAPI fileSystem = null; public static FileSystemAPI fileSystem = null;

View File

@ -3,6 +3,8 @@ package li.cil.oc.api;
import li.cil.oc.api.detail.ItemInfo; import li.cil.oc.api.detail.ItemInfo;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import java.util.concurrent.Callable;
/** /**
* Access to item definitions for all blocks and items provided by * Access to item definitions for all blocks and items provided by
* OpenComputers. * OpenComputers.
@ -44,6 +46,54 @@ public final class Items {
return null; return null;
} }
/**
* Register a single loot floppy disk.
* <p/>
* The disk will be listed in the creative tab of OpenComputers.
* <p/>
* 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.
* <p/>
* 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<li.cil.oc.api.fs.FileSystem> factory) {
if (API.items != null)
return API.items.registerFloppy(name, color, factory);
return null;
}
/**
* Register a single custom EEPROM.
* <p/>
* The EEPROM will be listed in the creative tab of OpenComputers.
* <p/>
* The EEPROM will be initialized with the specified code and data byte
* arrays. For script code (e.g. a Lua script) use <tt>String.getBytes("UTF-8")</tt>.
* You can omit any of the arguments by passing <tt>null</tt>.
*
* @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() { private Items() {

View File

@ -1,7 +1,10 @@
package li.cil.oc.api.detail; package li.cil.oc.api.detail;
import li.cil.oc.api.FileSystem;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import java.util.concurrent.Callable;
public interface ItemAPI { public interface ItemAPI {
/** /**
* Get a descriptor object for the block or item with the specified name. * 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. * if the stack is not a valid OpenComputers item or block.
*/ */
ItemInfo get(ItemStack stack); ItemInfo get(ItemStack stack);
/**
* Register a single loot floppy disk.
* <p/>
* The disk will be listed in the creative tab of OpenComputers.
* <p/>
* 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.
* <p/>
* To use some directory in your mod JAR as the directory provided by the
* loot disk, use {@link FileSystem#fromClass} in your callable.
* <p/>
* Call this in the init phase or later, <em>not</em> 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<li.cil.oc.api.fs.FileSystem> factory);
/**
* Register a single custom EEPROM.
* <p/>
* The EEPROM will be listed in the creative tab of OpenComputers.
* <p/>
* The EEPROM will be initialized with the specified code and data byte
* arrays. For script code (e.g. a Lua script) use <tt>String.getBytes("UTF-8")</tt>.
* You can omit any of the arguments by passing <tt>null</tt>.
* <p/>
* Call this in the init phase or later, <em>not</em> 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);
} }

View File

@ -10,7 +10,7 @@ MazeGen=maze:1:dyeOrange
Network=network:1:dyeLime Network=network:1:dyeLime
OpenIRC=irc:1:dyeLightBlue OpenIRC=irc:1:dyeLightBlue
OpenLoader=openloader:1:dyeMagenta OpenLoader=openloader:1:dyeMagenta
OpenOS=openos:0:dyeGreen OpenOS=openOS:0:dyeGreen
OPPM=oppm:0:dyeCyan OPPM=oppm:0:dyeCyan
# Higher chance to find the dig program, because it has the most immediate # 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 # use - OpenOS is craftable and IRC can be downloaded once an internet card

View File

@ -364,7 +364,6 @@ chameliumBlock {
["oc:chamelium", "oc:chamelium", "oc:chamelium"], ["oc:chamelium", "oc:chamelium", "oc:chamelium"],
["oc:chamelium", "oc:chamelium", "oc:chamelium"]] ["oc:chamelium", "oc:chamelium", "oc:chamelium"]]
} }
endstone { endstone {
input: [[enderPearl, "oc:chameliumBlock", enderPearl] input: [[enderPearl, "oc:chameliumBlock", enderPearl]
["oc:chameliumBlock", enderPearl, "oc:chameliumBlock"] ["oc:chameliumBlock", enderPearl, "oc:chameliumBlock"]

View File

@ -113,6 +113,7 @@ object Constants {
final val NavigationUpgrade = "navigationUpgrade" final val NavigationUpgrade = "navigationUpgrade"
final val NetworkCard = "lanCard" final val NetworkCard = "lanCard"
final val NumPad = "numPad" final val NumPad = "numPad"
final val OpenOS = "openOS"
final val PistonUpgrade = "pistonUpgrade" final val PistonUpgrade = "pistonUpgrade"
final val Present = "present" final val Present = "present"
final val PrintedCircuitBoard = "printedCircuitBoard" final val PrintedCircuitBoard = "printedCircuitBoard"

View File

@ -163,7 +163,7 @@ object Achievement {
val OpenOS = newAchievement("openOS"). val OpenOS = newAchievement("openOS").
at(10, 9). at(10, 9).
withParent(Floppy). withParent(Floppy).
whenCrafting(Items.createOpenOS()). whenCrafting(Constants.ItemName.OpenOS).
add() add()
val Raid = newAchievement("raid"). val Raid = newAchievement("raid").
at(8, 10). at(8, 10).

View File

@ -2,11 +2,15 @@ package li.cil.oc.common
import java.io import java.io
import java.util.Random import java.util.Random
import java.util.concurrent.Callable
import cpw.mods.fml.common.Loader
import cpw.mods.fml.common.eventhandler.SubscribeEvent import cpw.mods.fml.common.eventhandler.SubscribeEvent
import li.cil.oc.Constants import li.cil.oc.Constants
import li.cil.oc.OpenComputers import li.cil.oc.OpenComputers
import li.cil.oc.Settings 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.common.init.Items
import li.cil.oc.util.Color import li.cil.oc.util.Color
import net.minecraft.inventory.IInventory import net.minecraft.inventory.IInventory
@ -28,11 +32,38 @@ object Loot extends WeightedRandomChestContent(new ItemStack(null: Item), 1, 1,
ChestGenHooks.PYRAMID_JUNGLE_CHEST, ChestGenHooks.PYRAMID_JUNGLE_CHEST,
ChestGenHooks.STRONGHOLD_LIBRARY) 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 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() { def init() {
for (container <- containers) { 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") val listStream = getClass.getResourceAsStream("/assets/" + Settings.resourceDomain + "/loot/loot.properties")
list.load(listStream) list.load(listStream)
listStream.close() listStream.close()
parseLootDisks(list, builtInDisks) parseLootDisks(list, globalDisks, external = false)
} }
@SubscribeEvent @SubscribeEvent
def initForWorld(e: WorldEvent.Load) { def initForWorld(e: WorldEvent.Load): Unit = {
worldDisks.clear() worldDisks.clear()
disks.clear() disksForSampling.clear()
val path = new io.File(DimensionManager.getCurrentSaveRootDirectory, Settings.savePath + "loot/") val path = new io.File(DimensionManager.getCurrentSaveRootDirectory, Settings.savePath + "loot/")
if (path.exists && path.isDirectory) { if (path.exists && path.isDirectory) {
val listFile = new io.File(path, "loot.properties") 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() val list = new java.util.Properties()
list.load(listStream) list.load(listStream)
listStream.close() listStream.close()
parseLootDisks(list, worldDisks) parseLootDisks(list, worldDisks, external = true)
} }
catch { catch {
case t: Throwable => OpenComputers.log.warn("Failed opening loot descriptor file in saves folder.") 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 worldDisks += name -> entry
} }
for ((_, (stack, count)) <- worldDisks) { for ((_, (stack, count)) <- worldDisks) {
for (i <- 0 until count) { 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) { for (key <- list.stringPropertyNames) {
val value = list.getProperty(key) val value = list.getProperty(key)
try value.split(":") match { try value.split(":") match {
case Array(name, count, color) => 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) => case Array(name, count) =>
acc += key -> ((createLootDisk(name, key), count.toInt)) acc += key -> ((createLootDisk(name, key, external), count.toInt))
case _ => case _ =>
acc += key -> ((createLootDisk(value, key), 1)) acc += key -> ((createLootDisk(value, key, external), 1))
} }
catch { catch {
case t: Throwable => OpenComputers.log.warn("Bad loot descriptor: " + value, t) 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) = { def createLootDisk(name: String, path: String, external: Boolean, color: Option[Int] = None) = {
val data = new NBTTagCompound() val callable = if (external) new Callable[FileSystem] {
data.setString(Settings.namespace + "fs.label", name) override def call(): FileSystem = api.FileSystem.fromSaveDirectory("loot/" + path, 0, false)
} else new Callable[FileSystem] {
val tag = new NBTTagCompound() override def call(): FileSystem = api.FileSystem.fromClass(OpenComputers.getClass, Settings.resourceDomain, "loot/" + path)
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 _ =>
} }
val stack = registerLootDisk(name, color.getOrElse(8), callable)
val disk = Items.get(Constants.ItemName.LootDisk).createItemStack(1) if (!external) {
disk.setTagCompound(tag) Items.registerStack(stack, name)
}
disk stack
} }
override def generateChestContent(random: Random, newInventory: IInventory) = override def generateChestContent(random: Random, newInventory: IInventory) =
if (disks.length > 0) if (disksForSampling.length > 0)
ChestGenHooks.generateStacks(random, disks(random.nextInt(disks.length)), ChestGenHooks.generateStacks(random, disksForSampling(random.nextInt(disksForSampling.length)),
theMinimumChanceToGenerateItem, theMaximumChanceToGenerateItem) theMinimumChanceToGenerateItem, theMaximumChanceToGenerateItem)
else Array.empty[ItemStack] else Array.empty[ItemStack]
} }

View File

@ -1,11 +1,14 @@
package li.cil.oc.common.init package li.cil.oc.common.init
import java.util.concurrent.Callable
import cpw.mods.fml.common.registry.GameRegistry import cpw.mods.fml.common.registry.GameRegistry
import li.cil.oc.Constants import li.cil.oc.Constants
import li.cil.oc.OpenComputers import li.cil.oc.OpenComputers
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.api.detail.ItemAPI import li.cil.oc.api.detail.ItemAPI
import li.cil.oc.api.detail.ItemInfo import li.cil.oc.api.detail.ItemInfo
import li.cil.oc.api.fs.FileSystem
import li.cil.oc.common import li.cil.oc.common
import li.cil.oc.common.Loot import li.cil.oc.common.Loot
import li.cil.oc.common.Tier import li.cil.oc.common.Tier
@ -103,6 +106,24 @@ object Items extends ItemAPI {
instance 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 = private def getBlockOrItem(stack: ItemStack): Any =
if (stack == null) null if (stack == null) null
else Delegator.subItem(stack).getOrElse(stack.getItem match { else Delegator.subItem(stack).getOrElse(stack.getItem match {
@ -112,24 +133,60 @@ object Items extends ItemAPI {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
def createOpenOS(amount: Int = 1) = { val registeredItems = mutable.ArrayBuffer.empty[ItemStack]
Loot.builtInDisks.get("OpenOS").map(_._1.copy()).orNull
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) = { override def registerEEPROM(name: String, code: Array[Byte], data: Array[Byte], readonly: Boolean): ItemStack = {
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)")
val nbt = new NBTTagCompound() 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) val stackNbt = new NBTTagCompound()
stack.setTagCompound(nbt) 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 <tt>api.Items.get("openOS").createItemStack(amount)</tt> 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 <tt>api.Items.get("luaBios").createItemStack(amount)</tt> instead.
*/
@Deprecated
def createLuaBios(amount: Int = 1) = {
get(Constants.ItemName.LuaBios).createItemStack(amount)
} }
def createConfiguredDrone() = { def createConfiguredDrone() = {
@ -204,8 +261,8 @@ object Items extends ItemAPI {
get(Constants.ItemName.RAMTier6).createItemStack(1), get(Constants.ItemName.RAMTier6).createItemStack(1),
get(Constants.ItemName.RAMTier6).createItemStack(1), get(Constants.ItemName.RAMTier6).createItemStack(1),
createLuaBios(), get(Constants.ItemName.LuaBios).createItemStack(1),
createOpenOS(), get(Constants.ItemName.OpenOS).createItemStack(1),
get(Constants.ItemName.HDDTier3).createItemStack(1) get(Constants.ItemName.HDDTier3).createItemStack(1)
) )
data.containers = Array( 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(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)) Option(get(Constants.ItemName.HDDTier3).createItemStack(1))
).padTo(32, None) ).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)) data.container = Option(get(Constants.BlockName.DiskDrive).createItemStack(1))
val stack = get(Constants.ItemName.Tablet).createItemStack(1) val stack = get(Constants.ItemName.Tablet).createItemStack(1)
@ -255,20 +312,19 @@ object Items extends ItemAPI {
def init() { def init() {
val multi = new item.Delegator() { val multi = new item.Delegator() {
def configuredItems = Array( def additionalItems = Array(
createLuaBios(),
createConfiguredDrone(), createConfiguredDrone(),
createConfiguredMicrocontroller(), createConfiguredMicrocontroller(),
createConfiguredRobot(), createConfiguredRobot(),
createConfiguredTablet() createConfiguredTablet()
) ) ++ registeredItems
override def getSubItems(item: Item, tab: CreativeTabs, list: java.util.List[_]) { override def getSubItems(item: Item, tab: CreativeTabs, list: java.util.List[_]) {
// Workaround for MC's untyped lists... // Workaround for MC's untyped lists...
def add[T](list: java.util.List[T], value: Any) = list.add(value.asInstanceOf[T]) def add[T](list: java.util.List[T], value: Any) = list.add(value.asInstanceOf[T])
super.getSubItems(item, tab, list) super.getSubItems(item, tab, list)
Loot.worldDisks.values.foreach(entry => add(list, entry._1)) 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) { new item.FloppyDisk(multi) {
showInItemList = false 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) = { override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer) = {
if (player.isSneaking) get(Constants.ItemName.Floppy).createItemStack(1) if (player.isSneaking) get(Constants.ItemName.Floppy).createItemStack(1)
@ -414,7 +470,13 @@ object Items extends ItemAPI {
// 1.4.2 // 1.4.2
val eeprom = new item.EEPROM() val eeprom = new item.EEPROM()
Recipes.addItem(eeprom, Constants.ItemName.EEPROM, "oc: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") Recipes.addSubItem(new item.MicrocontrollerCase(multi, Tier.One), Constants.ItemName.MicrocontrollerCaseTier1, "oc:microcontrollerCase1")
// 1.4.3 // 1.4.3
@ -452,6 +514,5 @@ object Items extends ItemAPI {
// 1.5.8 // 1.5.8
Recipes.addSubItem(new item.UpgradeHover(multi, Tier.One), Constants.ItemName.HoverUpgradeTier1, "oc:hoverUpgrade1") 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") Recipes.addSubItem(new item.UpgradeHover(multi, Tier.Two), Constants.ItemName.HoverUpgradeTier2, "oc:hoverUpgrade2")
} }
} }

View File

@ -6,7 +6,6 @@ import li.cil.oc.Constants
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.api import li.cil.oc.api
import li.cil.oc.api.detail.ItemInfo 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.DroneData
import li.cil.oc.common.item.data.MicrocontrollerData import li.cil.oc.common.item.data.MicrocontrollerData
import li.cil.oc.common.item.data.PrintData import li.cil.oc.common.item.data.PrintData
@ -28,7 +27,7 @@ import scala.util.control.Breaks._
object ExtendedRecipe { object ExtendedRecipe {
private lazy val drone = api.Items.get(Constants.ItemName.Drone) private lazy val drone = api.Items.get(Constants.ItemName.Drone)
private lazy val eeprom = api.Items.get(Constants.ItemName.EEPROM) 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 mcu = api.Items.get(Constants.BlockName.Microcontroller)
private lazy val navigationUpgrade = api.Items.get(Constants.ItemName.NavigationUpgrade) private lazy val navigationUpgrade = api.Items.get(Constants.ItemName.NavigationUpgrade)
private lazy val linkedCard = api.Items.get(Constants.ItemName.LinkedCard) private lazy val linkedCard = api.Items.get(Constants.ItemName.LinkedCard)
@ -159,7 +158,7 @@ object ExtendedRecipe {
// EEPROM copying. // EEPROM copying.
if (api.Items.get(craftedStack) == eeprom && if (api.Items.get(craftedStack) == eeprom &&
!ItemStack.areItemStackTagsEqual(craftedStack, luaBios) && api.Items.get(craftedStack) != luaBios &&
recipe.isInstanceOf[ExtendedShapelessOreRecipe] && recipe.isInstanceOf[ExtendedShapelessOreRecipe] &&
recipe.asInstanceOf[ExtendedShapelessOreRecipe].getInput != null && recipe.asInstanceOf[ExtendedShapelessOreRecipe].getInput != null &&
recipe.asInstanceOf[ExtendedShapelessOreRecipe].getInput.size == 2) breakable { recipe.asInstanceOf[ExtendedShapelessOreRecipe].getInput.size == 2) breakable {

View File

@ -68,6 +68,13 @@ object Recipes {
instance 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) { def addRecipe(stack: ItemStack, name: String) {
list += stack -> name list += stack -> name
} }
@ -149,7 +156,7 @@ object Recipes {
val lootRecipes = recipes.getConfigList("lootDisks") val lootRecipes = recipes.getConfigList("lootDisks")
for (recipe <- lootRecipes) { for (recipe <- lootRecipes) {
val name = recipe.getString("name") 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 Some((stack, _)) => addRecipe(stack, recipe, s"loot disk '$name'")
case _ => case _ =>
OpenComputers.log.warn(s"Failed adding recipe for loot disk '$name': No such global loot disk.") OpenComputers.log.warn(s"Failed adding recipe for loot disk '$name': No such global loot disk.")

View File

@ -5,6 +5,7 @@ import li.cil.oc.Constants
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.api import li.cil.oc.api
import li.cil.oc.api.driver.EnvironmentHost import li.cil.oc.api.driver.EnvironmentHost
import li.cil.oc.common.Loot
import li.cil.oc.common.Slot import li.cil.oc.common.Slot
import li.cil.oc.common.item.Delegator import li.cil.oc.common.item.Delegator
import li.cil.oc.common.item.FloppyDisk 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) = { 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 if (stack.hasTagCompound && stack.getTagCompound.hasKey(Settings.namespace + "lootFactory")) {
// node's address as the folder name... so we generate the address here, // Loot disk, create file system using factory callback.
// if necessary. No one will know, right? Right!? Loot.factories.get(stack.getTagCompound.getString(Settings.namespace + "lootFactory")) match {
val address = addressFromTag(dataTag(stack)) case Some(factory) =>
val isFloppy = api.Items.get(stack) == api.Items.get(Constants.ItemName.Floppy) val label =
val fs = oc.api.FileSystem.fromSaveDirectory(address, capacity, Settings.get.bufferChanges) if (dataTag(stack).hasKey(Settings.namespace + "fs.label"))
val environment = oc.api.FileSystem.asManagedEnvironment(fs, new ReadWriteItemLabel(stack), host, Settings.resourceDomain + ":" + (if (isFloppy) "floppy_access" else "hdd_access"), speed) dataTag(stack).getString(Settings.namespace + "fs.label")
if (environment != null && environment.node != null) { else null
environment.node.asInstanceOf[oc.server.network.Node].address = address 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) = private def addressFromTag(tag: NBTTagCompound) =

View File

@ -11,6 +11,9 @@ import li.cil.oc.common.Slot
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraftforge.common.DimensionManager 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 { object DriverLootDisk extends Item {
override def worksWith(stack: ItemStack) = override def worksWith(stack: ItemStack) =
isOneOf(stack, api.Items.get(Constants.ItemName.LootDisk)) isOneOf(stack, api.Items.get(Constants.ItemName.LootDisk))