Add Lua 5.4 support, update LuaJ, JNLua, fix everything, break everything.

To say that this has been a long time coming would be an understatement.

This commit changes the following:

 * Updates LuaJ to 3.0.2 with many third-party patches applied. Not that
   it doesn't have obvious breaking bugs still - however, it emulates
   Lua 5.2 that little bit better now.
 * Updates JNLua in every conceivable way:
   * Now compiled with actual optimizations - ~2x better performance!
   * Updates Lua 5.2 with gamax92's backported bugfixes.
   * Updates Lua 5.3 from 5.3.2 to 5.3.6.
   * Adds experimental Lua 5.4 support (Lua 5.4.4).
   * Adds proper support for 64-bit integers (longs) in LuaState.
   * Adds official support for AArch64 on Linux and macOS.
   * Drops support for all architectures on FreeBSD and x86 on macOS.
   * Further minor bugfixes here and there.
 * Adds a Lua 5.4 architecture (behind a config option for now).
 * Updates the Lua copyright date.

Thanks to everyone who has been patient enough to wait over four years
for this to finally get upstreamed.

( No joke! https://github.com/MightyPirates/OpenComputers/pull/2898 )

Let's hope this doesn't break the world. (It probably does, though.)
This commit is contained in:
Adrian Siekierka 2022-09-04 21:05:03 +02:00
parent 62887f81a7
commit ac4d93589a
37 changed files with 164 additions and 76 deletions

View File

@ -12,7 +12,7 @@ A few useful links:
* [Community Forums][forums] * [Community Forums][forums]
### Experimental Builds ### Experimental Builds
You can find experimental builds [on the build server][jenkins]. Expect these to be generally more unstable than builds marked as releases. Use these **at your own risk**, but - when using the latest one - please *do* report bugs you encounter using them. Thanks! You can find experimental builds [on the build server][github-actions]. Expect these to be generally more unstable than builds marked as releases. Use these **at your own risk**, but - when using the latest one - please *do* report bugs you encounter using them. Thanks!
## License / Use in Modpacks ## License / Use in Modpacks
This mod is [licensed under the **MIT license**](https://github.com/MightyPirates/OpenComputers/blob/master-MC1.7.10/LICENSE). All **assets are public domain**, unless otherwise stated; all are free to be distributed as long as the license / source credits are kept. This means you can use this mod in any mod pack **as you please**. I'd be happy to hear about you using it, though, just out of curiosity. This mod is [licensed under the **MIT license**](https://github.com/MightyPirates/OpenComputers/blob/master-MC1.7.10/LICENSE). All **assets are public domain**, unless otherwise stated; all are free to be distributed as long as the license / source credits are kept. This means you can use this mod in any mod pack **as you please**. I'd be happy to hear about you using it, though, just out of curiosity.
@ -54,7 +54,7 @@ Also, and this should go without saying, your contributed code will also fall un
## Extending ## Extending
### In your own mod ### In your own mod
To use [the API][api] in your own mod, either get the API JAR from the [build server][jenkins], or if you're using [Gradle](http://gradle.org/), add a dependency to the maven repo: To use [the API][api] in your own mod, either get the API JAR from the [build server][github-actions], or if you're using [Gradle](http://gradle.org/), add a dependency to the maven repo:
```groovy ```groovy
repositories { repositories {
maven { url = "http://maven.cil.li/" } maven { url = "http://maven.cil.li/" }
@ -96,9 +96,9 @@ In the case you wish to use Eclipse rather than IntelliJ IDEA, the process is mo
[code conventions]: https://ocdoc.cil.li/lua_conventions [code conventions]: https://ocdoc.cil.li/lua_conventions
[dev-jar]: https://ci.cil.li/view/OpenComputers/job/OpenComputers-MC1.7.10/ [dev-jar]: https://ci.cil.li/view/OpenComputers/job/OpenComputers-MC1.7.10/
[forums]: https://oc.cil.li/ [forums]: https://oc.cil.li/
[github-actions]: https://github.com/MightyPirates/OpenComputers/actions
[irc]: http://webchat.esper.net/?channels=#oc [irc]: http://webchat.esper.net/?channels=#oc
[issues]: https://github.com/MightyPirates/OpenComputers/issues?state=open [issues]: https://github.com/MightyPirates/OpenComputers/issues?state=open
[jenkins]: http://ci.cil.li/
[localizations]: https://github.com/MightyPirates/OpenComputers/tree/master-MC1.7.10/src/main/resources/assets/opencomputers/lang [localizations]: https://github.com/MightyPirates/OpenComputers/tree/master-MC1.7.10/src/main/resources/assets/opencomputers/lang
[loot]: https://github.com/MightyPirates/OpenComputers/tree/master-MC1.7.10/src/main/resources/assets/opencomputers/loot [loot]: https://github.com/MightyPirates/OpenComputers/tree/master-MC1.7.10/src/main/resources/assets/opencomputers/loot
[manpages]: https://github.com/MightyPirates/OpenComputers/tree/master-MC1.7.10/src/main/resources/assets/opencomputers/loot/OpenOS/usr/man [manpages]: https://github.com/MightyPirates/OpenComputers/tree/master-MC1.7.10/src/main/resources/assets/opencomputers/loot/OpenOS/usr/man

View File

@ -157,7 +157,9 @@ dependencies {
compile 'com.google.code.findbugs:jsr305:1.3.9' // Annotations used by google libs. compile 'com.google.code.findbugs:jsr305:1.3.9' // Annotations used by google libs.
embedded files('libs/OpenComputers-JNLua.jar', 'libs/OpenComputers-LuaJ.jar') embedded name: 'OC-LuaJ', version: '20220904.0', ext: 'jar'
embedded name: 'OC-JNLua', version: '20220904.0', ext: 'jar'
embedded name: 'OC-JNLua-Natives', version: '20220904.0', ext: 'jar'
testCompile "org.mockito:mockito-all:1.10.19" testCompile "org.mockito:mockito-all:1.10.19"
testCompile "org.scalactic:scalactic_2.11:2.2.6" testCompile "org.scalactic:scalactic_2.11:2.2.6"

Binary file not shown.

Binary file not shown.

View File

@ -68,6 +68,19 @@ public interface Arguments extends Iterable<Object> {
*/ */
int checkInteger(int index); int checkInteger(int index);
/**
* Try to get a long value at the specified index.
* <br>
* Throws an error if there are too few arguments.
*
* @param index the index from which to get the argument.
* @return the long value at the specified index.
* @throws IllegalArgumentException if there is no argument at that index,
* or if the argument is not a number.
* @since OpenComputers 1.8.0
*/
long checkLong(int index);
/** /**
* Try to get a double value at the specified index. * Try to get a double value at the specified index.
* <br> * <br>
@ -188,6 +201,19 @@ public interface Arguments extends Iterable<Object> {
*/ */
int optInteger(int index, int def); int optInteger(int index, int def);
/**
* Try to get a long value at the specified index.
* <br>
* Return the specified default value if there is no such element, behaves
* like {@link #checkLong(int)} otherwise.
*
* @param index the index from which to get the argument.
* @return the long value at the specified index.
* @throws IllegalArgumentException if the argument exists but is not a number.
* @since OpenComputers 1.8.0
*/
long optLong(int index, long def);
/** /**
* Try to get a double value at the specified index. * Try to get a double value at the specified index.
* <br> * <br>
@ -273,6 +299,17 @@ public interface Arguments extends Iterable<Object> {
*/ */
boolean isInteger(int index); boolean isInteger(int index);
/**
* Tests whether the argument at the specified index is a long value.
* <br>
* This will return false if there is <em>no</em> argument at the specified
* index, i.e. if there are too few arguments.
*
* @param index the index to check.
* @return true if the argument is a long; false otherwise.
*/
boolean isLong(int index);
/** /**
* Tests whether the argument at the specified index is a double value. * Tests whether the argument at the specified index is a double value.
* <br> * <br>

View File

@ -231,6 +231,10 @@ opencomputers {
# If enabled, a crafted CPU will first be the Lua 5.3 architecture. # If enabled, a crafted CPU will first be the Lua 5.3 architecture.
defaultLua53: true defaultLua53: true
# Whether to make the Lua 5.4 architecture available. If enabled, you
# can reconfigure any CPU to use the Lua 5.4 architecture.
enableLua54: false
# The sizes of the six levels of RAM, in kilobytes. This list must # The sizes of the six levels of RAM, in kilobytes. This list must
# contain exactly six entries, or it will be ignored. Note that while # contain exactly six entries, or it will be ignored. Note that while
# there are six levels of RAM, they still fall into the three tiers of # there are six levels of RAM, they still fall into the three tiers of

View File

@ -86,7 +86,7 @@ local read_handler = {hint = function(line, index)
return hints return hints
end} end}
io.write("\27[37m".._VERSION .. " Copyright (C) 1994-2017 Lua.org, PUC-Rio\n") io.write("\27[37m".._VERSION .. " Copyright (C) 1994-2022 Lua.org, PUC-Rio\n")
io.write("\27[33mEnter a statement and hit enter to evaluate it.\n") io.write("\27[33mEnter a statement and hit enter to evaluate it.\n")
io.write("Prefix an expression with '=' to show its value.\n") io.write("Prefix an expression with '=' to show its value.\n")
io.write("Press Ctrl+D to exit the interpreter.\n\27[37m") io.write("Press Ctrl+D to exit the interpreter.\n\27[37m")

View File

@ -792,7 +792,7 @@ sandbox = {
tonumber = tonumber, tonumber = tonumber,
tostring = tostring, tostring = tostring,
type = type, type = type,
_VERSION = _VERSION:match("Luaj") and "Luaj" or _VERSION:match("5.3") and "Lua 5.3" or "Lua 5.2", _VERSION = _VERSION:match("Luaj") and "Luaj" or _VERSION:match("5.4") and "Lua 5.4" or _VERSION:match("5.3") and "Lua 5.3" or "Lua 5.2",
xpcall = function(f, msgh, ...) xpcall = function(f, msgh, ...)
local handled = false local handled = false
checkArg(2, msgh, "function") checkArg(2, msgh, "function")

View File

@ -84,6 +84,7 @@ class Settings(val config: Config) {
val allowGC = config.getBoolean("computer.lua.allowGC") val allowGC = config.getBoolean("computer.lua.allowGC")
val enableLua53 = config.getBoolean("computer.lua.enableLua53") val enableLua53 = config.getBoolean("computer.lua.enableLua53")
val defaultLua53 = config.getBoolean("computer.lua.defaultLua53") val defaultLua53 = config.getBoolean("computer.lua.defaultLua53")
val enableLua54 = config.getBoolean("computer.lua.enableLua54")
val ramSizes = Array(config.getIntList("computer.lua.ramSizes"): _*) match { val ramSizes = Array(config.getIntList("computer.lua.ramSizes"): _*) match {
case Array(tier1, tier2, tier3, tier4, tier5, tier6) => case Array(tier1, tier2, tier3, tier4, tier5, tier6) =>
Array(tier1: Int, tier2: Int, tier3: Int, tier4: Int, tier5: Int, tier6: Int) Array(tier1: Int, tier2: Int, tier3: Int, tier4: Int, tier5: Int, tier6: Int)
@ -567,7 +568,7 @@ object Settings {
"misc.maxOpenPorts", "misc.maxOpenPorts",
"computer.cpuComponentCount" "computer.cpuComponentCount"
), ),
// Upgrading to version 1.8.0, changed meaning of limitFlightHeight value. // Upgrading to version 1.8.0, changed meaning of limitFlightHeight value,
VersionRange.createFromVersionSpec("[0.0, 1.8.0)") -> Array( VersionRange.createFromVersionSpec("[0.0, 1.8.0)") -> Array(
"computer.robot.limitFlightHeight" "computer.robot.limitFlightHeight"
) )

View File

@ -16,9 +16,7 @@ import li.cil.oc.common.item.traits.Delegate
import li.cil.oc.common.recipe.Recipes import li.cil.oc.common.recipe.Recipes
import li.cil.oc.integration.Mods import li.cil.oc.integration.Mods
import li.cil.oc.server._ import li.cil.oc.server._
import li.cil.oc.server.machine.luac.LuaStateFactory import li.cil.oc.server.machine.luac.{LuaStateFactory, NativeLua52Architecture, NativeLua53Architecture, NativeLua54Architecture}
import li.cil.oc.server.machine.luac.NativeLua52Architecture
import li.cil.oc.server.machine.luac.NativeLua53Architecture
import li.cil.oc.server.machine.luaj.LuaJLuaArchitecture import li.cil.oc.server.machine.luaj.LuaJLuaArchitecture
import net.minecraft.item.Item import net.minecraft.item.Item
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
@ -73,20 +71,16 @@ class Proxy {
api.API.config = Settings.get.config api.API.config = Settings.get.config
// Weird JNLua bug identified if (LuaStateFactory.isAvailable) {
// When loading JNLua (for either 5.2 or 5.3 lua state) there is a static section that the library loads if (LuaStateFactory.include53) {
// being static, it loads once regardless of which lua state is loaded first api.Machine.add(classOf[NativeLua53Architecture])
// static { REGISTRYINDEX = lua_registryindex(); } }
// The problem is that lua_registryindex was removed in 5.3 if (LuaStateFactory.include54) {
// Thus, if we load JNLua from a lua5.3 state first, this static section fails api.Machine.add(classOf[NativeLua54Architecture])
// We must load 5.2 first, AND we know 5.3 will likely fail to load if 5.2 failed }
val include52: Boolean = LuaStateFactory.include52 if (LuaStateFactory.include52) {
// now that JNLua has been initialized from a lua52 state, we are safe to check 5.3 api.Machine.add(classOf[NativeLua52Architecture])
if (LuaStateFactory.include53) { }
api.Machine.add(classOf[NativeLua53Architecture])
}
if (include52) {
api.Machine.add(classOf[NativeLua52Architecture])
} }
if (LuaStateFactory.includeLuaJ) { if (LuaStateFactory.includeLuaJ) {
api.Machine.add(classOf[LuaJLuaArchitecture]) api.Machine.add(classOf[LuaJLuaArchitecture])

View File

@ -185,7 +185,7 @@ private[oc] object Registry extends api.detail.DriverAPI {
case arg: java.lang.Long => arg case arg: java.lang.Long => arg
case arg: java.lang.Float => arg case arg: java.lang.Float => arg
case arg: java.lang.Double => arg case arg: java.lang.Double => arg
case arg: java.lang.Number => Double.box(arg.doubleValue()) case arg: java.lang.Number => Double.box(arg.doubleValue)
case arg: java.lang.String => arg case arg: java.lang.String => arg
case arg: Array[Boolean] => arg case arg: Array[Boolean] => arg

View File

@ -70,6 +70,19 @@ class ArgumentsImpl(val args: Seq[AnyRef]) extends Arguments {
else checkInteger(index) else checkInteger(index)
} }
def checkLong(index: Int) = {
checkIndex(index, "number")
args(index) match {
case value: java.lang.Number => value.longValue
case value => throw typeError(index, value, "number")
}
}
def optLong(index: Int, default: Long) = {
if (!isDefined(index)) default
else checkLong(index)
}
def checkString(index: Int) = { def checkString(index: Int) = {
checkIndex(index, "string") checkIndex(index, "string")
args(index) match { args(index) match {
@ -159,6 +172,8 @@ class ArgumentsImpl(val args: Seq[AnyRef]) extends Arguments {
case _ => false case _ => false
}) })
def isLong(index: Int) = isInteger(index)
def isString(index: Int) = def isString(index: Int) =
index >= 0 && index < count && (args(index) match { index >= 0 && index < count && (args(index) match {
case value: java.lang.String => true case value: java.lang.String => true
@ -210,6 +225,10 @@ class ArgumentsImpl(val args: Seq[AnyRef]) extends Arguments {
private def typeName(value: AnyRef): String = value match { private def typeName(value: AnyRef): String = value match {
case null | Unit | None => "nil" case null | Unit | None => "nil"
case _: java.lang.Boolean => "boolean" case _: java.lang.Boolean => "boolean"
case _: java.lang.Byte => "integer"
case _: java.lang.Short => "integer"
case _: java.lang.Integer => "integer"
case _: java.lang.Long => "integer"
case _: java.lang.Number => "double" case _: java.lang.Number => "double"
case _: java.lang.String => "string" case _: java.lang.String => "string"
case _: Array[Byte] => "string" case _: Array[Byte] => "string"

View File

@ -312,7 +312,10 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
def convertArg(param: Any): AnyRef = { def convertArg(param: Any): AnyRef = {
param match { param match {
case arg: java.lang.Boolean => arg case arg: java.lang.Boolean => arg
case arg: java.lang.Character => Double.box(arg.toDouble) case arg: java.lang.Character => Integer.valueOf(arg.toInt)
case arg: java.lang.Byte => arg
case arg: java.lang.Short => arg
case arg: java.lang.Integer => arg
case arg: java.lang.Long => arg case arg: java.lang.Long => arg
case arg: java.lang.Number => Double.box(arg.doubleValue) case arg: java.lang.Number => Double.box(arg.doubleValue)
case arg: java.lang.String => arg case arg: java.lang.String => arg

View File

@ -15,7 +15,6 @@ import li.cil.oc.api.machine.Architecture
import li.cil.oc.server.machine.Machine import li.cil.oc.server.machine.Machine
import li.cil.oc.util.ExtendedLuaState._ import li.cil.oc.util.ExtendedLuaState._
import li.cil.repack.com.naef.jnlua import li.cil.repack.com.naef.jnlua
import li.cil.repack.com.naef.jnlua.NativeSupport.Loader
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import org.apache.commons.lang3.SystemUtils import org.apache.commons.lang3.SystemUtils
@ -23,10 +22,11 @@ import scala.util.Random
object LuaStateFactory { object LuaStateFactory {
def isAvailable: Boolean = { def isAvailable: Boolean = {
// Force initialization of both. // Force initialization of all.
val lua52 = Lua52.isAvailable val lua52 = Lua52.isAvailable
val lua53 = Lua53.isAvailable val lua53 = Lua53.isAvailable
lua52 || lua53 val lua54 = Lua54.isAvailable
lua52 || lua53 || lua54
} }
def luajRequested: Boolean = Settings.get.forceLuaJ || Settings.get.registerLuaJArchitecture def luajRequested: Boolean = Settings.get.forceLuaJ || Settings.get.registerLuaJArchitecture
@ -37,6 +37,8 @@ object LuaStateFactory {
def include53: Boolean = Lua53.isAvailable && Settings.get.enableLua53 && !Settings.get.forceLuaJ def include53: Boolean = Lua53.isAvailable && Settings.get.enableLua53 && !Settings.get.forceLuaJ
def include54: Boolean = Lua54.isAvailable && Settings.get.enableLua54 && !Settings.get.forceLuaJ
def default53: Boolean = include53 && Settings.get.defaultLua53 def default53: Boolean = include53 && Settings.get.defaultLua53
def setDefaultArch(stack: ItemStack): ItemStack = { def setDefaultArch(stack: ItemStack): ItemStack = {
@ -53,7 +55,7 @@ object LuaStateFactory {
} }
object Lua52 extends LuaStateFactory { object Lua52 extends LuaStateFactory {
override def version: String = "lua52" override def version: String = "52"
override protected def create(maxMemory: Option[Int]) = maxMemory.fold(new jnlua.LuaState())(new jnlua.LuaState(_)) override protected def create(maxMemory: Option[Int]) = maxMemory.fold(new jnlua.LuaState())(new jnlua.LuaState(_))
@ -71,7 +73,7 @@ object LuaStateFactory {
} }
object Lua53 extends LuaStateFactory { object Lua53 extends LuaStateFactory {
override def version: String = "lua53" override def version: String = "53"
override protected def create(maxMemory: Option[Int]) = maxMemory.fold(new jnlua.LuaStateFiveThree())(new jnlua.LuaStateFiveThree(_)) override protected def create(maxMemory: Option[Int]) = maxMemory.fold(new jnlua.LuaStateFiveThree())(new jnlua.LuaStateFiveThree(_))
@ -88,6 +90,24 @@ object LuaStateFactory {
} }
} }
object Lua54 extends LuaStateFactory {
override def version: String = "54"
override protected def create(maxMemory: Option[Int]) = maxMemory.fold(new jnlua.LuaStateFiveFour())(new jnlua.LuaStateFiveFour(_))
override protected def openLibs(state: jnlua.LuaState): Unit = {
state.openLib(jnlua.LuaState.Library.BASE)
state.openLib(jnlua.LuaState.Library.COROUTINE)
state.openLib(jnlua.LuaState.Library.DEBUG)
state.openLib(jnlua.LuaState.Library.ERIS)
state.openLib(jnlua.LuaState.Library.MATH)
state.openLib(jnlua.LuaState.Library.STRING)
state.openLib(jnlua.LuaState.Library.TABLE)
state.openLib(jnlua.LuaState.Library.UTF8)
state.pop(8)
}
}
} }
/** /**
@ -112,34 +132,35 @@ abstract class LuaStateFactory {
private val libraryName = { private val libraryName = {
if (!Strings.isNullOrEmpty(Settings.get.forceNativeLib)) Settings.get.forceNativeLib if (!Strings.isNullOrEmpty(Settings.get.forceNativeLib)) Settings.get.forceNativeLib
else if (SystemUtils.IS_OS_FREE_BSD && Architecture.IS_OS_X64) "native.64.bsd.so" else {
else if (SystemUtils.IS_OS_FREE_BSD && Architecture.IS_OS_X86) "native.32.bsd.so" val libExtension = {
if (SystemUtils.IS_OS_MAC) ".dylib"
else if (SystemUtils.IS_OS_WINDOWS) ".dll"
else ".so"
}
else if (SystemUtils.IS_OS_LINUX && Architecture.IS_OS_ARM) "native.32.arm.so" val systemName = {
else if (SystemUtils.IS_OS_LINUX && Architecture.IS_OS_X64) "native.64.so" if (SystemUtils.IS_OS_FREE_BSD) "freebsd"
else if (SystemUtils.IS_OS_LINUX && Architecture.IS_OS_X86) "native.32.so" else if (SystemUtils.IS_OS_NET_BSD) "netbsd"
else if (SystemUtils.IS_OS_OPEN_BSD) "openbsd"
else if (SystemUtils.IS_OS_SOLARIS) "solaris"
else if (SystemUtils.IS_OS_LINUX) "linux"
else if (SystemUtils.IS_OS_MAC) "darwin"
else if (SystemUtils.IS_OS_WINDOWS) "windows"
else "unknown"
}
else if (SystemUtils.IS_OS_MAC && Architecture.IS_OS_X64) "native.64.dylib" val archName = {
else if (SystemUtils.IS_OS_MAC && Architecture.IS_OS_X86) "native.32.dylib" if (Architecture.IS_OS_ARM64) "aarch64"
else if (Architecture.IS_OS_ARM) "arm"
else if (Architecture.IS_OS_X64) "x86_64"
else if (Architecture.IS_OS_X86) "x86"
else "unknown"
}
else if (SystemUtils.IS_OS_WINDOWS && Architecture.IS_OS_X64) "native.64.dll" "libjnlua" + version + "-" + systemName + "-" + archName + libExtension
else if (SystemUtils.IS_OS_WINDOWS && Architecture.IS_OS_X86) "native.32.dll"
else null
}
// Register a custom library loader with JNLua. We have to trigger
// library loads through JNLua to ensure the LuaState class is the
// one loading the library and not the other way around - the native
// library also references the LuaState class, and if it is loaded
// that way, it will fail to access native methods in its static
// initializer, because the native lib will not have been completely
// loaded at the time the initializer runs.
private def prepareLoad(lib: String): Unit = jnlua.NativeSupport.getInstance().setLoader(new Loader {
def load(): Unit = {
System.load(lib)
} }
}) }
protected def create(maxMemory: Option[Int] = None): jnlua.LuaState protected def create(maxMemory: Option[Int] = None): jnlua.LuaState
@ -173,7 +194,7 @@ abstract class LuaStateFactory {
} }
} }
val libraryUrl = classOf[Machine].getResource(s"/assets/${Settings.resourceDomain}/lib/$version/$libraryName") val libraryUrl = classOf[Machine].getResource(s"/assets/${Settings.resourceDomain}/lib/$libraryName")
if (libraryUrl == null) { if (libraryUrl == null) {
OpenComputers.log.warn(s"Native library with name '$version/$libraryName' not found.") OpenComputers.log.warn(s"Native library with name '$version/$libraryName' not found.")
return return
@ -277,7 +298,7 @@ abstract class LuaStateFactory {
currentLib = tmpLibFile.getAbsolutePath currentLib = tmpLibFile.getAbsolutePath
try { try {
LuaStateFactory.synchronized { LuaStateFactory.synchronized {
prepareLoad(currentLib) System.load(currentLib)
create().close() create().close()
} }
OpenComputers.log.info(s"Found a compatible native library: '${tmpLibFile.getName}'.") OpenComputers.log.info(s"Found a compatible native library: '${tmpLibFile.getName}'.")
@ -286,7 +307,7 @@ abstract class LuaStateFactory {
catch { catch {
case t: Throwable => case t: Throwable =>
if (Settings.get.logFullLibLoadErrors) { if (Settings.get.logFullLibLoadErrors) {
OpenComputers.log.trace(s"Could not load native library '${tmpLibFile.getName}'.", t) OpenComputers.log.warn(s"Could not load native library '${tmpLibFile.getName}'.", t)
} }
else { else {
OpenComputers.log.trace(s"Could not load native library '${tmpLibFile.getName}'.") OpenComputers.log.trace(s"Could not load native library '${tmpLibFile.getName}'.")
@ -310,7 +331,7 @@ abstract class LuaStateFactory {
try { try {
val state = LuaStateFactory.synchronized { val state = LuaStateFactory.synchronized {
prepareLoad(currentLib) System.load(currentLib)
if (Settings.get.limitMemory) create(Some(Int.MaxValue)) if (Settings.get.limitMemory) create(Some(Int.MaxValue))
else create() else create()
} }
@ -376,7 +397,7 @@ abstract class LuaStateFactory {
state.setField(-2, "random") state.setField(-2, "random")
state.pushScalaFunction(lua => { state.pushScalaFunction(lua => {
random.setSeed(lua.checkNumber(1).toLong) random.setSeed(lua.checkInteger(1))
0 0
}) })
state.setField(-2, "randomseed") state.setField(-2, "randomseed")
@ -409,6 +430,8 @@ abstract class LuaStateFactory {
val IS_OS_ARM = isOSArchMatch("arm") val IS_OS_ARM = isOSArchMatch("arm")
val IS_OS_ARM64 = isOSArchMatch("aarch64")
val IS_OS_X86 = isOSArchMatch("x86") || isOSArchMatch("i386") val IS_OS_X86 = isOSArchMatch("x86") || isOSArchMatch("i386")
val IS_OS_X64 = isOSArchMatch("x86_64") || isOSArchMatch("amd64") val IS_OS_X64 = isOSArchMatch("x86_64") || isOSArchMatch("amd64")

View File

@ -30,6 +30,11 @@ class NativeLua53Architecture(machine: api.machine.Machine) extends NativeLuaArc
override def factory = LuaStateFactory.Lua53 override def factory = LuaStateFactory.Lua53
} }
@Architecture.Name("Lua 5.4")
class NativeLua54Architecture(machine: api.machine.Machine) extends NativeLuaArchitecture(machine) {
override def factory = LuaStateFactory.Lua54
}
abstract class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architecture { abstract class NativeLuaArchitecture(val machine: api.machine.Machine) extends Architecture {
protected def factory: LuaStateFactory protected def factory: LuaStateFactory

View File

@ -25,7 +25,7 @@ class OSAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) {
else "%d/%m/%y %H:%M:%S" else "%d/%m/%y %H:%M:%S"
val time = val time =
if (lua.getTop > 1 && lua.isNumber(2)) lua.toNumber(2) if (lua.getTop > 1 && lua.isNumber(2)) lua.toNumber(2)
else (machine.worldTime + 6000) * 60 * 60 / 1000 else ((machine.worldTime + 6000) * 60 * 60) / 1000.0
val dt = GameTimeFormatter.parse(time) val dt = GameTimeFormatter.parse(time)
def fmt(format: String) { def fmt(format: String) {
@ -70,7 +70,7 @@ class OSAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) {
// starts days at 6 o'clock, versus the 1 o'clock of timestamps so we // starts days at 6 o'clock, versus the 1 o'clock of timestamps so we
// add those five hours. Thus: // add those five hours. Thus:
// timestamp = (time + 5000) * 60[kh] * 60[km] / 1000[s] // timestamp = (time + 5000) * 60[kh] * 60[km] / 1000[s]
lua.pushNumber((machine.worldTime + 5000) * 60 * 60 / 1000) lua.pushNumber(((machine.worldTime + 5000) * 60 * 60) / 1000.0)
} }
else { else {
def getField(key: String, d: Int) = { def getField(key: String, d: Int) = {
@ -80,7 +80,7 @@ class OSAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) {
if (res == null) if (res == null)
if (d < 0) throw new Exception("field '" + key + "' missing in date table") if (d < 0) throw new Exception("field '" + key + "' missing in date table")
else d else d
else res: Int else res.intValue()
} }
lua.checkType(1, LuaType.TABLE) lua.checkType(1, LuaType.TABLE)

View File

@ -85,8 +85,8 @@ class PersistenceAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) {
lua.getGlobal("_G") /* ... perms uperms k v */ lua.getGlobal("_G") /* ... perms uperms k v */
flattenAndStore() /* ... perms uperms */ flattenAndStore() /* ... perms uperms */
lua.setField(LuaState.REGISTRYINDEX, "uperms") /* ... perms */ lua.setField(lua.getRegistryIndex, "uperms") /* ... perms */
lua.setField(LuaState.REGISTRYINDEX, "perms") /* ... */ lua.setField(lua.getRegistryIndex, "perms") /* ... */
} }
} }
@ -126,7 +126,7 @@ class PersistenceAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) {
lua.getGlobal("eris") // ... eris lua.getGlobal("eris") // ... eris
lua.getField(-1, "persist") // ... eris persist lua.getField(-1, "persist") // ... eris persist
if (lua.isFunction(-1)) { if (lua.isFunction(-1)) {
lua.getField(LuaState.REGISTRYINDEX, "perms") // ... eris persist perms lua.getField(lua.getRegistryIndex, "perms") // ... eris persist perms
lua.pushValue(index) // ... eris persist perms obj lua.pushValue(index) // ... eris persist perms obj
try { try {
lua.call(2, 1) // ... eris str? lua.call(2, 1) // ... eris str?
@ -159,7 +159,7 @@ class PersistenceAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) {
lua.getGlobal("eris") // ... eris lua.getGlobal("eris") // ... eris
lua.getField(-1, "unpersist") // ... eris unpersist lua.getField(-1, "unpersist") // ... eris unpersist
if (lua.isFunction(-1)) { if (lua.isFunction(-1)) {
lua.getField(LuaState.REGISTRYINDEX, "uperms") // ... eris persist uperms lua.getField(lua.getRegistryIndex, "uperms") // ... eris persist uperms
lua.pushByteArray(value) // ... eris unpersist uperms str lua.pushByteArray(value) // ... eris unpersist uperms str
lua.call(2, 1) // ... eris obj lua.call(2, 1) // ... eris obj
lua.insert(-2) // ... obj eris lua.insert(-2) // ... obj eris

View File

@ -11,7 +11,7 @@ class SystemAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) {
println((1 to lua.getTop).map(i => lua.`type`(i) match { println((1 to lua.getTop).map(i => lua.`type`(i) match {
case LuaType.NIL => "nil" case LuaType.NIL => "nil"
case LuaType.BOOLEAN => lua.toBoolean(i) case LuaType.BOOLEAN => lua.toBoolean(i)
case LuaType.NUMBER => lua.toNumber(i) case LuaType.NUMBER => if (lua.isInteger(i)) lua.toInteger(i) else lua.toNumber(i)
case LuaType.STRING => lua.toString(i) case LuaType.STRING => lua.toString(i)
case LuaType.TABLE => "table" case LuaType.TABLE => "table"
case LuaType.FUNCTION => "function" case LuaType.FUNCTION => "function"

View File

@ -11,7 +11,7 @@ class UnicodeAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) {
lua.pushScalaFunction(lua => { lua.pushScalaFunction(lua => {
val builder = new java.lang.StringBuilder() val builder = new java.lang.StringBuilder()
(1 to lua.getTop).map(lua.checkInteger).foreach(builder.appendCodePoint) (1 to lua.getTop).map(lua.checkInt32).foreach(builder.appendCodePoint)
lua.pushString(builder.toString) lua.pushString(builder.toString)
1 1
}) })
@ -39,12 +39,12 @@ class UnicodeAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) {
lua.pushScalaFunction(lua => { lua.pushScalaFunction(lua => {
val string = lua.checkString(1) val string = lua.checkString(1)
val sLength = ExtendedUnicodeHelper.length(string) val sLength = ExtendedUnicodeHelper.length(string)
val start = lua.checkInteger(2) match { val start = lua.checkInt32(2) match {
case i if i < 0 => string.offsetByCodePoints(string.length, math.max(i, -sLength)) case i if i < 0 => string.offsetByCodePoints(string.length, math.max(i, -sLength))
case i => string.offsetByCodePoints(0, math.min(i - 1, sLength)) case i => string.offsetByCodePoints(0, math.min(i - 1, sLength))
} }
val end = val end =
if (lua.getTop > 2) lua.checkInteger(3) match { if (lua.getTop > 2) lua.checkInt32(3) match {
case i if i < 0 => string.offsetByCodePoints(string.length, math.max(i + 1, -sLength)) case i if i < 0 => string.offsetByCodePoints(string.length, math.max(i + 1, -sLength))
case i => string.offsetByCodePoints(0, math.min(i, sLength)) case i => string.offsetByCodePoints(0, math.min(i, sLength))
} }

View File

@ -39,11 +39,11 @@ object ExtendedLuaState {
}) match { }) match {
case null | Unit | _: BoxedUnit => lua.pushNil() case null | Unit | _: BoxedUnit => lua.pushNil()
case value: java.lang.Boolean => lua.pushBoolean(value.booleanValue) case value: java.lang.Boolean => lua.pushBoolean(value.booleanValue)
case value: java.lang.Byte => lua.pushNumber(value.byteValue) case value: java.lang.Byte => lua.pushInteger(value.byteValue)
case value: java.lang.Character => lua.pushString(String.valueOf(value)) case value: java.lang.Character => lua.pushString(String.valueOf(value))
case value: java.lang.Short => lua.pushNumber(value.shortValue) case value: java.lang.Short => lua.pushInteger(value.shortValue)
case value: java.lang.Integer => lua.pushNumber(value.intValue) case value: java.lang.Integer => lua.pushInteger(value.intValue)
case value: java.lang.Long => lua.pushNumber(value.longValue) case value: java.lang.Long => lua.pushInteger(value.longValue)
case value: java.lang.Float => lua.pushNumber(value.floatValue) case value: java.lang.Float => lua.pushNumber(value.floatValue)
case value: java.lang.Double => lua.pushNumber(value.doubleValue) case value: java.lang.Double => lua.pushNumber(value.doubleValue)
case value: java.lang.String => lua.pushString(value) case value: java.lang.String => lua.pushString(value)
@ -108,7 +108,7 @@ object ExtendedLuaState {
def toSimpleJavaObject(index: Int): AnyRef = lua.`type`(index) match { def toSimpleJavaObject(index: Int): AnyRef = lua.`type`(index) match {
case LuaType.BOOLEAN => Boolean.box(lua.toBoolean(index)) case LuaType.BOOLEAN => Boolean.box(lua.toBoolean(index))
case LuaType.NUMBER => Double.box(lua.toNumber(index)) case LuaType.NUMBER => if (lua.isInteger(index)) Long.box(lua.toInteger(index)) else Double.box(lua.toNumber(index))
case LuaType.STRING => lua.toByteArray(index) case LuaType.STRING => lua.toByteArray(index)
case LuaType.TABLE => lua.toJavaObject(index, classOf[java.util.Map[_, _]]) case LuaType.TABLE => lua.toJavaObject(index, classOf[java.util.Map[_, _]])
case LuaType.USERDATA => lua.toJavaObjectRaw(index) case LuaType.USERDATA => lua.toJavaObjectRaw(index)