import com.replaymod.gradle.preprocess.PreprocessTask import static gg.essential.gradle.util.PrebundleKt.prebundle buildscript { def mcVersion def (major, minor, patch) = project.name.tokenize('-')[0].tokenize('.') mcVersion = "${major}${minor.padLeft(2, '0')}${(patch ?: '').padLeft(2, '0')}" as int def fabric = mcVersion >= 11400 && !project.name.endsWith("-forge") project.ext.mcVersion = mcVersion project.ext.fabric = fabric repositories { mavenLocal() maven { url = "https://plugins.gradle.org/m2/" } mavenCentral() maven { name = "fabric" url = "https://maven.fabricmc.net/" } maven { name = "forge" url = "https://maven.minecraftforge.net" } maven { name = "sonatype" url = "https://oss.sonatype.org/content/repositories/snapshots/" } maven { url 'https://jitpack.io' } maven { url "https://maven.architectury.dev" } maven { url "https://repo.essential.gg/repository/maven-public" } } dependencies { classpath 'gradle.plugin.com.github.jengelman.gradle.plugins:shadow:7.0.0' if (fabric) { classpath 'fabric-loom:fabric-loom.gradle.plugin:0.11-SNAPSHOT' } else if (mcVersion >= 11400) { classpath('net.minecraftforge.gradle:ForgeGradle:5.0.5') { // the FG people still haven't learned to not do breaking changes exclude group: 'trove', module: 'trove' // preprocessor/idea requires more recent one } } else if (mcVersion >= 10800) { classpath('com.github.ReplayMod:ForgeGradle:' + ( mcVersion >= 11200 ? '34ab703' : // FG 2.3 mcVersion >= 10904 ? '5d1e8d8' : // FG 2.2 'ceb83c0' // FG 2.1 ) + ':all') } else { classpath 'com.github.ReplayMod:ForgeGradle:a8a9e0ca:all' // FG 1.2 } classpath 'gg.essential:essential-gradle-toolkit:0.1.10' } } def FG3 = !fabric && mcVersion >= 11400 def FABRIC = fabric def jGuiVersion = project.name if (['1.10.2', '1.11', '1.11.2'].contains(jGuiVersion)) jGuiVersion = '1.9.4' if (['1.12.1', '1.12.2'].contains(jGuiVersion)) jGuiVersion = '1.12' def jGui = project.evaluationDependsOn(":jGui:$jGuiVersion") apply plugin: 'com.github.johnrengelman.shadow' if (mcVersion >= 10800) { if (FABRIC) { apply plugin: 'fabric-loom' } else if (FG3) { apply plugin: 'net.minecraftforge.gradle' } else { apply plugin: 'net.minecraftforge.gradle.forge' } } else { apply plugin: 'forge' } if (!FABRIC) { ext { mixinSrg = new File(project.buildDir, 'tmp/mixins/mixins.srg') mixinRefMap = new File(project.buildDir, 'tmp/mixins/mixins.replaymod.refmap.json') } compileJava { options.compilerArgs += [ "-AoutSrgFile=${project.mixinSrg.canonicalPath}", "-AoutRefMapFile=${project.mixinRefMap.canonicalPath}", "-AreobfSrgFile=${project.file('build/mcp-srg.srg').canonicalPath}" ] } } apply plugin: 'com.replaymod.preprocess' preprocess { vars.put("MC", project.mcVersion) vars.put("FABRIC", project.fabric ? 1 : 0) keywords.set([ ".java": PreprocessTask.DEFAULT_KEYWORDS, ".json": PreprocessTask.DEFAULT_KEYWORDS, ".mcmeta": PreprocessTask.DEFAULT_KEYWORDS, ".cfg": PreprocessTask.CFG_KEYWORDS, ".vert": PreprocessTask.DEFAULT_KEYWORDS, ".frag": PreprocessTask.DEFAULT_KEYWORDS, ]) patternAnnotation.set("com.replaymod.gradle.remap.Pattern") } def mcVersionStr = "${(int)(mcVersion/10000)}.${(int)(mcVersion/100)%100}" + (mcVersion%100==0 ? '' : ".${mcVersion%100}") sourceCompatibility = targetCompatibility = mcVersion >= 11800 ? 17 : mcVersion >= 11700 ? 16 : 1.8 tasks.withType(JavaCompile).configureEach { options.release = mcVersion >= 11800 ? 17 : mcVersion >= 11700 ? 16 : 8 } if (mcVersion >= 11400) { sourceSets { api } } version = project.name + '-' + rootProject.version group= "com.replaymod" archivesBaseName = "replaymod" if (FABRIC) { loom { mixin.defaultRefmapName.set('mixins.replaymod.refmap.json') runConfigs.all { ideConfigGenerated = true } } } else { minecraft { if (FG3) { runs { client { workingDirectory rootProject.file('run') property 'forge.logging.console.level', 'info' mods { replaymod { source sourceSets.main } } } } } else { if (mcVersion >= 10800) { coreMod = 'com.replaymod.core.LoadingPlugin' } runDir = "../../run" } if (!FG3) { version = [ 11202: '1.12.2-14.23.0.2486', 11201: '1.12.1-14.22.0.2444', 11200: '1.12-14.21.1.2387', 11102: '1.11.2-13.20.0.2216', 11100: '1.11-13.19.1.2188', 11002: '1.10.2-12.18.2.2099', 10904: '1.9.4-12.17.0.1976', 10809: '1.8.9-11.15.1.1722', 10800: '1.8-11.14.4.1563', 10710: '1.7.10-10.13.4.1558-1.7.10', ][mcVersion] } mappings = [ 11404: "snapshot_20190719-1.14.3", 11202: "snapshot_20170615", 11201: "snapshot_20170615", 11200: "snapshot_20170615", 11102: "snapshot_20161220", 11100: "snapshot_20161111", 11002: "snapshot_20160518", 10904: "snapshot_20160518", 10809: "stable_22", 10800: "snapshot_nodoc_20141130", 10710: "stable_12", ][mcVersion] } } afterEvaluate { if (mcVersion >= 11400) { // No longer required in 1.13+ because all version info is in the toml file } else { // Note cannot use minecraft.replace because that has already been forwarded to the task by FG by now tasks.sourceMainJava.replace '@MOD_VERSION@', project.version // Includes intentional whitespace to stop Forge from declaring the mod to be compatible with // a newer srg-compatible MC version (that may be using a different protocol version) tasks.sourceMainJava.replace '@MC_VERSION@', "[ $mcVersionStr ]" } } repositories { mavenLocal() maven { name = "SpongePowered Repo" url = "https://repo.spongepowered.org/maven/" } maven { name = "fabric" url = "https://maven.fabricmc.net/" } maven { url 'https://maven.terraformersmc.com/releases/' content { includeGroup 'com.terraformersmc' } } maven { url 'https://jitpack.io' content { includeGroupByRegex 'com\\.github\\..*' } } exclusiveContent { forRepository { maven { name = "Modrinth" url = "https://api.modrinth.com/maven" } } filter { includeGroup "maven.modrinth" } } } configurations { // Include dep in fat jar without relocation and, when forge supports it, without exploding (TODO) shade implementation.extendsFrom shade // Include dep in fat jar with relocation and minimization shadow implementation.extendsFrom shadow } def shadeExclusions = { // Cannot just add these to the shade configuration because they'd be inherited by the compile configuration then exclude group: 'com.google.guava', module: 'guava-jdk5' exclude group: 'com.google.guava', module: 'guava' // provided by MC exclude group: 'com.google.code.gson', module: 'gson' // provided by MC (or manually bundled for 1.11.2 and below) } dependencies { if (FABRIC) { minecraft 'com.mojang:minecraft:' + [ 11404: '1.14.4', 11502: '1.15.2', 11601: '1.16.1', 11603: '1.16.3', 11604: '1.16.4', 11701: '1.17.1', 11800: '1.18', 11801: '1.18.1', 11802: '1.18.2', 11900: '1.19', 11901: '1.19.1', 11902: '1.19.2', 11903: '1.19.3-rc3', 11904: '1.19.4', 12001: '1.20.1', 12002: '1.20.2', 12004: '1.20.4', ][mcVersion] mappings 'net.fabricmc:yarn:' + [ 11404: '1.14.4+build.16', 11502: '1.15.2+build.14', 11601: '1.16.1+build.17:v2', 11603: '1.16.3+build.1:v2', 11604: '1.16.4+build.6:v2', 11701: '1.17.1+build.29:v2', 11800: '1.18+build.1:v2', 11801: '1.18.1+build.1:v2', 11802: '1.18.2+build.1:v2', 11900: '1.19+build.2:v2', 11901: '1.19.1+build.5:v2', 11902: '1.19.2+build.28:v2', 11903: '1.19.3-rc3+build.1:v2', 11904: '1.19.4+build.1:v2', 12001: '1.20.1+build.2:v2', 12002: '1.20.2+build.4:v2', 12004: '1.20.4+build.1:v2', ][mcVersion] modImplementation 'net.fabricmc:fabric-loader:0.15.1' def fabricApiVersion = [ 11404: '0.4.3+build.247-1.14', 11502: '0.5.1+build.294-1.15', 11601: '0.14.0+build.371-1.16', 11603: '0.17.1+build.394-1.16', 11604: '0.42.0+1.16', 11701: '0.46.1+1.17', 11800: '0.43.1+1.18', 11801: '0.43.1+1.18', 11802: '0.47.9+1.18.2', 11900: '0.55.3+1.19', 11901: '0.58.5+1.19.1', 11902: '0.68.0+1.19.2', 11903: '0.68.1+1.19.3', 11904: '0.76.0+1.19.4', 12001: '0.83.1+1.20.1', 12002: '0.90.7+1.20.2', 12004: '0.91.2+1.20.4', ][mcVersion] def fabricApiModules = [ "api-base", "networking-v0", "keybindings-v0", "resource-loader-v0", ] if (mcVersion >= 11600) { fabricApiModules.remove("keybindings-v0") fabricApiModules.add("key-binding-api-v1") } if (mcVersion >= 11604) { fabricApiModules.add("screen-api-v1") fabricApiModules.add("networking-api-v1") } if (mcVersion >= 11700) { fabricApiModules.remove("networking-v0") } fabricApiModules.each { module -> modImplementation fabricApi.module("fabric-$module", fabricApiVersion) include fabricApi.module("fabric-$module", fabricApiVersion) } } if (FG3) { minecraft 'net.minecraftforge:forge:' + [ 11404: '1.14.4-28.1.113', ][mcVersion] } if (!FABRIC) { // Mixin 0.8 is no longer compatible with MC 1.11.2 or older def mixinVersion = mcVersion >= 11200 ? '0.8.2' : '0.7.11-SNAPSHOT' annotationProcessor "org.spongepowered:mixin:$mixinVersion" compileOnly "org.spongepowered:mixin:$mixinVersion" shade("org.spongepowered:mixin:$mixinVersion") { transitive = false // deps should all be bundled with MC } // Mixin needs these (and depends on them but for some reason that's not enough. FG, did you do that?) annotationProcessor 'com.google.code.gson:gson:2.2.4' annotationProcessor 'com.google.guava:guava:21.0' annotationProcessor 'org.ow2.asm:asm-tree:6.2' annotationProcessor 'org.apache.logging.log4j:log4j-core:2.0-beta9' } if (mcVersion >= 11604) { shadow(annotationProcessor('com.github.LlamaLad7:MixinExtras:0.1.1')) } shadow 'com.googlecode.mp4parser:isoparser:1.1.7' shadow 'org.apache.commons:commons-exec:1.3' shadow 'com.google.apis:google-api-services-youtube:v3-rev178-1.22.0', shadeExclusions shadow 'com.google.api-client:google-api-client-gson:1.20.0', shadeExclusions shadow 'com.google.api-client:google-api-client-java6:1.20.0', shadeExclusions shadow 'com.google.oauth-client:google-oauth-client-jetty:1.20.0' def lwjgl = configurations.create("lwjgl") for (suffix in ['', ':natives-linux', ':natives-windows', ':natives-macos', ':natives-macos-arm64']) { add(lwjgl.name, 'org.lwjgl:lwjgl:3.3.1' + suffix) add(lwjgl.name, 'org.lwjgl:lwjgl-tinyexr:3.3.1' + suffix) } compileOnly('org.lwjgl:lwjgl-tinyexr:3.3.1') shadow(prebundle(project, lwjgl, "com/replaymod/render/utils/lwjgl.jar", {})) if (mcVersion < 11200) { // The version which MC ships is too old, we'll need to ship our own shadow 'com.google.code.gson:gson:2.8.7' } shadow 'com.github.javagl.JglTF:jgltf-model:3af6de4' if (FABRIC) { shadow 'org.apache.maven:maven-artifact:3.6.1' } shadow 'org.aspectj:aspectjrt:1.8.2' shadow 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8' shadow "com.github.ReplayMod:ReplayStudio:6cd39b0", shadeExclusions // FIXME this should be pulled in by ReplayStudio, and IntelliJ sees it, but javac for some reason does not implementation 'com.github.viaversion:opennbt:0a02214' // 2.0-SNAPSHOT (ViaVersion Edition) implementation(FABRIC ? dependencies.project(path: jGui.path, configuration: "namedElements") : jGui) { transitive = false // FG 1.2 puts all MC deps into the compile configuration and we don't want to shade those } shadow 'com.github.ReplayMod:lwjgl-utils:27dcd66' if (FABRIC) { if (mcVersion >= 12003) { modImplementation 'com.terraformersmc:modmenu:9.0.0-pre.1' } else if (mcVersion >= 12002) { modImplementation 'com.terraformersmc:modmenu:8.0.0' } else if (mcVersion >= 12000) { modImplementation 'com.terraformersmc:modmenu:7.0.1' } else if (mcVersion >= 11904) { modImplementation 'com.terraformersmc:modmenu:6.1.0-rc.4' } else if (mcVersion >= 11903) { modImplementation 'com.terraformersmc:modmenu:5.0.0-alpha.4' } else if (mcVersion >= 11901) { modImplementation 'com.terraformersmc:modmenu:4.0.5' } else if (mcVersion >= 11900) { modImplementation 'com.terraformersmc:modmenu:4.0.4' } else if (mcVersion >= 11802) { modImplementation 'com.terraformersmc:modmenu:3.1.0' } else if (mcVersion >= 11800) { modImplementation 'com.terraformersmc:modmenu:3.0.0' } else if (mcVersion >= 11700) { modImplementation 'com.terraformersmc:modmenu:2.0.0-beta.7' } else if (mcVersion >= 11602) { modImplementation 'com.terraformersmc:modmenu:1.16.8' } else if (mcVersion >= 11600) { modImplementation('com.terraformersmc:modmenu:1.14.15') { exclude module: 'fabric-resource-loader-v0' // inappropriate version for 1.16.1 } } else if (mcVersion >= 11500) { modImplementation 'com.terraformersmc:modmenu:1.10.6' } else { modCompileOnly 'com.terraformersmc:modmenu:1.10.6' } } if (mcVersion >= 11600) { modCompileOnly("maven.modrinth:iris:1.18.x-v1.2.0") { transitive = false // we do not want to upgrade our libs, we only need this to compile our mixins } } testImplementation 'junit:junit:4.11' } if (mcVersion <= 10710) { // FG 1.2 adds all MC deps to the compile configuration which we don't want afterEvaluate { // Remove them from the compile and runtime configurations configurations.compile.extendsFrom -= [configurations.minecraft, configurations.minecraftDeps] configurations.runtime.extendsFrom -= [configurations.forgeGradleStartClass] // And add them to the source sets instead sourceSets.main.with { compileClasspath += configurations.minecraft + configurations.minecraftDeps runtimeClasspath += configurations.minecraft + configurations.minecraftDeps + configurations.forgeGradleStartClass } // Also need to reconfigure the reobf task, so it can properly re-obfuscates inherited members tasks.reobf.obfOutput.all { artifact -> artifact.getFile() // force resolve artifact.classpath += configurations.minecraft + configurations.minecraftDeps } } // Test sources aren't preprocessed and I can't be bothered to fix that tasks.compileTestJava.onlyIf { false } } if (FABRIC) { tasks.remapJar { addNestedDependencies.set(true) afterEvaluate { // FIXME why does loom overwrite this if we set it immediately? archiveClassifier.set('obf') } } } File configureRelocationOutput = new File(project.buildDir, 'configureRelocation') task configureRelocation() { dependsOn tasks.jar dependsOn configurations.shadow outputs.file(configureRelocationOutput) doLast { def pkgs = files(configurations.shadow).filter { it.exists() }.collect { def tree = it.isDirectory() ? fileTree(it) : zipTree(it) def pkgs = [].toSet() tree.visit { file -> if (!file.directory && file.name.endsWith('.class') && file.path.contains('/')) { def pkg = file.path.substring(0, file.path.lastIndexOf('/')) + '/' if (pkg.startsWith('com/')) { if (pkg.startsWith('com/google/')) { if (!pkg.startsWith('com/google/common')) { pkgs << pkg.substring(0, pkg.indexOf('/', 'com/google/'.length())) } } else if (!pkg.startsWith('com/replaymod')) { pkgs << pkg.substring(0, pkg.indexOf('/', 4)) } } else if (pkg.startsWith('net/')) { if (!pkg.startsWith('net/minecraft') && !pkg.startsWith('net/fabric')) { pkgs << pkg.substring(0, pkg.indexOf('/', 'net/'.length())) } } else if (pkg.startsWith('org/')) { if (pkg.startsWith('org/apache/')) { if (pkg.startsWith('org/apache/commons/')) { if (!pkg.startsWith('org/apache/commons/io')) { pkgs << pkg.substring(0, pkg.indexOf('/', 'org/apache/commons/'.length())) } } else if (!pkg.startsWith('org/apache/logging')) { pkgs << pkg.substring(0, pkg.indexOf('/', 'org/apache/'.length())) } } else if (pkg.startsWith('org/lwjgl')) { return // either bundled with MC or uses natives which we can't relocate } else if (!pkg.startsWith('org/spongepowered')) { pkgs << pkg.substring(0, pkg.indexOf('/', 4)) } } else if (pkg.startsWith('it/unimi/dsi/fastutil') && mcVersion >= 11400) { return // MC uses this as well } else if (!pkg.startsWith('javax/')) { // Note: we cannot just use top level packages as those will be too generic and we'll run // into this long standing bug: https://github.com/johnrengelman/shadow/issues/232 def i = pkg.indexOf('/') def i2 = pkg.indexOf('/', i + 1) if (i2 > 0) { pkgs << pkg.substring(0, i2) } } } } pkgs }.flatten().unique() configureRelocationOutput.write(pkgs.join('\n')) } } // we want to base our shadowed jar on the reobfJar output, not the sourceSet output // Tried tasks.replace but that does not actually seem to replace everything. tasks.shadowJar.doFirst { throw new GradleException("Wrong task! You want to run 'bundleJar' instead.") } tasks.register('bundleJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar).configure { from { (FABRIC ? tasks.remapJar : tasks.jar).archiveFile.get() } dependsOn { FABRIC ? tasks.remapJar : (mcVersion >= 10800 ? tasks.reobfJar : tasks.reobf) } from({ zipTree((FABRIC ? jGui.tasks.remapJar : jGui.tasks.jar).archiveFile.get()) }) { filesMatching('mixins.jgui.json') { filter { it.replace('de.johni0702', 'com.replaymod.lib.de.johni0702') } } filesMatching('mixins.jgui.refmap.json') { filter { it.replace('de/johni0702', 'com/replaymod/lib/de/johni0702') } } } dependsOn { FABRIC ? jGui.tasks.remapJar : (mcVersion >= 10800 ? jGui.tasks.reobfJar : jGui.tasks.reobf) } relocate 'de.johni0702', 'com.replaymod.lib.de.johni0702' manifest.inheritFrom tasks.jar.manifest from project.configurations.shade configurations = [project.configurations.shadow] exclude 'META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'module-info.class' dependsOn tasks.configureRelocation inputs.file(configureRelocationOutput) doFirst { configureRelocationOutput.readLines().each { pkg -> def pkgName = pkg.replace('/', '.') relocate pkgName, 'com.replaymod.lib.' + pkgName } } // No need to shadow netty, MC provides it // (actually, pre-1.12 ships a netty which is too old, so we need to shade it there anyway) if (mcVersion >= 11200) { relocate 'com.github.steveice10.netty', 'io.netty' exclude 'com/github/steveice10/netty/**' } if (mcVersion >= 11400) { // MC ships this exclude 'it/unimi/dsi/fastutil/**' } minimize { exclude(dependency('.*spongepowered:mixin:.*')) } } tasks.assemble.dependsOn tasks.bundleJar jar { classifier = 'raw' if (!FABRIC) { from files(project.mixinRefMap.canonicalPath) manifest { attributes 'TweakClass': 'com.replaymod.core.tweaker.ReplayModTweaker', 'TweakOrder': '0', 'FMLCorePluginContainsFMLMod': 'true', 'FMLCorePlugin': 'com.replaymod.core.LoadingPlugin', 'FMLAT': 'replaymod_at.cfg' } } if (mcVersion >= 11700) { // Workaround a mixin bug which generates invalid refmaps for the `addDrawableChild` invoker filesMatching("mixins.replaymod.refmap.json") { it.filter { it.replace("addDrawableChild(L/;)L/;", "method_37063(Lnet/minecraft/class_364;)Lnet/minecraft/class_364;") } } } } processResources { // this will ensure that this task is redone when the versions change. inputs.property 'version', { project.version } inputs.property 'mcversion', { mcVersionStr } // replace stuff in mcmod.info (forge) and fabric.mod.json, nothing else filesMatching(['mcmod.info', 'fabric.mod.json']) { // replace version and mcversion expand 'version': project.version, 'mcversion': mcVersionStr } // strip comments from (strict) JSON files filesMatching('pack.mcmeta') { filter { line -> line.trim().startsWith('//') ? '' : line} } // exclude mod meta for non-applicable loader if (FABRIC) { exclude 'mcmod.info' } else { exclude 'fabric.mod.json' } } sourceSets { integrationTest { compileClasspath += main.runtimeClasspath + main.output java { srcDir file('src/integration-test/java') } resources.srcDir file('src/integration-test/resources') } } if (FABRIC) { // not required, fabric manages those by itself just fine } else if (FG3) { task copySrg(dependsOn: 'createMcpToSrg') { doLast { def tsrg = file(project.tasks.createMcpToSrg.output).readLines() def srg = [] def cls = '' for (def line : tsrg) { if (line[0] != '\t') { srg.add('CL: ' + line) cls = line.split(' ')[0] } else { def parts = line.substring(1).split(' ') if (line.contains('(')) { srg.add('MD: ' + cls + '/' + parts[0] + ' ' + parts[1] + ' ' + cls + '/' + parts[2] + ' ' + parts[1]) } else { srg.add('FD: ' + cls + '/' + parts[0] + ' ' + cls + '/' + parts[1]) } } } new File(project.buildDir, 'mcp-srg.srg').write(srg.join('\n')) } } compileJava.dependsOn copySrg } else { task copySrg(type: Copy, dependsOn: 'genSrgs') { from {project.tasks.genSrgs.mcpToSrg} into 'build' } compileJava.dependsOn copySrg } if (!FABRIC && !FG3) { if (mcVersion <= 10710) { reobf.addExtraSrgFile project.mixinSrg } else { reobfJar.addSecondarySrgFile project.mixinSrg } } /* FIXME // Mixin uses multiple HashMaps to generate the refmap. // HashMaps are unordered collections and as such do not produce deterministic output. // To fix that, we simply sort the refmap json file. import groovy.json.JsonSlurper import groovy.json.JsonOutput compileJava.doLast { File refmapFile = mcVersion >= 10800 ? compileJava.ext.refMapFile : project.mixinRefMap if (refmapFile.exists()) { def ordered ordered = { if (it instanceof Map) { def sorted = new TreeMap(it) sorted.replaceAll { k, v -> ordered(v) } sorted } else if (it instanceof List) { it.replaceAll { v -> ordered(v) } } else { it } } def json = JsonOutput.toJson(ordered(new JsonSlurper().parse(refmapFile))) refmapFile.withWriter { it.write json } } } */ if (!FG3 && !FABRIC) { // FIXME task runIntegrationTest(type: JavaExec, dependsOn: ["makeStart", "jar"]) { main = 'GradleStart' standardOutput = System.out errorOutput = System.err workingDir file(minecraft.runDir) def testDir = new File(minecraft.runDir, "integration-test") doFirst { testDir.deleteDir() testDir.mkdirs() } doLast { testDir.deleteDir() } afterEvaluate { def runClient = tasks.getByName("runClient") runIntegrationTest.jvmArgs = runClient.jvmArgs + "-Dfml.noGrab=true" runIntegrationTest.args = runClient.args + "--gameDir" + testDir.canonicalPath runIntegrationTest.classpath runClient.classpath + sourceSets.integrationTest.output } } } defaultTasks 'build'