diff --git a/build.gradle.kts b/build.gradle.kts index e219083..2ed329e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - kotlin("plugin.serialization") version "1.8.10" + alias(libs.plugins.kotlin.serialization) `kotlin-dsl` `maven-publish` } @@ -20,14 +20,10 @@ repositories { } dependencies { - // OW2 ASM - implementation(libs.asm) - implementation(libs.asmCommons) - - // Kotlinx.serialization JSON library - implementation(libs.kxSerJSON) - implementation(libs.mappingsUtil) - implementation(libs.weaveInternals) + implementation(libs.bundles.asm) + implementation(libs.kxser.json) + implementation(libs.mappings) + implementation(libs.weave.internals) } tasks.withType>() diff --git a/gradle.properties b/gradle.properties index 351455f..4665573 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,4 +2,4 @@ org.gradle.jvmargs = -Xmx2G # Project properties projectName = Weave-Gradle projectGroup = net.weavemc.gradle -projectVersion = 1.0.0-PRE +projectVersion = 1.0.0-b.3 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7751360..61052ab 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,15 +1,22 @@ [versions] -asm = "9.4" # https://asm.ow2.io/versions.html +asm = "9.7" # https://asm.ow2.io/versions.html junit = "5.8.1" # https://github.com/junit-team/junit5/releases kxSer = "1.5.1" # https://github.com/Kotlin/kotlinx.serialization/releases -mappingsUtil = "0.1.3" +mappingsUtil = "0.1.6" +kotlin = "1.9.22" [libraries] asm = { module = "org.ow2.asm:asm", version.ref = "asm" } -asmTree = { module = "org.ow2.asm:asm-tree", version.ref = "asm" } -asmCommons = { module = "org.ow2.asm:asm-commons", version.ref = "asm" } -junitApi = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } -junitEngine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" } -kxSerJSON = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kxSer" } -mappingsUtil = { module = "io.github.770grappenmaker:mappings-util", version.ref = "mappingsUtil" } -weaveInternals = { module = "net.weavemc:internals", version = "1.0.0-PRE" } +asm-tree = { module = "org.ow2.asm:asm-tree", version.ref = "asm" } +asm-commons = { module = "org.ow2.asm:asm-commons", version.ref = "asm" } +junit-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } +junit-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" } +kxser-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kxSer" } +mappings = { module = "io.github.770grappenmaker:mappings-util", version.ref = "mappingsUtil" } +weave-internals = { module = "net.weavemc:internals", version = "1.0.0-b.3" } + +[plugins] +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } + +[bundles] +asm = [ "asm", "asm-commons", "asm-tree" ] diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 249e583..e644113 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 15de902..a441313 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index a69d9cb..b740cf1 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,11 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +131,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index f127cfd..25da30d 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -42,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/src/main/kotlin/net/weavemc/gradle/WeaveGradle.kt b/src/main/kotlin/net/weavemc/gradle/WeaveGradle.kt index d839087..eab2e7a 100644 --- a/src/main/kotlin/net/weavemc/gradle/WeaveGradle.kt +++ b/src/main/kotlin/net/weavemc/gradle/WeaveGradle.kt @@ -1,19 +1,24 @@ package net.weavemc.gradle -import com.grappenmaker.mappings.remapJar import kotlinx.serialization.encodeToString import net.weavemc.gradle.configuration.WeaveMinecraftExtension import net.weavemc.gradle.configuration.pullDeps import net.weavemc.gradle.util.Constants +import net.weavemc.gradle.util.localCache +import net.weavemc.gradle.util.minecraftJarCache +import net.weavemc.internals.MappingsRetrieval import net.weavemc.internals.MinecraftVersion +import org.gradle.api.DefaultTask import org.gradle.api.GradleException import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.plugins.JavaPlugin -import org.gradle.kotlin.dsl.apply -import org.gradle.kotlin.dsl.create -import org.gradle.kotlin.dsl.withType -import org.gradle.language.jvm.tasks.ProcessResources +import org.gradle.api.tasks.Delete +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.SourceSetContainer +import org.gradle.api.tasks.TaskAction +import org.gradle.api.tasks.bundling.Jar +import org.gradle.kotlin.dsl.* /** * Gradle build system plugin used to automate the setup of a modding environment. @@ -43,12 +48,30 @@ class WeaveGradle : Plugin { pullDeps(version, ext.configuration.get().namespace) } - project.tasks.withType().configureEach { - outputs.upToDateWhen { false } - doLast { - val config = ext.configuration.get().copy(compiledFor = ext.version.get().versionName) - destinationDir.resolve("weave.mod.json").writeText(Constants.JSON.encodeToString(config)) - } + val writeModConfig = project.tasks.register("writeModConfig") + + project.tasks.named("jar") { + dependsOn(writeModConfig) + from(writeModConfig) + } + + project.tasks.named("clean") { delete(writeModConfig) } + } + + open class WriteModConfig : DefaultTask() { + @get:OutputFile + val output = project.localCache().map { it.file("weave.mod.json") } + + @TaskAction + fun run() { + val config = project.extensions.getByName("minecraft").configuration.get() + output.get().asFile.writeText(Constants.JSON.encodeToString(config)) } } } + +fun MinecraftVersion.loadMergedMappings() = + MappingsRetrieval.loadMergedWeaveMappings(versionName, minecraftJarCache).mappings + + +val Project.sourceSets get() = extensions.getByName("sourceSets") diff --git a/src/main/kotlin/net/weavemc/gradle/configuration/DependencyManager.kt b/src/main/kotlin/net/weavemc/gradle/configuration/DependencyManager.kt index b739cc9..149def9 100644 --- a/src/main/kotlin/net/weavemc/gradle/configuration/DependencyManager.kt +++ b/src/main/kotlin/net/weavemc/gradle/configuration/DependencyManager.kt @@ -1,14 +1,16 @@ package net.weavemc.gradle.configuration -import com.grappenmaker.mappings.remapJar +import com.grappenmaker.mappings.* import kotlinx.serialization.Serializable -import net.weavemc.gradle.util.Constants -import net.weavemc.gradle.util.DownloadUtil -import net.weavemc.gradle.util.mappedJarCache -import net.weavemc.gradle.util.minecraftJarCache -import net.weavemc.internals.MappingsRetrieval +import net.weavemc.gradle.loadMergedMappings +import net.weavemc.gradle.sourceSets +import net.weavemc.gradle.util.* import net.weavemc.internals.MinecraftVersion import org.gradle.api.Project +import org.gradle.api.logging.LogLevel +import org.gradle.kotlin.dsl.get +import org.objectweb.asm.ClassVisitor +import java.io.File import java.net.URL private inline fun String?.decodeJSON() = @@ -42,19 +44,54 @@ private fun Project.addMinecraftAssets(version: MinecraftVersion) { .forEach { dependencies.add("compileOnly", it.name) } } +private fun Project.retrieveWideners(): List { + // Cursed code + val ext = extensions["minecraft"] as WeaveMinecraftExtension + val wideners = ext.configuration.get().accessWideners.toHashSet() + val widenerFiles = mutableListOf() + + a@ for (set in project.sourceSets) { + for (dir in set.resources.sourceDirectories) { + wideners.removeIf { left -> + val f = dir.resolve(left) + f.exists().also { if (it) widenerFiles += f } + } + + if (wideners.isEmpty()) break@a + } + } + + require(wideners.isEmpty()) { "Could not resolve access wideners $wideners! Double-check if the file exists" } + return widenerFiles +} + +private fun File.loadWidener() = loadAccessWidener(readText().trim().lines()) + private fun Project.addMappedMinecraft(version: MinecraftVersion, namespace: String) = runCatching { - val mapped = version.mappedJarCache(namespace) - if (!mapped.exists()) { - val fullMappings = version.loadMergedMappings() - remapJar(fullMappings, version.minecraftJarCache, mapped, to = namespace) + val fullMappings = version.loadMergedMappings() + val allWideners = retrieveWideners().map { it.loadWidener().remap(fullMappings, namespace) } + val joinedWideners = allWideners.takeIf { it.isNotEmpty() }?.join() + val joinedFile = localGradleCache().file("joined.accesswidener").asFile + val mapped = mappedJarCache(namespace, version) + + if ( + // should be able to simplify this, right? + !mapped.exists() || + (allWideners.isNotEmpty() xor joinedFile.exists()) || + (allWideners.isNotEmpty() && joinedFile.loadWidener() != joinedWideners) + ) { + logger.log(LogLevel.LIFECYCLE, "Remapping vanilla jar to $namespace for version ${version.versionName}") + mapped.parentFile.mkdirs() // TODO use NIO api? + + val visitor = joinedWideners?.toTree()?.let { { parent: ClassVisitor -> AccessWidenerVisitor(parent, it) } } + remapJar(fullMappings, version.minecraftJarCache, mapped, to = namespace, visitor = visitor) } + joinedWideners?.write()?.let { joinedFile.writeText(it.joinToString("\n")) } ?: joinedFile.delete() + dependencies.add("compileOnly", project.files(mapped)) }.onFailure { it.printStackTrace() } -fun MinecraftVersion.loadMergedMappings() = - MappingsRetrieval.loadMergedWeaveMappings(versionName, minecraftJarCache).mappings - @Serializable private data class VersionManifest(val versions: List) diff --git a/src/main/kotlin/net/weavemc/gradle/configuration/WeaveMinecraftExtension.kt b/src/main/kotlin/net/weavemc/gradle/configuration/WeaveMinecraftExtension.kt index a958078..c677871 100644 --- a/src/main/kotlin/net/weavemc/gradle/configuration/WeaveMinecraftExtension.kt +++ b/src/main/kotlin/net/weavemc/gradle/configuration/WeaveMinecraftExtension.kt @@ -31,6 +31,8 @@ class ConfigurationBuilder { var namespace by mutatingProperty(backing.namespace) { copy(namespace = it) } var dependencies by mutatingProperty(backing.dependencies) { copy(dependencies = it) } var entryPoints by mutatingProperty(backing.entryPoints) { copy(entryPoints = it) } + var tweakers by mutatingProperty(backing.tweakers) { copy(tweakers = it) } + var accessWideners by mutatingProperty(backing.accessWideners) { copy(accessWideners = it) } var hooks by mutatingProperty(backing.hooks) { copy(hooks = it) } var mixinConfigs by mutatingProperty(backing.mixinConfigs) { copy(mixinConfigs = it) } diff --git a/src/main/kotlin/net/weavemc/gradle/util/Constants.kt b/src/main/kotlin/net/weavemc/gradle/util/Constants.kt index 6e956c3..7467ebf 100644 --- a/src/main/kotlin/net/weavemc/gradle/util/Constants.kt +++ b/src/main/kotlin/net/weavemc/gradle/util/Constants.kt @@ -2,6 +2,7 @@ package net.weavemc.gradle.util import kotlinx.serialization.json.Json import net.weavemc.internals.MinecraftVersion +import org.gradle.api.Project import java.io.File /** @@ -31,5 +32,9 @@ object Constants { val MinecraftVersion.cacheDirectory get() = Constants.CACHE_DIR.resolve("cache-${versionName}").also { it.mkdirs() } val MinecraftVersion.minecraftJarCache get() = cacheDirectory.resolve("client.jar") -fun MinecraftVersion.mappedJarCache(namespace: String) = - minecraftJarCache.resolveSibling("${minecraftJarCache.nameWithoutExtension}-$namespace.jar") + +fun Project.mappedJarCache(namespace: String, version: MinecraftVersion) = + localGradleCache().file("${version.minecraftJarCache.nameWithoutExtension}-$namespace.jar").asFile + +fun Project.localGradleCache() = layout.projectDirectory.dir(".gradle").dir("weave") +fun Project.localCache() = layout.buildDirectory.dir("weave")