]> git.lizzy.rs Git - LightOverlay.git/blob - architectPlugin/src/main/kotlin/me/shedaniel/plugin/architect/RemapMCPTask.kt
e6a62b09b0bad6217f95b57bb666b9f1df1a6865
[LightOverlay.git] / architectPlugin / src / main / kotlin / me / shedaniel / plugin / architect / RemapMCPTask.kt
1 @file:Suppress("UnstableApiUsage")
2
3 package me.shedaniel.plugin.architect
4
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
18 import java.net.URL
19 import java.nio.file.Files
20 import java.nio.file.Path
21
22
23 open class RemapMCPTask : Jar() {
24     private val fromM: String = "named"
25     private val toM: String = "official"
26     val input: RegularFileProperty = GradleSupport.getfileProperty(project)
27
28     @TaskAction
29     fun doTask() {
30         val input: Path = this.input.asFile.get().toPath()
31         val output: Path = this.archiveFile.get().asFile.toPath()
32
33         output.toFile().delete()
34
35         if (!Files.exists(input)) {
36             throw FileNotFoundException(input.toString())
37         }
38
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))
43
44         project.logger.lifecycle(":remapping " + input.fileName)
45
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("""
52 Manifest-Version: 1.0
53 FMLModType: LIBRARY
54         """.trimIndent())
55
56         val remapper = remapperBuilder.build()
57
58         try {
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)
64             }
65         } catch (e: Exception) {
66             remapper.finish()
67             throw RuntimeException("Failed to remap $input to $output", e)
68         }
69
70         architectFolder.deleteRecursively()
71         remapper.finish()
72
73         if (!Files.exists(output)) {
74             throw RuntimeException("Failed to remap $input to $output - file missing!")
75         }
76     }
77
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") 
82         
83         parent.load(object : IMappingProvider.MappingAcceptor {
84             override fun acceptClass(srcName: String?, dstName: String?) {
85                 it.acceptClass(srcName, mojmapToMcpClass[srcName] ?: srcName)
86             }
87
88             override fun acceptMethod(method: IMappingProvider.Member?, dstName: String?) {
89                 it.acceptMethod(method, dstName)
90             }
91
92             override fun acceptMethodArg(method: IMappingProvider.Member?, lvIndex: Int, dstName: String?) {
93                 it.acceptMethodArg(method, lvIndex, dstName)
94             }
95
96             override fun acceptMethodVar(method: IMappingProvider.Member?, lvIndex: Int, startOpIdx: Int, asmIndex: Int, dstName: String?) {
97                 it.acceptMethodVar(method, lvIndex, startOpIdx, asmIndex, dstName)
98             }
99
100             override fun acceptField(field: IMappingProvider.Member?, dstName: String?) {
101                 it.acceptField(field, dstName)
102             }
103         })
104     }
105
106     private fun getMappings(): TinyTree {
107         val loomExtension = project.extensions.getByType(LoomGradleExtension::class.java)
108         return loomExtension.mappingsProvider.mappings
109     }
110
111     private fun getRootExtension(): ArchitectPluginExtension =
112             project.rootProject.extensions.getByType(ArchitectPluginExtension::class.java)
113
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]
121             if (mcp != null) {
122                 mutableMap[named] = mcp
123             }
124         }
125         return mutableMap
126     }
127
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())
133         }
134         return mutableMapOf<String, String>().also { readMappings(it, file.inputStream()) }
135     }
136
137     private fun readMappings(mutableMap: MutableMap<String, String>, inputStream: InputStream) {
138         inputStream.bufferedReader().forEachLine {
139             if (!it.startsWith("\t")) {
140                 val split = it.split(" ")
141                 val obf = split[0]
142                 val className = split[1]
143                 mutableMap[obf] = className
144             }
145         }
146     }
147 }