diff --git a/patcher/src/main/kotlin/org/openrs2/patcher/Architecture.kt b/patcher/src/main/kotlin/org/openrs2/patcher/Architecture.kt new file mode 100644 index 00000000..0389ce35 --- /dev/null +++ b/patcher/src/main/kotlin/org/openrs2/patcher/Architecture.kt @@ -0,0 +1,10 @@ +package org.openrs2.patcher + +public enum class Architecture( + public val needles: List +) { + I386(listOf("i386", "x86")), + AMD64(listOf("amd64", "x86_64")); + + public val id: String = name.toLowerCase() +} diff --git a/patcher/src/main/kotlin/org/openrs2/patcher/OperatingSystem.kt b/patcher/src/main/kotlin/org/openrs2/patcher/OperatingSystem.kt new file mode 100644 index 00000000..a7eb922e --- /dev/null +++ b/patcher/src/main/kotlin/org/openrs2/patcher/OperatingSystem.kt @@ -0,0 +1,17 @@ +package org.openrs2.patcher + +import org.openrs2.patcher.Architecture.AMD64 +import org.openrs2.patcher.Architecture.I386 + +public enum class OperatingSystem( + public val needle: String, + public val architectures: List, + public val glLibraries: List +) { + // AMD64 must be before I386 as x86 is a substring of x86_64 + WINDOWS("win", listOf(AMD64, I386), listOf("jaggl.dll")), + MAC("mac", listOf(AMD64, I386), listOf("libjaggl.dylib")), + LINUX("linux", listOf(AMD64, I386), listOf("libjaggl.so", "libjaggl_dri.so")); + + public val id: String = name.toLowerCase() +} diff --git a/patcher/src/main/kotlin/org/openrs2/patcher/Resource.kt b/patcher/src/main/kotlin/org/openrs2/patcher/Resource.kt index e02b2090..bd75cfd8 100644 --- a/patcher/src/main/kotlin/org/openrs2/patcher/Resource.kt +++ b/patcher/src/main/kotlin/org/openrs2/patcher/Resource.kt @@ -85,43 +85,43 @@ public class Resource( return compress(source, destination, uncompressed) } - public fun compressGlNatives(): List> = listOf( - // Windows i386 - listOf( - compressNative("jaggl_0_0.lib", "jaggl.dll", "windows-i386/jaggl.dll") - ), - - // Windows amd64 - listOf( - compressNative("jaggl_1_0.lib", "jaggl.dll", "windows-amd64/jaggl.dll") - ), - - // macOS i386 - listOf( - compressNative("jaggl_2_0.lib", "libjaggl.dylib", "mac-i386/libjaggl.dylib") - ), - - // macOS amd64 - listOf( - compressNative("jaggl_3_0.lib", "libjaggl.dylib", "mac-amd64/libjaggl.dylib") - ), - - // Linux i386 - listOf( - compressNative("jaggl_4_0.lib", "libjaggl.so", "linux-i386/libjaggl.so"), - compressNative("jaggl_4_1.lib", "libjaggl_dri.so", "linux-i386/libjaggl_dri.so") - ), - - // Linux amd64 - listOf( - compressNative("jaggl_5_0.lib", "libjaggl.so", "linux-amd64/libjaggl.so"), - compressNative("jaggl_5_1.lib", "libjaggl_dri.so", "linux-amd64/libjaggl_dri.so") - ) - ) - - public fun compressMiscNatives(): List = listOf( - compressNative("jagmisc_0.lib", "jagmisc.dll", "windows-i386/jagmisc.dll"), - compressNative("jagmisc_1.lib", "jagmisc.dll", "windows-amd64/jagmisc.dll") - ) + public fun compressGlNatives(): List> { + val platforms = mutableListOf>() + var i = 0 + + for (os in OperatingSystem.values()) { + for (arch in os.architectures) { + val resources = mutableListOf() + + for ((j, library) in os.glLibraries.withIndex()) { + resources += compressNative( + source = "jaggl_${i}_$j.lib", + destination = library, + resource = "${os.id}-${arch.id}/$library" + ) + } + + platforms += resources + i++ + } + } + + return platforms + } + + public fun compressMiscNatives(): List { + val os = OperatingSystem.WINDOWS + val resources = mutableListOf() + + for ((i, arch) in os.architectures.withIndex()) { + resources += compressNative( + source = "jagmisc_$i.lib", + destination = "jagmisc.dll", + resource = "${os.id}-${arch.id}/jagmisc.dll" + ) + } + + return resources + } } } diff --git a/patcher/src/main/kotlin/org/openrs2/patcher/transform/PlatformDetectionTransformer.kt b/patcher/src/main/kotlin/org/openrs2/patcher/transform/PlatformDetectionTransformer.kt index 871f061d..3dcc3622 100644 --- a/patcher/src/main/kotlin/org/openrs2/patcher/transform/PlatformDetectionTransformer.kt +++ b/patcher/src/main/kotlin/org/openrs2/patcher/transform/PlatformDetectionTransformer.kt @@ -5,7 +5,6 @@ import org.objectweb.asm.Opcodes import org.objectweb.asm.tree.AbstractInsnNode import org.objectweb.asm.tree.ClassNode import org.objectweb.asm.tree.InsnList -import org.objectweb.asm.tree.InsnNode import org.objectweb.asm.tree.JumpInsnNode import org.objectweb.asm.tree.LabelNode import org.objectweb.asm.tree.LdcInsnNode @@ -16,9 +15,9 @@ import org.openrs2.asm.InsnMatcher import org.openrs2.asm.MemberRef import org.openrs2.asm.classpath.ClassPath import org.openrs2.asm.classpath.Library -import org.openrs2.asm.intConstant import org.openrs2.asm.toAbstractInsnNode import org.openrs2.asm.transform.Transformer +import org.openrs2.patcher.OperatingSystem import javax.inject.Singleton @Singleton @@ -32,7 +31,7 @@ public class PlatformDetectionTransformer : Transformer() { } override fun transformCode(classPath: ClassPath, library: Library, clazz: ClassNode, method: MethodNode): Boolean { - val match = GL_PLATFORM_DETECTION_MATCHER.match(method).singleOrNull() + var match = GL_PLATFORM_DETECTION_MATCHER.match(method).singleOrNull() if (match != null) { // find os.name, os.arch and platform ID variables val nameStore = match[3] as VarInsnNode @@ -50,14 +49,13 @@ public class PlatformDetectionTransformer : Transformer() { // generate our own platform detection code val list = InsnList() val end = LabelNode() + var platform = 0 - for ((index, os) in OS_NAMES.withIndex()) { - val next = LabelNode() - val amd64 = LabelNode() - val i386 = LabelNode() + for (os in OperatingSystem.values()) { + val nextOs = LabelNode() list.add(VarInsnNode(Opcodes.ALOAD, nameVar)) - list.add(LdcInsnNode(os)) + list.add(LdcInsnNode(os.needle)) list.add( MethodInsnNode( Opcodes.INVOKEVIRTUAL, @@ -66,43 +64,42 @@ public class PlatformDetectionTransformer : Transformer() { STARTS_WITH.desc ) ) - list.add(JumpInsnNode(Opcodes.IFEQ, next)) - - list.add(VarInsnNode(Opcodes.ALOAD, archVar)) - list.add(LdcInsnNode("amd64")) - list.add( - MethodInsnNode( - Opcodes.INVOKEVIRTUAL, - STARTS_WITH.owner, - STARTS_WITH.name, - STARTS_WITH.desc - ) - ) - list.add(JumpInsnNode(Opcodes.IFNE, amd64)) - - list.add(VarInsnNode(Opcodes.ALOAD, archVar)) - list.add(LdcInsnNode("x86_64")) - list.add( - MethodInsnNode( - Opcodes.INVOKEVIRTUAL, - STARTS_WITH.owner, - STARTS_WITH.name, - STARTS_WITH.desc - ) - ) - list.add(JumpInsnNode(Opcodes.IFEQ, i386)) - - list.add(amd64) - list.add((index * 2 + 1).toAbstractInsnNode()) - list.add(VarInsnNode(Opcodes.ISTORE, platformVar)) - list.add(JumpInsnNode(Opcodes.GOTO, end)) - - list.add(i386) - list.add((index * 2).toAbstractInsnNode()) - list.add(VarInsnNode(Opcodes.ISTORE, platformVar)) - list.add(JumpInsnNode(Opcodes.GOTO, end)) + list.add(JumpInsnNode(Opcodes.IFEQ, nextOs)) + + for ((i, arch) in os.architectures.withIndex()) { + val matchingArch = LabelNode() + val nextArch = LabelNode() + + if (i != os.architectures.size - 1) { + for ((j, needle) in arch.needles.withIndex()) { + list.add(VarInsnNode(Opcodes.ALOAD, archVar)) + list.add(LdcInsnNode(needle)) + list.add( + MethodInsnNode( + Opcodes.INVOKEVIRTUAL, + STARTS_WITH.owner, + STARTS_WITH.name, + STARTS_WITH.desc + ) + ) + + if (j != arch.needles.size - 1) { + list.add(JumpInsnNode(Opcodes.IFNE, matchingArch)) + } else { + list.add(JumpInsnNode(Opcodes.IFEQ, nextArch)) + } + } + } + + list.add(matchingArch) + list.add((platform++).toAbstractInsnNode()) + list.add(VarInsnNode(Opcodes.ISTORE, platformVar)) + list.add(JumpInsnNode(Opcodes.GOTO, end)) + + list.add(nextArch) + } - list.add(next) + list.add(nextOs) } list.add(unknownOs) @@ -119,28 +116,62 @@ public class PlatformDetectionTransformer : Transformer() { } // adjust jagmisc platform IDs to account for the removal of MSJVM support - val miscMatch = MISC_PLATFORM_DETECTION_MATCHER.match(method).filter { - val const1 = it[0].intConstant - if (const1 != 0 && const1 != 2) { - return@filter false - } + match = MISC_PLATFORM_DETECTION_MATCHER.match(method).singleOrNull() + if (match != null) { + // find os.arch and platform ID variables + val archStore = match[12] as VarInsnNode + val archVar = archStore.`var` + + val platformStore = match[match.size - 5] as VarInsnNode + val platformVar = platformStore.`var` - val const2 = it[it.size - 2].intConstant - if (const2 != 0 && const2 != 2) { - return@filter false + // generate our own platform detection code + val list = InsnList() + val end = LabelNode() + val os = OperatingSystem.WINDOWS + + for ((i, arch) in os.architectures.withIndex()) { + val matchingArch = LabelNode() + val nextArch = LabelNode() + + if (i != os.architectures.size - 1) { + for ((j, needle) in arch.needles.withIndex()) { + list.add(VarInsnNode(Opcodes.ALOAD, archVar)) + list.add(LdcInsnNode(needle)) + list.add( + MethodInsnNode( + Opcodes.INVOKEVIRTUAL, + STARTS_WITH.owner, + STARTS_WITH.name, + STARTS_WITH.desc + ) + ) + + if (j != arch.needles.size - 1) { + list.add(JumpInsnNode(Opcodes.IFNE, matchingArch)) + } else { + list.add(JumpInsnNode(Opcodes.IFEQ, nextArch)) + } + } + } + + list.add(matchingArch) + list.add(i.toAbstractInsnNode()) + list.add(VarInsnNode(Opcodes.ISTORE, platformVar)) + list.add(JumpInsnNode(Opcodes.GOTO, end)) + + list.add(nextArch) } - if (const1 == const2) { - return@filter false + list.add(end) + + // replace existing platform detection code with our own + for (i in (13 until match.size - 4)) { + method.instructions.remove(match[i]) } - val store1 = it[1] as VarInsnNode - val store2 = it[it.size - 1] as VarInsnNode - return@filter store1.`var` == store2.`var` - }.singleOrNull() - if (miscMatch != null) { - val iconst = miscMatch.single { it.intConstant == 2 } - method.instructions.set(iconst, InsnNode(Opcodes.ICONST_1)) + method.instructions.insert(match[12], list) + miscBlocks++ } @@ -161,9 +192,14 @@ public class PlatformDetectionTransformer : Transformer() { ICONST ISTORE ILOAD GETSTATIC ILOAD AALOAD ARRAYLENGTH """ ) - private val MISC_PLATFORM_DETECTION_MATCHER = - InsnMatcher.compile("ICONST ISTORE ((GETSTATIC | ILOAD) IFEQ | GOTO) ICONST ISTORE") - private val OS_NAMES = listOf("win", "mac", "linux") + private val MISC_PLATFORM_DETECTION_MATCHER = InsnMatcher.compile( + """ + LDC INVOKESTATIC INVOKEVIRTUAL ASTORE ALOAD LDC INVOKEVIRTUAL IFNE GOTO + LDC INVOKESTATIC INVOKEVIRTUAL ASTORE + .* + ICONST ISTORE ALOAD ALOAD LDC INVOKEVIRTUAL + """ + ) private val STARTS_WITH = MemberRef("java/lang/String", "startsWith", "(Ljava/lang/String;)Z") private fun findUnknownOs(match: List): InsnList {