Merge remote-tracking branch 'origin/master-MC1.7.10' into master-MC1.12

This commit is contained in:
Adrian Siekierka 2022-09-28 16:06:18 +02:00
commit 4a09b855d8
5 changed files with 154 additions and 124 deletions

View File

@ -220,8 +220,8 @@ dependencies {
}
embedded name: 'OC-LuaJ', version: '20220907.1', ext: 'jar'
embedded name: 'OC-JNLua', version: '20220904.0', ext: 'jar'
embedded name: 'OC-JNLua-Natives', version: '20220904.0', ext: 'jar'
embedded name: 'OC-JNLua', version: '20220928.0', ext: 'jar'
embedded name: 'OC-JNLua-Natives', version: '20220928.0', ext: 'jar'
testImplementation("org.mockito:mockito-all:1.10.19")

View File

@ -1506,10 +1506,21 @@ opencomputers {
# to work.
logFullNativeLibLoadErrors: false
# Force loading one specific library, to avoid trying to load any
# others. Use this if you get warnings in the log or are told to do
# so for debugging purposes ;-)
forceNativeLibWithName: ""
# Force the platform name for the native libraries, instead of relying
# on auto-detecting it. Use this if your system is using an otherwise
# unsupported operating system or CPU architecture. If unsure, leave blank.
#
# Examples of platform strings include "solaris-x86_64" for 64-bit Solaris,
# or "windows-aarch64" for Windows on the aarch64 (64-bit arm) architecture.
forceNativeLibPlatform: ""
# Force the native library loader to check the specified directory for natives first,
# before trying to find libraries packaged with OpenComputers. Use this if you want to
# use custom native libraries, or are on an unsupported platform. If unsure, leave blank.
#
# This can be an absolute or relative path. If relative, the base directory will be the .minecraft
# directory of the running Minecraft instance.
forceNativeLibPathFirst: ""
# Used to suppress log spam for OpenGL errors on derpy drivers. I'm
# quite certain the code in the font render is valid, display list

View File

@ -442,7 +442,8 @@ class Settings(val config: Config) {
val limitMemory = !config.getBoolean("debug.disableMemoryLimit")
val forceCaseInsensitive = config.getBoolean("debug.forceCaseInsensitiveFS")
val logFullLibLoadErrors = config.getBoolean("debug.logFullNativeLibLoadErrors")
val forceNativeLib = config.getString("debug.forceNativeLibWithName")
val forceNativeLibPlatform = config.getString("debug.forceNativeLibPlatform")
val forceNativeLibPathFirst = config.getString("debug.forceNativeLibPathFirst")
val logOpenGLErrors = config.getBoolean("debug.logOpenGLErrors")
val logHexFontErrors = config.getBoolean("debug.logHexFontErrors")
val alwaysTryNative = config.getBoolean("debug.alwaysTryNative")

View File

@ -4,8 +4,8 @@ import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.nio.channels.Channels
import java.nio.file.Paths
import java.util.regex.Pattern
import com.google.common.base.Strings
import com.google.common.io.PatternFilenameFilter
import li.cil.oc.OpenComputers
@ -130,36 +130,39 @@ abstract class LuaStateFactory {
private var currentLib = ""
private val libraryName = {
if (!Strings.isNullOrEmpty(Settings.get.forceNativeLib)) Settings.get.forceNativeLib
else {
val libExtension = {
if (SystemUtils.IS_OS_MAC) ".dylib"
else if (SystemUtils.IS_OS_WINDOWS) ".dll"
else ".so"
}
val systemName = {
if (SystemUtils.IS_OS_FREE_BSD) "freebsd"
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"
}
val archName = {
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"
}
"libjnlua" + version + "-" + systemName + "-" + archName + libExtension
val libExtension = {
if (SystemUtils.IS_OS_MAC) ".dylib"
else if (SystemUtils.IS_OS_WINDOWS) ".dll"
else ".so"
}
val platformName = {
if (!Strings.isNullOrEmpty(Settings.get.forceNativeLibPlatform)) Settings.get.forceNativeLibPlatform
else {
val systemName = {
if (SystemUtils.IS_OS_FREE_BSD) "freebsd"
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"
}
val archName = {
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"
}
systemName + "-" + archName
}
}
"libjnlua" + version + "-" + platformName + libExtension
}
protected def create(maxMemory: Option[Int] = None): jnlua.LuaState
@ -170,13 +173,12 @@ abstract class LuaStateFactory {
def isAvailable = haveNativeLibrary
val is64Bit = Architecture.IS_OS_X64
// Since we use native libraries we have to do some work. This includes
// figuring out what we're running on, so that we can load the proper shared
// libraries compiled for that system. It also means we have to unpack the
// shared libraries somewhere so that we can load them, because we cannot
// load them directly from a JAR.
// load them directly from a JAR. Lastly, we need to handle library overrides in
// case the user wants to use custom libraries, or are not on a supported platform.
def init() {
if (libraryName == null) {
return
@ -194,108 +196,123 @@ abstract class LuaStateFactory {
}
}
val libraryUrl = classOf[Machine].getResource(s"/assets/${Settings.resourceDomain}/lib/$libraryName")
if (libraryUrl == null) {
OpenComputers.log.warn(s"Native library with name '$version/$libraryName' not found.")
return
var tmpLibFile: File = null
if (!Strings.isNullOrEmpty(Settings.get.forceNativeLibPathFirst)) {
val libraryTest = new File(Settings.get.forceNativeLibPathFirst, libraryName);
if (libraryTest.canRead) {
tmpLibFile = libraryTest
currentLib = libraryTest.getAbsolutePath
OpenComputers.log.info(s"Found forced-path filesystem library $currentLib.")
}
else
OpenComputers.log.warn(s"forceNativeLibPathFirst is set, but $currentLib was not found there. Falling back to checking the built-in libraries.")
}
val tmpLibName = s"OpenComputersMod-${OpenComputers.Version}-$version-$libraryName"
val tmpBasePath = if (Settings.get.nativeInTmpDir) {
val path = System.getProperty("java.io.tmpdir")
if (path == null) ""
else if (path.endsWith("/") || path.endsWith("\\")) path
else path + "/"
}
else "./"
val tmpLibFile = new File(tmpBasePath + tmpLibName)
if (currentLib.isEmpty) {
val libraryUrl = classOf[Machine].getResource(s"/assets/${Settings.resourceDomain}/lib/$libraryName")
if (libraryUrl == null) {
OpenComputers.log.warn(s"Native library with name '$libraryName' not found.")
return
}
// Clean up old library files when not in tmp dir.
if (!Settings.get.nativeInTmpDir) {
val libDir = new File(tmpBasePath)
if (libDir.isDirectory) {
for (file <- libDir.listFiles(new PatternFilenameFilter("^" + Pattern.quote("OpenComputersMod-") + ".*" + Pattern.quote("-" + libraryName) + "$"))) {
if (file.compareTo(tmpLibFile) != 0) {
file.delete()
val tmpLibName = s"OpenComputersMod-${OpenComputers.Version}-$version-$libraryName"
val tmpBasePath = if (Settings.get.nativeInTmpDir) {
val path = System.getProperty("java.io.tmpdir")
if (path == null) ""
else if (path.endsWith("/") || path.endsWith("\\")) path
else path + "/"
}
else "./"
tmpLibFile = new File(tmpBasePath + tmpLibName)
// Clean up old library files when not in tmp dir.
if (!Settings.get.nativeInTmpDir) {
val libDir = new File(tmpBasePath)
if (libDir.isDirectory) {
for (file <- libDir.listFiles(new PatternFilenameFilter("^" + Pattern.quote("OpenComputersMod-") + ".*" + Pattern.quote("-" + libraryName) + "$"))) {
if (file.compareTo(tmpLibFile) != 0) {
file.delete()
}
}
}
}
}
// If the file, already exists, make sure it's the same we need, if it's
// not disable use of the natives.
if (tmpLibFile.exists()) {
var matching = true
try {
val inCurrent = libraryUrl.openStream()
val inExisting = new FileInputStream(tmpLibFile)
var inCurrentByte = 0
var inExistingByte = 0
do {
inCurrentByte = inCurrent.read()
inExistingByte = inExisting.read()
if (inCurrentByte != inExistingByte) {
matching = false
inCurrentByte = -1
inExistingByte = -1
}
}
while (inCurrentByte != -1 && inExistingByte != -1)
inCurrent.close()
inExisting.close()
}
catch {
case _: Throwable =>
matching = false
}
if (!matching) {
// 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).
// Note that this should only ever be necessary for dev-builds, where the
// version number didn't change (since the version number is part of the name).
// If the file, already exists, make sure it's the same we need, if it's
// not disable use of the natives.
if (tmpLibFile.exists()) {
var matching = true
try {
tmpLibFile.delete()
val inCurrent = libraryUrl.openStream()
val inExisting = new FileInputStream(tmpLibFile)
var inCurrentByte = 0
var inExistingByte = 0
do {
inCurrentByte = inCurrent.read()
inExistingByte = inExisting.read()
if (inCurrentByte != inExistingByte) {
matching = false
inCurrentByte = -1
inExistingByte = -1
}
}
while (inCurrentByte != -1 && inExistingByte != -1)
inCurrent.close()
inExisting.close()
}
catch {
case t: Throwable => // Ignore.
case _: Throwable =>
matching = false
}
if (tmpLibFile.exists()) {
OpenComputers.log.warn(s"Could not update native library '${tmpLibFile.getName}'!")
if (!matching) {
// 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).
// Note that this should only ever be necessary for dev-builds, where the
// version number didn't change (since the version number is part of the name).
try {
tmpLibFile.delete()
}
catch {
case t: Throwable => // Ignore.
}
if (tmpLibFile.exists()) {
OpenComputers.log.warn(s"Could not update native library '${tmpLibFile.getName}'!")
}
}
}
}
// Copy the file contents to the temporary file.
try {
val in = Channels.newChannel(libraryUrl.openStream())
// Copy the file contents to the temporary file.
try {
val out = new FileOutputStream(tmpLibFile).getChannel
val in = Channels.newChannel(libraryUrl.openStream())
try {
out.transferFrom(in, 0, Long.MaxValue)
tmpLibFile.deleteOnExit()
// Set file permissions more liberally for multi-user+instance servers.
tmpLibFile.setReadable(true, false)
tmpLibFile.setWritable(true, false)
tmpLibFile.setExecutable(true, false)
val out = new FileOutputStream(tmpLibFile).getChannel
try {
out.transferFrom(in, 0, Long.MaxValue)
tmpLibFile.deleteOnExit()
// Set file permissions more liberally for multi-user+instance servers.
tmpLibFile.setReadable(true, false)
tmpLibFile.setWritable(true, false)
tmpLibFile.setExecutable(true, false)
}
finally {
out.close()
}
}
finally {
out.close()
in.close()
}
}
finally {
in.close()
catch {
// Java (or Windows?) locks the library file when opening it, so any
// further tries to update it while another instance is still running
// will fail. We still want to try each time, since the files may have
// been updated.
// Alternatively, the file could not be opened for reading/writing.
case t: Throwable => // Nothing.
}
// Try to load the lib.
currentLib = tmpLibFile.getAbsolutePath
}
catch {
// Java (or Windows?) locks the library file when opening it, so any
// further tries to update it while another instance is still running
// will fail. We still want to try each time, since the files may have
// been updated.
// Alternatively, the file could not be opened for reading/writing.
case t: Throwable => // Nothing.
}
// Try to load the lib.
currentLib = tmpLibFile.getAbsolutePath
try {
LuaStateFactory.synchronized {
System.load(currentLib)

View File

@ -42,7 +42,7 @@ abstract class NativeLuaArchitecture(val machine: api.machine.Machine) extends A
private[machine] var kernelMemory = 0
private[machine] val ramScale = if (factory.is64Bit) Settings.get.ramScaleFor64Bit else 1.0
private[machine] var ramScale: Double = 1.0
private val persistence = new PersistenceAPI(this)
@ -150,16 +150,16 @@ abstract class NativeLuaArchitecture(val machine: api.machine.Machine) extends A
override def isInitialized = kernelMemory > 0
override def recomputeMemory(components: java.lang.Iterable[ItemStack]) = {
val memory = math.ceil(memoryInBytes(components) * ramScale).toInt
val memoryBytes = memoryInBytes(components)
Option(lua) match {
case Some(l) if Settings.get.limitMemory =>
l.setTotalMemory(Int.MaxValue)
if (kernelMemory > 0) {
l.setTotalMemory(kernelMemory + memory)
l.setTotalMemory(kernelMemory + math.ceil(memoryBytes * ramScale).toInt)
}
case _ =>
}
memory > 0
memoryBytes > 0
}
private def memoryInBytes(components: java.lang.Iterable[ItemStack]) = components.foldLeft(0.0)((acc, stack) => acc + (Option(api.Driver.driverFor(stack)) match {
@ -314,6 +314,7 @@ abstract class NativeLuaArchitecture(val machine: api.machine.Machine) extends A
return false
case Some(value) => lua = value
}
ramScale = if (lua.getPointerWidth >= 8) Settings.get.ramScaleFor64Bit else 1.0
apis.foreach(_.initialize())