start supporting other mapping formats

This commit is contained in:
moehreag 2024-07-01 18:55:47 +02:00
parent 97c27ac542
commit b6b212fdd9
4 changed files with 126 additions and 41 deletions

View file

@ -10,7 +10,7 @@ object ProjectStorage {
fun get(project: Project): ProjectData { fun get(project: Project): ProjectData {
if (!data.containsKey(project)) { if (!data.containsKey(project)) {
data[project] = ProjectData(null, null, null, null, null) data[project] = ProjectData(null, null, null, null, null, null)
} }
return data[project]!! return data[project]!!
} }
@ -22,5 +22,6 @@ class ProjectData(
var minecraftVersion: String?, var minecraftVersion: String?,
var remappedGameJarPath: Path?, var remappedGameJarPath: Path?,
var mappings: MappingBundle?, var mappings: MappingBundle?,
var mappingsName: String? var mappingsName: String?,
var targetNamespace: String?
) )

View file

@ -1,6 +1,7 @@
package dev.frogmc.phytotelma.ext package dev.frogmc.phytotelma.ext
import dev.frogmc.phytotelma.PhytotelmaPlugin import dev.frogmc.phytotelma.PhytotelmaPlugin
import dev.frogmc.phytotelma.mappings.renameDstNamespace
import dev.frogmc.thyroxine.api.data.MappingBundle import dev.frogmc.thyroxine.api.data.MappingBundle
import dev.frogmc.thyroxine.parser.tiny.TinyV2Parser import dev.frogmc.thyroxine.parser.tiny.TinyV2Parser
import dev.frogmc.thyroxine.provider.MojmapProvider import dev.frogmc.thyroxine.provider.MojmapProvider
@ -22,19 +23,15 @@ abstract class MinecraftConfiguration @Inject constructor(
) { ) {
var version: String? = null var version: String? = null
var mappings: Provider<MappingBundle> = mojmapParchment() internal var mappings: Provider<MappingBundle> = mojmapParchment()
private lateinit var mappingsName: String internal lateinit var mappingsName: String
internal lateinit var targetNamespace: String
internal fun mappingsName(): String {
return mappingsName
}
fun mojmapParchment(): Provider<MappingBundle> { fun mojmapParchment(): Provider<MappingBundle> {
return mojmapParchment {} return mojmapParchment {}
} }
fun mojmapParchment(action: Action<ParchmentConfiguration>): Provider<MappingBundle> { fun mojmapParchment(action: Action<ParchmentConfiguration>): Provider<MappingBundle> {
mappingsName = "mojmap"
return project.provider { return project.provider {
val conf = objects.newInstance(ParchmentConfiguration::class.java) val conf = objects.newInstance(ParchmentConfiguration::class.java)
conf.gameVersion = version conf.gameVersion = version
@ -44,12 +41,13 @@ abstract class MinecraftConfiguration @Inject constructor(
if (conf.version == null) { if (conf.version == null) {
conf.version = ParchmentProvider.findForMinecraftVersion(conf.gameVersion) conf.version = ParchmentProvider.findForMinecraftVersion(conf.gameVersion)
} }
mappingsName = "mojmap($version)+parchment(${conf.gameVersion}, ${conf.version})"
return@provider MappingBundle.merge( return@provider MappingBundle.merge(
MojmapProvider.get( MojmapProvider.get(
version, version,
cacheDir.resolve("net/minecraft/client/$version/client-$version.txt") cacheDir.resolve("net/minecraft/client/$version/client-$version.txt")
).orElseThrow(), ).orElseThrow().reverse(),
ParchmentProvider.getParchment( ParchmentProvider.getParchment(
version, version,
cacheDir.resolve("org/parchmentmc/parchment/${conf.gameVersion}/${conf.version}") cacheDir.resolve("org/parchmentmc/parchment/${conf.gameVersion}/${conf.version}")
@ -58,23 +56,35 @@ abstract class MinecraftConfiguration @Inject constructor(
} }
} }
fun mojmap(): Provider<MappingBundle> {
return project.provider {
val cacheDir = PhytotelmaPlugin.globalCacheDir
mappingsName = "mojmap($version)"
return@provider MojmapProvider.get(
version,
cacheDir.resolve("net/minecraft/client/$version/client-$version.txt")
).orElseThrow().reverse()
}
}
fun quiltMappings(action: Action<VersionConfiguration>): Provider<MappingBundle> { fun quiltMappings(action: Action<VersionConfiguration>): Provider<MappingBundle> {
mappingsName = "quilt"
return project.provider { return project.provider {
val conf = objects.newInstance(VersionConfiguration::class.java) val conf = objects.newInstance(VersionConfiguration::class.java)
action.execute(conf) action.execute(conf)
if (conf.version == null) { if (conf.version == null) {
error("No version provided for quilt mappings!") error("No version provided for quilt mappings!")
} }
mappingsName = "quilt(${conf.version})"
targetNamespace = "quilt"
// Use qm via intermediary because hashed publications are broken
return@provider twoStepMappings( return@provider twoStepMappings(
"org.quiltmc:hashed:$version", "net.fabricmc:intermediary:$version:v2",
"org.quiltmc:quilt-mappings:${conf.version}:v2" "org.quiltmc:quilt-mappings:${conf.version}:intermediary-v2"
) ).renameDstNamespace(targetNamespace)
} }
} }
fun twoStepMappings(action: Action<TwoStepMappingsConfiguration>): Provider<MappingBundle> { fun twoStepMappings(action: Action<TwoStepMappingsConfiguration>): Provider<MappingBundle> {
mappingsName = "custom/two-step"
return project.provider { return project.provider {
val conf = objects.newInstance(TwoStepMappingsConfiguration::class.java) val conf = objects.newInstance(TwoStepMappingsConfiguration::class.java)
action.execute(conf) action.execute(conf)
@ -84,37 +94,34 @@ abstract class MinecraftConfiguration @Inject constructor(
if (conf.second == null) { if (conf.second == null) {
error("No version provided for second mapping step!") error("No version provided for second mapping step!")
} }
return@provider twoStepMappings(conf.first!!, conf.second!!) mappingsName = "custom/two-step(${conf.first!!}, ${conf.second!!})"
val bundle = twoStepMappings(conf.first!!, conf.second!!)
targetNamespace = bundle.flattenData().dstNamespace
return@provider bundle
} }
} }
fun tinyMappings(action: Action<NameConfiguration>): Provider<MappingBundle> { fun tinyMappings(action: Action<NameConfiguration>): Provider<MappingBundle> {
mappingsName = "custom/tiny"
return project.provider { return project.provider {
val conf = objects.newInstance(NameConfiguration::class.java) val conf = objects.newInstance(NameConfiguration::class.java)
action.execute(conf) action.execute(conf)
if (conf.name == null) { if (conf.name == null) {
error("No maven coordinate provided for tiny mappings!") error("No maven coordinate provided for tiny mappings!")
} }
return@provider tinyMappings(conf.name!!) mappingsName = "custom/tiny(${conf.name})"
} val bundle = tinyMappings(conf.name!!)
} targetNamespace = bundle.flattenData().dstNamespace
fun mappings(action: Action<MappingBundle>): Provider<MappingBundle> {
mappingsName = "custom"
return project.provider {
val bundle = MappingBundle()
action.execute(bundle)
return@provider bundle return@provider bundle
} }
} }
fun layer(action: Action<LayerConfiguration>): Provider<MappingBundle> { fun mappings(action: Action<MappingBundle>): Provider<MappingBundle> {
return project.provider { return project.provider {
val config = objects.newInstance(LayerConfiguration::class.java) val bundle = MappingBundle()
action.execute(config) action.execute(bundle)
mappingsName = "custom(${bundle.srcNamespaces()}, ${bundle.dstNamespaces()})"
return@provider MappingBundle.merge(*config.layers.map { it.get() }.toTypedArray()) targetNamespace = bundle.flattenData().dstNamespace
return@provider bundle
} }
} }

View file

@ -1,36 +1,48 @@
package dev.frogmc.phytotelma.ext package dev.frogmc.phytotelma.ext
import dev.frogmc.phytotelma.Constants import dev.frogmc.phytotelma.Constants
import dev.frogmc.phytotelma.PhytotelmaPlugin
import dev.frogmc.phytotelma.ProjectStorage import dev.frogmc.phytotelma.ProjectStorage
import dev.frogmc.phytotelma.VersionChecker import dev.frogmc.phytotelma.VersionChecker
import dev.frogmc.phytotelma.accesswidener.AccessWidener import dev.frogmc.phytotelma.accesswidener.AccessWidener
import dev.frogmc.phytotelma.build.PhytotelmaBuildTask import dev.frogmc.phytotelma.build.PhytotelmaBuildTask
import dev.frogmc.phytotelma.common.Env import dev.frogmc.phytotelma.common.Env
import dev.frogmc.phytotelma.mappings.renameDstNamespace
import dev.frogmc.phytotelma.run.AssetDownloader import dev.frogmc.phytotelma.run.AssetDownloader
import dev.frogmc.phytotelma.run.RunConfigGenerator import dev.frogmc.phytotelma.run.RunConfigGenerator
import dev.frogmc.phytotelma.run.task.RunGameTask import dev.frogmc.phytotelma.run.task.RunGameTask
import dev.frogmc.phytotelma.vineflower.FrogJavadocProvider import dev.frogmc.phytotelma.vineflower.FrogJavadocProvider
import dev.frogmc.thyroxine.Thyroxine import dev.frogmc.thyroxine.Thyroxine
import dev.frogmc.thyroxine.api.data.MappingBundle
import dev.frogmc.thyroxine.provider.MojmapProvider
import net.fabricmc.fernflower.api.IFabricJavadocProvider import net.fabricmc.fernflower.api.IFabricJavadocProvider
import org.gradle.api.Action import org.gradle.api.Action
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.model.ObjectFactory import org.gradle.api.model.ObjectFactory
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.api.plugins.JavaPlugin import org.gradle.api.plugins.JavaPlugin
import org.jetbrains.java.decompiler.main.Fernflower import org.jetbrains.java.decompiler.main.Fernflower
import org.jetbrains.java.decompiler.main.decompiler.PrintStreamLogger import org.jetbrains.java.decompiler.main.decompiler.PrintStreamLogger
import org.jetbrains.java.decompiler.main.decompiler.SingleFileSaver import org.jetbrains.java.decompiler.main.decompiler.SingleFileSaver
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences
import java.io.PrintStream import java.io.PrintStream
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
import javax.inject.Inject import javax.inject.Inject
import kotlin.io.path.createParentDirectories import kotlin.io.path.createParentDirectories
import kotlin.io.path.deleteExisting import kotlin.io.path.deleteExisting
import kotlin.io.path.exists import kotlin.io.path.exists
import kotlin.io.path.notExists import kotlin.io.path.notExists
abstract class PhytotelmaGradleExtensionImpl @Inject constructor(private val project: Project, private val objects: ObjectFactory) : PhytotelmaGradleExtension { abstract class PhytotelmaGradleExtensionImpl @Inject constructor(
private val project: Project,
private val objects: ObjectFactory
) : PhytotelmaGradleExtension {
private fun setupTasks() { private fun setupTasks() {
project.tasks.register("genSources") {task -> project.tasks.register("genSources") { task ->
task.group = Constants.TASK_GROUP task.group = Constants.TASK_GROUP
task.actions.add { task.actions.add {
val projectData = ProjectStorage.get(it.project) val projectData = ProjectStorage.get(it.project)
@ -49,7 +61,8 @@ abstract class PhytotelmaGradleExtensionImpl @Inject constructor(private val pro
val options = mutableMapOf<String, Any>() val options = mutableMapOf<String, Any>()
println("Preparing Parchment...") println("Preparing Parchment...")
val javadocs = ProjectStorage.get(project).mappings!! val javadocs = ProjectStorage.get(project).mappings!!
options[IFabricJavadocProvider.PROPERTY_NAME] = FrogJavadocProvider(javadocs.docsForNamespace(Constants.DEV_NAMESPACE)) options[IFabricJavadocProvider.PROPERTY_NAME] =
FrogJavadocProvider(javadocs.docsForNamespace(Constants.DEV_NAMESPACE))
println("Decompiling...") println("Decompiling...")
val logger = PrintStreamLogger(PrintStream(System.out)) val logger = PrintStreamLogger(PrintStream(System.out))
@ -74,7 +87,7 @@ abstract class PhytotelmaGradleExtensionImpl @Inject constructor(private val pro
} }
} }
project.tasks.register(Constants.GEN_RUN_CONFIGS_TASK) {task -> project.tasks.register(Constants.GEN_RUN_CONFIGS_TASK) { task ->
task.group = Constants.TASK_GROUP task.group = Constants.TASK_GROUP
task.doFirst { task.doFirst {
RunConfigGenerator.generate(project) RunConfigGenerator.generate(project)
@ -107,7 +120,24 @@ abstract class PhytotelmaGradleExtensionImpl @Inject constructor(private val pro
} }
val buildTask = project.tasks.register(Constants.BUILD_TASK, PhytotelmaBuildTask::class.java) val buildTask = project.tasks.register(Constants.BUILD_TASK, PhytotelmaBuildTask::class.java)
project.tasks.getByName("build").dependsOn(buildTask) project.tasks.getByName(JavaBasePlugin.BUILD_TASK_NAME).dependsOn(buildTask)
project.tasks.getByName(JavaPlugin.JAR_TASK_NAME).actions.addLast {
val storage = ProjectStorage.get(project)
if (storage.targetNamespace != "mojmap") {
val mappings = MappingBundle.merge(
storage.mappings!!.reverse(), MojmapProvider.get(
storage.minecraftVersion!!,
PhytotelmaPlugin.globalCacheDir.resolve("net/minecraft/client/${storage.minecraftVersion}/client-${storage.minecraftVersion}.txt")
).orElseThrow().reverse().renameDstNamespace("mojmap")
).forNamespaces(storage.targetNamespace, "mojmap")
it.outputs.files.forEach { file ->
val temp = Files.createTempFile("", file.name)
Files.copy(file.toPath(), temp, StandardCopyOption.REPLACE_EXISTING)
Thyroxine.remap(mappings, temp, file.toPath(), false, false)
Files.deleteIfExists(temp)
}
}
}
project.tasks.register(Constants.UPDATE_AW_TASK) { task -> project.tasks.register(Constants.UPDATE_AW_TASK) { task ->
task.group = Constants.TASK_GROUP task.group = Constants.TASK_GROUP
@ -115,6 +145,29 @@ abstract class PhytotelmaGradleExtensionImpl @Inject constructor(private val pro
AccessWidener.apply(project, ProjectStorage.get(it.project).remappedGameJarPath!!) AccessWidener.apply(project, ProjectStorage.get(it.project).remappedGameJarPath!!)
} }
} }
val configuration = project.configurations.create("modImplemenation") {
it.isCanBeResolved = true
it.isCanBeConsumed = false
}
project.afterEvaluate {
remapModDependencies(configuration)
}
}
private fun remapModDependencies(configuration: Configuration) {
// TODO
val mappings =
ProjectStorage.get(project).mappings!!.forNamespaces("mojmap", ProjectStorage.get(project).targetNamespace)
val targetPath = ProjectStorage.get(project).localCacheDir!!
val remappedPaths = mutableListOf<Path>()
configuration.resolvedConfiguration.resolvedArtifacts.forEach {
val remappedPath = targetPath.resolve(it.id.toString().replace(":", "/").replace(".", "/"))
remappedPaths.add(remappedPath)
configuration.dependencies.removeIf { d -> d.group + ":" + d.name + ":" + d.version == it.id.toString() }
}
} }
override fun minecraft(action: Action<MinecraftConfiguration>) { override fun minecraft(action: Action<MinecraftConfiguration>) {
@ -135,7 +188,7 @@ abstract class PhytotelmaGradleExtensionImpl @Inject constructor(private val pro
projectData.minecraftVersion = version projectData.minecraftVersion = version
val mappings = mcConf.mappings.get() val mappings = mcConf.mappings.get()
println("Using mappings: "+mcConf.mappingsName()) println("Using mappings: " + mcConf.mappingsName)
projectData.mappings = mappings projectData.mappings = mappings
val clientJar = VersionChecker.downloadClient(project, version) val clientJar = VersionChecker.downloadClient(project, version)
@ -145,11 +198,14 @@ abstract class PhytotelmaGradleExtensionImpl @Inject constructor(private val pro
projectData.remappedGameJarPath = remappedJar projectData.remappedGameJarPath = remappedJar
println("Time to setup Minecraft!") println("Time to setup Minecraft!")
val applyAW = AccessWidener.needsUpdate(project) val applyAW = AccessWidener.needsUpdate(project)
if (remappedJar.notExists() || applyAW || mcConf.mappingsName() != projectData.mappingsName) { if (remappedJar.notExists() || applyAW || mcConf.mappingsName != projectData.mappingsName) {
projectData.mappingsName = mcConf.mappingsName() projectData.mappingsName = mcConf.mappingsName
println("Remapping the game...") println("Remapping the game...")
Thyroxine.remap(mappings.forNamespaces("official", "named"), projectData.targetNamespace = mcConf.targetNamespace
clientJar, remappedJar, true, true) Thyroxine.remap(
mappings.forNamespaces("official", mcConf.targetNamespace),
clientJar, remappedJar, true, true
)
} }
project.dependencies.add( project.dependencies.add(

View file

@ -0,0 +1,21 @@
package dev.frogmc.phytotelma.mappings
import dev.frogmc.thyroxine.api.data.DocumentationData
import dev.frogmc.thyroxine.api.data.MappingBundle
import dev.frogmc.thyroxine.api.data.MappingData
fun MappingBundle.renameDstNamespace(newDst: String): MappingBundle {
val renamed = MappingBundle()
val oldData = flattenData()
val newData = MappingData(oldData.srcNamespace, newDst)
val newDocs = DocumentationData(newDst)
oldData.apply {
newData.classes.putAll(classes)
newData.fields.putAll(fields)
newData.methods.putAll(methods)
newData.parameters.putAll(parameters)
}
return renamed.insert(newData, newDocs.insert(get(oldData.dstNamespace)))
}