From b1a5022c8c21bc14b01657d336ccc02a84c4747f Mon Sep 17 00:00:00 2001 From: shedaniel Date: Wed, 30 Dec 2020 18:52:48 +0800 Subject: [PATCH] Remove old unused tasks, add the remap of mixins for the common modules --- build.gradle | 6 +- gradle.properties | 3 +- .../architect/plugin/ArchitectPlugin.kt | 10 +- .../plugin/ArchitectPluginExtension.kt | 40 +--- .../architect/plugin/RemapMCPTask.kt | 181 +++++++++++++++++- 5 files changed, 182 insertions(+), 58 deletions(-) diff --git a/build.gradle b/build.gradle index e2ed4ce..e64f592 100644 --- a/build.gradle +++ b/build.gradle @@ -28,14 +28,16 @@ dependencies { implementation gradleApi() implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72" implementation "org.jetbrains.kotlin:kotlin-reflect:1.3.72" - implementation "me.shedaniel:forgified-fabric-loom:0.5.12" - runtime "me.shedaniel:forgified-fabric-loom:0.5.12" + implementation "me.shedaniel:forgified-fabric-loom:$loom_version" + runtime "me.shedaniel:forgified-fabric-loom:$loom_version" implementation "net.fabricmc:tiny-remapper:0.3.0.70" implementation "net.fabricmc:tiny-mappings-parser:0.2.2.14" implementation "org.ow2.asm:asm:8.0" implementation "org.ow2.asm:asm-commons:8.0" implementation "org.ow2.asm:asm-tree:8.0" implementation "org.ow2.asm:asm-util:8.0" + implementation "org.zeroturnaround:zt-zip:1.13" + implementation "com.google.code.gson:gson:2.8.5" } compileKotlin { diff --git a/gradle.properties b/gradle.properties index 29e08e8..cf41dc1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,2 @@ -kotlin.code.style=official \ No newline at end of file +kotlin.code.style=official +loom_version=0.5.16 \ No newline at end of file diff --git a/src/main/kotlin/me/shedaniel/architect/plugin/ArchitectPlugin.kt b/src/main/kotlin/me/shedaniel/architect/plugin/ArchitectPlugin.kt index 0e9d876..12d20c5 100644 --- a/src/main/kotlin/me/shedaniel/architect/plugin/ArchitectPlugin.kt +++ b/src/main/kotlin/me/shedaniel/architect/plugin/ArchitectPlugin.kt @@ -29,16 +29,8 @@ class ArchitectPlugin : Plugin { } } - project.tasks.register("remapMcp", RemapMCPTask::class.java) { - it.group = "Architect" - } - - project.tasks.register("remapMcpFakeMod", RemapMCPTask::class.java) { - it.fakeMod = true - it.group = "Architect" - } - project.tasks.register("transformForge", RemapMCPTask::class.java) { + it.fakeMod = false it.remapMcp = false it.group = "Architect" } diff --git a/src/main/kotlin/me/shedaniel/architect/plugin/ArchitectPluginExtension.kt b/src/main/kotlin/me/shedaniel/architect/plugin/ArchitectPluginExtension.kt index 2d3500b..8a0447e 100644 --- a/src/main/kotlin/me/shedaniel/architect/plugin/ArchitectPluginExtension.kt +++ b/src/main/kotlin/me/shedaniel/architect/plugin/ArchitectPluginExtension.kt @@ -57,31 +57,11 @@ open class ArchitectPluginExtension(val project: Project) { } as RemapJarTask if (forgeEnabled) { - val remapMCPTask = project.tasks.getByName("remapMcp") { - it as RemapMCPTask - - it.input.set(transformArchitectJarTask.archiveFile.get()) - it.archiveClassifier.set("mcp") - it.dependsOn(transformArchitectJarTask) - buildTask.dependsOn(it) - it.outputs.upToDateWhen { false } - } as RemapMCPTask - - val remapMCPFakeModTask = project.tasks.getByName("remapMcpFakeMod") { - it as RemapMCPTask - - it.input.set(transformArchitectJarTask.archiveFile.get()) - it.archiveClassifier.set("mcpGenerateMod") - it.dependsOn(transformArchitectJarTask) - buildTask.dependsOn(it) - it.outputs.upToDateWhen { false } - } as RemapMCPTask - val transformForgeTask = project.tasks.getByName("transformForge") { it as RemapMCPTask it.input.set(transformArchitectJarTask.archiveFile.get()) - it.archiveClassifier.set("transformForge") + it.archiveClassifier.set("transformedForge") it.dependsOn(transformArchitectJarTask) buildTask.dependsOn(it) it.outputs.upToDateWhen { false } @@ -91,27 +71,13 @@ open class ArchitectPluginExtension(val project: Project) { it as RemapMCPTask it.input.set(transformArchitectJarTask.archiveFile.get()) - it.archiveClassifier.set("transformForgeFakeMod") + it.archiveClassifier.set("transformedForgeFakeMod") it.dependsOn(transformArchitectJarTask) buildTask.dependsOn(it) it.outputs.upToDateWhen { false } } as RemapMCPTask project.artifacts { - it.add( - "mcp", mapOf( - "file" to remapMCPTask.archiveFile.get().asFile, - "type" to "jar", - "builtBy" to remapMCPTask - ) - ) - it.add( - "mcpGenerateMod", mapOf( - "file" to remapMCPFakeModTask.archiveFile.get().asFile, - "type" to "jar", - "builtBy" to remapMCPFakeModTask - ) - ) it.add( "transformForge", mapOf( "file" to transformForgeTask.archiveFile.get().asFile, @@ -127,6 +93,8 @@ open class ArchitectPluginExtension(val project: Project) { ) ) } + + project.extensions.getByType(LoomGradleExtension::class.java).generateSrgTiny = true } project.artifacts { diff --git a/src/main/kotlin/me/shedaniel/architect/plugin/RemapMCPTask.kt b/src/main/kotlin/me/shedaniel/architect/plugin/RemapMCPTask.kt index 5ec650d..a88fcf6 100644 --- a/src/main/kotlin/me/shedaniel/architect/plugin/RemapMCPTask.kt +++ b/src/main/kotlin/me/shedaniel/architect/plugin/RemapMCPTask.kt @@ -2,6 +2,9 @@ package me.shedaniel.architect.plugin +import com.google.gson.GsonBuilder +import com.google.gson.JsonObject +import com.google.gson.JsonParser import me.shedaniel.architect.plugin.utils.GradleSupport import net.fabricmc.loom.LoomGradleExtension import net.fabricmc.loom.util.LoggerFilter @@ -20,13 +23,14 @@ import org.objectweb.asm.Opcodes import org.objectweb.asm.tree.AnnotationNode import org.objectweb.asm.tree.ClassNode import org.objectweb.asm.tree.MethodInsnNode -import java.io.File -import java.io.FileNotFoundException -import java.io.InputStream +import org.zeroturnaround.zip.ByteSource +import org.zeroturnaround.zip.ZipUtil +import java.io.* import java.net.URL import java.nio.file.Files import java.nio.file.Path import java.util.* +import java.util.jar.Manifest import java.util.zip.ZipEntry import java.util.zip.ZipInputStream import java.util.zip.ZipOutputStream @@ -34,7 +38,6 @@ import kotlin.collections.LinkedHashSet open class RemapMCPTask : Jar() { private val fromM: String = "named" - private val toM: String = "official" var remapMcp = true var fakeMod = false val input: RegularFileProperty = GradleSupport.getFileProperty(project) @@ -102,7 +105,14 @@ open class RemapMCPTask : Jar() { remapperBuilder.skipLocalVariableMapping(true) } - project.logger.lifecycle(":remapping " + input.fileName) + project.logger.lifecycle( + ":${ + listOfNotNull( + "remapping".takeIf { remapMcp }, + "transforming" + ).joinToString(" and ") + } " + input.fileName + " => " + output.fileName + if (fakeMod) " (with fake mod)" else "" + ) val architectFolder = project.rootProject.buildDir.resolve("tmp/architect") architectFolder.deleteRecursively() @@ -133,7 +143,7 @@ modId = "$fakeModId" try { OutputConsumerPath.Builder(output).build().use { outputConsumer -> - outputConsumer.addNonClassFiles(input, NonClassCopyMode.SKIP_META_INF, null) + outputConsumer.addNonClassFiles(input, NonClassCopyMode.FIX_META_INF, null) outputConsumer.addNonClassFiles(architectFolder.toPath(), NonClassCopyMode.UNCHANGED, null) remapper.readClassPath(*classpath) remapper.readInputs(intermediate) @@ -165,13 +175,164 @@ modId = "$fakeModId" architectFolder.deleteRecursively() remapper.finish() -// intermediate.toFile().delete() + intermediate.toFile().delete() + + fixMixins(output.toFile()) if (!Files.exists(output)) { throw RuntimeException("Failed to remap $input to $output - file missing!") } } + private fun fixMixins(output: File) { + val loomExtension = project.extensions.getByType(LoomGradleExtension::class.java) + val gson = GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create() + val mixinConfigs = mutableMapOf() + val refmap = loomExtension.getRefmapName() + ZipUtil.iterate(output) { stream, entry -> + if (!entry.isDirectory && entry.name.endsWith(".json") && + !entry.name.contains("/") && !entry.name.contains("\\") + ) { + try { + InputStreamReader(stream).use { reader -> + val json: JsonObject? = gson.fromJson(reader, JsonObject::class.java) + if (json != null) { + val hasMixins = json.has("mixins") && json["mixins"].isJsonArray + val hasClient = json.has("client") && json["client"].isJsonArray + val hasServer = json.has("server") && json["server"].isJsonArray + if (json.has("package") && (hasMixins || hasClient || hasServer)) { + mixinConfigs[entry.name] = json.deepCopy().also { + it.addProperty("refmap", refmap) + } + } + } + } + } catch (ignored: Exception) { + } + } + } + ZipUtil.replaceEntries(output, mixinConfigs.entries.map { (path, obj) -> + ByteSource(path, gson.toJson(obj).toByteArray()) + }.toTypedArray()) + if (mixinConfigs.isNotEmpty()) { + if (ZipUtil.containsEntry(output, "META-INF/MANIFEST.MF")) { + ZipUtil.transformEntry(output, "META-INF/MANIFEST.MF") { input, zipEntry, out -> + val manifest = Manifest(input) + manifest.mainAttributes.putValue("MixinConfigs", mixinConfigs.keys.joinToString(",")) + out.putNextEntry(ZipEntry(zipEntry.name)) + manifest.write(out) + out.closeEntry() + } + } + } + ZipUtil.transformEntry(output, refmap) { input, zipEntry, out -> + val refmapElement: JsonObject = JsonParser().parse(InputStreamReader(input)).asJsonObject.deepCopy() + if (refmapElement.has("mappings")) { + refmapElement["mappings"].asJsonObject.entrySet().forEach { (_, value) -> + remapRefmap(value.asJsonObject) + } + } + if (refmapElement.has("data")) { + val data = refmapElement["data"].asJsonObject + if (data.has("named:intermediary")) { + data.add("searge", data["named:intermediary"].deepCopy().also { + it.asJsonObject.entrySet().forEach { (_, value) -> + remapRefmap(value.asJsonObject) + } + }) + data.remove("named:intermediary") + } + } + out.putNextEntry(ZipEntry(zipEntry.name)) + out.write(gson.toJson(refmapElement).toByteArray()) + out.closeEntry() + } + } + + private fun remapRefmap(obj: JsonObject) { + val srg = project.extensions.getByType(LoomGradleExtension::class.java).mappingsProvider.mappingsWithSrg + val methodPattern = "L(.*);(.*)(\\(.*)".toRegex() + val fieldPattern = "(.*):(.*)".toRegex() + + obj.keySet().forEach { key -> + val originalRef = obj[key].asString + + val methodMatch = methodPattern.matchEntire(originalRef) + val fieldMatch = fieldPattern.matchEntire(originalRef) + + when { + methodMatch != null -> { + val matchedClass = + srg.classes.firstOrNull { it.getName("intermediary") == methodMatch.groups[1]!!.value } + val replacementName: String = srg.classes.asSequence() + .flatMap { it.methods.asSequence() } + .filter { it.getName("intermediary") == methodMatch.groups[2]!!.value } + .firstOrNull { it.getDescriptor("intermediary") == methodMatch.groups[3]!!.value } + ?.getName("srg") ?: methodMatch.groups[2]!!.value + obj.addProperty( + key, originalRef + .replaceFirst( + methodMatch.groups[1]!!.value, + matchedClass?.getName("srg") ?: methodMatch.groups[1]!!.value + ) + .replaceFirst(methodMatch.groups[2]!!.value, replacementName) + .replaceFirst(methodMatch.groups[3]!!.value, methodMatch.groups[3]!!.value.remapDescriptor { + srg.classes.firstOrNull { def -> def.getName("intermediary") == it }?.getName("srg") + ?: it + }) + ) + } + fieldMatch != null -> { + val replacementName: String = srg.classes.asSequence() + .flatMap { it.fields.asSequence() } + .filter { it.getName("intermediary") == fieldMatch.groups[1]!!.value } + .firstOrNull { it.getDescriptor("intermediary") == fieldMatch.groups[2]!!.value } + ?.getName("srg") ?: fieldMatch.groups[1]!!.value + obj.addProperty( + key, originalRef + .replaceFirst(fieldMatch.groups[1]!!.value, replacementName) + .replaceFirst(fieldMatch.groups[2]!!.value, fieldMatch.groups[2]!!.value.remapDescriptor { + srg.classes.firstOrNull { def -> def.getName("intermediary") == it }?.getName("srg") + ?: it + }) + ) + } + else -> logger.warn("Failed to remap refmap value: $originalRef") + } + } + } + + private fun String.remapDescriptor(classMappings: (String) -> String): String { + return try { + val reader = StringReader(this) + val result = StringBuilder() + var insideClassName = false + val className = StringBuilder() + while (true) { + val c: Int = reader.read() + if (c == -1) { + break + } + if (c == ';'.toInt()) { + insideClassName = false + result.append(classMappings(className.toString())) + } + if (insideClassName) { + className.append(c.toChar()) + } else { + result.append(c.toChar()) + } + if (!insideClassName && c == 'L'.toInt()) { + insideClassName = true + className.setLength(0) + } + } + result.toString() + } catch (e: IOException) { + throw AssertionError(e) + } + } + private fun remapToMcp(parent: IMappingProvider?, mojmapToMcpClass: Map?): IMappingProvider = IMappingProvider { out -> out.acceptClass("net/fabricmc/api/Environment", "net/minecraftforge/api/distmarker/OnlyIn") @@ -254,8 +415,8 @@ modId = "$fakeModId" val cancellable = "Lnet/minecraftforge/eventbus/api/Cancelable;" private fun transform(node: ClassNode): ClassNode { - if(node.access and Opcodes.ACC_INTERFACE == 0) { - if(node.visibleAnnotations?.any { it.desc == forgeEvent || it.desc == forgeEventCancellable} == true) { + if (node.access and Opcodes.ACC_INTERFACE == 0) { + if (node.visibleAnnotations?.any { it.desc == forgeEvent || it.desc == forgeEventCancellable } == true) { node.superName = "net/minecraftforge/eventbus/api/Event" node.methods.forEach { if (it.name == "") { @@ -275,7 +436,7 @@ modId = "$fakeModId" } // if @ForgeEventCancellable, add the cancellable annotation from forge node.visibleAnnotations.apply { - if(any {it.desc == forgeEventCancellable}) { + if (any { it.desc == forgeEventCancellable }) { add(AnnotationNode(cancellable)) } }