Compare commits

..

18 commits

Author SHA1 Message Date
moehreag 461688d5f6 update gradle wrapper
Some checks failed
Publish to snapshot maven / build (push) Failing after 13s
2024-06-07 15:19:16 +02:00
moehreag 35afc6a296 fix javadoc injection 2024-06-05 16:28:22 +02:00
moehreag 333d5889b7 rename more things: nonsense->frog 2024-06-03 13:31:00 +02:00
moehreag 3e21b4d8d5 move to domain namespace 2024-06-02 23:13:58 +02:00
moehreag 999dad62bc move packages 2024-06-02 16:36:49 +02:00
moehreag 5353fe7d60 correct version 2024-06-02 16:33:50 +02:00
moehreag d68aae3066 move maven group 2024-06-02 16:19:16 +02:00
owlsys 709f5fbbe7 Merge pull request 'add jij inclusions' (#3) from owlsys/jij into mistress
Reviewed-on: https://git-esnesnon.ecorous.org/esnesnon/phytotelma/pulls/3
Reviewed-by: Ecorous <ecorous@outlook.com>
2024-06-01 12:19:25 -04:00
moehreag 3f4c38d821 add simpler integration with gradle version catalogues 2024-05-28 19:17:08 +02:00
moehreag b90330917c improve error handling 2024-05-28 18:52:05 +02:00
moehreag 0234a3b49a clean up a few things 2024-05-28 17:52:34 +02:00
moehreag 7dc23b1279 remove usages of .parallelStream 2024-05-28 15:15:15 +02:00
moehreag 67c253f2f0 fix remaining issues, improve speed 2024-05-28 14:15:21 +02:00
moehreag 80a9fc3fdc add accesswidener processing 2024-05-28 01:16:38 +02:00
moehreag 5f8c1538c3 add version to jar manifest 2024-05-27 12:10:43 +02:00
moehreag 056350e1dd add included mod ids to manifest 2024-05-27 12:03:19 +02:00
moehreag 4094397909 add jij inclusions 2024-05-27 00:35:39 +02:00
moehreag 61cfc68ddd enable built mod file renaming, remove mixin AP since we don't need it
because there's no need to remap mixins in any way as we run the game in mojmap as well
2024-05-25 15:45:29 +02:00
23 changed files with 815 additions and 299 deletions

View file

@ -18,6 +18,6 @@ jobs:
- name: Build - name: Build
run: | run: |
chmod +x ./gradlew chmod +x ./gradlew
./gradlew publishAllPublicationsToEsnesnonSnapshotsMavenRepository \ ./gradlew publishAllPublicationsToFrogMCSnapshotsMavenRepository \
-PEsnesnonSnapshotsMavenUsername=${{ secrets.MAVEN_PUSH_USER }} \ -PFrogMCSnapshotsMavenUsername=${{ secrets.MAVEN_PUSH_USER }} \
-PEsnesnonSnapshotsMavenPassword=${{ secrets.MAVEN_PUSH_TOKEN }} -PFrogMCSnapshotsMavenPassword=${{ secrets.MAVEN_PUSH_TOKEN }}

1
.gitignore vendored
View file

@ -37,3 +37,4 @@ bin/
### Mac OS ### ### Mac OS ###
.DS_Store .DS_Store
.kotlin/

View file

@ -1,41 +1,50 @@
plugins { plugins {
kotlin("jvm") version "1.9.23" kotlin("jvm") version "2.0.0"
`java-gradle-plugin` `java-gradle-plugin`
`maven-publish` `maven-publish`
} }
group = "org.ecorous.esnesnon" group = "dev.frogmc"
version = "0.0.1-SNAPSHOT" version = "0.0.1-SNAPSHOT"
repositories { repositories {
maven { maven {
name = "Esnesnos Maven Releases" name = "FrogMC Maven Releases"
url = uri("https://maven-esnesnon.ecorous.org/releases") url = uri("https://maven.frogmc.dev/releases")
} }
maven { maven {
name = "Esnesnos Maven Snapshots" name = "FrogMC Maven Snapshots"
url = uri("https://maven-esnesnon.ecorous.org/snapshots") url = uri("https://maven.frogmc.dev/snapshots")
} }
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
implementation("org.ecorous.esnesnon:nonsense-remapper:1.0.0-SNAPSHOT") implementation("org.ecorous.frogmc:thyroxine:1.0.0-SNAPSHOT")
implementation("org.ow2.asm:asm: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.2")
implementation("com.google.jimfs:jimfs:1.3.0")
} }
gradlePlugin { gradlePlugin {
plugins { plugins {
create("nonsense-gradle") { create("phytotelma") {
id = "org.ecorous.esnesnon.nonsense-gradle" id = "dev.frogmc.phytotelma"
implementationClass = "org.ecorous.esnesnon.gradle.NonsenseGradlePlugin" implementationClass = "dev.frogmc.phytotelma.PhytotelmaPlugin"
} }
} }
} }
tasks.jar {
manifest {
attributes["Implementation-Version"] = version
}
}
tasks.test { tasks.test {
useJUnitPlatform() useJUnitPlatform()
} }
@ -50,8 +59,8 @@ publishing {
repositories { repositories {
maven { maven {
name = "EsnesnonSnapshotsMaven" name = "FrogMCSnapshotsMaven"
url = uri("https://maven-esnesnon.ecorous.org/snapshots") url = uri("https://maven.frogmc.dev/snapshots")
credentials(PasswordCredentials::class) credentials(PasswordCredentials::class)
authentication { authentication {
create<BasicAuthentication>("basic") create<BasicAuthentication>("basic")
@ -59,8 +68,8 @@ publishing {
} }
maven { maven {
name = "EsnesnonReleasesMaven" name = "FrogMCReleasesMaven"
url = uri("https://maven-esnesnon.ecorous.org/releases") url = uri("https://maven.frogmc.dev/releases")
credentials(PasswordCredentials::class) credentials(PasswordCredentials::class)
authentication { authentication {
create<BasicAuthentication>("basic") create<BasicAuthentication>("basic")

View file

@ -1,6 +1,6 @@
#Sun May 12 17:35:40 BST 2024 #Sun May 12 17:35:40 BST 2024
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View file

@ -1,5 +1,5 @@
plugins { plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
} }
rootProject.name = "nonsense-gradle" rootProject.name = "phytotelma"

View file

@ -0,0 +1,191 @@
package dev.frogmc.phytotelma
import com.electronwill.nightconfig.core.CommentedConfig
import com.electronwill.nightconfig.core.file.FileNotFoundAction
import com.electronwill.nightconfig.core.io.WritingMode
import com.electronwill.nightconfig.toml.TomlParser
import com.electronwill.nightconfig.toml.TomlWriter
import net.fabricmc.fernflower.api.IFabricJavadocProvider
import dev.frogmc.phytotelma.accesswidener.AccessWidener
import dev.frogmc.phytotelma.common.Env
import dev.frogmc.phytotelma.nest.Nester
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 org.ecorous.frogmc.thyroxine.provider.ParchmentProvider
import org.gradle.api.Plugin
import org.gradle.api.Project
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.charset.StandardCharsets
import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
import kotlin.io.path.*
class PhytotelmaPlugin : Plugin<Project> {
private val taskGroup = "frogmc"
override fun apply(project: Project) {
println("> Applying FrogMC Gradle Plugin")
globalCacheDir = project.gradle.gradleUserHomeDir.resolve("caches/phytotelma/").toPath()
globalCacheDir.createDirectories()
project.plugins.let {
it.apply("java-library")
it.apply("eclipse")
it.apply("idea")
}
project.repositories.apply {
maven {
it.name = "FrogMC Releases"
it.url = URI.create("https://maven.frogmc.dev/releases")
}
maven {
it.name = "FrogMC Snapshots"
it.url = URI.create("https://maven.frogmc.dev/snapshots")
}
maven {
it.name = "Minecraft/Local"
it.url = project.gradle.gradleUserHomeDir.resolve("caches/phytotelma/").toURI()
}
maven {
it.name = "Minecraft Libraries"
it.url = URI.create("https://libraries.minecraft.net/")
}
}
project.repositories.mavenCentral()
project.task("genSources").apply {
group = taskGroup
doFirst {
val fileName = remappedGameJarPath.fileName.toString()
val output =
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(
minecraftVersion,
parchmentVersion,
project.gradle.gradleUserHomeDir.resolve("phytotelma/org/parchmentmc/parchment/$minecraftVersion/$parchmentVersion/")
.toPath()
)
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(remappedGameJarPath.toFile())
decomp.decompileContext()
}
}
project.task("genRunConfigs").apply {
group = taskGroup
doFirst {
RunConfigGenerator.generate(project)
}
}
project.tasks.register("runClient", RunGameTask::class.java, Env.CLIENT)
project.tasks.register("runServer", RunGameTask::class.java, Env.SERVER)
project.task("downloadAssets").apply {
group = taskGroup
doFirst {
AssetDownloader.download()
}
}
val includeConfiguration = project.configurations.register("include") {
it.isCanBeResolved = true
it.isCanBeConsumed = false
}
project.tasks.getByName("jar") { task ->
task.outputs.upToDateWhen { false }
task.actions.addLast { _ ->
task.outputs.files.forEach { file ->
val output = file.toPath().parent.resolveSibling("frogmc")
output.createDirectories()
if (file.name.endsWith(".jar") && !(file.name.contains("-dev.") || file.name.contains("-sources."))) {
val outFile = output.resolve(file.name.substring(0, file.name.length - 4) + ".frogmod")
Files.copy(file.toPath(), outFile, StandardCopyOption.REPLACE_EXISTING)
FileSystems.newFileSystem(outFile).use { fs ->
if (includeConfiguration.isPresent) {
val jijPath = fs.getPath("META-INF/jars")
val files = Nester.run(includeConfiguration.get(), jijPath).map { it.toml() }.toList()
if (files.isNotEmpty()) {
val manifest = fs.getPath("frog.mod.toml")
val config: CommentedConfig =
TomlParser().parse(manifest, FileNotFoundAction.THROW_ERROR)
if (!config.add("frog.extensions.included_jars", listOf(files))) {
println("Failed to add included jars to mod manifest, make sure it doesn't include a key at 'frog.extensions.included_jars'!")
}
TomlWriter().write(config, manifest, WritingMode.REPLACE)
}
}
val manifest = fs.getPath("META-INF/MANIFEST.MF")
val lines = manifest.readLines().filter { it.isNotBlank() }
.plus("""
Built-By: Phytotelma ${this.javaClass.`package`.implementationVersion}
Target-Namespace: Mojmap
Built-For: Minecraft $minecraftVersion
""".trimIndent()
)
manifest.writeLines(lines, StandardCharsets.UTF_8)
}
println("Built mod to ${outFile.toUri()}")
}
}
}
}
project.tasks.register("updateAccesswidener") {
it.group = taskGroup
it.actions.addFirst {
AccessWidener.apply(project, remappedGameJarPath)
}
}
}
companion object {
lateinit var globalCacheDir: Path
lateinit var minecraftVersion: String
lateinit var remappedGameJarPath: Path
lateinit var parchmentVersion: String
}
}

View file

@ -1,8 +1,8 @@
package org.ecorous.esnesnon.gradle package dev.frogmc.phytotelma
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import org.ecorous.esnesnon.gradle.common.CachingHttpClient import dev.frogmc.phytotelma.common.CachingHttpClient
import java.net.URI import java.net.URI
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
@ -17,18 +17,16 @@ object VersionChecker {
fetchVersionData(version) fetchVersionData(version)
val clientData = fetchClientDownload(version) val clientData = fetchClientDownload(version)
// download client data // download client data
val downloadDirectory = NonsenseGradlePlugin.nonsenseCacheDir.resolve("net/minecraft/client/$version/") val downloadDirectory = PhytotelmaPlugin.globalCacheDir.resolve("net/minecraft/client/$version/")
println("Directory: "+downloadDirectory.absolutePathString())
val downloadFile = downloadDirectory.resolve("client-$version.jar") val downloadFile = downloadDirectory.resolve("client-$version.jar")
if (downloadFile.exists()) { if (downloadFile.exists()) {
println("Client already downloaded to $downloadFile. Assuming it's valid. FIXME: Add checksum validation.") println("Client already downloaded! Assuming it's valid. FIXME: Add checksum validation.")
return downloadFile return downloadFile
} }
downloadDirectory.createDirectories() downloadDirectory.createDirectories()
val raw = rawDownload(clientData.url) val raw = rawDownload(clientData.url)
downloadFile.writeBytes(raw) downloadFile.writeBytes(raw)
savePomFile(version, downloadDirectory) savePomFile(version, downloadDirectory)
println("Downloaded client to $downloadFile")
return downloadFile return downloadFile
} }

View file

@ -0,0 +1,296 @@
package dev.frogmc.phytotelma.accesswidener
import com.electronwill.nightconfig.core.file.FileNotFoundAction
import com.electronwill.nightconfig.toml.TomlParser
import com.google.common.hash.Hashing
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginExtension
import org.objectweb.asm.*
import java.nio.charset.StandardCharsets
import java.nio.file.FileSystems
import java.nio.file.Path
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentSkipListSet
import java.util.regex.Pattern
import java.util.stream.Stream
import kotlin.io.path.bufferedReader
import kotlin.io.path.exists
import kotlin.io.path.readBytes
import kotlin.io.path.writeBytes
object AccessWidener {
private val PARSER = TomlParser()
private var awHash = ""
private val HEADER = Pattern.compile("accessWidener\\s+v[12]\\s+.*").asMatchPredicate()
private val SEPARATOR = "[\\t ]+".toRegex()
private fun getAWFile(project: Project): Path? {
project.extensions.getByType(JavaPluginExtension::class.java).sourceSets.forEach { set ->
set.resources.filter { it.name == "frog.mod.toml" }.firstOrNull {
if (it == null) {
println("Please make sure a 'frog.mod.toml' file is present in the mod's resources!")
return null
}
return PARSER.parse(it, FileNotFoundAction.READ_NOTHING)
.get<String>("frog.extensions.frog_aw")?.let { name ->
return it.resolveSibling(name).toPath()
}
}
}
println("Please make sure a 'frog.mod.toml' file is present in the mod's resources!")
return null
}
private fun findDependencyAWs(project: Project): List<Path> {
return project.configurations.getByName("runtimeClasspath").resolvedConfiguration.firstLevelModuleDependencies.flatMap { dep ->
dep.moduleArtifacts
}.map { it.file }.map { it.toPath() }.toList()
}
fun needsUpdate(project: Project): Boolean {
getAWFile(project)?.let {
val hash = Hashing.sha256().hashBytes(it.readBytes()).toString()
if (hash != awHash) {
awHash = hash
return true
}
}
return false
}
private fun readAW(project: Project): Stream<String> {
val awFile = getAWFile(project)
println("Found accesswidener in project: $awFile")
return awFile?.bufferedReader(StandardCharsets.UTF_8)?.lines()?.map { it.replace("transitive-", "") }
?: Stream.empty()
}
private fun readTransitiveAW(path: Path): Stream<String> {
return path.bufferedReader(StandardCharsets.UTF_8).lines().filter { it.startsWith("transitive-") }
}
private fun readAllAWs(project: Project): Stream<Entry> {
return Stream.concat(
findDependencyAWs(project).stream().flatMap { i -> readTransitiveAW(i) },
readAW(project)
)
.filter { it.isNotBlank() }
.map { if (it.contains("#")) it.split("#")[0] else it }.filter { !HEADER.test(it) }
.filter { it.isNotBlank() }
.unordered().distinct()
.map { it.split(SEPARATOR) }.filter { it.isNotEmpty() }.map { Entry(it) }
}
fun apply(project: Project, input: Path) {
val startTime = System.currentTimeMillis()
val classNames: MutableSet<String> = ConcurrentSkipListSet()
val classMap: MutableMap<String, Entry> = ConcurrentHashMap()
val methods: MutableMap<String, MutableMap<String, Entry>> = ConcurrentHashMap()
val fields: MutableMap<String, MutableMap<String, Entry>> = ConcurrentHashMap()
val mutations: MutableMap<String, MutableMap<String, Entry>> = ConcurrentHashMap()
val entries = readAllAWs(project)
entries.forEach { e ->
classNames.add(e.className)
if ("class" == e.targetType) {
if (e.type == AccessType.MUTABLE) {
throw IllegalArgumentException("aw format error: classes can not have a 'mutable' modifier (at: $e)")
}
if (!classMap.containsKey(e.className)) {
classMap[e.className] = e
} else {
val other = classMap[e.className]!!
if (e.isAccessGreaterThan(other)) {
classMap[e.className] = e
}
}
} else if ("method" == e.targetType) {
if (e.type == AccessType.MUTABLE) {
throw IllegalArgumentException("aw format error: methods can not have a 'mutable' modifier (at: $e)")
}
val map = methods.computeIfAbsent(e.className) { ConcurrentHashMap() }
val id = e.name + e.descriptor
if (!map.containsKey(id)) {
map[id] = e
} else {
val other = map[id]!!
if (e.isAccessGreaterThan(other)) {
classMap[id] = e
}
}
} else if ("field" == e.targetType) {
if (e.type == AccessType.EXTENDABLE) {
throw IllegalArgumentException("aw format error: fields can not have a 'extendable' modifier (at: $e)")
}
val map = fields.computeIfAbsent(e.className) { ConcurrentHashMap() }
val id = e.name + e.descriptor
if (e.type == AccessType.MUTABLE) {
mutations.computeIfAbsent(e.className) { ConcurrentHashMap() }.putIfAbsent(id, e)
} else {
if (!map.containsKey(id)) {
map[id] = e
} else {
val other = map[id]!!
if (e.isAccessGreaterThan(other)) {
classMap[id] = e
}
}
}
}
}
FileSystems.newFileSystem(input).use {
classNames.forEach { className ->
val file = it.getPath("/$className.class")
if (file.exists()) {
val reader = ClassReader(file.readBytes())
val writer = ClassWriter(0)
val mapper = AWClassVisitor(writer, classMap, fields, methods, mutations, className)
reader.accept(mapper, 0)
file.writeBytes(writer.toByteArray())
}
}
}
println(
"Applied AccessWideners (${
"%.2fs".format(
(System.currentTimeMillis() - startTime) / 1000f
)
})"
)
}
}
data class Entry(
val type: AccessType,
val targetType: String,
val className: String,
val name: String,
val descriptor: String
) {
constructor(line: List<String>) : this(
AccessType.of(line[0]),
line[1],
line[2],
line[3],
line[4]
)
fun isAccessGreaterThan(other: Entry): Boolean {
return Access.of(type.access).index < Access.of(other.type.access).index
}
}
enum class AccessType(val id: String, val access: Int) {
ACCESSIBLE("accessible", Opcodes.ACC_PUBLIC),
EXTENDABLE("extendable", Opcodes.ACC_PROTECTED),
MUTABLE("mutable", Opcodes.ACC_FINAL.inv());
companion object {
fun of(name: String): AccessType {
return entries.firstOrNull { a -> a.id == name }
?: throw IllegalArgumentException("Access type '$name' is not known. Known types: ${entries.map { it.id }} (and transitive variants)")
}
}
}
private enum class Access(val index: Int) {
PUBLIC(1), PROTECTED(2), PACKAGE_PRIVATE(3), PRIVATE(4);
companion object {
fun of(access: Int): Access {
if ((access and Opcodes.ACC_PUBLIC) != 0) {
return PUBLIC
}
if ((access and Opcodes.ACC_PROTECTED) != 0) {
return PROTECTED
}
if ((access and Opcodes.ACC_PRIVATE) != 0) {
return PRIVATE
}
return PACKAGE_PRIVATE
}
}
}
class AWClassVisitor(
visitor: ClassVisitor,
private val classMap: Map<String, Entry>,
private val fields: Map<String, Map<String, Entry>>,
private val methods: Map<String, Map<String, Entry>>,
private val mutations: Map<String, Map<String, Entry>>,
private val className: String
) : ClassVisitor(Opcodes.ASM9, visitor) {
override fun visit(
version: Int,
acc: Int,
name: String?,
signature: String?,
superName: String?,
interfaces: Array<out String>?
) {
var access = acc
val e = classMap[className]
if (e != null) {
access = access and (Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED or Opcodes.ACC_PUBLIC).inv()
access = access or e.type.access
}
if (fields.containsKey(className) || methods.containsKey(className) || mutations.containsKey(
className
)
) { // make all classes with modifications public as well
access = access and (Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED or Opcodes.ACC_PUBLIC).inv()
access = access or Opcodes.ACC_PUBLIC
}
super.visit(version, access, name, signature, superName, interfaces)
}
override fun visitField(
acc: Int,
name: String?,
descriptor: String?,
signature: String?,
value: Any?
): FieldVisitor {
var access = acc
var map = fields[className]
if (map != null) {
val e = map[name + descriptor]
if (e != null) {
access =
access and (Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED or Opcodes.ACC_PUBLIC).inv() // remove all access modifiers
access = access or e.type.access // re-add the new one
}
}
map = mutations[className]
if (map != null) {
val e = map[name + descriptor]
if (e != null) {
access = access and Opcodes.ACC_FINAL.inv() // always AccessType.MUTABLE
}
}
return super.visitField(access, name, descriptor, signature, value)
}
override fun visitMethod(
acc: Int,
name: String?,
descriptor: String?,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor {
var access = acc
val map = methods[className]
if (map != null) {
val e = map[name + descriptor]
if (e != null) {
access =
access and ((Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED or Opcodes.ACC_PUBLIC).inv())// remove all access modifiers
access = access or (e.type.access)// re-add the new one
}
}
return super.visitMethod(access, name, descriptor, signature, exceptions)
}
}

View file

@ -1,6 +1,6 @@
package org.ecorous.esnesnon.gradle.common package dev.frogmc.phytotelma.common
import org.ecorous.esnesnon.gradle.NonsenseGradlePlugin import dev.frogmc.phytotelma.PhytotelmaPlugin
import java.io.InputStream import java.io.InputStream
import java.net.URI import java.net.URI
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
@ -39,7 +39,7 @@ object CachingHttpClient {
} }
private fun getCacheFile(uri: URI): Path { private fun getCacheFile(uri: URI): Path {
val path = NonsenseGradlePlugin.nonsenseCacheDir.resolve("httpCache") val path = PhytotelmaPlugin.globalCacheDir.resolve("httpCache")
.resolve(uri.host+uri.rawPath) // Use rawPath to ensure ASCII compat (since this will be a filesystem dir) .resolve(uri.host+uri.rawPath) // Use rawPath to ensure ASCII compat (since this will be a filesystem dir)
path.createParentDirectories() path.createParentDirectories()
return path return path

View file

@ -1,4 +1,4 @@
package org.ecorous.esnesnon.gradle.common package dev.frogmc.phytotelma.common
enum class Env(val id: String, val pascalName: String) { enum class Env(val id: String, val pascalName: String) {
SERVER("server", "Server"), SERVER("server", "Server"),

View file

@ -1,4 +1,4 @@
package org.ecorous.esnesnon.gradle.common package dev.frogmc.phytotelma.common
fun sanitizeXmlValue(value: String): String { fun sanitizeXmlValue(value: String): String {
return value.replace("&", "&amp;").replace("\"", "&quot;") return value.replace("&", "&amp;").replace("\"", "&quot;")

View file

@ -0,0 +1,97 @@
package dev.frogmc.phytotelma.ext
import dev.frogmc.phytotelma.PhytotelmaPlugin
import dev.frogmc.phytotelma.VersionChecker
import dev.frogmc.phytotelma.accesswidener.AccessWidener
import dev.frogmc.phytotelma.run.RunConfigGenerator
import org.ecorous.frogmc.thyroxine.Thyroxine
import org.ecorous.frogmc.thyroxine.parser.ProguardParser
import org.ecorous.frogmc.thyroxine.provider.MojmapProvider
import org.ecorous.frogmc.thyroxine.provider.ParchmentProvider
import org.gradle.api.Project
import org.gradle.api.provider.Provider
import kotlin.io.path.notExists
fun Project.minecraft(
version: String,
parchmentVersion: String? = null
): Project { // return self to allow for chaining
if (VersionChecker.validateVersion(version)) {
println("Setting up Minecraft...")
val parchment = parchmentVersion ?: kotlin.runCatching { ParchmentProvider.findForMinecraftVersion(version) }
.getOrDefault("")
PhytotelmaPlugin.minecraftVersion = version
PhytotelmaPlugin.parchmentVersion = parchment
println("Valid version! $version")
val clientJar = VersionChecker.downloadClient(version)
val remappedJar = clientJar.resolveSibling("client-$version-remapped.jar")
PhytotelmaPlugin.remappedGameJarPath = remappedJar
println("Time to setup Minecraft!")
val applyAW = AccessWidener.needsUpdate(this)
if (remappedJar.notExists() || applyAW) {
println("Remapping the game...")
val data = kotlin.runCatching {
ProguardParser.read(
MojmapProvider.get(
version,
clientJar.resolveSibling("client-$version.txt")
).orElseThrow()
).reverse()
}.getOrNull()
val paramMappings = if (parchment.isNotEmpty()) kotlin.runCatching {
ParchmentProvider.getParchment(
version, parchment,
PhytotelmaPlugin.globalCacheDir.resolve("org/parchmentmc/parchment/$version/$parchment")
)
}.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 $version could not be found")
}
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...")
dependencies.add("implementation", "net.minecrell:terminalconsoleappender:1.2.0")
VersionChecker.getDependencies(version) {
dependencies.add("implementation", it)
}
dependencies.add("implementation", "net.minecraft:client:$version:remapped")
println("Generating run configurations...")
RunConfigGenerator.generate(this)
if (applyAW) {
project.afterEvaluate {
println("Applying AccessWideners..")
AccessWidener.apply(this, remappedJar)
}
}
println("Done!")
} else {
println("Invalid version! $version")
error("Invalid minecraft version provided: $version")
}
return this
}
fun Project.minecraft(
version: Provider<String>,
parchmentVersion: Provider<String> = provider { null }
): Project {
return minecraft(version.get(), parchmentVersion.orNull)
}
fun Project.loader(version: String) {
dependencies.add("implementation", "dev.frogmc:frogloader:$version")
}
fun Project.loader(version: Provider<String>) {
return loader(version.get())
}

View file

@ -0,0 +1,136 @@
package dev.frogmc.phytotelma.nest
import com.electronwill.nightconfig.core.Config
import com.electronwill.nightconfig.core.UnmodifiableConfig
import com.google.common.jimfs.Jimfs
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import java.nio.file.FileSystem
import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.Path
import java.util.*
import kotlin.io.path.*
object Nester {
fun run(configuration: Configuration, path: Path): Collection<NestedJar> {
val files = mutableListOf<NestedJar>()
Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix()).use { memFs ->
configuration.dependencies.filterIsInstance<ProjectDependency>().forEach { dependency ->
val project = dependency.dependencyProject
project.getTasksByName(JavaPlugin.JAR_TASK_NAME, false).map { t -> t as AbstractArchiveTask }
.forEach { task ->
val location = task.archiveFile.map {
addMetadata(
it.asFile.toPath(),
dependency.group!!,
dependency.name,
dependency.version!!,
task.archiveClassifier.orNull,
memFs
)
}.get()
path.createDirectories()
val target = path.resolve(location.fileName.toString())
Files.copy(location, target)
files.add(
NestedJar(("${dependency.group}_${dependency.name}${if (task.archiveClassifier.isPresent) "_${task.archiveClassifier}" else ""}").replace(
"\\.".toRegex(),
"_"
).lowercase(Locale.ROOT), target.absolute().toString())
)
}
}
configuration.resolvedConfiguration.firstLevelModuleDependencies.forEach { dep ->
dep.moduleArtifacts.forEach { artifact ->
val location = addMetadata(
artifact.file.toPath(),
dep.moduleGroup,
dep.moduleName,
dep.moduleVersion,
artifact.classifier,
memFs
)
path.createDirectories()
val target = path.resolve(location.fileName.toString())
Files.copy(location, target)
files.add(
NestedJar(("${dep.moduleGroup}_${dep.moduleName}${if (artifact.classifier != null) "_${artifact.classifier}" else ""}").replace(
"\\.".toRegex(),
"_"
).lowercase(Locale.ROOT), target.absolute().toString())
)
}
}
}
return files
}
private fun addMetadata(
input: Path,
group: String,
name: String,
version: String,
classifier: String?,
memFs: FileSystem
): Path {
FileSystems.newFileSystem(input).use { original ->
val toml = original.getPath("frog.mod.toml")
if (toml.notExists()) {
val tempFile = memFs.getPath(
"${
group.replace(
".",
"/"
)
}/${name}/${version}/${input.name}/${group.replace(".", "_")}_${input.name}"
)
if (tempFile.exists()) {
FileSystems.newFileSystem(tempFile).use {
if (it.getPath("frog.mod.toml").exists()){
return tempFile
}
}
}
tempFile.createParentDirectories()
input.copyTo(tempFile)
FileSystems.newFileSystem(tempFile).use {
it.getPath("frog.mod.toml").writeText(
"""
[frog]
manifest_version = "1.0.0"
[frog.mod]
id = "${
("${group}_$name${if (classifier != null) "_$classifier" else ""}").replace(
"\\.".toRegex(),
"_"
).lowercase(Locale.ROOT)
}"
name = "$name"
version = "${version.replace("(\\d+\\.\\d+\\.\\d+)(.*)".toRegex(), "$1+$2")}"
license = ""
[frog.extensions]
phytotelma.generated = true
""".trimIndent()
)
}
return tempFile
}
return input
}
}
}
class NestedJar(val id: String, val path: String){
fun toml(): UnmodifiableConfig {
val config = Config.inMemory()
config.add("id", id)
config.add("path", path)
return config
}
}

View file

@ -1,10 +1,10 @@
package org.ecorous.esnesnon.gradle.run package dev.frogmc.phytotelma.run
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.JsonObject import com.google.gson.JsonObject
import org.ecorous.esnesnon.gradle.NonsenseGradlePlugin import dev.frogmc.phytotelma.PhytotelmaPlugin
import org.ecorous.esnesnon.gradle.VersionChecker import dev.frogmc.phytotelma.VersionChecker
import org.ecorous.esnesnon.gradle.common.CachingHttpClient import dev.frogmc.phytotelma.common.CachingHttpClient
import java.net.URI import java.net.URI
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import java.nio.file.Path import java.nio.file.Path
@ -15,8 +15,8 @@ object AssetDownloader {
private const val ASSETS_URL = "https://resources.download.minecraft.net" private const val ASSETS_URL = "https://resources.download.minecraft.net"
fun download() { fun download() {
val version = NonsenseGradlePlugin.minecraftVersion val version = PhytotelmaPlugin.minecraftVersion
val path = NonsenseGradlePlugin.nonsenseCacheDir.resolve("assets") val path = PhytotelmaPlugin.globalCacheDir.resolve("assets")
val id = VersionChecker.downloadAssetIndex(version, path.resolve("indexes")) val id = VersionChecker.downloadAssetIndex(version, path.resolve("indexes"))
val index = Gson().fromJson( val index = Gson().fromJson(

View file

@ -1,4 +1,4 @@
package org.ecorous.esnesnon.gradle.run package dev.frogmc.phytotelma.run
import org.gradle.api.Project import org.gradle.api.Project
@ -12,5 +12,5 @@ interface RunConfigAdapter {
) )
/** Typically, return whether we are running within the IDE which makes use of this format. */ /** Typically, return whether we are running within the IDE which makes use of this format. */
fun shouldGenerate(): Boolean; fun shouldGenerate(): Boolean
} }

View file

@ -1,10 +1,10 @@
package org.ecorous.esnesnon.gradle.run package dev.frogmc.phytotelma.run
import org.ecorous.esnesnon.gradle.NonsenseGradlePlugin import dev.frogmc.phytotelma.PhytotelmaPlugin
import org.ecorous.esnesnon.gradle.VersionChecker import dev.frogmc.phytotelma.VersionChecker
import org.ecorous.esnesnon.gradle.common.Env import dev.frogmc.phytotelma.common.Env
import org.ecorous.esnesnon.gradle.run.adapter.EclipseAdapter import dev.frogmc.phytotelma.run.adapter.EclipseAdapter
import org.ecorous.esnesnon.gradle.run.adapter.IdeaAdapter import dev.frogmc.phytotelma.run.adapter.IdeaAdapter
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.logging.configuration.ConsoleOutput import org.gradle.api.logging.configuration.ConsoleOutput
import java.nio.file.Files import java.nio.file.Files
@ -14,7 +14,7 @@ import kotlin.io.path.createParentDirectories
import kotlin.io.path.notExists import kotlin.io.path.notExists
object RunConfigGenerator { object RunConfigGenerator {
private const val LOG4J_CONFIG_PATH = ".gradle/nonsense-gradle/log4j.xml" private const val LOG4J_CONFIG_PATH = ".gradle/phytotelma/log4j.xml"
private const val ASSET_DIR = "assets" private const val ASSET_DIR = "assets"
private val ADAPTERS = arrayOf(EclipseAdapter(), IdeaAdapter()) private val ADAPTERS = arrayOf(EclipseAdapter(), IdeaAdapter())
@ -27,15 +27,12 @@ object RunConfigGenerator {
} }
} }
val assetPath = NonsenseGradlePlugin.nonsenseCacheDir.resolve(ASSET_DIR).absolute() val assetPath = PhytotelmaPlugin.globalCacheDir.resolve(ASSET_DIR).absolute()
val assetIndexPath = assetPath.resolve("indexes") val assetIndexPath = assetPath.resolve("indexes")
if (assetIndexPath.notExists()) { if (assetIndexPath.notExists()) {
assetIndexPath.createDirectories() assetIndexPath.createDirectories()
} }
val indexId = VersionChecker.downloadAssetIndex(NonsenseGradlePlugin.minecraftVersion, assetIndexPath) val indexId = VersionChecker.downloadAssetIndex(PhytotelmaPlugin.minecraftVersion, assetIndexPath)
val runConfigPath = project.rootDir.resolve(".idea").resolve("runConfigurations")
runConfigPath.mkdirs()
for (adapter in ADAPTERS) { for (adapter in ADAPTERS) {
if (!adapter.shouldGenerate()) if (!adapter.shouldGenerate())
@ -45,21 +42,21 @@ object RunConfigGenerator {
adapter.generate( adapter.generate(
project, project,
"Minecraft ${env.pascalName}", "Minecraft ${env.pascalName}",
"org.ecorous.esnesnon.nonsense.loader.impl.launch.${env.id}.Nonsense${env.pascalName}", "dev.frogmc.frogloader.impl.launch.${env.id}.Frog${env.pascalName}",
mutableListOf( mutableListOf(
"-Xmx${project.properties.getOrDefault("nonsense.gameHeap", "2048M")}", "-Xmx${project.properties.getOrDefault("frogmc.gameHeap", "2048M")}",
"-Dnonsense.development=true", "-Dfrogmc.development=true",
"-Dnonsense.plugin.minecraft.gameJar=${NonsenseGradlePlugin.remappedGameJarPath}", "-Dfrogmc.plugin.minecraft.gameJar=${PhytotelmaPlugin.remappedGameJarPath}",
"-Dlog4j2.configurationFile=$log4jPath", "-Dlog4j2.configurationFile=$log4jPath",
"-Dlog4j2.formatMsgLookups=true" "-Dlog4j2.formatMsgLookups=true"
).apply { ).apply {
if (project.gradle.startParameter.consoleOutput != ConsoleOutput.Plain){ if (project.gradle.startParameter.consoleOutput != ConsoleOutput.Plain){
add("-Dnonsense.log.disableAnsi=false") add("-Dfrogmc.log.disableAnsi=false")
} }
}.toTypedArray(), if (env == Env.CLIENT) { }.toTypedArray(), if (env == Env.CLIENT) {
arrayOf( arrayOf(
"--assetsDir", assetPath.toString(), "--assetsDir", assetPath.toString(),
"--version", "Nonsense", "--version", "FrogMC",
"--assetIndex", indexId, "--assetIndex", indexId,
"--accessToken", "0" "--accessToken", "0"
) )

View file

@ -1,8 +1,8 @@
package org.ecorous.esnesnon.gradle.run.adapter package dev.frogmc.phytotelma.run.adapter
import org.ecorous.esnesnon.gradle.common.formatXmlList import dev.frogmc.phytotelma.common.formatXmlList
import org.ecorous.esnesnon.gradle.common.sanitizeXmlValue import dev.frogmc.phytotelma.common.sanitizeXmlValue
import org.ecorous.esnesnon.gradle.run.RunConfigAdapter import dev.frogmc.phytotelma.run.RunConfigAdapter
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.plugins.ide.eclipse.model.EclipseModel import org.gradle.plugins.ide.eclipse.model.EclipseModel
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets

View file

@ -1,8 +1,8 @@
package org.ecorous.esnesnon.gradle.run.adapter package dev.frogmc.phytotelma.run.adapter
import org.ecorous.esnesnon.gradle.common.formatXmlList import dev.frogmc.phytotelma.common.formatXmlList
import org.ecorous.esnesnon.gradle.common.sanitizeXmlValue import dev.frogmc.phytotelma.common.sanitizeXmlValue
import org.ecorous.esnesnon.gradle.run.RunConfigAdapter import dev.frogmc.phytotelma.run.RunConfigAdapter
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginExtension import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.SourceSet

View file

@ -1,8 +1,8 @@
package org.ecorous.esnesnon.gradle.run.task package dev.frogmc.phytotelma.run.task
import org.ecorous.esnesnon.gradle.NonsenseGradlePlugin import dev.frogmc.phytotelma.PhytotelmaPlugin
import org.ecorous.esnesnon.gradle.VersionChecker import dev.frogmc.phytotelma.VersionChecker
import org.ecorous.esnesnon.gradle.common.Env import dev.frogmc.phytotelma.common.Env
import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.logging.configuration.ConsoleOutput import org.gradle.api.logging.configuration.ConsoleOutput
@ -21,14 +21,14 @@ abstract class RunGameTask @Inject constructor(env: Env) : JavaExec() {
private val classpath: ConfigurableFileCollection = project.objects.fileCollection() private val classpath: ConfigurableFileCollection = project.objects.fileCollection()
init { init {
group = "nonsense" group = "frogmc"
val assetPath = NonsenseGradlePlugin.nonsenseCacheDir.resolve("assets").absolute() val assetPath = PhytotelmaPlugin.globalCacheDir.resolve("assets").absolute()
val assetIndexPath = assetPath.resolve("indexes") val assetIndexPath = assetPath.resolve("indexes")
if (assetIndexPath.notExists()) { if (assetIndexPath.notExists()) {
assetIndexPath.createDirectories() assetIndexPath.createDirectories()
} }
val indexId = VersionChecker.downloadAssetIndex(NonsenseGradlePlugin.minecraftVersion, assetIndexPath) val indexId = VersionChecker.downloadAssetIndex(PhytotelmaPlugin.minecraftVersion, assetIndexPath)
val log4jPath = project.rootDir.resolve(".gradle/nonsense-gradle/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()
this::class.java.getResourceAsStream("/log4j.xml").use { input -> this::class.java.getResourceAsStream("/log4j.xml").use { input ->
@ -40,7 +40,7 @@ abstract class RunGameTask @Inject constructor(env: Env) : JavaExec() {
if (env == Env.CLIENT) { if (env == Env.CLIENT) {
listOf( listOf(
"--assetsDir", assetPath.toString(), "--assetsDir", assetPath.toString(),
"--version", "Nonsense", "--version", "FrogMC",
"--assetIndex", indexId, "--assetIndex", indexId,
"--accessToken", "0" "--accessToken", "0"
) )
@ -53,23 +53,23 @@ abstract class RunGameTask @Inject constructor(env: Env) : JavaExec() {
).runtimeClasspath.filter { it.exists() }) ).runtimeClasspath.filter { it.exists() })
jvmArguments.addAll( jvmArguments.addAll(
"-Xmx${project.properties.getOrDefault("nonsense.gameHeap", "2048M")}", "-Xmx${project.properties.getOrDefault("frogmc.gameHeap", "2048M")}",
"-Dnonsense.development=true", "-Dfrogmc.development=true",
"-Dnonsense.plugin.minecraft.gameJar=${NonsenseGradlePlugin.remappedGameJarPath}", "-Dfrogmc.plugin.minecraft.gameJar=${PhytotelmaPlugin.remappedGameJarPath}",
"-Dlog4j2.configurationFile=$log4jPath", "-Dlog4j2.configurationFile=$log4jPath",
"-Dlog4j2.formatMsgNoLookups=true", "-Dlog4j2.formatMsgNoLookups=true",
writeArgFile() writeArgFile()
) )
if (project.gradle.startParameter.consoleOutput != ConsoleOutput.Plain){ if (project.gradle.startParameter.consoleOutput != ConsoleOutput.Plain){
jvmArguments.add("-Dnonsense.log.disableAnsi=false") jvmArguments.add("-Dfrogmc.log.disableAnsi=false")
} }
mainClass.set("org.ecorous.esnesnon.nonsense.loader.impl.launch.${env.id}.Nonsense${env.pascalName}") mainClass.set("dev.frogmc.frogloader.impl.launch.${env.id}.Frog${env.pascalName}")
} }
private fun writeArgFile(): String { private fun writeArgFile(): String {
val file = Files.createTempFile("nonsense-classpath", ".args") val file = Files.createTempFile("phytotelma-classpath", ".args")
val content = "-classpath " + classpath.files.stream() val content = "-classpath " + classpath.files.stream()
.map { it.absolutePath } .map { it.absolutePath }

View file

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

View file

@ -1,148 +0,0 @@
package org.ecorous.esnesnon.gradle
import net.fabricmc.fernflower.api.IFabricJavadocProvider
import org.ecorous.esnesnon.gradle.common.Env
import org.ecorous.esnesnon.gradle.run.AssetDownloader
import org.ecorous.esnesnon.gradle.run.RunConfigGenerator
import org.ecorous.esnesnon.gradle.run.task.RunGameTask
import org.ecorous.esnesnon.gradle.vineflower.ParchmentJavadocProvider
import org.ecorous.esnesnon.nonsense_remapper.provider.ParchmentProvider
import org.gradle.api.Plugin
import org.gradle.api.Project
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 NonsenseGradlePlugin : Plugin<Project> {
override fun apply(project: Project) {
println("> Applying Nonsense Gradle Plugin")
nonsenseCacheDir = project.gradle.gradleUserHomeDir.resolve("caches/nonsense-gradle/").toPath()
nonsenseCacheDir.createDirectories()
project.apply {
mapOf("plugin" to "java-library")
mapOf("plugin" to "eclipse")
mapOf("plugin" to "idea")
mapOf("plugin" to "maven-publish")
}
project.repositories.apply {
maven {
it.name = "Esnesnon Releases"
it.url = URI.create("https://maven-esnesnon.ecorous.org/releases")
}
maven {
it.name = "Esnesnon Snapshots"
it.url = URI.create("https://maven-esnesnon.ecorous.org/snapshots")
}
maven {
it.name = "FabricMC"
it.url = URI.create("https://maven.fabricmc.net")
}
maven {
it.name = "Minecraft/Local"
it.url = project.gradle.gradleUserHomeDir.resolve("caches/nonsense-gradle/").toURI()
}
maven {
it.name = "Minecraft Libraries"
it.url = URI.create("https://libraries.minecraft.net/")
}
}
project.repositories.mavenCentral()
project.task("genSources").apply {
group = "nonsense"
doFirst {
val fileName = remappedGameJarPath.fileName.toString()
val output =
remappedGameJarPath.resolveSibling(fileName.substring(0, fileName.length - 13) + "-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(
minecraftVersion,
parchmentVersion,
project.gradle.gradleUserHomeDir.resolve("nonsense-gradle/org/parchmentmc/parchment/$minecraftVersion/$parchmentVersion/")
.toPath()
)
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 "warn",
IFernflowerPreferences.THREADS to Runtime.getRuntime().availableProcessors().toString(),
IFernflowerPreferences.INDENT_STRING to "\t"
)
)
val decomp = Fernflower(
SingleFileSaver(output.toFile()),
options, logger
)
decomp.addSource(remappedGameJarPath.toFile())
decomp.decompileContext()
}
}
project.task("genRunConfigs").apply {
group = "nonsense"
doFirst {
RunConfigGenerator.generate(project)
}
}
project.tasks.register("runClient", RunGameTask::class.java, Env.CLIENT)
project.tasks.register("runServer", RunGameTask::class.java, Env.SERVER)
project.task("downloadAssets").apply {
group = "nonsense"
doFirst {
AssetDownloader.download()
}
}
// TODO mod relocation/renaming: decide on mod file extension
/*project.tasks.getByName("jar").actions.addLast {
it.outputs.files.forEach {file ->
val output = file.toPath().parent.resolveSibling("nonsense-mods")
output.createDirectories()
if (file.name.endsWith(".jar") && !(file.name.contains("-dev.") || file.name.contains("-sources."))){
Files.copy(file.toPath(), output.resolve(file.name.substring(0, file.name.length-4)+".nonsense"))
}
}
}*/
val includeConfiguration = project.configurations.create("include").apply {
extendsFrom(project.configurations.getByName("implementation"))
}
project.tasks.getByName("jar").actions.addLast {
it.outputs.files(includeConfiguration.artifacts.files)
}
}
companion object {
lateinit var nonsenseCacheDir: Path
lateinit var minecraftVersion: String
lateinit var remappedGameJarPath: Path
lateinit var parchmentVersion: String
}
}

View file

@ -1,61 +0,0 @@
package org.ecorous.esnesnon.gradle.ext
import org.ecorous.esnesnon.gradle.NonsenseGradlePlugin
import org.ecorous.esnesnon.gradle.VersionChecker
import org.ecorous.esnesnon.gradle.run.RunConfigGenerator
import org.ecorous.esnesnon.nonsense_remapper.NonsenseRemapper
import org.ecorous.esnesnon.nonsense_remapper.parser.ProguardParser
import org.ecorous.esnesnon.nonsense_remapper.provider.MojmapProvider
import org.ecorous.esnesnon.nonsense_remapper.provider.ParchmentProvider
import org.gradle.api.Project
import kotlin.io.path.notExists
fun Project.minecraft(
version: String,
parchmentVersion: String = ParchmentProvider.findForMinecraftVersion(version)
): Project { // return self to allow for chaining
if (VersionChecker.validateVersion(version)) {
NonsenseGradlePlugin.minecraftVersion = version
NonsenseGradlePlugin.parchmentVersion = parchmentVersion
println("Valid version! $version")
val clientData = VersionChecker.fetchClientDownload(version)
println("Client data: ${clientData.url}")
// download client data
println("Downloading client...")
val clientJar = VersionChecker.downloadClient(version)
println("Downloaded client!")
val remappedJar = clientJar.resolveSibling("client-$version-remapped.jar")
NonsenseGradlePlugin.remappedGameJarPath = remappedJar
println("Time to setup Minecraft!")
if (remappedJar.notExists()) {
println("Remapping the game...")
val data = ProguardParser.read(MojmapProvider.get(version, clientJar.resolveSibling("client-$version.txt")).orElseThrow()).reverse()
val paramMappings = ParchmentProvider.getParchment(
version, parchmentVersion,
NonsenseGradlePlugin.nonsenseCacheDir.resolve("org/parchmentmc/parchment/$version/$parchmentVersion")
)
NonsenseRemapper.remap(data, clientJar, remappedJar, true, paramMappings)
}
println("Adding dependencies...")
//configurations.getByName("development").extendsFrom(configurations.getByName("implementation"))
dependencies.add("implementation","net.minecrell:terminalconsoleappender:1.2.0")
VersionChecker.getDependencies(version) {
dependencies.add("implementation", it)
}
dependencies.add("implementation", "net.minecraft:client:$version:remapped")
println("Generating run configurations...")
RunConfigGenerator.generate(this)
println("Done!")
} else {
println("Invalid version! $version")
error("Invalid minecraft version provided: $version")
}
return this
}
fun Project.loader(version: String){
dependencies.add("implementation", "org.ecorous.esnesnon:nonsense-loader:$version")
// TODO how can we make this version not have to be hard-coded?
dependencies.add("annotationProcessor", "net.fabricmc:sponge-mixin:0.13.4+mixin.0.8.5")
}

View file

@ -11,7 +11,7 @@
<RegexFilter regex="^Couldn't connect to realms$" onMatch="DENY" onMismatch="NEUTRAL"/> <RegexFilter regex="^Couldn't connect to realms$" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters> </Filters>
<PatternLayout> <PatternLayout>
<LoggerNamePatternSelector defaultPattern="%style{[%d{HH:mm:ss}]}{blue} %highlight{[%t/%level]}{FATAL=red, ERROR=red, WARN=yellow, INFO=green, DEBUG=green, TRACE=blue} %style{(%logger{1})}{cyan} %highlight{%msg%n}{FATAL=red, ERROR=red, WARN=normal, INFO=normal, DEBUG=normal, TRACE=normal}" disableAnsi="${sys:nonsense.log.disableAnsi:-true}"> <LoggerNamePatternSelector defaultPattern="%style{[%d{HH:mm:ss}]}{blue} %highlight{[%t/%level]}{FATAL=red, ERROR=red, WARN=yellow, INFO=green, DEBUG=green, TRACE=blue} %style{(%logger{1})}{cyan} %highlight{%msg%n}{FATAL=red, ERROR=red, WARN=normal, INFO=normal, DEBUG=normal, TRACE=normal}" disableAnsi="${sys:frogmc.log.disableAnsi:-true}">
<!-- Dont show the logger name for minecraft classes--> <!-- Dont show the logger name for minecraft classes-->
<PatternMatch key="net.minecraft.,com.mojang." pattern="%style{[%d{HH:mm:ss}]}{blue} %highlight{[%t/%level]}{FATAL=red, ERROR=red, WARN=yellow, INFO=green, DEBUG=green, TRACE=blue} %style{(Minecraft)}{cyan} %highlight{%msg{nolookups}%n}{FATAL=red, ERROR=red, WARN=normal, INFO=normal, DEBUG=normal, TRACE=normal}"/> <PatternMatch key="net.minecraft.,com.mojang." pattern="%style{[%d{HH:mm:ss}]}{blue} %highlight{[%t/%level]}{FATAL=red, ERROR=red, WARN=yellow, INFO=green, DEBUG=green, TRACE=blue} %style{(Minecraft)}{cyan} %highlight{%msg{nolookups}%n}{FATAL=red, ERROR=red, WARN=normal, INFO=normal, DEBUG=normal, TRACE=normal}"/>
</LoggerNamePatternSelector> </LoggerNamePatternSelector>
@ -57,12 +57,12 @@
</RollingRandomAccessFile> </RollingRandomAccessFile>
</Appenders> </Appenders>
<Loggers> <Loggers>
<Logger level="${sys:nonsense.log.level:-info}" name="net.minecraft"/> <Logger level="${sys:frogmc.log.level:-info}" name="net.minecraft"/>
<Root level="all"> <Root level="all">
<AppenderRef ref="DebugFile" level="${sys:nonsense.log.debug.level:-debug}"/> <AppenderRef ref="DebugFile" level="${sys:frogmc.log.debug.level:-debug}"/>
<AppenderRef ref="SysOut" level="${sys:nonsense.log.level:-info}"/> <AppenderRef ref="SysOut" level="${sys:frogmc.log.level:-info}"/>
<AppenderRef ref="LatestFile" level="${sys:nonsense.log.level:-info}"/> <AppenderRef ref="LatestFile" level="${sys:frogmc.log.level:-info}"/>
<AppenderRef ref="ServerGuiConsole" level="${sys:nonsense.log.level:-info}"/> <AppenderRef ref="ServerGuiConsole" level="${sys:frogmc.log.level:-info}"/>
</Root> </Root>
</Loggers> </Loggers>
</Configuration> </Configuration>