diff --git a/.gitignore b/.gitignore index 12f8644..755fbb2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,25 +1,83 @@ -# eclipse -bin -*.launch -.settings +.nopublish + +### Windows ### + +thumbs.db +*.db + +### Java ### + +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.war +*.ear +*.txt + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### Eclipse ### + +*.pydevproject .metadata -.classpath +.gradle +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +/eclipse + +# Eclipse Core .project -# idea -out +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Java annotation processor (APT) +.factorypath + +# PDT-specific +.buildpath + +# sbteclipse plugin +.target + +# TeXlipse plugin +.texlipse + +### Intellij IDEA ### + +*.iml *.ipr *.iws -*.iml -.idea -# gradle -build -.gradle +.idea/ +.idea_modules/ +/classes/ +/out/ +/build/ + +# Linux +*~ -# other -eclipse -run +run/ -# Files from Forge MDK -forge*changelog.txt +logs/ diff --git a/build.gradle b/build.gradle index d5c2532..796a122 100644 --- a/build.gradle +++ b/build.gradle @@ -1,81 +1,1257 @@ -buildscript { - repositories { - maven { url = 'https://files.minecraftforge.net/maven' } - maven { url = 'https://repo.spongepowered.org/maven' } - jcenter() - mavenCentral() +//version: 1707682661 +/* + * 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/GregTechCEu/Buildscripts/blob/master/build.gradle for updates. + * You can also run ./gradlew updateBuildScript to update your buildscript. + */ + +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import com.gtnewhorizons.retrofuturagradle.mcp.ReobfuscatedJar +import com.modrinth.minotaur.dependencies.ModDependency +import com.modrinth.minotaur.dependencies.VersionDependency +import org.gradle.api.tasks.testing.logging.TestExceptionFormat +import org.gradle.api.tasks.testing.logging.TestLogEvent +import org.gradle.internal.logging.text.StyledTextOutputFactory +import org.jetbrains.gradle.ext.Gradle + +import static org.gradle.internal.logging.text.StyledTextOutput.Style + +plugins { + id 'java' + id 'java-library' + id 'base' + id 'eclipse' + id 'maven-publish' + id 'org.jetbrains.gradle.plugin.idea-ext' version '1.1.7' + id 'com.gtnewhorizons.retrofuturagradle' version '1.3.33' + id 'net.darkhax.curseforgegradle' version '1.1.18' apply false + id 'com.modrinth.minotaur' version '2.8.7' apply false + id 'com.diffplug.spotless' version '6.13.0' apply false + id 'com.palantir.git-version' version '3.0.0' apply false + id 'com.github.johnrengelman.shadow' version '8.1.1' apply false + 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 +} + +def out = services.get(StyledTextOutputFactory).create('an-output') + + +// Project properties + +// Required properties: we don't know how to handle these being missing gracefully +checkPropertyExists("modName") +checkPropertyExists("modId") +checkPropertyExists("modGroup") +checkPropertyExists("minecraftVersion") // hard-coding this makes it harder to immediately tell what version a mod is in (even though this only really supports 1.12.2) +checkPropertyExists("apiPackage") +checkPropertyExists("accessTransformersFile") +checkPropertyExists("usesMixins") +checkPropertyExists("mixinsPackage") +checkPropertyExists("coreModClass") +checkPropertyExists("containsMixinsAndOrCoreModOnly") + +// Optional properties: we can assume some default behavior if these are missing +propertyDefaultIfUnset("modVersion", "") +propertyDefaultIfUnset("includeMCVersionJar", false) +propertyDefaultIfUnset("autoUpdateBuildScript", false) +propertyDefaultIfUnset("modArchivesBaseName", project.modId) +propertyDefaultIfUnsetWithEnvVar("developmentEnvironmentUserName", "Developer", "DEV_USERNAME") +propertyDefaultIfUnset("generateGradleTokenClass", "") +propertyDefaultIfUnset("gradleTokenModId", "") +propertyDefaultIfUnset("gradleTokenModName", "") +propertyDefaultIfUnset("gradleTokenVersion", "") +propertyDefaultIfUnset("useSrcApiPath", false) +propertyDefaultIfUnset("includeWellKnownRepositories", true) +propertyDefaultIfUnset("includeCommonDevEnvMods", true) +propertyDefaultIfUnset("noPublishedSources", false) +propertyDefaultIfUnset("forceEnableMixins", false) +propertyDefaultIfUnsetWithEnvVar("enableCoreModDebug", false, "CORE_MOD_DEBUG") +propertyDefaultIfUnset("generateMixinConfig", true) +propertyDefaultIfUnset("usesShadowedDependencies", false) +propertyDefaultIfUnset("minimizeShadowedDependencies", true) +propertyDefaultIfUnset("relocateShadowedDependencies", true) +propertyDefaultIfUnset("separateRunDirectories", false) +propertyDefaultIfUnset("versionDisplayFormat", '$MOD_NAME \u2212 $VERSION') +propertyDefaultIfUnsetWithEnvVar("modrinthProjectId", "", "MODRINTH_PROJECT_ID") +propertyDefaultIfUnset("modrinthRelations", "") +propertyDefaultIfUnsetWithEnvVar("curseForgeProjectId", "", "CURSEFORGE_PROJECT_ID") +propertyDefaultIfUnset("curseForgeRelations", "") +propertyDefaultIfUnsetWithEnvVar("releaseType", "release", "RELEASE_TYPE") +propertyDefaultIfUnset("generateDefaultChangelog", false) +propertyDefaultIfUnset("customMavenPublishUrl", "") +propertyDefaultIfUnset("mavenArtifactGroup", getDefaultArtifactGroup()) +propertyDefaultIfUnset("enableModernJavaSyntax", false) +propertyDefaultIfUnset("enableSpotless", false) +propertyDefaultIfUnset("enableJUnit", false) +propertyDefaultIfUnsetWithEnvVar("deploymentDebug", false, "DEPLOYMENT_DEBUG") + + +// Project property assertions + +final String javaSourceDir = 'src/main/java/' +final String scalaSourceDir = 'src/main/scala/' +final String kotlinSourceDir = 'src/main/kotlin/' + +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) { + final String endApiPath = modGroupPath + '/' + apiPackagePath + if (useSrcApiPath) { + targetPackageJava = 'src/api/java/' + endApiPath + targetPackageScala = 'src/api/scala/' + endApiPath + targetPackageKotlin = 'src/api/kotlin/' + endApiPath + } else { + targetPackageJava = javaSourceDir + endApiPath + targetPackageScala = scalaSourceDir + endApiPath + targetPackageKotlin = kotlinSourceDir + endApiPath + } + 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/' + 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) + } +} + +if (usesMixins.toBoolean()) { + if (mixinsPackage.isEmpty()) { + throw new GradleException("\"usesMixins\" requires \"mixinsPackage\" to be set!") + } + final String mixinPackagePath = mixinsPackage.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 (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}") + } +} + + +// Plugin application + +// Scala +if (getFile('src/main/scala').exists()) { + apply plugin: 'scala' +} + +if (getFile('src/main/kotlin').exists()) { + apply plugin: 'org.jetbrains.kotlin.jvm' +} + +// Kotlin +pluginManager.withPlugin('org.jetbrains.kotlin.jvm') { + kotlin { + jvmToolchain(8) } - dependencies { - classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' - classpath 'org.spongepowered:mixingradle:0.6-SNAPSHOT' + 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 + } } } - -apply plugin: 'net.minecraftforge.gradle.forge' -apply plugin: 'org.spongepowered.mixin' -// Only edit below this line, the above code adds and enables the necessary things for Forge to be setup. -apply plugin: 'eclipse' -apply plugin: 'maven-publish' -version = '4.0' -group = 'zone.rong' // http://maven.apache.org/guides/mini/guide-naming-conventions.html -archivesBaseName = 'thaumicspeedup' +// Spotless +//noinspection GroovyAssignabilityCheck +project.extensions.add(com.diffplug.blowdryer.Blowdryer, 'Blowdryer', com.diffplug.blowdryer.Blowdryer) // make Blowdryer available in plugin application +if (enableSpotless.toBoolean()) { + apply plugin: 'com.diffplug.spotless' -sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly. + // Spotless auto-formatter + // See https://github.com/diffplug/spotless/tree/main/plugin-gradle + // Can be locally toggled via spotless:off/spotless:on comments + spotless { + encoding 'UTF-8' + + format 'misc', { + target '.gitignore' + + trimTrailingWhitespace() + indentWithSpaces(4) + endWithNewline() + } + java { + target 'src/main/java/**/*.java', 'src/test/java/**/*.java' // exclude api as they are not our files + + def orderFile = project.file('spotless.importorder') + if (!orderFile.exists()) { + orderFile = Blowdryer.file('spotless.importorder') + } + def formatFile = project.file('spotless.eclipseformat.xml') + if (!formatFile.exists()) { + formatFile = Blowdryer.file('spotless.eclipseformat.xml') + } + + toggleOffOn() + importOrderFile(orderFile) + removeUnusedImports() + endWithNewline() + //noinspection GroovyAssignabilityCheck + eclipse('4.19.0').configFile(formatFile) + } + kotlin { + target 'src/*/kotlin/**/*.kt' + + toggleOffOn() + ktfmt('0.39') + + trimTrailingWhitespace() + indentWithSpaces(4) + endWithNewline() + } + scala { + target 'src/*/scala/**/*.scala' + scalafmt('3.7.1') + } + } +} + +// Git version checking, also checking for if this is a submodule +if (project.file('.git/HEAD').isFile() || project.file('.git').isFile()) { + apply plugin: 'com.palantir.git-version' +} + +// Shadowing +if (usesShadowedDependencies.toBoolean()) { + apply plugin: 'com.github.johnrengelman.shadow' +} + + +// Configure Java + +java { + toolchain { + if (enableModernJavaSyntax.toBoolean()) { + languageVersion.set(JavaLanguageVersion.of(17)) + } else { + languageVersion.set(JavaLanguageVersion.of(8)) + } + // Azul covers the most platforms for Java 8+ toolchains, crucially including MacOS arm64 + vendor.set(JvmVendorSpec.AZUL) + } + if (!noPublishedSources.toBoolean()) { + withSourcesJar() + } +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' + + if (enableModernJavaSyntax.toBoolean()) { + if (it.name in ['compileMcLauncherJava', 'compilePatchedMcJava']) { + return + } + + sourceCompatibility = 17 + options.release.set(8) + + javaCompiler.set(javaToolchains.compilerFor { + languageVersion.set(JavaLanguageVersion.of(17)) + vendor.set(JvmVendorSpec.AZUL) + }) + } +} + +tasks.withType(ScalaCompile).configureEach { + options.encoding = 'UTF-8' +} + + +// Allow others using this buildscript to have custom gradle code run +if (getFile('addon.gradle').exists()) { + apply from: 'addon.gradle' +} else if (getFile('addon.gradle.kts').exists()) { + apply from: 'addon.gradle.kts' +} + + +// Configure Minecraft + +// Try to gather mod version from git tags if version is not manually specified +if (!modVersion) { + try { + modVersion = gitVersion() + } catch (Exception ignored) { + out.style(Style.Failure).text( + "Mod version could not be determined! Property 'modVersion' is not set, and either git is not installed or no git tags exist.\n" + + "Either specify a mod version in 'gradle.properties.old', or create at least one tag in git for this project." + ) + modVersion = 'NO-GIT-TAG-SET' + } +} + +if (includeMCVersionJar.toBoolean()){ + version = "${minecraftVersion}-${modVersion}" +} +else { + version = modVersion +} + +group = modGroup + +base { + archivesName = modArchivesBaseName +} minecraft { - version = "1.12.2-14.23.5.2847" - runDir = "run" - mappings = "stable_39" - useDepAts = true + mcVersion = minecraftVersion + username = developmentEnvironmentUserName.toString() + useDependencyAccessTransformers = true + + // Automatic token injection with RetroFuturaGradle + if (gradleTokenModId) { + injectedTags.put gradleTokenModId, modId + } + if (gradleTokenModName) { + injectedTags.put gradleTokenModName, modName + } + if (gradleTokenVersion) { + injectedTags.put gradleTokenVersion, modVersion + } + + // JVM arguments + extraRunJvmArguments.add("-ea:${modGroup}") + if (usesMixins.toBoolean()) { + extraRunJvmArguments.addAll([ + '-Dmixin.hotSwap=true', + '-Dmixin.checks.interfaces=true', + '-Dmixin.debug.export=true' + ]) + } + + if (enableCoreModDebug.toBoolean()) { + extraRunJvmArguments.addAll([ + '-Dlegacy.debugClassLoading=true', + '-Dlegacy.debugClassLoadingFiner=true', + '-Dlegacy.debugClassLoadingSave=true' + ]) + } } -configurations { - embed - implementation.extendsFrom(embed) +if (coreModClass) { + for (runTask in ['runClient', 'runServer']) { + tasks.named(runTask).configure { + extraJvmArgs.add("-Dfml.coreMods.load=${modGroup}.${coreModClass}") + } + } +} + +if (generateGradleTokenClass) { + tasks.injectTags.outputClassName.set(generateGradleTokenClass) +} + +tasks.named('processIdeaSettings').configure { + dependsOn('injectTags') +} + + +// Repositories + +// Allow unsafe repos but warn +repositories.configureEach { repo -> + if (repo instanceof 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 + } + } +} + +// Allow adding custom repositories to the buildscript +if (getFile('repositories.gradle').exists()) { + apply from: 'repositories.gradle' +} else if (getFile('repositories.gradle.kts').exists()) { + apply from: 'repositories.gradle.kts' } repositories { - maven { - url 'https://www.cursemaven.com' + if (includeWellKnownRepositories.toBoolean() || includeCommonDevEnvMods.toBoolean()) { + exclusiveContent { + forRepository { + //noinspection ForeignDelegate + maven { + name = 'Curse Maven' + url = 'https://www.cursemaven.com' + // url = 'https://beta.cursemaven.com' + } + } + filter { + includeGroup 'curse.maven' + } + } + exclusiveContent { + forRepository { + //noinspection ForeignDelegate + maven { + name = 'Modrinth' + url = 'https://api.modrinth.com/maven' + } + } + filter { + includeGroup 'maven.modrinth' + } + } + maven { + name 'Cleanroom Maven' + url 'https://maven.cleanroommc.com' + } + maven { + name 'BlameJared Maven' + url 'https://maven.blamejared.com' + } + maven { + name 'GTNH Maven' + url 'https://nexus.gtnewhorizons.com/repository/public/' + } + maven { + name 'GTCEu Maven' + url 'https://maven.gtceu.com' + } } - maven { - url 'https://repo.spongepowered.org/maven' + if (usesMixins.toBoolean() || forceEnableMixins.toBoolean()) { + // need to add this here even if we did not above + if (!includeWellKnownRepositories.toBoolean()) { + maven { + name 'Cleanroom Maven' + url 'https://maven.cleanroommc.com' + } + } + } + mavenLocal() // Must be last for caching to work +} + + +// Dependencies + +// Configure dependency configurations +configurations { + embed + implementation.extendsFrom(embed) + + if (usesShadowedDependencies.toBoolean()) { + for (config in [compileClasspath, runtimeClasspath, testCompileClasspath, testRuntimeClasspath]) { + config.extendsFrom(shadowImplementation) + config.extendsFrom(shadowCompile) + } } - maven { - url 'https://maven.thiakil.com' + + create("runtimeOnlyNonPublishable") { + description = "Runtime only dependencies that are not published alongside the jar" + canBeConsumed = false + canBeResolved = false } - maven { - url 'https://jitpack.io' + 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) + runtimeClasspath.extendsFrom(runtimeOnlyNonPublishable) + testRuntimeClasspath.extendsFrom(runtimeOnlyNonPublishable) } +String mixinProviderSpec = 'zone.rong:mixinbooter:9.1' dependencies { + if (usesMixins.toBoolean()) { + annotationProcessor 'org.ow2.asm:asm-debug-all:5.2' + // should use 24.1.1 but 30.0+ has a vulnerability fix + annotationProcessor 'com.google.guava:guava:30.0-jre' + // should use 2.8.6 but 2.8.9+ has a vulnerability fix + annotationProcessor 'com.google.code.gson:gson:2.8.9' - deobfCompile 'curse.maven:mixin-booter-419286:3321174' - deobfCompile 'com.azanor.baubles:Baubles:1.12-1.5.2' - deobfCompile 'curse.maven:thaumcraft-223628:2629023' + mixinProviderSpec = modUtils.enableMixins(mixinProviderSpec, "mixins.${modId}.refmap.json") + api (mixinProviderSpec) { + transitive = false + } - deobfCompile 'curse.maven:bwm-core-294335:2624990' - deobfCompile 'curse.maven:bwm-suite-246760:3289033' + annotationProcessor(mixinProviderSpec) { + transitive = false + } + } else if (forceEnableMixins.toBoolean()) { + runtimeOnlyNonPublishable(mixinProviderSpec) + } + + if (enableJUnit.toBoolean()) { + testImplementation 'org.hamcrest:hamcrest:2.2' + testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + } - provided ('org.spongepowered:mixin:0.8.1-SNAPSHOT') { // Don't include in the build + if (enableModernJavaSyntax.toBoolean()) { + annotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:1.0.1' + compileOnly('com.github.bsideup.jabel:jabel-javac-plugin:1.0.1') { + transitive = false + } + // workaround for https://github.com/bsideup/jabel/issues/174 + annotationProcessor 'net.java.dev.jna:jna-platform:5.13.0' + // Allow jdk.unsupported classes like sun.misc.Unsafe, workaround for JDK-8206937 and fixes Forge crashes in tests. + patchedMinecraft 'me.eigenraven.java8unsupported:java-8-unsupported-shim:1.0.0' + + // allow Jabel to work in tests + testAnnotationProcessor "com.github.bsideup.jabel:jabel-javac-plugin:1.0.1" + testCompileOnly("com.github.bsideup.jabel:jabel-javac-plugin:1.0.1") { + transitive = false // We only care about the 1 annotation class + } + testCompileOnly "me.eigenraven.java8unsupported:java-8-unsupported-shim:1.0.0" + } + + compileOnlyApi 'org.jetbrains:annotations:24.1.0' + annotationProcessor 'org.jetbrains:annotations:24.1.0' + patchedMinecraft('net.minecraft:launchwrapper:1.17.2') { transitive = false } - compile 'com.github.LoliKingdom:Persistency:1.2.0' + if (includeCommonDevEnvMods.toBoolean()) { + if (!(modId.equals('jei'))) { + implementation 'mezz.jei:jei_1.12.2:4.16.1.302' + } + if (!(modId.equals('theoneprobe'))) { + //noinspection DependencyNotationArgument + implementation rfg.deobf('curse.maven:top-245211:2667280') // TOP 1.4.28 + } + } +} +pluginManager.withPlugin('org.jetbrains.kotlin.kapt') { + if (usesMixins.toBoolean()) { + dependencies { + kapt(mixinProviderSpec) + } + } } -// Example for how to get properties into the manifest for reading by the runtime.. -jar { - from (configurations.embed.collect { it.isDirectory() ? it : zipTree(it) }) { - exclude 'LICENSE.txt', 'META-INF/MANIFSET.MF', 'META-INF/maven/**', 'META-INF/*.RSA', 'META-INF/*.SF' +configurations.configureEach { + resolutionStrategy.dependencySubstitution { + substitute module('org.scala-lang:scala-library:2.11.1') using module('org.scala-lang:scala-library:2.11.5') because('To allow mixing with Java 8 targets') } } +if (getFile('dependencies.gradle').exists()) { + apply from: 'dependencies.gradle' +} else if (getFile('dependencies.gradle.kts').exists()) { + apply from: 'dependencies.gradle.kts' +} + + +// Test configuration + +// Ensure tests have access to minecraft classes sourceSets { - main { - ext.refMap = 'mixins.thaumicspeedup.refmap.json' + test { + java { + compileClasspath += patchedMc.output + mcLauncher.output + runtimeClasspath += patchedMc.output + mcLauncher.output + } + } +} + +test { + // ensure tests are run with java8 + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(8) + }.get() + + testLogging { + events TestLogEvent.STARTED, TestLogEvent.PASSED, TestLogEvent.FAILED + exceptionFormat TestExceptionFormat.FULL + showExceptions true + showStackTraces true + showCauses true + showStandardStreams true + } + + if (enableJUnit.toBoolean()) { + useJUnitPlatform() + } +} + + +// Resource processing and jar building + +processResources { + // this will ensure that this task is redone when the versions change. + inputs.property 'version', modVersion + inputs.property 'mcversion', minecraftVersion + // Blowdryer puts these files into the resource directory, so + // exclude them from builds (doesn't hurt to exclude even if not present) + exclude('spotless.importorder') + exclude('spotless.eclipseformat.xml') + + // replace stuff in mcmod.info, nothing else + filesMatching('mcmod.info') { fcd -> + fcd.expand( + 'version': modVersion, + 'mcversion': minecraftVersion, + 'modid': modId, + 'modname': modName + ) + } + + if (accessTransformersFile) { + String[] ats = accessTransformersFile.split(',') + ats.each { at -> + rename "(${at})", 'META-INF/$1' + } } -} \ No newline at end of file +} + +// Automatically generate a mixin json file if it does not already exist +tasks.register('generateAssets') { + group = 'GT Buildscript' + description = 'Generates a pack.mcmeta, mcmod.info, or mixins.{modid}.json if needed' + doLast { + // pack.mcmeta + def packMcmetaFile = getFile('src/main/resources/pack.mcmeta') + if (!packMcmetaFile.exists()) { + packMcmetaFile.text = """{ + "pack": { + "pack_format": 3, + "description": "${modName} Resource Pack" + } +} +""" + } + + // mcmod.info + def mcmodInfoFile = getFile('src/main/resources/mcmod.info') + if (!mcmodInfoFile.exists()) { + mcmodInfoFile.text = """[{ + "modid": "\${modid}", + "name": "\${modname}", + "description": "An example mod for Minecraft 1.12.2 with Forge", + "version": "\${version}", + "mcversion": "\${mcversion}", + "logoFile": "", + "url": "", + "authorList": [], + "credits": "", + "dependencies": [] +}] +""" + } + + // mixins.{modid}.json + if (usesMixins.toBoolean() && generateMixinConfig.toBoolean()) { + def mixinConfigFile = getFile("src/main/resources/mixins.${modId}.json") + if (!mixinConfigFile.exists()) { + def mixinConfigRefmap = "mixins.${modId}.refmap.json" + + mixinConfigFile.text = """{ + "package": "${modGroup}.${mixinsPackage}", + "refmap": "${mixinConfigRefmap}", + "target": "@env(DEFAULT)", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_8", + "mixins": [], + "client": [], + "server": [] +} +""" + } + } + } +} + +tasks.named('processResources').configure { + dependsOn('generateAssets') +} + +jar { + manifest { + attributes(getManifestAttributes()) + } + + // Add all embedded dependencies into the jar + from provider { + configurations.embed.collect { + it.isDirectory() ? it : zipTree(it) + } + } + + if (useSrcApiPath && apiPackage) { + from sourceSets.api.output + dependsOn apiClasses + + include "${modGroupPath}/**" + include "assets/**" + include "mcmod.info" + include "pack.mcmeta" + if (accessTransformersFile) { + include "META-INF/${accessTransformersFile}" + } + } +} + +// Configure default run tasks +if (separateRunDirectories.toBoolean()) { + runClient { + workingDir = file('run/client') + } + + runServer { + workingDir = file('run/server') + } +} + +// Create API library jar +tasks.register('apiJar', Jar) { + archiveClassifier.set 'api' + if (useSrcApiPath) { + from(sourceSets.api.java) { + include "${modGroupPath}/${apiPackagePath}/**" + } + from(sourceSets.api.output) { + include "${modGroupPath}/${apiPackagePath}/**" + } + } else { + from(sourceSets.main.java) { + include "${modGroupPath}/${apiPackagePath}/**" + } + + from(sourceSets.main.output) { + include "${modGroupPath}/${apiPackagePath}/**" + } + } +} + +// Configure shadow jar task +if (usesShadowedDependencies.toBoolean()) { + tasks.named('shadowJar', ShadowJar).configure { + manifest { + attributes(getManifestAttributes()) + } + // Only shadow classes that are actually used, if enabled + if (minimizeShadowedDependencies.toBoolean()) { + minimize() + } + configurations = [ + project.configurations.shadowImplementation, + project.configurations.shadowCompile + ] + 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']) { + tasks.named(runTask).configure { + dependsOn('shadowJar') + } + } +} + +def getManifestAttributes() { + def attributes = [:] + if (coreModClass) { + attributes['FMLCorePlugin'] = "${modGroup}.${coreModClass}" + } + if (!containsMixinsAndOrCoreModOnly.toBoolean() && (usesMixins.toBoolean() || coreModClass)) { + attributes['FMLCorePluginContainsFMLMod'] = true + } + if (accessTransformersFile) { + attributes['FMLAT'] = accessTransformersFile.toString() + } + + if (usesMixins.toBoolean()) { + attributes['ForceLoadAsMod'] = !containsMixinsAndOrCoreModOnly.toBoolean() + } + return attributes +} + + +// IDE Configuration + +eclipse { + classpath { + downloadSources = true + downloadJavadoc = true + } +} + +idea { + module { + inheritOutputDirs true + downloadJavadoc true + downloadSources true + } + project { + settings { + runConfigurations { + '1. Setup Workspace'(Gradle) { + taskNames = ['setupDecompWorkspace'] + } + '2. Run Client'(Gradle) { + taskNames = ['runClient'] + } + '3. Run Server'(Gradle) { + taskNames = ['runServer'] + } + '4. Run Obfuscated Client'(Gradle) { + taskNames = ['runObfClient'] + } + '5. Run Obfuscated Server'(Gradle) { + taskNames = ['runObfServer'] + } + if (enableSpotless.toBoolean()) { + '6. Apply Spotless'(Gradle) { + taskNames = ["spotlessApply"] + } + '7. Build Jars'(Gradle) { + taskNames = ['build'] + } + } else { + '6. Build Jars'(Gradle) { + taskNames = ['build'] + } + } + 'Update Buildscript'(Gradle) { + taskNames = ['updateBuildScript'] + } + 'FAQ'(Gradle) { + taskNames = ['faq'] + } + } + compiler.javac { + afterEvaluate { + javacAdditionalOptions = '-encoding utf8' + moduleJavacAdditionalOptions = [ + (project.name + '.main'): tasks.compileJava.options.compilerArgs.collect { + '"' + it + '"' + }.join(' ') + ] + } + } + } + } +} + + +// Deployment +def final modrinthApiKey = providers.environmentVariable('MODRINTH_API_KEY') +def final cfApiKey = providers.environmentVariable('CURSEFORGE_API_KEY') +final boolean isCIEnv = providers.environmentVariable('CI').getOrElse('false').toBoolean() + +if (isCIEnv || deploymentDebug.toBoolean()) { + artifacts { + if (!noPublishedSources.toBoolean()) { + archives sourcesJar + } + if (apiPackage) { + archives apiJar + } + } +} + +// Changelog generation +tasks.register('generateChangelog') { + group = 'GT Buildscript' + description = 'Generate a default changelog of all commits since the last tagged git commit' + onlyIf { + generateDefaultChangelog.toBoolean() + } + doLast { + def lastTag = getLastTag() + + def changelog = runShell(([ + "git", + "log", + "--date=format:%d %b %Y", + "--pretty=%s - **%an** (%ad)", + "${lastTag}..HEAD" + ] + (sourceSets.main.java.srcDirs + sourceSets.main.resources.srcDirs) + .collect { ['--', it] }).flatten()) + + if (changelog) { + changelog = "Changes since ${lastTag}:\n${{("\n" + changelog).replaceAll("\n", "\n* ")}}" + } + def f = getFile('build/changelog.md') + changelog = changelog ?: 'There have been no changes.' + f.write(changelog, 'UTF-8') + + // Set changelog for Modrinth + if (modrinthApiKey.isPresent() || deploymentDebug.toBoolean()) { + modrinth.changelog.set(changelog) + } + } +} + +if (cfApiKey.isPresent() || deploymentDebug.toBoolean()) { + apply plugin: 'net.darkhax.curseforgegradle' + //noinspection UnnecessaryQualifiedReference + tasks.register('curseforge', net.darkhax.curseforgegradle.TaskPublishCurseForge) { + disableVersionDetection() + debugMode = deploymentDebug.toBoolean() + apiToken = cfApiKey.getOrElse('debug_token') + + doFirst { + def mainFile = upload(curseForgeProjectId, reobfJar) + def changelogFile = getChangelog() + def changelogRaw = changelogFile.exists() ? changelogFile.getText('UTF-8') : "" + + mainFile.displayName = versionDisplayFormat.replace('$MOD_NAME', modName).replace('$VERSION', modVersion) + mainFile.releaseType = getReleaseType() + mainFile.changelog = changelogRaw + mainFile.changelogType = 'markdown' + mainFile.addModLoader 'Forge' + mainFile.addJavaVersion "Java 8" + mainFile.addGameVersion minecraftVersion + + if (curseForgeRelations.size() != 0) { + String[] deps = curseForgeRelations.split(';') + deps.each { dep -> + if (dep.size() == 0) { + return + } + String[] parts = dep.split(':') + String type = parts[0], slug = parts[1] + def types = [ + 'req' : 'requiredDependency', 'required': 'requiredDependency', + 'opt' : 'optionalDependency', 'optional': 'optionalDependency', + 'embed' : 'embeddedLibrary', 'embedded': 'embeddedLibrary', + 'incomp': 'incompatible', 'fail' : 'incompatible'] + if (types.containsKey(type)) type = types[type] + if (!(type in ['requiredDependency', 'embeddedLibrary', 'optionalDependency', 'tool', 'incompatible'])) { + throw new Exception('Invalid Curseforge dependency type: ' + type) + } + mainFile.addRelation(slug, type) + } + } + + for (artifact in getSecondaryArtifacts()) { + def additionalFile = mainFile.withAdditionalFile(artifact) + additionalFile.changelog = changelogRaw + } + } + } + tasks.curseforge.dependsOn(build) + tasks.curseforge.dependsOn('generateChangelog') +} + +if (modrinthApiKey.isPresent() || deploymentDebug.toBoolean()) { + apply plugin: 'com.modrinth.minotaur' + def final changelogFile = getChangelog() + + modrinth { + token = modrinthApiKey.getOrElse('debug_token') + projectId = modrinthProjectId + versionName = versionDisplayFormat.replace('$MOD_NAME', modName).replace('$VERSION', modVersion) + changelog = changelogFile.exists() ? changelogFile.getText('UTF-8') : "" + versionType = getReleaseType() + versionNumber = modVersion + gameVersions = [minecraftVersion] + loaders = ["forge"] + debugMode = deploymentDebug.toBoolean() + uploadFile = reobfJar + additionalFiles = getSecondaryArtifacts() + } + 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.length > 1 ? qual[1] : 'project', parts[1]) + } + } + tasks.modrinth.dependsOn(build) + tasks.modrinth.dependsOn('generateChangelog') +} + +def addModrinthDep(String scope, String type, String name) { + com.modrinth.minotaur.dependencies.Dependency dep + def types = [ + 'req' : 'required', + 'opt' : 'optional', + 'embed' : 'embedded', + 'incomp': 'incompatible', 'fail': 'incompatible'] + if (types.containsKey(scope)) scope = types[scope] + if (!(scope in ['required', 'optional', 'incompatible', 'embedded'])) { + throw new Exception('Invalid modrinth dependency scope: ' + scope) + } + types = ['proj': 'project', '': 'project', 'p': 'project', 'ver': 'version', 'v': 'version'] + if (types.containsKey(type)) type = types[type] + 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) +} + +if (customMavenPublishUrl) { + String publishedVersion = modVersion + + publishing { + publications { + create('maven', MavenPublication) { + //noinspection GroovyAssignabilityCheck + from components.java + + if (apiPackage) { + artifact apiJar + } + + // providers is not available here, use System for getting env vars + groupId = System.getenv('ARTIFACT_GROUP_ID') ?: project.mavenArtifactGroup + artifactId = System.getenv('ARTIFACT_ID') ?: project.modArchivesBaseName + version = System.getenv('RELEASE_VERSION') ?: publishedVersion + } + } + + repositories { + maven { + url = customMavenPublishUrl + allowInsecureProtocol = !customMavenPublishUrl.startsWith('https') + credentials { + username = providers.environmentVariable('MAVEN_USER').getOrElse('NONE') + password = providers.environmentVariable('MAVEN_PASSWORD').getOrElse('NONE') + } + } + } + } +} + +def getSecondaryArtifacts() { + def secondaryArtifacts = [usesShadowedDependencies.toBoolean() ? tasks.shadowJar : tasks.jar] + if (!noPublishedSources.toBoolean()) secondaryArtifacts += [sourcesJar] + if (apiPackage) secondaryArtifacts += [apiJar] + return secondaryArtifacts +} + +def getReleaseType() { + String type = project.releaseType + if (!(type in ['release', 'beta', 'alpha'])) { + throw new Exception("Release type invalid! Found \"" + type + "\", allowed: \"release\", \"beta\", \"alpha\"") + } + return type +} + +/* + * If CHANGELOG_LOCATION env var is set, that takes highest precedence. + * Next, if 'generateDefaultChangelog' option is enabled, use that. + * Otherwise, try to use a CHANGELOG.md file at root directory. + */ +def getChangelog() { + def final changelogEnv = providers.environmentVariable('CHANGELOG_LOCATION') + if (changelogEnv.isPresent()) { + return new File(changelogEnv.get()) + } + if (generateDefaultChangelog.toBoolean()) { + return getFile('build/changelog.md') + } + return getFile('CHANGELOG.md') +} + + +// Buildscript updating + +def buildscriptGradleVersion = '8.5' + +tasks.named('wrapper', Wrapper).configure { + gradleVersion = buildscriptGradleVersion +} + +tasks.register('updateBuildScript') { + group = 'GT 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") + } + } +} + +static URL availableBuildScriptUrl() { + new URL("https://raw.githubusercontent.com/GregTechCEu/Buildscripts/master/build.gradle") +} + +static URL availableSettingsGradleUrl() { + new URL("https://raw.githubusercontent.com/GregTechCEu/Buildscripts/master/settings.gradle") +} + +boolean performBuildScriptUpdate() { + if (isNewBuildScriptVersionAvailable()) { + def buildscriptFile = getFile("build.gradle") + def settingsFile = getFile("settings.gradle") + availableBuildScriptUrl().withInputStream { i -> buildscriptFile.withOutputStream { it << i } } + availableSettingsGradleUrl().withInputStream { i -> settingsFile.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!") + return true + } + return false +} + +boolean isNewBuildScriptVersionAvailable() { + Map parameters = ["connectTimeout": 10000, "readTimeout": 10000] + + 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 "" +} + + +// Faq + +tasks.register('faq') { + group = 'GT Buildscript' + description = 'Prints frequently asked questions about building a project' + doLast { + print("\nTo update this buildscript to the latest version, run 'gradlew updateBuildScript' or run the generated run configuration if you are using IDEA.\n" + + "To set up the project, run the 'setupDecompWorkspace' task, which you can run as './gradlew setupDecompWorkspace' in a terminal, or find in the 'modded minecraft' gradle category.\n\n" + + "To add new dependencies to your project, place them in 'dependencies.gradle', NOT in 'build.gradle' as they would be replaced when the script updates.\n" + + "To add new repositories to your project, place them in 'repositories.gradle'.\n" + + "If you need additional gradle code to run, you can place it in a file named 'addon.gradle' (or either of the above, up to you for organization).\n\n" + + "If your build fails to recognize the syntax of newer Java versions, enable Jabel in your 'gradle.properties.old' under the option name 'enableModernJavaSyntax'.\n" + + "To see information on how to configure your IDE properly for Java 17, see https://github.com/GregTechCEu/Buildscripts/blob/master/docs/jabel.md\n\n" + + "Report any issues or feature requests you have for this build script to https://github.com/GregTechCEu/Buildscripts/issues\n") + } +} + + +// Helpers + +def getDefaultArtifactGroup() { + def lastIndex = project.modGroup.lastIndexOf('.') + return lastIndex < 0 ? project.modGroup : project.modGroup.substring(0, lastIndex) +} + +def getFile(String relativePath) { + return new File(projectDir, relativePath) +} + +def checkPropertyExists(String propertyName) { + if (!project.hasProperty(propertyName)) { + throw new GradleException("This project requires a property \"" + propertyName + "\"! Please add it your \"gradle.properties.old\". You can find all properties and their description here: https://github.com/GregTechCEu/Buildscripts/blob/main/gradle.properties") + } +} + +def propertyDefaultIfUnset(String propertyName, defaultValue) { + if (!project.hasProperty(propertyName) || project.property(propertyName) == "") { + project.ext.setProperty(propertyName, defaultValue) + } +} + +def propertyDefaultIfUnsetWithEnvVar(String propertyName, defaultValue, String envVarName) { + def envVar = providers.environmentVariable(envVarName) + if (envVar.isPresent()) { + project.ext.setProperty(propertyName, envVar.get()) + } else { + propertyDefaultIfUnset(propertyName, defaultValue) + } +} + +static runShell(command) { + def process = command.execute() + def outputStream = new StringBuffer() + def errorStream = new StringBuffer() + process.waitForProcessOutput(outputStream, errorStream) + + errorStream.toString().with { + if (it) { + throw new GradleException("Error executing ${command}:\n> ${it}") + } + } + return outputStream.toString().trim() +} + +def getLastTag() { + def githubTag = providers.environmentVariable('GITHUB_TAG') + return runShell('git describe --abbrev=0 --tags ' + + (githubTag.isPresent() ? runShell('git rev-list --tags --skip=1 --max-count=1') : '')) +} diff --git a/dependencies.gradle b/dependencies.gradle new file mode 100644 index 0000000..b311fb6 --- /dev/null +++ b/dependencies.gradle @@ -0,0 +1,50 @@ +//file:noinspection DependencyNotationArgument +// TODO remove when fixed in RFG ^ +/* + * Add your dependencies here. Supported configurations: + * - api("group:name:version:classifier"): if you use the types from this dependency in the public API of this mod + * Available at runtime and compiletime for mods depending on this mod + * - implementation("g:n:v:c"): if you need this for internal implementation details of the mod, but none of it is visible via the public API + * Available at runtime but not compiletime for mods depending on this mod + * - compileOnly("g:n:v:c"): if the mod you're building doesn't need this dependency during runtime at all, e.g. for optional mods + * Not available at all for mods depending on this mod, only visible at compiletime for this mod + * - compileOnlyApi("g:n:v:c"): like compileOnly, but also visible at compiletime for mods depending on this mod + * Available at compiletime but not runtime for mods depending on this mod + * - runtimeOnlyNonPublishable("g:n:v:c"): if you want to include a mod in this mod's runClient/runServer runs, but not publish it as a dependency + * Not available at all for mods depending on this mod, only visible at runtime for this mod + * - devOnlyNonPublishable("g:n:v:c"): a combination of runtimeOnlyNonPublishable and compileOnly for dependencies present at both compiletime and runtime, + * but not published as Maven dependencies - useful for RFG-deobfuscated dependencies or local testing + * - runtimeOnly("g:n:v:c"): if you don't need this at compile time, but want it to be present at runtime + * Available at runtime for mods depending on this mod + * - annotationProcessor("g:n:v:c"): mostly for java compiler plugins, if you know you need this, use it, otherwise don't worry + * - testCONFIG("g:n:v:c") - replace CONFIG by one of the above (except api), same as above but for the test sources instead of main + * + * - shadowImplementation("g:n:v:c"): effectively the same as API, but the dependency is included in your jar under a renamed package name + * Requires you to enable usesShadowedDependencies in gradle.properties.old + * For more info, see https://github.com/GregTechCEu/Buildscripts/blob/master/docs/shadow.md + * + * You can exclude transitive dependencies (dependencies of the chosen dependency) by appending { transitive = false } if needed, + * but use this sparingly as it can break using your mod as another mod's dependency if you're not careful. + * + * To depend on obfuscated jars you can use `devOnlyNonPublishable(rfg.deobf("dep:spec:1.2.3"))` to fetch an obfuscated jar from maven, + * or `devOnlyNonPublishable(rfg.deobf(project.files("libs/my-mod-jar.jar")))` to use a file. + * + * To add a mod with CurseMaven, replace '("g:n:v:c")' in the above with 'rfg.deobf("curse.maven:project_slug-project_id:file_id")' + * Example: devOnlyNonPublishable(rfg.deobf("curse.maven:top-245211:2667280")) + * + * Gradle names for some of the configuration can be misleading, compileOnlyApi and runtimeOnly both get published as dependencies in Maven, but compileOnly does not. + * The buildscript adds runtimeOnlyNonPublishable to also have a runtime dependency that's not published. + * + * For more details, see https://docs.gradle.org/8.4/userguide/java_library_plugin.html#sec:java_library_configurations_graph + */ +dependencies { + + implementation rfg.deobf('curse.maven:thaumcraft-223628:2629023') + implementation rfg.deobf('curse.maven:baubles-227083:2518667') + implementation rfg.deobf('curse.maven:persistency-554387:3556105') + + // soft deps + compileOnly rfg.deobf('curse.maven:bwm-suite-246760:3289033') + compileOnly rfg.deobf('curse.maven:bwm-core-294335:2624990') + +} diff --git a/gradle.properties b/gradle.properties index 878bf1f..0f97683 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,179 @@ +modName = Thaumic Speedup + +# This is a case-sensitive string to identify your mod. Convention is to use lower case. +modId = thaumicspeedup + +modGroup = zone.rong.thaumicspeedup + +# Version of your mod. +# This field can be left empty if you want your mod's version to be determined by the latest git tag instead. +modVersion = 4.0 + +# Whether to use the old jar naming structure (modid-mcversion-version) instead of the new version (modid-version) +includeMCVersionJar = false + +# The name of your jar when you produce builds, not including any versioning info +modArchivesBaseName = thaumicspeedup + +# Will update your build.gradle automatically whenever an update is available +autoUpdateBuildScript = false + +minecraftVersion = 1.12.2 + +# Select a username for testing your mod with breakpoints. You may leave this empty for a random username each time you +# restart Minecraft in development. Choose this dependent on your mod: +# Do you need consistent player progressing (for example Thaumcraft)? -> Select a name +# Do you need to test how your custom blocks interacts with a player that is not the owner? -> leave name empty +# Alternatively this can be set with the 'DEV_USERNAME' environment variable. +developmentEnvironmentUserName = Developer + +# Enables using modern java syntax (up to version 17) via Jabel, while still targeting JVM 8. +# See https://github.com/bsideup/jabel for details on how this works. +# Using this requires that you use a Java 17 JDK for development. +enableModernJavaSyntax = true + +# Generate a class with String fields for the mod id, name and version named with the fields below +generateGradleTokenClass = zone.rong.thaumicspeedup.Tags +gradleTokenModId = MODID +gradleTokenModName = MODNAME +gradleTokenVersion = VERSION + +# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise, you can +# leave this property empty. +# Example value: apiPackage = api + modGroup = com.myname.mymodid -> com.myname.mymodid.api +apiPackage = + +# If you want to keep your API code in src/api instead of src/main +useSrcApiPath = false + +# Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/ +# There can be multiple files in a comma-separated list. +# Example value: mymodid_at.cfg,jei_at.cfg +accessTransformersFile = + +# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled! +usesMixins = true +# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail! +mixinsPackage = mixins +# Automatically generates a mixin config json if enabled, with the name mixins.modid.json +generateMixinConfig = true +# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin! +# Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin +coreModClass = +# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod (meaning that +# there is no class annotated with @Mod) you want this to be true. When in doubt: leave it on false! +containsMixinsAndOrCoreModOnly = false + +# Enables Mixins even if this mod doesn't use them, useful if one of the dependencies uses mixins. +forceEnableMixins = false + +# Outputs pre-transformed and post-transformed loaded classes to run/CLASSLOADER_TEMP. Can be used in combination with +# diff to see exactly what your ASM or Mixins are changing in the target file. +# Optionally can be specified with the 'CORE_MOD_DEBUG' env var. Will output a lot of files! +enableCoreModDebug = false + +# Adds CurseMaven, Modrinth Maven, BlameJared maven, and some more well-known 1.12.2 repositories +includeWellKnownRepositories = true + +# Adds JEI and TheOneProbe to your development environment. Adds them as 'implementation', meaning they will +# be available at compiletime and runtime for your mod (in-game and in-code). +# Overrides the above setting to be always true, as these repositories are needed to fetch the mods +includeCommonDevEnvMods = true + + +# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated in your jar. It is your +# responsibility check the licence and request permission for distribution, if required. +usesShadowedDependencies = false +# If disabled, won't remove unused classes from shaded dependencies. Some libraries use reflection to access +# their own classes, making the minimization unreliable. +minimizeShadowedDependencies = true +# If disabled, won't rename the shadowed classes. +relocateShadowedDependencies = true + +# Separate run directories into "run/client" for runClient task, and "run/server" for runServer task. +# Useful for debugging a server and client simultaneously. If not enabled, it will be in the standard location "run/" +separateRunDirectories = false + +# The display name format of versions published to Curse and Modrinth. $MOD_NAME and $VERSION are available variables. +# Default: $MOD_NAME \u2212 $VERSION. \u2212 is the minus character which looks much better than the hyphen minus on Curse. +versionDisplayFormat = $MOD_NAME \u2212 $VERSION + +# Publishing to modrinth requires you to set the MODRINTH_API_KEY environment variable to your current modrinth API token. + +# The project's ID on Modrinth. Can be either the slug or the ID. +# Leave this empty if you don't want to publish on Modrinth. +# Alternatively this can be set with the 'MODRINTH_PROJECT_ID' environment variable. +modrinthProjectId = + +# The project's relations on Modrinth. You can use this to refer to other projects on Modrinth. +# Syntax: scope1-type1:name1;scope2-type2:name2;... +# Where scope can be one of [required, optional, incompatible, embedded], +# type can be one of [project, version], +# and the name is the Modrinth project or version slug/id of the other mod. +# Example: required-project:jei;optional-project:top;incompatible-project:gregtech +modrinthRelations = + + +# Publishing to CurseForge requires you to set the CURSEFORGE_API_KEY environment variable to one of your CurseForge API tokens. + +# The project's numeric ID on CurseForge. You can find this in the About Project box. +# Leave this empty if you don't want to publish on CurseForge. +# Alternatively this can be set with the 'CURSEFORGE_PROJECT_ID' environment variable. +curseForgeProjectId = + +# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge. +# Syntax: type1:name1;type2:name2;... +# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible], +# and the name is the CurseForge project slug of the other mod. +# Example: requiredDependency:railcraft;embeddedLibrary:cofhlib;incompatible:buildcraft +curseForgeRelations = + +# This project's release type on CurseForge and/or Modrinth +# Alternatively this can be set with the 'RELEASE_TYPE' environment variable. +# Allowed types: release, beta, alpha +releaseType = release + +# Generate a default changelog for releases. Requires git to be installed, as it uses it to generate a changelog of +# commits since the last tagged release. +generateDefaultChangelog = false + +# Prevent the source code from being published +noPublishedSources = false + + +# Publish to a custom maven location. Follows a few rules: +# Group ID can be set with the 'ARTIFACT_GROUP_ID' environment variable, default to 'project.group' +# Artifact ID can be set with the 'ARTIFACT_ID' environment variable, default to 'project.name' +# Version can be set with the 'RELEASE_VERSION' environment variable, default to 'modVersion' +# For maven credentials: +# Username is set with the 'MAVEN_USER' environment variable, default to "NONE" +# Password is set with the 'MAVEN_PASSWORD' environment variable, default to "NONE" +customMavenPublishUrl = + +# The group for maven artifacts. Defaults to the 'project.modGroup' until the last '.' (if any). +# So 'mymod' becomes 'mymod' and 'com.myname.mymodid' 'becomes com.myname' +mavenArtifactGroup = + +# Enable spotless checks +# Enforces code formatting on your source code +# By default this will use the files found here: https://github.com/GregTechCEu/Buildscripts/tree/master/spotless +# to format your code. However, you can create your own version of these files and place them in your project's +# root directory to apply your own formatting options instead. +enableSpotless = false + +# Enable JUnit testing platform used for testing your code. +# Uses JUnit 5. See guide and documentation here: https://junit.org/junit5/docs/current/user-guide/ +enableJUnit = true + +# Deployment debug setting +# Uncomment this to test deployments to CurseForge and Modrinth +# Alternatively, you can set the 'DEPLOYMENT_DEBUG' environment variable. +deploymentDebug = false + + +# Gradle Settings +# Effectively applies the '--stacktrace' flag by default +org.gradle.logging.stacktrace = all # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. -org.gradle.jvmargs=-Xmx3G -org.gradle.daemon=false \ No newline at end of file +org.gradle.jvmargs = -Xmx3G diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7a3265e..033e24c 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 949819d..1af9e09 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip diff --git a/gradlew b/gradlew index cccdd3d..fcb6fca 100644 --- a/gradlew +++ b/gradlew @@ -1,78 +1,126 @@ -#!/usr/bin/env sh +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -81,92 +129,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" fi +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index f955316..93e3f59 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,4 +1,20 @@ -@if "%DEBUG%" == "" @echo off +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -9,19 +25,23 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +55,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,38 +65,26 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/repositories.gradle b/repositories.gradle new file mode 100644 index 0000000..c884390 --- /dev/null +++ b/repositories.gradle @@ -0,0 +1,5 @@ +// Add any additional repositories for your dependencies here + +repositories { + +} diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..771def3 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,30 @@ +pluginManagement { + repositories { + maven { + // RetroFuturaGradle + name 'GTNH Maven' + url 'https://nexus.gtnewhorizons.com/repository/public/' + //noinspection GroovyAssignabilityCheck + mavenContent { + includeGroup 'com.gtnewhorizons' + includeGroup 'com.gtnewhorizons.retrofuturagradle' + } + } + gradlePluginPortal() + mavenCentral() + mavenLocal() + } +} + +plugins { + id 'com.diffplug.blowdryerSetup' version '1.7.0' + // Automatic toolchain provisioning + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0' +} + +blowdryerSetup { + repoSubfolder 'spotless' + github 'GregTechCEu/Buildscripts', 'tag', 'v1.0.7' +} + +rootProject.name = rootProject.projectDir.getName() diff --git a/src/main/java/zone/rong/thaumicspeedup/DummyAspectEventProxy.java b/src/main/java/zone/rong/thaumicspeedup/DummyAspectEventProxy.java new file mode 100644 index 0000000..d859b80 --- /dev/null +++ b/src/main/java/zone/rong/thaumicspeedup/DummyAspectEventProxy.java @@ -0,0 +1,27 @@ +package zone.rong.thaumicspeedup; + +import net.minecraft.item.ItemStack; +import thaumcraft.api.aspects.AspectEventProxy; +import thaumcraft.api.aspects.AspectList; + +public class DummyAspectEventProxy extends AspectEventProxy { + + // This class is just to send the event for any mods that might listen to it for inserting Entity aspects, and such. + + @Override + public void registerObjectTag(ItemStack item, AspectList aspects) { + } + + @Override + public void registerObjectTag(String oreDict, AspectList aspects) { + } + + @Override + public void registerComplexObjectTag(ItemStack item, AspectList aspects) { + } + + @Override + public void registerComplexObjectTag(String oreDict, AspectList aspects) { + } + +} diff --git a/src/main/java/zone/rong/thaumicspeedup/ThaumicSpeedup.java b/src/main/java/zone/rong/thaumicspeedup/ThaumicSpeedup.java index 9ef9aee..2a367f2 100644 --- a/src/main/java/zone/rong/thaumicspeedup/ThaumicSpeedup.java +++ b/src/main/java/zone/rong/thaumicspeedup/ThaumicSpeedup.java @@ -2,12 +2,17 @@ import com.google.common.base.Stopwatch; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.minecraft.launchwrapper.Launch; -import net.minecraft.util.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.event.FMLConstructionEvent; -import net.minecraftforge.fml.common.event.FMLLoadCompleteEvent; +import net.minecraftforge.fml.common.event.FMLServerStartedEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import thaumcraft.api.aspects.Aspect; @@ -15,29 +20,29 @@ import thaumcraft.api.aspects.AspectList; import thaumcraft.api.internal.CommonInternals; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.util.Set; +import java.io.*; +import java.util.HashMap; +import java.util.Map; -@Mod(modid = "thaumicspeedup", name = "Thaumic Speedup", version = "4.0", dependencies = "required:thaumcraft;required:persistency") +@Mod(modid = Tags.MODID, name = Tags.MODNAME, version = Tags.VERSION, dependencies = "required:thaumcraft;required:persistency") +@Mod.EventBusSubscriber(modid = Tags.MODID) public class ThaumicSpeedup { public static final Logger LOGGER = LogManager.getLogger("ThaumicSpeedup"); - public static final AspectEventProxy PROXY_INSTANCE = new AspectEventProxy(); + public static AspectEventProxy PROXY_INSTANCE = new AspectEventProxy(); public static volatile boolean persistentAspectsCache = true; public static Thread aspectsThread; - public static ThreadLocal> craftingRegistryKeys; + public static HashMap lateObjectTags; + private static long nextSave = -1L; @Mod.EventHandler public void construct(FMLConstructionEvent event) { if ((boolean) Launch.blackboard.getOrDefault("ConsistentLoad", false)) { File aspectsCache = new File((File) Launch.blackboard.get("CachesFolderFile"), "thaumicspeedup/aspects_cache.bin"); if (aspectsCache.isFile() && aspectsCache.exists() && aspectsCache.length() > 0L) { - new Thread(() -> { + aspectsThread = new Thread(() -> { try { ThaumicSpeedup.LOGGER.info("Offloading aspects deserialization..."); Stopwatch stopwatch = Stopwatch.createStarted(); @@ -52,11 +57,13 @@ public void construct(FMLConstructionEvent event) { objectStream.close(); fileStream.close(); ThaumicSpeedup.LOGGER.info("Aspects deserialization complete! Taken {}.", stopwatch.stop()); + ThaumicSpeedup.lateObjectTags = new HashMap<>(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); persistentAspectsCache = false; } - }, "ThaumicSpeedup/AspectThread-0").start(); + }, "ThaumicSpeedup/AspectThread"); + aspectsThread.start(); } else { persistentAspectsCache = false; } @@ -64,12 +71,44 @@ public void construct(FMLConstructionEvent event) { } @Mod.EventHandler - public void loadComplete(FMLLoadCompleteEvent event) { - if (aspectsThread != null) { - try { - aspectsThread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); + public void onServerStarted(FMLServerStartedEvent event) { + if (ThaumicSpeedupConfig.saveInterval > 0) { + nextSave = System.currentTimeMillis() + (ThaumicSpeedupConfig.saveInterval * 1000L); + } + } + + @SubscribeEvent + public static void tick(TickEvent.ServerTickEvent event) { + if (event.phase == TickEvent.Phase.START) return; + MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance(); + if (server == null) return; + long now = System.currentTimeMillis(); + if (nextSave > 0 && nextSave < now) { + nextSave = now + (ThaumicSpeedupConfig.saveInterval * 1000L); + if (lateObjectTags.isEmpty()) { + LOGGER.info(Tags.MODNAME + " found 0 new item aspects to save."); + return; + } + LOGGER.info(Tags.MODNAME + " found " + lateObjectTags.size() + " new item aspects to save."); + File aspectsCache = new File((File) Launch.blackboard.get("CachesFolderFile"), "thaumicspeedup/aspects_cache.bin"); + if (aspectsCache.isFile() && aspectsCache.exists() && aspectsCache.length() > 0L) { + new Thread(() -> { + try { + Stopwatch stopwatch = Stopwatch.createStarted(); + FileOutputStream fileOutputStream = new FileOutputStream(aspectsCache); + ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); + Int2ObjectMap> objectTags = new Int2ObjectOpenHashMap<>(); + lateObjectTags.forEach((k, v) -> objectTags.put(k, v.aspects.entrySet().stream().collect(Object2IntArrayMap::new, (m, av) -> m.put(av.getKey().getTag(), av.getValue()), Map::putAll))); + objectOutputStream.writeObject(objectTags); + fileOutputStream.close(); + objectOutputStream.close(); + ThaumicSpeedup.LOGGER.info("Aspects serialization complete! Taken {}.", stopwatch.stop()); + ThaumicSpeedup.lateObjectTags.clear(); + } catch (IOException e) { + ThaumicSpeedup.LOGGER.error("Aspects serialization failed!"); + e.printStackTrace(); + } + }, "ThaumicSpeedup/AspectThread").start(); } } } diff --git a/src/main/java/zone/rong/thaumicspeedup/ThaumicSpeedupConfig.java b/src/main/java/zone/rong/thaumicspeedup/ThaumicSpeedupConfig.java new file mode 100644 index 0000000..7a716b2 --- /dev/null +++ b/src/main/java/zone/rong/thaumicspeedup/ThaumicSpeedupConfig.java @@ -0,0 +1,11 @@ +package zone.rong.thaumicspeedup; + +import net.minecraftforge.common.config.Config; + +@Config(modid = Tags.MODID) +public class ThaumicSpeedupConfig { + + @Config.Comment("Save interval for item aspects calculated at runtime (in seconds). Make it -1 if you don't want to save periodically, although I wouldn't recommend it.") + public static int saveInterval = 300; + +} diff --git a/src/main/java/zone/rong/thaumicspeedup/ThaumicSpeedupMixinLoader.java b/src/main/java/zone/rong/thaumicspeedup/ThaumicSpeedupMixinLoader.java index 92d81f6..242637e 100644 --- a/src/main/java/zone/rong/thaumicspeedup/ThaumicSpeedupMixinLoader.java +++ b/src/main/java/zone/rong/thaumicspeedup/ThaumicSpeedupMixinLoader.java @@ -1,17 +1,21 @@ package zone.rong.thaumicspeedup; import net.minecraftforge.fml.common.Loader; -import org.spongepowered.asm.mixin.Mixins; -import zone.rong.mixinbooter.MixinLoader; +import zone.rong.mixinbooter.ILateMixinLoader; -@MixinLoader -public class ThaumicSpeedupMixinLoader { +import java.util.ArrayList; +import java.util.List; - { - Mixins.addConfiguration("mixins.thaumicspeedup.json"); +public class ThaumicSpeedupMixinLoader implements ILateMixinLoader { + + @Override + public List getMixinConfigs() { + ArrayList configs = new ArrayList<>(); + configs.add("mixins.thaumicspeedup.json"); if (Loader.isModLoaded("betterwithmods")) { - Mixins.addConfiguration("mixins.thaumicspeedup_bwmcompat.json"); + configs.add("mixins.thaumicspeedup_bwmcompat.json"); } + return configs; } } diff --git a/src/main/java/zone/rong/thaumicspeedup/mixins/CommonInternalsMixin.java b/src/main/java/zone/rong/thaumicspeedup/mixins/CommonInternalsMixin.java index b5bf6c5..a9fedba 100644 --- a/src/main/java/zone/rong/thaumicspeedup/mixins/CommonInternalsMixin.java +++ b/src/main/java/zone/rong/thaumicspeedup/mixins/CommonInternalsMixin.java @@ -2,37 +2,13 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.ResourceLocation; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import thaumcraft.api.crafting.IThaumcraftRecipe; import thaumcraft.api.internal.CommonInternals; -import zone.rong.thaumicspeedup.ConcurrentHashMapTypedMap; - -import java.util.HashMap; @Mixin(value = CommonInternals.class, remap = false) public class CommonInternalsMixin { - @Shadow public static HashMap jsonLocs; - @Shadow public static HashMap craftingRecipeCatalog; - @Shadow public static HashMap craftingRecipeCatalogFake; - @Shadow public static HashMap warpMap; - @Shadow public static HashMap seedList; - - @Inject(method = "", at = @At("RETURN")) - private static void injectInStaticBlock(CallbackInfo ci) { - jsonLocs = new ConcurrentHashMapTypedMap<>(); - craftingRecipeCatalog = new ConcurrentHashMapTypedMap<>(); - craftingRecipeCatalogFake = new ConcurrentHashMapTypedMap<>(); - warpMap = new ConcurrentHashMapTypedMap<>(); - seedList = new ConcurrentHashMapTypedMap<>(); - } - /** * @author Rongmario * @reason Eliminate ItemStack#copy + Use NBTTagCompound's native hashCode implementation diff --git a/src/main/java/zone/rong/thaumicspeedup/mixins/ConfigAspectsMixin.java b/src/main/java/zone/rong/thaumicspeedup/mixins/ConfigAspectsMixin.java index 2c616a3..a8835a8 100644 --- a/src/main/java/zone/rong/thaumicspeedup/mixins/ConfigAspectsMixin.java +++ b/src/main/java/zone/rong/thaumicspeedup/mixins/ConfigAspectsMixin.java @@ -6,11 +6,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import it.unimi.dsi.fastutil.objects.ObjectSets; -import net.minecraft.item.crafting.CraftingManager; import net.minecraft.launchwrapper.Launch; -import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.MinecraftForge; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; @@ -18,17 +14,15 @@ import thaumcraft.api.aspects.AspectRegistryEvent; import thaumcraft.api.internal.CommonInternals; import thaumcraft.common.config.ConfigAspects; -import zone.rong.thaumicspeedup.ConcurrentHashMapTypedMap; +import zone.rong.thaumicspeedup.DummyAspectEventProxy; import zone.rong.thaumicspeedup.ThaumicSpeedup; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; -import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.Set; @Mixin(value = ConfigAspects.class, remap = false) public abstract class ConfigAspectsMixin { @@ -43,46 +37,53 @@ public abstract class ConfigAspectsMixin { @Overwrite public static void postInit() { if (!(boolean) Launch.blackboard.getOrDefault("ConsistentLoad", false) || !ThaumicSpeedup.persistentAspectsCache) { - ThaumicSpeedup.aspectsThread = new Thread(() -> { - Stopwatch stopwatch = Stopwatch.createStarted(); - ThaumicSpeedup.LOGGER.info("Offloading aspects registration..."); - ThaumicSpeedup.craftingRegistryKeys = ThreadLocal.withInitial(() -> ObjectSets.unmodifiable(new ObjectOpenHashSet<>(CraftingManager.REGISTRY.getKeys()))); - CommonInternals.objectTags.clear(); - registerItemAspects(); + ThaumicSpeedup.LOGGER.info("Beginning aspects registration..."); + Stopwatch stopwatch = Stopwatch.createStarted(); + CommonInternals.objectTags.clear(); + registerItemAspects(); + registerEntityAspects(); + AspectRegistryEvent are = new AspectRegistryEvent(); + are.register = ThaumicSpeedup.PROXY_INSTANCE; + MinecraftForge.EVENT_BUS.post(are); + ThaumicSpeedup.LOGGER.info("Aspects registration completed in {}.", stopwatch.stop()); + // Write aspects to cache + try { + stopwatch.start(); + File tempAspectsCache = File.createTempFile("thaumicspeedup-aspects_cache", null); + tempAspectsCache.deleteOnExit(); + FileOutputStream fileOutputStream = new FileOutputStream(tempAspectsCache); + ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); + Int2ObjectMap> objectTags = new Int2ObjectOpenHashMap<>(); + CommonInternals.objectTags.forEach((k, v) -> objectTags.put(k, v.aspects.entrySet().stream().collect(Object2IntArrayMap::new, (m, av) -> m.put(av.getKey().getTag(), av.getValue()), Map::putAll))); + objectOutputStream.writeObject(objectTags); + fileOutputStream.close(); + objectOutputStream.close(); + File thaumicSpeedupFolder = new File((File) Launch.blackboard.get("CachesFolderFile"), "thaumicspeedup"); + thaumicSpeedupFolder.mkdirs(); + File aspectsCache = new File(thaumicSpeedupFolder, "aspects_cache.bin"); + aspectsCache.createNewFile(); + Files.move(tempAspectsCache, aspectsCache); + ThaumicSpeedup.LOGGER.info("Aspects serialization complete! Taken {}.", stopwatch.stop()); + ThaumicSpeedup.lateObjectTags = new HashMap<>(); + } catch (IOException e) { + ThaumicSpeedup.LOGGER.error("Aspects serialization failed!"); + e.printStackTrace(); + } + } + // Before moving on make sure cache loading thread is finished. (if it was started) + if (ThaumicSpeedup.aspectsThread != null) { + try { + ThaumicSpeedup.aspectsThread.join(); + // since we don't serialize entity aspects make sure to initialize thaum's registerEntityAspects(); + // and send a dummy registry event for any entity aspects that get registered by other mods in that AspectRegistryEvent are = new AspectRegistryEvent(); + ThaumicSpeedup.PROXY_INSTANCE = new DummyAspectEventProxy(); are.register = ThaumicSpeedup.PROXY_INSTANCE; MinecraftForge.EVENT_BUS.post(are); - ThaumicSpeedup.LOGGER.info("Aspects registration complete! Taken {}, now writing to disk.", stopwatch.stop()); - try { - stopwatch.start(); - File tempAspectsCache = File.createTempFile("thaumicspeedup-aspects_cache", null); - tempAspectsCache.deleteOnExit(); - FileOutputStream fileOutputStream = new FileOutputStream(tempAspectsCache); - ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); - Int2ObjectMap> objectTags = new Int2ObjectOpenHashMap<>(); - CommonInternals.objectTags.forEach((k, v) -> objectTags.put(k, v.aspects.entrySet().stream().collect(Object2IntArrayMap::new, (m, av) -> m.put(av.getKey().getTag(), av.getValue()), Map::putAll))); - objectOutputStream.writeObject(objectTags); - fileOutputStream.close(); - objectOutputStream.close(); - File thaumicSpeedupFolder = new File((File) Launch.blackboard.get("CachesFolderFile"), "thaumicspeedup"); - thaumicSpeedupFolder.mkdirs(); - File aspectsCache = new File(thaumicSpeedupFolder, "aspects_cache.bin"); - aspectsCache.createNewFile(); - Files.move(tempAspectsCache, aspectsCache); - ThaumicSpeedup.LOGGER.info("Aspects serialization complete! Taken {}.", stopwatch.stop()); - } catch (IOException e) { - ThaumicSpeedup.LOGGER.error("Aspects serialization failed!"); - e.printStackTrace(); - } - ThaumicSpeedup.craftingRegistryKeys = null; - CommonInternals.jsonLocs = new HashMap<>(CommonInternals.jsonLocs); - CommonInternals.craftingRecipeCatalog = new HashMap<>(CommonInternals.craftingRecipeCatalog); - CommonInternals.craftingRecipeCatalogFake = new HashMap<>(CommonInternals.craftingRecipeCatalogFake); - CommonInternals.warpMap = new HashMap<>(CommonInternals.warpMap); - CommonInternals.seedList = new HashMap<>(CommonInternals.seedList); - }, "ThaumicSpeedup/AspectThread"); - ThaumicSpeedup.aspectsThread.start(); + } catch (InterruptedException e) { + e.printStackTrace(); + } } } diff --git a/src/main/java/zone/rong/thaumicspeedup/mixins/ThaumcraftApiMixin.java b/src/main/java/zone/rong/thaumicspeedup/mixins/ThaumcraftApiMixin.java index 2c175f5..0efa482 100644 --- a/src/main/java/zone/rong/thaumicspeedup/mixins/ThaumcraftApiMixin.java +++ b/src/main/java/zone/rong/thaumicspeedup/mixins/ThaumcraftApiMixin.java @@ -2,35 +2,54 @@ import net.minecraft.item.ItemStack; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.Overwrite; import thaumcraft.api.ThaumcraftApi; -import thaumcraft.api.aspects.AspectEventProxy; import thaumcraft.api.aspects.AspectList; import zone.rong.thaumicspeedup.ThaumicSpeedup; @Mixin(value = ThaumcraftApi.class, remap = false) public class ThaumcraftApiMixin { - @Redirect(method = "*", at = @At(value = "NEW", target = "Lthaumcraft/api/aspects/AspectEventProxy;()V")) - private static AspectEventProxy useProxyInstanceSingleton() { - return ThaumicSpeedup.PROXY_INSTANCE; + /** + * @author SumTingWong + * @reason Thaumcraft deprecated this method in version 6 with an event in AspectEventProxy to replace it + */ + @Deprecated + @Overwrite + public static void registerObjectTag(ItemStack item, AspectList aspects) { + if (item == null || item.isEmpty()) return; + ThaumicSpeedup.PROXY_INSTANCE.registerObjectTag(item, aspects); } - @Inject(method = "registerObjectTag(Lnet/minecraft/item/ItemStack;Lthaumcraft/api/aspects/AspectList;)V", at = @At("HEAD"), cancellable = true) - private static void disallowEmptyStacks(ItemStack item, AspectList aspects, CallbackInfo ci) { - if (item == null || item.isEmpty()) { - ci.cancel(); - } + /** + * @author SumTingWong + * @reason Thaumcraft deprecated this method in version 6 with an event in AspectEventProxy to replace it + */ + @Deprecated + @Overwrite + public static void registerObjectTag(String oreDict, AspectList aspects) { + ThaumicSpeedup.PROXY_INSTANCE.registerObjectTag(oreDict, aspects); } - @Inject(method = "registerComplexObjectTag(Lnet/minecraft/item/ItemStack;Lthaumcraft/api/aspects/AspectList;)V", at = @At("HEAD"), cancellable = true) - private static void disallowComplexEmptyStacks(ItemStack item, AspectList aspects, CallbackInfo ci) { - if (item == null || item.isEmpty()) { - ci.cancel(); - } + /** + * @author SumTingWong + * @reason Thaumcraft deprecated this method in version 6 with an event in AspectEventProxy to replace it + */ + @Deprecated + @Overwrite + public static void registerComplexObjectTag(ItemStack item, AspectList aspects) { + if (item == null || item.isEmpty()) return; + ThaumicSpeedup.PROXY_INSTANCE.registerComplexObjectTag(item, aspects); + } + + /** + * @author SumTingWong + * @reason Thaumcraft deprecated this method in version 6 with an event in AspectEventProxy to replace it + */ + @Deprecated + @Overwrite + public static void registerComplexObjectTag(String oreDict, AspectList aspects) { + ThaumicSpeedup.PROXY_INSTANCE.registerComplexObjectTag(oreDict, aspects); } } diff --git a/src/main/java/zone/rong/thaumicspeedup/mixins/ThaumcraftCraftingManagerMixin.java b/src/main/java/zone/rong/thaumicspeedup/mixins/ThaumcraftCraftingManagerMixin.java index e91d8cd..82f42c5 100644 --- a/src/main/java/zone/rong/thaumicspeedup/mixins/ThaumcraftCraftingManagerMixin.java +++ b/src/main/java/zone/rong/thaumicspeedup/mixins/ThaumcraftCraftingManagerMixin.java @@ -1,21 +1,24 @@ package zone.rong.thaumicspeedup.mixins; -import net.minecraft.item.crafting.CraftingManager; -import net.minecraft.util.registry.RegistryNamespaced; +import net.minecraft.item.ItemStack; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import thaumcraft.api.aspects.AspectList; +import thaumcraft.api.internal.CommonInternals; import thaumcraft.common.lib.crafting.ThaumcraftCraftingManager; import zone.rong.thaumicspeedup.ThaumicSpeedup; -import java.util.Set; - @Mixin(ThaumcraftCraftingManager.class) public class ThaumcraftCraftingManagerMixin { - @Redirect(method = "generateTagsFromCraftingRecipes", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/registry/RegistryNamespaced;getKeys()Ljava/util/Set;")) - private static Set getThreadSafeRegistry(RegistryNamespaced instance) { - return ThaumicSpeedup.craftingRegistryKeys == null ? CraftingManager.REGISTRY.getKeys() : ThaumicSpeedup.craftingRegistryKeys.get(); + @Inject(method = "generateTags(Lnet/minecraft/item/ItemStack;)Lthaumcraft/api/aspects/AspectList;", at = @At("RETURN"), remap = false) + private static void captureLateObjectTags(ItemStack is, CallbackInfoReturnable cir) { + if (ThaumicSpeedup.lateObjectTags != null) { + ThaumicSpeedup.lateObjectTags.put(CommonInternals.generateUniqueItemstackId(is), cir.getReturnValue()); + ThaumicSpeedup.LOGGER.debug("Captured late object tag for item: " + is.getItem().getRegistryName()); + } } } diff --git a/src/main/java/zone/rong/thaumicspeedup/mixins/bwm/ThaumcraftMixin.java b/src/main/java/zone/rong/thaumicspeedup/mixins/bwm/ThaumcraftMixin.java index df0846c..fb4f75c 100644 --- a/src/main/java/zone/rong/thaumicspeedup/mixins/bwm/ThaumcraftMixin.java +++ b/src/main/java/zone/rong/thaumicspeedup/mixins/bwm/ThaumcraftMixin.java @@ -7,6 +7,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Pseudo; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -33,8 +34,9 @@ private void disablePostInit(FMLPostInitializationEvent event, CallbackInfo ci) ci.cancel(); } + @Unique @SubscribeEvent - public void registerAspects(AspectRegistryEvent event) { + public void thaumicSpeedup$registerAspects(AspectRegistryEvent event) { this.registerAspectOverrides(); this.registerAspects(); registerAnvilRecipeAspects();