From 4514190276443ded8afd313964922ce95886eabc Mon Sep 17 00:00:00 2001 From: shedaniel Date: Sat, 10 Oct 2020 13:47:14 +0800 Subject: [PATCH] Transform invisible @Environment annotations to visible @OnlyIn --- .../plugin/ArchitectPluginExtension.kt | 2 + .../architect/plugin/RemapMCPTask.kt | 144 +++++++++++++----- 2 files changed, 110 insertions(+), 36 deletions(-) diff --git a/src/main/kotlin/me/shedaniel/architect/plugin/ArchitectPluginExtension.kt b/src/main/kotlin/me/shedaniel/architect/plugin/ArchitectPluginExtension.kt index 02f5512..912ac8c 100644 --- a/src/main/kotlin/me/shedaniel/architect/plugin/ArchitectPluginExtension.kt +++ b/src/main/kotlin/me/shedaniel/architect/plugin/ArchitectPluginExtension.kt @@ -1,3 +1,5 @@ +@file:Suppress("UnstableApiUsage") + package me.shedaniel.architect.plugin import org.gradle.api.Project diff --git a/src/main/kotlin/me/shedaniel/architect/plugin/RemapMCPTask.kt b/src/main/kotlin/me/shedaniel/architect/plugin/RemapMCPTask.kt index 521da90..2d35ebc 100644 --- a/src/main/kotlin/me/shedaniel/architect/plugin/RemapMCPTask.kt +++ b/src/main/kotlin/me/shedaniel/architect/plugin/RemapMCPTask.kt @@ -13,8 +13,8 @@ import net.fabricmc.tinyremapper.TinyRemapper import org.gradle.api.file.RegularFileProperty import org.gradle.api.tasks.TaskAction import org.gradle.jvm.tasks.Jar -import org.objectweb.asm.ClassWriter -import org.objectweb.asm.Opcodes +import org.objectweb.asm.* +import org.objectweb.asm.tree.ClassNode import java.io.File import java.io.FileNotFoundException import java.io.InputStream @@ -22,6 +22,9 @@ import java.net.URL import java.nio.file.Files import java.nio.file.Path import java.util.* +import java.util.zip.ZipEntry +import java.util.zip.ZipInputStream +import java.util.zip.ZipOutputStream import kotlin.collections.LinkedHashSet @@ -30,28 +33,62 @@ open class RemapMCPTask : Jar() { private val toM: String = "official" var fakeMod = false val input: RegularFileProperty = GradleSupport.getfileProperty(project) + private val environmentClass = "net/fabricmc/api/Environment" @TaskAction fun doTask() { val input: Path = this.input.asFile.get().toPath() + val intermediate: Path = input.parent.resolve(input.toFile().nameWithoutExtension + "-intermediate.jar") val output: Path = this.archiveFile.get().asFile.toPath() + intermediate.toFile().delete() output.toFile().delete() if (!Files.exists(input)) { throw FileNotFoundException(input.toString()) } + run { + val zipOutputStream = ZipOutputStream(intermediate.toFile().outputStream()) + zipOutputStream.use { + ZipInputStream(Files.newInputStream(input)).use { + while (true) { + val entry = it.nextEntry ?: break + zipOutputStream.putNextEntry(ZipEntry(entry.name)) + var allBytes = it.readBytes() + if (entry.name.toString().endsWith(".class")) { + val reader = ClassReader(allBytes) + if ((reader.access and Opcodes.ACC_MODULE) == 0) { + val node = ClassNode(Opcodes.ASM8) + reader.accept(node, ClassReader.EXPAND_FRAMES) + val writer = ClassWriter(0) + transform(node).accept(writer) + allBytes = writer.toByteArray() + } + } + zipOutputStream.write(allBytes) + zipOutputStream.closeEntry() + } + } + } + } + val remapperBuilder: TinyRemapper.Builder = TinyRemapper.newRemapper() val classpathFiles: Set = LinkedHashSet( - project.configurations.getByName("compileClasspath").files + project.configurations.getByName("compileClasspath").files ) - val classpath = classpathFiles.asSequence().map { obj: File -> obj.toPath() }.filter { p: Path -> input != p && Files.exists(p) }.toList().toTypedArray() + val classpath = classpathFiles.asSequence().map { obj: File -> obj.toPath() } + .filter { p: Path -> input != p && Files.exists(p) }.toList().toTypedArray() val mappings = getMappings() val mojmapToMcpClass = createMojmapToMcpClass(mappings) - remapperBuilder.withMappings(remapToMcp(TinyRemapperMappingsHelper.create(mappings, fromM, fromM, false), mojmapToMcpClass)) + remapperBuilder.withMappings( + remapToMcp( + TinyRemapperMappingsHelper.create(mappings, fromM, fromM, false), + mojmapToMcpClass + ) + ) remapperBuilder.ignoreFieldDesc(true) remapperBuilder.skipLocalVariableMapping(true) @@ -64,26 +101,23 @@ open class RemapMCPTask : Jar() { if (fakeMod) { val modsToml = architectFolder.resolve("META-INF/mods.toml") modsToml.parentFile.mkdirs() - modsToml.writeText(""" + modsToml.writeText( + """ modLoader = "javafml" loaderVersion = "[33,)" license = "Generated" [[mods]] modId = "$fakeModId" - """.trimIndent()) + """.trimIndent() + ) val mcmeta = architectFolder.resolve("pack.mcmeta") mcmeta.parentFile.mkdirs() - mcmeta.writeText(""" + mcmeta.writeText( + """ {"pack":{"description":"Generated","pack_format":4}} - """.trimIndent()) + """.trimIndent() + ) } - /*val manifestFile = architectFolder.resolve("META-INF/MANIFEST.MF") - manifestFile.parentFile.mkdirs() - manifestFile.writeText(""" -Manifest-Version: 1.0 -FMLModType: LIBRARY - - """.trimIndent())*/ val remapper = remapperBuilder.build() @@ -92,7 +126,7 @@ FMLModType: LIBRARY outputConsumer.addNonClassFiles(input, NonClassCopyMode.SKIP_META_INF, null) outputConsumer.addNonClassFiles(architectFolder.toPath(), NonClassCopyMode.UNCHANGED, null) remapper.readClassPath(*classpath) - remapper.readInputs(input) + remapper.readInputs(intermediate) remapper.apply(outputConsumer) if (fakeMod) { @@ -121,34 +155,46 @@ FMLModType: LIBRARY architectFolder.deleteRecursively() remapper.finish() + intermediate.toFile().delete() + if (!Files.exists(output)) { throw RuntimeException("Failed to remap $input to $output - file missing!") } } - private fun remapToMcp(parent: IMappingProvider, mojmapToMcpClass: Map): IMappingProvider = IMappingProvider { - it.acceptClass("net/fabricmc/api/Environment", "net/minecraftforge/api/distmarker/OnlyIn") - it.acceptClass("net/fabricmc/api/EnvType", "net/minecraftforge/api/distmarker/Dist") - it.acceptField(IMappingProvider.Member("net/fabricmc/api/EnvType", "SERVER", "Lnet/fabricmc/api/EnvType;"), "DEDICATED_SERVER") + private fun remapToMcp(parent: IMappingProvider, mojmapToMcpClass: Map): IMappingProvider = + IMappingProvider { + it.acceptClass("net/fabricmc/api/Environment", "net/minecraftforge/api/distmarker/OnlyIn") + it.acceptClass("net/fabricmc/api/EnvType", "net/minecraftforge/api/distmarker/Dist") + it.acceptField( + IMappingProvider.Member("net/fabricmc/api/EnvType", "SERVER", "Lnet/fabricmc/api/EnvType;"), + "DEDICATED_SERVER" + ) - parent.load(object : IMappingProvider.MappingAcceptor { - override fun acceptClass(srcName: String?, dstName: String?) { - it.acceptClass(srcName, mojmapToMcpClass[srcName] ?: srcName) - } + parent.load(object : IMappingProvider.MappingAcceptor { + override fun acceptClass(srcName: String?, dstName: String?) { + it.acceptClass(srcName, mojmapToMcpClass[srcName] ?: srcName) + } - override fun acceptMethod(method: IMappingProvider.Member?, dstName: String?) { - } + override fun acceptMethod(method: IMappingProvider.Member?, dstName: String?) { + } - override fun acceptMethodArg(method: IMappingProvider.Member?, lvIndex: Int, dstName: String?) { - } + override fun acceptMethodArg(method: IMappingProvider.Member?, lvIndex: Int, dstName: String?) { + } - override fun acceptMethodVar(method: IMappingProvider.Member?, lvIndex: Int, startOpIdx: Int, asmIndex: Int, dstName: String?) { - } + override fun acceptMethodVar( + method: IMappingProvider.Member?, + lvIndex: Int, + startOpIdx: Int, + asmIndex: Int, + dstName: String? + ) { + } - override fun acceptField(field: IMappingProvider.Member?, dstName: String?) { - } - }) - } + override fun acceptField(field: IMappingProvider.Member?, dstName: String?) { + } + }) + } private fun getMappings(): TinyTree { val loomExtension = project.extensions.getByType(LoomGradleExtension::class.java) @@ -156,7 +202,7 @@ FMLModType: LIBRARY } private fun getRootExtension(): ArchitectPluginExtension = - project.rootProject.extensions.getByType(ArchitectPluginExtension::class.java) + project.rootProject.extensions.getByType(ArchitectPluginExtension::class.java) private fun createMojmapToMcpClass(mappings: TinyTree): Map { val mcpMappings = readMCPMappings(getRootExtension().minecraft) @@ -191,4 +237,30 @@ FMLModType: LIBRARY } } } + + private fun transform(node: ClassNode): ClassNode { + node.visibleAnnotations = (node.visibleAnnotations ?: mutableListOf()).apply { + val invisibleEnvironments = + node.invisibleAnnotations?.filter { it.desc == "L${environmentClass};" } ?: emptyList() + node.invisibleAnnotations?.removeAll(invisibleEnvironments) + addAll(invisibleEnvironments) + } + node.fields.forEach { field -> + field.visibleAnnotations = (field.visibleAnnotations ?: mutableListOf()).apply { + val invisibleEnvironments = + field.invisibleAnnotations?.filter { it.desc == "L${environmentClass};" } ?: emptyList() + field.invisibleAnnotations?.removeAll(invisibleEnvironments) + addAll(invisibleEnvironments) + } + } + node.methods.forEach { method -> + method.visibleAnnotations = (method.visibleAnnotations ?: mutableListOf()).apply { + val invisibleEnvironments = + method.invisibleAnnotations?.filter { it.desc == "L${environmentClass};" } ?: emptyList() + method.invisibleAnnotations?.removeAll(invisibleEnvironments) + addAll(invisibleEnvironments) + } + } + return node + } } \ No newline at end of file