Files
AE2FluidCraft-Rework/build.gradle
T
chill d5b8ef6ea9 Code cleanup (#133)
* gradle updateBuildScript

* fix comments and commented-out code

Code deletion, converting comments into javadocs, and refactoring code to not
need comments.

* remove redundant suppressions

* replace C-style array declaration with Java-style

* make private field final

* remove unnecessary semicolon

* extract a common part from an if

* simplify boolean expression

* simplify ternary if

* remove unused imports

* convert escaped characters for clarity

* replace while with for

* replace explicit types with diamond operators

* replace anonymous type with lambda

* enable modern Java syntax

* migrate to enhanced switch

* migrate to pattern variables for instanceof

* remove empty javadoc

* add Nonnull annotation to overrides of Nonnull methods

* replace wailaStack with null

When wailaStack is not null, the flow breaks out of the loop,
so there's no need to confuse the reader with putting wailaStack
both as the result and the parameter of the call - there's no
recursion.

* int cannot be bigger than its max value

* suppress dataflow warning

* remove redundant initializer

The default value of int is 0.

* null check is covered by instanceof

* simplify some calls of addVertexWithUV

* fix typos and add TODOs

* make flipState more understandable
2023-06-18 23:29:57 +02:00

1513 lines
58 KiB
Groovy

//version: 1685785062
/*
DO NOT CHANGE THIS FILE!
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.
*/
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.gtnewhorizons.retrofuturagradle.ObfuscationAttribute
import com.gtnewhorizons.retrofuturagradle.mcp.ReobfuscatedJar
import com.gtnewhorizons.retrofuturagradle.minecraft.RunMinecraftTask
import com.gtnewhorizons.retrofuturagradle.util.Distribution
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.StyledTextOutputFactory
import org.gradle.internal.xml.XmlTransformer
import org.jetbrains.gradle.ext.Application
import org.jetbrains.gradle.ext.Gradle
import javax.inject.Inject
import java.nio.file.Files
import java.nio.file.Paths
import java.util.concurrent.TimeUnit
buildscript {
repositories {
mavenCentral()
maven {
name 'forge'
url 'https://maven.minecraftforge.net'
}
maven {
// GTNH RetroFuturaGradle and ASM Fork
name "GTNH Maven"
url "http://jenkins.usrv.eu:8081/nexus/content/groups/public/"
allowInsecureProtocol = true
}
maven {
name 'sonatype'
url 'https://oss.sonatype.org/content/repositories/snapshots/'
}
maven {
name 'Scala CI dependencies'
url 'https://repo1.maven.org/maven2/'
}
mavenLocal()
}
}
plugins {
id 'java-library'
id "org.jetbrains.gradle.plugin.idea-ext" version "1.1.7"
id 'eclipse'
id 'scala'
id 'maven-publish'
id 'org.jetbrains.kotlin.jvm' version '1.8.0' apply false
id 'org.jetbrains.kotlin.kapt' version '1.8.0' apply false
id 'com.google.devtools.ksp' version '1.8.0-1.0.9' apply false
id 'org.ajoberstar.grgit' version '4.1.1' // 4.1.1 is the last jvm8 supporting version, unused, available for addon.gradle
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false
id 'com.palantir.git-version' version '3.0.0' apply false
id 'de.undercouch.download' version '5.4.0'
id 'com.github.gmazzo.buildconfig' version '3.1.0' apply false // Unused, available for addon.gradle
id 'com.diffplug.spotless' version '6.13.0' apply false // 6.13.0 is the last jvm8 supporting version
id 'com.modrinth.minotaur' version '2.+' apply false
id 'com.matthewprenger.cursegradle' version '1.4.0' apply false
id 'com.gtnewhorizons.retrofuturagradle' version '1.3.14'
}
print("You might want to check out './gradlew :faq' if your build fails.\n")
boolean settingsupdated = verifySettingsGradle()
settingsupdated = verifyGitAttributes() || settingsupdated
if (settingsupdated)
throw new GradleException("Settings has been updated, please re-run task.")
// In submodules, .git is a file pointing to the real git dir
if (project.file('.git/HEAD').isFile() || project.file('.git').isFile()) {
apply plugin: 'com.palantir.git-version'
}
def out = services.get(StyledTextOutputFactory).create('an-output')
def projectJavaVersion = JavaLanguageVersion.of(8)
boolean disableSpotless = project.hasProperty("disableSpotless") ? project.disableSpotless.toBoolean() : false
checkPropertyExists("modName")
checkPropertyExists("modId")
checkPropertyExists("modGroup")
checkPropertyExists("autoUpdateBuildScript")
checkPropertyExists("minecraftVersion")
checkPropertyExists("forgeVersion")
checkPropertyExists("replaceGradleTokenInFile")
checkPropertyExists("gradleTokenVersion")
checkPropertyExists("apiPackage")
checkPropertyExists("accessTransformersFile")
checkPropertyExists("usesMixins")
checkPropertyExists("mixinPlugin")
checkPropertyExists("mixinsPackage")
checkPropertyExists("coreModClass")
checkPropertyExists("containsMixinsAndOrCoreModOnly")
checkPropertyExists("usesShadowedDependencies")
checkPropertyExists("developmentEnvironmentUserName")
propertyDefaultIfUnset("generateGradleTokenClass", "")
propertyDefaultIfUnset("includeWellKnownRepositories", true)
propertyDefaultIfUnset("noPublishedSources", false)
propertyDefaultIfUnset("usesMixinDebug", project.usesMixins)
propertyDefaultIfUnset("forceEnableMixins", false)
propertyDefaultIfUnset("channel", "stable")
propertyDefaultIfUnset("mappingsVersion", "12")
propertyDefaultIfUnset("modrinthProjectId", "")
propertyDefaultIfUnset("modrinthRelations", "")
propertyDefaultIfUnset("curseForgeProjectId", "")
propertyDefaultIfUnset("curseForgeRelations", "")
propertyDefaultIfUnset("minimizeShadowedDependencies", true)
propertyDefaultIfUnset("relocateShadowedDependencies", true)
// Deprecated properties (kept for backwards compat)
propertyDefaultIfUnset("gradleTokenModId", "")
propertyDefaultIfUnset("gradleTokenModName", "")
propertyDefaultIfUnset("gradleTokenGroupName", "")
propertyDefaultIfUnset("enableModernJavaSyntax", false) // On by default for new projects only
propertyDefaultIfUnset("enableGenericInjection", false) // On by default for new projects only
// this is meant to be set using the user wide property file. by default we do nothing.
propertyDefaultIfUnset("ideaOverrideBuildType", "") // Can be nothing, "gradle" or "idea"
project.extensions.add(com.diffplug.blowdryer.Blowdryer, "Blowdryer", com.diffplug.blowdryer.Blowdryer) // Make blowdryer available in "apply from:" scripts
if (!disableSpotless) {
apply plugin: 'com.diffplug.spotless'
apply from: Blowdryer.file('spotless.gradle')
}
String javaSourceDir = "src/main/java/"
String scalaSourceDir = "src/main/scala/"
String kotlinSourceDir = "src/main/kotlin/"
if (usesShadowedDependencies.toBoolean()) {
apply plugin: "com.github.johnrengelman.shadow"
}
java {
toolchain {
if (enableModernJavaSyntax.toBoolean()) {
languageVersion.set(JavaLanguageVersion.of(17))
} else {
languageVersion.set(projectJavaVersion)
}
vendor.set(JvmVendorSpec.AZUL)
}
if (!noPublishedSources) {
withSourcesJar()
}
}
tasks.withType(JavaCompile).configureEach {
options.encoding = "UTF-8"
}
tasks.withType(ScalaCompile).configureEach {
options.encoding = "UTF-8"
}
pluginManager.withPlugin('org.jetbrains.kotlin.jvm') {
// If Kotlin is enabled in the project
kotlin {
jvmToolchain(8)
}
// Kotlin hacks our source sets, so we hack Kotlin's tasks
def disabledKotlinTaskList = [
"kaptGenerateStubsMcLauncherKotlin",
"kaptGenerateStubsPatchedMcKotlin",
"kaptGenerateStubsInjectedTagsKotlin",
"compileMcLauncherKotlin",
"compilePatchedMcKotlin",
"compileInjectedTagsKotlin",
"kaptMcLauncherKotlin",
"kaptPatchedMcKotlin",
"kaptInjectedTagsKotlin",
"kspMcLauncherKotlin",
"kspPatchedMcKotlin",
"kspInjectedTagsKotlin",
]
tasks.configureEach { task ->
if (task.name in disabledKotlinTaskList) {
task.enabled = false
}
}
}
configurations {
create("runtimeOnlyNonPublishable") {
description = "Runtime only dependencies that are not published alongside the jar"
canBeConsumed = false
canBeResolved = false
}
create("devOnlyNonPublishable") {
description = "Runtime and compiletime dependencies that are not published alongside the jar (compileOnly + runtimeOnlyNonPublishable)"
canBeConsumed = false
canBeResolved = false
}
compileOnly.extendsFrom(devOnlyNonPublishable)
runtimeOnlyNonPublishable.extendsFrom(devOnlyNonPublishable)
}
if (enableModernJavaSyntax.toBoolean()) {
repositories {
mavenCentral {
mavenContent {
includeGroup("me.eigenraven.java8unsupported")
}
}
}
dependencies {
annotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:1.0.0'
// workaround for https://github.com/bsideup/jabel/issues/174
annotationProcessor 'net.java.dev.jna:jna-platform:5.13.0'
compileOnly('com.github.bsideup.jabel:jabel-javac-plugin:1.0.0') {
transitive = false // We only care about the 1 annotation class
}
// Allow using jdk.unsupported classes like sun.misc.Unsafe in the compiled code, working around JDK-8206937.
patchedMinecraft('me.eigenraven.java8unsupported:java-8-unsupported-shim:1.0.0')
}
tasks.withType(JavaCompile).configureEach {
if (it.name in ["compileMcLauncherJava", "compilePatchedMcJava"]) {
return
}
sourceCompatibility = 17 // for the IDE support
options.release.set(8)
javaCompiler.set(javaToolchains.compilerFor {
languageVersion.set(JavaLanguageVersion.of(17))
vendor.set(JvmVendorSpec.AZUL)
})
}
}
eclipse {
classpath {
downloadSources = true
downloadJavadoc = true
}
}
final String modGroupPath = modGroup.toString().replace('.' as char, '/' as char)
final String apiPackagePath = apiPackage.toString().replace('.' as char, '/' as char)
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)
}
if (apiPackage) {
targetPackageJava = javaSourceDir + modGroupPath + "/" + apiPackagePath
targetPackageScala = scalaSourceDir + modGroupPath + "/" + apiPackagePath
targetPackageKotlin = kotlinSourceDir + modGroupPath + "/" + apiPackagePath
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)
}
}
if (accessTransformersFile) {
for (atFile in accessTransformersFile.split(",")) {
String targetFile = "src/main/resources/META-INF/" + atFile.trim()
if (!getFile(targetFile).exists()) {
throw new GradleException("Could not resolve \"accessTransformersFile\"! Could not find " + targetFile)
}
tasks.deobfuscateMergedJarToSrg.accessTransformerFiles.from(targetFile)
tasks.srgifyBinpatchedJar.accessTransformerFiles.from(targetFile)
}
} else {
boolean atsFound = false
for (File at : sourceSets.getByName("main").resources.files) {
if (at.name.toLowerCase().endsWith("_at.cfg")) {
atsFound = true
tasks.deobfuscateMergedJarToSrg.accessTransformerFiles.from(at)
tasks.srgifyBinpatchedJar.accessTransformerFiles.from(at)
}
}
for (File at : sourceSets.getByName("api").resources.files) {
if (at.name.toLowerCase().endsWith("_at.cfg")) {
atsFound = true
tasks.deobfuscateMergedJarToSrg.accessTransformerFiles.from(at)
tasks.srgifyBinpatchedJar.accessTransformerFiles.from(at)
}
}
if (atsFound) {
logger.warn("Found and added access transformers in the resources folder, please configure gradle.properties to explicitly mention them by name")
}
}
if (usesMixins.toBoolean()) {
if (mixinsPackage.isEmpty()) {
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)
}
if (!mixinPlugin.isEmpty()) {
String targetFileJava = javaSourceDir + modGroupPath + "/" + mixinPluginPath + ".java"
String targetFileScala = scalaSourceDir + modGroupPath + "/" + mixinPluginPath + ".scala"
String targetFileScalaJava = scalaSourceDir + modGroupPath + "/" + mixinPluginPath + ".java"
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)
}
}
}
if (coreModClass) {
final String coreModPath = coreModClass.toString().replaceAll("\\.", "/")
String targetFileJava = javaSourceDir + modGroupPath + "/" + coreModPath + ".java"
String targetFileScala = scalaSourceDir + modGroupPath + "/" + coreModPath + ".scala"
String targetFileScalaJava = scalaSourceDir + modGroupPath + "/" + coreModPath + ".java"
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)
}
}
configurations.configureEach {
resolutionStrategy.cacheChangingModulesFor(0, TimeUnit.SECONDS)
// Make sure GregTech build won't time out
System.setProperty("org.gradle.internal.http.connectionTimeout", 120000 as String)
System.setProperty("org.gradle.internal.http.socketTimeout", 120000 as String)
}
// Fix Jenkins' Git: chmod a file should not be detected as a change and append a '.dirty' to the version
try {
'git config core.fileMode false'.execute()
}
catch (Exception ignored) {
out.style(Style.Failure).println("git isn't installed at all")
}
// Pulls version first from the VERSION env and then git tag
String identifiedVersion
String versionOverride = System.getenv("VERSION") ?: null
try {
identifiedVersion = versionOverride == null ? gitVersion() : versionOverride
}
catch (Exception ignored) {
out.style(Style.Failure).text(
'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' +
'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'
identifiedVersion = versionOverride
}
version = identifiedVersion
ext {
modVersion = identifiedVersion
}
if (identifiedVersion == versionOverride) {
out.style(Style.Failure).text('Override version to ').style(Style.Identifier).text(modVersion).style(Style.Failure).println('!\7')
}
group = "com.github.GTNewHorizons"
if (project.hasProperty("customArchiveBaseName") && customArchiveBaseName) {
archivesBaseName = customArchiveBaseName
} else {
archivesBaseName = modId
}
minecraft {
if (replaceGradleTokenInFile) {
for (f in replaceGradleTokenInFile.split(',')) {
tagReplacementFiles.add f
}
}
if (gradleTokenModId) {
injectedTags.put gradleTokenModId, modId
}
if (gradleTokenModName) {
injectedTags.put gradleTokenModName, modName
}
if (gradleTokenVersion) {
injectedTags.put gradleTokenVersion, modVersion
}
if (gradleTokenGroupName) {
injectedTags.put gradleTokenGroupName, modGroup
}
if (enableGenericInjection.toBoolean()) {
injectMissingGenerics.set(true)
}
username = developmentEnvironmentUserName.toString()
lwjgl3Version = "3.3.2"
// Enable assertions in the current mod
extraRunJvmArguments.add("-ea:${modGroup}")
if (usesMixins.toBoolean() || forceEnableMixins.toBoolean()) {
if (usesMixinDebug.toBoolean()) {
extraRunJvmArguments.addAll([
"-Dmixin.debug.countInjections=true",
"-Dmixin.debug.verbose=true",
"-Dmixin.debug.export=true"
])
}
}
// Blowdryer is present in some old mod builds, do not propagate it further as a dependency
// IC2 has no reobf jars in its Maven
groupsToExcludeFromAutoReobfMapping.addAll(["com.diffplug", "com.diffplug.durian", "net.industrial-craft"])
}
if (generateGradleTokenClass) {
tasks.injectTags.outputClassName.set(generateGradleTokenClass)
}
// Custom reobf auto-mappings
configurations.configureEach {
dependencies.configureEach { dep ->
if (dep instanceof org.gradle.api.artifacts.ExternalModuleDependency) {
if (dep.group == "net.industrial-craft" && dep.name == "industrialcraft-2") {
// https://www.curseforge.com/minecraft/mc-mods/industrial-craft/files/2353971
project.dependencies.reobfJarConfiguration("curse.maven:ic2-242638:2353971")
}
}
}
def obfuscationAttr = it.attributes.getAttribute(ObfuscationAttribute.OBFUSCATION_ATTRIBUTE)
if (obfuscationAttr != null && obfuscationAttr.name == ObfuscationAttribute.SRG) {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
// Remap CoFH core cursemaven dev jar to the obfuscated version for runObfClient/Server
if (details.requested.group == 'curse.maven' && details.requested.name.endsWith('-69162') && details.requested.version == '2388751') {
details.useVersion '2388750'
details.because 'Pick obfuscated jar'
}
}
}
}
// Ensure tests have access to minecraft classes
sourceSets {
test {
java {
compileClasspath += sourceSets.patchedMc.output + sourceSets.mcLauncher.output
runtimeClasspath += sourceSets.patchedMc.output + sourceSets.mcLauncher.output
}
}
}
if (file('addon.gradle').exists()) {
apply from: 'addon.gradle'
}
// Allow unsafe repos but warn
repositories.configureEach { repo ->
if (repo instanceof org.gradle.api.artifacts.repositories.UrlArtifactRepository) {
if (repo.getUrl() != null && repo.getUrl().getScheme() == "http" && !repo.allowInsecureProtocol) {
logger.warn("Deprecated: Allowing insecure connections for repo '${repo.name}' - add 'allowInsecureProtocol = true'")
repo.allowInsecureProtocol = true
}
}
}
apply from: 'repositories.gradle'
configurations {
runtimeClasspath.extendsFrom(runtimeOnlyNonPublishable)
testRuntimeClasspath.extendsFrom(runtimeOnlyNonPublishable)
for (config in [compileClasspath, runtimeClasspath, testCompileClasspath, testRuntimeClasspath]) {
if (usesShadowedDependencies.toBoolean()) {
config.extendsFrom(shadowImplementation)
// TODO: remove Compile after all uses are refactored to Implementation
config.extendsFrom(shadeCompile)
config.extendsFrom(shadowCompile)
}
}
// A "bag-of-dependencies"-style configuration for backwards compatibility, gets put in "api"
create("compile") {
description = "Deprecated: use api or implementation instead, gets put in api"
canBeConsumed = false
canBeResolved = false
visible = false
}
create("testCompile") {
description = "Deprecated: use testImplementation instead"
canBeConsumed = false
canBeResolved = false
visible = false
}
api.extendsFrom(compile)
testImplementation.extendsFrom(testCompile)
}
afterEvaluate {
if (!configurations.compile.allDependencies.empty || !configurations.testCompile.allDependencies.empty) {
logger.warn("This project uses deprecated `compile` dependencies, please migrate to using `api` and `implementation`")
logger.warn("For more details, see https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/master/dependencies.gradle")
}
}
repositories {
maven {
name 'Overmind forge repo mirror'
url 'https://gregtech.overminddl1.com/'
mavenContent {
excludeGroup("net.minecraftforge") // missing the `universal` artefact
}
}
maven {
name = "GTNH Maven"
url = "http://jenkins.usrv.eu:8081/nexus/content/groups/public/"
allowInsecureProtocol = true
}
maven {
name 'sonatype'
url 'https://oss.sonatype.org/content/repositories/snapshots/'
content {
includeGroup "org.lwjgl"
}
}
if (includeWellKnownRepositories.toBoolean()) {
maven {
name "CurseMaven"
url "https://cursemaven.com"
content {
includeGroup "curse.maven"
}
}
maven {
name = "ic2"
url = "https://maven.ic2.player.to/"
metadataSources {
mavenPom()
artifact()
}
}
maven {
name = "ic2-mirror"
url = "https://maven2.ic2.player.to/"
metadataSources {
mavenPom()
artifact()
}
}
maven {
name "MMD Maven"
url "https://maven.mcmoddev.com/"
}
}
}
def mixinProviderGroup = "io.github.legacymoddingmc"
def mixinProviderModule = "unimixins"
def mixinProviderVersion = "0.1.7.1"
def mixinProviderSpecNoClassifer = "${mixinProviderGroup}:${mixinProviderModule}:${mixinProviderVersion}"
def mixinProviderSpec = "${mixinProviderSpecNoClassifer}:dev"
ext.mixinProviderSpec = mixinProviderSpec
dependencies {
if (usesMixins.toBoolean()) {
annotationProcessor('org.ow2.asm:asm-debug-all:5.0.3')
annotationProcessor('com.google.guava:guava:24.1.1-jre')
annotationProcessor('com.google.code.gson:gson:2.8.6')
annotationProcessor(mixinProviderSpec)
if (usesMixinDebug.toBoolean()) {
runtimeOnlyNonPublishable('org.jetbrains:intellij-fernflower:1.2.1.16')
}
}
if (usesMixins.toBoolean()) {
implementation(mixinProviderSpec)
} else if (forceEnableMixins.toBoolean()) {
runtimeOnlyNonPublishable(mixinProviderSpec)
}
}
pluginManager.withPlugin('org.jetbrains.kotlin.kapt') {
if (usesMixins.toBoolean()) {
dependencies {
kapt(mixinProviderSpec)
}
}
}
// Replace old mixin mods with unimixins
// https://docs.gradle.org/8.0.2/userguide/resolution_rules.html#sec:substitution_with_classifier
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute module('com.gtnewhorizon:gtnhmixins') using module(mixinProviderSpecNoClassifer) withClassifier("dev") because("Unimixins replaces other mixin mods")
substitute module('com.github.GTNewHorizons:Mixingasm') using module(mixinProviderSpecNoClassifer) withClassifier("dev") because("Unimixins replaces other mixin mods")
substitute module('com.github.GTNewHorizons:SpongePoweredMixin') using module(mixinProviderSpecNoClassifer) withClassifier("dev") because("Unimixins replaces other mixin mods")
substitute module('com.github.GTNewHorizons:SpongeMixins') using module(mixinProviderSpecNoClassifer) withClassifier("dev") because("Unimixins replaces other mixin mods")
substitute module('io.github.legacymoddingmc:unimixins') using module(mixinProviderSpecNoClassifer) withClassifier("dev") because("Our previous unimixins upload was missing the dev classifier")
}
}
apply from: 'dependencies.gradle'
def mixingConfigRefMap = 'mixins.' + modId + '.refmap.json'
def mixinTmpDir = buildDir.path + File.separator + 'tmp' + File.separator + 'mixins'
def refMap = "${mixinTmpDir}" + File.separator + mixingConfigRefMap
def mixinSrg = "${mixinTmpDir}" + File.separator + "mixins.srg"
tasks.register('generateAssets') {
group = "GTNH Buildscript"
description = "Generates a mixin config file at /src/main/resources/mixins.modid.json if needed"
onlyIf { usesMixins.toBoolean() }
doLast {
def mixinConfigFile = getFile("/src/main/resources/mixins." + modId + ".json")
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 = """{
"required": true,
"minVersion": "0.8.5-GTNH",
"package": "${modGroup}.${mixinsPackage}",${mixinPluginLine}
"refmap": "${mixingConfigRefMap}",
"target": "@env(DEFAULT)",
"compatibilityLevel": "JAVA_8",
"mixins": [],
"client": [],
"server": []
}
"""
}
}
}
if (usesMixins.toBoolean()) {
tasks.named("reobfJar", ReobfuscatedJar).configure {
extraSrgFiles.from(mixinSrg)
}
tasks.named("processResources").configure {
dependsOn("generateAssets")
}
tasks.named("compileJava", JavaCompile).configure {
doFirst {
new File(mixinTmpDir).mkdirs()
}
options.compilerArgs += [
"-AreobfSrgFile=${tasks.reobfJar.srg.get().asFile}",
"-AoutSrgFile=${mixinSrg}",
"-AoutRefMapFile=${refMap}",
// Elan: from what I understand they are just some linter configs so you get some warning on how to properly code
"-XDenableSunApiLintControl",
"-XDignore.symbol.file"
]
}
pluginManager.withPlugin('org.jetbrains.kotlin.kapt') {
kapt {
correctErrorTypes = true
javacOptions {
option("-AreobfSrgFile=${tasks.reobfJar.srg.get().asFile}")
option("-AoutSrgFile=$mixinSrg")
option("-AoutRefMapFile=$refMap")
}
}
tasks.configureEach { task ->
if (task.name == "kaptKotlin") {
task.doFirst {
new File(mixinTmpDir).mkdirs()
}
}
}
}
}
tasks.named("processResources", ProcessResources).configure {
// this will ensure that this task is redone when the versions change.
inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.mcVersion
exclude("spotless.gradle")
// replace stuff in mcmod.info, nothing else. replaces ${key} with value in text
filesMatching("mcmod.info") {
expand "minecraftVersion": project.minecraft.mcVersion,
"modVersion": modVersion,
"modId": modId,
"modName": modName
}
if (usesMixins.toBoolean()) {
from refMap
dependsOn("compileJava", "compileScala")
}
}
ext.java17Toolchain = (JavaToolchainSpec spec) -> {
spec.languageVersion.set(JavaLanguageVersion.of(17))
spec.vendor.set(JvmVendorSpec.matching("jetbrains"))
}
ext.java17DependenciesCfg = configurations.create("java17Dependencies") {
extendsFrom(configurations.getByName("runtimeClasspath")) // Ensure consistent transitive dependency resolution
canBeConsumed = false
}
ext.java17PatchDependenciesCfg = configurations.create("java17PatchDependencies") {
canBeConsumed = false
}
dependencies {
def lwjgl3ifyVersion = '1.3.5'
def asmVersion = '9.4'
if (modId != 'lwjgl3ify') {
java17Dependencies("com.github.GTNewHorizons:lwjgl3ify:${lwjgl3ifyVersion}")
}
if (modId != 'hodgepodge') {
java17Dependencies('com.github.GTNewHorizons:Hodgepodge:2.2.13')
}
java17PatchDependencies('net.minecraft:launchwrapper:1.15') {transitive = false}
java17PatchDependencies("org.ow2.asm:asm:${asmVersion}")
java17PatchDependencies("org.ow2.asm:asm-commons:${asmVersion}")
java17PatchDependencies("org.ow2.asm:asm-tree:${asmVersion}")
java17PatchDependencies("org.ow2.asm:asm-analysis:${asmVersion}")
java17PatchDependencies("org.ow2.asm:asm-util:${asmVersion}")
java17PatchDependencies('org.ow2.asm:asm-deprecated:7.1')
java17PatchDependencies("org.apache.commons:commons-lang3:3.12.0")
java17PatchDependencies("com.github.GTNewHorizons:lwjgl3ify:${lwjgl3ifyVersion}:forgePatches") {transitive = false}
}
ext.java17JvmArgs = [
// Java 9+ support
"--illegal-access=warn",
"-Djava.security.manager=allow",
"-Dfile.encoding=UTF-8",
"--add-opens", "java.base/jdk.internal.loader=ALL-UNNAMED",
"--add-opens", "java.base/java.net=ALL-UNNAMED",
"--add-opens", "java.base/java.nio=ALL-UNNAMED",
"--add-opens", "java.base/java.io=ALL-UNNAMED",
"--add-opens", "java.base/java.lang=ALL-UNNAMED",
"--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED",
"--add-opens", "java.base/java.text=ALL-UNNAMED",
"--add-opens", "java.base/java.util=ALL-UNNAMED",
"--add-opens", "java.base/jdk.internal.reflect=ALL-UNNAMED",
"--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED",
"--add-opens", "jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED,java.naming",
"--add-opens", "java.desktop/sun.awt.image=ALL-UNNAMED",
"--add-modules", "jdk.dynalink",
"--add-opens", "jdk.dynalink/jdk.dynalink.beans=ALL-UNNAMED",
"--add-modules", "java.sql.rowset",
"--add-opens", "java.sql.rowset/javax.sql.rowset.serial=ALL-UNNAMED"
]
ext.hotswapJvmArgs = [
// DCEVM advanced hot reload
"-XX:+AllowEnhancedClassRedefinition",
"-XX:HotswapAgent=fatjar"
]
ext.setupHotswapAgentTask = tasks.register("setupHotswapAgent") {
group = "GTNH Buildscript"
description = "Installs a recent version of HotSwapAgent into the Java 17 JetBrains runtime directory"
def hsaUrl = 'https://github.com/HotswapProjects/HotswapAgent/releases/download/1.4.2-SNAPSHOT/hotswap-agent-1.4.2-SNAPSHOT.jar'
def targetFolderProvider = javaToolchains.launcherFor(java17Toolchain).map {it.metadata.installationPath.dir("lib/hotswap")}
def targetFilename = "hotswap-agent.jar"
onlyIf {
!targetFolderProvider.get().file(targetFilename).asFile.exists()
}
doLast {
def targetFolder = targetFolderProvider.get()
targetFolder.asFile.mkdirs()
download.run {
src hsaUrl
dest targetFolder.file(targetFilename).asFile
overwrite false
tempAndMove true
}
}
}
public abstract class RunHotswappableMinecraftTask extends RunMinecraftTask {
// IntelliJ doesn't seem to allow commandline arguments so we also support an env variable
private boolean enableHotswap = Boolean.valueOf(System.getenv("HOTSWAP"));
@Input
public boolean getEnableHotswap() { return enableHotswap }
@Option(option = "hotswap", description = "Enables HotSwapAgent for enhanced class reloading under a debugger")
public boolean setEnableHotswap(boolean enable) { enableHotswap = enable }
@Inject
public RunHotswappableMinecraftTask(Distribution side, String superTask, org.gradle.api.invocation.Gradle gradle) {
super(side, gradle)
this.lwjglVersion = 3
this.javaLauncher = project.javaToolchains.launcherFor(project.java17Toolchain)
this.extraJvmArgs.addAll(project.java17JvmArgs)
this.extraJvmArgs.addAll(project.provider(() -> enableHotswap ? project.hotswapJvmArgs : []))
this.classpath(project.java17PatchDependenciesCfg)
if (side == Distribution.CLIENT) {
this.classpath(project.minecraftTasks.lwjgl3Configuration)
}
// Use a raw provider instead of map to not create a dependency on the task
this.classpath(project.provider(() -> project.tasks.named(superTask, RunMinecraftTask).get().classpath))
this.classpath.filter { file ->
!file.path.contains("2.9.4-nightly-20150209") // Remove lwjgl2
}
this.classpath(project.java17DependenciesCfg)
}
public void setup(Project project) {
super.setup(project)
if (project.usesMixins.toBoolean()) {
this.extraJvmArgs.addAll(project.provider(() -> {
def mixinCfg = project.configurations.detachedConfiguration(project.dependencies.create(project.mixinProviderSpec))
mixinCfg.canBeConsumed = false
mixinCfg.transitive = false
enableHotswap ? ["-javaagent:" + mixinCfg.singleFile.absolutePath] : []
}))
}
}
}
def runClient17Task = tasks.register("runClient17", RunHotswappableMinecraftTask, Distribution.CLIENT, "runClient")
runClient17Task.configure {
setup(project)
group = "Modded Minecraft"
description = "Runs the modded client using Java 17, lwjgl3ify and Hodgepodge"
dependsOn(setupHotswapAgentTask, mcpTasks.launcherSources.classesTaskName, minecraftTasks.taskDownloadVanillaAssets, mcpTasks.taskPackagePatchedMc, 'jar')
mainClass = "GradleStart"
username = minecraft.username
userUUID = minecraft.userUUID
}
def runServer17Task = tasks.register("runServer17", RunHotswappableMinecraftTask, Distribution.DEDICATED_SERVER, "runServer")
runServer17Task.configure {
setup(project)
group = "Modded Minecraft"
description = "Runs the modded server using Java 17, lwjgl3ify and Hodgepodge"
dependsOn(setupHotswapAgentTask, mcpTasks.launcherSources.classesTaskName, minecraftTasks.taskDownloadVanillaAssets, mcpTasks.taskPackagePatchedMc, 'jar')
mainClass = "GradleStartServer"
extraArgs.add("nogui")
}
def getManifestAttributes() {
def manifestAttributes = [:]
if (!containsMixinsAndOrCoreModOnly.toBoolean() && (usesMixins.toBoolean() || coreModClass)) {
manifestAttributes += ["FMLCorePluginContainsFMLMod": true]
}
if (accessTransformersFile) {
manifestAttributes += ["FMLAT": accessTransformersFile.toString()]
}
if (coreModClass) {
manifestAttributes += ["FMLCorePlugin": modGroup + "." + coreModClass]
}
if (usesMixins.toBoolean()) {
manifestAttributes += [
"TweakClass" : "org.spongepowered.asm.launch.MixinTweaker",
"MixinConfigs" : "mixins." + modId + ".json",
"ForceLoadAsMod": !containsMixinsAndOrCoreModOnly.toBoolean()
]
}
return manifestAttributes
}
tasks.named("jar", Jar).configure {
manifest {
attributes(getManifestAttributes())
}
}
if (usesShadowedDependencies.toBoolean()) {
tasks.named("shadowJar", ShadowJar).configure {
manifest {
attributes(getManifestAttributes())
}
if (minimizeShadowedDependencies.toBoolean()) {
minimize() // This will only allow shading for actually used classes
}
configurations = [
project.configurations.shadowImplementation,
project.configurations.shadowCompile,
project.configurations.shadeCompile
]
archiveClassifier.set('dev')
if (relocateShadowedDependencies.toBoolean()) {
relocationPrefix = modGroup + ".shadow"
enableRelocation = true
}
}
configurations.runtimeElements.outgoing.artifacts.clear()
configurations.apiElements.outgoing.artifacts.clear()
configurations.runtimeElements.outgoing.artifact(tasks.named("shadowJar", ShadowJar))
configurations.apiElements.outgoing.artifact(tasks.named("shadowJar", ShadowJar))
tasks.named("jar", Jar) {
enabled = false
finalizedBy(tasks.shadowJar)
}
tasks.named("reobfJar", ReobfuscatedJar) {
inputJar.set(tasks.named("shadowJar", ShadowJar).flatMap({it.archiveFile}))
}
AdhocComponentWithVariants javaComponent = (AdhocComponentWithVariants) project.components.findByName("java")
javaComponent.withVariantsFromConfiguration(configurations.shadowRuntimeElements) {
skip()
}
for (runTask in ["runClient", "runServer", "runClient17", "runServer17"]) {
tasks.named(runTask).configure {
dependsOn("shadowJar")
}
}
}
ext.publishableDevJar = usesShadowedDependencies.toBoolean() ? tasks.shadowJar : tasks.jar
ext.publishableObfJar = tasks.reobfJar
tasks.register('apiJar', Jar) {
from(sourceSets.main.allSource) {
include modGroupPath + "/" + apiPackagePath + '/**'
}
from(sourceSets.main.output) {
include modGroupPath + "/" + apiPackagePath + '/**'
}
from(sourceSets.main.resources.srcDirs) {
include("LICENSE")
}
getArchiveClassifier().set('api')
}
artifacts {
if (!noPublishedSources) {
archives tasks.named("sourcesJar")
}
if (apiPackage) {
archives tasks.named("apiJar")
}
}
idea {
module {
downloadJavadoc = true
downloadSources = true
inheritOutputDirs = true
}
project {
settings {
if (ideaOverrideBuildType != "") {
delegateActions {
if ("gradle".equalsIgnoreCase(ideaOverrideBuildType)) {
delegateBuildRunToGradle = true
testRunner = org.jetbrains.gradle.ext.ActionDelegationConfig.TestRunner.GRADLE
} else if ("idea".equalsIgnoreCase(ideaOverrideBuildType)) {
delegateBuildRunToGradle = false
testRunner = org.jetbrains.gradle.ext.ActionDelegationConfig.TestRunner.PLATFORM
} else {
throw GradleScriptException('Accepted value for ideaOverrideBuildType is one of gradle or idea.')
}
}
}
runConfigurations {
"1. Run Client"(Gradle) {
taskNames = ["runClient"]
}
"2. Run Server"(Gradle) {
taskNames = ["runServer"]
}
"1a. Run Client (Java 17)"(Gradle) {
taskNames = ["runClient17"]
}
"2a. Run Server (Java 17)"(Gradle) {
taskNames = ["runServer17"]
}
"1b. Run Client (Java 17, Hotswap)"(Gradle) {
taskNames = ["runClient17"]
envs = ["HOTSWAP": "true"]
}
"2b. Run Server (Java 17, Hotswap)"(Gradle) {
taskNames = ["runServer17"]
envs = ["HOTSWAP": "true"]
}
"3. Run Obfuscated Client"(Gradle) {
taskNames = ["runObfClient"]
}
"4. Run Obfuscated Server"(Gradle) {
taskNames = ["runObfServer"]
}
if (!disableSpotless) {
"5. Apply spotless"(Gradle) {
taskNames = ["spotlessApply"]
}
}
def coreModArgs = ""
if (coreModClass) {
coreModArgs = ' "-Dfml.coreMods.load=' + modGroup + '.' + coreModClass + '"'
}
"Run Client (IJ Native)"(Application) {
mainClass = "GradleStart"
moduleName = project.name + ".ideVirtualMain"
afterEvaluate {
workingDirectory = tasks.runClient.workingDir.absolutePath
programParameters = tasks.runClient.calculateArgs(project).collect { '"' + it + '"' }.join(' ')
jvmArgs = tasks.runClient.calculateJvmArgs(project).collect { '"' + it + '"' }.join(' ') +
' ' + tasks.runClient.systemProperties.collect { '"-D' + it.key + '=' + it.value.toString() + '"' }.join(' ') +
coreModArgs
}
}
"Run Server (IJ Native)"(Application) {
mainClass = "GradleStartServer"
moduleName = project.name + ".ideVirtualMain"
afterEvaluate {
workingDirectory = tasks.runServer.workingDir.absolutePath
programParameters = tasks.runServer.calculateArgs(project).collect { '"' + it + '"' }.join(' ')
jvmArgs = tasks.runServer.calculateJvmArgs(project).collect { '"' + it + '"' }.join(' ') +
' ' + tasks.runServer.systemProperties.collect { '"-D' + it.key + '=' + it.value.toString() + '"' }.join(' ') +
coreModArgs
}
}
}
compiler.javac {
afterEvaluate {
javacAdditionalOptions = "-encoding utf8"
moduleJavacAdditionalOptions = [
(project.name + ".main"): tasks.compileJava.options.compilerArgs.collect { '"' + it + '"' }.join(' ')
]
}
}
withIDEADir { File ideaDir ->
if (!ideaDir.path.contains(".idea")) {
// If an .ipr file exists, the project root directory is passed here instead of the .idea subdirectory
ideaDir = new File(ideaDir, ".idea")
}
if (ideaDir.isDirectory()) {
def miscFile = new File(ideaDir, "misc.xml")
if (miscFile.isFile()) {
boolean dirty = false
def miscTransformer = new XmlTransformer()
miscTransformer.addAction { root ->
Node rootNode = root.asNode()
def rootManager = rootNode
.component.find { it.@name == 'ProjectRootManager' }
if (!rootManager) {
rootManager = rootNode.appendNode('component', ['name': 'ProjectRootManager', 'version': '2'])
dirty = true
}
def output = rootManager.output
if (!output) {
output = rootManager.appendNode('output')
dirty = true
}
if (!output.@url) {
// Only modify the output url if it doesn't yet have one, or if the existing one is blank somehow.
// This is a sensible default for most setups
output.@url = 'file://$PROJECT_DIR$/build/ideaBuild'
dirty = true
}
}
def result = miscTransformer.transform(miscFile.text)
if (dirty) {
miscFile.write(result)
}
} else {
miscFile.text = """<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2">
<output url="file://\$PROJECT_DIR\$/out" />
</component>
</project>
"""
}
}
}
}
}
}
tasks.named("processIdeaSettings").configure {
dependsOn("injectTags")
}
// workaround variable hiding in pom processing
def projectConfigs = project.configurations
publishing {
publications {
create("maven", MavenPublication) {
from components.java
if (apiPackage) {
artifact apiJar
}
groupId = System.getenv("ARTIFACT_GROUP_ID") ?: project.group
artifactId = System.getenv("ARTIFACT_ID") ?: project.name
// Using the identified version, not project.version as it has the prepended 1.7.10
version = System.getenv("RELEASE_VERSION") ?: identifiedVersion
}
}
repositories {
maven {
url = "http://jenkins.usrv.eu:8081/nexus/content/repositories/releases"
allowInsecureProtocol = true
credentials {
username = System.getenv("MAVEN_USER") ?: "NONE"
password = System.getenv("MAVEN_PASSWORD") ?: "NONE"
}
}
}
}
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 = publishableObfJar
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", "project", "unimixins")
}
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 publishableObfJar
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", "unimixins")
}
tasks.curseforge.dependsOn(build)
tasks.publish.dependsOn(tasks.curseforge)
}
def addModrinthDep(String scope, String type, String 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(String type, String 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
def buildscriptGradleVersion = "8.1.1"
tasks.named('wrapper', Wrapper).configure {
gradleVersion = buildscriptGradleVersion
}
tasks.register('updateBuildScript') {
group = 'GTNH Buildscript'
description = 'Updates the build script to the latest version'
if (gradle.gradleVersion != buildscriptGradleVersion && !Boolean.getBoolean('DISABLE_BUILDSCRIPT_GRADLE_UPDATE')) {
dependsOn('wrapper')
}
doLast {
if (performBuildScriptUpdate()) return
print("Build script already up-to-date!")
}
}
if (!project.getGradle().startParameter.isOffline() && !Boolean.getBoolean('DISABLE_BUILDSCRIPT_UPDATE_CHECK') && isNewBuildScriptVersionAvailable()) {
if (autoUpdateBuildScript.toBoolean()) {
performBuildScriptUpdate()
} else {
out.style(Style.SuccessHeader).println("Build script update available! Run 'gradle updateBuildScript'")
if (gradle.gradleVersion != buildscriptGradleVersion) {
out.style(Style.SuccessHeader).println("updateBuildScript can update gradle from ${gradle.gradleVersion} to ${buildscriptGradleVersion}\n")
}
}
}
// If you want to add more cases to this task, implement them as arguments if total amount to print gets too large
tasks.register('faq') {
group = 'GTNH Buildscript'
description = 'Prints frequently asked questions about building a project'
doLast {
print("If your build fails to fetch dependencies, run './gradlew updateDependencies'. " +
"Or you can manually check if the versions are still on the distributing sites - " +
"the links can be found in repositories.gradle and build.gradle:repositories, " +
"but not build.gradle:buildscript.repositories - those ones are for gradle plugin metadata.\n\n" +
"If your build fails to recognize the syntax of new Java versions, enable Jabel in your " +
"gradle.properties. See how it's done in GTNH ExampleMod/gradle.properties. " +
"However, keep in mind that Jabel enables only syntax features, but not APIs that were introduced in " +
"Java 9 or later.")
}
}
static URL availableBuildScriptUrl() {
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() {
if (isNewBuildScriptVersionAvailable()) {
def buildscriptFile = getFile("build.gradle")
availableBuildScriptUrl().withInputStream { i -> buildscriptFile.withOutputStream { it << i } }
def out = services.get(StyledTextOutputFactory).create('buildscript-update-output')
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 false
}
boolean isNewBuildScriptVersionAvailable() {
Map parameters = ["connectTimeout": 2000, "readTimeout": 2000]
String currentBuildScript = getFile("build.gradle").getText()
String currentBuildScriptHash = getVersionHash(currentBuildScript)
String availableBuildScript = availableBuildScriptUrl().newInputStream(parameters).getText()
String availableBuildScriptHash = getVersionHash(availableBuildScript)
boolean isUpToDate = currentBuildScriptHash.empty || availableBuildScriptHash.empty || currentBuildScriptHash == availableBuildScriptHash
return !isUpToDate
}
static String getVersionHash(String buildScriptContent) {
String versionLine = buildScriptContent.find("^//version: [a-z0-9]*")
if (versionLine != null) {
return versionLine.split(": ").last()
}
return ""
}
// Parameter Deobfuscation
tasks.register('deobfParams') {
group = 'GTNH Buildscript'
description = 'Rename all obfuscated parameter names inherited from Minecraft classes'
doLast { // TODO
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 ...")
copy {
from(zipTree(mcpZIP))
into(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
}
// Dependency Deobfuscation (Deprecated, use the new RFG API documented in dependencies.gradle)
def deobf(String sourceURL) {
try {
URL url = new URL(sourceURL)
String fileName = url.getFile()
//get rid of directories:
int lastSlash = fileName.lastIndexOf("/")
if (lastSlash > 0) {
fileName = fileName.substring(lastSlash + 1)
}
//get rid of extension:
if (fileName.endsWith(".jar") || fileName.endsWith(".litemod")) {
fileName = fileName.substring(0, fileName.lastIndexOf("."))
}
String hostName = url.getHost()
if (hostName.startsWith("www.")) {
hostName = hostName.substring(4)
}
List parts = Arrays.asList(hostName.split("\\."))
Collections.reverse(parts)
hostName = String.join(".", parts)
return deobf(sourceURL, "$hostName/$fileName")
} catch (Exception ignored) {
return deobf(sourceURL, "deobf/${sourceURL.hashCode()}")
}
}
def deobfMaven(String repoURL, String mavenDep) {
if (!repoURL.endsWith("/")) {
repoURL += "/"
}
String[] parts = mavenDep.split(":")
parts[0] = parts[0].replace('.', '/')
def jarURL = repoURL + parts[0] + "/" + parts[1] + "/" + parts[2] + "/" + parts[1] + "-" + parts[2] + ".jar"
return deobf(jarURL)
}
def deobfCurse(String curseDep) {
return dependencies.rfg.deobf("curse.maven:$curseDep")
}
// 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 rawFileName) {
String bon2Version = "2.5.1"
String fileName = URLDecoder.decode(rawFileName, "UTF-8")
String cacheDir = "$project.gradle.gradleUserHomeDir/caches"
String obfFile = "$cacheDir/modules-2/files-2.1/${fileName}.jar"
download.run {
src sourceURL
dest obfFile
quiet true
overwrite false
}
return dependencies.rfg.deobf(files(obfFile))
}
// Helper methods
def checkPropertyExists(String propertyName) {
if (!project.hasProperty(propertyName)) {
throw new GradleException("This project requires a property \"" + propertyName + "\"! Please add it your \"gradle.properties\". You can find all properties and their description here: https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/gradle.properties")
}
}
def propertyDefaultIfUnset(String propertyName, defaultValue) {
if (!project.hasProperty(propertyName) || project.property(propertyName) == "") {
project.ext.setProperty(propertyName, defaultValue)
}
}
def getFile(String 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 = [publishableDevJar]
if (!noPublishedSources) secondaryArtifacts += [sourcesJar]
if (apiPackage) secondaryArtifacts += [apiJar]
return secondaryArtifacts
}