diff options
-rw-r--r-- | build.gradle.kts | 6 | ||||
-rw-r--r-- | gradle/libs.versions.toml | 7 | ||||
-rw-r--r-- | settings.gradle.kts | 1 | ||||
-rw-r--r-- | testagent/build.gradle.kts | 14 | ||||
-rw-r--r-- | testagent/src/main/java/moe/nea/firmament/testagent/AgentMain.java | 21 | ||||
-rw-r--r-- | testagent/src/main/java/moe/nea/firmament/testagent/ProtectedToPublicClassRewriter.java | 31 | ||||
-rw-r--r-- | testagent/src/main/java/moe/nea/firmament/testagent/ProtectedToPublicClassTransformer.java | 30 |
7 files changed, 109 insertions, 1 deletions
diff --git a/build.gradle.kts b/build.gradle.kts index 05912a7..1d5478f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -214,6 +214,9 @@ val hotswap by configurations.creating { val nonModImplentation by configurations.creating { configurations.implementation.get().extendsFrom(this) } +val testAgent by configurations.creating { + isVisible = false +} val configuredSourceSet = createIsolatedSourceSet("configured", @@ -306,6 +309,7 @@ dependencies { testImplementation("io.kotest:kotest-runner-junit5:6.0.0.M1") + testAgent(project(":testagent", configuration = "shadow")) implementation(project(":symbols")) ksp(project(":symbols")) @@ -371,11 +375,13 @@ tasks.test { val wd = file("build/testWorkDir") workingDir(wd) dependsOn(downloadTestRepo) + dependsOn(testAgent) doFirst { wd.mkdirs() wd.resolve("config").deleteRecursively() systemProperty("firmament.testrepo", downloadTestRepo.flatMap { it.outputDirectory.asFile }.map { it.absolutePath }.get()) + jvmArgs("-javaagent:${testAgent.singleFile.absolutePath}") } systemProperty("jdk.attach.allowAttachSelf", "true") jvmArgs("-XX:+EnableDynamicAgentLoading") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 83e1ae7..74de8e8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -85,6 +85,9 @@ basicMath = "0.6.1" # Update from https://mvnrepository.com/artifact/net.lenni0451.classtransform/core classtransform = "1.14.0" +# Update from https://mvnrepository.com/artifact/org.ow2.asm/asm/ +asm = "9.7.1" + [libraries] minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" } fabric_loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric_loader" } @@ -124,6 +127,8 @@ basicMath = { module = "me.shedaniel.cloth:basic-math", version.ref = "basicMath classTransform-mixinsTranslator = { module = "net.lenni0451.classtransform:mixinstranslator", version.ref = "classtransform" } classTransform-core = { module = "net.lenni0451.classtransform:core", version.ref = "classtransform" } +asm = { module = "org.ow2.asm:asm", version.ref = "asm" } + [bundles] runtime_required = [ "rei_fabric", @@ -145,4 +150,4 @@ kotlin_plugin_serialization = { id = "org.jetbrains.kotlin.plugin.serialization" kotlin_plugin_powerassert = { id = "org.jetbrains.kotlin.plugin.power-assert", version.ref = "kotlin" } kotlin_plugin_ksp = { id = "com.google.devtools.ksp", version.ref = "kotlin_ksp" } loom = { id = "dev.architectury.loom", version.ref = "loom" } -shadow = { id = "com.github.johnrengelman.shadow",version="8.1.1" } +shadow = { id = "com.github.johnrengelman.shadow", version = "8.1.1" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 5c4a313..aef468a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -37,3 +37,4 @@ rootProject.name = "Firmament" include("symbols") include("javaplugin") +include("testagent") diff --git a/testagent/build.gradle.kts b/testagent/build.gradle.kts new file mode 100644 index 0000000..3bd8c8c --- /dev/null +++ b/testagent/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + java + alias(libs.plugins.shadow) +} +dependencies { + implementation(libs.asm) +} +tasks.withType<Jar> { + val agentMain = "moe.nea.firmament.testagent.AgentMain" + manifest.attributes( + "Agent-Class" to agentMain, + "Premain-Class" to agentMain, + ) +} diff --git a/testagent/src/main/java/moe/nea/firmament/testagent/AgentMain.java b/testagent/src/main/java/moe/nea/firmament/testagent/AgentMain.java new file mode 100644 index 0000000..79023d8 --- /dev/null +++ b/testagent/src/main/java/moe/nea/firmament/testagent/AgentMain.java @@ -0,0 +1,21 @@ +package moe.nea.firmament.testagent; + +import java.lang.instrument.Instrumentation; + +public class AgentMain { + + public static void premain( + String agentArgs, Instrumentation inst) { + System.out.println("Pre-Main Firmament Test Agent"); + AgentMain.inject(inst); + } + + public static void agentmain( + String agentArgs, Instrumentation inst) { + System.out.println("Injected Firmament Test Agent"); + AgentMain.inject(inst); + } + + private static void inject(Instrumentation inst) { + inst.addTransformer(new ProtectedToPublicClassTransformer(inst)); } +} diff --git a/testagent/src/main/java/moe/nea/firmament/testagent/ProtectedToPublicClassRewriter.java b/testagent/src/main/java/moe/nea/firmament/testagent/ProtectedToPublicClassRewriter.java new file mode 100644 index 0000000..7d9aa56 --- /dev/null +++ b/testagent/src/main/java/moe/nea/firmament/testagent/ProtectedToPublicClassRewriter.java @@ -0,0 +1,31 @@ +package moe.nea.firmament.testagent; + +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +public class ProtectedToPublicClassRewriter extends ClassVisitor { + public ProtectedToPublicClassRewriter(ClassWriter writer) { + super(Opcodes.ASM9, writer); + } + + int makePublic(int flags) { + if ((flags & Opcodes.ACC_PROTECTED) != 0) + return (flags & ~Opcodes.ACC_PROTECTED) | Opcodes.ACC_PUBLIC; + if ((flags & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE)) == 0) + return flags | Opcodes.ACC_PUBLIC; + return flags; + } + + @Override + public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { + return super.visitField(makePublic(access), name, descriptor, signature, value); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { + return super.visitMethod(makePublic(access), name, descriptor, signature, exceptions); + } +} diff --git a/testagent/src/main/java/moe/nea/firmament/testagent/ProtectedToPublicClassTransformer.java b/testagent/src/main/java/moe/nea/firmament/testagent/ProtectedToPublicClassTransformer.java new file mode 100644 index 0000000..5d59035 --- /dev/null +++ b/testagent/src/main/java/moe/nea/firmament/testagent/ProtectedToPublicClassTransformer.java @@ -0,0 +1,30 @@ +package moe.nea.firmament.testagent; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; +import java.lang.instrument.Instrumentation; +import java.security.ProtectionDomain; + +public class ProtectedToPublicClassTransformer implements ClassFileTransformer { + public ProtectedToPublicClassTransformer(Instrumentation inst) { + } + + @Override + public byte[] transform(ClassLoader loader, + String className, + Class<?> classBeingRedefined, + ProtectionDomain protectionDomain, + byte[] classfileBuffer) + throws IllegalClassFormatException { + if (!className.startsWith("net/minecraft/")) return classfileBuffer; + if (classfileBuffer == null) return null; + var reader = new ClassReader(classfileBuffer); + var writer = new ClassWriter(0); + var transformer = new ProtectedToPublicClassRewriter(writer); + reader.accept(transformer, 0); + return writer.toByteArray(); + } +} |