Skip to content

Commit

Permalink
Make most things not use coroutines, improve component metadata rules…
Browse files Browse the repository at this point in the history
…, fix access wideners, improve run configuration argument handling
  • Loading branch information
MsRandom committed Nov 23, 2024
1 parent f1f6b09 commit ea6a4f9
Show file tree
Hide file tree
Showing 55 changed files with 893 additions and 924 deletions.
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ childProjects.values.forEach { project ->

tasks.compileKotlin {
kotlinOptions {
jvmTarget = "11"

freeCompilerArgs =
listOf(
"-opt-in=kotlin.ExperimentalStdlibApi",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package net.msrandom.minecraftcodev.accesswidener

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import net.fabricmc.accesswidener.AccessWidenerReader
Expand All @@ -28,7 +26,7 @@ class ZipAccessModifierResolutionRuleHandler :
AccessModifierResolutionRule

class AccessWidenerResolutionRule : AccessModifierResolutionRule {
override suspend fun load(path: Path, extension: String, data: AccessModifierResolutionData): Boolean {
override fun load(path: Path, extension: String, data: AccessModifierResolutionData): Boolean {
if (extension.lowercase() != "accesswidener") {
return false
}
Expand All @@ -44,7 +42,7 @@ class AccessWidenerResolutionRule : AccessModifierResolutionRule {
}

class AccessModifierJsonResolutionRule : AccessModifierResolutionRule {
override suspend fun load(path: Path, extension: String, data: AccessModifierResolutionData): Boolean {
override fun load(path: Path, extension: String, data: AccessModifierResolutionData): Boolean {
if (extension.lowercase() != "json") {
return false
}
Expand All @@ -61,22 +59,20 @@ class AccessModifierJsonResolutionRule : AccessModifierResolutionRule {

}

val mappingResolutionRules = serviceLoader<ZipAccessModifierResolutionRuleHandler>()
val accessModifierResolutionRules = serviceLoader<AccessModifierResolutionRule>()

suspend fun loadAccessWideners(
fun loadAccessWideners(
files: FileCollection,
namespace: String?,
): AccessModifiers {
val widener = AccessModifiers(false, namespace)

val data = AccessModifierResolutionData(widener, namespace)

withContext(Dispatchers.IO) {
for (file in files) {
for (rule in mappingResolutionRules) {
if (rule.load(file.toPath(), file.extension, data)) {
break
}
for (file in files) {
for (rule in accessModifierResolutionRules) {
if (rule.load(file.toPath(), file.extension, data)) {
break
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package net.msrandom.minecraftcodev.accesswidener

import kotlinx.coroutines.runBlocking
import net.msrandom.minecraftcodev.core.resolve.isCodevGeneratedMinecraftJar
import net.msrandom.minecraftcodev.core.utils.toPath
import net.msrandom.minecraftcodev.core.utils.walk
Expand Down Expand Up @@ -37,13 +36,13 @@ abstract class AccessWiden : TransformAction<AccessWiden.Parameters> {
@PathSensitive(PathSensitivity.NONE)
get

override fun transform(outputs: TransformOutputs) = runBlocking {
override fun transform(outputs: TransformOutputs) {
val input = inputFile.get().toPath()

if (parameters.accessWideners.isEmpty || !isCodevGeneratedMinecraftJar(input)) {
outputs.file(inputFile)

return@runBlocking
return
}

println("Access widening $input")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package net.msrandom.minecraftcodev.core

import kotlinx.coroutines.runBlocking
import net.msrandom.minecraftcodev.core.resolve.MinecraftVersionList
import net.msrandom.minecraftcodev.core.resolve.getClientDependencies
import net.msrandom.minecraftcodev.core.resolve.setupCommon
Expand All @@ -10,15 +9,14 @@ import org.gradle.api.artifacts.ComponentMetadataRule
import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.Category
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Provider
import java.io.File
import java.nio.file.Path
import javax.inject.Inject

const val VERSION_MANIFEST_URL = "https://launchermeta.mojang.com/mc/game/version_manifest_v2.json"

// TODO: Caching
suspend fun getVersionList(
fun getVersionList(
cacheDirectory: Path,
url: String = VERSION_MANIFEST_URL,
isOffline: Boolean,
Expand All @@ -27,13 +25,14 @@ suspend fun getVersionList(
@CacheableRule
abstract class MinecraftComponentMetadataRule<T : Any> @Inject constructor(
private val cacheDirectory: File,
private val version: Provider<String>,
private val versionManifestUrl: Provider<String>,
private val isOffline: Provider<Boolean>,
private val version: String,
private val versionManifestUrl: String,
private val isOffline: Boolean,
private val client: Boolean,
private val variantName: String,
private val attribute: Attribute<T>,
private val attributeValue: T,
private val commonAttributeValue: T,
private val clientAttributeValue: T,
) : ComponentMetadataRule {
abstract val objectFactory: ObjectFactory
@Inject get
Expand All @@ -43,18 +42,30 @@ abstract class MinecraftComponentMetadataRule<T : Any> @Inject constructor(
it.attributes { attributes ->
attributes
.attribute(Category.CATEGORY_ATTRIBUTE, objectFactory.named(Category::class.java, Category.REGULAR_PLATFORM))
.attribute(attribute, attributeValue)
.attribute(attribute, clientAttributeValue)
}

it.withDependencies {
runBlocking {
val versionMetadata = getVersionList(cacheDirectory.toPath(), versionManifestUrl.get(), isOffline.get()).version(version.get())
it.withCapabilities { capabilities ->
capabilities.addCapability("net.minecraft.dependencies", if (client) "client" else "server", "1.0.0")
}

it.withDependencies { dependencies ->
val versionMetadata = getVersionList(cacheDirectory.toPath(), versionManifestUrl, isOffline).version(version)

if (client) {
val id = context.details.id

getClientDependencies(cacheDirectory.toPath(), versionMetadata, isOffline).forEach(dependencies::add)

if (client) {
setupCommon(cacheDirectory.toPath(), versionMetadata, isOffline.get())
} else {
getClientDependencies(cacheDirectory.toPath(), versionMetadata, isOffline.get())
dependencies.add("${id.group}:${id.name}:${id.version}") { commonDependency ->
commonDependency.attributes { attributes ->
attributes
.attribute(Category.CATEGORY_ATTRIBUTE, objectFactory.named(Category::class.java, Category.REGULAR_PLATFORM))
.attribute(attribute, commonAttributeValue)
}
}
} else {
setupCommon(cacheDirectory.toPath(), versionMetadata, isOffline).forEach(dependencies::add)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package net.msrandom.minecraftcodev.core

import net.msrandom.minecraftcodev.core.resolve.MinecraftVersionMetadata
import org.gradle.api.artifacts.CacheableRule
import org.gradle.api.artifacts.ComponentMetadataContext
import org.gradle.api.artifacts.ComponentMetadataRule
import org.gradle.api.model.ObjectFactory
import org.gradle.nativeplatform.OperatingSystemFamily
import java.io.File
import javax.inject.Inject

@CacheableRule
abstract class MinecraftDependenciesOperatingSystemMetadataRule @Inject constructor(
private val cacheDirectory: File,
private val versions: List<String>,
private val versionManifestUrl: String,
private val isOffline: Boolean,
) : ComponentMetadataRule {
abstract val objectFactory: ObjectFactory
@Inject get

override fun execute(context: ComponentMetadataContext) {
val versionList = getVersionList(cacheDirectory.toPath(), versionManifestUrl, isOffline)

val id = context.details.id

val libraries = versions.asSequence().flatMap {
versionList.version(it).libraries
}.filter {
it.name.group == id.group && it.name.module == id.name && it.name.version == id.version
}

val classifierOperatingSystems = libraries.flatMap {
buildList {
if (it.name.classifier != null) {
val osName = it.rules.firstOrNull {
it.action == MinecraftVersionMetadata.RuleAction.Allow
}?.os?.name

if (osName != null) {
add(osName to it.downloads.artifact!!.path.substringAfterLast('/'))
}
}

addAll(it.natives.entries.map { (key, value) ->
key to it.downloads.classifiers.getValue(value).path.substringAfterLast('/')
})
}
}

for ((operatingSystem, file) in classifierOperatingSystems.distinctBy { (operatingSystem, _) -> operatingSystem }) {
context.details.addVariant(operatingSystem, "runtime") { variant ->
variant.attributes { attribute ->
attribute.attribute(
OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE,
objectFactory.named(OperatingSystemFamily::class.java, operatingSystem),
)
}

variant.withFiles { files ->
files.addFile(file)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,25 @@ import kotlinx.serialization.encoding.Encoder

@Serializable(ModuleLibraryIdentifier.IdentifierSerializer::class)
data class ModuleLibraryIdentifier(val group: String, val module: String, val version: String, val classifier: String?) {
override fun toString() = "$group:$module:$version${classifier?.let { ":$it" }.orEmpty()}"
override fun toString() = buildString {
append(group)
append(':')

append(module)
append(':')

append(version)

if (classifier != null) {
append(':')
append(classifier)
}
}

companion object {
fun load(notation: String) = notation.split(":").let { ModuleLibraryIdentifier(it[0], it[1], it[2], it.getOrNull(3)) }
fun load(notation: String) = notation.split(":").let {
ModuleLibraryIdentifier(it[0], it[1], it[2], it.getOrNull(3))
}
}

@Serializer(ModuleLibraryIdentifier::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,23 @@ open class ResolutionData<T>(
)

fun interface ResolutionRule<T : ResolutionData<*>> {
suspend fun load(
fun load(
path: Path,
extension: String,
data: T,
): Boolean
}

fun interface ZipResolutionRule<T : ResolutionData<*>> {
suspend fun load(
fun load(
path: Path,
fileSystem: FileSystem,
isJar: Boolean,
data: T,
): Boolean
}

suspend fun <T : ResolutionData<*>> handleZipRules(
fun <T : ResolutionData<*>> handleZipRules(
zipResolutionRules: Iterable<ZipResolutionRule<T>>,
path: Path,
extension: String,
Expand All @@ -56,7 +56,7 @@ suspend fun <T : ResolutionData<*>> handleZipRules(
abstract class ZipResolutionRuleHandler<T : ResolutionData<*>, U : ZipResolutionRule<T>>(
private val zipResolutionRules: Iterable<U>,
) : ResolutionRule<T> {
override suspend fun load(
override fun load(
path: Path,
extension: String,
data: T,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@ import net.msrandom.minecraftcodev.core.utils.zipFileSystem
import java.nio.file.Path
import java.util.jar.JarFile
import java.util.jar.Manifest
import kotlin.io.path.createDirectories
import kotlin.io.path.exists
import kotlin.io.path.inputStream
import kotlin.io.path.outputStream
import kotlin.io.path.*

private const val CODEV_MINECRAFT_MARKER = "Codev-Minecraft-Marker"

suspend fun addMinecraftMarker(path: Path) {
fun addMinecraftMarker(path: Path) {
zipFileSystem(path).use { fs ->
val manifestPath = fs.getPath(JarFile.MANIFEST_NAME)

Expand All @@ -29,8 +26,14 @@ suspend fun addMinecraftMarker(path: Path) {
}
}

suspend fun isCodevGeneratedMinecraftJar(path: Path) = zipFileSystem(path).use { fs ->
val manifest = fs.getPath(JarFile.MANIFEST_NAME).inputStream().use(::Manifest)
fun isCodevGeneratedMinecraftJar(path: Path) = zipFileSystem(path).use { fs ->
val manifestPath = fs.getPath(JarFile.MANIFEST_NAME)

if (manifestPath.notExists()) {
return@use false
}

val manifest = manifestPath.inputStream().use(::Manifest)

manifest.mainAttributes.getValue(CODEV_MINECRAFT_MARKER).toBoolean()
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,7 @@ class MinecraftVersionList(private val cacheDirectory: Path, manifest: Minecraft
private val versions = manifest.versions.associateBy(MinecraftVersionManifest.VersionInfo::id)
private val versionInfoCache = hashMapOf<String, MinecraftVersionMetadata>()

suspend fun version(version: String): MinecraftVersionMetadata {
val it = versionInfoCache[version]

if (it != null) {
return it
}

fun version(version: String) = versionInfoCache.computeIfAbsent(version) {
val versionInfo = versions[version] ?: throw InvalidUserCodeException("Minecraft version $version not found")

val path =
Expand All @@ -33,15 +27,11 @@ class MinecraftVersionList(private val cacheDirectory: Path, manifest: Minecraft
isOffline,
)

val metadata: MinecraftVersionMetadata = path.inputStream().use(json::decodeFromStream)

versionInfoCache[version] = metadata

return metadata
path.inputStream().use(json::decodeFromStream)
}

companion object {
suspend fun load(
fun load(
cacheDirectory: Path,
metadataUrl: String,
isOffline: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.json.*
import net.msrandom.minecraftcodev.core.ModuleLibraryIdentifier
import net.msrandom.minecraftcodev.core.URISerializer
import net.msrandom.minecraftcodev.core.utils.extension
import org.gradle.api.Project
Expand Down Expand Up @@ -83,7 +84,7 @@ data class MinecraftVersionMetadata(
data class Library(
val downloads: LibraryDownloads,
val extract: ExtractData? = null,
val name: String,
val name: ModuleLibraryIdentifier,
val natives: Map<String, String> = emptyMap(),
val rules: List<Rule> = emptyList(),
) {
Expand Down
Loading

0 comments on commit ea6a4f9

Please sign in to comment.