forked from openrs2/openrs2
parent
2b82451b96
commit
a79dfd6f32
@ -1,10 +1,205 @@ |
|||||||
package dev.openrs2.bundler.transform |
package dev.openrs2.bundler.transform |
||||||
|
|
||||||
|
import com.github.michaelbull.logging.InlineLogger |
||||||
|
import dev.openrs2.asm.InsnMatcher |
||||||
|
import dev.openrs2.asm.classpath.ClassPath |
||||||
|
import dev.openrs2.asm.classpath.Library |
||||||
|
import dev.openrs2.asm.createIntConstant |
||||||
import dev.openrs2.asm.transform.Transformer |
import dev.openrs2.asm.transform.Transformer |
||||||
import dev.openrs2.bundler.Resource |
import dev.openrs2.bundler.Resource |
||||||
|
import org.objectweb.asm.Opcodes |
||||||
|
import org.objectweb.asm.tree.ClassNode |
||||||
|
import org.objectweb.asm.tree.InsnList |
||||||
|
import org.objectweb.asm.tree.InsnNode |
||||||
|
import org.objectweb.asm.tree.IntInsnNode |
||||||
|
import org.objectweb.asm.tree.LdcInsnNode |
||||||
|
import org.objectweb.asm.tree.MethodInsnNode |
||||||
|
import org.objectweb.asm.tree.MethodNode |
||||||
|
import org.objectweb.asm.tree.TypeInsnNode |
||||||
|
|
||||||
class ResourceTransformer( |
class ResourceTransformer( |
||||||
private val resources: List<Resource>? = null, |
private val resources: List<Resource>? = null, |
||||||
private val glResources: List<List<Resource>> = Resource.compressGlResources(), |
private val glResources: List<List<Resource>> = Resource.compressGlResources(), |
||||||
private val miscResources: List<Resource> = Resource.compressMiscResources() |
private val miscResources: List<Resource> = Resource.compressMiscResources() |
||||||
) : Transformer() |
) : Transformer() { |
||||||
|
private var glBlocks = 0 |
||||||
|
private var miscBlocks = 0 |
||||||
|
|
||||||
|
override fun preTransform(classPath: ClassPath) { |
||||||
|
glBlocks = 0 |
||||||
|
miscBlocks = 0 |
||||||
|
} |
||||||
|
|
||||||
|
override fun transformCode(classPath: ClassPath, library: Library, clazz: ClassNode, method: MethodNode): Boolean { |
||||||
|
val match = GL_RESOURCES_MATCHER.match(method).singleOrNull() |
||||||
|
if (match != null) { |
||||||
|
// remove everything but the PUTSTATIC |
||||||
|
for (i in 0 until match.size - 1) { |
||||||
|
method.instructions.remove(match[i]) |
||||||
|
} |
||||||
|
|
||||||
|
// find the type of the resource class |
||||||
|
val new = match[8] as TypeInsnNode |
||||||
|
val type = new.desc |
||||||
|
|
||||||
|
// create our own resource array |
||||||
|
val list = InsnList() |
||||||
|
create2dResourceArray(list, type, glResources, GL_LOADING_MESSAGES) |
||||||
|
|
||||||
|
// insert our own resource array before the PUTSTATIC |
||||||
|
method.instructions.insertBefore(match[match.size - 1], list) |
||||||
|
|
||||||
|
glBlocks++ |
||||||
|
} |
||||||
|
|
||||||
|
val miscMatch = MISC_RESOURCES_MATCHER.match(method).singleOrNull() |
||||||
|
if (miscMatch != null) { |
||||||
|
// remove everything but the PUTSTATIC |
||||||
|
for (i in 0 until miscMatch.size - 1) { |
||||||
|
method.instructions.remove(miscMatch[i]) |
||||||
|
} |
||||||
|
|
||||||
|
// find the type of the resource class |
||||||
|
val new = miscMatch[4] as TypeInsnNode |
||||||
|
val type = new.desc |
||||||
|
|
||||||
|
// create our own resource array |
||||||
|
val list = InsnList() |
||||||
|
createResourceArray(list, type, miscResources, MISC_LOADING_MESSAGES) |
||||||
|
|
||||||
|
// insert our own resource array before the PUTSTATIC |
||||||
|
method.instructions.insertBefore(miscMatch[miscMatch.size - 1], list) |
||||||
|
|
||||||
|
miscBlocks++ |
||||||
|
} |
||||||
|
|
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
private fun create2dResourceArray( |
||||||
|
list: InsnList, |
||||||
|
type: String, |
||||||
|
resources: List<List<Resource>>, |
||||||
|
messages: List<String> |
||||||
|
) { |
||||||
|
list.add(createIntConstant(resources.size)) |
||||||
|
list.add(TypeInsnNode(Opcodes.ANEWARRAY, "[L$type;")) |
||||||
|
|
||||||
|
for ((i, innerResources) in resources.withIndex()) { |
||||||
|
list.add(InsnNode(Opcodes.DUP)) |
||||||
|
list.add(createIntConstant(i)) |
||||||
|
|
||||||
|
createResourceArray(list, type, innerResources, messages, progressSufix = true) |
||||||
|
|
||||||
|
list.add(InsnNode(Opcodes.AASTORE)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun createResourceArray( |
||||||
|
list: InsnList, |
||||||
|
type: String, |
||||||
|
resources: List<Resource>, |
||||||
|
messages: List<String>, |
||||||
|
progressSufix: Boolean = false |
||||||
|
) { |
||||||
|
list.add(createIntConstant(resources.size)) |
||||||
|
list.add(TypeInsnNode(Opcodes.ANEWARRAY, type)) |
||||||
|
|
||||||
|
for ((i, resource) in resources.withIndex()) { |
||||||
|
list.add(InsnNode(Opcodes.DUP)) |
||||||
|
list.add(createIntConstant(i)) |
||||||
|
|
||||||
|
list.add(TypeInsnNode(Opcodes.NEW, type)) |
||||||
|
list.add(InsnNode(Opcodes.DUP)) |
||||||
|
list.add(LdcInsnNode(resource.destination)) |
||||||
|
list.add(LdcInsnNode(resource.source)) |
||||||
|
|
||||||
|
list.add(createIntConstant(messages.size)) |
||||||
|
list.add(TypeInsnNode(Opcodes.ANEWARRAY, "java/lang/String")) |
||||||
|
|
||||||
|
for ((j, message) in messages.withIndex()) { |
||||||
|
val messageWithSuffix = if (progressSufix && resources.size > 1) { |
||||||
|
"$message (${i + 1}/${resources.size})" |
||||||
|
} else { |
||||||
|
message |
||||||
|
} |
||||||
|
|
||||||
|
list.add(InsnNode(Opcodes.DUP)) |
||||||
|
list.add(createIntConstant(j)) |
||||||
|
list.add(LdcInsnNode(messageWithSuffix)) |
||||||
|
list.add(InsnNode(Opcodes.AASTORE)) |
||||||
|
} |
||||||
|
|
||||||
|
list.add(createIntConstant(resource.uncompressedSize)) |
||||||
|
list.add(createIntConstant(resource.compressedSize)) |
||||||
|
|
||||||
|
list.add(createIntConstant(resource.digest.size)) |
||||||
|
list.add(IntInsnNode(Opcodes.NEWARRAY, Opcodes.T_INT)) |
||||||
|
|
||||||
|
for ((j, byte) in resource.digest.withIndex()) { |
||||||
|
list.add(InsnNode(Opcodes.DUP)) |
||||||
|
list.add(createIntConstant(j)) |
||||||
|
list.add(createIntConstant(byte.toInt())) |
||||||
|
list.add(InsnNode(Opcodes.IASTORE)) |
||||||
|
} |
||||||
|
|
||||||
|
list.add( |
||||||
|
MethodInsnNode( |
||||||
|
Opcodes.INVOKESPECIAL, |
||||||
|
type, |
||||||
|
"<init>", |
||||||
|
"(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;II[I)V" |
||||||
|
) |
||||||
|
) |
||||||
|
list.add(InsnNode(Opcodes.AASTORE)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun postTransform(classPath: ClassPath) { |
||||||
|
logger.info { "Replaced $glBlocks jaggl and $miscBlocks jagmisc resource constructor blocks" } |
||||||
|
} |
||||||
|
|
||||||
|
companion object { |
||||||
|
private val logger = InlineLogger() |
||||||
|
|
||||||
|
private const val RESOURCE_CONSTRUCTOR = """ |
||||||
|
NEW DUP |
||||||
|
LDC |
||||||
|
LDC |
||||||
|
ICONST_4 ANEWARRAY (DUP ICONST LDC AASTORE)+ |
||||||
|
(ICONST | BIPUSH | SIPUSH | LDC) |
||||||
|
(ICONST | BIPUSH | SIPUSH | LDC) |
||||||
|
BIPUSH |
||||||
|
NEWARRAY |
||||||
|
(DUP (ICONST | BIPUSH) (ICONST | BIPUSH) IASTORE)+ |
||||||
|
INVOKESPECIAL |
||||||
|
""" |
||||||
|
private const val RESOURCE_ARRAY_CONSTRUCTOR = "ICONST ANEWARRAY (DUP ICONST $RESOURCE_CONSTRUCTOR AASTORE)+" |
||||||
|
|
||||||
|
private val GL_RESOURCES_MATCHER = InsnMatcher.compile( |
||||||
|
""" |
||||||
|
ICONST ANEWARRAY |
||||||
|
( |
||||||
|
DUP ICONST |
||||||
|
$RESOURCE_ARRAY_CONSTRUCTOR |
||||||
|
AASTORE |
||||||
|
)+ |
||||||
|
PUTSTATIC |
||||||
|
""" |
||||||
|
) |
||||||
|
private val MISC_RESOURCES_MATCHER = InsnMatcher.compile("$RESOURCE_ARRAY_CONSTRUCTOR PUTSTATIC") |
||||||
|
|
||||||
|
private val GL_LOADING_MESSAGES = listOf( |
||||||
|
"Loading 3D library", |
||||||
|
"Lade 3D-Softwarebibliothek", |
||||||
|
"Chargement de la librairie 3D", |
||||||
|
"Carregando biblioteca 3D" |
||||||
|
) |
||||||
|
private val MISC_LOADING_MESSAGES = listOf( |
||||||
|
"Loading utility library", |
||||||
|
"Lade Utility-Softwarebibliothek", |
||||||
|
"Chargement de la librairie utilitaire", |
||||||
|
"Carregando biblioteca de ferramentas" |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
Loading…
Reference in new issue