Skip to content

Commit

Permalink
base implementation of forge transformers
Browse files Browse the repository at this point in the history
split platform from transformer stuff
  • Loading branch information
Wyvest committed Jul 30, 2024
1 parent 428876c commit 258f842
Show file tree
Hide file tree
Showing 18 changed files with 222 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,3 @@ fun getStrings(node: MethodNode): Set<String> =
}
.flatten().toSet()

inline fun <reified T> internalName(): String = T::class.java.name.replace(".", "/")
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import wtf.zani.spice.platform.api.IClassTransformer
import wtf.zani.spice.util.getStrings

object LunarTransformer : IClassTransformer {
override fun getClassNames(): Array<String>? {
return null
}

override fun transform(node: ClassNode) {
if (!node.name.startsWith("com/moonsworth/lunar/")) return

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> {
return arrayOf("net.optifine.shaders.Shaders")
}

override fun transform(node: ClassNode) {
node.methods.forEach { method ->
(method as MethodNode)
.instructions
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String> {
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" }
}
}
}
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -72,4 +72,4 @@ class LwjglProvider {

return classNode
}
}
}
Original file line number Diff line number Diff line change
@@ -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<String>? {
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)
Expand All @@ -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()
}
}

Expand Down Expand Up @@ -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<OpenAlFixes>(), "create", "()V")
invokestatic("wtf/zani/spice/patcher/fixes/OpenAlFixes", "create", "()V")

_return
}

destroyMethod.instructions = asm {
invokestatic(internalName<OpenAlFixes>(), "destroyContext", "()V")
invokestatic("wtf/zani/spice/patcher/fixes/OpenAlFixes", "destroyContext", "()V")

_return
}
Expand All @@ -151,15 +138,15 @@ object LwjglTransformer : IClassTransformer {
val method = MethodNode()

method.name = "glShaderSource"
method.desc = "(IL${internalName<ByteBuffer>()};)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<OpenGlFixes>(),
"wtf/zani/spice/patcher/fixes/OpenGlFixes",
method.name,
method.desc
)
Expand All @@ -172,4 +159,4 @@ object LwjglTransformer : IClassTransformer {
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -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)
}
Original file line number Diff line number Diff line change
@@ -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)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>?
fun transform(node: ClassNode)
}
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package wtf.zani.spice.platform.api

import java.net.URL

interface Transformer {
fun addTransformer(transformer: IClassTransformer)

fun appendToClassPath(url: URL)
}
Original file line number Diff line number Diff line change
@@ -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<IClassTransformer>()

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()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, ByteArray>()
private val classMapping = mutableMapOf<String, String>()
private val transformedClasses = mutableSetOf<String>()

private lateinit var platform: FabricPlatform
private val transformers = mutableListOf<IClassTransformer>()
private var addUrl: Method? = null
private var loader: ClassLoader? = null

override fun onLoad(mixinPackage: String) {
val classLoader = javaClass.classLoader
Expand All @@ -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") }
Expand All @@ -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

Expand Down Expand Up @@ -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)
}

Expand All @@ -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) }
}
}
14 changes: 11 additions & 3 deletions versions/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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",
Expand All @@ -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/**",
)
}
}
}
Expand Down
Loading

0 comments on commit 258f842

Please sign in to comment.