]> git.lizzy.rs Git - LightOverlay.git/blob - architectPlugin/src/main/kotlin/me/shedaniel/plugin/architect/RemapMCPTask.kt
Properly remap EnvType
[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.File
17 import java.io.FileNotFoundException
18 import java.io.InputStream
19 import java.net.URL
20 import java.nio.file.Files
21 import java.nio.file.Path
22
23
24 open class RemapMCPTask : Jar() {
25     private val fromM: String = "named"
26     private val toM: String = "official"
27     val input: RegularFileProperty = GradleSupport.getfileProperty(project)
28
29     @TaskAction
30     fun doTask() {
31         val input: Path = this.input.asFile.get().toPath()
32         val output: Path = this.archiveFile.get().asFile.toPath()
33
34         output.toFile().delete()
35
36         if (!Files.exists(input)) {
37             throw FileNotFoundException(input.toString())
38         }
39
40         val remapperBuilder: TinyRemapper.Builder = TinyRemapper.newRemapper()
41
42         val classpathFiles: Set<File> = LinkedHashSet(
43                 project.configurations.getByName("compileClasspath").files
44         )
45         val classpath = classpathFiles.asSequence().map { obj: File -> obj.toPath() }.filter { p: Path -> input != p && Files.exists(p) }.toList().toTypedArray()
46
47         val mappings = getMappings()
48         val mojmapToMcpClass = createMojmapToMcpClass(mappings)
49         remapperBuilder.withMappings(remapToMcp(TinyRemapperMappingsHelper.create(mappings, fromM, fromM, false), mojmapToMcpClass))
50         remapperBuilder.ignoreFieldDesc(true)
51         remapperBuilder.skipLocalVariableMapping(true)
52
53         project.logger.lifecycle(":remapping " + input.fileName)
54
55         val architectFolder = project.rootProject.buildDir.resolve("tmp/architect")
56         architectFolder.deleteRecursively()
57         architectFolder.mkdirs()
58         val manifestFile = architectFolder.resolve("META-INF/MANIFEST.MF")
59         manifestFile.parentFile.mkdirs()
60         manifestFile.writeText("""
61 Manifest-Version: 1.0
62 FMLModType: LIBRARY
63
64         """.trimIndent())
65
66         val remapper = remapperBuilder.build()
67
68         try {
69             OutputConsumerPath.Builder(output).build().use { outputConsumer ->
70                 outputConsumer.addNonClassFiles(input, NonClassCopyMode.SKIP_META_INF, null)
71                 outputConsumer.addNonClassFiles(architectFolder.toPath(), NonClassCopyMode.UNCHANGED, null)
72                 remapper.readClassPath(*classpath)
73                 remapper.readInputs(input)
74                 remapper.apply(outputConsumer)
75             }
76         } catch (e: Exception) {
77             remapper.finish()
78             throw RuntimeException("Failed to remap $input to $output", e)
79         }
80
81         architectFolder.deleteRecursively()
82         remapper.finish()
83
84         if (!Files.exists(output)) {
85             throw RuntimeException("Failed to remap $input to $output - file missing!")
86         }
87     }
88
89     private fun remapToMcp(parent: IMappingProvider, mojmapToMcpClass: Map<String, String>): IMappingProvider = IMappingProvider {
90         it.acceptClass("net/fabricmc/api/Environment", "net/minecraftforge/api/distmarker/OnlyIn")
91         it.acceptClass("net/fabricmc/api/EnvType", "net/minecraftforge/api/distmarker/Dist")
92         it.acceptField(IMappingProvider.Member("net/fabricmc/api/EnvType", "SERVER", "Lnet/fabricmc/api/EnvType;"), "DEDICATED_SERVER")
93
94         parent.load(object : IMappingProvider.MappingAcceptor {
95             override fun acceptClass(srcName: String?, dstName: String?) {
96                 it.acceptClass(srcName, mojmapToMcpClass[srcName] ?: srcName)
97             }
98
99             override fun acceptMethod(method: IMappingProvider.Member?, dstName: String?) {
100             }
101
102             override fun acceptMethodArg(method: IMappingProvider.Member?, lvIndex: Int, dstName: String?) {
103             }
104
105             override fun acceptMethodVar(method: IMappingProvider.Member?, lvIndex: Int, startOpIdx: Int, asmIndex: Int, dstName: String?) {
106             }
107
108             override fun acceptField(field: IMappingProvider.Member?, dstName: String?) {
109             }
110         })
111     }
112
113     private fun getMappings(): TinyTree {
114         val loomExtension = project.extensions.getByType(LoomGradleExtension::class.java)
115         return loomExtension.mappingsProvider.mappings
116     }
117
118     private fun getRootExtension(): ArchitectPluginExtension =
119             project.rootProject.extensions.getByType(ArchitectPluginExtension::class.java)
120
121     private fun createMojmapToMcpClass(mappings: TinyTree): Map<String, String> {
122         val mcpMappings = readMCPMappings(getRootExtension().minecraft)
123         val mutableMap = mutableMapOf<String, String>()
124         mappings.classes.forEach { clazz ->
125             val official = clazz.getName("official")
126             val named = clazz.getName("named")
127             val mcp = mcpMappings[official]
128             if (mcp != null) {
129                 mutableMap[named] = mcp
130             }
131         }
132         return mutableMap
133     }
134
135     private fun readMCPMappings(version: String): Map<String, String> {
136         val file = project.rootProject.file(".gradle/mappings/mcp-$version.tsrg")
137         if (file.exists().not()) {
138             file.parentFile.mkdirs()
139             file.writeText(URL("https://raw.githubusercontent.com/MinecraftForge/MCPConfig/master/versions/release/$version/joined.tsrg").readText())
140         }
141         return mutableMapOf<String, String>().also { readMappings(it, file.inputStream()) }
142     }
143
144     private fun readMappings(mutableMap: MutableMap<String, String>, inputStream: InputStream) {
145         inputStream.bufferedReader().forEachLine {
146             if (!it.startsWith("\t")) {
147                 val split = it.split(" ")
148                 val obf = split[0]
149                 val className = split[1]
150                 mutableMap[obf] = className
151             }
152         }
153     }
154 }