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("""
56 val remapper = remapperBuilder.build()
59 OutputConsumerPath.Builder(output).build().use { outputConsumer ->
60 outputConsumer.addNonClassFiles(input, NonClassCopyMode.SKIP_META_INF, null)
61 outputConsumer.addNonClassFiles(architectFolder.toPath(), NonClassCopyMode.UNCHANGED, null)
62 remapper.readInputs(input)
63 remapper.apply(outputConsumer)
65 } catch (e: Exception) {
67 throw RuntimeException("Failed to remap $input to $output", e)
70 architectFolder.deleteRecursively()
73 if (!Files.exists(output)) {
74 throw RuntimeException("Failed to remap $input to $output - file missing!")
78 private fun remapToMcp(parent: IMappingProvider, mojmapToMcpClass: Map<String, String>): IMappingProvider = IMappingProvider {
79 it.acceptClass("net/fabricmc/api/Environment","net/minecraftforge/api/distmarker/OnlyIn")
80 it.acceptClass("net/fabricmc/api/EnvType","net/minecraftforge/api/distmarker/Dist")
81 it.acceptField(IMappingProvider.Member("net/fabricmc/api/EnvType", "SERVER", "Lnet/fabricmc/api/EnvType;"),"DEDICATED_SERVER")
83 parent.load(object : IMappingProvider.MappingAcceptor {
84 override fun acceptClass(srcName: String?, dstName: String?) {
85 it.acceptClass(srcName, mojmapToMcpClass[srcName] ?: srcName)
88 override fun acceptMethod(method: IMappingProvider.Member?, dstName: String?) {
89 it.acceptMethod(method, dstName)
92 override fun acceptMethodArg(method: IMappingProvider.Member?, lvIndex: Int, dstName: String?) {
93 it.acceptMethodArg(method, lvIndex, dstName)
96 override fun acceptMethodVar(method: IMappingProvider.Member?, lvIndex: Int, startOpIdx: Int, asmIndex: Int, dstName: String?) {
97 it.acceptMethodVar(method, lvIndex, startOpIdx, asmIndex, dstName)
100 override fun acceptField(field: IMappingProvider.Member?, dstName: String?) {
101 it.acceptField(field, dstName)
106 private fun getMappings(): TinyTree {
107 val loomExtension = project.extensions.getByType(LoomGradleExtension::class.java)
108 return loomExtension.mappingsProvider.mappings
111 private fun getRootExtension(): ArchitectPluginExtension =
112 project.rootProject.extensions.getByType(ArchitectPluginExtension::class.java)
114 private fun createMojmapToMcpClass(mappings: TinyTree): Map<String, String> {
115 val mcpMappings = readMCPMappings(getRootExtension().minecraft)
116 val mutableMap = mutableMapOf<String, String>()
117 mappings.classes.forEach { clazz ->
118 val official = clazz.getName("official")
119 val named = clazz.getName("named")
120 val mcp = mcpMappings[official]
122 mutableMap[named] = mcp
128 private fun readMCPMappings(version: String): Map<String, String> {
129 val file = project.rootProject.file(".gradle/mappings/mcp-$version.tsrg")
130 if (file.exists().not()) {
131 file.parentFile.mkdirs()
132 file.writeText(URL("https://raw.githubusercontent.com/MinecraftForge/MCPConfig/master/versions/release/$version/joined.tsrg").readText())
134 return mutableMapOf<String, String>().also { readMappings(it, file.inputStream()) }
137 private fun readMappings(mutableMap: MutableMap<String, String>, inputStream: InputStream) {
138 inputStream.bufferedReader().forEachLine {
139 if (!it.startsWith("\t")) {
140 val split = it.split(" ")
142 val className = split[1]
143 mutableMap[obf] = className