From 258f84208fc1dff90b5a2fa809d82e37957f90e2 Mon Sep 17 00:00:00 2001 From: ev chang Date: Wed, 31 Jul 2024 05:30:36 +0900 Subject: [PATCH] base implementation of forge transformers split platform from transformer stuff --- .../kotlin/wtf/zani/spice/util/ClassUtil.kt | 1 - .../zani/spice/patcher/LunarTransformer.kt | 4 + .../zani/spice/patcher/OptifineTransformer.kt | 6 +- .../spice/patcher/lwjgl/LibraryTransformer.kt | 22 +++++ .../patcher/{ => lwjgl}/LwjglProvider.kt | 4 +- .../patcher/{ => lwjgl}/LwjglTransformer.kt | 41 +++------ .../wtf/zani/spice/platform/Bootstrap.kt | 6 -- .../spice/platform/TransformerBootstrap.kt | 11 +++ .../spice/platform/api/IClassTransformer.kt | 6 ++ .../wtf/zani/spice/platform/api/Platform.kt | 5 -- .../zani/spice/platform/api/Transformer.kt | 9 ++ .../platform/impl/fabric/FabricPlatform.kt | 18 +--- .../impl/fabric/asm/TransformerPlugin.kt | 29 +++++-- versions/build.gradle.kts | 14 ++- .../impl/forge/asm/TransformerPlugin.java | 34 -------- .../platform/impl/forge/ForgePlatform.kt | 20 +---- .../impl/forge/asm/ClassTransformer.kt | 87 +++++++++++++++++++ .../impl/forge/asm/TransformerPlugin.kt | 25 ++++++ 18 files changed, 222 insertions(+), 120 deletions(-) create mode 100644 modules/core/src/main/kotlin/wtf/zani/spice/patcher/lwjgl/LibraryTransformer.kt rename modules/core/src/main/kotlin/wtf/zani/spice/patcher/{ => lwjgl}/LwjglProvider.kt (98%) rename modules/core/src/main/kotlin/wtf/zani/spice/patcher/{ => lwjgl}/LwjglTransformer.kt (81%) create mode 100644 modules/core/src/main/kotlin/wtf/zani/spice/platform/TransformerBootstrap.kt create mode 100644 modules/core/src/main/kotlin/wtf/zani/spice/platform/api/Transformer.kt delete mode 100644 versions/src/main/java/wtf/zani/spice/platform/impl/forge/asm/TransformerPlugin.java create mode 100644 versions/src/main/kotlin/wtf/zani/spice/platform/impl/forge/asm/ClassTransformer.kt create mode 100644 versions/src/main/kotlin/wtf/zani/spice/platform/impl/forge/asm/TransformerPlugin.kt diff --git a/modules/common/src/main/kotlin/wtf/zani/spice/util/ClassUtil.kt b/modules/common/src/main/kotlin/wtf/zani/spice/util/ClassUtil.kt index 903c17d..3580eb3 100644 --- a/modules/common/src/main/kotlin/wtf/zani/spice/util/ClassUtil.kt +++ b/modules/common/src/main/kotlin/wtf/zani/spice/util/ClassUtil.kt @@ -22,4 +22,3 @@ fun getStrings(node: MethodNode): Set = } .flatten().toSet() -inline fun internalName(): String = T::class.java.name.replace(".", "/") diff --git a/modules/core/src/main/kotlin/wtf/zani/spice/patcher/LunarTransformer.kt b/modules/core/src/main/kotlin/wtf/zani/spice/patcher/LunarTransformer.kt index eebf0bc..f82018f 100644 --- a/modules/core/src/main/kotlin/wtf/zani/spice/patcher/LunarTransformer.kt +++ b/modules/core/src/main/kotlin/wtf/zani/spice/patcher/LunarTransformer.kt @@ -7,6 +7,10 @@ import wtf.zani.spice.platform.api.IClassTransformer import wtf.zani.spice.util.getStrings object LunarTransformer : IClassTransformer { + override fun getClassNames(): Array? { + return null + } + override fun transform(node: ClassNode) { if (!node.name.startsWith("com/moonsworth/lunar/")) return diff --git a/modules/core/src/main/kotlin/wtf/zani/spice/patcher/OptifineTransformer.kt b/modules/core/src/main/kotlin/wtf/zani/spice/patcher/OptifineTransformer.kt index a3075ee..a76d492 100644 --- a/modules/core/src/main/kotlin/wtf/zani/spice/patcher/OptifineTransformer.kt +++ b/modules/core/src/main/kotlin/wtf/zani/spice/patcher/OptifineTransformer.kt @@ -7,9 +7,11 @@ import org.objectweb.asm.tree.MethodNode import wtf.zani.spice.platform.api.IClassTransformer object OptifineTransformer : IClassTransformer { - override fun transform(node: ClassNode) { - if (node.name != "net/optifine/shaders/Shaders") return + override fun getClassNames(): Array { + return arrayOf("net.optifine.shaders.Shaders") + } + override fun transform(node: ClassNode) { node.methods.forEach { method -> (method as MethodNode) .instructions diff --git a/modules/core/src/main/kotlin/wtf/zani/spice/patcher/lwjgl/LibraryTransformer.kt b/modules/core/src/main/kotlin/wtf/zani/spice/patcher/lwjgl/LibraryTransformer.kt new file mode 100644 index 0000000..e37c501 --- /dev/null +++ b/modules/core/src/main/kotlin/wtf/zani/spice/patcher/lwjgl/LibraryTransformer.kt @@ -0,0 +1,22 @@ +package wtf.zani.spice.patcher.lwjgl + +import org.objectweb.asm.tree.ClassNode +import org.objectweb.asm.tree.LdcInsnNode +import org.objectweb.asm.tree.MethodNode +import wtf.zani.spice.platform.api.IClassTransformer + +object LibraryTransformer : IClassTransformer { + override fun getClassNames(): Array { + return arrayOf("org.lwjgl.system.Library") + } + + override fun transform(node: ClassNode) { + node.methods.forEach { method -> + (method as MethodNode).instructions + .iterator() + .asSequence() + .filter { it is LdcInsnNode && it.cst is String && it.cst == "java.library.path" } + .forEach { (it as LdcInsnNode).cst = "spice.library.path" } + } + } +} \ No newline at end of file diff --git a/modules/core/src/main/kotlin/wtf/zani/spice/patcher/LwjglProvider.kt b/modules/core/src/main/kotlin/wtf/zani/spice/patcher/lwjgl/LwjglProvider.kt similarity index 98% rename from modules/core/src/main/kotlin/wtf/zani/spice/patcher/LwjglProvider.kt rename to modules/core/src/main/kotlin/wtf/zani/spice/patcher/lwjgl/LwjglProvider.kt index 9d62a73..aeee9cd 100644 --- a/modules/core/src/main/kotlin/wtf/zani/spice/patcher/LwjglProvider.kt +++ b/modules/core/src/main/kotlin/wtf/zani/spice/patcher/lwjgl/LwjglProvider.kt @@ -1,4 +1,4 @@ -package wtf.zani.spice.patcher +package wtf.zani.spice.patcher.lwjgl import org.objectweb.asm.ClassReader import org.objectweb.asm.tree.ClassNode @@ -72,4 +72,4 @@ class LwjglProvider { return classNode } -} +} \ No newline at end of file diff --git a/modules/core/src/main/kotlin/wtf/zani/spice/patcher/LwjglTransformer.kt b/modules/core/src/main/kotlin/wtf/zani/spice/patcher/lwjgl/LwjglTransformer.kt similarity index 81% rename from modules/core/src/main/kotlin/wtf/zani/spice/patcher/LwjglTransformer.kt rename to modules/core/src/main/kotlin/wtf/zani/spice/patcher/lwjgl/LwjglTransformer.kt index 5dea6fe..8043e63 100644 --- a/modules/core/src/main/kotlin/wtf/zani/spice/patcher/LwjglTransformer.kt +++ b/modules/core/src/main/kotlin/wtf/zani/spice/patcher/lwjgl/LwjglTransformer.kt @@ -1,34 +1,21 @@ -package wtf.zani.spice.patcher +package wtf.zani.spice.patcher.lwjgl import net.weavemc.loader.api.util.asm -import org.objectweb.asm.Opcodes.* +import org.objectweb.asm.Opcodes import org.objectweb.asm.tree.ClassNode import org.objectweb.asm.tree.FieldNode -import org.objectweb.asm.tree.LdcInsnNode import org.objectweb.asm.tree.MethodNode -import wtf.zani.spice.patcher.fixes.OpenAlFixes -import wtf.zani.spice.patcher.fixes.OpenGlFixes import wtf.zani.spice.platform.api.IClassTransformer -import wtf.zani.spice.util.internalName -import java.nio.ByteBuffer object LwjglTransformer : IClassTransformer { val provider = LwjglProvider() + override fun getClassNames(): Array? { + return null + } override fun transform(node: ClassNode) { if (!node.name.startsWith("org/lwjgl")) return if (node.name == "org/lwjgl/opengl/PixelFormat") return - if (node.name == "org/lwjgl/system/Library") { - node.methods.forEach { method -> - (method as MethodNode).instructions - .iterator() - .asSequence() - .filter { it is LdcInsnNode && it.cst is String && it.cst == "java.library.path" } - .forEach { (it as LdcInsnNode).cst = "spice.library.path" } - } - - return - } val patch = provider.getClassNode(node.name) @@ -48,7 +35,7 @@ object LwjglTransformer : IClassTransformer { node .fields .forEach { field -> - (field as FieldNode).access = field.access and ACC_FINAL.inv() + (field as FieldNode).access = field.access and Opcodes.ACC_FINAL.inv() } } @@ -113,20 +100,20 @@ object LwjglTransformer : IClassTransformer { createMethod.name = "create" createMethod.desc = "()V" - createMethod.access = ACC_PUBLIC + ACC_STATIC + ACC_SYNTHETIC + createMethod.access = Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC + Opcodes.ACC_SYNTHETIC destroyMethod.name = "destroy" destroyMethod.desc = "()V" - destroyMethod.access = ACC_PUBLIC + ACC_STATIC + ACC_SYNTHETIC + destroyMethod.access = Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC + Opcodes.ACC_SYNTHETIC createMethod.instructions = asm { - invokestatic(internalName(), "create", "()V") + invokestatic("wtf/zani/spice/patcher/fixes/OpenAlFixes", "create", "()V") _return } destroyMethod.instructions = asm { - invokestatic(internalName(), "destroyContext", "()V") + invokestatic("wtf/zani/spice/patcher/fixes/OpenAlFixes", "destroyContext", "()V") _return } @@ -151,15 +138,15 @@ object LwjglTransformer : IClassTransformer { val method = MethodNode() method.name = "glShaderSource" - method.desc = "(IL${internalName()};)V" - method.access = ACC_PUBLIC + ACC_STATIC + ACC_SYNTHETIC + method.desc = "(ILjava/nio/ByteBuffer;)V" + method.access = Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC + Opcodes.ACC_SYNTHETIC method.instructions = asm { iload(0) aload(1) invokestatic( - internalName(), + "wtf/zani/spice/patcher/fixes/OpenGlFixes", method.name, method.desc ) @@ -172,4 +159,4 @@ object LwjglTransformer : IClassTransformer { } } } -} +} \ No newline at end of file diff --git a/modules/core/src/main/kotlin/wtf/zani/spice/platform/Bootstrap.kt b/modules/core/src/main/kotlin/wtf/zani/spice/platform/Bootstrap.kt index 9258126..365856a 100644 --- a/modules/core/src/main/kotlin/wtf/zani/spice/platform/Bootstrap.kt +++ b/modules/core/src/main/kotlin/wtf/zani/spice/platform/Bootstrap.kt @@ -1,14 +1,8 @@ package wtf.zani.spice.platform import wtf.zani.spice.Spice -import wtf.zani.spice.patcher.LwjglTransformer import wtf.zani.spice.platform.api.Platform -fun bootstrapTransformer(platform: Platform) { - platform.addTransformer(LwjglTransformer) - platform.appendToClassPath(LwjglTransformer.provider.url) -} - fun bootstrap(platform: Platform) { Spice.initialize(platform) } diff --git a/modules/core/src/main/kotlin/wtf/zani/spice/platform/TransformerBootstrap.kt b/modules/core/src/main/kotlin/wtf/zani/spice/platform/TransformerBootstrap.kt new file mode 100644 index 0000000..bd2bb80 --- /dev/null +++ b/modules/core/src/main/kotlin/wtf/zani/spice/platform/TransformerBootstrap.kt @@ -0,0 +1,11 @@ +package wtf.zani.spice.platform + +import wtf.zani.spice.patcher.lwjgl.LibraryTransformer +import wtf.zani.spice.patcher.lwjgl.LwjglTransformer +import wtf.zani.spice.platform.api.Transformer + +fun bootstrapTransformer(transformer: Transformer) { + transformer.addTransformer(LwjglTransformer) + transformer.appendToClassPath(LwjglTransformer.provider.url) + transformer.addTransformer(LibraryTransformer) +} \ No newline at end of file diff --git a/modules/core/src/main/kotlin/wtf/zani/spice/platform/api/IClassTransformer.kt b/modules/core/src/main/kotlin/wtf/zani/spice/platform/api/IClassTransformer.kt index ee98d8d..6359a1b 100644 --- a/modules/core/src/main/kotlin/wtf/zani/spice/platform/api/IClassTransformer.kt +++ b/modules/core/src/main/kotlin/wtf/zani/spice/platform/api/IClassTransformer.kt @@ -3,5 +3,11 @@ package wtf.zani.spice.platform.api import org.objectweb.asm.tree.ClassNode interface IClassTransformer { + /** + * @return The class names that this transformer should transform + * If null, the transformer will transform all classes + * Format like net.minecraft.client.Minecraft, not like net/minecraft/client/Minecraft + */ + fun getClassNames(): Array? fun transform(node: ClassNode) } diff --git a/modules/core/src/main/kotlin/wtf/zani/spice/platform/api/Platform.kt b/modules/core/src/main/kotlin/wtf/zani/spice/platform/api/Platform.kt index d9634da..250c69d 100644 --- a/modules/core/src/main/kotlin/wtf/zani/spice/platform/api/Platform.kt +++ b/modules/core/src/main/kotlin/wtf/zani/spice/platform/api/Platform.kt @@ -1,13 +1,8 @@ package wtf.zani.spice.platform.api -import java.net.URL - interface Platform { val id: ID - fun addTransformer(transformer: IClassTransformer) - fun appendToClassPath(url: URL) - enum class ID { Agent, Forge, diff --git a/modules/core/src/main/kotlin/wtf/zani/spice/platform/api/Transformer.kt b/modules/core/src/main/kotlin/wtf/zani/spice/platform/api/Transformer.kt new file mode 100644 index 0000000..505cb56 --- /dev/null +++ b/modules/core/src/main/kotlin/wtf/zani/spice/platform/api/Transformer.kt @@ -0,0 +1,9 @@ +package wtf.zani.spice.platform.api + +import java.net.URL + +interface Transformer { + fun addTransformer(transformer: IClassTransformer) + + fun appendToClassPath(url: URL) +} \ No newline at end of file diff --git a/versions/1.8.9-fabric/src/main/kotlin/wtf/zani/spice/platform/impl/fabric/FabricPlatform.kt b/versions/1.8.9-fabric/src/main/kotlin/wtf/zani/spice/platform/impl/fabric/FabricPlatform.kt index 0ab79d7..6ff82c4 100644 --- a/versions/1.8.9-fabric/src/main/kotlin/wtf/zani/spice/platform/impl/fabric/FabricPlatform.kt +++ b/versions/1.8.9-fabric/src/main/kotlin/wtf/zani/spice/platform/impl/fabric/FabricPlatform.kt @@ -1,29 +1,15 @@ package wtf.zani.spice.platform.impl.fabric -import wtf.zani.spice.platform.api.IClassTransformer import wtf.zani.spice.platform.api.Platform -import java.lang.reflect.Method -import java.net.URL -class FabricPlatform(private val loader: ClassLoader, private val addUrl: Method) : Platform { +class FabricPlatform : Platform { init { instance = this } override val id = Platform.ID.Fabric - internal val transformers = mutableListOf() - - override fun addTransformer(transformer: IClassTransformer) { - transformers += transformer - } - - override fun appendToClassPath(url: URL) { - println("appending $url to the classpath") - - addUrl(loader, url) - } companion object { - lateinit var instance: FabricPlatform + var instance: FabricPlatform = FabricPlatform() } } diff --git a/versions/1.8.9-fabric/src/main/kotlin/wtf/zani/spice/platform/impl/fabric/asm/TransformerPlugin.kt b/versions/1.8.9-fabric/src/main/kotlin/wtf/zani/spice/platform/impl/fabric/asm/TransformerPlugin.kt index 0ee81a7..a491716 100644 --- a/versions/1.8.9-fabric/src/main/kotlin/wtf/zani/spice/platform/impl/fabric/asm/TransformerPlugin.kt +++ b/versions/1.8.9-fabric/src/main/kotlin/wtf/zani/spice/platform/impl/fabric/asm/TransformerPlugin.kt @@ -4,21 +4,25 @@ import org.objectweb.asm.tree.ClassNode import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin import org.spongepowered.asm.mixin.extensibility.IMixinInfo import org.spongepowered.asm.service.MixinService +import wtf.zani.spice.platform.api.IClassTransformer +import wtf.zani.spice.platform.api.Transformer import wtf.zani.spice.platform.bootstrapTransformer -import wtf.zani.spice.platform.impl.fabric.FabricPlatform import wtf.zani.spice.platform.impl.fabric.util.collectResources import wtf.zani.spice.util.UrlByteArrayConnection +import java.lang.reflect.Method import java.net.URL import java.net.URLClassLoader import java.net.URLConnection import java.net.URLStreamHandler -class TransformerPlugin : IMixinConfigPlugin { +class TransformerPlugin : IMixinConfigPlugin, Transformer { private val mixinCache = mutableMapOf() private val classMapping = mutableMapOf() private val transformedClasses = mutableSetOf() - private lateinit var platform: FabricPlatform + private val transformers = mutableListOf() + private var addUrl: Method? = null + private var loader: ClassLoader? = null override fun onLoad(mixinPackage: String) { val classLoader = javaClass.classLoader @@ -39,9 +43,10 @@ class TransformerPlugin : IMixinConfigPlugin { val urlLoader = urlLoaderField.get(classLoader) as URLClassLoader val classTracker = MixinService.getService().classTracker - platform = FabricPlatform(classLoader, addUrl) + this.addUrl = addUrl + this.loader = classLoader - bootstrapTransformer(platform) + bootstrapTransformer(this) collectResources(urlLoader.urLs) .filter { it.endsWith(".class") } @@ -55,7 +60,7 @@ class TransformerPlugin : IMixinConfigPlugin { classMapping["/$base/$it.class"] = it } - platform.appendToClassPath(URL("transformer", null, -1, "/", object : URLStreamHandler() { + appendToClassPath(URL("transformer", null, -1, "/", object : URLStreamHandler() { override fun openConnection(url: URL): URLConnection? { if (!classMapping.contains(url.path)) return null @@ -87,7 +92,7 @@ class TransformerPlugin : IMixinConfigPlugin { ) { if (transformedClasses.contains(targetClassName)) return - platform.transformers.forEach { it.transform(targetClass) } + transformers.forEach { it.transform(targetClass) } transformedClasses.add(targetClassName) } @@ -102,4 +107,14 @@ class TransformerPlugin : IMixinConfigPlugin { targetClass.interfaces.remove(mixinClassName.replace(".", "/")) mixinCache.remove(mixinClassName) } + + override fun addTransformer(transformer: IClassTransformer) { + transformers += transformer + } + + override fun appendToClassPath(url: URL) { + println("appending $url to the classpath") + + addUrl?.let { it(loader, url) } + } } diff --git a/versions/build.gradle.kts b/versions/build.gradle.kts index 7cbfbc4..99502eb 100644 --- a/versions/build.gradle.kts +++ b/versions/build.gradle.kts @@ -26,6 +26,7 @@ loom { runConfigs { "client" { if (project.platform.isLegacyForge) { + property("fml.coreMods.load", "wtf.zani.spice.platform.impl.forge.asm.TransformerPlugin") programArgs("--tweakClass", tweakClass) } property("mixin.debug.export", "true") @@ -97,6 +98,8 @@ tasks { if (platform.isLegacyForge) { manifest { attributes += mapOf( + "FMLCorePluginContainsFMLMod" to "Yes, yes it does", + "FMLCorePlugin" to "wtf.zani.spice.platform.impl.forge.asm.TransformerPlugin", "ModSide" to "CLIENT", "ForceLoadAsMod" to true, "TweakOrder" to "0", @@ -122,9 +125,14 @@ tasks { exclude("fabric.mod.json") if (platform.isLegacyForge) { exclude("**/mods.toml") - exclude("META-INF/versions/**") - exclude("**/module-info.class") - exclude("**/package-info.class") + exclude( + "**/module-info.class", + "**/package-info.class", + "META-INF/proguard/**", + "META-INF/maven/**", + "META-INF/versions/**", + "META-INF/com.android.tools/**", + ) } } } diff --git a/versions/src/main/java/wtf/zani/spice/platform/impl/forge/asm/TransformerPlugin.java b/versions/src/main/java/wtf/zani/spice/platform/impl/forge/asm/TransformerPlugin.java deleted file mode 100644 index 33b39f0..0000000 --- a/versions/src/main/java/wtf/zani/spice/platform/impl/forge/asm/TransformerPlugin.java +++ /dev/null @@ -1,34 +0,0 @@ -package wtf.zani.spice.platform.impl.forge.asm; -//#if FORGE - -import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; - -import java.util.Map; - -public class TransformerPlugin implements IFMLLoadingPlugin { - @Override - public String[] getASMTransformerClass() { - return new String[0]; - } - - @Override - public String getModContainerClass() { - return null; - } - - @Override - public String getSetupClass() { - return null; - } - - @Override - public void injectData(Map map) { - - } - - @Override - public String getAccessTransformerClass() { - return null; - } -} -//#endif \ No newline at end of file diff --git a/versions/src/main/kotlin/wtf/zani/spice/platform/impl/forge/ForgePlatform.kt b/versions/src/main/kotlin/wtf/zani/spice/platform/impl/forge/ForgePlatform.kt index 310b1bd..db5bce7 100644 --- a/versions/src/main/kotlin/wtf/zani/spice/platform/impl/forge/ForgePlatform.kt +++ b/versions/src/main/kotlin/wtf/zani/spice/platform/impl/forge/ForgePlatform.kt @@ -1,31 +1,17 @@ package wtf.zani.spice.platform.impl.forge //#if FORGE -import wtf.zani.spice.platform.api.IClassTransformer import wtf.zani.spice.platform.api.Platform -import java.lang.reflect.Method -import java.net.URL -class ForgePlatform(private val loader: ClassLoader, private val addUrl: Method) : Platform { +class ForgePlatform : Platform { init { instance = this } - override val id = Platform.ID.Fabric - internal val transformers = mutableListOf() - - override fun addTransformer(transformer: IClassTransformer) { - transformers += transformer - } - - override fun appendToClassPath(url: URL) { - println("appending $url to the classpath") - - addUrl(loader, url) - } + override val id = Platform.ID.Forge companion object { - lateinit var instance: ForgePlatform + var instance: ForgePlatform = ForgePlatform() } } //#endif \ No newline at end of file diff --git a/versions/src/main/kotlin/wtf/zani/spice/platform/impl/forge/asm/ClassTransformer.kt b/versions/src/main/kotlin/wtf/zani/spice/platform/impl/forge/asm/ClassTransformer.kt new file mode 100644 index 0000000..4c008c2 --- /dev/null +++ b/versions/src/main/kotlin/wtf/zani/spice/platform/impl/forge/asm/ClassTransformer.kt @@ -0,0 +1,87 @@ +package wtf.zani.spice.platform.impl.forge.asm +//#if FORGE + +import com.google.common.collect.ArrayListMultimap +import com.google.common.collect.Multimap +import org.objectweb.asm.ClassReader +import org.objectweb.asm.ClassWriter +import org.objectweb.asm.tree.ClassNode +import wtf.zani.spice.platform.api.IClassTransformer +import wtf.zani.spice.platform.api.Transformer +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.net.URL + +class ClassTransformer : net.minecraft.launchwrapper.IClassTransformer, Transformer { + + private val transformerMap: Multimap = + ArrayListMultimap.create() + private val transformers: MutableList = ArrayList() + private val outputBytecode = System.getProperty("debugBytecode", "false").toBoolean() + private fun registerTransformer(transformer: IClassTransformer) { + val classes = transformer.getClassNames() + if (classes == null) { + transformers.add(transformer) + } else { + for (cls in classes) { + transformerMap.put(cls, transformer) + } + } + } + + override fun transform(name: String, transformedName: String, bytes: ByteArray?): ByteArray? { + if (bytes == null) return null + val transformers = transformerMap[transformedName] + transformers.addAll(this.transformers) + if (transformers.isEmpty()) return bytes + val classReader = ClassReader(bytes) + val classNode = ClassNode() + classReader.accept(classNode, ClassReader.EXPAND_FRAMES) + for (transformer in transformers) { + transformer.transform(classNode) + } + val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) + try { + classNode.accept(classWriter) + } catch (e: Throwable) { + e.printStackTrace() + } + if (outputBytecode) { + val bytecodeDirectory = File("bytecode") + + // anonymous classes + val transformedClassName = if (transformedName.contains("$")) { + transformedName.replace('$', '.') + ".class" + } else { + "$transformedName.class" + } + val bytecodeOutput = File(bytecodeDirectory, transformedClassName) + try { + if (!bytecodeDirectory.exists()) { + bytecodeDirectory.mkdirs() + } + if (!bytecodeOutput.exists()) { + bytecodeOutput.createNewFile() + } + } catch (e: Exception) { + e.printStackTrace() + } + try { + FileOutputStream(bytecodeOutput).use { os -> os.write(classWriter.toByteArray()) } + } catch (e: IOException) { + e.printStackTrace() + } + } + return classWriter.toByteArray() + } + + override fun addTransformer(transformer: IClassTransformer) { + registerTransformer(transformer) + } + + override fun appendToClassPath(url: URL) { + //TODO: Implement + } +} +//#endif \ No newline at end of file diff --git a/versions/src/main/kotlin/wtf/zani/spice/platform/impl/forge/asm/TransformerPlugin.kt b/versions/src/main/kotlin/wtf/zani/spice/platform/impl/forge/asm/TransformerPlugin.kt new file mode 100644 index 0000000..e2bd487 --- /dev/null +++ b/versions/src/main/kotlin/wtf/zani/spice/platform/impl/forge/asm/TransformerPlugin.kt @@ -0,0 +1,25 @@ +package wtf.zani.spice.platform.impl.forge.asm +//#if FORGE + +import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin + +class TransformerPlugin : IFMLLoadingPlugin { + override fun getASMTransformerClass(): Array { + return arrayOf(ClassTransformer::class.java.getName()) + } + + override fun getModContainerClass(): String? { + return null + } + + override fun getSetupClass(): String? { + return null + } + + override fun injectData(map: Map) {} + override fun getAccessTransformerClass(): String? { + return null + } +} + +//#endif \ No newline at end of file