From cf43ca1d8671ad22067c066bbab2b5be6a730e07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 9 Jun 2016 21:33:48 +0200 Subject: [PATCH] Added `computer.getProgramLocations` and IMC message to populate the returned table. --- src/main/java/li/cil/oc/api/IMC.java | 62 +++++++++++++++---- .../assets/opencomputers/lua/machine.lua | 7 ++- src/main/scala/li/cil/oc/common/IMC.scala | 8 +++ .../opencomputers/ModOpenComputers.scala | 21 +++++++ .../li/cil/oc/server/machine/Machine.scala | 4 ++ .../oc/server/machine/ProgramLocations.scala | 19 ++++++ 6 files changed, 108 insertions(+), 13 deletions(-) create mode 100644 src/main/scala/li/cil/oc/server/machine/ProgramLocations.scala diff --git a/src/main/java/li/cil/oc/api/IMC.java b/src/main/java/li/cil/oc/api/IMC.java index 4cf7a391b..c03b2251d 100644 --- a/src/main/java/li/cil/oc/api/IMC.java +++ b/src/main/java/li/cil/oc/api/IMC.java @@ -4,6 +4,7 @@ import cpw.mods.fml.common.event.FMLInterModComms; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; +import net.minecraft.nbt.NBTTagString; import org.apache.commons.lang3.tuple.Pair; /** @@ -20,6 +21,7 @@ import org.apache.commons.lang3.tuple.Pair; * copy this class while keeping the package name, to avoid conflicts if this * class gets updated. */ +@SuppressWarnings("unused") public final class IMC { /** * Register a callback that is used as a filter for assembler templates. @@ -37,7 +39,7 @@ public final class IMC { * * @param callback the callback to register as a filtering method. */ - public static void registerAssemblerFilter(String callback) { + public static void registerAssemblerFilter(final String callback) { FMLInterModComms.sendMessage(MOD_ID, "registerAssemblerFilter", callback); } @@ -98,7 +100,7 @@ public final class IMC { * with only two card slots will pass null * for the third component slot. Up to nine. */ - public static void registerAssemblerTemplate(String name, String select, String validate, String assemble, Class host, int[] containerTiers, int[] upgradeTiers, Iterable> componentSlots) { + public static void registerAssemblerTemplate(final String name, final String select, final String validate, final String assemble, final Class host, final int[] containerTiers, final int[] upgradeTiers, final Iterable> componentSlots) { final NBTTagCompound nbt = new NBTTagCompound(); if (name != null) { nbt.setString("name", name); @@ -187,7 +189,7 @@ public final class IMC { * @param disassemble callback used to apply a template and extract * ingredients from an item. */ - public static void registerDisassemblerTemplate(String name, String select, String disassemble) { + public static void registerDisassemblerTemplate(final String name, final String select, final String disassemble) { final NBTTagCompound nbt = new NBTTagCompound(); if (name != null) { nbt.setString("name", name); @@ -218,7 +220,7 @@ public final class IMC { * * @param callback the callback to register as a durability provider. */ - public static void registerToolDurabilityProvider(String callback) { + public static void registerToolDurabilityProvider(final String callback) { FMLInterModComms.sendMessage(MOD_ID, "registerToolDurabilityProvider", callback); } @@ -234,7 +236,7 @@ public final class IMC { *

* Signature of callbacks must be: *

-     * boolean callback(EntityPlayer player, int x, int y, int z, boolean changeDurability)
+     * boolean callback(EntityPlayer player, BlockPos pos, boolean changeDurability)
      * 
*

* Callbacks must be declared as packagePath.className.methodName. @@ -242,7 +244,7 @@ public final class IMC { * * @param callback the callback to register as a wrench tool handler. */ - public static void registerWrenchTool(String callback) { + public static void registerWrenchTool(final String callback) { FMLInterModComms.sendMessage(MOD_ID, "registerWrenchTool", callback); } @@ -265,7 +267,7 @@ public final class IMC { * * @param callback the callback to register as a wrench tool tester. */ - public static void registerWrenchToolCheck(String callback) { + public static void registerWrenchToolCheck(final String callback) { FMLInterModComms.sendMessage(MOD_ID, "registerWrenchToolCheck", callback); } @@ -291,7 +293,7 @@ public final class IMC { * @param canCharge the callback to register for checking chargeability. * @param charge the callback to register for charging items. */ - public static void registerItemCharge(String name, String canCharge, String charge) { + public static void registerItemCharge(final String name, final String canCharge, final String charge) { final NBTTagCompound nbt = new NBTTagCompound(); nbt.setString("name", name); nbt.setString("canCharge", canCharge); @@ -319,7 +321,7 @@ public final class IMC { * * @param callback the callback to register as an ink provider. */ - public static void registerInkProvider(String callback) { + public static void registerInkProvider(final String callback) { FMLInterModComms.sendMessage(MOD_ID, "registerInkProvider", callback); } @@ -332,7 +334,7 @@ public final class IMC { * * @param peripheral the class of the peripheral to blacklist. */ - public static void blacklistPeripheral(Class peripheral) { + public static void blacklistPeripheral(final Class peripheral) { FMLInterModComms.sendMessage(MOD_ID, "blacklistPeripheral", peripheral.getName()); } @@ -351,7 +353,7 @@ public final class IMC { * @param host the class of the host to blacklist the component for. * @param stack the item stack representing the blacklisted component. */ - public static void blacklistHost(String name, Class host, ItemStack stack) { + public static void blacklistHost(final String name, final Class host, final ItemStack stack) { final NBTTagCompound nbt = new NBTTagCompound(); nbt.setString("name", name); nbt.setString("host", host.getName()); @@ -372,6 +374,44 @@ public final class IMC { FMLInterModComms.sendMessage(MOD_ID, "registerCustomPowerSystem", "true"); } + /** + * Register a mapping of program name to loot disk. + *

+ * The table of mappings is made available to machines to allow displaying + * a message to the user telling her on which floppy disk to find the program + * they were trying to run. + *

+ * For Lua programs, this should be the program name, i.e. the file + * name without the .lua extension. + *

+ * The list of architectures is optional, if it is not specified this mapping + * will be made available to all architectures. It allows filtering since + * typically programs will be written for one specific architecture type, e.g. + * Lua programs will not (directly) work on a MIPS architecture. The name + * specified is the in the {@link li.cil.oc.api.machine.Architecture.Name} + * annotation of the architecture (also shown in the CPU tooltip). + *

+ * The architecture names for Lua are Lua 5.2, Lua 5.3 + * and LuaJ for example. + * + * @param programName the name of the program. + * @param diskLabel the label of the disk the program is on. + * @param architectures the names of the architectures this entry applies to. + */ + public static void registerProgramDiskLabel(final String programName, final String diskLabel, final String... architectures) { + final NBTTagCompound nbt = new NBTTagCompound(); + nbt.setString("program", programName); + nbt.setString("label", diskLabel); + if (architectures != null && architectures.length > 0) { + final NBTTagList architecturesNbt = new NBTTagList(); + for (final String architecture : architectures) { + architecturesNbt.appendTag(new NBTTagString(architecture)); + } + nbt.setTag("architectures", architecturesNbt); + } + FMLInterModComms.sendMessage(MOD_ID, "registerProgramDiskLabel", nbt); + } + // ----------------------------------------------------------------------- // private static final String MOD_ID = "OpenComputers"; diff --git a/src/main/resources/assets/opencomputers/lua/machine.lua b/src/main/resources/assets/opencomputers/lua/machine.lua index 23b3e45b1..3a67047dd 100644 --- a/src/main/resources/assets/opencomputers/lua/machine.lua +++ b/src/main/resources/assets/opencomputers/lua/machine.lua @@ -1334,8 +1334,11 @@ local libcomputer = { beep = function(...) return libcomponent.invoke(computer.address(), "beep", ...) end, - getDeviceInfo = function(...) - return libcomponent.invoke(computer.address(), "getDeviceInfo", ...) + getDeviceInfo = function() + return libcomponent.invoke(computer.address(), "getDeviceInfo") + end, + getProgramLocations = function() + return libcomponent.invoke(computer.address(), "getProgramLocations") end, getArchitectures = function(...) diff --git a/src/main/scala/li/cil/oc/common/IMC.scala b/src/main/scala/li/cil/oc/common/IMC.scala index 7cdd67891..27811148c 100644 --- a/src/main/scala/li/cil/oc/common/IMC.scala +++ b/src/main/scala/li/cil/oc/common/IMC.scala @@ -12,8 +12,11 @@ import li.cil.oc.common.template.DisassemblerTemplates import li.cil.oc.integration.util.ItemCharge import li.cil.oc.integration.util.Wrench import li.cil.oc.server.driver.Registry +import li.cil.oc.server.machine.ProgramLocations +import li.cil.oc.util.ExtendedNBT._ import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagString import net.minecraftforge.common.util.Constants.NBT import scala.collection.convert.WrapAsScala._ @@ -91,8 +94,13 @@ object IMC { } } else if (message.key == "registerCustomPowerSystem" && message.isStringMessage) { + OpenComputers.log.info(s"Was told there is an unknown power system present by mod ${message.getSender}.") Settings.get.is3rdPartyPowerSystemPresent = message.getStringValue == "true" } + else if (message.key == "registerProgramDiskLabel" && message.isNBTMessage) { + OpenComputers.log.info(s"Registering new program location mapping for program '${message.getNBTValue.getString("program")}' being on disk '${message.getNBTValue.getString("label")}' from mod ${message.getSender}.") + ProgramLocations.addMapping(message.getNBTValue.getString("program"), message.getNBTValue.getString("label"), message.getNBTValue.getTagList("architectures", NBT.TAG_STRING).map((tag: NBTTagString) => tag.func_150285_a_()).toArray: _*) + } else { OpenComputers.log.warn(s"Got an unrecognized or invalid IMC message '${message.key}' from mod ${message.getSender}.") } diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala index d415189a9..097e93f5d 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala @@ -67,9 +67,30 @@ object ModOpenComputers extends ModProxy { "OpenComputers", "li.cil.oc.integration.opencomputers.ModOpenComputers.canCharge", "li.cil.oc.integration.opencomputers.ModOpenComputers.charge") + api.IMC.registerInkProvider("li.cil.oc.integration.opencomputers.ModOpenComputers.inkCartridgeInkProvider") api.IMC.registerInkProvider("li.cil.oc.integration.opencomputers.ModOpenComputers.dyeInkProvider") + api.IMC.registerProgramDiskLabel("build", "builder", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("dig", "dig", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("base64", "data", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("deflate", "data", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("gpg", "data", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("inflate", "data", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("md5sum", "data", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("sha256sum", "data", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("refuel", "generator", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("pastebin", "internet", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("wget", "internet", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("irc", "irc", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("maze", "maze", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("arp", "network", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("ifconfig", "network", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("ping", "network", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("route", "network", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("opl-flash", "openloader", "Lua 5.2", "Lua 5.3", "LuaJ") + api.IMC.registerProgramDiskLabel("oppm", "oppm", "Lua 5.2", "Lua 5.3", "LuaJ") + ForgeChunkManager.setForcedChunkLoadingCallback(OpenComputers, ChunkloaderUpgradeHandler) FMLCommonHandler.instance.bus.register(EventHandler) diff --git a/src/main/scala/li/cil/oc/server/machine/Machine.scala b/src/main/scala/li/cil/oc/server/machine/Machine.scala index 0a04b298e..8aaacc6ef 100644 --- a/src/main/scala/li/cil/oc/server/machine/Machine.scala +++ b/src/main/scala/li/cil/oc/server/machine/Machine.scala @@ -452,6 +452,10 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach }.collect { case Some(kvp) => kvp }.toMap) } + @Callback(doc = """function():table -- Returns a map of program name to disk label for known programs.""") + def getProgramLocations(context: Context, args: Arguments): Array[AnyRef] = + result(ProgramLocations.getMappings(Machine.getArchitectureName(architecture.getClass))) + // ----------------------------------------------------------------------- // def isExecuting = state.synchronized(state.contains(Machine.State.Running)) diff --git a/src/main/scala/li/cil/oc/server/machine/ProgramLocations.scala b/src/main/scala/li/cil/oc/server/machine/ProgramLocations.scala new file mode 100644 index 000000000..d4578a61c --- /dev/null +++ b/src/main/scala/li/cil/oc/server/machine/ProgramLocations.scala @@ -0,0 +1,19 @@ +package li.cil.oc.server.machine + +import scala.collection.mutable + +object ProgramLocations { + final val architectureLocations = mutable.Map.empty[String, mutable.Map[String, String]] + final val globalLocations = mutable.Map.empty[String, String] + + def addMapping(program: String, label: String, architectures: String*): Unit = { + if (architectures == null || architectures.isEmpty) { + globalLocations += (program -> label) + } + else { + architectures.foreach(architectureLocations.getOrElseUpdate(_, mutable.Map.empty[String, String]) += (program -> label)) + } + } + + def getMappings(architecture: String) = architectureLocations.getOrElse(architecture, Iterable.empty) ++ globalLocations +}