diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf index f59a1280c..42f9df5d7 100644 --- a/src/main/resources/reference.conf +++ b/src/main/resources/reference.conf @@ -186,6 +186,11 @@ opencomputers { # always be erased when the computer is completely powered off, even if # it crashed. This setting is purely for software-triggered reboots. eraseTmpOnReboot: false + + # Forces the use of the LuaJ fallback instead of the native libraries. + # Use this if you have (unfounded) concerns using native libraries or + # experience issues with the native library. Also used for debugging. + forceLuaJ: false } # Robot related settings, what they may do and general balancing. diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index e488884c7..94687adb4 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -59,6 +59,7 @@ class Settings(config: Config) { val allowBytecode = config.getBoolean("computer.allowBytecode") val logLuaCallbackErrors = config.getBoolean("computer.logCallbackErrors") val eraseTmpOnReboot = config.getBoolean("computer.eraseTmpOnReboot") + val forceLuaJ = config.getBoolean("computer.forceLuaJ") // ----------------------------------------------------------------------- // // robot diff --git a/src/main/scala/li/cil/oc/common/Proxy.scala b/src/main/scala/li/cil/oc/common/Proxy.scala index 17ad2e66f..d81679730 100644 --- a/src/main/scala/li/cil/oc/common/Proxy.scala +++ b/src/main/scala/li/cil/oc/common/Proxy.scala @@ -44,7 +44,7 @@ class Proxy { api.Items.instance = Items api.Machine.instance = machine.Machine api.Machine.LuaArchitecture = - if (LuaStateFactory.isAvailable) classOf[NativeLuaArchitecture] + if (LuaStateFactory.isAvailable && !Settings.get.forceLuaJ) classOf[NativeLuaArchitecture] else classOf[LuaJLuaArchitecture] api.Network.instance = network.Network diff --git a/src/main/scala/li/cil/oc/server/component/machine/LuaJLuaArchitecture.scala b/src/main/scala/li/cil/oc/server/component/machine/LuaJLuaArchitecture.scala index 5f710a43a..26124348d 100644 --- a/src/main/scala/li/cil/oc/server/component/machine/LuaJLuaArchitecture.scala +++ b/src/main/scala/li/cil/oc/server/component/machine/LuaJLuaArchitecture.scala @@ -25,11 +25,14 @@ class LuaJLuaArchitecture(val machine: api.machine.Machine) extends Architecture private[machine] var memory = 0 + private[machine] var bootAddress = "" + private val apis = Array( new ComponentAPI(this), new ComputerAPI(this), new OSAPI(this), new SystemAPI(this), + new UnicodeAPI(this), new UserdataAPI(this)) private[machine] def invoke(f: () => Array[AnyRef]): Varargs = try { @@ -158,16 +161,18 @@ class LuaJLuaArchitecture(val machine: api.machine.Machine) extends Architecture // The kernel thread returned. If it threw we'd be in the catch below. else { // We're expecting the result of a pcall, if anything, so boolean + (result | string). - if (results.`type`(2) != LuaValue.TBOOLEAN || !(results.isstring(3) || results.isnil(3))) { + if (results.`type`(2) != LuaValue.TBOOLEAN || !(results.isstring(3) || results.isnoneornil(3))) { OpenComputers.log.warning("Kernel returned unexpected results.") } // The pcall *should* never return normally... but check for it nonetheless. - if (results.toboolean(1)) { + if (results.toboolean(2)) { OpenComputers.log.warning("Kernel stopped unexpectedly.") new ExecutionResult.Shutdown(false) } else { - val error = results.tojstring(3) + val error = + if (results.isuserdata(3)) results.touserdata(3).toString + else results.tojstring(3) if (error != null) new ExecutionResult.Error(error) else new ExecutionResult.Error("unknown error") } @@ -219,6 +224,8 @@ class LuaJLuaArchitecture(val machine: api.machine.Machine) extends Architecture // ----------------------------------------------------------------------- // override def load(nbt: NBTTagCompound) { + bootAddress = nbt.getString("bootAddress") + if (machine.isRunning) { machine.stop() machine.start() @@ -226,5 +233,8 @@ class LuaJLuaArchitecture(val machine: api.machine.Machine) extends Architecture } override def save(nbt: NBTTagCompound) { + if (bootAddress != null) { + nbt.setString("bootAddress", bootAddress) + } } } diff --git a/src/main/scala/li/cil/oc/server/component/machine/NativeLuaArchitecture.scala b/src/main/scala/li/cil/oc/server/component/machine/NativeLuaArchitecture.scala index ded56c816..9f7aad7bc 100644 --- a/src/main/scala/li/cil/oc/server/component/machine/NativeLuaArchitecture.scala +++ b/src/main/scala/li/cil/oc/server/component/machine/NativeLuaArchitecture.scala @@ -316,6 +316,8 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu private def state = machine.asInstanceOf[Machine].state override def load(nbt: NBTTagCompound) { + bootAddress = nbt.getString("bootAddress") + // Unlimit memory use while unpersisting. lua.setTotalMemory(Integer.MAX_VALUE) @@ -366,6 +368,10 @@ class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architectu } override def save(nbt: NBTTagCompound) { + if (bootAddress != null) { + nbt.setString("bootAddress", bootAddress) + } + // Unlimit memory while persisting. lua.setTotalMemory(Integer.MAX_VALUE) diff --git a/src/main/scala/li/cil/oc/server/component/machine/luaj/ComputerAPI.scala b/src/main/scala/li/cil/oc/server/component/machine/luaj/ComputerAPI.scala index 24267dadf..ff2634d1b 100644 --- a/src/main/scala/li/cil/oc/server/component/machine/luaj/ComputerAPI.scala +++ b/src/main/scala/li/cil/oc/server/component/machine/luaj/ComputerAPI.scala @@ -27,6 +27,18 @@ class ComputerAPI(owner: LuaJLuaArchitecture) extends LuaJAPI(owner) { case _ => LuaValue.NIL }) + // Get/set address of boot device. + computer.set("getBootAddress", (_: Varargs) => owner.bootAddress match { + case "" => LuaValue.NIL + case address => LuaValue.valueOf(address) + }) + + computer.set("setBootAddress", (args: Varargs) => { + if (args.isnoneornil(1)) owner.bootAddress = "" + else owner.bootAddress = args.checkjstring(1) + LuaValue.NIL + }) + computer.set("freeMemory", (_: Varargs) => LuaValue.valueOf(owner.memory / 2)) computer.set("totalMemory", (_: Varargs) => LuaValue.valueOf(owner.memory)) diff --git a/src/main/scala/li/cil/oc/server/component/machine/luaj/SystemAPI.scala b/src/main/scala/li/cil/oc/server/component/machine/luaj/SystemAPI.scala index 2eb08097e..45526f48d 100644 --- a/src/main/scala/li/cil/oc/server/component/machine/luaj/SystemAPI.scala +++ b/src/main/scala/li/cil/oc/server/component/machine/luaj/SystemAPI.scala @@ -13,7 +13,7 @@ class SystemAPI(owner: LuaJLuaArchitecture) extends LuaJAPI(owner) { system.set("allowBytecode", (_: Varargs) => LuaValue.valueOf(Settings.get.allowBytecode)) // How long programs may run without yielding before we stop them. - system.set("timeout", LuaValue.valueOf(Settings.get.timeout)) + system.set("timeout", (_: Varargs) => LuaValue.valueOf(Settings.get.timeout)) lua.set("system", system) } diff --git a/src/main/scala/li/cil/oc/util/ScalaClosure.scala b/src/main/scala/li/cil/oc/util/ScalaClosure.scala index 2e96b5c8a..07358b640 100644 --- a/src/main/scala/li/cil/oc/util/ScalaClosure.scala +++ b/src/main/scala/li/cil/oc/util/ScalaClosure.scala @@ -8,6 +8,7 @@ import scala.collection.mutable import scala.language.implicitConversions import scala.math.ScalaNumber import scala.runtime.BoxedUnit +import li.cil.oc.api.machine.Value class ScalaClosure(val f: (Varargs) => Varargs) extends VarArgFunction { override def invoke(args: Varargs) = f(args) @@ -41,6 +42,7 @@ object ScalaClosure { case value: java.lang.String => LuaValue.valueOf(value) case value: Array[Byte] => LuaValue.valueOf(value) case value: Array[_] => toLuaList(value) + case value: Value => LuaValue.userdataOf(value) case value: Product => toLuaList(value.productIterator.toIterable) case value: Seq[_] => toLuaList(value) case value: java.util.Map[_, _] => toLuaTable(value.toMap)