Update buildscript

This commit is contained in:
Matej Dipčár committed 2022-11-28 01:53:10 +01:00
1 parent d28ffa6adc
commit 18b67f804b
3 files changed
+558 -148

No files matched your search

+44
View File
@@ -0,0 +1,44 @@
* text eol=lf
*.[jJ][aA][rR] binary
*.[pP][nN][gG] binary
*.[jJ][pP][gG] binary
*.[jJ][pP][eE][gG] binary
*.[gG][iI][fF] binary
*.[tT][iI][fF] binary
*.[tT][iI][fF][fF] binary
*.[iI][cC][oO] binary
*.[sS][vV][gG] text
*.[eE][pP][sS] binary
*.[xX][cC][fF] binary
*.[kK][aA][rR] binary
*.[mM]4[aA] binary
*.[mM][iI][dD] binary
*.[mM][iI][dD][iI] binary
*.[mM][pP]3 binary
*.[oO][gG][gG] binary
*.[rR][aA] binary
*.7[zZ] binary
*.[gG][zZ] binary
*.[tT][aA][rR] binary
*.[tT][gG][zZ] binary
*.[zZ][iI][pP] binary
*.[tT][cC][nN] binary
*.[sS][oO] binary
*.[dD][lL][lL] binary
*.[dD][yY][lL][iI][bB] binary
*.[pP][sS][dD] binary
*.[tT][tT][fF] binary
*.[oO][tT][fF] binary
*.[pP][aA][tT][cC][hH] -text
*.[bB][aA][tT] text eol=crlf
*.[cC][mM][dD] text eol=crlf
*.[pP][sS]1 text eol=crlf
*[aA][uU][tT][oO][gG][eE][nN][eE][rR][aA][tT][eE][dD]* binary
+504 -148
View File
@@ -1,25 +1,40 @@
//version: 1650343995 //version: 1669411416
/* /*
DO NOT CHANGE THIS FILE! DO NOT CHANGE THIS FILE!
Also, you may replace this file at any time if there is an update available.
Also, you may replace this file at any time if there is an update available. Please check https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/master/build.gradle for updates.
Please check https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/build.gradle for updates. */
*/
import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.matthewprenger.cursegradle.CurseArtifact
import com.matthewprenger.cursegradle.CurseRelation
import com.modrinth.minotaur.dependencies.ModDependency
import com.modrinth.minotaur.dependencies.VersionDependency
import org.gradle.internal.logging.text.StyledTextOutput.Style import org.gradle.internal.logging.text.StyledTextOutput.Style
import org.gradle.internal.logging.text.StyledTextOutputFactory import org.gradle.internal.logging.text.StyledTextOutputFactory
import java.nio.file.Files
import java.nio.file.Paths
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream
buildscript { buildscript {
repositories { repositories {
mavenCentral()
maven { maven {
name 'forge' name 'forge'
url 'https://maven.minecraftforge.net' url 'https://maven.minecraftforge.net'
} }
maven {
// GTNH ForgeGradle Fork
name = "GTNH Maven"
url = "http://jenkins.usrv.eu:8081/nexus/content/groups/public/"
}
maven { maven {
name 'sonatype' name 'sonatype'
url 'https://oss.sonatype.org/content/repositories/snapshots/' url 'https://oss.sonatype.org/content/repositories/snapshots/'
@@ -28,30 +43,39 @@ buildscript {
name 'Scala CI dependencies' name 'Scala CI dependencies'
url 'https://repo1.maven.org/maven2/' url 'https://repo1.maven.org/maven2/'
} }
maven {
name 'jitpack'
url 'https://jitpack.io'
}
} }
dependencies { dependencies {
classpath 'com.github.GTNewHorizons:ForgeGradle:1.2.11' classpath 'net.minecraftforge.gradle:ForgeGradle:1.2.11'
} }
} }
plugins { plugins {
id 'java-library' id 'java-library'
id 'idea' id 'idea'
id 'eclipse' id 'eclipse'
id 'scala' id 'scala'
id 'maven-publish' id 'maven-publish'
id 'org.jetbrains.kotlin.jvm' version '1.5.30' apply false id 'org.jetbrains.kotlin.jvm' version '1.5.30' apply false
id 'org.jetbrains.kotlin.kapt' version '1.5.30' apply false id 'org.jetbrains.kotlin.kapt' version '1.5.30' apply false
id 'org.ajoberstar.grgit' version '4.1.1' id 'com.google.devtools.ksp' version '1.5.30-1.0.0' apply false
id 'org.ajoberstar.grgit' version '4.1.1'
id 'com.github.johnrengelman.shadow' version '4.0.4' id 'com.github.johnrengelman.shadow' version '4.0.4'
id 'com.palantir.git-version' version '0.13.0' apply false id 'com.palantir.git-version' version '0.13.0' apply false
id 'de.undercouch.download' version '5.0.1' id 'de.undercouch.download' version '5.0.1'
id 'com.github.gmazzo.buildconfig' version '3.0.3' apply false id 'com.github.gmazzo.buildconfig' version '3.0.3' apply false
id 'com.diffplug.spotless' version '6.7.2' apply false
id 'com.modrinth.minotaur' version '2.+' apply false
id 'com.matthewprenger.cursegradle' version '1.4.0' apply false
} }
boolean settingsupdated = verifySettingsGradle()
settingsupdated = verifyGitAttributes() || settingsupdated
if (settingsupdated)
throw new GradleException("Settings has been updated, please re-run task.")
dependencies {
implementation 'com.diffplug:blowdryer:1.6.0'
}
apply plugin: 'com.diffplug.blowdryer'
if (project.file('.git/HEAD').isFile()) { if (project.file('.git/HEAD').isFile()) {
apply plugin: 'com.palantir.git-version' apply plugin: 'com.palantir.git-version'
@@ -77,7 +101,14 @@ idea {
} }
} }
if(JavaVersion.current() != JavaVersion.VERSION_1_8) { boolean disableSpotless = project.hasProperty("disableSpotless") ? project.disableSpotless.toBoolean() : false
if (!disableSpotless) {
apply plugin: 'com.diffplug.spotless'
apply from: Blowdryer.file('spotless.gradle')
}
if (JavaVersion.current() != JavaVersion.VERSION_1_8) {
throw new GradleException("This project requires Java 8, but it's running on " + JavaVersion.current()) throw new GradleException("This project requires Java 8, but it's running on " + JavaVersion.current())
} }
@@ -102,63 +133,79 @@ checkPropertyExists("containsMixinsAndOrCoreModOnly")
checkPropertyExists("usesShadowedDependencies") checkPropertyExists("usesShadowedDependencies")
checkPropertyExists("developmentEnvironmentUserName") checkPropertyExists("developmentEnvironmentUserName")
boolean noPublishedSources = project.findProperty("noPublishedSources") ? project.noPublishedSources.toBoolean() : false propertyDefaultIfUnset("noPublishedSources", false)
boolean usesMixinDebug = project.findProperty('usesMixinDebug') ?: project.usesMixins.toBoolean() propertyDefaultIfUnset("usesMixinDebug", project.usesMixins)
propertyDefaultIfUnset("forceEnableMixins", false)
propertyDefaultIfUnset("channel", "stable")
propertyDefaultIfUnset("mappingsVersion", "12")
propertyDefaultIfUnset("modrinthProjectId", "")
propertyDefaultIfUnset("modrinthRelations", "")
propertyDefaultIfUnset("curseForgeProjectId", "")
propertyDefaultIfUnset("curseForgeRelations", "")
String javaSourceDir = "src/main/java/" String javaSourceDir = "src/main/java/"
String scalaSourceDir = "src/main/scala/" String scalaSourceDir = "src/main/scala/"
String kotlinSourceDir = "src/main/kotlin/" String kotlinSourceDir = "src/main/kotlin/"
String targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/")
String targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") final String modGroupPath = modGroup.toString().replaceAll("\\.", "/")
String targetPackageKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") final String apiPackagePath = apiPackage.toString().replaceAll("\\.", "/")
if(!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) {
String targetPackageJava = javaSourceDir + modGroupPath
String targetPackageScala = scalaSourceDir + modGroupPath
String targetPackageKotlin = kotlinSourceDir + modGroupPath
if (!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) {
throw new GradleException("Could not resolve \"modGroup\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin) throw new GradleException("Could not resolve \"modGroup\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin)
} }
if(apiPackage) { if (apiPackage) {
targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") targetPackageJava = javaSourceDir + modGroupPath + "/" + apiPackagePath
targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") targetPackageScala = scalaSourceDir + modGroupPath + "/" + apiPackagePath
targetPackageKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") targetPackageKotlin = kotlinSourceDir + modGroupPath + "/" + apiPackagePath
if(!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) { if (!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) {
throw new GradleException("Could not resolve \"apiPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin) throw new GradleException("Could not resolve \"apiPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin)
} }
} }
if(accessTransformersFile) { if (accessTransformersFile) {
String targetFile = "src/main/resources/META-INF/" + accessTransformersFile String targetFile = "src/main/resources/META-INF/" + accessTransformersFile
if(!getFile(targetFile).exists()) { if (!getFile(targetFile).exists()) {
throw new GradleException("Could not resolve \"accessTransformersFile\"! Could not find " + targetFile) throw new GradleException("Could not resolve \"accessTransformersFile\"! Could not find " + targetFile)
} }
} }
if(usesMixins.toBoolean()) { if (usesMixins.toBoolean()) {
if(mixinsPackage.isEmpty() || mixinPlugin.isEmpty()) { if (mixinsPackage.isEmpty()) {
throw new GradleException("\"mixinPlugin\" requires \"mixinsPackage\" and \"mixinPlugin\" to be set!") throw new GradleException("\"usesMixins\" requires \"mixinsPackage\" to be set!")
}
final String mixinPackagePath = mixinsPackage.toString().replaceAll("\\.", "/")
final String mixinPluginPath = mixinPlugin.toString().replaceAll("\\.", "/")
targetPackageJava = javaSourceDir + modGroupPath + "/" + mixinPackagePath
targetPackageScala = scalaSourceDir + modGroupPath + "/" + mixinPackagePath
targetPackageKotlin = kotlinSourceDir + modGroupPath + "/" + mixinPackagePath
if (!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) {
throw new GradleException("Could not resolve \"mixinsPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin)
} }
targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/") if (!mixinPlugin.isEmpty()) {
targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/") String targetFileJava = javaSourceDir + modGroupPath + "/" + mixinPluginPath + ".java"
targetPackageKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/") String targetFileScala = scalaSourceDir + modGroupPath + "/" + mixinPluginPath + ".scala"
if(!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) { String targetFileScalaJava = scalaSourceDir + modGroupPath + "/" + mixinPluginPath + ".java"
throw new GradleException("Could not resolve \"mixinsPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin) String targetFileKotlin = kotlinSourceDir + modGroupPath + "/" + mixinPluginPath + ".kt"
} if (!(getFile(targetFileJava).exists() || getFile(targetFileScala).exists() || getFile(targetFileScalaJava).exists() || getFile(targetFileKotlin).exists())) {
throw new GradleException("Could not resolve \"mixinPlugin\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava + " or " + targetFileKotlin)
String targetFileJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".java" }
String targetFileScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".scala"
String targetFileScalaJava = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".java"
String targetFileKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".kt"
if(!(getFile(targetFileJava).exists() || getFile(targetFileScala).exists() || getFile(targetFileScalaJava).exists() || getFile(targetFileKotlin).exists())) {
throw new GradleException("Could not resolve \"mixinPlugin\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava + " or " + targetFileKotlin)
} }
} }
if(coreModClass) { if (coreModClass) {
String targetFileJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".java" final String coreModPath = coreModClass.toString().replaceAll("\\.", "/")
String targetFileScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".scala" String targetFileJava = javaSourceDir + modGroupPath + "/" + coreModPath + ".java"
String targetFileScalaJava = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".java" String targetFileScala = scalaSourceDir + modGroupPath + "/" + coreModPath + ".scala"
String targetFileKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".kt" String targetFileScalaJava = scalaSourceDir + modGroupPath + "/" + coreModPath + ".java"
if(!(getFile(targetFileJava).exists() || getFile(targetFileScala).exists() || getFile(targetFileScalaJava).exists() || getFile(targetFileKotlin).exists())) { String targetFileKotlin = kotlinSourceDir + modGroupPath + "/" + coreModPath + ".kt"
if (!(getFile(targetFileJava).exists() || getFile(targetFileScala).exists() || getFile(targetFileScalaJava).exists() || getFile(targetFileKotlin).exists())) {
throw new GradleException("Could not resolve \"coreModClass\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava + " or " + targetFileKotlin) throw new GradleException("Could not resolve \"coreModClass\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava + " or " + targetFileKotlin)
} }
} }
@@ -188,7 +235,7 @@ try {
catch (Exception ignored) { catch (Exception ignored) {
out.style(Style.Failure).text( out.style(Style.Failure).text(
'This mod must be version controlled by Git AND the repository must provide at least one tag,\n' + 'This mod must be version controlled by Git AND the repository must provide at least one tag,\n' +
'or the VERSION override must be set! ').style(Style.SuccessHeader).text('(Do NOT download from GitHub using the ZIP option, instead\n' + 'or the VERSION override must be set! ').style(Style.SuccessHeader).text('(Do NOT download from GitHub using the ZIP option, instead\n' +
'clone the repository, see ').style(Style.Info).text('https://gtnh.miraheze.org/wiki/Development').style(Style.SuccessHeader).println(' for details.)' 'clone the repository, see ').style(Style.Info).text('https://gtnh.miraheze.org/wiki/Development').style(Style.SuccessHeader).println(' for details.)'
) )
versionOverride = 'NO-GIT-TAG-SET' versionOverride = 'NO-GIT-TAG-SET'
@@ -199,22 +246,21 @@ ext {
modVersion = identifiedVersion modVersion = identifiedVersion
} }
if(identifiedVersion == versionOverride) { if (identifiedVersion == versionOverride) {
out.style(Style.Failure).text('Override version to ').style(Style.Identifier).text(modVersion).style(Style.Failure).println('!\7') out.style(Style.Failure).text('Override version to ').style(Style.Identifier).text(modVersion).style(Style.Failure).println('!\7')
} }
group = modGroup group = modGroup
if(project.hasProperty("customArchiveBaseName") && customArchiveBaseName) { if (project.hasProperty("customArchiveBaseName") && customArchiveBaseName) {
archivesBaseName = customArchiveBaseName archivesBaseName = customArchiveBaseName
} } else {
else {
archivesBaseName = modId archivesBaseName = modId
} }
def arguments = [] def arguments = []
def jvmArguments = [] def jvmArguments = []
if (usesMixins.toBoolean()) { if (usesMixins.toBoolean() || forceEnableMixins.toBoolean()) {
arguments += [ arguments += [
"--tweakClass org.spongepowered.asm.launch.MixinTweaker" "--tweakClass org.spongepowered.asm.launch.MixinTweaker"
] ]
@@ -233,16 +279,16 @@ minecraft {
if (replaceGradleTokenInFile) { if (replaceGradleTokenInFile) {
replaceIn replaceGradleTokenInFile replaceIn replaceGradleTokenInFile
if(gradleTokenModId) { if (gradleTokenModId) {
replace gradleTokenModId, modId replace gradleTokenModId, modId
} }
if(gradleTokenModName) { if (gradleTokenModName) {
replace gradleTokenModName, modName replace gradleTokenModName, modName
} }
if(gradleTokenVersion) { if (gradleTokenVersion) {
replace gradleTokenVersion, modVersion replace gradleTokenVersion, modVersion
} }
if(gradleTokenGroupName) { if (gradleTokenGroupName) {
replace gradleTokenGroupName, modGroup replace gradleTokenGroupName, modGroup
} }
} }
@@ -251,7 +297,7 @@ minecraft {
args(arguments) args(arguments)
jvmArgs(jvmArguments) jvmArgs(jvmArguments)
if(developmentEnvironmentUserName) { if (developmentEnvironmentUserName) {
args("--username", developmentEnvironmentUserName) args("--username", developmentEnvironmentUserName)
} }
} }
@@ -262,7 +308,7 @@ minecraft {
} }
} }
if(file('addon.gradle').exists()) { if (file('addon.gradle').exists()) {
apply from: 'addon.gradle' apply from: 'addon.gradle'
} }
@@ -279,33 +325,23 @@ repositories {
name 'Overmind forge repo mirror' name 'Overmind forge repo mirror'
url 'https://gregtech.overminddl1.com/' url 'https://gregtech.overminddl1.com/'
} }
if(usesMixins.toBoolean()) { if (usesMixins.toBoolean() || forceEnableMixins.toBoolean()) {
maven { maven {
name 'sponge' name = "GTNH Maven"
url 'https://repo.spongepowered.org/repository/maven-public' url = "http://jenkins.usrv.eu:8081/nexus/content/groups/public/"
}
maven {
url 'https://jitpack.io'
} }
} }
} }
dependencies { dependencies {
if(usesMixins.toBoolean()) { if (usesMixins.toBoolean()) {
annotationProcessor('org.ow2.asm:asm-debug-all:5.0.3') annotationProcessor('org.ow2.asm:asm-debug-all:5.0.3')
annotationProcessor('com.google.guava:guava:24.1.1-jre') annotationProcessor('com.google.guava:guava:24.1.1-jre')
annotationProcessor('com.google.code.gson:gson:2.8.6') annotationProcessor('com.google.code.gson:gson:2.8.6')
annotationProcessor('org.spongepowered:mixin:0.8-SNAPSHOT') annotationProcessor('com.gtnewhorizon:gtnhmixins:2.1.1:processor')
// using 0.8 to workaround a issue in 0.7 which fails mixin application }
compile('com.github.GTNewHorizons:SpongePoweredMixin:0.7.12-GTNH') { if (usesMixins.toBoolean() || forceEnableMixins.toBoolean()) {
// Mixin includes a lot of dependencies that are too up-to-date compile('com.gtnewhorizon:gtnhmixins:2.1.1')
exclude module: 'launchwrapper'
exclude module: 'guava'
exclude module: 'gson'
exclude module: 'commons-io'
exclude module: 'log4j-core'
}
compile('com.github.GTNewHorizons:SpongeMixins:1.5.0')
} }
} }
@@ -317,13 +353,18 @@ def mixinSrg = "${tasks.reobf.temporaryDir}" + File.separator + "mixins.srg"
task generateAssets { task generateAssets {
if (usesMixins.toBoolean()) { if (usesMixins.toBoolean()) {
def mixinConfigFile = getFile("/src/main/resources/mixins." + modId + ".json"); def mixinConfigFile = getFile("/src/main/resources/mixins." + modId + ".json")
if (!mixinConfigFile.exists()) { if (!mixinConfigFile.exists()) {
def mixinPluginLine = ""
if(!mixinPlugin.isEmpty()) {
// We might not have a mixin plugin if we're using early/late mixins
mixinPluginLine += """\n "plugin": "${modGroup}.${mixinPlugin}", """
}
mixinConfigFile.text = """{ mixinConfigFile.text = """{
"required": true, "required": true,
"minVersion": "0.7.11", "minVersion": "0.8.5-GTNH",
"package": "${modGroup}.${mixinsPackage}", "package": "${modGroup}.${mixinsPackage}",${mixinPluginLine}
"plugin": "${modGroup}.${mixinPlugin}",
"refmap": "${mixingConfigRefMap}", "refmap": "${mixingConfigRefMap}",
"target": "@env(DEFAULT)", "target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_8", "compatibilityLevel": "JAVA_8",
@@ -353,7 +394,10 @@ shadowJar {
} }
minimize() // This will only allow shading for actually used classes minimize() // This will only allow shading for actually used classes
configurations = [project.configurations.shadowImplementation, project.configurations.shadowCompile] configurations = [
project.configurations.shadowImplementation,
project.configurations.shadowCompile
]
dependsOn(relocateShadowJar) dependsOn(relocateShadowJar)
} }
@@ -368,38 +412,38 @@ jar {
attributes(getManifestAttributes()) attributes(getManifestAttributes())
} }
if(usesShadowedDependencies.toBoolean()) { if (usesShadowedDependencies.toBoolean()) {
dependsOn(shadowJar) dependsOn(shadowJar)
enabled = false enabled = false
} }
} }
reobf { reobf {
if(usesMixins.toBoolean()) { if (usesMixins.toBoolean()) {
addExtraSrgFile mixinSrg addExtraSrgFile mixinSrg
} }
} }
afterEvaluate { afterEvaluate {
if(usesMixins.toBoolean()) { if (usesMixins.toBoolean()) {
tasks.compileJava { tasks.compileJava {
options.compilerArgs += [ options.compilerArgs += [
"-AreobfSrgFile=${tasks.reobf.srg}", "-AreobfSrgFile=${tasks.reobf.srg}",
"-AoutSrgFile=${mixinSrg}", "-AoutSrgFile=${mixinSrg}",
"-AoutRefMapFile=${refMap}", "-AoutRefMapFile=${refMap}",
// Elan: from what I understand they are just some linter configs so you get some warning on how to properly code // Elan: from what I understand they are just some linter configs so you get some warning on how to properly code
"-XDenableSunApiLintControl", "-XDenableSunApiLintControl",
"-XDignore.symbol.file" "-XDignore.symbol.file"
] ]
} }
} }
} }
runClient { runClient {
if(developmentEnvironmentUserName) { if (developmentEnvironmentUserName) {
arguments += [ arguments += [
"--username", "--username",
developmentEnvironmentUserName developmentEnvironmentUserName
] ]
} }
@@ -414,9 +458,9 @@ runServer {
tasks.withType(JavaExec).configureEach { tasks.withType(JavaExec).configureEach {
javaLauncher.set( javaLauncher.set(
javaToolchains.launcherFor { javaToolchains.launcherFor {
languageVersion = projectJavaVersion languageVersion = projectJavaVersion
} }
) )
} }
@@ -424,6 +468,7 @@ processResources {
// this will ensure that this task is redone when the versions change. // this will ensure that this task is redone when the versions change.
inputs.property "version", project.version inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.version inputs.property "mcversion", project.minecraft.version
exclude("spotless.gradle")
// replace stuff in mcmod.info, nothing else // replace stuff in mcmod.info, nothing else
from(sourceSets.main.resources.srcDirs) { from(sourceSets.main.resources.srcDirs) {
@@ -436,43 +481,44 @@ processResources {
"modName": modName "modName": modName
} }
if(usesMixins.toBoolean()) { if (usesMixins.toBoolean()) {
from refMap from refMap
} }
// copy everything else that's not the mcmod.info // copy everything else that's not the mcmod.info
from(sourceSets.main.resources.srcDirs) { from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info' exclude 'mcmod.info'
exclude 'spotless.gradle'
} }
} }
def getManifestAttributes() { def getManifestAttributes() {
def manifestAttributes = [:] def manifestAttributes = [:]
if(!containsMixinsAndOrCoreModOnly.toBoolean() && (usesMixins.toBoolean() || coreModClass)) { if (!containsMixinsAndOrCoreModOnly.toBoolean() && (usesMixins.toBoolean() || coreModClass)) {
manifestAttributes += ["FMLCorePluginContainsFMLMod": true] manifestAttributes += ["FMLCorePluginContainsFMLMod": true]
} }
if(accessTransformersFile) { if (accessTransformersFile) {
manifestAttributes += ["FMLAT" : accessTransformersFile.toString()] manifestAttributes += ["FMLAT": accessTransformersFile.toString()]
} }
if(coreModClass) { if (coreModClass) {
manifestAttributes += ["FMLCorePlugin": modGroup + "." + coreModClass] manifestAttributes += ["FMLCorePlugin": modGroup + "." + coreModClass]
} }
if(usesMixins.toBoolean()) { if (usesMixins.toBoolean()) {
manifestAttributes += [ manifestAttributes += [
"TweakClass" : "org.spongepowered.asm.launch.MixinTweaker", "TweakClass" : "org.spongepowered.asm.launch.MixinTweaker",
"MixinConfigs" : "mixins." + modId + ".json", "MixinConfigs" : "mixins." + modId + ".json",
"ForceLoadAsMod" : !containsMixinsAndOrCoreModOnly.toBoolean() "ForceLoadAsMod": !containsMixinsAndOrCoreModOnly.toBoolean()
] ]
} }
return manifestAttributes return manifestAttributes
} }
task sourcesJar(type: Jar) { task sourcesJar(type: Jar) {
from (sourceSets.main.allSource) from(sourceSets.main.allSource)
from (file("$projectDir/LICENSE")) from(file("$projectDir/LICENSE"))
getArchiveClassifier().set('sources') getArchiveClassifier().set('sources')
} }
@@ -491,7 +537,10 @@ task shadowDevJar(type: ShadowJar) {
} }
minimize() // This will only allow shading for actually used classes minimize() // This will only allow shading for actually used classes
configurations = [project.configurations.shadowImplementation, project.configurations.shadowCompile] configurations = [
project.configurations.shadowImplementation,
project.configurations.shadowCompile
]
} }
task relocateShadowDevJar(type: ConfigureShadowRelocation) { task relocateShadowDevJar(type: ConfigureShadowRelocation) {
@@ -519,22 +568,22 @@ task devJar(type: Jar) {
attributes(getManifestAttributes()) attributes(getManifestAttributes())
} }
if(usesShadowedDependencies.toBoolean()) { if (usesShadowedDependencies.toBoolean()) {
dependsOn(circularResolverJar) dependsOn(circularResolverJar)
enabled = false enabled = false
} }
} }
task apiJar(type: Jar) { task apiJar(type: Jar) {
from (sourceSets.main.allSource) { from(sourceSets.main.allSource) {
include modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") + '/**' include modGroupPath + "/" + apiPackagePath + '/**'
} }
from (sourceSets.main.output) { from(sourceSets.main.output) {
include modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") + '/**' include modGroupPath + "/" + apiPackagePath + '/**'
} }
from (sourceSets.main.resources.srcDirs) { from(sourceSets.main.resources.srcDirs) {
include("LICENSE") include("LICENSE")
} }
@@ -542,11 +591,11 @@ task apiJar(type: Jar) {
} }
artifacts { artifacts {
if(!noPublishedSources) { if (!noPublishedSources) {
archives sourcesJar archives sourcesJar
} }
archives devJar archives devJar
if(apiPackage) { if (apiPackage) {
archives apiJar archives apiJar
} }
} }
@@ -564,10 +613,10 @@ publishing {
publications { publications {
maven(MavenPublication) { maven(MavenPublication) {
from components.java from components.java
if(usesShadowedDependencies.toBoolean()) { if (usesShadowedDependencies.toBoolean()) {
artifact source: shadowJar, classifier: "" artifact source: shadowJar, classifier: ""
} }
if(!noPublishedSources) { if (!noPublishedSources) {
artifact source: sourcesJar, classifier: "sources" artifact source: sourcesJar, classifier: "sources"
} }
artifact source: usesShadowedDependencies.toBoolean() ? shadowDevJar : devJar, classifier: "dev" artifact source: usesShadowedDependencies.toBoolean() ? shadowDevJar : devJar, classifier: "dev"
@@ -582,8 +631,11 @@ publishing {
// remove extra garbage from minecraft and minecraftDeps configuration // remove extra garbage from minecraft and minecraftDeps configuration
pom.withXml { pom.withXml {
def badArtifacts = [:].withDefault {[] as Set<String>} def badArtifacts = [:].withDefault { [] as Set<String> }
for (configuration in [projectConfigs.minecraft, projectConfigs.minecraftDeps]) { for (configuration in [
projectConfigs.minecraft,
projectConfigs.minecraftDeps
]) {
for (dependency in configuration.allDependencies) { for (dependency in configuration.allDependencies) {
badArtifacts[dependency.group == null ? "" : dependency.group] += dependency.name badArtifacts[dependency.group == null ? "" : dependency.group] += dependency.name
} }
@@ -612,6 +664,113 @@ publishing {
} }
} }
if (modrinthProjectId.size() != 0 && System.getenv("MODRINTH_TOKEN") != null) {
apply plugin: 'com.modrinth.minotaur'
File changelogFile = new File(System.getenv("CHANGELOG_FILE") ?: "CHANGELOG.md")
modrinth {
token = System.getenv("MODRINTH_TOKEN")
projectId = modrinthProjectId
versionNumber = identifiedVersion
versionType = identifiedVersion.endsWith("-pre") ? "beta" : "release"
changelog = changelogFile.exists() ? changelogFile.getText("UTF-8") : ""
uploadFile = jar
additionalFiles = getSecondaryArtifacts()
gameVersions = [minecraftVersion]
loaders = ["forge"]
debugMode = false
}
if (modrinthRelations.size() != 0) {
String[] deps = modrinthRelations.split(";")
deps.each { dep ->
if (dep.size() == 0) {
return
}
String[] parts = dep.split(":")
String[] qual = parts[0].split("-")
addModrinthDep(qual[0], qual[1], parts[1])
}
}
if (usesMixins.toBoolean()) {
addModrinthDep("required", "version", "gtnhmixins")
}
tasks.modrinth.dependsOn(build)
tasks.publish.dependsOn(tasks.modrinth)
}
if (curseForgeProjectId.size() != 0 && System.getenv("CURSEFORGE_TOKEN") != null) {
apply plugin: 'com.matthewprenger.cursegradle'
File changelogFile = new File(System.getenv("CHANGELOG_FILE") ?: "CHANGELOG.md")
curseforge {
apiKey = System.getenv("CURSEFORGE_TOKEN")
project {
id = curseForgeProjectId
if (changelogFile.exists()) {
changelogType = "markdown"
changelog = changelogFile
}
releaseType = identifiedVersion.endsWith("-pre") ? "beta" : "release"
addGameVersion minecraftVersion
addGameVersion "Forge"
mainArtifact jar
for (artifact in getSecondaryArtifacts()) addArtifact artifact
}
options {
javaIntegration = false
forgeGradleIntegration = false
debug = false
}
}
if (curseForgeRelations.size() != 0) {
String[] deps = curseForgeRelations.split(";")
deps.each { dep ->
if (dep.size() == 0) {
return
}
String[] parts = dep.split(":")
addCurseForgeRelation(parts[0], parts[1])
}
}
if (usesMixins.toBoolean()) {
addCurseForgeRelation("requiredDependency", "gtnhmixins")
}
tasks.curseforge.dependsOn(build)
tasks.publish.dependsOn(tasks.curseforge)
}
def addModrinthDep(scope, type, name) {
com.modrinth.minotaur.dependencies.Dependency dep;
if (!(scope in ["required", "optional", "incompatible", "embedded"])) {
throw new Exception("Invalid modrinth dependency scope: " + scope)
}
switch (type) {
case "project":
dep = new ModDependency(name, scope)
break
case "version":
dep = new VersionDependency(name, scope)
break
default:
throw new Exception("Invalid modrinth dependency type: " + type)
}
project.modrinth.dependencies.add(dep)
}
def addCurseForgeRelation(type, name) {
if (!(type in ["requiredDependency", "embeddedLibrary", "optionalDependency", "tool", "incompatible"])) {
throw new Exception("Invalid CurseForge relation type: " + type)
}
CurseArtifact artifact = project.curseforge.curseProjects[0].mainArtifact
CurseRelation rel = (artifact.curseRelations ?: (artifact.curseRelations = new CurseRelation()))
rel."$type"(name)
}
// Updating // Updating
task updateBuildScript { task updateBuildScript {
doLast { doLast {
@@ -621,7 +780,7 @@ task updateBuildScript {
} }
} }
if (isNewBuildScriptVersionAvailable(projectDir.toString())) { if (!project.getGradle().startParameter.isOffline() && isNewBuildScriptVersionAvailable(projectDir.toString())) {
if (autoUpdateBuildScript.toBoolean()) { if (autoUpdateBuildScript.toBoolean()) {
performBuildScriptUpdate(projectDir.toString()) performBuildScriptUpdate(projectDir.toString())
} else { } else {
@@ -630,7 +789,40 @@ if (isNewBuildScriptVersionAvailable(projectDir.toString())) {
} }
static URL availableBuildScriptUrl() { static URL availableBuildScriptUrl() {
new URL("https://raw.githubusercontent.com/GTNewHorizons/ExampleMod1.7.10/main/build.gradle") new URL("https://raw.githubusercontent.com/GTNewHorizons/ExampleMod1.7.10/master/build.gradle")
}
static URL exampleSettingsGradleUrl() {
new URL("https://raw.githubusercontent.com/GTNewHorizons/ExampleMod1.7.10/master/settings.gradle.example")
}
static URL exampleGitAttributesUrl() {
new URL("https://raw.githubusercontent.com/GTNewHorizons/ExampleMod1.7.10/master/.gitattributes")
}
boolean verifyGitAttributes() {
def gitattributesFile = getFile(".gitattributes")
if (!gitattributesFile.exists()) {
println("Downloading default .gitattributes")
exampleGitAttributesUrl().withInputStream { i -> gitattributesFile.withOutputStream { it << i } }
exec {
workingDir '.'
commandLine 'git', 'add', '--renormalize', '.'
}
return true
}
return false
}
boolean verifySettingsGradle() {
def settingsFile = getFile("settings.gradle")
if (!settingsFile.exists()) {
println("Downloading default settings.gradle")
exampleSettingsGradleUrl().withInputStream { i -> settingsFile.withOutputStream { it << i } }
return true
}
return false
} }
boolean performBuildScriptUpdate(String projectDir) { boolean performBuildScriptUpdate(String projectDir) {
@@ -638,6 +830,10 @@ boolean performBuildScriptUpdate(String projectDir) {
def buildscriptFile = getFile("build.gradle") def buildscriptFile = getFile("build.gradle")
availableBuildScriptUrl().withInputStream { i -> buildscriptFile.withOutputStream { it << i } } availableBuildScriptUrl().withInputStream { i -> buildscriptFile.withOutputStream { it << i } }
out.style(Style.Success).print("Build script updated. Please REIMPORT the project or RESTART your IDE!") out.style(Style.Success).print("Build script updated. Please REIMPORT the project or RESTART your IDE!")
boolean settingsupdated = verifySettingsGradle()
settingsupdated = verifyGitAttributes() || settingsupdated
if (settingsupdated)
throw new GradleException("Settings has been updated, please re-run task.")
return true return true
} }
return false return false
@@ -657,7 +853,7 @@ boolean isNewBuildScriptVersionAvailable(String projectDir) {
static String getVersionHash(String buildScriptContent) { static String getVersionHash(String buildScriptContent) {
String versionLine = buildScriptContent.find("^//version: [a-z0-9]*") String versionLine = buildScriptContent.find("^//version: [a-z0-9]*")
if(versionLine != null) { if (versionLine != null) {
return versionLine.split(": ").last() return versionLine.split(": ").last()
} }
return "" return ""
@@ -668,7 +864,103 @@ configure(updateBuildScript) {
description = 'Updates the build script to the latest version' description = 'Updates the build script to the latest version'
} }
// Deobfuscation // Parameter Deobfuscation
task deobfParams {
doLast {
String mcpDir = "$project.gradle.gradleUserHomeDir/caches/minecraft/de/oceanlabs/mcp/mcp_$channel/$mappingsVersion"
String mcpZIP = "$mcpDir/mcp_$channel-$mappingsVersion-${minecraftVersion}.zip"
String paramsCSV = "$mcpDir/params.csv"
download.run {
src "https://maven.minecraftforge.net/de/oceanlabs/mcp/mcp_$channel/$mappingsVersion-$minecraftVersion/mcp_$channel-$mappingsVersion-${minecraftVersion}.zip"
dest mcpZIP
overwrite false
}
if (!file(paramsCSV).exists()) {
println("Extracting MCP archive ...")
unzip(mcpZIP, mcpDir)
}
println("Parsing params.csv ...")
Map<String, String> params = new HashMap<>()
Files.lines(Paths.get(paramsCSV)).forEach { line ->
String[] cells = line.split(",")
if (cells.length > 2 && cells[0].matches("p_i?\\d+_\\d+_")) {
params.put(cells[0], cells[1])
}
}
out.style(Style.Success).println("Modified ${replaceParams(file("$projectDir/src/main/java"), params)} files!")
out.style(Style.Failure).println("Don't forget to verify that the code still works as before!\n It could be broken due to duplicate variables existing now\n or parameters taking priority over other variables.")
}
}
static int replaceParams(File file, Map<String, String> params) {
int fileCount = 0
if (file.isDirectory()) {
for (File f : file.listFiles()) {
fileCount += replaceParams(f, params)
}
return fileCount
}
println("Visiting ${file.getName()} ...")
try {
String content = new String(Files.readAllBytes(file.toPath()))
int hash = content.hashCode()
params.forEach { key, value ->
content = content.replaceAll(key, value)
}
if (hash != content.hashCode()) {
Files.write(file.toPath(), content.getBytes("UTF-8"))
return 1
}
} catch (Exception e) {
e.printStackTrace()
}
return 0
}
// Credit: bitsnaps (https://gist.github.com/bitsnaps/00947f2dce66f4bbdabc67d7e7b33681)
static unzip(String zipFileName, String outputDir) {
byte[] buffer = new byte[16384]
ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFileName))
ZipEntry zipEntry = zis.getNextEntry()
while (zipEntry != null) {
File newFile = new File(outputDir + File.separator, zipEntry.name)
if (zipEntry.isDirectory()) {
if (!newFile.isDirectory() && !newFile.mkdirs()) {
throw new IOException("Failed to create directory $newFile")
}
} else {
// fix for Windows-created archives
File parent = newFile.parentFile
if (!parent.isDirectory() && !parent.mkdirs()) {
throw new IOException("Failed to create directory $parent")
}
// write file content
FileOutputStream fos = new FileOutputStream(newFile)
int len = 0
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len)
}
fos.close()
}
zipEntry = zis.getNextEntry()
}
zis.closeEntry()
zis.close()
}
configure(deobfParams) {
group = 'forgegradle'
description = 'Rename all obfuscated parameter names inherited from Minecraft classes'
}
// Dependency Deobfuscation
def deobf(String sourceURL) { def deobf(String sourceURL) {
try { try {
@@ -677,42 +969,57 @@ def deobf(String sourceURL) {
//get rid of directories: //get rid of directories:
int lastSlash = fileName.lastIndexOf("/") int lastSlash = fileName.lastIndexOf("/")
if(lastSlash > 0) { if (lastSlash > 0) {
fileName = fileName.substring(lastSlash + 1) fileName = fileName.substring(lastSlash + 1)
} }
//get rid of extension: //get rid of extension:
if(fileName.endsWith(".jar")) { if (fileName.endsWith(".jar") || fileName.endsWith(".litemod")) {
fileName = fileName.substring(0, fileName.lastIndexOf(".")) fileName = fileName.substring(0, fileName.lastIndexOf("."))
} }
String hostName = url.getHost() String hostName = url.getHost()
if(hostName.startsWith("www.")) { if (hostName.startsWith("www.")) {
hostName = hostName.substring(4) hostName = hostName.substring(4)
} }
List parts = Arrays.asList(hostName.split("\\.")) List parts = Arrays.asList(hostName.split("\\."))
Collections.reverse(parts) Collections.reverse(parts)
hostName = String.join(".", parts) hostName = String.join(".", parts)
return deobf(sourceURL, hostName + "/" + fileName) return deobf(sourceURL, "$hostName/$fileName")
} catch(Exception e) { } catch (Exception e) {
return deobf(sourceURL, "deobf/" + String.valueOf(sourceURL.hashCode())) return deobf(sourceURL, "deobf/${sourceURL.hashCode()}")
} }
} }
// The method above is to be preferred. Use this method if the filename is not at the end of the URL. // The method above is to be preferred. Use this method if the filename is not at the end of the URL.
def deobf(String sourceURL, String fileName) { def deobf(String sourceURL, String rawFileName) {
String cacheDir = System.getProperty("user.home") + "/.gradle/caches/" String bon2Version = "2.5.1"
String bon2Dir = cacheDir + "forge_gradle/deobf" String fileName = URLDecoder.decode(rawFileName, "UTF-8")
String bon2File = bon2Dir + "/BON2-2.5.0.jar" String cacheDir = "$project.gradle.gradleUserHomeDir/caches"
String obfFile = cacheDir + "modules-2/files-2.1/" + fileName + ".jar" String bon2Dir = "$cacheDir/forge_gradle/deobf"
String deobfFile = cacheDir + "modules-2/files-2.1/" + fileName + "-deobf.jar" String bon2File = "$bon2Dir/BON2-${bon2Version}.jar"
String obfFile = "$cacheDir/modules-2/files-2.1/${fileName}.jar"
String deobfFile = "$cacheDir/modules-2/files-2.1/${fileName}-deobf.jar"
if(file(deobfFile).exists()) { if (file(deobfFile).exists()) {
return files(deobfFile) return files(deobfFile)
} }
String mappingsVer
String remoteMappings = project.hasProperty('remoteMappings') ? project.remoteMappings : 'https://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/'
if (remoteMappings) {
String id = "${forgeVersion.split("\\.")[3]}-$minecraftVersion"
String mappingsZIP = "$cacheDir/forge_gradle/maven_downloader/de/oceanlabs/mcp/mcp_snapshot_nodoc/$id/mcp_snapshot_nodoc-${id}.zip"
zipMappings(mappingsZIP, remoteMappings, bon2Dir)
mappingsVer = "snapshot_$id"
} else {
mappingsVer = "${channel}_$mappingsVersion"
}
download.run { download.run {
src 'https://github.com/GTNewHorizons/BON2/releases/download/2.5.0/BON2-2.5.0.CUSTOM-all.jar' src "http://jenkins.usrv.eu:8081/nexus/content/repositories/releases/com/github/parker8283/BON2/$bon2Version-CUSTOM/BON2-$bon2Version-CUSTOM-all.jar"
dest bon2File dest bon2File
quiet true quiet true
overwrite false overwrite false
@@ -726,14 +1033,48 @@ def deobf(String sourceURL, String fileName) {
} }
exec { exec {
commandLine 'java', '-jar', bon2File, '--inputJar', obfFile, '--outputJar', deobfFile, '--mcVer', '1.7.10', '--mappingsVer', 'stable_12', '--notch' commandLine 'java', '-jar', bon2File, '--inputJar', obfFile, '--outputJar', deobfFile, '--mcVer', minecraftVersion, '--mappingsVer', mappingsVer, '--notch'
workingDir bon2Dir workingDir bon2Dir
standardOutput = new ByteArrayOutputStream() standardOutput = new FileOutputStream("${deobfFile}.log")
} }
return files(deobfFile) return files(deobfFile)
} }
def zipMappings(String zipPath, String url, String bon2Dir) {
File zipFile = new File(zipPath)
if (zipFile.exists()) {
return
}
String fieldsCache = "$bon2Dir/data/fields.csv"
String methodsCache = "$bon2Dir/data/methods.csv"
download.run {
src "${url}fields.csv"
dest fieldsCache
quiet true
}
download.run {
src "${url}methods.csv"
dest methodsCache
quiet true
}
zipFile.getParentFile().mkdirs()
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))
zos.putNextEntry(new ZipEntry("fields.csv"))
Files.copy(Paths.get(fieldsCache), zos)
zos.closeEntry()
zos.putNextEntry(new ZipEntry("methods.csv"))
Files.copy(Paths.get(methodsCache), zos)
zos.closeEntry()
zos.close()
}
// Helper methods // Helper methods
def checkPropertyExists(String propertyName) { def checkPropertyExists(String propertyName) {
@@ -742,6 +1083,21 @@ def checkPropertyExists(String propertyName) {
} }
} }
def propertyDefaultIfUnset(String propertyName, defaultValue) {
if (!project.hasProperty(propertyName) || project.property(propertyName) == "") {
project.ext.setProperty(propertyName, defaultValue)
}
}
def getFile(String relativePath) { def getFile(String relativePath) {
return new File(projectDir, relativePath) return new File(projectDir, relativePath)
} }
def getSecondaryArtifacts() {
// Because noPublishedSources from the beginning of the script is somehow not visible here...
boolean noPublishedSources = project.hasProperty("noPublishedSources") ? project.noPublishedSources.toBoolean() : false
def secondaryArtifacts = [devJar]
if (!noPublishedSources) secondaryArtifacts += [sourcesJar]
if (apiPackage) secondaryArtifacts += [apiJar]
return secondaryArtifacts
}
+10
View File
@@ -0,0 +1,10 @@
plugins {
id 'com.diffplug.blowdryerSetup' version '1.6.0'
}
apply plugin: 'com.diffplug.blowdryerSetup'
blowdryerSetup {
github('GTNewHorizons/ExampleMod1.7.10', 'tag', '0.1.5')
//devLocal '.' // Use this when testing config updates locally
}