Merge pull request 'rework dsl, add mod configurations (remapped), add support for other mappings' (#3) from owlsys/other-mappings into mistress
All checks were successful
Publish to snapshot maven / build (push) Successful in 40s
All checks were successful
Publish to snapshot maven / build (push) Successful in 40s
Reviewed-on: #3 Reviewed-by: Ecorous <ecorous@outlook.com>
This commit is contained in:
commit
97048555c6
|
@ -7,7 +7,7 @@ plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "dev.frogmc"
|
group = "dev.frogmc"
|
||||||
version = "0.0.1-alpha.12"
|
version = "0.0.1-alpha.13"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
|
@ -18,17 +18,20 @@ repositories {
|
||||||
name = "FrogMC Maven Snapshots"
|
name = "FrogMC Maven Snapshots"
|
||||||
url = uri("https://maven.frogmc.dev/snapshots")
|
url = uri("https://maven.frogmc.dev/snapshots")
|
||||||
}
|
}
|
||||||
|
mavenLocal()
|
||||||
|
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
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("org.ow2.asm:asm:9.7")
|
||||||
|
implementation("org.ow2.asm:asm-commons:9.7")
|
||||||
|
implementation("org.ow2.asm:asm-tree:9.7")
|
||||||
implementation("com.google.code.gson:gson:2.10.1")
|
implementation("com.google.code.gson:gson:2.10.1")
|
||||||
implementation("org.vineflower:vineflower:1.10.1")
|
implementation("org.vineflower:vineflower:1.10.1")
|
||||||
testImplementation(kotlin("test"))
|
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")
|
implementation("com.google.jimfs:jimfs:1.3.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,4 +12,6 @@ object Constants {
|
||||||
const val GEN_RUN_CONFIGS_TASK = "genRunConfigs"
|
const val GEN_RUN_CONFIGS_TASK = "genRunConfigs"
|
||||||
const val RUN_CLIENT_TASK = "runClient"
|
const val RUN_CLIENT_TASK = "runClient"
|
||||||
const val RUNT_SERVER_TASK = "runServer"
|
const val RUNT_SERVER_TASK = "runServer"
|
||||||
|
const val CLEAR_LOCAL_CACHE_TASK = "clearLocalCache"
|
||||||
|
const val CLEAR_GLOBAL_CACHE_TASK = "clearGlobalCache"
|
||||||
}
|
}
|
70
src/main/kotlin/dev/frogmc/phytotelma/ModConfigurations.kt
Normal file
70
src/main/kotlin/dev/frogmc/phytotelma/ModConfigurations.kt
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
package dev.frogmc.phytotelma
|
||||||
|
|
||||||
|
import org.gradle.api.plugins.JavaPlugin
|
||||||
|
|
||||||
|
object ModConfigurations {
|
||||||
|
val configurations = listOf(
|
||||||
|
ModConfiguration(
|
||||||
|
JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME, listOf(
|
||||||
|
JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME,
|
||||||
|
JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME,
|
||||||
|
JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME,
|
||||||
|
JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME
|
||||||
|
), DependencyType.RUNTIME
|
||||||
|
),
|
||||||
|
ModConfiguration(
|
||||||
|
JavaPlugin.TEST_IMPLEMENTATION_CONFIGURATION_NAME, listOf(
|
||||||
|
JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME,
|
||||||
|
JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME
|
||||||
|
), DependencyType.RUNTIME
|
||||||
|
),
|
||||||
|
ModConfiguration(
|
||||||
|
JavaPlugin.API_CONFIGURATION_NAME, listOf(
|
||||||
|
JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME,
|
||||||
|
JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME,
|
||||||
|
JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME,
|
||||||
|
JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME
|
||||||
|
), DependencyType.COMPILE
|
||||||
|
),
|
||||||
|
ModConfiguration(
|
||||||
|
JavaPlugin.COMPILE_ONLY_API_CONFIGURATION_NAME, listOf(
|
||||||
|
JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME,
|
||||||
|
JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME
|
||||||
|
), DependencyType.COMPILE
|
||||||
|
),
|
||||||
|
ModConfiguration(
|
||||||
|
JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME, listOf(
|
||||||
|
JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME,
|
||||||
|
JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME
|
||||||
|
)
|
||||||
|
),
|
||||||
|
ModConfiguration(
|
||||||
|
JavaPlugin.TEST_COMPILE_ONLY_CONFIGURATION_NAME, listOf(
|
||||||
|
JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME
|
||||||
|
)
|
||||||
|
),
|
||||||
|
ModConfiguration(
|
||||||
|
JavaPlugin.RUNTIME_ONLY_CONFIGURATION_NAME, listOf(
|
||||||
|
JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME,
|
||||||
|
JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
ModConfiguration(
|
||||||
|
JavaPlugin.TEST_RUNTIME_ONLY_CONFIGURATION_NAME, listOf(
|
||||||
|
JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class ModConfiguration(
|
||||||
|
val name: String,
|
||||||
|
val classpathNames: List<String>,
|
||||||
|
val dependencyType: DependencyType = DependencyType.NONE,
|
||||||
|
)
|
||||||
|
|
||||||
|
enum class DependencyType {
|
||||||
|
NONE,
|
||||||
|
RUNTIME,
|
||||||
|
COMPILE
|
||||||
|
}
|
|
@ -1,29 +1,14 @@
|
||||||
package dev.frogmc.phytotelma
|
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.PhytotelmaGradleExtension
|
||||||
import dev.frogmc.phytotelma.ext.PhytotelmaGradleExtensionImpl
|
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.Plugin
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.plugins.JavaPlugin
|
import org.gradle.api.plugins.JavaPlugin
|
||||||
import org.jetbrains.java.decompiler.main.Fernflower
|
import org.gradle.configurationcache.extensions.capitalized
|
||||||
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.net.URI
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.io.path.createDirectories
|
import kotlin.io.path.createDirectories
|
||||||
import kotlin.io.path.deleteExisting
|
|
||||||
import kotlin.io.path.exists
|
|
||||||
|
|
||||||
|
|
||||||
class PhytotelmaPlugin : Plugin<Project> {
|
class PhytotelmaPlugin : Plugin<Project> {
|
||||||
|
@ -43,6 +28,10 @@ class PhytotelmaPlugin : Plugin<Project> {
|
||||||
}
|
}
|
||||||
|
|
||||||
project.repositories.apply {
|
project.repositories.apply {
|
||||||
|
maven {
|
||||||
|
it.name = "Remapped Mod Dependencies"
|
||||||
|
it.url = project.layout.buildDirectory.asFile.get().resolve("remappedMods").toURI()
|
||||||
|
}
|
||||||
maven {
|
maven {
|
||||||
it.name = "Minecraft/Local"
|
it.name = "Minecraft/Local"
|
||||||
it.url = localCacheDir.toUri()
|
it.url = localCacheDir.toUri()
|
||||||
|
@ -68,70 +57,20 @@ class PhytotelmaPlugin : Plugin<Project> {
|
||||||
PhytotelmaGradleExtensionImpl::class.java
|
PhytotelmaGradleExtensionImpl::class.java
|
||||||
)
|
)
|
||||||
|
|
||||||
project.extensions.findByType(PhytotelmaGradleExtension::class.java) ?: return
|
ModConfigurations.configurations.forEach { conf ->
|
||||||
|
project.configurations.create("mod" + conf.name.capitalized()) { c ->
|
||||||
|
c.isCanBeResolved = true
|
||||||
|
c.isCanBeConsumed = false
|
||||||
|
|
||||||
project.tasks.register("genSources") {task ->
|
when (conf.dependencyType) {
|
||||||
task.group = Constants.TASK_GROUP
|
DependencyType.RUNTIME -> project.configurations.getByName(JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME)
|
||||||
task.actions.add {
|
.extendsFrom(c)
|
||||||
val projectData = ProjectStorage.get(it.project)
|
|
||||||
val fileName = projectData.remappedGameJarPath!!.fileName.toString()
|
DependencyType.COMPILE -> project.configurations.getByName(JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME)
|
||||||
val output =
|
.extendsFrom(c)
|
||||||
projectData.remappedGameJarPath!!.resolveSibling(
|
|
||||||
fileName.substring(
|
DependencyType.NONE -> {}
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,16 +88,6 @@ class PhytotelmaPlugin : Plugin<Project> {
|
||||||
it.isCanBeConsumed = false
|
it.isCanBeConsumed = false
|
||||||
it.isTransitive = 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 {
|
companion object {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package dev.frogmc.phytotelma
|
package dev.frogmc.phytotelma
|
||||||
|
|
||||||
|
import dev.frogmc.thyroxine.api.data.MappingBundle
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
@ -8,15 +9,19 @@ object ProjectStorage {
|
||||||
private val data = mutableMapOf<Project, ProjectData>()
|
private val data = mutableMapOf<Project, ProjectData>()
|
||||||
|
|
||||||
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)
|
data[project] = ProjectData(null, null, null, null, null, null)
|
||||||
}
|
}
|
||||||
return data[project]!!
|
return data[project]!!
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ProjectData(var localCacheDir: Path?,
|
class ProjectData(
|
||||||
|
var localCacheDir: Path?,
|
||||||
var minecraftVersion: String?,
|
var minecraftVersion: String?,
|
||||||
var remappedGameJarPath: Path?,
|
var remappedGameJarPath: Path?,
|
||||||
var parchmentVersion: String?)
|
var mappings: MappingBundle?,
|
||||||
|
var mappingsName: String?,
|
||||||
|
var targetNamespace: String?
|
||||||
|
)
|
|
@ -1,3 +1,5 @@
|
||||||
|
@file:Suppress("unused")
|
||||||
|
|
||||||
package dev.frogmc.phytotelma
|
package dev.frogmc.phytotelma
|
||||||
|
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
|
@ -5,9 +7,11 @@ import com.google.gson.GsonBuilder
|
||||||
import dev.frogmc.phytotelma.common.CachingHttpClient
|
import dev.frogmc.phytotelma.common.CachingHttpClient
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.nio.file.Files
|
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.io.path.*
|
import kotlin.io.path.createDirectories
|
||||||
|
import kotlin.io.path.exists
|
||||||
|
import kotlin.io.path.writeBytes
|
||||||
|
import kotlin.io.path.writeText
|
||||||
|
|
||||||
object VersionChecker {
|
object VersionChecker {
|
||||||
private var validVersions = mutableListOf<VersionUrl>()
|
private var validVersions = mutableListOf<VersionUrl>()
|
||||||
|
@ -77,17 +81,6 @@ object VersionChecker {
|
||||||
return fetchVersionData(version).downloads.client
|
return fetchVersionData(version).downloads.client
|
||||||
}
|
}
|
||||||
|
|
||||||
fun downloadAssetIndex(version: String, path: Path): String {
|
|
||||||
val index = fetchVersionData(version).assetIndex
|
|
||||||
val dest = path.resolve(index.id + ".json")
|
|
||||||
if (dest.notExists()) {
|
|
||||||
CachingHttpClient.getUncached(URI.create(index.url)).use {
|
|
||||||
Files.copy(it, dest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return index.id
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun rawDownload(url: String): ByteArray {
|
private fun rawDownload(url: String): ByteArray {
|
||||||
return CachingHttpClient.getUncached(URI.create(url)).readAllBytes()
|
return CachingHttpClient.getUncached(URI.create(url)).readAllBytes()
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.gradle.api.artifacts.ProjectDependency
|
||||||
import org.gradle.api.plugins.JavaPlugin
|
import org.gradle.api.plugins.JavaPlugin
|
||||||
import org.gradle.api.plugins.JavaPluginExtension
|
import org.gradle.api.plugins.JavaPluginExtension
|
||||||
import org.objectweb.asm.*
|
import org.objectweb.asm.*
|
||||||
|
import org.objectweb.asm.tree.ClassNode
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.nio.file.FileSystems
|
import java.nio.file.FileSystems
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
@ -45,18 +46,20 @@ object AccessWidener {
|
||||||
private fun findDependencyAWs(project: Project): Stream<String> {
|
private fun findDependencyAWs(project: Project): Stream<String> {
|
||||||
val conf = project.configurations.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME)
|
val conf = project.configurations.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME)
|
||||||
val projectDeps = conf.dependencies.filterIsInstance<ProjectDependency>()
|
val projectDeps = conf.dependencies.filterIsInstance<ProjectDependency>()
|
||||||
.mapNotNull { getAWFile(it.dependencyProject) }.stream().flatMap { readTransitiveAW(it) }
|
.mapNotNull { getAWFile(it.dependencyProject) }.flatMap { readTransitiveAW(it) }
|
||||||
val dependencies = conf.resolvedConfiguration.files.map { it.toPath() }.filter { it.exists() && it.isRegularFile() }.stream().flatMap {
|
val dependencies =
|
||||||
FileSystems.newFileSystem(it).use {fs ->
|
conf.resolvedConfiguration.files.map { it.toPath() }.filter { it.exists() && it.isRegularFile() }.stream()
|
||||||
|
.flatMap {
|
||||||
|
FileSystems.newFileSystem(it).use { fs ->
|
||||||
val metadata = fs.getPath(Constants.MOD_METADATA_FILE)
|
val metadata = fs.getPath(Constants.MOD_METADATA_FILE)
|
||||||
PARSER.parse(metadata, FileNotFoundAction.READ_NOTHING)
|
PARSER.parse(metadata, FileNotFoundAction.READ_NOTHING)
|
||||||
.get<String>("frog.extensions.accesswidener")?.let { name ->
|
.get<String>("frog.extensions.accesswidener")?.let { name ->
|
||||||
return@flatMap readTransitiveAW(metadata.resolveSibling(name))
|
return@flatMap readTransitiveAW(metadata.resolveSibling(name)).stream()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return@flatMap null
|
return@flatMap null
|
||||||
}.filter { it != null }
|
}.filter { it != null }
|
||||||
return Stream.concat(projectDeps, dependencies)
|
return Stream.concat(projectDeps.stream(), dependencies)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun needsUpdate(project: Project): Boolean {
|
fun needsUpdate(project: Project): Boolean {
|
||||||
|
@ -70,24 +73,75 @@ object AccessWidener {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readAW(project: Project): Stream<String> {
|
fun checkAW(path: Path, gamePath: Path) {
|
||||||
|
val reader = path.bufferedReader(StandardCharsets.UTF_8)
|
||||||
|
if (!HEADER.test(reader.readLine() ?: "")) {
|
||||||
|
error("AccessWidener validation failed (invalid header)")
|
||||||
|
}
|
||||||
|
FileSystems.newFileSystem(gamePath).use { fs ->
|
||||||
|
reader.lines().toList().forEachIndexed { index, line ->
|
||||||
|
val checkString = line.substring(0, line.indexOf("#"))
|
||||||
|
|
||||||
|
if (checkString.isNotEmpty()) {
|
||||||
|
val parts = checkString.split(SEPARATOR)
|
||||||
|
if (parts.size < 3) {
|
||||||
|
error("AccessWidener validation failed in line ${index + 2}: $line")
|
||||||
|
}
|
||||||
|
if (parts[1] == "class") {
|
||||||
|
val target = parts[2]
|
||||||
|
if (fs.getPath(target).notExists()) {
|
||||||
|
error("AccessWidener validation failed in line ${index + 2}: $line (Invalid target)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (parts.size < 5) {
|
||||||
|
error("AccessWidener validation failed in line ${index + 2}: $line (Declaration missing)")
|
||||||
|
}
|
||||||
|
val owner = parts[2]
|
||||||
|
val name = parts[3]
|
||||||
|
val desc = parts[4]
|
||||||
|
when (parts[1]) {
|
||||||
|
"method" -> {
|
||||||
|
val classReader = ClassReader(fs.getPath(owner).readBytes())
|
||||||
|
val node = ClassNode()
|
||||||
|
classReader.accept(node, 0)
|
||||||
|
if (node.methods.none { it.name.equals(name) && it.desc.equals(desc) }) {
|
||||||
|
error("AccessWidener validation failed in line ${index + 2}: $line (Could not find target method)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"field" -> {
|
||||||
|
val classReader = ClassReader(fs.getPath(owner).readBytes())
|
||||||
|
val node = ClassNode()
|
||||||
|
classReader.accept(node, 0)
|
||||||
|
if (node.fields.none { it.name.equals(name) && it.desc.equals(desc) }) {
|
||||||
|
error("AccessWidener validation failed in line ${index + 2}: $line (Could not find target field)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readAW(project: Project): List<String> {
|
||||||
val awFile = getAWFile(project)
|
val awFile = getAWFile(project)
|
||||||
println("Found accesswidener in project: $awFile")
|
println("Found accesswidener in project: $awFile")
|
||||||
return awFile?.bufferedReader(StandardCharsets.UTF_8)
|
return awFile?.bufferedReader(StandardCharsets.UTF_8)
|
||||||
.takeIf { HEADER.test(it?.readLine() ?: "") }?.lines()
|
.takeIf { HEADER.test(it?.readLine() ?: "") }?.lines()
|
||||||
?.map { it.replace("transitive-", "") }
|
?.map { it.replace("transitive-", "") }?.toList()
|
||||||
?: Stream.empty()
|
?: emptyList()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readTransitiveAW(path: Path): Stream<String> {
|
private fun readTransitiveAW(path: Path): List<String> {
|
||||||
return path.bufferedReader(StandardCharsets.UTF_8).takeIf { HEADER.test(it.readLine() ?: "") }?.lines()?.filter { it.startsWith("transitive-") }?: Stream.empty()
|
return path.bufferedReader(StandardCharsets.UTF_8).takeIf { HEADER.test(it.readLine() ?: "") }?.lines()
|
||||||
|
?.filter { it.startsWith("transitive-") }?.toList() ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readAllAWs(project: Project): Stream<Entry> {
|
private fun readAllAWs(project: Project): Stream<Entry> {
|
||||||
return Stream.concat(
|
return Stream.concat(
|
||||||
findDependencyAWs(project),
|
findDependencyAWs(project),
|
||||||
readAW(project)
|
readAW(project).stream()
|
||||||
)
|
)
|
||||||
.filter { it.isNotBlank() }
|
.filter { it.isNotBlank() }
|
||||||
.map { if (it.contains("#")) it.split("#")[0] else it }.filter { !HEADER.test(it) }
|
.map { if (it.contains("#")) it.split("#")[0] else it }.filter { !HEADER.test(it) }
|
||||||
|
|
|
@ -0,0 +1,260 @@
|
||||||
|
package dev.frogmc.phytotelma.ext
|
||||||
|
|
||||||
|
import dev.frogmc.phytotelma.PhytotelmaPlugin
|
||||||
|
import dev.frogmc.phytotelma.mappings.filterClasses
|
||||||
|
import dev.frogmc.phytotelma.mappings.renameDstNamespace
|
||||||
|
import dev.frogmc.phytotelma.mappings.renameNamespaces
|
||||||
|
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()
|
||||||
|
internal lateinit var mappingsName: String
|
||||||
|
internal lateinit var targetNamespace: String
|
||||||
|
|
||||||
|
fun mojmapParchment(): Provider<MappingBundle> {
|
||||||
|
return mojmapParchment {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mojmapParchment(action: Action<ParchmentConfiguration>): Provider<MappingBundle> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
mappingsName = "mojmap($version)+parchment(${conf.gameVersion}, ${conf.version})"
|
||||||
|
targetNamespace = "mojmap"
|
||||||
|
|
||||||
|
return@provider MappingBundle.merge(
|
||||||
|
MojmapProvider.get(
|
||||||
|
version,
|
||||||
|
cacheDir.resolve("net/minecraft/client/$version/client-$version.txt")
|
||||||
|
).orElseThrow().reverse(),
|
||||||
|
ParchmentProvider.getParchment(
|
||||||
|
version,
|
||||||
|
cacheDir.resolve("org/parchmentmc/parchment/${conf.gameVersion}/${conf.version}")
|
||||||
|
)
|
||||||
|
).renameDstNamespace(targetNamespace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parchment(action: Action<ParchmentConfiguration>): Provider<MappingBundle> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
mappingsName = "parchment(${conf.gameVersion}, ${conf.version})"
|
||||||
|
targetNamespace = "parchment"
|
||||||
|
|
||||||
|
return@provider ParchmentProvider.getParchment(
|
||||||
|
version,
|
||||||
|
cacheDir.resolve("org/parchmentmc/parchment/${conf.gameVersion}/${conf.version}")
|
||||||
|
).renameNamespaces("mojmap", "parchment")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mojmap(): Provider<MappingBundle> {
|
||||||
|
return project.provider {
|
||||||
|
val cacheDir = PhytotelmaPlugin.globalCacheDir
|
||||||
|
mappingsName = "mojmap($version)"
|
||||||
|
targetNamespace = "mojmap"
|
||||||
|
return@provider MojmapProvider.get(
|
||||||
|
version,
|
||||||
|
cacheDir.resolve("net/minecraft/client/$version/client-$version.txt")
|
||||||
|
).orElseThrow().reverse().renameDstNamespace(targetNamespace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun quiltMappings(action: Action<VersionConfiguration>): Provider<MappingBundle> {
|
||||||
|
return project.provider {
|
||||||
|
val conf = objects.newInstance(VersionConfiguration::class.java)
|
||||||
|
action.execute(conf)
|
||||||
|
if (conf.version == null) {
|
||||||
|
error("No version provided for quilt mappings!")
|
||||||
|
}
|
||||||
|
mappingsName = "quilt-mappings(${conf.version})"
|
||||||
|
targetNamespace = "quilt-mappings"
|
||||||
|
// Use qm via intermediary because hashed publications are broken
|
||||||
|
return@provider twoStepMappings(
|
||||||
|
"net.fabricmc:intermediary:$version:v2",
|
||||||
|
"org.quiltmc:quilt-mappings:${conf.version}:intermediary-v2"
|
||||||
|
).filterClasses { !it.startsWith("net/minecraft/unmapped") }
|
||||||
|
.flatten(true).renameDstNamespace(targetNamespace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun yarn(action: Action<VersionConfiguration>): Provider<MappingBundle> {
|
||||||
|
return project.provider {
|
||||||
|
val conf = objects.newInstance(VersionConfiguration::class.java)
|
||||||
|
action.execute(conf)
|
||||||
|
if (conf.version == null) {
|
||||||
|
error("No version provided for yarn!")
|
||||||
|
}
|
||||||
|
mappingsName = "yarn(${conf.version})"
|
||||||
|
targetNamespace = "yarn"
|
||||||
|
// Use qm via intermediary because hashed publications are broken
|
||||||
|
return@provider twoStepMappings(
|
||||||
|
"net.fabricmc:intermediary:$version:v2",
|
||||||
|
"net.fabricmc:yarn:${conf.version}:v2"
|
||||||
|
).filterClasses { !it.startsWith("net/minecraft/class_") }
|
||||||
|
.flatten(true).renameDstNamespace(targetNamespace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun twoStepMappings(action: Action<TwoStepMappingsConfiguration>): Provider<MappingBundle> {
|
||||||
|
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!")
|
||||||
|
}
|
||||||
|
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> {
|
||||||
|
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!")
|
||||||
|
}
|
||||||
|
mappingsName = "custom/tiny(${conf.name})"
|
||||||
|
val bundle = tinyMappings(conf.name!!)
|
||||||
|
targetNamespace = bundle.flattenData().dstNamespace
|
||||||
|
return@provider bundle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mappings(action: Action<MappingBundle>): Provider<MappingBundle> {
|
||||||
|
return project.provider {
|
||||||
|
val bundle = MappingBundle()
|
||||||
|
action.execute(bundle)
|
||||||
|
mappingsName = "custom(${bundle.srcNamespaces()}, ${bundle.dstNamespaces()})"
|
||||||
|
targetNamespace = bundle.flattenData().dstNamespace
|
||||||
|
return@provider bundle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun layer(action: Action<LayerConfiguration>): Provider<MappingBundle> {
|
||||||
|
return project.provider {
|
||||||
|
val conf = objects.newInstance(LayerConfiguration::class.java)
|
||||||
|
action.execute(conf)
|
||||||
|
|
||||||
|
var back = MappingBundle()
|
||||||
|
var name = "layer["
|
||||||
|
|
||||||
|
val layers = conf.layers.mapIndexed { index, provider ->
|
||||||
|
val bundle = provider.get().flatten(true)
|
||||||
|
if (index == 0) {
|
||||||
|
name += mappingsName
|
||||||
|
back.insert(bundle)
|
||||||
|
return@mapIndexed bundle
|
||||||
|
}
|
||||||
|
name += ", $mappingsName"
|
||||||
|
|
||||||
|
back = back.flatten(false)
|
||||||
|
val prevDst = back.data[0].dstNamespace
|
||||||
|
val dst = bundle.data[0].dstNamespace
|
||||||
|
val remapped = MappingBundle.merge(bundle.reverse(), back)
|
||||||
|
.flatten(prevDst, dst)
|
||||||
|
.insert(back.docsForNamespace(dst))
|
||||||
|
|
||||||
|
back.insert(remapped)
|
||||||
|
return@mapIndexed remapped
|
||||||
|
}
|
||||||
|
mappingsName = "$name]"
|
||||||
|
val result = MappingBundle.merge(*layers.toTypedArray())
|
||||||
|
.flatten("official", layers.last().dstNamespaces()[0])
|
||||||
|
targetNamespace = result.data[0].dstNamespace
|
||||||
|
return@provider result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,13 @@
|
||||||
package dev.frogmc.phytotelma.ext
|
package dev.frogmc.phytotelma.ext
|
||||||
|
|
||||||
import org.gradle.api.provider.Provider
|
import org.gradle.api.Action
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
interface PhytotelmaGradleExtension {
|
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) {
|
fun loader(action: Action<VersionConfiguration>)
|
||||||
minecraft(version.get(), parchmentGameVersion?.get(), parchmentVersion?.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loader(version: String)
|
fun froglib(action: Action<VersionConfiguration>)
|
||||||
|
|
||||||
fun loader(version: Provider<String>) {
|
|
||||||
loader(version.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun froglib(version: String)
|
|
||||||
|
|
||||||
fun froglib(version: Provider<String>) {
|
|
||||||
froglib(version.get())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,105 +1,328 @@
|
||||||
package dev.frogmc.phytotelma.ext
|
package dev.frogmc.phytotelma.ext
|
||||||
|
|
||||||
import dev.frogmc.phytotelma.Constants
|
import com.electronwill.nightconfig.core.file.FileNotFoundAction
|
||||||
import dev.frogmc.phytotelma.PhytotelmaPlugin
|
import com.electronwill.nightconfig.toml.TomlParser
|
||||||
import dev.frogmc.phytotelma.ProjectStorage
|
import dev.frogmc.phytotelma.*
|
||||||
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.common.Env
|
||||||
|
import dev.frogmc.phytotelma.mappings.renameDstNamespace
|
||||||
|
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.vineflower.FrogJavadocProvider
|
||||||
import dev.frogmc.thyroxine.Thyroxine
|
import dev.frogmc.thyroxine.Thyroxine
|
||||||
import dev.frogmc.thyroxine.parser.ProguardParser
|
import dev.frogmc.thyroxine.api.Mapper
|
||||||
|
import dev.frogmc.thyroxine.api.data.MappingBundle
|
||||||
import dev.frogmc.thyroxine.provider.MojmapProvider
|
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.Project
|
||||||
|
import org.gradle.api.model.ObjectFactory
|
||||||
|
import org.gradle.api.plugins.JavaBasePlugin
|
||||||
|
import org.gradle.api.plugins.JavaPlugin
|
||||||
|
import org.gradle.api.tasks.Delete
|
||||||
|
import org.gradle.configurationcache.extensions.capitalized
|
||||||
|
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.OutputStream
|
||||||
|
import java.io.PrintStream
|
||||||
|
import java.nio.file.FileSystems
|
||||||
|
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.*
|
||||||
import kotlin.io.path.notExists
|
|
||||||
|
|
||||||
abstract class PhytotelmaGradleExtensionImpl : PhytotelmaGradleExtension {
|
abstract class PhytotelmaGradleExtensionImpl @Inject constructor(
|
||||||
|
private val project: Project,
|
||||||
|
private val objects: ObjectFactory
|
||||||
|
) : PhytotelmaGradleExtension {
|
||||||
|
|
||||||
@Inject
|
private fun setupTasks() {
|
||||||
abstract fun getProject(): Project
|
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.get(ProjectStorage.get(project).targetNamespace))
|
||||||
|
|
||||||
override fun minecraft(version: String, parchmentGameVersion: String?, parchmentVersion: String?) {
|
println("Decompiling...")
|
||||||
if (VersionChecker.validateVersion(version, offlineMode = getProject().gradle.startParameter.isOffline)) {
|
val logger = PrintStreamLogger(PrintStream(System.out))
|
||||||
println("Setting up Minecraft...")
|
options.putAll(
|
||||||
val parchmentGameVer = parchmentGameVersion?: version
|
mapOf(
|
||||||
val parchment =
|
IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES to "1",
|
||||||
parchmentVersion ?: kotlin.runCatching { ParchmentProvider.findForMinecraftVersion(parchmentGameVer) }
|
IFernflowerPreferences.BYTECODE_SOURCE_MAPPING to "1",
|
||||||
.getOrDefault("")
|
IFernflowerPreferences.REMOVE_SYNTHETIC to "1",
|
||||||
val projectData = ProjectStorage.get(getProject())
|
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, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val buildTask = project.tasks.register(Constants.BUILD_TASK, PhytotelmaBuildTask::class.java)
|
||||||
|
project.tasks.getByName(JavaBasePlugin.BUILD_TASK_NAME).dependsOn(buildTask)
|
||||||
|
|
||||||
|
project.tasks.getByName(JavaPlugin.JAR_TASK_NAME).actions.addLast { task ->
|
||||||
|
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")
|
||||||
|
val parser = TomlParser()
|
||||||
|
task.outputs.files.forEach { file ->
|
||||||
|
val temp = Files.createTempFile("", file.name)
|
||||||
|
Files.copy(file.toPath(), temp, StandardCopyOption.REPLACE_EXISTING)
|
||||||
|
FileSystems.newFileSystem(temp).use { fs ->
|
||||||
|
val metadata = fs.getPath(Constants.MOD_METADATA_FILE)
|
||||||
|
parser.parse(metadata, FileNotFoundAction.READ_NOTHING)
|
||||||
|
.get<String>("frog.extensions.accesswidener")?.let { name ->
|
||||||
|
val aw = metadata.resolveSibling(name)
|
||||||
|
AccessWidener.checkAW(aw, ProjectStorage.get(project).remappedGameJarPath!!)
|
||||||
|
val mapper = Mapper(mappings) { listOf() }
|
||||||
|
val buffer = buildString {
|
||||||
|
aw.forEachLine {
|
||||||
|
if (it.contains("\\t") && !it.startsWith("#")) {
|
||||||
|
val parts = it.split("[\\t #]+".toRegex()).toMutableList()
|
||||||
|
|
||||||
|
if (parts.size > 2) {
|
||||||
|
|
||||||
|
val type = parts[1]
|
||||||
|
when (type) {
|
||||||
|
"class" -> {
|
||||||
|
parts[2] = mapper.map(parts[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
"fields" -> {
|
||||||
|
parts[3] = mapper.mapFieldName(parts[2], parts[3], parts[4])
|
||||||
|
parts[4] = mapper.mapDesc(parts[4])
|
||||||
|
parts[3] = mapper.map(parts[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
"methods" -> {
|
||||||
|
parts[3] = mapper.mapMethodName(parts[2], parts[3], parts[4])
|
||||||
|
parts[4] = mapper.mapMethodDesc(parts[4])
|
||||||
|
parts[2] = mapper.map(parts[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appendLine(parts.joinToString("\\t"))
|
||||||
|
return@forEachLine
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appendLine(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aw.writeText(buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Thyroxine.remap(mappings, temp, file.toPath(), false, false)
|
||||||
|
Files.deleteIfExists(temp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
project.tasks.register(Constants.UPDATE_AW_TASK) { task ->
|
||||||
|
task.group = Constants.TASK_GROUP
|
||||||
|
task.actions.addFirst {
|
||||||
|
AccessWidener.apply(project, ProjectStorage.get(it.project).remappedGameJarPath!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
project.tasks.register(Constants.CLEAR_LOCAL_CACHE_TASK, Delete::class.java) { task ->
|
||||||
|
task.group = Constants.TASK_GROUP
|
||||||
|
task.delete = setOf(ProjectStorage.get(project).localCacheDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
project.tasks.register(Constants.CLEAR_GLOBAL_CACHE_TASK, Delete::class.java) { task ->
|
||||||
|
task.group = Constants.TASK_GROUP
|
||||||
|
task.delete = setOf(PhytotelmaPlugin.globalCacheDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
project.afterEvaluate {
|
||||||
|
remapModDependencies()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun remapModDependencies() {
|
||||||
|
val out = System.out
|
||||||
|
// Mute the output from thyroxine as there may be a lot of remapping operations here
|
||||||
|
System.setOut(PrintStream(OutputStream.nullOutputStream()))
|
||||||
|
ModConfigurations.configurations.forEach { conf ->
|
||||||
|
val artifacts = project.configurations.getByName("mod" + conf.name.capitalized())
|
||||||
|
.resolvedConfiguration.resolvedArtifacts
|
||||||
|
if (artifacts.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val target = project.configurations.create("mod" + conf.name.capitalized() + "Mapped") { c ->
|
||||||
|
c.isTransitive = false
|
||||||
|
conf.classpathNames.forEach {
|
||||||
|
project.configurations.getByName(it).extendsFrom(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val storage = ProjectStorage.get(project)
|
||||||
|
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("mojmap", storage.targetNamespace)
|
||||||
|
val targetPath = project.layout.buildDirectory.asFile.get().toPath().resolve("remappedMods")
|
||||||
|
.resolve("dev/frogmc/phytotelma/remapped_mods")
|
||||||
|
val remappedPaths = mutableListOf<Path>()
|
||||||
|
artifacts.forEach { artifact ->
|
||||||
|
val group = artifact.moduleVersion.id.group
|
||||||
|
val name = artifact.moduleVersion.id.name
|
||||||
|
val groupname = (group + "_" + name).replace(".", "_")
|
||||||
|
val version = artifact.moduleVersion.id.version
|
||||||
|
val classifier = artifact.classifier
|
||||||
|
val remappedPath = targetPath.resolve(groupname).resolve(version)
|
||||||
|
.resolve(groupname + "-" + version + (classifier?.let { "-$it" } ?: "") + ".jar")
|
||||||
|
remappedPath.createParentDirectories()
|
||||||
|
remappedPaths.add(remappedPath)
|
||||||
|
|
||||||
|
val pom = remappedPath.resolveSibling(remappedPath.fileName.toString().removeSuffix(".jar") + ".pom")
|
||||||
|
pom.writeText(
|
||||||
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
||||||
|
"<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n" +
|
||||||
|
"\t\t xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
|
||||||
|
"\t<modelVersion>4.0.0</modelVersion>\n" +
|
||||||
|
"\t<groupId>dev.frogmc.phytotelma.remapped_mods</groupId>\n" +
|
||||||
|
"\t<artifactId>$groupname</artifactId>\n" +
|
||||||
|
"\t<version>$version</version>\n" +
|
||||||
|
"</project>"
|
||||||
|
)
|
||||||
|
remappedPaths.add(pom)
|
||||||
|
|
||||||
|
Thyroxine.remap(mappings, artifact.file.toPath(), remappedPath, false, false)
|
||||||
|
|
||||||
|
project.dependencies.add(
|
||||||
|
target.name,
|
||||||
|
"dev.frogmc.phytotelma.remapped_mods:$groupname:$version" + (classifier?.let { ":$it" } ?: "")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.setOut(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun minecraft(action: Action<MinecraftConfiguration>) {
|
||||||
|
setupTasks()
|
||||||
|
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
|
projectData.minecraftVersion = version
|
||||||
projectData.parchmentVersion = parchment
|
|
||||||
println("Valid version! $version")
|
val mappings = mcConf.mappings.get()
|
||||||
val clientJar = VersionChecker.downloadClient(getProject(), version)
|
println("Using mappings: " + mcConf.mappingsName)
|
||||||
|
projectData.mappings = mappings
|
||||||
|
|
||||||
|
val clientJar = VersionChecker.downloadClient(project, version)
|
||||||
val remappedJar =
|
val remappedJar =
|
||||||
projectData.localCacheDir!!.resolve("net/minecraft/client/$version/client-$version-remapped.jar")
|
projectData.localCacheDir!!.resolve("net/minecraft/client/$version/client-$version-remapped.jar")
|
||||||
remappedJar.createParentDirectories()
|
remappedJar.createParentDirectories()
|
||||||
projectData.remappedGameJarPath = remappedJar
|
projectData.remappedGameJarPath = remappedJar
|
||||||
println("Time to setup Minecraft!")
|
val applyAW = AccessWidener.needsUpdate(project)
|
||||||
val applyAW = AccessWidener.needsUpdate(getProject())
|
if (remappedJar.notExists() || applyAW || mcConf.mappingsName != projectData.mappingsName) {
|
||||||
if (remappedJar.notExists() || applyAW) {
|
projectData.mappingsName = mcConf.mappingsName
|
||||||
println("Remapping the game...")
|
println("Remapping the game...")
|
||||||
val data = kotlin.runCatching {
|
projectData.targetNamespace = mcConf.targetNamespace
|
||||||
ProguardParser.read(
|
Thyroxine.remap(
|
||||||
MojmapProvider.get(
|
mappings.forNamespaces("official", mcConf.targetNamespace),
|
||||||
version,
|
clientJar, remappedJar, true, true
|
||||||
clientJar.resolveSibling("client-$version.txt")
|
|
||||||
).orElseThrow()
|
|
||||||
).reverse()
|
|
||||||
}.getOrNull()
|
|
||||||
val paramMappings = if (parchment.isNotEmpty()) kotlin.runCatching {
|
|
||||||
ParchmentProvider.getParchment(
|
|
||||||
parchmentGameVer, parchment,
|
|
||||||
PhytotelmaPlugin.globalCacheDir.resolve("org/parchmentmc/parchment/$parchmentGameVer/$parchment"),
|
|
||||||
getProject().gradle.startParameter.isRefreshDependencies
|
|
||||||
)
|
)
|
||||||
}.getOrNull() else {
|
|
||||||
println("Parameter mappings will not be present as no parchment version was found. It may be possible to declare it manually.")
|
|
||||||
null
|
|
||||||
}
|
}
|
||||||
if (paramMappings == null && parchment.isNotEmpty()) {
|
|
||||||
println("Parameter mappings will not be present as the version $parchmentVersion for minecraft version $parchmentGameVer could not be found")
|
project.dependencies.add(
|
||||||
}
|
|
||||||
if (data != null) {
|
|
||||||
Thyroxine.remap(data, clientJar, remappedJar, true, paramMappings)
|
|
||||||
} 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.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println("Adding dependencies...")
|
|
||||||
getProject().dependencies.add(
|
|
||||||
Constants.MINECRAFT_CONFIGURATION,
|
Constants.MINECRAFT_CONFIGURATION,
|
||||||
"net.minecrell:terminalconsoleappender:1.2.0"
|
"net.minecrell:terminalconsoleappender:1.2.0"
|
||||||
)
|
)
|
||||||
VersionChecker.getDependencies(version) {
|
VersionChecker.getDependencies(version) {
|
||||||
getProject().dependencies.add(Constants.MINECRAFT_CONFIGURATION, it)
|
project.dependencies.add(Constants.MINECRAFT_CONFIGURATION, it)
|
||||||
}
|
}
|
||||||
VersionChecker.savePomFile(version, remappedJar.parent)
|
VersionChecker.savePomFile(version, remappedJar.parent)
|
||||||
getProject().dependencies.add(Constants.MINECRAFT_CONFIGURATION, "net.minecraft:client:$version:remapped")
|
project.dependencies.add(Constants.MINECRAFT_CONFIGURATION, "net.minecraft:client:$version:remapped")
|
||||||
|
|
||||||
println("Generating run configurations...")
|
RunConfigGenerator.generate(project)
|
||||||
RunConfigGenerator.generate(getProject())
|
AssetDownloader.download(project)
|
||||||
|
|
||||||
if (applyAW) {
|
if (applyAW) {
|
||||||
getProject().afterEvaluate {
|
project.afterEvaluate {
|
||||||
println("Applying AccessWideners...")
|
println("Applying AccessWideners...")
|
||||||
AccessWidener.apply(getProject(), remappedJar)
|
AccessWidener.apply(project, remappedJar)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println("Done!")
|
override fun loader(action: Action<VersionConfiguration>) {
|
||||||
} else {
|
val conf = objects.newInstance(VersionConfiguration::class.java)
|
||||||
println("Invalid version! $version")
|
action.execute(conf)
|
||||||
error("Invalid minecraft version provided: $version")
|
if (conf.version == null) {
|
||||||
|
error("No loader version provided!")
|
||||||
}
|
}
|
||||||
|
project.dependencies.add("implementation", "dev.frogmc:frogloader:${conf.version!!}")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loader(version: String) {
|
override fun froglib(action: Action<VersionConfiguration>) {
|
||||||
getProject().dependencies.add("implementation", "dev.frogmc:frogloader:$version")
|
val conf = objects.newInstance(VersionConfiguration::class.java)
|
||||||
|
action.execute(conf)
|
||||||
|
if (conf.version == null) {
|
||||||
|
error("No froglib version provided!")
|
||||||
}
|
}
|
||||||
|
project.dependencies.add("modImplementation", "dev.frogmc:froglib:${conf.version!!}")
|
||||||
override fun froglib(version: String) {
|
|
||||||
getProject().dependencies.add("implementation", "dev.frogmc:froglib:$version")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
48
src/main/kotlin/dev/frogmc/phytotelma/mappings/Mappings.kt
Normal file
48
src/main/kotlin/dev/frogmc/phytotelma/mappings/Mappings.kt
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
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.renameNamespaces(newSrc: String?, newDst: String): MappingBundle {
|
||||||
|
val oldData = if (srcNamespaces().size > 1 || dstNamespaces().size > 1) flattenData() else data[0]
|
||||||
|
val newData = MappingData(newSrc ?: 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 MappingBundle(newData, get(oldData.dstNamespace)?.let { newDocs.insert(it) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fun MappingBundle.renameDstNamespace(newDst: String): MappingBundle {
|
||||||
|
return renameNamespaces(null, newDst)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun MappingBundle.filterClasses(filter: (String) -> Boolean): MappingBundle {
|
||||||
|
val oldData = data.last()
|
||||||
|
val newData = MappingData(oldData.srcNamespace, oldData.dstNamespace)
|
||||||
|
val oldDocs = if (documentation.isNotEmpty()) documentation.last() else null
|
||||||
|
|
||||||
|
oldData.apply {
|
||||||
|
newData.classes.putAll(classes.filter { filter.invoke(it.value) })
|
||||||
|
newData.fields.putAll(fields.filter { newData.classes.containsKey(it.key.owner) })
|
||||||
|
newData.methods.putAll(methods.filter { newData.classes.containsKey(it.key.owner) })
|
||||||
|
newData.parameters.putAll(parameters.filter { newData.classes.containsKey(it.key.owner) })
|
||||||
|
}
|
||||||
|
|
||||||
|
val bundle = MappingBundle(data.subList(0, data.size - 1).plus(newData), mutableListOf())
|
||||||
|
|
||||||
|
if (oldDocs != null) {
|
||||||
|
val newDocs = DocumentationData(newData.dstNamespace)
|
||||||
|
newDocs.classes.addAll(oldDocs.classes.filter { filter.invoke(it.name) })
|
||||||
|
bundle.insert(newDocs)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return bundle
|
||||||
|
}
|
|
@ -110,8 +110,8 @@ object Nester {
|
||||||
val matcher = pattern.matcher(version)
|
val matcher = pattern.matcher(version)
|
||||||
matcher.find()
|
matcher.find()
|
||||||
val semver = matcher.group(1) +
|
val semver = matcher.group(1) +
|
||||||
(if (matcher.group(2) != null) "-"+matcher.group(2) else "") +
|
(if (matcher.group(2) != null) "-" + matcher.group(2) else "") +
|
||||||
(if (matcher.group(3) != null) "+"+matcher.group(3) else "")
|
(if (matcher.group(3) != null) "+" + matcher.group(3) else "")
|
||||||
it.getPath("frog.mod.toml").writeText(
|
it.getPath("frog.mod.toml").writeText(
|
||||||
"""
|
"""
|
||||||
[frog]
|
[frog]
|
||||||
|
|
|
@ -9,43 +9,59 @@ import dev.frogmc.phytotelma.common.CachingHttpClient
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import kotlin.io.path.createDirectories
|
import kotlin.io.path.createDirectories
|
||||||
|
import kotlin.io.path.notExists
|
||||||
import kotlin.io.path.reader
|
import kotlin.io.path.reader
|
||||||
|
|
||||||
object AssetDownloader {
|
object AssetDownloader {
|
||||||
private const val ASSETS_URL = "https://resources.download.minecraft.net"
|
private const val ASSETS_URL = "https://resources.download.minecraft.net"
|
||||||
|
|
||||||
fun download(project: Project) {
|
fun download(project: Project, manualInvocation: Boolean = false) {
|
||||||
val version = ProjectStorage.get(project).minecraftVersion!!
|
val version = ProjectStorage.get(project).minecraftVersion!!
|
||||||
val path = PhytotelmaPlugin.globalCacheDir.resolve("assets")
|
val path = PhytotelmaPlugin.globalCacheDir.resolve("assets")
|
||||||
val id = VersionChecker.downloadAssetIndex(version, path.resolve("indexes"))
|
val assetIndex = VersionChecker.fetchVersionData(version).assetIndex
|
||||||
|
val dest = path.resolve("indexes").resolve(assetIndex.id + ".json")
|
||||||
|
var overwrite = manualInvocation
|
||||||
|
if (dest.notExists()) {
|
||||||
|
CachingHttpClient.getUncached(URI.create(assetIndex.url)).use {
|
||||||
|
Files.copy(it, dest)
|
||||||
|
}
|
||||||
|
overwrite = true
|
||||||
|
}
|
||||||
|
|
||||||
val index = Gson().fromJson(
|
val index = Gson().fromJson(
|
||||||
path.resolve("indexes").resolve("$id.json").reader(StandardCharsets.UTF_8),
|
path.resolve("indexes").resolve("${assetIndex.id}.json").reader(StandardCharsets.UTF_8),
|
||||||
JsonObject::class.java
|
JsonObject::class.java
|
||||||
)
|
)
|
||||||
val objectsPath = path.resolve("objects")
|
val objectsPath = path.resolve("objects")
|
||||||
objectsPath.createDirectories()
|
objectsPath.createDirectories()
|
||||||
val entries = index.getAsJsonObject("objects").entrySet()
|
val entries = index.getAsJsonObject("objects").entrySet()
|
||||||
val totalSize = entries.size
|
val totalSize = entries.size
|
||||||
|
if (overwrite) {
|
||||||
print("Downloading $totalSize assets... ()")
|
print("Downloading $totalSize assets... ()")
|
||||||
System.out.flush()
|
System.out.flush()
|
||||||
|
}
|
||||||
entries.forEachIndexed { i, it ->
|
entries.forEachIndexed { i, it ->
|
||||||
val hash = it.value.asJsonObject.get("hash").asString
|
val hash = it.value.asJsonObject.get("hash").asString
|
||||||
/*val size = it.value.asJsonObject.get("size").asInt
|
/*val size = it.value.asJsonObject.get("size").asInt
|
||||||
val name = it.key*/
|
val name = it.key*/
|
||||||
// TODO asset downloading for versions <=1.7 (legacy)
|
// TODO asset downloading for versions <=1.7 (legacy)
|
||||||
print("\rDownloading $totalSize assets... ($i/$totalSize): $hash"+" ".repeat(30))
|
if (overwrite) {
|
||||||
|
print("\rDownloading $totalSize assets... ($i/$totalSize): $hash" + " ".repeat(30))
|
||||||
System.out.flush()
|
System.out.flush()
|
||||||
get(objectsPath, hash)
|
|
||||||
}
|
}
|
||||||
println("\rDownloading $totalSize assets... Done!"+" ".repeat(50))
|
get(objectsPath, hash, overwrite)
|
||||||
|
}
|
||||||
|
if (overwrite) {
|
||||||
|
println("\rDownloading $totalSize assets... Done!" + " ".repeat(50))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun get(localDir: Path, hash: String) {
|
private fun get(localDir: Path, hash: String, overwrite: Boolean) {
|
||||||
val shortHash = hash.substring(0, 2)
|
val shortHash = hash.substring(0, 2)
|
||||||
val path = localDir.resolve("$shortHash/$hash")
|
val path = localDir.resolve("$shortHash/$hash")
|
||||||
CachingHttpClient.downloadTo(URI.create("$ASSETS_URL/$shortHash/$hash"), path, true)
|
CachingHttpClient.downloadTo(URI.create("$ASSETS_URL/$shortHash/$hash"), path, overwrite)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ object RunConfigGenerator {
|
||||||
assetIndexPath.createDirectories()
|
assetIndexPath.createDirectories()
|
||||||
}
|
}
|
||||||
val projectData = ProjectStorage.get(project)
|
val projectData = ProjectStorage.get(project)
|
||||||
val indexId = VersionChecker.downloadAssetIndex(projectData.minecraftVersion!!, assetIndexPath)
|
val indexId = VersionChecker.fetchVersionData(projectData.minecraftVersion!!).assetIndex.id
|
||||||
|
|
||||||
val projectName = if (project.rootDir == project.projectDir) "" else " (${project.name})"
|
val projectName = if (project.rootDir == project.projectDir) "" else " (${project.name})"
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ abstract class RunGameTask @Inject constructor(env: Env) : JavaExec() {
|
||||||
if (assetIndexPath.notExists()) {
|
if (assetIndexPath.notExists()) {
|
||||||
assetIndexPath.createDirectories()
|
assetIndexPath.createDirectories()
|
||||||
}
|
}
|
||||||
val indexId = VersionChecker.downloadAssetIndex(ProjectStorage.get(project).minecraftVersion!!, assetIndexPath)
|
val indexId = VersionChecker.fetchVersionData(ProjectStorage.get(project).minecraftVersion!!).assetIndex.id
|
||||||
val log4jPath = project.rootDir.resolve(".gradle/phytotelma/log4j.xml").toPath().absolute()
|
val log4jPath = project.rootDir.resolve(".gradle/phytotelma/log4j.xml").toPath().absolute()
|
||||||
if (log4jPath.notExists()) {
|
if (log4jPath.notExists()) {
|
||||||
log4jPath.createParentDirectories()
|
log4jPath.createParentDirectories()
|
||||||
|
|
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue