1 @file:Suppress("UnstableApiUsage")
3 package me.shedaniel.plugin.architect
5 import net.fabricmc.loom.LoomGradleExtension
6 import net.fabricmc.loom.util.GradleSupport
7 import net.fabricmc.loom.util.TinyRemapperMappingsHelper
8 import net.fabricmc.mapping.tree.TinyTree
9 import net.fabricmc.tinyremapper.IMappingProvider
10 import net.fabricmc.tinyremapper.NonClassCopyMode
11 import net.fabricmc.tinyremapper.OutputConsumerPath
12 import net.fabricmc.tinyremapper.TinyRemapper
13 import org.gradle.api.file.RegularFileProperty
14 import org.gradle.api.tasks.TaskAction
15 import org.gradle.jvm.tasks.Jar
16 import java.io.FileNotFoundException
17 import java.io.InputStream
19 import java.nio.file.Files
20 import java.nio.file.Path
23 open class RemapMCPTask : Jar() {
24 private val fromM: String = "named"
25 private val toM: String = "official"
26 val input: RegularFileProperty = GradleSupport.getfileProperty(project)
30 val input: Path = this.input.asFile.get().toPath()
31 val output: Path = this.archiveFile.get().asFile.toPath()
33 output.toFile().delete()
35 if (!Files.exists(input)) {
36 throw FileNotFoundException(input.toString())
39 val remapperBuilder: TinyRemapper.Builder = TinyRemapper.newRemapper()
40 val mappings = getMappings()
41 val mojmapToMcpClass = createMojmapToMcpClass(mappings)
42 remapperBuilder.withMappings(remapToMcp(TinyRemapperMappingsHelper.create(mappings, fromM, toM, false), mojmapToMcpClass))
44 project.logger.lifecycle(":remapping " + input.fileName)
46 val architectFolder = project.rootProject.buildDir.resolve("tmp/architect")
47 architectFolder.deleteRecursively()
48 architectFolder.mkdirs()
49 val manifestFile = architectFolder.resolve("META-INF/MANIFEST.MF")
50 manifestFile.parentFile.mkdirs()
51 manifestFile.writeText("""
57 val remapper = remapperBuilder.build()
60 OutputConsumerPath.Builder(output).build().use { outputConsumer ->
61 outputConsumer.addNonClassFiles(input, NonClassCopyMode.SKIP_META_INF, null)
62 outputConsumer.addNonClassFiles(architectFolder.toPath(), NonClassCopyMode.UNCHANGED, null)
63 remapper.readInputs(input)
64 remapper.apply(outputConsumer)
66 } catch (e: Exception) {
68 throw RuntimeException("Failed to remap $input to $output", e)
71 architectFolder.deleteRecursively()
74 if (!Files.exists(output)) {
75 throw RuntimeException("Failed to remap $input to $output - file missing!")
79 private fun remapToMcp(parent: IMappingProvider, mojmapToMcpClass: Map<String, String>): IMappingProvider = IMappingProvider {
80 it.acceptClass("net/fabricmc/api/Environment","net/minecraftforge/api/distmarker/OnlyIn")
81 it.acceptClass("net/fabricmc/api/EnvType","net/minecraftforge/api/distmarker/Dist")
82 it.acceptField(IMappingProvider.Member("net/fabricmc/api/EnvType", "SERVER", "Lnet/fabricmc/api/EnvType;"),"DEDICATED_SERVER")
84 parent.load(object : IMappingProvider.MappingAcceptor {
85 override fun acceptClass(srcName: String?, dstName: String?) {
86 it.acceptClass(srcName, mojmapToMcpClass[srcName] ?: srcName)
89 override fun acceptMethod(method: IMappingProvider.Member?, dstName: String?) {
90 it.acceptMethod(method, dstName)
93 override fun acceptMethodArg(method: IMappingProvider.Member?, lvIndex: Int, dstName: String?) {
94 it.acceptMethodArg(method, lvIndex, dstName)
97 override fun acceptMethodVar(method: IMappingProvider.Member?, lvIndex: Int, startOpIdx: Int, asmIndex: Int, dstName: String?) {
98 it.acceptMethodVar(method, lvIndex, startOpIdx, asmIndex, dstName)
101 override fun acceptField(field: IMappingProvider.Member?, dstName: String?) {
102 it.acceptField(field, dstName)
107 private fun getMappings(): TinyTree {
108 val loomExtension = project.extensions.getByType(LoomGradleExtension::class.java)
109 return loomExtension.mappingsProvider.mappings
112 private fun getRootExtension(): ArchitectPluginExtension =
113 project.rootProject.extensions.getByType(ArchitectPluginExtension::class.java)
115 private fun createMojmapToMcpClass(mappings: TinyTree): Map<String, String> {
116 val mcpMappings = readMCPMappings(getRootExtension().minecraft)
117 val mutableMap = mutableMapOf<String, String>()
118 mappings.classes.forEach { clazz ->
119 val official = clazz.getName("official")
120 val named = clazz.getName("named")
121 val mcp = mcpMappings[official]
123 mutableMap[named] = mcp
129 private fun readMCPMappings(version: String): Map<String, String> {
130 val file = project.rootProject.file(".gradle/mappings/mcp-$version.tsrg")
131 if (file.exists().not()) {
132 file.parentFile.mkdirs()
133 file.writeText(URL("https://raw.githubusercontent.com/MinecraftForge/MCPConfig/master/versions/release/$version/joined.tsrg").readText())
135 return mutableMapOf<String, String>().also { readMappings(it, file.inputStream()) }
138 private fun readMappings(mutableMap: MutableMap<String, String>, inputStream: InputStream) {
139 inputStream.bufferedReader().forEachLine {
140 if (!it.startsWith("\t")) {
141 val split = it.split(" ")
143 val className = split[1]
144 mutableMap[obf] = className