From fbbee65c8485378565fff59b65eae7b2a8533756 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Thu, 17 Sep 2026 14:52:51 +0100 Subject: [PATCH] Update MinecraftExec to work with config cache - Switch withFileContents/withFileSource to be normal inputs. - Download complementary shaders from Maven instead. --- .../cc/tweaked/gradle/CCTweakedExtension.kt | 43 +--------- .../kotlin/cc/tweaked/gradle/Extensions.kt | 8 +- .../kotlin/cc/tweaked/gradle/MinecraftExec.kt | 81 ++++++++++++------- gradle/libs.versions.toml | 2 + projects/common-api/build.gradle.kts | 12 --- projects/fabric/build.gradle.kts | 18 ++--- 6 files changed, 71 insertions(+), 93 deletions(-) diff --git a/build-logic/base/src/main/kotlin/cc/tweaked/gradle/CCTweakedExtension.kt b/build-logic/base/src/main/kotlin/cc/tweaked/gradle/CCTweakedExtension.kt index 3a5438117..a46aae018 100644 --- a/build-logic/base/src/main/kotlin/cc/tweaked/gradle/CCTweakedExtension.kt +++ b/build-logic/base/src/main/kotlin/cc/tweaked/gradle/CCTweakedExtension.kt @@ -19,9 +19,7 @@ import org.gradle.process.JavaForkOptions import org.gradle.testing.jacoco.plugins.JacocoPluginExtension import org.gradle.testing.jacoco.plugins.JacocoTaskExtension import org.gradle.testing.jacoco.tasks.JacocoReport -import java.io.File import java.io.IOException -import java.net.URI import java.util.regex.Pattern abstract class CCTweakedExtension(private val project: Project) { @@ -55,10 +53,12 @@ abstract class CCTweakedExtension(private val project: Project) { ExternalProjectArtifacts.configure(this) } - val embeddedProjectClasses: Provider = embeddedProjectsResolved.map(ExternalProjectArtifacts::classes) + val embeddedProjectClasses: Provider = + embeddedProjectsResolved.map(ExternalProjectArtifacts::classes) val embeddedProjectClassesAndResources: Provider = embeddedProjectsResolved.map(ExternalProjectArtifacts::classesAndResources) - val embeddedProjectSources: Provider = embeddedProjectsResolved.map(ExternalProjectArtifacts::sources) + val embeddedProjectSources: Provider = + embeddedProjectsResolved.map(ExternalProjectArtifacts::sources) /** * Enable our custom linters on this project. @@ -105,41 +105,6 @@ abstract class CCTweakedExtension(private val project: Project) { } } - /** - * Download a file by creating a dummy Ivy repository. - * - * This should only be used for one-off downloads. Using a more conventional Ivy or Maven repository is preferred - * where possible. - */ - fun downloadFile(label: String, url: String): File { - val uri = URI(url) - val path = File(uri.path) - - project.repositories.ivy { - name = label - setUrl(URI(uri.scheme, uri.userInfo, uri.host, uri.port, path.parent, null, null)) - patternLayout { - artifact("[artifact].[ext]") - } - metadataSources { - artifact() - } - content { - includeModule("cc.tweaked.internal", path.nameWithoutExtension) - } - } - - return project.configurations.detachedConfiguration( - project.dependencies.create( - mapOf( - "group" to "cc.tweaked.internal", - "name" to path.nameWithoutExtension, - "ext" to path.extension, - ), - ), - ).resolve().single() - } - private fun gitProvider(default: T, command: List, process: (String) -> T): Provider { val baseResult = project.providers.exec { commandLine = listOf("git", "-C", project.rootDir.absolutePath) + command diff --git a/build-logic/base/src/main/kotlin/cc/tweaked/gradle/Extensions.kt b/build-logic/base/src/main/kotlin/cc/tweaked/gradle/Extensions.kt index d614a82a6..079858ee0 100644 --- a/build-logic/base/src/main/kotlin/cc/tweaked/gradle/Extensions.kt +++ b/build-logic/base/src/main/kotlin/cc/tweaked/gradle/Extensions.kt @@ -32,10 +32,12 @@ fun DependencyHandler.annotationProcessorEverywhere(dep: Any) { fun JavaExec.copyToFull(spec: JavaExec) { copyTo(spec) - // Additional Java options - spec.jvmArgs = jvmArgs // Fabric overrides getJvmArgs so copyTo doesn't do the right thing. + // Copy arguments. We have to evaluate argument providers immediately to avoid holding a reference to the other + // task. spec.args = args - spec.argumentProviders.addAll(argumentProviders) + for (argProvider in argumentProviders) spec.args(argProvider.asArguments()) + + // Additional Java options spec.mainClass.set(mainClass) spec.classpath = classpath spec.javaLauncher.set(javaLauncher) diff --git a/build-logic/base/src/main/kotlin/cc/tweaked/gradle/MinecraftExec.kt b/build-logic/base/src/main/kotlin/cc/tweaked/gradle/MinecraftExec.kt index fecae4c53..f35bb4b03 100644 --- a/build-logic/base/src/main/kotlin/cc/tweaked/gradle/MinecraftExec.kt +++ b/build-logic/base/src/main/kotlin/cc/tweaked/gradle/MinecraftExec.kt @@ -6,18 +6,22 @@ package cc.tweaked.gradle import net.neoforged.moddevgradle.internal.RunGameTask import org.gradle.api.GradleException +import org.gradle.api.file.FileCollection import org.gradle.api.file.FileSystemOperations import org.gradle.api.invocation.Gradle +import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Provider import org.gradle.api.services.BuildService import org.gradle.api.services.BuildServiceParameters -import org.gradle.api.tasks.* +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.JavaExec +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction import org.gradle.kotlin.dsl.getByName import org.gradle.language.base.plugins.LifecycleBasePlugin import java.io.File import java.nio.file.Files import java.util.concurrent.TimeUnit -import java.util.function.Supplier import javax.inject.Inject import kotlin.random.Random @@ -34,19 +38,28 @@ abstract class ClientJavaExec : JavaExec() { } @get:Input - val renderdoc get() = project.hasProperty("renderdoc") + val renderdoc: Provider = project.provider { project.hasProperty("renderdoc") } /** - * When [false], tests will not be run automatically, allowing the user to debug rendering. + * When `false`, tests will not be run automatically, allowing the user to debug rendering. */ @get:Input - val clientDebug get() = renderdoc || project.hasProperty("clientDebug") + val clientDebug: Provider = project.provider { renderdoc.get() || project.hasProperty("clientDebug") } /** - * When [false], tests will not run under a framebuffer. + * When `false`, tests will not run under a framebuffer. */ @get:Input - val useFramebuffer get() = !clientDebug && !project.hasProperty("clientNoFramebuffer") + val useFramebuffer: Provider = + project.provider { !clientDebug.get() && !project.hasProperty("clientNoFramebuffer") } + + /** Additional files to write to the destination directory. */ + @get:Input + abstract val fileContents: MapProperty + + /** Additional files to copy to the destination directory. */ + @get:Input + abstract val fileSources: MapProperty /** * The path test results are written to. @@ -55,8 +68,8 @@ abstract class ClientJavaExec : JavaExec() { val testResults = project.layout.buildDirectory.file("test-results/$name.xml") private fun setTestProperties() { - if (!clientDebug) systemProperty("cctest.client", "") - if (renderdoc) environment("LD_PRELOAD", "/usr/lib/librenderdoc.so") + if (!clientDebug.get()) systemProperty("cctest.client", "") + if (renderdoc.get()) environment("LD_PRELOAD", "/usr/lib/librenderdoc.so") systemProperty("cctest.gametest-report", testResults.get().asFile.absoluteFile) workingDir(project.layout.buildDirectory.dir("gametest/$name")) } @@ -102,27 +115,19 @@ abstract class ClientJavaExec : JavaExec() { systemProperty("cctest.tags", tags.joinToString(",")) } - /** - * Write a file with the given contents before starting Minecraft. This may be useful for writing config files. - */ - fun withFileContents(path: Any, contents: Supplier) { - val file = project.file(path).toPath() - doFirst { - Files.createDirectories(file.parent) - Files.writeString(file, contents.get()) - } - } + /** Configure Iris to use the given shader pack. */ + fun withShaderPack(shaders: FileCollection) = withShaderPack(shaders.elements.map { it.single().asFile }) - /** - * Copy a file to the provided path before starting Minecraft. This copy only occurs if the file does not already - * exist. - */ - fun withFileFrom(path: Any, source: Supplier) { - val file = project.file(path).toPath() - doFirst { - Files.createDirectories(file.parent) - if (!Files.exists(file)) Files.copy(source.get().toPath(), file) - } + /** Configure Iris to use the given shader pack. */ + fun withShaderPack(shaders: Provider) { + fileSources.put("shaderpacks/shaders.zip", shaders) + fileContents.put( + "config/iris.properties", + """ + enableShaders=true + shaderPack=shaders.zip + """.trimIndent(), + ) } @TaskAction @@ -130,7 +135,23 @@ abstract class ClientJavaExec : JavaExec() { Files.createDirectories(workingDir.toPath()) fsOperations.delete { delete(workingDir.resolve("screenshots")) } - if (useFramebuffer) { + for ((dest, contents) in fileContents.get()) { + val destFile = workingDir.resolve(dest).toPath() + Files.createDirectories(destFile.parent) + Files.writeString(destFile, contents) + } + + for ((dest, source) in fileSources.get()) { + val destFile = workingDir.resolve(dest) + Files.createDirectories(destFile.parentFile.toPath()) + fsOperations.copy { + from(source); + into(destFile.parent) + rename { destFile.name } + } + } + + if (useFramebuffer.get()) { clientRunner.get().wrapClient(this) { super.exec() } } else { super.exec() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a9e9cda7d..5e48a35be 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -36,6 +36,7 @@ kotlin-coroutines = "1.11.0" nightConfig = "3.9.0" # Minecraft mods +complementary = "r5.9.3" emi = "1.0.8+1.20.1" fabricPermissions = "0.3.20230723" iris = "1.6.4+1.20" @@ -102,6 +103,7 @@ nightConfig-toml = { module = "com.electronwill.night-config:toml", version.ref slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } # Minecraft mods +complementary = { module = "maven.modrinth:complementary-reimagined", version.ref = "complementary" } create-fabric = { module = "com.simibubi.create:create-fabric-1.20.1", version.ref = "create-fabric" } create-forge = { module = "com.simibubi.create:create-1.20.1", version.ref = "create-forge" } emi = { module = "dev.emi:emi-xplat-mojmap", version.ref = "emi" } diff --git a/projects/common-api/build.gradle.kts b/projects/common-api/build.gradle.kts index 9a290f919..5d1763c9e 100644 --- a/projects/common-api/build.gradle.kts +++ b/projects/common-api/build.gradle.kts @@ -81,18 +81,6 @@ tasks.javadoc { // Include the core-api in our javadoc export. This is wrong, but it means we can export a single javadoc dump. source("../core-api/src/main/java") - - options { - this as StandardJavadocDocletOptions - addBooleanOption("-allow-script-in-comments", true) - bottom( - """ - - - - """.trimIndent(), - ) - } } configurations.named("javadocElements") { diff --git a/projects/fabric/build.gradle.kts b/projects/fabric/build.gradle.kts index 5431dd112..9d54c1562 100644 --- a/projects/fabric/build.gradle.kts +++ b/projects/fabric/build.gradle.kts @@ -67,6 +67,11 @@ configurations { runtimeClasspath { extendsFrom(localImplementation.get()) } } +val testWithIrisShaders = configurations.dependencyScope("testWithIrisShaders") +val testWithIrisShadersResolve = configurations.resolvable("testWithIrisShadersResolve") { + extendsFrom(testWithIrisShaders) +} + dependencies { clientCompileOnly(variantOf(libs.emi) { classifier("api") }) modCompileOnly(libs.bundles.externalMods.fabric.compile) { @@ -83,6 +88,7 @@ dependencies { "modTestWithSodium"(libs.sodium) "modTestWithIris"(libs.iris) "modTestWithIris"(libs.sodium) + "testWithIrisShaders"(variantOf(libs.complementary) { artifactType("zip") }) "includeRuntimeOnly"(libs.cobalt) "includeRuntimeOnly"(libs.jzlib) @@ -289,15 +295,9 @@ val runGametestClientWithIris = tasks.register("runGametestClien tags("iris") classpath += configurations["testWithIris"] - withFileFrom(workingDir.resolve("shaderpacks/ComplementaryShaders_v4.6.zip")) { - cct.downloadFile("Complementary Shaders", "https://edge.forgecdn.net/files/3951/170/ComplementaryShaders_v4.6.zip") - } - withFileContents(workingDir.resolve("config/iris.properties")) { - """ - enableShaders=true - shaderPack=ComplementaryShaders_v4.6.zip - """.trimIndent() - } + // Ideally we'd use a detached configuration here, but that seems to ignore the artifactType (so it tries to fetch + // a jar), hence we use a full one. + withShaderPack(testWithIrisShadersResolve.get()) } cct.jacoco(runGametestClientWithIris)