mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-17 03:05:30 -04:00
catching error when creating lua state due to missing libraries in factory and logging it right there, to allow printing error to chat the first time, too; different name the lib is saved to the tmp folder to reduce the chance of collisions; explicit message for windows users reminding them to install the vc2012 runtimes on library load errors
This commit is contained in:
parent
fb6f0a8866
commit
55524c4a78
@ -5,6 +5,7 @@ import com.naef.jnlua.{LuaState, NativeSupport}
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.nio.channels.Channels
|
import java.nio.channels.Channels
|
||||||
|
import java.util.logging.Level
|
||||||
import li.cil.oc.server.component.Computer
|
import li.cil.oc.server.component.Computer
|
||||||
import li.cil.oc.util.ExtendedLuaState._
|
import li.cil.oc.util.ExtendedLuaState._
|
||||||
import li.cil.oc.{OpenComputers, Settings}
|
import li.cil.oc.{OpenComputers, Settings}
|
||||||
@ -27,6 +28,8 @@ object LuaStateFactory {
|
|||||||
/** Set to true in initialization code below if available. */
|
/** Set to true in initialization code below if available. */
|
||||||
private var haveNativeLibrary = false
|
private var haveNativeLibrary = false
|
||||||
|
|
||||||
|
private var isWindows = false
|
||||||
|
|
||||||
private var _is64Bit = false
|
private var _is64Bit = false
|
||||||
|
|
||||||
def is64Bit = _is64Bit
|
def is64Bit = _is64Bit
|
||||||
@ -76,6 +79,7 @@ object LuaStateFactory {
|
|||||||
break()
|
break()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
isWindows = extension == ".dll"
|
||||||
val libPath = "/assets/" + Settings.resourceDomain + "/lib/"
|
val libPath = "/assets/" + Settings.resourceDomain + "/lib/"
|
||||||
|
|
||||||
val tmpPath = {
|
val tmpPath = {
|
||||||
@ -92,7 +96,7 @@ object LuaStateFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Found file with proper extension. Create a temporary file.
|
// Found file with proper extension. Create a temporary file.
|
||||||
val file = new File(tmpPath + library)
|
val file = new File(tmpPath + "OpenComputersMod-" + library)
|
||||||
// Try to delete an old instance of the library, in case we have an update
|
// Try to delete an old instance of the library, in case we have an update
|
||||||
// and deleteOnExit fails (which it regularly does on Windows it seems).
|
// and deleteOnExit fails (which it regularly does on Windows it seems).
|
||||||
try {
|
try {
|
||||||
@ -145,145 +149,160 @@ object LuaStateFactory {
|
|||||||
def createState(): Option[LuaState] = {
|
def createState(): Option[LuaState] = {
|
||||||
if (!haveNativeLibrary) return None
|
if (!haveNativeLibrary) return None
|
||||||
|
|
||||||
val state = new LuaState(Int.MaxValue)
|
|
||||||
try {
|
try {
|
||||||
// Load all libraries.
|
val state = new LuaState(Int.MaxValue)
|
||||||
state.openLib(LuaState.Library.BASE)
|
try {
|
||||||
state.openLib(LuaState.Library.BIT32)
|
// Load all libraries.
|
||||||
state.openLib(LuaState.Library.COROUTINE)
|
state.openLib(LuaState.Library.BASE)
|
||||||
state.openLib(LuaState.Library.DEBUG)
|
state.openLib(LuaState.Library.BIT32)
|
||||||
state.openLib(LuaState.Library.ERIS)
|
state.openLib(LuaState.Library.COROUTINE)
|
||||||
state.openLib(LuaState.Library.MATH)
|
state.openLib(LuaState.Library.DEBUG)
|
||||||
state.openLib(LuaState.Library.STRING)
|
state.openLib(LuaState.Library.ERIS)
|
||||||
state.openLib(LuaState.Library.TABLE)
|
state.openLib(LuaState.Library.MATH)
|
||||||
state.pop(8)
|
state.openLib(LuaState.Library.STRING)
|
||||||
|
state.openLib(LuaState.Library.TABLE)
|
||||||
|
state.pop(8)
|
||||||
|
|
||||||
// Prepare table for os stuff.
|
// Prepare table for os stuff.
|
||||||
state.newTable()
|
state.newTable()
|
||||||
state.setGlobal("os")
|
state.setGlobal("os")
|
||||||
|
|
||||||
// Kill compat entries.
|
// Kill compat entries.
|
||||||
state.pushNil()
|
state.pushNil()
|
||||||
state.setGlobal("unpack")
|
state.setGlobal("unpack")
|
||||||
state.pushNil()
|
state.pushNil()
|
||||||
state.setGlobal("loadstring")
|
state.setGlobal("loadstring")
|
||||||
state.getGlobal("math")
|
state.getGlobal("math")
|
||||||
state.pushNil()
|
state.pushNil()
|
||||||
state.setField(-2, "log10")
|
state.setField(-2, "log10")
|
||||||
state.pop(1)
|
state.pop(1)
|
||||||
state.getGlobal("table")
|
state.getGlobal("table")
|
||||||
state.pushNil()
|
state.pushNil()
|
||||||
state.setField(-2, "maxn")
|
state.setField(-2, "maxn")
|
||||||
state.pop(1)
|
state.pop(1)
|
||||||
|
|
||||||
// Remove some other functions we don't need and are dangerous.
|
// Remove some other functions we don't need and are dangerous.
|
||||||
state.pushNil()
|
state.pushNil()
|
||||||
state.setGlobal("dofile")
|
state.setGlobal("dofile")
|
||||||
state.pushNil()
|
state.pushNil()
|
||||||
state.setGlobal("loadfile")
|
state.setGlobal("loadfile")
|
||||||
|
|
||||||
state.getGlobal("math")
|
state.getGlobal("math")
|
||||||
|
|
||||||
// We give each Lua state it's own randomizer, since otherwise they'd
|
// We give each Lua state it's own randomizer, since otherwise they'd
|
||||||
// use the good old rand() from C. Which can be terrible, and isn't
|
// use the good old rand() from C. Which can be terrible, and isn't
|
||||||
// necessarily thread-safe.
|
// necessarily thread-safe.
|
||||||
val random = new Random
|
val random = new Random
|
||||||
state.pushScalaFunction(lua => {
|
state.pushScalaFunction(lua => {
|
||||||
lua.getTop match {
|
lua.getTop match {
|
||||||
case 0 => lua.pushNumber(random.nextDouble())
|
case 0 => lua.pushNumber(random.nextDouble())
|
||||||
case 1 =>
|
case 1 =>
|
||||||
val u = lua.checkInteger(1)
|
val u = lua.checkInteger(1)
|
||||||
lua.checkArg(1, 1 < u, "interval is empty")
|
lua.checkArg(1, 1 < u, "interval is empty")
|
||||||
lua.pushInteger(1 + random.nextInt(u))
|
lua.pushInteger(1 + random.nextInt(u))
|
||||||
case 2 =>
|
case 2 =>
|
||||||
val l = lua.checkInteger(1)
|
val l = lua.checkInteger(1)
|
||||||
val u = lua.checkInteger(2)
|
val u = lua.checkInteger(2)
|
||||||
lua.checkArg(1, l < u, "interval is empty")
|
lua.checkArg(1, l < u, "interval is empty")
|
||||||
lua.pushInteger(l + random.nextInt(u - (l - 1)))
|
lua.pushInteger(l + random.nextInt(u - (l - 1)))
|
||||||
case _ => throw new IllegalArgumentException("wrong number of arguments")
|
case _ => throw new IllegalArgumentException("wrong number of arguments")
|
||||||
}
|
}
|
||||||
1
|
1
|
||||||
})
|
|
||||||
state.setField(-2, "random")
|
|
||||||
|
|
||||||
state.pushScalaFunction(lua => {
|
|
||||||
random.setSeed(lua.checkInteger(1))
|
|
||||||
0
|
|
||||||
})
|
|
||||||
state.setField(-2, "randomseed")
|
|
||||||
|
|
||||||
// Pop the math table.
|
|
||||||
state.pop(1)
|
|
||||||
|
|
||||||
// Provide some better Unicode support.
|
|
||||||
state.newTable()
|
|
||||||
|
|
||||||
// TODO find (probably not necessary?)
|
|
||||||
|
|
||||||
// TODO format (probably not necessary?)
|
|
||||||
|
|
||||||
// TODO gmatch (probably not necessary?)
|
|
||||||
|
|
||||||
// TODO gsub (probably not necessary?)
|
|
||||||
|
|
||||||
// TODO match (probably not necessary?)
|
|
||||||
|
|
||||||
state.pushScalaFunction(lua => {
|
|
||||||
lua.pushString(lua.checkString(1).toLowerCase)
|
|
||||||
1
|
|
||||||
})
|
|
||||||
state.setField(-2, "lower")
|
|
||||||
|
|
||||||
state.pushScalaFunction(lua => {
|
|
||||||
lua.pushString(lua.checkString(1).toUpperCase)
|
|
||||||
1
|
|
||||||
})
|
|
||||||
state.setField(-2, "upper")
|
|
||||||
|
|
||||||
state.pushScalaFunction(lua => {
|
|
||||||
lua.pushString(String.valueOf((1 to lua.getTop).map(lua.checkInteger).map(_.toChar).toArray))
|
|
||||||
1
|
|
||||||
})
|
|
||||||
state.setField(-2, "char")
|
|
||||||
|
|
||||||
state.pushScalaFunction(lua => {
|
|
||||||
lua.pushInteger(lua.checkString(1).length)
|
|
||||||
1
|
|
||||||
})
|
|
||||||
state.setField(-2, "len")
|
|
||||||
|
|
||||||
state.pushScalaFunction(lua => {
|
|
||||||
lua.pushString(lua.checkString(1).reverse)
|
|
||||||
1
|
|
||||||
})
|
|
||||||
state.setField(-2, "reverse")
|
|
||||||
|
|
||||||
state.pushScalaFunction(lua => {
|
|
||||||
val string = lua.checkString(1)
|
|
||||||
val start = math.max(0, lua.checkInteger(2) match {
|
|
||||||
case i if i < 0 => string.length + i
|
|
||||||
case i => i - 1
|
|
||||||
})
|
})
|
||||||
val end =
|
state.setField(-2, "random")
|
||||||
if (lua.getTop > 2) math.min(string.length, lua.checkInteger(3) match {
|
|
||||||
case i if i < 0 => string.length + i + 1
|
state.pushScalaFunction(lua => {
|
||||||
case i => i
|
random.setSeed(lua.checkInteger(1))
|
||||||
|
0
|
||||||
|
})
|
||||||
|
state.setField(-2, "randomseed")
|
||||||
|
|
||||||
|
// Pop the math table.
|
||||||
|
state.pop(1)
|
||||||
|
|
||||||
|
// Provide some better Unicode support.
|
||||||
|
state.newTable()
|
||||||
|
|
||||||
|
// TODO find (probably not necessary?)
|
||||||
|
|
||||||
|
// TODO format (probably not necessary?)
|
||||||
|
|
||||||
|
// TODO gmatch (probably not necessary?)
|
||||||
|
|
||||||
|
// TODO gsub (probably not necessary?)
|
||||||
|
|
||||||
|
// TODO match (probably not necessary?)
|
||||||
|
|
||||||
|
state.pushScalaFunction(lua => {
|
||||||
|
lua.pushString(lua.checkString(1).toLowerCase)
|
||||||
|
1
|
||||||
|
})
|
||||||
|
state.setField(-2, "lower")
|
||||||
|
|
||||||
|
state.pushScalaFunction(lua => {
|
||||||
|
lua.pushString(lua.checkString(1).toUpperCase)
|
||||||
|
1
|
||||||
|
})
|
||||||
|
state.setField(-2, "upper")
|
||||||
|
|
||||||
|
state.pushScalaFunction(lua => {
|
||||||
|
lua.pushString(String.valueOf((1 to lua.getTop).map(lua.checkInteger).map(_.toChar).toArray))
|
||||||
|
1
|
||||||
|
})
|
||||||
|
state.setField(-2, "char")
|
||||||
|
|
||||||
|
state.pushScalaFunction(lua => {
|
||||||
|
lua.pushInteger(lua.checkString(1).length)
|
||||||
|
1
|
||||||
|
})
|
||||||
|
state.setField(-2, "len")
|
||||||
|
|
||||||
|
state.pushScalaFunction(lua => {
|
||||||
|
lua.pushString(lua.checkString(1).reverse)
|
||||||
|
1
|
||||||
|
})
|
||||||
|
state.setField(-2, "reverse")
|
||||||
|
|
||||||
|
state.pushScalaFunction(lua => {
|
||||||
|
val string = lua.checkString(1)
|
||||||
|
val start = math.max(0, lua.checkInteger(2) match {
|
||||||
|
case i if i < 0 => string.length + i
|
||||||
|
case i => i - 1
|
||||||
})
|
})
|
||||||
else string.length
|
val end =
|
||||||
if (end <= start) lua.pushString("")
|
if (lua.getTop > 2) math.min(string.length, lua.checkInteger(3) match {
|
||||||
else lua.pushString(string.substring(start, end))
|
case i if i < 0 => string.length + i + 1
|
||||||
1
|
case i => i
|
||||||
})
|
})
|
||||||
state.setField(-2, "sub")
|
else string.length
|
||||||
|
if (end <= start) lua.pushString("")
|
||||||
|
else lua.pushString(string.substring(start, end))
|
||||||
|
1
|
||||||
|
})
|
||||||
|
state.setField(-2, "sub")
|
||||||
|
|
||||||
state.setGlobal("unicode")
|
state.setGlobal("unicode")
|
||||||
|
|
||||||
Some(state)
|
return Some(state)
|
||||||
} catch {
|
}
|
||||||
case ex: Throwable =>
|
catch {
|
||||||
ex.printStackTrace()
|
case t: Throwable =>
|
||||||
state.close()
|
OpenComputers.log.log(Level.WARNING, "Failed creating Lua state.", t)
|
||||||
return None
|
state.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
catch {
|
||||||
|
case _: UnsatisfiedLinkError =>
|
||||||
|
OpenComputers.log.severe("Failed loading the native libraries.")
|
||||||
|
if (isWindows) {
|
||||||
|
OpenComputers.log.severe(
|
||||||
|
"Please ensure you have the Visual C++ 2012 Runtime installed " +
|
||||||
|
"(when on 64 Bit, both the 32 bit and 64 bit version of the " +
|
||||||
|
"runtime).")
|
||||||
|
}
|
||||||
|
case t: Throwable =>
|
||||||
|
OpenComputers.log.log(Level.WARNING, "Failed creating Lua state.", t)
|
||||||
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user