update thyroxine, rewrite dsl, add support for other mapping formats

This commit is contained in:
moehreag 2024-07-01 01:00:42 +02:00
parent a918a9143b
commit 97c27ac542
9 changed files with 406 additions and 172 deletions

View file

@ -7,7 +7,7 @@ plugins {
}
group = "dev.frogmc"
version = "0.0.1-alpha.12"
version = "0.0.1-alpha.13"
repositories {
maven {
@ -18,17 +18,18 @@ repositories {
name = "FrogMC Maven Snapshots"
url = uri("https://maven.frogmc.dev/snapshots")
}
mavenLocal()
mavenCentral()
}
dependencies {
implementation("dev.frogmc:thyroxine:0.0.1-alpha.5")
implementation("dev.frogmc:thyroxine:0.0.1-alpha.6")
implementation("org.ow2.asm:asm:9.7")
implementation("com.google.code.gson:gson:2.10.1")
implementation("org.vineflower:vineflower:1.10.1")
testImplementation(kotlin("test"))
implementation("com.electronwill.night-config:toml:3.7.3")
implementation("com.electronwill.night-config:toml:3.8.0")
implementation("com.google.jimfs:jimfs:1.3.0")
}

View file

@ -12,4 +12,5 @@ object Constants {
const val GEN_RUN_CONFIGS_TASK = "genRunConfigs"
const val RUN_CLIENT_TASK = "runClient"
const val RUNT_SERVER_TASK = "runServer"
const val DEV_NAMESPACE = "named"
}

View file

@ -1,29 +1,12 @@
package dev.frogmc.phytotelma
import dev.frogmc.phytotelma.accesswidener.AccessWidener
import dev.frogmc.phytotelma.build.PhytotelmaBuildTask
import dev.frogmc.phytotelma.common.Env
import dev.frogmc.phytotelma.ext.PhytotelmaGradleExtension
import dev.frogmc.phytotelma.ext.PhytotelmaGradleExtensionImpl
import dev.frogmc.phytotelma.run.AssetDownloader
import dev.frogmc.phytotelma.run.RunConfigGenerator
import dev.frogmc.phytotelma.run.task.RunGameTask
import dev.frogmc.phytotelma.vineflower.ParchmentJavadocProvider
import dev.frogmc.thyroxine.provider.ParchmentProvider
import net.fabricmc.fernflower.api.IFabricJavadocProvider
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPlugin
import org.jetbrains.java.decompiler.main.Fernflower
import org.jetbrains.java.decompiler.main.decompiler.PrintStreamLogger
import org.jetbrains.java.decompiler.main.decompiler.SingleFileSaver
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences
import java.io.PrintStream
import java.net.URI
import java.nio.file.Path
import kotlin.io.path.createDirectories
import kotlin.io.path.deleteExisting
import kotlin.io.path.exists
class PhytotelmaPlugin : Plugin<Project> {
@ -67,98 +50,6 @@ class PhytotelmaPlugin : Plugin<Project> {
"phytotelma",
PhytotelmaGradleExtensionImpl::class.java
)
project.extensions.findByType(PhytotelmaGradleExtension::class.java) ?: return
project.tasks.register("genSources") {task ->
task.group = Constants.TASK_GROUP
task.actions.add {
val projectData = ProjectStorage.get(it.project)
val fileName = projectData.remappedGameJarPath!!.fileName.toString()
val output =
projectData.remappedGameJarPath!!.resolveSibling(
fileName.substring(
0,
fileName.lastIndexOf("-")
) + "-sources.jar"
)
if (output.exists()) {
println("Output $output already exists, deleting!")
output.deleteExisting()
}
val options = mutableMapOf<String, Any>()
println("Preparing Parchment...")
val parchment = ParchmentProvider.getParchment(
projectData.minecraftVersion!!,
projectData.parchmentVersion!!,
globalCacheDir.resolve("org/parchmentmc/parchment/${projectData.minecraftVersion}/${projectData.parchmentVersion}/")
)
options[IFabricJavadocProvider.PROPERTY_NAME] = ParchmentJavadocProvider(parchment)
println("Decompiling...")
val logger = PrintStreamLogger(PrintStream(System.out))
options.putAll(
mapOf(
IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES to "1",
IFernflowerPreferences.BYTECODE_SOURCE_MAPPING to "1",
IFernflowerPreferences.REMOVE_SYNTHETIC to "1",
IFernflowerPreferences.LOG_LEVEL to "error",
IFernflowerPreferences.THREADS to Runtime.getRuntime().availableProcessors().toString(),
IFernflowerPreferences.INDENT_STRING to "\t"
)
)
val decomp = Fernflower(
SingleFileSaver(output.toFile()),
options, logger
)
decomp.addSource(projectData.remappedGameJarPath!!.toFile())
decomp.decompileContext()
}
}
project.tasks.register(Constants.GEN_RUN_CONFIGS_TASK) {task ->
task.group = Constants.TASK_GROUP
task.doFirst {
RunConfigGenerator.generate(project)
}
}
project.tasks.register(Constants.RUN_CLIENT_TASK, RunGameTask::class.java, Env.CLIENT)
project.tasks.register(Constants.RUNT_SERVER_TASK, RunGameTask::class.java, Env.SERVER)
project.tasks.register(Constants.DOWNLOAD_ASSETS_TASK) { task ->
task.group = Constants.TASK_GROUP
task.doFirst {
AssetDownloader.download(it.project)
}
}
project.configurations.register(Constants.INCLUDE_CONFIGURATION) {
it.isCanBeResolved = true
it.isCanBeConsumed = false
}
project.configurations.register(Constants.MINECRAFT_CONFIGURATION) {
project.configurations.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME).extendsFrom(it)
project.configurations.getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME).extendsFrom(it)
project.configurations.getByName(JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME).extendsFrom(it)
project.configurations.getByName(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME).extendsFrom(it)
it.isCanBeResolved = false
it.isCanBeConsumed = false
it.isTransitive = false
}
val buildTask = project.tasks.register(Constants.BUILD_TASK, PhytotelmaBuildTask::class.java)
project.tasks.getByName("build").dependsOn(buildTask)
project.tasks.register(Constants.UPDATE_AW_TASK) { task ->
task.group = Constants.TASK_GROUP
task.actions.addFirst {
AccessWidener.apply(project, ProjectStorage.get(it.project).remappedGameJarPath!!)
}
}
}
companion object {

View file

@ -1,5 +1,6 @@
package dev.frogmc.phytotelma
import dev.frogmc.thyroxine.api.data.MappingBundle
import org.gradle.api.Project
import java.nio.file.Path
@ -9,14 +10,17 @@ object ProjectStorage {
fun get(project: Project): ProjectData {
if (!data.containsKey(project)) {
data[project] = ProjectData(null, null, null, null)
data[project] = ProjectData(null, null, null, null, null)
}
return data[project]!!
}
}
class ProjectData(var localCacheDir: Path?,
class ProjectData(
var localCacheDir: Path?,
var minecraftVersion: String?,
var remappedGameJarPath: Path?,
var parchmentVersion: String?)
var mappings: MappingBundle?,
var mappingsName: String?
)

View file

@ -0,0 +1,174 @@
package dev.frogmc.phytotelma.ext
import dev.frogmc.phytotelma.PhytotelmaPlugin
import dev.frogmc.thyroxine.api.data.MappingBundle
import dev.frogmc.thyroxine.parser.tiny.TinyV2Parser
import dev.frogmc.thyroxine.provider.MojmapProvider
import dev.frogmc.thyroxine.provider.ParchmentProvider
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Provider
import java.nio.charset.StandardCharsets
import java.nio.file.FileSystems
import java.nio.file.Path
import javax.inject.Inject
import kotlin.io.path.readText
@Suppress("MemberVisibilityCanBePrivate", "unused")
abstract class MinecraftConfiguration @Inject constructor(
private val project: Project,
private val objects: ObjectFactory
) {
var version: String? = null
var mappings: Provider<MappingBundle> = mojmapParchment()
private lateinit var mappingsName: String
internal fun mappingsName(): String {
return mappingsName
}
fun mojmapParchment(): Provider<MappingBundle> {
return mojmapParchment {}
}
fun mojmapParchment(action: Action<ParchmentConfiguration>): Provider<MappingBundle> {
mappingsName = "mojmap"
return project.provider {
val conf = objects.newInstance(ParchmentConfiguration::class.java)
conf.gameVersion = version
action.execute(conf)
val cacheDir = PhytotelmaPlugin.globalCacheDir
if (conf.version == null) {
conf.version = ParchmentProvider.findForMinecraftVersion(conf.gameVersion)
}
return@provider MappingBundle.merge(
MojmapProvider.get(
version,
cacheDir.resolve("net/minecraft/client/$version/client-$version.txt")
).orElseThrow(),
ParchmentProvider.getParchment(
version,
cacheDir.resolve("org/parchmentmc/parchment/${conf.gameVersion}/${conf.version}")
)
)
}
}
fun quiltMappings(action: Action<VersionConfiguration>): Provider<MappingBundle> {
mappingsName = "quilt"
return project.provider {
val conf = objects.newInstance(VersionConfiguration::class.java)
action.execute(conf)
if (conf.version == null) {
error("No version provided for quilt mappings!")
}
return@provider twoStepMappings(
"org.quiltmc:hashed:$version",
"org.quiltmc:quilt-mappings:${conf.version}:v2"
)
}
}
fun twoStepMappings(action: Action<TwoStepMappingsConfiguration>): Provider<MappingBundle> {
mappingsName = "custom/two-step"
return project.provider {
val conf = objects.newInstance(TwoStepMappingsConfiguration::class.java)
action.execute(conf)
if (conf.first == null) {
error("No version provided for first mapping step!")
}
if (conf.second == null) {
error("No version provided for second mapping step!")
}
return@provider twoStepMappings(conf.first!!, conf.second!!)
}
}
fun tinyMappings(action: Action<NameConfiguration>): Provider<MappingBundle> {
mappingsName = "custom/tiny"
return project.provider {
val conf = objects.newInstance(NameConfiguration::class.java)
action.execute(conf)
if (conf.name == null) {
error("No maven coordinate provided for tiny mappings!")
}
return@provider tinyMappings(conf.name!!)
}
}
fun mappings(action: Action<MappingBundle>): Provider<MappingBundle> {
mappingsName = "custom"
return project.provider {
val bundle = MappingBundle()
action.execute(bundle)
return@provider bundle
}
}
fun layer(action: Action<LayerConfiguration>): Provider<MappingBundle> {
return project.provider {
val config = objects.newInstance(LayerConfiguration::class.java)
action.execute(config)
return@provider MappingBundle.merge(*config.layers.map { it.get() }.toTypedArray())
}
}
private fun twoStepMappings(intermediary: String, mappings: String): MappingBundle {
return MappingBundle.merge(tinyMappings(intermediary), tinyMappings(mappings))
}
private fun tinyMappings(name: String): MappingBundle {
mavenMappings(name).let { path ->
FileSystems.newFileSystem(path).use {
return TinyV2Parser.parse(it.getPath("mappings/mappings.tiny").readText(StandardCharsets.UTF_8))
}
}
}
@Suppress("UnstableApiUsage")
private fun mavenMappings(name: String): Path {
val configuration = project.configurations.create("mappings") {
it.isCanBeResolved = true
it.isCanBeDeclared = true
}
configuration.dependencies.add(project.dependencies.create(name))
val path = configuration.resolve().first().toPath()
project.configurations.remove(configuration)
return path
}
abstract class TwoStepMappingsConfiguration {
var first: String? = null
var second: String? = null
}
abstract class ParchmentConfiguration {
var gameVersion: String? = null
var version: String? = null
}
abstract class LayerConfiguration {
internal val layers = mutableListOf<Provider<MappingBundle>>()
fun add(mappings: Provider<MappingBundle>): LayerConfiguration {
layers.add(mappings)
return this
}
}
}
abstract class NameConfiguration {
var name: String? = null
}
abstract class VersionConfiguration {
var version: String? = null
}

View file

@ -1,25 +1,13 @@
package dev.frogmc.phytotelma.ext
import org.gradle.api.provider.Provider
import org.gradle.api.Action
@Suppress("unused")
interface PhytotelmaGradleExtension {
fun minecraft(version: String, parchmentGameVersion: String? = null, parchmentVersion: String? = null)
fun minecraft(action: Action<MinecraftConfiguration>)
fun minecraft(version: Provider<String>, parchmentGameVersion: Provider<String>? = null, parchmentVersion: Provider<String>? = null) {
minecraft(version.get(), parchmentGameVersion?.get(), parchmentVersion?.get())
}
fun loader(version: String)
fun loader(version: Provider<String>) {
loader(version.get())
}
fun froglib(version: String)
fun froglib(version: Provider<String>) {
froglib(version.get())
}
fun loader(action: Action<VersionConfiguration>)
fun froglib(action: Action<VersionConfiguration>)
}

View file

@ -1,26 +1,200 @@
package dev.frogmc.phytotelma.ext
import dev.frogmc.phytotelma.Constants
import dev.frogmc.phytotelma.PhytotelmaPlugin
import dev.frogmc.phytotelma.ProjectStorage
import dev.frogmc.phytotelma.VersionChecker
import dev.frogmc.phytotelma.accesswidener.AccessWidener
import dev.frogmc.phytotelma.build.PhytotelmaBuildTask
import dev.frogmc.phytotelma.common.Env
import dev.frogmc.phytotelma.run.AssetDownloader
import dev.frogmc.phytotelma.run.RunConfigGenerator
import dev.frogmc.phytotelma.run.task.RunGameTask
import dev.frogmc.phytotelma.vineflower.FrogJavadocProvider
import dev.frogmc.thyroxine.Thyroxine
import dev.frogmc.thyroxine.parser.ProguardParser
import dev.frogmc.thyroxine.provider.MojmapProvider
import dev.frogmc.thyroxine.provider.ParchmentProvider
import net.fabricmc.fernflower.api.IFabricJavadocProvider
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.model.ObjectFactory
import org.gradle.api.plugins.JavaPlugin
import org.jetbrains.java.decompiler.main.Fernflower
import org.jetbrains.java.decompiler.main.decompiler.PrintStreamLogger
import org.jetbrains.java.decompiler.main.decompiler.SingleFileSaver
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences
import java.io.PrintStream
import javax.inject.Inject
import kotlin.io.path.createParentDirectories
import kotlin.io.path.deleteExisting
import kotlin.io.path.exists
import kotlin.io.path.notExists
abstract class PhytotelmaGradleExtensionImpl : PhytotelmaGradleExtension {
abstract class PhytotelmaGradleExtensionImpl @Inject constructor(private val project: Project, private val objects: ObjectFactory) : PhytotelmaGradleExtension {
@Inject
abstract fun getProject(): Project
private fun setupTasks() {
project.tasks.register("genSources") {task ->
task.group = Constants.TASK_GROUP
task.actions.add {
val projectData = ProjectStorage.get(it.project)
val fileName = projectData.remappedGameJarPath!!.fileName.toString()
val output =
projectData.remappedGameJarPath!!.resolveSibling(
fileName.substring(
0,
fileName.lastIndexOf("-")
) + "-sources.jar"
)
if (output.exists()) {
println("Output $output already exists, deleting!")
output.deleteExisting()
}
val options = mutableMapOf<String, Any>()
println("Preparing Parchment...")
val javadocs = ProjectStorage.get(project).mappings!!
options[IFabricJavadocProvider.PROPERTY_NAME] = FrogJavadocProvider(javadocs.docsForNamespace(Constants.DEV_NAMESPACE))
println("Decompiling...")
val logger = PrintStreamLogger(PrintStream(System.out))
options.putAll(
mapOf(
IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES to "1",
IFernflowerPreferences.BYTECODE_SOURCE_MAPPING to "1",
IFernflowerPreferences.REMOVE_SYNTHETIC to "1",
IFernflowerPreferences.LOG_LEVEL to "error",
IFernflowerPreferences.THREADS to Runtime.getRuntime().availableProcessors().toString(),
IFernflowerPreferences.INDENT_STRING to "\t"
)
)
val decomp = Fernflower(
SingleFileSaver(output.toFile()),
options, logger
)
decomp.addSource(projectData.remappedGameJarPath!!.toFile())
decomp.decompileContext()
}
}
project.tasks.register(Constants.GEN_RUN_CONFIGS_TASK) {task ->
task.group = Constants.TASK_GROUP
task.doFirst {
RunConfigGenerator.generate(project)
}
}
project.tasks.register(Constants.RUN_CLIENT_TASK, RunGameTask::class.java, Env.CLIENT)
project.tasks.register(Constants.RUNT_SERVER_TASK, RunGameTask::class.java, Env.SERVER)
project.tasks.register(Constants.DOWNLOAD_ASSETS_TASK) { task ->
task.group = Constants.TASK_GROUP
task.doFirst {
AssetDownloader.download(it.project)
}
}
project.configurations.register(Constants.INCLUDE_CONFIGURATION) {
it.isCanBeResolved = true
it.isCanBeConsumed = false
}
project.configurations.register(Constants.MINECRAFT_CONFIGURATION) {
project.configurations.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME).extendsFrom(it)
project.configurations.getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME).extendsFrom(it)
project.configurations.getByName(JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME).extendsFrom(it)
project.configurations.getByName(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME).extendsFrom(it)
it.isCanBeResolved = false
it.isCanBeConsumed = false
it.isTransitive = false
}
val buildTask = project.tasks.register(Constants.BUILD_TASK, PhytotelmaBuildTask::class.java)
project.tasks.getByName("build").dependsOn(buildTask)
project.tasks.register(Constants.UPDATE_AW_TASK) { task ->
task.group = Constants.TASK_GROUP
task.actions.addFirst {
AccessWidener.apply(project, ProjectStorage.get(it.project).remappedGameJarPath!!)
}
}
}
override fun minecraft(action: Action<MinecraftConfiguration>) {
println("Setting up Tasks...")
setupTasks()
println("Setting up Minecraft...")
val mcConf = objects.newInstance(MinecraftConfiguration::class.java)
action.execute(mcConf)
if (mcConf.version == null) {
error("No Minecraft version provided!")
}
val version = mcConf.version!!
if (VersionChecker.validateVersion(version, offlineMode = project.gradle.startParameter.isOffline)) {
val projectData = ProjectStorage.get(project)
projectData.minecraftVersion = version
val mappings = mcConf.mappings.get()
println("Using mappings: "+mcConf.mappingsName())
projectData.mappings = mappings
val clientJar = VersionChecker.downloadClient(project, version)
val remappedJar =
projectData.localCacheDir!!.resolve("net/minecraft/client/$version/client-$version-remapped.jar")
remappedJar.createParentDirectories()
projectData.remappedGameJarPath = remappedJar
println("Time to setup Minecraft!")
val applyAW = AccessWidener.needsUpdate(project)
if (remappedJar.notExists() || applyAW || mcConf.mappingsName() != projectData.mappingsName) {
projectData.mappingsName = mcConf.mappingsName()
println("Remapping the game...")
Thyroxine.remap(mappings.forNamespaces("official", "named"),
clientJar, remappedJar, true, true)
}
project.dependencies.add(
Constants.MINECRAFT_CONFIGURATION,
"net.minecrell:terminalconsoleappender:1.2.0"
)
VersionChecker.getDependencies(version) {
project.dependencies.add(Constants.MINECRAFT_CONFIGURATION, it)
}
VersionChecker.savePomFile(version, remappedJar.parent)
project.dependencies.add(Constants.MINECRAFT_CONFIGURATION, "net.minecraft:client:$version:remapped")
println("Generating run configurations...")
RunConfigGenerator.generate(project)
if (applyAW) {
project.afterEvaluate {
println("Applying AccessWideners...")
AccessWidener.apply(project, remappedJar)
}
}
}
}
override fun loader(action: Action<VersionConfiguration>) {
val conf = objects.newInstance(VersionConfiguration::class.java)
action.execute(conf)
if (conf.version == null) {
error("No loader version provided!")
}
project.dependencies.add("implementation", "dev.frogmc:frogloader:${conf.version!!}")
}
override fun froglib(action: Action<VersionConfiguration>) {
val conf = objects.newInstance(VersionConfiguration::class.java)
action.execute(conf)
if (conf.version == null) {
error("No froglib version provided!")
}
project.dependencies.add("implementation", "dev.frogmc:froglib:${conf.version!!}")
}
/*override fun minecraft(version: String, parchmentGameVersion: String?, parchmentVersion: String?) {
override fun minecraft(version: String, parchmentGameVersion: String?, parchmentVersion: String?) {
if (VersionChecker.validateVersion(version, offlineMode = getProject().gradle.startParameter.isOffline)) {
println("Setting up Minecraft...")
val parchmentGameVer = parchmentGameVersion?: version
@ -41,12 +215,10 @@ abstract class PhytotelmaGradleExtensionImpl : PhytotelmaGradleExtension {
if (remappedJar.notExists() || applyAW) {
println("Remapping the game...")
val data = kotlin.runCatching {
ProguardParser.read(
MojmapProvider.get(
version,
clientJar.resolveSibling("client-$version.txt")
).orElseThrow()
).reverse()
).orElseThrow().reverse()
}.getOrNull()
val paramMappings = if (parchment.isNotEmpty()) kotlin.runCatching {
ParchmentProvider.getParchment(
@ -62,7 +234,7 @@ abstract class PhytotelmaGradleExtensionImpl : PhytotelmaGradleExtension {
println("Parameter mappings will not be present as the version $parchmentVersion for minecraft version $parchmentGameVer could not be found")
}
if (data != null) {
Thyroxine.remap(data, clientJar, remappedJar, true, paramMappings)
Thyroxine.remap(data.forNamespaces("official", "named"), clientJar, remappedJar, true, true)
} else {
error("Failed to remap the game as no mojmap version was found for game version $version. Other mapping formats may be implemented in the future.")
}
@ -101,5 +273,5 @@ abstract class PhytotelmaGradleExtensionImpl : PhytotelmaGradleExtension {
override fun froglib(version: String) {
getProject().dependencies.add("implementation", "dev.frogmc:froglib:$version")
}
}*/
}

View file

@ -0,0 +1,28 @@
package dev.frogmc.phytotelma.vineflower
import dev.frogmc.thyroxine.api.data.DocumentationData
import net.fabricmc.fernflower.api.IFabricJavadocProvider
import org.jetbrains.java.decompiler.struct.StructClass
import org.jetbrains.java.decompiler.struct.StructField
import org.jetbrains.java.decompiler.struct.StructMethod
import java.util.stream.Collectors
class FrogJavadocProvider(data: DocumentationData) : IFabricJavadocProvider {
private val classMap = data.classes.stream().collect(Collectors.toMap({ it.name() }, { it }))
override fun getClassDoc(structClass: StructClass): String? {
return classMap[structClass.qualifiedName]?.javadoc?.joinToString("\n")
}
override fun getFieldDoc(structClass: StructClass, structField: StructField): String? {
return classMap[structClass.qualifiedName]
?.getField(structField.name, structField.descriptor)
?.orElse(null)?.javadoc?.joinToString("\n")
}
override fun getMethodDoc(structClass: StructClass, structMethod: StructMethod): String? {
return classMap[structClass.qualifiedName]?.getMethod(structMethod.name, structMethod.descriptor)
?.orElse(null)?.javadoc?.joinToString("\n")
}
}

View file

@ -1,25 +0,0 @@
package dev.frogmc.phytotelma.vineflower
import dev.frogmc.thyroxine.api.data.Parchment
import net.fabricmc.fernflower.api.IFabricJavadocProvider
import org.jetbrains.java.decompiler.struct.StructClass
import org.jetbrains.java.decompiler.struct.StructField
import org.jetbrains.java.decompiler.struct.StructMethod
class ParchmentJavadocProvider(private val parchment: Parchment) : IFabricJavadocProvider {
override fun getClassDoc(structClass: StructClass): String? {
return parchment.getClass(structClass.qualifiedName).orElse(null)?.javadoc?.joinToString("\n")
}
override fun getFieldDoc(structClass: StructClass, structField: StructField): String? {
return parchment.getClass(structClass.qualifiedName)
.flatMap { it.getField(structField.name, structField.descriptor) }
.orElse(null)?.javadoc?.joinToString("\n")
}
override fun getMethodDoc(structClass: StructClass, structMethod: StructMethod): String? {
return parchment.getClass(structClass.qualifiedName)
.flatMap { it.getMethod(structMethod.name, structMethod.descriptor) }
.orElse(null)?.javadoc?.joinToString("\n")
}
}