forked from openrs2/openrs2
parent
2b82451b96
commit
a79dfd6f32
@ -1,10 +1,205 @@ |
||||
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.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( |
||||
private val resources: List<Resource>? = null, |
||||
private val glResources: List<List<Resource>> = Resource.compressGlResources(), |
||||
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