import io.gitlab.jfronny.scripts.* import net.fabricmc.loom.task.PrepareJarRemapTask import net.fabricmc.loom.task.RemapJarTask import org.gradle.kotlin.dsl.* plugins { id("jf.java") idea `maven-publish` id("dev.architectury.loom") id("com.github.johnrengelman.shadow") } val devlibs = project.layout.buildDirectory.dir("devlibs").get().asFile // Register lom extension with recognised loom platform, mirrored in jfmod.gradle.kts val args = extensions.create("lom") args.loaderKind = LoaderKind.fromString(prop("loom.platform", "fabric")) args.loaderKind.finalizeValue() // Configure loom for stricter dev env loom { runtimeOnlyLog4j.set(true) // Other loaders unfortunately don't support this yet if (args.isSplitSources) splitEnvironmentSourceSets() silentMojangMappingsLicense() } // Create testmod source set with access to main and client classpaths sourceSets { create("testmod") { compileClasspath += sourceSets.main.get().compileClasspath runtimeClasspath += sourceSets.main.get().runtimeClasspath if (args.isSplitSources) { compileClasspath += sourceSets.client.get().compileClasspath runtimeClasspath += sourceSets.client.get().runtimeClasspath } } } val hasTestmod = !sourceSets.testmod.get().resources.isEmpty // Class path groups (required to allow ultra early init) loom { mods { register(name) { sourceSet(sourceSets.main.get()) if (args.isSplitSources) sourceSet(sourceSets.client.get()) } if (hasTestmod) { register("$name-testmod") { sourceSet(sourceSets.testmod.get()) } } } if (hasTestmod) { runs { create("testmodClient") { client() ideConfigGenerated(rootProject == project) name("Testmod Client") source(sourceSets.testmod.get()) } create("testmodServer") { server() ideConfigGenerated(rootProject == project) name("Testmod Server") source(sourceSets.testmod.get()) } } } } // Common repositories for mods repositories { maven("https://maven.terraformersmc.com/") { name = "TerraformersMC" } maven("https://maven.frohnmeyer-wds.de/artifacts") { name = "JFronny" } mavenCentral() mavenLocal() } // Register common dependencies earlyAfterEvaluate { args.check(this) dependencies { minecraft("com.mojang:minecraft:${args.minecraftVersion.get()}") if (args.yarnBuild.isPresent) mappings("net.fabricmc:yarn:${args.minecraftVersion.get()}+${args.yarnBuild.get()}:v2") else loom.officialMojangMappings() when (args.loaderKind.get()) { LoaderKind.NEOFORGE -> { "neoForge"("net.neoforged:neoforge:${args.loaderVersion.get()}") } LoaderKind.FORGE -> { "forge"("net.minecraftforge:forge:${args.minecraftVersion.get()}-${args.loaderVersion.get()}") } LoaderKind.FABRIC -> { modImplementation("net.fabricmc:fabric-loader:${args.loaderVersion.get()}") testImplementation("net.fabricmc:fabric-loader-junit:${args.loaderVersion.get()}") } } testmodImplementation(sourceSets.main.get().output) if (args.isSplitSources) testmodImplementation(sourceSets.client.get().output) } } tasks.test { useJUnitPlatform() } // Mark normal jars as -dev tasks.jar.get().archiveClassifier.set("dev") // configure the shadow task to not shadow by default and output to builds/devlibs tasks.shadowJar { // get injectCompiledConfig task if present (-> LibJF) or use normal jar task val inputTask = providers.provider { tasks.findByName("injectCompiledConfig") as Jar? }.orElse(tasks.jar) dependsOn(inputTask) configurations.clear() from(project.configurations.shadow, inputTask) archiveClassifier.set("shadow") destinationDirectory.set(devlibs) } val dev by configurations.creating { isCanBeConsumed = true isCanBeResolved = false extendsFrom(configurations["shadow"]) // Provide shadowed classes to dependent modules } artifacts { add(dev.name, tasks.shadowJar) } // generate sources jar to publish for better debugging with dependents java { withSourcesJar() } // attempt to allow reproducible builds by removing unneeded metadata from jars tasks.withType { isPreserveFileTimestamps = false isReproducibleFileOrder = false } // generate remapped jar without JiJ'd dependencies for maven publish val remapMavenJar by tasks.registering(RemapJarTask::class) { dependsOn(tasks.shadowJar) inputFile.set(tasks.shadowJar.get().archiveFile) archiveFileName.set("${archiveBaseName.get()}-${project.versionS}-maven.jar") addNestedDependencies.set(false) } tasks.assemble { dependsOn(remapMavenJar) } // configure remapJar to use the output of shadow tasks.remapJar { dependsOn(tasks.shadowJar) inputFile.set(tasks.shadowJar.get().archiveFile) archiveFileName.set("${archiveBaseName.get()}-${project.versionS}.jar") } // fill in mod version tasks.processResources { filesMatching(listOf("fabric.mod.json", "META-INF/mods.toml")) { expand(mapOf("version" to project.versionS)) } inputs.property("version", project.versionS) } // publish sources jar and remapped jar without JiJ'd deps publishing { publications { create("lom") { from(components["java"]) setArtifacts(listOf(remapMavenJar, tasks.sourcesJar)) } } } tasks.publish { dependsOn(tasks.build) } tasks.deployDebug.dependsOn(tasks.publish) // create testmodInclude configuration val testmodIncludeConfiguration = configurations.create("testmodInclude") if (hasTestmod) { // generate jar from testmod source set val testmodJar by tasks.registering(Jar::class) { from(sourceSets.testmod.get().output) destinationDirectory.set(devlibs) archiveClassifier.set("testmod") } afterEvaluate { // remap configuration for outputting usable testmod jar val remapTestmodJar by tasks.registering(RemapJarTask::class) { dependsOn(testmodJar) inputFile.set(testmodJar.get().archiveFile) archiveClassifier.set("testmod") // add nested jars from testmodInclude addNestedDependencies.set(true) nestedJars.setFrom(*testmodIncludeConfiguration.files.toTypedArray()) } tasks.assemble { dependsOn(remapTestmodJar) } } } afterEvaluate { // from fabric-example-mod, enforces modern java tasks.withType().configureEach { options.encoding = "UTF-8" options.release.set(17) } // otherwise we can't easily overwrite the artifacts to publish while keeping dependency metadata tasks.withType { enabled = false } // Fix prepareRemapJar // Finds remapJar tasks and the corresponding prepareRemapJar tasks and ensures the dependencies of remapJar are run before prepareRemapJar // This ensures the input files exist when the task is run tasks.configureEach { if (this is RemapJarTask) { this.dependsOn.filterIsInstance().forEach { prepareTask -> prepareTask.dependsOn(*this.dependsOn.filterNot { it == prepareTask }.toTypedArray()) } } } }