diff --git a/.gitignore b/.gitignore index d3754c4c8f..c134175e62 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +#forgedev dev if the folder exists in here +forgedev + #eclipse **/bin **/.settings @@ -22,10 +25,12 @@ /*/build /*/.gradle +# Minecraft +/run +/*.launch + # Projects repo, either ignore it, or ignore patches. -/projects/mcp/ -/projects/clean/ -/projects/forge/ +src/minecraft #occupational hazards /projects/**/build/ @@ -48,3 +53,8 @@ src/*/generated/**/.cache/ /*/.factorypath /*/.apt_generated/ /fmlcore/logs/ +/lib/ +/_actual/ +/runs/ +/forge.ipr +/forge.iws diff --git a/LICENSE.txt b/LICENSE.txt index 249debe26b..51c22dd7db 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -3,7 +3,7 @@ parts herein are licensed under the terms of the LGPL 2.1 found here http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt and copied below. -Homepage: http://minecraftforge.net/ +Homepage: https://minecraftforge.net/ https://github.com/MinecraftForge/MinecraftForge diff --git a/build.gradle b/build.gradle index d99a97e636..46ebfa85f0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,57 +1,798 @@ -import net.minecraftforge.forge.tasks.* -import net.minecraftforge.gradleutils.PomUtils +import org.apache.tools.ant.filters.ReplaceTokens plugins { - id 'net.minecraftforge.licenser' version '1.0.1' - id 'com.github.ben-manes.versions' version '0.46.0' - id 'net.minecraftforge.gradleutils' version '[2.6.4,2.7)' + id 'java-library' + id 'idea' id 'eclipse' - id 'de.undercouch.download' version '5.4.0' - id 'net.minecraftforge.gradle.patcher' version '[6.0.51,6.2)' apply false - id 'net.minecraftforge.gradle.mcp' version '[6.0.51,6.2)' apply false - id 'net.minecraftforge.gradlejarsigner' version '1.0.4' - //id 'org.barfuin.gradle.taskinfo' version '3.0.1' + id 'maven-publish' + alias libs.plugins.licenser + alias libs.plugins.versions + alias libs.plugins.gradleutils + alias libs.plugins.gitversion + alias libs.plugins.changelog + alias libs.plugins.renamer + alias libs.plugins.jarsigner + id 'net.minecraftforge.forgedev' + id 'net.minecraftforge.forge.build.convention' } -Util.init() //Init all our extension methods! +gradleutils.displayName = 'Forge' +group = 'net.minecraftforge' +description = 'Modifications to Minecraft to enable mod developers.' -ext { - VERSION = gitversion.getMCTagOffsetBranch(MC_VERSION) - FORGE_VERSION = VERSION.substring(MC_VERSION.length() + 1) +// NOTE: See settings.gradle for all the referenceable version variables. +// All subprojects (that apply 'net.minecraftforge.forge.build.convention') will have these available. +println "Version: $version" + +java.toolchain.languageVersion = JavaLanguageVersion.of(javaVersion) + +jarSigner.autoDetect('forge') + +// We have to tell ForgeDev to use the exact versions of tools we ship in the installer +fdtools { + configure('binpatcher') { + version = buildLibs.binarypatcher.get().version + } + configure('installertools') { + version = buildLibs.installertools.get().version + } + configure('jarcompatibilitychecker') { + javaLauncher = javaToolchains.launcherFor(java.toolchain) + } +} +renamerTools { + configure('classes') { + artifact = buildLibs.renamer.get().toString() + ':all' + } + configure('srg2source') { + version = buildLibs.srg2source.get().version + javaLauncher = javaToolchains.launcherFor(java.toolchain) + } } -changelog { - from '65.0' +/* This is used for debugging, comparing all published artifacts against actual production +forgedev.validatePublish { + task { + baseBranch = 'upstream/26.1.2' + versionPrefix = minecraftVersion + } +} +*/ + +final minecraftFiles = forgedev.minecraftFiles(minecraftVersion) + +final mcpBase = forgedev.mcpBase { + mcpVersion = "${minecraftVersion}-${project.ext.mcpVersion}" + accessTransformers.from file('src/main/resources/META-INF/accesstransformer.cfg') + sideAnnotationStrippers.from file('src/main/resources/forge.sas') +} + +forgedev.patches { + base = mcpBase + patches = file('patches/minecraft') + patched = file('src/minecraft/java') + sourceSets.main.java.srcDir patched } tasks.register('setup') { - dependsOn ':forge:extractMapped' - if (findProject(':clean')) - dependsOn ':clean:extractMapped' + dependsOn forgedev.patches.apply } -tasks.register('doChecks') { - dependsOn ':forge:checkJarCompatibility' - dependsOn ':forge:publish' -} - -project(':mcp') { - apply plugin: 'net.minecraftforge.gradle.mcp' - mcp { - config MC_VERSION + '-' + MCP_VERSION - pipeline = 'joined' +sourceSets { + named('main') { + resources.srcDir 'src/main/generated' } - repositories { - mavenLocal() + named('test') { + resources.srcDir 'src/test/generated' } } -if (System.env.TEAMCITY_VERSION) { - //Only setup the CI environment if and only if the environment variables are set. - tasks.named('configureTeamCity').configure { - doLast { - println "##teamcity[buildNumber '${project(':forge').version}']" - println "##teamcity[setParameter name='env.PUBLISHED_JAVA_ARTIFACT_VERSION' value='${project(':forge').version}']" +license { + header = file('LICENSE-header.txt') + + include 'net/minecraftforge/' + exclude 'net/minecraftforge/common/LenientUnboundedMapCodec.java' + + tasks.tap { + register('main') { + files.from files('src/main/java') + } + + register('test') { + files.from files('src/test/java') } } } + +changelog { + from changelogBase + publishAll = false +} + +// TODO [ForgeDev] Support compileOnlyApi, runtimeOnly, and a consumable annotation processor configuration +configurations { + // Don't pull all libraries, if we're missing something, add it to the installer list so the installer knows to download it. + register('bootstrap') { + transitive = false + canBeDeclared = true + canBeResolved = true + } + + register('installer') { + transitive = false + canBeDeclared = true + canBeResolved = true + extendsFrom(bootstrap) + } + + named('api') { + extendsFrom(installer) + } + + named('implementation') { + // Inherit vanilla Minecraft's dependencies + extendsFrom(mcpBase.dependencyConfiguration) + } +} + +dependencies { + // These need to actually be on the classpath at the start. This is only used for the server shim jar. + // And this is only needed because custom file systems are REQUIRED to be on the boot classloader. + // This has ASM/BootStrap/Unsafe all because I haven't gotten around to moving UnionFileSystem out to its own project. + bootstrap libs.jarjar.fs // JarInJar file system + bootstrap libs.roimfs // JarInJar File System - FileSystems need to be on boot loader. + bootstrap libs.bundles.jimfs // In memory file system used for ForgeDev launches + bootstrap libs.securemodules // Has Union file system in it + bootstrap libs.unsafe // Needed by securemodules + bootstrap libs.bundles.asm // Needed by securemodules + + implementation libs.jopt.simple + + installer libs.bootstrap + installer libs.bootstrap.api // Needed by securemodules + installer libs.accesstransformers + installer libs.eventbus + installer libs.jspecify // Dep of EventBus + installer libs.forgespi + installer libs.coremods.api + installer libs.modlauncher + installer libs.mergetool.api + installer libs.bundles.night.config + installer libs.maven.artifact + installer libs.bundles.terminalconsoleappender + installer libs.mixin + installer libs.mixinextras.forge + installer libs.bundles.jarjar + installer libs.roimfs + + installer projects.fmlcore + installer projects.fmlloader + installer projects.fmlearlydisplay + installer projects.javafmllanguage + installer projects.lowcodelanguage + installer projects.mclanguage + installer projects.forgeTransformers + + runtimeOnly files(mcpBase.extra) + + runtimeOnly libs.bootstrap + runtimeOnly libs.bootstrap.dev + + annotationProcessor libs.eventbus.validator +} + +final EXTRA_TXTS = [ + file('LICENSE.txt'), + changelog.task.flatMap(task -> task.outputFile) +] +forgedev.runs { + configureEach { + options { + workingDir = layout.projectDirectory.dir("runs/$name") + + mainClass = 'net.minecraftforge.bootstrap.ForgeBootstrap' + args '--gameDir', '.' + jvmArgs '-Djava.net.preferIPv6Addresses=system', '-XX:+UseCompactObjectHeaders' + + systemProperty 'bsl.debug', 'true' + systemProperty 'terminal.jline', 'true' + with(sourceSets.test) { + systemProperty 'forge.enableGameTest', 'true' + systemProperty 'forgedev.enableTestMods', 'true' + } + } + } + + create('client') { + options { + systemProperty 'eventbus.api.strictRuntimeChecks', 'true' + systemProperty 'org.lwjgl.system.SharedLibraryExtractDirectory', 'lwjgl_dll' + + args '--launchTarget', 'forge_dev_client', + '--username', 'Dev', + '--version', project.name, + '--accessToken', '0', + '--userType', 'mojang', + '--versionType', 'release', + '--assetsDir', '{assets_root}', + '--assetIndex', '{asset_index}' + } + } + + create('server') { + options { + args '--launchTarget', 'forge_dev_server' + } + } + + create('gameTestServer') { + options { + args '--launchTarget', 'forge_dev_server_gametest' + args '--uniqueWorld' // Unique world is used so that the world regenerates, as well as the world config isn't influenced by other runs + } + } + + create('data') { + options { + args '--launchTarget', 'forge_dev_data', + '--all', + '--existing', sourceSets.main.resources.srcDirs[0], + '--assetsDir', '{assets_root}', + '--assetIndex', '{asset_index}' + + with(sourceSets.main) { + args '--mod', 'forge', + '--output', rootProject.file('src/main/generated/') + } + + with(sourceSets.test) { + args '--mod', '.+', + '--existing', sourceSets.test.resources.srcDirs[0], + '--output', rootProject.file('src/test/generated/') + } + } + } + + create('clientData') { + options { + args '--all', + '--existing', sourceSets.main.resources.srcDirs[0], + '--assetsDir', '{assets_root}', + '--assetIndex', '{asset_index}' + + with(sourceSets.main) { + args '--launchTarget', 'forge_dev_client_data', + '--mod', 'forge', + '--output', rootProject.file('src/main/generated/'), + '--mod', 'forge' + } + + with(sourceSets.test) { + args '--launchTarget', 'forge_dev', + '--launchEntry', 'minecraft/net.minecraft.client.data.Main', + '--launchData', + '--mod', '.+', + '--existing', sourceSets.test.resources.srcDirs[0], + '--output', rootProject.file('src/test/generated/') + } + } + } +} +tasks.register('genAllData') { + dependsOn forgedev.runs.data.run, forgedev.runs.data.runTest, forgedev.runs.clientData.run, forgedev.runs.clientData.runTest +} + +final serverShim = forgedev.shim { + config { + mainClass = 'net.minecraftforge.bootstrap.ForgeBootstrap' + args = ['--launchTarget', 'forge_server'] + } + classpath { + libraries configurations.installer + library tasks.named('universalJar', Jar) + library forgedev.binaryPatches('server').apply, 'server' + serverBundle.fileProvider(minecraftFiles.server) + } + bootstrapClasspath(configurations.bootstrap) + jar { + jarSigner.sign(it) + } +} + +final finalizeSpawn = forgedev.methodCallFinder('findFinalizeSpawnTargets') { + jar.fileProvider(mcpBase.classes) + output = rootProject.file('forge-transformers/src/main/resources/coremods/finalize_spawn_targets.json') + blacklist 'net/minecraft/world/level/BaseSpawner' // Ignore this class as we special case it. + invokeVirtual('finalizeSpawn', '(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/EntitySpawnReason;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;') +} + +forgedev.validateDeprecations(tasks.named('jar', Jar)) { + mcVersion = minecraftVersion +} + +forgedev.checks() { + base = mcpBase + ats {} + sas {} + execs {} + + patches { + dependsOn forgedev.patches.make + patchDir = forgedev.patches.patches + patchesWithS2SArtifact = [ + 'minecraft/net/minecraft/client/renderer/ViewArea.java.patch', + 'minecraft/net/minecraft/data/models/blockstates/Variant.java.patch', + ] + } + + fix { + dependsOn finalizeSpawn + } + + forgedev.patches.make.configure { + finalizedBy forgedev.checks.patches.fix + } +} + +final crowdin = forgedev.crowdin // Create the crowdin tasks +tasks.named('jar', Jar) { + from(EXTRA_TXTS) + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + exclude '.cache' + + from(zipTree(crowdin.flatMap { it.output } )) { + include 'assets/forge/lang/*.json' + } + + manifest { + attributes([ + 'Automatic-Module-Name': 'net.minecraftforge.forge' + ]) + attributes([ + 'Specification-Title' : gradleutils.displayName.get(), + 'Specification-Vendor' : gradleutils.vendor.get(), + 'Specification-Version' : gitversion.info.tag, + 'Implementation-Title' : project.group, + 'Implementation-Vendor' : gradleutils.vendor.get(), + 'Implementation-Version': forgeVersion + ], 'net/minecraftforge/versions/forge/') + attributes([ + 'Specification-Title' : 'Minecraft', + 'Specification-Vendor' : gradleutils.vendor.get(), + 'Specification-Version' : minecraftVersion, + 'Implementation-Title' : 'MCP', + 'Implementation-Vendor' : gradleutils.vendor.get(), + 'Implementation-Version': mcpVersion + ], 'net/minecraftforge/versions/mcp/') + } + jarSigner.sign(it) +} + +final universalJar = tasks.register('universalJar', Jar) { + from (zipTree(tasks.named('jar', Jar).flatMap { it.archiveFile } )) { + exclude(forgedev.filterVanilla(mcpBase.classes)) + } + manifest = tasks.named('jar', Jar).get().manifest + archiveClassifier = 'universal' + jarSigner.sign(it) +} + +final sourcesJarAll = tasks.register('sourcesJarAll', Jar) { + archiveClassifier = 'sources-all' + from(sourceSets.main.allJava.srcDirs) +} + +// Our sources, plus the patches we do to Vanilla Minecraft +final sourcesJar = tasks.register('sourcesJar', Jar) { + archiveClassifier = 'sources' + from(sourceSets.main.allJava.srcDirs - forgedev.patches.patched.asFile.get()) + mustRunAfter(forgedev.patches.make) + from(forgedev.patches.patches) { + into 'patches/' + } +} + +forgedev.userDev { + base(mcpBase) + + config { + universal universalJar + sources sourcesJar + addLibraries(configurations.installer) + // TODO [ForgeDev][UserDev] Split API/Runtime elements in userdev config + // so we don't gotta keep making exceptions for MixinExtras + addCompileDependency(libs.mixinextras.common) + addAnnotationProcessorDependency(libs.mixinextras.common) + + // TODO [ForgeDev] Consolidate Patcher + UserDev Config runs in a sane way + runs { + configureEach { + parents = [] + main = 'net.minecraftforge.bootstrap.ForgeBootstrap' + args '--gameDir', '.' + jvmArgs '-Djava.net.preferIPv6Addresses=system', '-XX:+UseCompactObjectHeaders' + client = it.name.containsIgnoreCase('client') + environment 'MCP_MAPPINGS', '{mcp_mappings}' + } + + register('clientData') { + args '--launchTarget', "forge_userdev_client_data" + args '--assetIndex', '{asset_index}' + args '--assetsDir', '{assets_root}' + } + + register('client') { + property 'forge.enableGameTest', 'true' + args '--launchTarget', "forge_userdev_client" + args '--version', 'MOD_DEV' + args '--assetIndex', '{asset_index}' + args '--assetsDir', '{assets_root}' + } + + register('server') { + property 'forge.enableGameTest', 'true' + args '--launchTarget', "forge_userdev_server" + } + + register('gameTestServer') { + args '--launchTarget', "forge_userdev_server_gametest" + } + + register('data') { + args '--launchTarget', "forge_userdev_data" + args '--assetIndex', '{asset_index}' + args '--assetsDir', '{assets_root}' + } + } + } + patches { + modified.setFrom(sourcesJarAll.flatMap { it.archiveFile }) + } + binaryPatches { + mustRunAfter(forgedev.patches.make) + patches.setFrom(forgedev.patches.patches) + dirty.setFrom(tasks.named('jar', Jar).flatMap { it.archiveFile }) + } +} + +forgedev.userdevCompatibility(minecraftVersion) { + clean = mcpBase.classes + dirty = tasks.named('jar', Jar) +} + +// region Installer tasks, Not needed when we simplify the installer/remove obf +final clientBinPatches = forgedev.binaryPatches('client') { + clean = minecraftFiles.client + // Workaround for 3rd party launcher issues, marker needed to locate MC, store needed to fix zlib-ng issues + apply { + store = true + marker = '.forge_patched_minecraft' + } +} +final serverBinPatches = forgedev.binaryPatches('server') { + clean = minecraftFiles.serverExtracted + apply { store = true } +} +// endregion + +forgedev.installer { + dev = !forgedev.ci + offline = false + baseVersion = buildLibs.installer.get().version.toString() + + // Add extra libraries + pack serverShim.jar // The Server executable jar IS needed to be packed, as the installer would need a spec bump in order to download it + pack universalJar // I don't think this is strictly needed to be packed anymore, will need to double check later + + launcherLibrary universalJar + // We configure the launcher here to keep the order for easier diff, after publishing, move this to the LauncherJson configuration below + launcherJson { + // We create this during install, so it's not downloadable + generated(clientBinPatches.apply, 'client') + } + + launcherLibraries configurations.installer + + final launcherId = "${minecraftVersion}-${project.name}-${forgeVersion}" + final installertools = tool(buildLibs.installertools) + final binarypatcher = tool(buildLibs.binarypatcher) + final renamer = tool(buildLibs.renamer) + + jar { + from(EXTRA_TXTS) + from(rootProject.file('/forge_installer_logo.png')) { + rename { 'big_logo.png' } + } + from(clientBinPatches.create.flatMap { t -> t.output }) { + rename { 'data/client.lzma' } + } + from(serverBinPatches.create.flatMap { t -> t.output }) { + rename { 'data/server.lzma' } + } + + final argsFile = rootProject.file('server_files/args.txt') + final tokens = [tokens: [ + SHIM_JAR_FILE: serverShim.jar.get().archiveFileName.get(), + MAVEN_PATH: forgedev.mavenArtifact.directory + ]] + from(argsFile) { + filter(tokens, ReplaceTokens) + into 'data' + rename { 'unix_args.txt' } + } + from(argsFile) { + filter(tokens, ReplaceTokens) + into 'data' + rename { 'win_args.txt' } + } + + from(rootProject.file('server_files')) { + filter(tokens, ReplaceTokens) + into 'data' + exclude 'args.txt' + } + + jarSigner.sign(it) + } + json { + icon = rootProject.file('icon.ico') + executable serverShim.jar + minecraft = minecraftVersion + profileVersion = launcherId + + final projectArtifact = "${project.group}:${project.name}:${project.version}" + + data 'MC_UNPACKED', "[net.minecraft:client:${minecraftVersion}]", "[net.minecraft:server:${minecraftVersion}:unpacked]" + data 'MC_UNPACKED_SHA', minecraftFiles.client, minecraftFiles.serverExtracted + + data 'BINPATCH', '/data/client.lzma', '/data/server.lzma' + data 'PATCHED', "[$projectArtifact:client]", "[$projectArtifact:server]" + data 'PATCHED_SHA', clientBinPatches.apply.flatMap { it.output }, serverBinPatches.apply.flatMap { it.output } + + steps = [ + extract(installertools) { + side = 'server' + archive '{INSTALLER}' + extract 'data/README.txt', '{ROOT}/README.txt' + extract 'data/run.sh', '{ROOT}/run.sh' + executable '{ROOT}/run.sh' + extract 'data/run.bat', '{ROOT}/run.bat' + optional 'data/user_jvm_args.txt', '{ROOT}/user_jvm_args.txt' + extract 'data/unix_args.txt', "{ROOT}/libraries/${forgedev.mavenArtifact.directory}/unix_args.txt" + extract 'data/win_args.txt', "{ROOT}/libraries/${forgedev.mavenArtifact.directory}/win_args.txt" + }, + extractBundle(installertools) { + side = 'server' + libraries() + }, + extractBundle(installertools) { + side = 'server' + jar '{MINECRAFT_JAR}', '{MC_UNPACKED}' + cache '{MC_UNPACKED}', '{MC_UNPACKED_SHA}' + }, + step(binarypatcher) { + side = 'server' + args = [ + '--clean', '{MC_UNPACKED}', + '--output', '{PATCHED}', + '--apply', '{BINPATCH}', + '--data', '--unpatched', + '--store' + ] + cache '{PATCHED}', '{PATCHED_SHA}' + }, + step(binarypatcher) { + side = 'client' + args = [ + '--clean', '{MINECRAFT_JAR}', + '--output', '{PATCHED}', + '--apply', '{BINPATCH}', + '--data', '--unpatched', + '--store', + '--marker', '.forge_patched_minecraft' + ] + cache '{PATCHED}', '{PATCHED_SHA}' + } + ] + } + + launcherJson { + // These are flags to preserve glitchy old behavior to make diffing easier, removing when migrating to production is recommended + sortLibraries = false // Don't sort, makes things non-deterministic, but easier to diff old versions + duplicateLibraries = true // Our 'bootstrap' layer go added twice + librariesLast = false // Makes libraries be added before args + + id = launcherId + inheritsFrom = minecraftVersion + mainClass = 'net.minecraftforge.bootstrap.ForgeBootstrap' + gameArgs = [ '--launchTarget', 'forge_client' ] + jvmArgs = [ '-Djava.net.preferIPv6Addresses=system', '-XX:+UseCompactObjectHeaders' ] + } +} + +final mdkGradleWrapper = tasks.register('mdkGradleWrapper', Wrapper) { + gradleVersion = '9.5.0' + scriptFile = layout.buildDirectory.dir("wrapper/" + gradleVersion + "/gradlew") + jarFile = layout.buildDirectory.dir("wrapper/" + gradleVersion + "/gradle/wrapper/gradle-wrapper.jar") +} + +final mdkZip = tasks.register('mdkZip', Zip) { + dependsOn mdkGradleWrapper + + archiveBaseName = project.name + archiveClassifier = 'mdk' + archiveVersion = project.version + destinationDirectory = file('build/libs') + from(EXTRA_TXTS) + + from mdkGradleWrapper.map(Wrapper.&getScriptFile) + from mdkGradleWrapper.map(Wrapper.&getBatchScript) + into('gradle/wrapper/') { + from mdkGradleWrapper.map(Wrapper.&getJarFile) + from mdkGradleWrapper.map(Wrapper.&getPropertiesFile) + } + from(rootProject.file('mdk/')){ + rootProject.file('mdk/gitignore.txt').eachLine { + if (!it.trim().isEmpty() && !it.trim().startsWith('#')) + exclude it + } + filter(ReplaceTokens, tokens: [ + FORGE_VERSION: forgeVersion, + FORGE_GROUP: project.group, + FORGE_NAME: project.name, + MC_VERSION: minecraftVersion, + FORGE_SPEC_VERSION: gitversion.info.tag.split("\\.")[0], + MC_NEXT_VERSION: minecraftNextVersion, + EVENTBUS_VERSION: libs.versions.eventbus.get() + ]) + rename 'gitignore\\.txt', '.gitignore' + rename 'gitattributes\\.txt', '.gitattributes' + } + from(rootProject.file('src/test/java/com/example/examplemod/')) { + into('src/main/java/com/example/examplemod/') + } + from(rootProject.file('src/test/generated/mdk_datagen/')) { + into('src/main/resources/') + exclude '**/.cache/' + } +} + +/* +tasks.named('javadoc', Javadoc) { + description = 'Generates the combined javadocs for the FML projects and the main Forge project' + var includedProjects = [ ':fmlcore', ':fmlloader', ':javafmllanguage', ':mclanguage', ':forge-transformers' ] + source includedProjects.collect { project(it).sourceSets.main.allJava } + classpath = classpath + files(includedProjects.collect { project(it).sourceSets.main.compileClasspath }) + + var docsDir = rootProject.file('src/docs/') + inputs.dir(docsDir) + .withPropertyName('docs resources directory') + .withPathSensitivity(PathSensitivity.RELATIVE) + .optional() + + failOnError = false + + // Exclude the Minecraft classes if not enabled + if (!project.hasProperty('generateAllDocumentation')) { + exclude 'net/minecraft/**' + exclude 'com/mojang/**' + } + exclude 'mcp/**' + + options { + stylesheetFile = new File(docsDir, 'stylesheet.css') + + tags = [ + 'apiNote:a:API Note:', + 'implSpec:a:Implementation Requirements:', + 'implNote:a:Implementation Note:' + ] + + groups = [ + 'Forge Mod Loader': [ + 'net.minecraftforge.fml.common.asm*', + 'net.minecraftforge.fml.loading*', + 'net.minecraftforge.fml.server*' + ], + 'FML Core': [ + 'net.minecraftforge.fml', + 'net.minecraftforge.fml.config*', + 'net.minecraftforge.fml.event*', + 'net.minecraftforge.fml.util*' + ], + 'FML Common': [ + 'net.minecraftforge.fml.core', + 'net.minecraftforge.fml.event.config', + 'net.minecraftforge.fml.event.lifecycle' + ], + 'FML Java/MC Language Providers': [ + 'net.minecraftforge.fml.common', + 'net.minecraftforge.fml.javafmlmod', + 'net.minecraftforge.fml.mclanguageprovider' + ], + 'Minecraft Forge API': [ + 'net.minecraftforge*' + ] + ] + + author = false + noSince = true + noHelp = true + + bottom = "Minecraft Forge is an open source modding API for Minecraft: Java Edition, licensed under the Lesser GNU General Public License, version 2.1." + windowTitle = "Minecraft Forge API ${version}" + docTitle = "Minecraft Forge API - ${forgeVersion} for Minecraft ${minecraftVersion}" + header = "
${forgeVersion} for Minecraft ${minecraftVersion}
" + } + + doLast { + project.copy { + from docsDir + exclude '/stylesheet.css' + into destinationDir + } + } +} +*/ + +publishing { + repositories { + maven gradleutils.publishingForgeMaven + } + + publications.register('mavenJava', MavenPublication) { + changelog.publish(it) + gradleutils.promote(it) + + artifact universalJar + artifact forgedev.installer.jar + artifact mdkZip + artifact forgedev.userDev.jar + artifact sourcesJar + artifact serverShim.jar + + pom { + description = project.description + + gradleutils.pom.addRemoteDetails(pom) + + licenses { + license gradleutils.pom.licenses.LGPLv2_1 + } + } + } +} + + +/* +// These are debugging tasks that are only used when developing ForgeDevPlugin, to bulk test task's config/caching +// region ForgeDev Tests +def all = tasks.register('all') {} +afterEvaluate { + if (gradle.startParameter.taskNames.contains('all')) { + tasks.forEach { task -> // This forces everything to be realized, which is why we have the startParameter check + if (!gradle.startParameter.isTaskGraph() && task.name.startsWith('run')) return + if (task.name in [all.name, 'dependencyInsight', 'dependencies', 'dependencyUpdates', 'init', 'buildEnvironment', 'idea', + 'eclipse', 'javaToolchains', 'outgoingVariants', 'projects', 'properties', 'resolvableConfigurations', 'tasks', 'updateDaemonJvm', + 'generateActionsWorkflow' + ]) return + if (task.name.startsWith('clean')) return + if (task.name == 'checkJarCompatibility') return // This doesn't work in FG6 dev, I think it's cuz we check vs srg names. Will need to look at later + all.configure { dependsOn(task) } + } + } +} +*/ +// endregion +// We dont have any unit tests, so disable this error +tasks.withType(AbstractTestTask).configureEach { + failOnNoDiscoveredTests = false +} +// This shouldn't be needed according to the Gradle devs, as we never run these commands together. +// But in another case of Gradle being gradle, here we are +[ 'makePatches', 'compileJava', 'checkLicenseMain', 'updateLicenseMain', 'sourcesJar', 'sourcesJarAll' ] + .each{ tasks.named(it).configure{ mustRunAfter forgedev.patches.apply }} +forgedev.runs.configureEach { + run.configure { dependsOn finalizeSpawn} + runTest.configure { dependsOn finalizeSpawn} +} diff --git a/buildSrc/.gitignore b/buildSrc/.gitignore deleted file mode 100644 index 2979d33310..0000000000 --- a/buildSrc/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/.gradle/ -/build/ -/out/ diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle deleted file mode 100644 index c3e2c4e2b5..0000000000 --- a/buildSrc/build.gradle +++ /dev/null @@ -1,14 +0,0 @@ -repositories { - maven { url = 'https://maven.minecraftforge.net/' } - mavenCentral() -} - -dependencies { - implementation 'org.ow2.asm:asm:9.9.1' - implementation 'org.ow2.asm:asm-tree:9.9.1' - implementation 'net.minecraftforge:srgutils:0.6.2' - implementation 'net.minecraftforge:JarJarMetadata:0.3.27' - implementation 'commons-io:commons-io:2.13.0' - implementation 'com.google.code.gson:gson:2.10.1' - implementation 'org.eclipse.jgit:org.eclipse.jgit:6.7.0.202309050840-r' -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/BundleList.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/BundleList.groovy deleted file mode 100644 index ad9bed5f55..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/BundleList.groovy +++ /dev/null @@ -1,67 +0,0 @@ -package net.minecraftforge.forge.tasks - -import org.gradle.api.tasks.* -import org.gradle.api.DefaultTask -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.tasks.bundling.AbstractArchiveTask - -import java.util.zip.ZipFile - -abstract class BundleList extends DefaultTask { - @InputFiles abstract ConfigurableFileCollection getConfig() - @InputFile abstract RegularFileProperty getServerBundle() - @OutputFile abstract RegularFileProperty getOutput() - - BundleList() { - config.setFrom(project.configurations.installer) - output.convention(project.layout.buildDirectory.file("$name/output.list")) - configure { - dependsOn(project.tasks.universalJar) - inputs.file(project.tasks.universalJar.archiveFile) - dependsOn(project.tasks.applyServerBinPatches) - inputs.file(project.tasks.applyServerBinPatches.output) - } - } - - @TaskAction - void run() { - def entries = [:] as TreeMap - def resolved = project.configurations.installer.resolvedConfiguration.resolvedArtifacts - for (def dep : resolved) { - def info = Util.getMavenInfoFromDep(dep) - //println("$dep.file.sha1\t$info.name\t$info.path") - entries.put("$info.art.group:$info.art.name", "$dep.file.sha256\t$info.name\t$info.path") - } - - var packed = (AbstractArchiveTask) project.tasks.universalJar - var info = Util.getMavenInfoFromTask(packed) - def file = packed.archiveFile.get().asFile - entries.put("$info.art.group:$info.art.name:$info.art.classifier", "$file.sha256\t$info.name\t$info.path") - - var classifier = 'server' - var genned = project.tasks.applyServerBinPatches - info = Util.getMavenInfoFromTask(genned, classifier) - file = genned.output.get().asFile - entries.put("$info.art.group:$info.art.name:$info.art.classifier", "$file.sha256\t$info.name\t$info.path") - - try (def zip = new ZipFile(serverBundle.get().asFile)) { - def entry = zip.getEntry('META-INF/libraries.list') - def data = zip.getInputStream(entry).text.split('\n') - for (def line : data) { - def (sha, artifact, path) = line.split('\t') - def (group, name, other) = artifact.split(':', 3) - //println("Group: $group Name: $name") - def key = "$group:$name" - if (other.indexOf(':') != -1){ - key += ':' + other.split(':', 2)[1] - //println("\tKey: $key") - } - if (!entries.containsKey(key)) - entries.put(key, line) - } - } - - output.get().asFile.text = entries.values().join('\n') - } -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/BytecodeFinder.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/BytecodeFinder.groovy deleted file mode 100644 index 8f8271f490..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/BytecodeFinder.groovy +++ /dev/null @@ -1,52 +0,0 @@ -package net.minecraftforge.forge.tasks - -import groovy.json.JsonBuilder -import groovy.transform.CompileStatic -import org.gradle.api.DefaultTask -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.tasks.InputFile -import org.gradle.api.tasks.Internal -import org.gradle.api.tasks.TaskAction -import org.objectweb.asm.tree.ClassNode -import org.objectweb.asm.tree.FieldNode -import org.objectweb.asm.tree.MethodNode - -@CompileStatic -abstract class BytecodeFinder extends DefaultTask { - @InputFile abstract RegularFileProperty getJar() - // It should be fine to mark the output as internal as we want to control when we run it anyways. - // This also shuts Gradle 8 up about implicit task dependencies. - @Internal abstract RegularFileProperty getOutput() - - BytecodeFinder() { - output.convention(project.layout.buildDirectory.dir(name).map { it.file("output.json") }) - } - - @TaskAction - protected void exec() { - Util.init() - - var outputFile = output.get().asFile - if (outputFile.exists()) - outputFile.delete() - - pre() - - Util.processClassNodes(jar.get().asFile, this.&process) - - post() - outputFile.text = new JsonBuilder(getData()).toPrettyString() - } - - - protected process(ClassNode node) { - if (node.fields !== null) node.fields.each { process(node, it) } - if (node.methods !== null) node.methods.each { process(node, it) } - } - - protected pre() {} - protected process(ClassNode parent, FieldNode node) {} - protected process(ClassNode parent, MethodNode node) {} - protected post() {} - protected abstract Object getData() -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/BytecodePredicateFinder.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/BytecodePredicateFinder.groovy deleted file mode 100644 index b0efa482cc..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/BytecodePredicateFinder.groovy +++ /dev/null @@ -1,48 +0,0 @@ -package net.minecraftforge.forge.tasks - -import groovy.transform.CompileStatic -import org.gradle.api.provider.Property -import org.gradle.api.tasks.Internal -import org.objectweb.asm.Opcodes -import org.objectweb.asm.tree.ClassNode -import org.objectweb.asm.tree.MethodNode - -@CompileStatic -abstract class BytecodePredicateFinder extends BytecodeFinder { - - @Internal - abstract Property> getPredicate() - - private final Map> matches = new TreeMap<>(Comparator.naturalOrder()) - - @Override - protected process(ClassNode parent, MethodNode node) { - for (final current : node.instructions) { - if (predicate.get().call(parent, node, current)) { - var methods = matches.compute(parent.name, { k, v -> v ?: new ArrayList<>() }) - - // only add non-synthetic methods - if ((node.access & Opcodes.ACC_SYNTHETIC) == 0) { - methods.add(node.name + node.desc) - } - - return - } - } - } - - @Internal - @Override - protected Object getData() { - var array = new ArrayList() - matches.forEach { c, m -> - { - array.add( - 'class': c, - 'methods': m - ) - } - } - return array ?: { throw new RuntimeException('Failed to find any targets, please ensure that method names and descriptors are correct.') }() - } -} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/CleanProperties.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/CleanProperties.groovy deleted file mode 100644 index 676ac30300..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/CleanProperties.groovy +++ /dev/null @@ -1,97 +0,0 @@ -package net.minecraftforge.forge.tasks; - -import groovy.transform.CompileDynamic; -import groovy.transform.CompileStatic; - -import java.util.Properties; -import java.util.Enumeration; -import java.util.Map; -import java.util.TreeSet; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.Reader; -import java.io.InputStreamReader; -import java.io.IOException; -import java.io.OutputStream; -import java.io.Writer; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.Set; - -/** - * Eclipse config files are literally just java properties, with the header cleaned up. - * https://github.com/eclipse/buildship/blob/5b2c7fca7fa86cd74d71b3c099c7b1559eba038e/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/PreferenceStore.java#L238 - * - * This does the same thing, as well as sorting alphabetically. - * It also ignores all comments. We can add them latter if someone cares. - */ -@CompileStatic -public class CleanProperties extends Properties { - private static final long serialVersionUID = 1L; - private static final String LINE_SEP = System.getProperty("line.separator"); - private static final String UNIX_LINE_SEP = "\n"; - private static final Charset ENCODING = StandardCharsets.UTF_8; - - public CleanProperties load(File input) throws IOException { - if (input.exists()) { - try (Reader is = new InputStreamReader(new FileInputStream(input), ENCODING)) { - super.load(is); - } - } - return this; - } - - public void store(File out) throws IOException { - if (!out.getParentFile().exists()) - out.getParentFile().mkdirs(); - - try (OutputStream os = new FileOutputStream(out)) { - store(os, null); - } - } - - @Override - public synchronized Enumeration keys() { - Set ret = new TreeSet<>(); - for (Enumeration e = super.keys(); e.hasMoreElements();) - ret.add(e.nextElement()); - return Collections.enumeration(ret); - } - - @CompileDynamic - @Override - public Set> entrySet() { - Set> ret = new TreeSet<>((l, r) -> ((String)l.getKey()).compareTo((String)r.getKey())); - ret.addAll(super.entrySet()); - return ret; - } - - @Override - public void store(OutputStream out, String comments) throws IOException { - out.write(clean().getBytes(ENCODING)); - out.flush(); - } - - @Override - public void store(Writer out, String comments) throws IOException { - out.write(clean()); - out.flush(); - } - - private String clean() throws IOException { - ByteArrayOutputStream tmp = new ByteArrayOutputStream(); - try { - super.store(tmp, null); - } finally { - tmp.close(); - } - - String ret = tmp.toString(ENCODING).replace(LINE_SEP, UNIX_LINE_SEP); - ret = ret.substring(ret.indexOf(UNIX_LINE_SEP) + 1); - return ret; - } -} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/ClosureHelper.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/ClosureHelper.groovy deleted file mode 100644 index 348ca2cfe2..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/ClosureHelper.groovy +++ /dev/null @@ -1,33 +0,0 @@ -package net.minecraftforge.forge.tasks - -import groovy.transform.stc.FirstParam - -import java.util.function.BiConsumer - -public class ClosureHelper { - BiConsumer callback - - public ClosureHelper(Closure cl, BiConsumer callback) { - this.callback = callback - apply(this, cl) - } - - - def methodMissing(String name, Object args) { - if (!args.class.isArray()) return - Object[] aargs = (Object[])args - - if (aargs.length == 1 && aargs[0] instanceof Closure) { - this.callback.accept(name, (Closure)aargs[0]) - } else { - throw new IllegalArgumentException('Unknown method: "' + name + '" with arguments ' + args + ' for ' + this) - } - } - - static T apply(T obj, @DelegatesTo(value = FirstParam, strategy = Closure.DELEGATE_FIRST) Closure cl) { - cl.delegate = obj - cl.resolveStrategy = Closure.DELEGATE_FIRST - cl() - return obj - } -} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/DownloadLibraries.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/DownloadLibraries.groovy deleted file mode 100644 index c3f98258ff..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/DownloadLibraries.groovy +++ /dev/null @@ -1,54 +0,0 @@ -package net.minecraftforge.forge.tasks - -import org.gradle.api.DefaultTask -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.tasks.InputFile -import org.gradle.api.tasks.Internal -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.OutputFiles -import org.gradle.api.tasks.TaskAction -import org.gradle.api.tasks.OutputDirectory - -import java.nio.file.Files - -abstract class DownloadLibraries extends DefaultTask { - @InputFile abstract RegularFileProperty getInput() - @OutputDirectory abstract DirectoryProperty getOutput() - @OutputFile abstract RegularFileProperty getLibrariesOutput() - - DownloadLibraries() { - output.convention(project.layout.buildDirectory.dir(name)) - librariesOutput.convention(project.layout.buildDirectory.dir(name).map(d -> d.file('libraries.txt'))) - } - - @TaskAction - def run() { - Util.init() - File outputDir = output.get().asFile - var libraries = new ArrayList() - - def json = input.get().asFile.json().libraries.each { lib -> - //TODO: Thread? - def artifacts = [lib.downloads.artifact] + lib.downloads.get('classifiers', [:]).values() - artifacts.each{ art -> - def target = new File(outputDir, art.path) - libraries.add(target.absolutePath) - if (!target.exists() || art.sha1 != target.sha1()) { - project.logger.lifecycle("Downloading ${art.url}") - if (!target.parentFile.exists()) { - target.parentFile.mkdirs() - } - new URL(art.url).withInputStream { i -> - target.withOutputStream { it << i } - } - if (art.sha1 != target.sha1()) { - throw new IllegalStateException("Failed to download ${art.url} to ${target.canonicalPath} SHA Mismatch") - } - } - } - } - Files.write(librariesOutput.get().asFile.toPath(), libraries) - } -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/ExtractFile.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/ExtractFile.groovy deleted file mode 100644 index 727c3258e0..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/ExtractFile.groovy +++ /dev/null @@ -1,28 +0,0 @@ -package net.minecraftforge.forge.tasks - -import groovy.transform.CompileStatic -import org.gradle.api.DefaultTask -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.provider.Property -import org.gradle.api.tasks.* - -import java.util.zip.ZipFile - -@CompileStatic -abstract class ExtractFile extends DefaultTask { - @InputFile abstract RegularFileProperty getInput() - @Input abstract Property getTarget() - @OutputFile abstract RegularFileProperty getOutput() - - @TaskAction - protected void exec() { - var zip = new ZipFile(input.get().asFile); - var entry = zip.getEntry(target.get()) - if (entry == null) - throw new IllegalStateException(input.get().asFile.absolutePath + " does not contain " + target.get()) - var stream = zip.getInputStream(entry) - output.get().asFile.withOutputStream { out -> - stream.transferTo(out) - } - } -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/FieldCompareFinder.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/FieldCompareFinder.groovy deleted file mode 100644 index ec0deac865..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/FieldCompareFinder.groovy +++ /dev/null @@ -1,101 +0,0 @@ -package net.minecraftforge.forge.tasks - -import groovy.transform.CompileStatic -import groovy.transform.EqualsAndHashCode - -import org.gradle.api.tasks.* -import org.objectweb.asm.tree.AbstractInsnNode -import org.objectweb.asm.tree.ClassNode -import org.objectweb.asm.tree.MethodNode - -import static org.objectweb.asm.Opcodes.* - -abstract class FieldCompareFinder extends BytecodeFinder { - @Nested - Map fields = [:] as HashMap - @Internal - Map fieldsReverse = [:] as HashMap - @Internal - Map> targets = [:] as TreeMap - - @Override - protected pre() { - //fields.each{ k,v -> logger.lifecycle("Fields: " + k + ' ' + v) } - } - - @Override - protected process(ClassNode parent, MethodNode node) { - AbstractInsnNode last = null - def parentInstance = new ObjectTarget(owner: parent.name, name: '', desc: '') - for (int x = 0; x < node.instructions.size(); x++) { - def current = node.instructions.get(x) - if (current.opcode === IF_ACMPEQ || current.opcode === IF_ACMPNE) { - if (last !== null && (last.opcode === GETSTATIC || last.opcode === GETFIELD)) { - def target = new Search(cls: last.owner, name: last.name) - def wanted = fieldsReverse.get(target) - def original = fields.get(wanted) - def instance = new ObjectTarget(owner: parent.name, name: node.name, desc: node.desc) - if (wanted !== null && (original.blacklist === null || (!original.blacklist.contains(instance) && !original.blacklist.contains(parentInstance)))) { - targets.computeIfAbsent(wanted, { k -> new TreeSet() }).add(instance) - } - } - } - last = current - } - } - - @Internal - @Override - protected Object getData() { - def ret = [:] as HashMap - targets.forEach{ k, v -> - def e = fields.get(k) - ret[k] = [ - cls: e.cls, - name: e.name, - replacement: e.replacement, - targets: v - ] - } - return ret - } - - @CompileStatic - @EqualsAndHashCode(excludes = ['replacement', 'blacklist']) - static class Search { - @Input - String cls - - @Input - String name - - @Input - String replacement - - @Nested - @Optional - Set blacklist - - @Override - String toString() { - return cls + '.' + name - } - - def blacklist(String owner, String name, String desc) { - if (blacklist === null) - blacklist = new HashSet<>() - blacklist.add(new ObjectTarget(owner: owner, name: name, desc: desc)) - } - def blacklist(String owner) { - blacklist(owner, '', '') - } - } - - void fields(Closure cl) { - new ClosureHelper(cl, {name, ccl -> - def search = ClosureHelper.apply(new Search(), ccl) - this.fields.put(name, search) - this.fieldsReverse.put(search, name) - }) - } -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/InheritanceData.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/InheritanceData.groovy deleted file mode 100644 index 546aec2018..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/InheritanceData.groovy +++ /dev/null @@ -1,49 +0,0 @@ -package net.minecraftforge.forge.tasks - -import com.google.gson.Gson -import com.google.gson.reflect.TypeToken -import groovy.transform.CompileStatic -import groovy.transform.TupleConstructor - -@CompileStatic -@TupleConstructor -final class InheritanceData implements Annotatable { - String name - int access - String superName - List interfaces = [] - Map methods = [:] - Map fields = [:] - List annotations = [] - - @TupleConstructor - static final class Method implements Annotatable { - int access - String override - List annotations = [] - } - - @TupleConstructor - static final class Field implements Annotatable { - int access - String desc - List annotations = [] - } - - @TupleConstructor - static final class Annotation { - String desc - } - - private static final Gson GSON = new Gson() - static Map parse(File file) { - try (final reader = file.newReader()) { - return GSON.fromJson(reader, new TypeToken>() {}) - } - } -} - -@CompileStatic -interface Annotatable { - List getAnnotations() -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/InstallerJar.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/InstallerJar.groovy deleted file mode 100644 index f0918baace..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/InstallerJar.groovy +++ /dev/null @@ -1,158 +0,0 @@ -package net.minecraftforge.forge.tasks - -import org.gradle.api.file.DuplicatesStrategy -import org.gradle.api.tasks.bundling.AbstractArchiveTask -import org.gradle.api.tasks.bundling.Zip -import org.gradle.api.tasks.* -import org.gradle.api.DefaultTask -import org.gradle.api.provider.Property -import groovy.json.JsonSlurper - -abstract class InstallerJar extends Zip { - @Input @Optional abstract Property getFat() - @Input @Optional abstract Property getOffline() - - InstallerJar() { - archiveClassifier.set('installer') - archiveExtension.set('jar') // Needs to be Zip task to not override Manifest, so set extension - destinationDirectory.set(project.layout.buildDirectory.dir('libs')) - fat.convention(false) - offline.convention(false) - - def installerJson = project.tasks.installerJson - def launcherJson = project.tasks.launcherJson - def downloadInstaller = project.tasks.downloadInstaller - - dependsOn(installerJson, launcherJson, downloadInstaller, project.configurations.installer) - from(installerJson, launcherJson) - - from(project.rootProject.file('/src/main/resources/url.png')) - project.afterEvaluate { - from(project.zipTree(downloadInstaller.output)) { - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - } - - if (fat.get() || offline.get()) { - def cfg = project.tasks.register(name + "Config", Configure) - cfg.get().configure { - parent = this - dependsOn(project.tasks.installerJson, project.tasks.launcherJson) - } - dependsOn(cfg) - } else { - // Things we ALWAYS bundle, this just the server shim jar, because the installer spec only says to extract the file. - // I should make it allow downloads but thats a spec break, and this is just a ~14KB jar - [ - project.tasks.serverShimJar // Server bootstrap executable jar - ].forEach { AbstractArchiveTask packed -> - def path = Util.getMavenInfoFromTask(packed).path - from(packed) { - rename { "maven/$path" } - } - } - } - } - } - - static abstract class Configure extends DefaultTask { - public Zip parent - private int count = 0; - - @TaskAction - protected void exec() { - def deps = [:] as java.util.TreeMap - - // Gather all things that need downloading - [ - project.tasks.installerJson, - project.tasks.launcherJson - ].each { task -> - def json = task.output.get().asFile.json - json.libraries.each { lib -> - if (lib.downloads?.artifact?.url !== null && !lib.downloads.artifact.url.isEmpty()) - deps.put(lib.name, lib.downloads.artifact) - } - } - - // First find things we build in this project. - [ - project.tasks.universalJar, // Forge runtime code - project.tasks.serverShimJar // Shim jar for dedicated server - ].forEach { AbstractArchiveTask packed -> - def name = Util.getMavenInfoFromTask(packed).name - def info = deps.remove(name) - if (info !== null) { - println("Adding: $packed.path $name") - parent.from(packed) { - rename { "maven/$info.path" } - } - } - } - - // Find any artifacts from the 'installer' config - // This config specifies the runtime files we intend for the interaller to have. - // And are typically what we would be developing and testing alongside Forge. - // So we may have local modified versions - def cfg = project.configurations.installer - while (cfg != null) { - //println('') - def resolved = cfg.resolvedConfiguration.resolvedArtifacts - int found = 0 - for (def dep : resolved) { - def name = Util.getMavenInfoFromDep(dep).name - def info = deps.remove(name) - if (info == null) { - //println("Skipping: $name") - continue - } - //println("-$name") - found++ - addFile(dep.file, info) - } - - if (deps.isEmpty()) { - cfg = null - continue - } - - // Prevent infinite loops if something fucky happens - if (found == 0) - throw new IllegalStateException("Failed to find any installer dependencies") - - def seen = [] as Set - cfg = project.configurations.detachedConfiguration() - cfg.transitive = false - for (def key : deps.keySet()) { - def (group, artifact, other) = key.split(':', 3) - // Only resolve unique group:artifact so we don't get version overrides - if (seen.add(group + ':' + artifact)) { - //println("+$key") - cfg.dependencies.add(project.dependencies.create(key)) - } - } - } - } - - void addFile(file, info) { - boolean pack = parent.offline.get() || info.url.isEmpty() - - // If it's a offline jar just always pack - if (!pack) { - try { - var remote = new URL("${info.url}.sha1").getText('UTF-8') - pack = info.sha1 != remote - } catch (FileNotFoundException e) { - pack = !info.url.startsWith('https://libraries.minecraft.net/') - // Oh noes its not there! - } - } - - if (pack) { - println("Adding: $file.absolutePath") - parent.from(file) { - rename { "maven/$info.path" } - } - } - } - } -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/InstallerJson.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/InstallerJson.groovy deleted file mode 100644 index 1076b7552b..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/InstallerJson.groovy +++ /dev/null @@ -1,73 +0,0 @@ -package net.minecraftforge.forge.tasks - -import groovy.json.JsonBuilder -import org.gradle.api.DefaultTask -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.provider.Property -import org.gradle.api.provider.SetProperty -import org.gradle.api.tasks.* -import org.gradle.api.tasks.bundling.AbstractArchiveTask - -import java.nio.file.Files - -abstract class InstallerJson extends DefaultTask { - @OutputFile abstract RegularFileProperty getOutput() - @InputFiles abstract ConfigurableFileCollection getInput() - @Input @Optional final Map libraries = new LinkedHashMap<>() - @Input Map json = new LinkedHashMap<>() - @InputFile abstract RegularFileProperty getIcon() - @Input abstract Property getLauncherJsonName() - @Input abstract Property getLogo() - @Input abstract Property getMirrors() - @Input abstract Property getWelcome() - - InstallerJson() { - launcherJsonName.convention('/version.json') - logo.convention('/big_logo.png') - mirrors.convention('https://files.minecraftforge.net/mirrors-2.0.json') - welcome.convention("Welcome to the ${project.name.capitalize()} installer.") - output.convention(project.layout.buildDirectory.file('libs/install_profile.json')) - - project.afterEvaluate { - [ - project.tasks.universalJar, - project.tasks.serverShimJar - ].forEach { packed -> - dependsOn(packed) - input.from packed.archiveFile - } - } - } - - @TaskAction - protected void exec() { - def libs = libraries - [ - project.tasks.universalJar, - project.tasks.serverShimJar - ].forEach { AbstractArchiveTask packed -> - def info = Util.getMavenInfoFromTask(packed) - libs.put(info.name, [ - name: info.name, - downloads: [ - artifact: [ - path: info.path, - url: "https://maven.minecraftforge.net/$info.path", - sha1: packed.archiveFile.get().asFile.sha1(), - size: packed.archiveFile.get().asFile.length() - ] - ] - ]) - } - json.libraries = libs.values().sort{a,b -> a.name.compareTo(b.name)} - json.icon = "data:image/png;base64," + new String(Base64.getEncoder().encode(Files.readAllBytes(icon.get().asFile.toPath()))) - json.json = launcherJsonName.get() - json.logo = logo.get() - if (!mirrors.get().isEmpty()) - json.mirrorList = mirrors.get() - json.welcome = welcome.get() - - Files.writeString(output.get().getAsFile().toPath(), new JsonBuilder(json).toPrettyString()) - } -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/JarJarMetadataOptions.java b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/JarJarMetadataOptions.java deleted file mode 100644 index 8837a29032..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/JarJarMetadataOptions.java +++ /dev/null @@ -1,415 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.forge.tasks; - -import com.google.common.reflect.TypeToken; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import net.minecraftforge.jarjar.metadata.ContainedJarIdentifier; -import net.minecraftforge.jarjar.metadata.ContainedJarMetadata; -import net.minecraftforge.jarjar.metadata.ContainedVersion; -import net.minecraftforge.jarjar.metadata.Metadata; -import net.minecraftforge.jarjar.metadata.MetadataIOHandler; -import net.minecraftforge.jarjar.metadata.json.ArtifactVersionSerializer; -import net.minecraftforge.jarjar.metadata.json.ContainedJarIdentifierSerializer; -import net.minecraftforge.jarjar.metadata.json.ContainedJarMetadataSerializer; -import net.minecraftforge.jarjar.metadata.json.ContainedVersionSerializer; -import net.minecraftforge.jarjar.metadata.json.MetadataSerializer; -import net.minecraftforge.jarjar.metadata.json.VersionRangeSerializer; -import org.apache.maven.artifact.versioning.ArtifactVersion; -import org.apache.maven.artifact.versioning.DefaultArtifactVersion; -import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; -import org.apache.maven.artifact.versioning.VersionRange; -import org.codehaus.groovy.runtime.InvokerHelper; -import org.gradle.api.Action; -import org.gradle.api.DefaultTask; -import org.gradle.api.artifacts.ConfigurationContainer; -import org.gradle.api.artifacts.Dependency; -import org.gradle.api.artifacts.ExternalModuleDependency; -import org.gradle.api.artifacts.FileCollectionDependency; -import org.gradle.api.artifacts.MinimalExternalModuleDependency; -import org.gradle.api.artifacts.ModuleDependency; -import org.gradle.api.artifacts.ModuleIdentifier; -import org.gradle.api.artifacts.ModuleVersionIdentifier; -import org.gradle.api.artifacts.ResolvedArtifact; -import org.gradle.api.file.ProjectLayout; -import org.gradle.api.file.RegularFileProperty; -import org.gradle.api.provider.Provider; -import org.gradle.api.provider.SetProperty; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.OutputFile; -import org.gradle.api.tasks.TaskAction; - -import javax.inject.Inject; -import java.io.File; -import java.io.IOException; -import java.io.Serial; -import java.io.Serializable; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.zip.ZipFile; - -// TODO SUPER SUPER SUPER UGLY, CLEAN UP IN FORGEDEV 7 -@Deprecated(forRemoval = true) // Will be moved to JarJar plugin in ForgeDev 7 -public abstract class JarJarMetadataOptions extends DefaultTask { - private static final Gson GSON = new GsonBuilder() - .registerTypeAdapter(VersionRange.class, new VersionRangeSerializer()) - .registerTypeAdapter(ArtifactVersion.class, new ArtifactVersionSerializer()) - .registerTypeAdapter(DefaultArtifactVersion.class, new ArtifactVersionSerializer()) - .registerTypeAdapter(ContainedJarIdentifier.class, new ContainedJarIdentifierSerializer()) - .registerTypeAdapter(ContainedJarMetadata.class, new ContainedJarMetadataSerializer()) - .registerTypeAdapter(ContainedVersion.class, new ContainedVersionSerializer()) - .registerTypeAdapter(Metadata.class, new MetadataSerializer()) - .setPrettyPrinting() - .create(); - - protected abstract @Input SetProperty getResolvedDependencies(); - - protected abstract @OutputFile RegularFileProperty getMetadataFile(); - - protected abstract @Inject ProjectLayout getLayout(); - - // NOTE: I'm not adding a non-provider version. please just use the version catalog entries for now. - public void add(Provider dependency, Action action) { - this.getResolvedDependencies().add(dependency.map(d -> { - var ret = ResolvedDependencyInfoImpl.from(this.getProject().getConfigurations(), d); - action.execute(ret); - return ret; - })); - } - - @Inject - public JarJarMetadataOptions() { - this.getMetadataFile().convention(this.getLayout().getBuildDirectory().file(this.getName() + "/options.json")); - } - - @TaskAction - protected void exec() { - record ForgeLocaterOptions(String resource, String layer, String id, List deps, ContainedJarMetadata meta, boolean nested) { } - - var resolved = this.getResolvedDependencies().get(); - var jars = new ArrayList(resolved.size()); - for (var dependency : resolved) { - var deps = new ArrayList(); - try (var zip = new ZipFile(dependency.artifact)) { - var entry = zip.getEntry("META-INF/jarjar/metadata.json"); - if (entry != null) { - try (var stream = zip.getInputStream(entry)) { - var meta = MetadataIOHandler.fromStream(stream).orElse(null); - if (meta == null) - throw new IllegalStateException("Corrupt metadata.json in " + dependency.artifact.getAbsolutePath()); - for (var dep : meta.jars()) - deps.add(new ContainedJarMetadata(dep.identifier(), dep.version(), "", dep.isObfuscated())); - } - } - } catch (IOException e) { - throw new RuntimeException(e); - } - jars.add(new ForgeLocaterOptions( - dependency.resource, - dependency.layer, - dependency.identifier, - deps, - new ContainedJarMetadata( - new ContainedJarIdentifier(validateGroup(dependency), dependency.module.getName()), - new ContainedVersion(null, parseVersion(dependency)), - Objects.requireNonNull(dependency.path, "Dependency path is unspecified: " + dependency.asString), - false - ), - dependency.nested - )); - } - - try { - record Meta(List options){} - - Files.writeString( - this.getMetadataFile().getAsFile().get().toPath(), - GSON.toJson(new Meta(jars), Meta.class) - ); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private String validateGroup(ResolvedDependencyInfoImpl dependency) { - try { - return Objects.requireNonNull(dependency.module.getGroup()); - } catch (NullPointerException e) { - throw new IllegalArgumentException("Module dependency has no group: " + dependency.asString, e); - } - } - - private ArtifactVersion parseVersion(ResolvedDependencyInfoImpl resolved) { - try { - return VersionRange.createFromVersionSpec(Objects.requireNonNull(resolved.version)).getRecommendedVersion(); - } catch (InvalidVersionSpecificationException e) { - throw new IllegalArgumentException("Version is invalid for: " + resolved.asString, e); - } catch (NullPointerException e) { - throw new IllegalArgumentException("Version is unspecified for: " + resolved.asString, e); - } - } - - private VersionRange parseVersionRange(ResolvedDependencyInfoImpl dependency) { - if (dependency.hasManuallySpecifiedRange) { - try { - return VersionRange.createFromVersionSpec(dependency.versionRange); - } catch (InvalidVersionSpecificationException e) { - throw new IllegalArgumentException("Version is invalid for: " + dependency.asString, e); - } - } else { - try { - return VersionRange.createFromVersionSpec("[%s,)".formatted(Objects.requireNonNull(dependency.versionRange))); - } catch (InvalidVersionSpecificationException e) { - throw new IllegalArgumentException("Version range is invalid for: " + dependency.asString, e); - } catch (NullPointerException e) { - throw new IllegalArgumentException("Version is unspecified for: " + dependency.asString, e); - } - } - } - - public interface ResolvedDependencyInfo { - void containedJarMetadata(Action action); - - void setResource(String resource); - - void setLayer(String layer); - - void setId(String identifier); - - void setNested(boolean nested); - - interface ContainedJarMetadataInfo { - void setGroup(String group); - - void setName(String name); - - void setPath(String version); - } - } - - static final class ResolvedDependencyInfoImpl implements ResolvedDependencyInfo, ResolvedDependencyInfo.ContainedJarMetadataInfo, Serializable { - private static final @Serial long serialVersionUID = -7577318115877822993L; - - final MinimalModuleVersionIdentifier module; - final String version; - String versionRange; - boolean hasManuallySpecifiedRange; - boolean nested; - final File artifact; - String path; - String resource; - String layer; - String identifier; - final String asString; - - public ResolvedDependencyInfoImpl(MinimalModuleVersionIdentifier module, String version, File artifact, String asString) { - this.module = module; - this.version = version; - this.artifact = artifact; - this.asString = asString; - } - - @Override - public void containedJarMetadata(Action action) { - action.execute(this); - } - - @Override - public void setGroup(String group) { - this.module.group = group; - } - - @Override - public void setName(String name) { - this.module.name = name; - } - - @Override - public void setPath(String path) { - this.path = path; - } - - @Override - public void setResource(String resource) { - this.resource = resource; - } - - @Override - public void setLayer(String layer) { - this.layer = layer; - } - - @Override - public void setId(String identifier) { - this.identifier = identifier; - } - - @Override - public void setNested(boolean nested) { - this.nested = nested; - } - - static Set getFiles(Set resolvedDependencies) { - var ret = new HashSet(resolvedDependencies.size()); - for (var dependency : resolvedDependencies) { - ret.add(dependency.artifact); - } - return ret; - } - - static ResolvedDependencyInfoImpl from(ConfigurationContainer configurations, Dependency dependency) { - var group = dependency.getGroup(); - var name = dependency.getName(); - var version = dependency.getVersion(); - - if (dependency instanceof FileCollectionDependency filesDependency) { - File artifact; - try { - artifact = filesDependency.getFiles().getSingleFile(); - } catch (IllegalStateException e) { - // TODO fileCollectionDependencyIsNotSingleFile - throw e; - } - - return new ResolvedDependencyInfoImpl( - new MinimalModuleVersionIdentifier(group, name, version), - version, - artifact, - filesDependency.toString() - ); - } else if (dependency instanceof ModuleDependency moduleDependency) { - moduleDependency = moduleDependency.copy(); - if (moduleDependency instanceof ExternalModuleDependency externalModuleDependency) { - externalModuleDependency.version(v -> v.strictly(version.toString())); - } - - var detachedConfiguration = configurations.detachedConfiguration(moduleDependency); - detachedConfiguration.setTransitive(false); - - ResolvedDependencyInfoImpl ret = null; - for (var artifact : detachedConfiguration.getResolvedConfiguration().getFirstLevelModuleDependencies().iterator().next().getModuleArtifacts()) { - var fileName = getFileName(artifact); - if (!fileName.endsWith(".jar")) - continue; - - if (ret != null) - throw new IllegalArgumentException("Module dependency has too many Jar artifacts: " + moduleDependency); - - ret = new ResolvedDependencyInfoImpl( - new MinimalModuleVersionIdentifier(group, name, artifact.getModuleVersion().getId().getVersion()), - version, - artifact.getFile(), - moduleDependency.toString() - ); - } - if (ret == null) - throw new IllegalArgumentException("Module dependency has no Jar artifacts: " + moduleDependency); - - return ret; - } else { - throw new IllegalArgumentException("Unsupported dependency type: " + dependency.getClass().getName() + " -- " + dependency); - } - } - - private static String getFileName(ResolvedArtifact artifact) { - try { - return InvokerHelper.getProperty(artifact.getId(), "fileName").toString(); - } catch (Throwable e) { - // NOTE: Why not just use this to begin with? - // ComponentArtifactIdentifier can have a getFileName() method, which doesn't necessarily resolve the file itself. - // This allows us to get the name of the file to be used without asking Gradle to download the file. - // So, if a file is not a JAR file, we can check the name without actually downloading it. - return artifact.getFile().getName(); - } - } - - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj == null || obj.getClass() != this.getClass()) return false; - var that = (ResolvedDependencyInfoImpl) obj; - return Objects.equals(this.module, that.module) && - Objects.equals(this.version, that.version) && - Objects.equals(this.versionRange, that.versionRange) && - Objects.equals(this.artifact, that.artifact); - } - - @Override - public int hashCode() { - return Objects.hash(module, version, versionRange, artifact); - } - - @Override - public String toString() { - return "ResolvedDependencyInfo[" + - "module=" + module + ", " + - "fixedVersion=" + version + ", " + - "versionRange=" + versionRange + ", " + - "artifact=" + artifact + ']'; - } - - static final class MinimalModuleVersionIdentifier implements ModuleIdentifier, ModuleVersionIdentifier { - private static final @Serial long serialVersionUID = -955346236759069739L; - - private String group; - private String name; - private final String version; - - @Inject - public MinimalModuleVersionIdentifier(String group, String name, String version) { - this.group = group; - this.name = name; - this.version = version; - } - - @Override - public ModuleIdentifier getModule() { - return this; - } - - @Override - public String getGroup() { - return this.group; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public String getVersion() { - return this.version; - } - - @Override - public boolean equals(Object obj) { - return this == obj || obj instanceof MinimalModuleVersionIdentifier o - && Objects.equals(this.group, o.group) - && Objects.equals(this.name, o.name) - && Objects.equals(this.version, o.version); - } - - @Override - public int hashCode() { - return Objects.hash(group, name, version); - } - - @Override - public String toString() { - return "MinimalModuleVersionIdentifier[" + - "group=" + group + ", " + - "name=" + name + ", " + - "version=" + version + ']'; - } - } - } -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/LauncherJson.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/LauncherJson.groovy deleted file mode 100644 index e9cf3a18d2..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/LauncherJson.groovy +++ /dev/null @@ -1,94 +0,0 @@ -package net.minecraftforge.forge.tasks - -import groovy.json.JsonBuilder -import org.gradle.api.DefaultTask -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.provider.SetProperty -import org.gradle.api.tasks.* -import org.gradle.api.tasks.bundling.AbstractArchiveTask - -import java.nio.file.Files - -import static net.minecraftforge.forge.tasks.Util.getArtifacts -import static net.minecraftforge.forge.tasks.Util.iso8601Now - -abstract class LauncherJson extends DefaultTask { - @OutputFile abstract RegularFileProperty getOutput() - @InputFiles abstract ConfigurableFileCollection getInput() - @Input Map json = new LinkedHashMap<>() - - LauncherJson() { - output.convention(project.layout.buildDirectory.file('libs/version.json')) - - dependsOn(project.tasks.universalJar) - input.from(project.tasks.universalJar.archiveFile) - input.from(project.configurations.installer) - configure { - def mc = project.rootProject.ext.MC_VERSION - def forge = project.rootProject.ext.FORGE_VERSION - def timestamp = iso8601Now() - json.putAll([ - _comment: [ - "Please do not automate the download and installation of Forge.", - "Our efforts are supported by ads from the download page.", - "If you MUST automate this, please consider supporting the project through https://www.patreon.com/LexManos/" - ], - id: "$mc-$project.name-$forge", - time: timestamp, - releaseTime: timestamp, - inheritsFrom: mc, - type: 'release', - logging: [:], - mainClass: '', - libraries: [] - ] as LinkedHashMap) - - [ - project.tasks.universalJar - ].forEach { packed -> - dependsOn(packed) - input.from packed.archiveFile - } - - def patched = project.tasks.applyClientBinPatches - dependsOn(patched) - input.from patched.output - } - } - - @TaskAction - protected void exec() { - var packed = (AbstractArchiveTask) project.tasks.universalJar - def info = Util.getMavenInfoFromTask(packed) - json.libraries.add([ - name: info.name, - downloads: [ - artifact: [ - path: info.path, - url: "https://maven.minecraftforge.net/$info.path", - sha1: packed.archiveFile.get().asFile.sha1(), - size: packed.archiveFile.get().asFile.length() - ] - ] - ]) - - var classifier = 'client' - var genned = project.tasks.applyClientBinPatches - info = Util.getMavenInfoFromTask(genned, classifier) - json.libraries.add([ - name: info.name, - downloads: [ - artifact: [ - path: info.path, - url: "", - sha1: genned.output.get().asFile.sha1(), - size: genned.output.get().asFile.length() - ] - ] - ]) - - json.libraries.addAll(getArtifacts(project.configurations.installer).values()) - Files.writeString(output.get().asFile.toPath(), new JsonBuilder(json).toPrettyString()) - } -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/MergeJars.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/MergeJars.groovy deleted file mode 100644 index 0f95d42f36..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/MergeJars.groovy +++ /dev/null @@ -1,46 +0,0 @@ -package net.minecraftforge.forge.tasks - -import groovy.transform.CompileStatic -import org.apache.commons.io.IOUtils -import org.gradle.api.DefaultTask -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.tasks.InputFiles -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.TaskAction - -import java.util.zip.ZipEntry -import java.util.zip.ZipInputStream -import java.util.zip.ZipOutputStream - -@CompileStatic -abstract class MergeJars extends DefaultTask { - MergeJars() { - output.convention(project.layout.buildDirectory.dir(name).map { it.file('output.jar') }) - } - - @TaskAction - void run() { - def jars = inputJars.files - - try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(output.get().asFile))) { - for (def jar : jars) { - try (ZipInputStream zin = new ZipInputStream(new FileInputStream(jar))) { - ZipEntry entry - while ((entry = zin.getNextEntry()) !== null) { - ZipEntry _new = new ZipEntry(entry.getName()) - _new.setTime(0) //SHOULD be the same time as the main entry, but NOOOO _new.setTime(entry.getTime()) throws DateTimeException, so you get 0, screw you! - zout.putNextEntry(_new) - IOUtils.copy(zin, zout) - } - } - } - } - } - - @InputFiles - abstract ConfigurableFileCollection getInputJars() - - @OutputFile - abstract RegularFileProperty getOutput() -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/ObjectTarget.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/ObjectTarget.groovy deleted file mode 100644 index 00f64e18fa..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/ObjectTarget.groovy +++ /dev/null @@ -1,32 +0,0 @@ -package net.minecraftforge.forge.tasks - -import groovy.transform.EqualsAndHashCode - -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.Nested -import org.gradle.api.tasks.Optional - -@EqualsAndHashCode -public class ObjectTarget implements Comparable { - @Input - String owner - - @Input - String name - - @Input - @Optional - String desc - - @Override - String toString() { - if (desc == null) - return owner + '.' + name - return owner + '.' + name + desc - } - - @Override - int compareTo(ObjectTarget o) { - return toString() <=> o.toString() - } -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/SetupCheckJarCompatibility.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/SetupCheckJarCompatibility.groovy deleted file mode 100644 index a583d6b5e6..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/SetupCheckJarCompatibility.groovy +++ /dev/null @@ -1,47 +0,0 @@ -package net.minecraftforge.forge.tasks - -import org.gradle.api.DefaultTask -import org.gradle.api.artifacts.Dependency -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.provider.Property -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.Optional -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.TaskAction - -import java.nio.file.Files -import java.nio.file.StandardCopyOption - -abstract class SetupCheckJarCompatibility extends DefaultTask { - SetupCheckJarCompatibility() { - group = 'jar compatibility' - onlyIf { - inputVersion.getOrNull() !== null - } - outputs.upToDateWhen { false } // Never up to date, because this setup task should always run - - baseBinPatchesOutput.convention(project.layout.buildDirectory.dir(name).map { it.file('joined.lzma') }) - } - - @TaskAction - void run() { - def inputVersion = inputVersion.get() - - def baseForgeUserdev = project.layout.buildDirectory.dir(name).map { it.file("forge-${inputVersion}-userdev.jar") }.get().asFile - project.rootProject.extensions.download.run { - src "https://maven.minecraftforge.net/net/minecraftforge/forge/${inputVersion}/forge-${inputVersion}-userdev.jar" - dest baseForgeUserdev - } - - def joinedLzma = project.zipTree(baseForgeUserdev).matching { it.include('joined.lzma') }.singleFile - - Files.copy(joinedLzma.toPath(), baseBinPatchesOutput.get().asFile.toPath(), StandardCopyOption.REPLACE_EXISTING) - } - - @Input - @Optional - abstract Property getInputVersion() - - @OutputFile - abstract RegularFileProperty getBaseBinPatchesOutput() -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/TeamcityRequests.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/TeamcityRequests.groovy deleted file mode 100644 index bccebbaffa..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/TeamcityRequests.groovy +++ /dev/null @@ -1,74 +0,0 @@ -package net.minecraftforge.forge.tasks - -import com.google.gson.Gson -import com.google.gson.reflect.TypeToken -import groovy.transform.CompileStatic -import org.eclipse.jgit.api.Git - -import javax.annotation.Nullable -import java.util.stream.Collectors - -@CompileStatic -class TeamcityRequests { - public static final Gson GSON = new Gson() - - @Nullable - static T jsonRequest(TypeToken clazz, String url) throws Exception { - final HttpURLConnection conn = (HttpURLConnection) URI.create(url).toURL().openConnection() - conn.setRequestProperty('Accept', 'application/json') - conn.setReadTimeout(5 * 1000) - conn.setConnectTimeout(5 * 1000) - conn.connect() - - if (conn.responseCode !== 200) { - return null - } - - try (final InputStream is = conn.getInputStream()) { - GSON.fromJson(new InputStreamReader(is), clazz.getType()) - } - } - - @Nullable - static Map buildsByCommit() throws IOException { - final Map builds = [:] - jsonRequest(new TypeToken() {}, 'https://teamcity.minecraftforge.net/guestAuth/app/rest/builds?fields=build:(revisions,number)&locator=buildType:(id:MinecraftForge_MinecraftForge_MinecraftForge_MinecraftForge__Build),defaultFilter:false,count:300,status:SUCCESS') - ?.build?.forEach { - it.revisions.revision.each { rev -> builds[rev.version] = it } - } - return builds - } - - @Nullable - static String attemptFindBase(File gitPath) { - try (final git = Git.open(gitPath)) { - final Map buildByCommit = buildsByCommit() - for (final commit in git.log().setMaxCount(100).call()) { - // Find the first commit which was built on CI - final build = buildByCommit[commit.id.name] - if (build) { - return build.number - } - } - } catch (Exception ignored) {} - return null - } - - static final class Builds { - public List build - } - - static final class Build { - public String number - public Revisions revisions - } - - static final class Revisions { - public int count - public List revision - } - - static final class Revision { - public String version - } -} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/Util.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/Util.groovy deleted file mode 100644 index c15e595952..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/Util.groovy +++ /dev/null @@ -1,230 +0,0 @@ -package net.minecraftforge.forge.tasks - -import groovy.json.JsonBuilder -import groovy.json.JsonSlurper -import groovy.transform.CompileStatic -import groovy.transform.stc.ClosureParams -import groovy.transform.stc.SimpleType -import org.gradle.api.Project -import org.gradle.api.Task -import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.ResolvedArtifact -import org.gradle.api.tasks.bundling.AbstractArchiveTask -import org.objectweb.asm.ClassReader -import org.objectweb.asm.Opcodes -import org.objectweb.asm.tree.ClassNode - -import java.net.http.HttpClient -import java.net.http.HttpRequest -import java.net.http.HttpResponse -import java.security.MessageDigest -import java.text.SimpleDateFormat -import java.util.concurrent.ConcurrentHashMap -import java.util.concurrent.Semaphore -import java.util.zip.ZipEntry -import java.util.zip.ZipInputStream - -final class Util { - public static final int ASM_LEVEL = Opcodes.ASM9 - private static final HttpClient HTTP = HttpClient.newBuilder().build() - - static void init() { - File.metaClass.sha1 = { -> - MessageDigest md = MessageDigest.getInstance('SHA-1') - delegate.eachByte(4096) { byte[] bytes, int size -> - md.update(bytes, 0, size) - } - return md.digest().collect(this.&toHex).join('') - } - File.metaClass.getSha1 = { !delegate.exists() ? null : delegate.sha1() } - File.metaClass.sha256 = { -> - MessageDigest md = MessageDigest.getInstance('SHA-256') - delegate.eachByte(4096) { byte[] bytes, int size -> - md.update(bytes, 0, size) - } - return md.digest().collect(this.&toHex).join('') - } - File.metaClass.getSha256 = { !delegate.exists() ? null : delegate.sha256() } - - File.metaClass.json = { -> new JsonSlurper().parseText(delegate.text) } - File.metaClass.getJson = { return delegate.exists() ? new JsonSlurper().parse(delegate) : [:] } - File.metaClass.setJson = { json -> delegate.text = new JsonBuilder(json).toPrettyString() } - - Date.metaClass.iso8601 = { -> - var format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") - var result = format.format(delegate) - return result[0..21] + ':' + result[22..-1] - } - - String.metaClass.rsplit = { String del, int limit = -1 -> - var lst = new ArrayList() - int x = 0 - int idx - String tmp = delegate - while ((idx = tmp.lastIndexOf(del)) != -1 && (limit === -1 || x++ < limit)) { - lst.add(0, tmp.substring(idx + del.length(), tmp.length())) - tmp = tmp.substring(0, idx) - } - lst.add(0, tmp) - return lst - } - } - - static String[] getClasspath(Project project, Map libs, String artifact) { - def ret = [] - artifactTree(project, artifact).each { key, lib -> - libs[lib.name] = lib - if (lib.name != artifact) - ret.add(lib.name) - } - return ret - } - - @CompileStatic - static Map getArtifacts(Configuration config) { - var ret = [:] - var semaphore = new Semaphore(1, true) - config.resolvedConfiguration.resolvedArtifacts.parallelStream().forEachOrdered(dep -> { - var info = getMavenInfoFromDep(dep) - var domain = 'libraries.minecraft.net' - var url = "https://$domain/$info.path" - if (!checkExists(url)) - url.values[0] = 'maven.minecraftforge.net' - - var sha1 = sha1(dep.file) - - semaphore.acquire() - ret[info.key] = [ - name: info.name, - downloads: [ - artifact: [ - path: info.path, - url: url.toString(), - sha1: sha1, - size: dep.file.length() - ] - ] - ] - semaphore.release() - }) - return ret - } - - @CompileStatic - static Map getMavenInfoFromDep(ResolvedArtifact dep) { - return getMavenInfoFromMap([ - group: dep.moduleVersion.id.group, - name: dep.moduleVersion.id.name, - version: dep.moduleVersion.id.version, - classifier: dep.classifier, - extension: dep.extension - ]) - } - - @CompileStatic - static Map getMavenInfoFromTask(AbstractArchiveTask task) { - return getMavenInfoFromMap([ - group: task.project.group.toString(), - name: task.project.name, - version: task.project.version.toString(), - classifier: task.archiveClassifier.get(), - extension: task.archiveExtension.get() - ]) - } - - @CompileStatic - static Map getMavenInfoFromTask(Task task, String classifier) { - return getMavenInfoFromMap([ - group: task.project.group.toString(), - name: task.project.name, - version: task.project.version.toString(), - classifier: classifier, - extension: 'jar' - ]) - } - - @CompileStatic - private static Map getMavenInfoFromMap(Map art) { - var key = "$art.group:$art.name" - var name = "$art.group:$art.name:$art.version" - var path = "${art.group.replace('.', '/')}/$art.name/$art.version/$art.name-$art.version" - if (art.classifier !== null) { - name += ":$art.classifier" - path += "-$art.classifier" - } - if ('jar' != art.extension) { - name += "@$art.extension" - path += ".$art.extension" - } else { - path += ".jar" - } - return [ - key: key.toString(), - name: name.toString(), - path: path.toString(), - art: art - ] - } - - static String iso8601Now() { new Date().iso8601() } - - @CompileStatic - static String sha1(File file) { - MessageDigest md = MessageDigest.getInstance('SHA-1') - file.eachByte(4096) { byte[] bytes, int size -> - md.update(bytes, 0, size) - } - return md.digest().collect(this.&toHex).join('') - } - - @CompileStatic - private static String toHex(byte bite) { - return String.format('%02x', bite) - } - - private static Map artifactTree(Project project, String artifact, boolean transitive = true) { - if (!project.ext.has('tree_resolver')) - project.ext.tree_resolver = 1 - def cfg = project.configurations.create('tree_resolver_' + project.ext.tree_resolver++) - cfg.transitive = transitive - def dep = project.dependencies.create(artifact) - cfg.dependencies.add(dep) - def files = cfg.resolve() - return getArtifacts(cfg) - } - - @CompileStatic - static boolean checkExists(String url) { - try { - return HTTP.send(HttpRequest.newBuilder(new URI(url)) - .method('HEAD', HttpRequest.BodyPublishers.noBody()).build(), HttpResponse.BodyHandlers.discarding() - ).statusCode() === 200 - } catch (Exception e) { - if (e.toString().contains('unable to find valid certification path to requested target')) - throw new RuntimeException("Failed to connect to $url: Missing certificate root authority, try updating Java") - throw e - } - } - - static String getLatestForgeVersion(String mcVersion) { - final json = new JsonSlurper().parseText(new URL('https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json').getText('UTF-8')) - final ver = json.promos["$mcVersion-latest"] - ver === null ? null : (mcVersion + '-' + ver) - } - - @CompileStatic - static void processClassNodes(File file, @ClosureParams(value = SimpleType, options = 'org.objectweb.asm.tree.ClassNode') Closure process) { - file.withInputStream { i -> - new ZipInputStream(i).withCloseable { zin -> - ZipEntry zein - while ((zein = zin.nextEntry) !== null) { - if (zein.name.endsWith('.class')) { - var node = new ClassNode(ASM_LEVEL) - new ClassReader(zin).accept(node, 0) - process(node) - } - } - } - } - } -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/ValidateDeprecations.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/ValidateDeprecations.groovy deleted file mode 100644 index 14018ddd8a..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/ValidateDeprecations.groovy +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -package net.minecraftforge.forge.tasks - -import groovy.transform.CompileStatic -import net.minecraftforge.srgutils.MinecraftVersion -import org.gradle.api.DefaultTask -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.provider.Property -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputFile -import org.gradle.api.tasks.TaskAction -import org.objectweb.asm.tree.AnnotationNode -import org.objectweb.asm.tree.ClassNode - -abstract class ValidateDeprecations extends DefaultTask { - @InputFile - abstract RegularFileProperty getInput() - - @Input - abstract Property getMcVersion() - - ValidateDeprecations() { - this.onlyIf { !System.env.TEAMCITY_VERSION } - } - - @TaskAction - protected void exec() { - var mcVer = MinecraftVersion.from(mcVersion.get()) - List errors = [] - - Util.processClassNodes(input.get().asFile) { - processNode(mcVer, errors, it) - } - - if (!errors.isEmpty()) { - errors.forEach { - this.logger.error("Deprecated ${it[0]} is marked for removal in ${it[1]} but is not yet removed") - } - throw new IllegalStateException("Found deprecated members marked for removal but not yet removed in ${mcVer}; see log for details") - } - } - - protected processNode(MinecraftVersion mcVer, List errors, ClassNode node) { - node.visibleAnnotations?.each { annotation -> - ValidateDeprecations.processAnnotations(annotation, mcVer, errors) { - "class ${node.name}" - } - } - node.fields?.each { field -> - field.visibleAnnotations?.each { annotation -> - ValidateDeprecations.processAnnotations(annotation, mcVer, errors) { - "field ${node.name}#${field.name}" - } - } - } - node.methods?.each { method -> - method.visibleAnnotations?.each { annotation -> - ValidateDeprecations.processAnnotations(annotation, mcVer, errors) { - "method ${node.name}#${method.name}${method.desc}" - } - } - } - } - - private static void processAnnotations(AnnotationNode annotation, MinecraftVersion mcVer, List errors, Closure context) { - def values = annotation.values - if (values === null) - return - int forRemoval = values.indexOf('forRemoval') - int since = values.indexOf('since') - if (annotation.desc == 'Ljava/lang/Deprecated;' && forRemoval !== -1 && since !== -1 && values.size() >= 4 && values[forRemoval + 1] === true) { - def oldVersion = MinecraftVersion.from(values[since + 1]) - int[] split = ValidateDeprecations.splitDots(oldVersion.toString()) - if (split.length < 2) - return - def removeVersion = MinecraftVersion.from("${split[0]}.${split[1] + 1}") - if (removeVersion <= mcVer) - errors.add([context(), removeVersion]) - } - } - - @CompileStatic - private static int[] splitDots(String version) { - String[] pts = version.split('\\.') - int[] values = new int[pts.length] - for (int x = 0; x < pts.length; x++) - values[x] = Integer.parseInt(pts[x]) - return values - } -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckATs.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckATs.groovy deleted file mode 100644 index 7e7bf20da2..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckATs.groovy +++ /dev/null @@ -1,282 +0,0 @@ -package net.minecraftforge.forge.tasks.checks - -import groovy.transform.CompileStatic -import groovy.transform.TupleConstructor -import net.minecraftforge.forge.tasks.InheritanceData -import net.minecraftforge.srgutils.IMappingFile -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.RegularFile -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.tasks.InputFile -import org.gradle.api.tasks.InputFiles -import org.gradle.api.tasks.Optional -import org.objectweb.asm.Opcodes - -@CompileStatic -abstract class CheckATs extends CheckTask { - - @InputFile abstract RegularFileProperty getInheritance() - @InputFiles abstract ConfigurableFileCollection getAts() - - @Override - void check(Reporter reporter, boolean fix) { - final inheritance = InheritanceData.parse(this.inheritance.get().asFile) - - ats.each { - final lines = process(it, reporter, inheritance) - if (fix) { - it.text = joinBack(lines, inheritance).join('\n') - } - } - } - - private static TreeMap process(File file, Reporter reporter, Map inheritance) { - final TreeMap lines = ATParser.parse(file.readLines(), reporter) - final Map constructorGroups = [:] - - final itr = lines.entrySet().iterator() - final toRemove = [] - while (itr.hasNext()) { - final next = itr.next() - String key = next.key - final entry = next.value - if (entry === null) continue - - final binaryName = entry.cls.replaceAll('\\.', '/') - - // Process Groups, this will remove any entries outside the group that is covered by the group - if (entry.group) { - final jcls = inheritance[binaryName] - if (jcls === null) { - itr.remove() - reporter.report("Invalid group: $key") - } else if ('*' == entry.desc) { - if (!jcls.fields) { - itr.remove() - reporter.report("Invalid group, class has no fields: $key") - } else { - jcls.fields.each { field, value -> - final fkey = entry.cls + ' ' + field - if (accessLevel(value.access) < accessStr(entry.modifier)) { - if (lines.containsKey(fkey)) { - toRemove.add(fkey) - } else if (!entry.existing.contains(fkey)) { - reporter.report("Missing group entry: $fkey") - } - entry.children.add(fkey) - } else if (lines.containsKey(fkey)) { - toRemove.add(fkey) - reporter.report("Found invalid group entry: $fkey") - } - } - entry.existing.findAll { it !in entry.children }.each { println('Removed: ' + it) } - } - } else if ('*()' == entry.desc) { - if (!jcls.methods) { - itr.remove() - reporter.report("Invalid group, class has no methods: $key") - } else { - jcls.methods.each { mtd, value -> - if (mtd.startsWith('') || mtd.startsWith('lambda$')) return - key = entry.cls + ' ' + mtd.replace(' ', '') - if (accessLevel(value.access) < accessStr(entry.modifier)) { - if (lines.containsKey(key)) { - toRemove.add(key) - } else if (!entry.existing.contains(key)) { - reporter.report("Missing group entry: $key") - } - entry.children.add(key) - } else if (lines.containsKey(key)) { - toRemove.add(key) - reporter.report("Found invalid group entry: $key") - } - } - entry.existing.findAll { it !in entry.children }.each { println('Removed: ' + it) } - } - } else if ('' == entry.desc) { //Make all public non-abstract subclasses - constructorGroups.put(binaryName, entry) - } - } - - // Process normal lines, remove invalid and remove narrowing - else { - def jcls = inheritance.get(binaryName) - if (jcls === null) { - itr.remove() - reporter.report("Invalid: $key") - } else if (entry.desc == '') { - if (accessLevel(jcls.access) > accessStr(entry.modifier) && (entry.comment === null || !entry.comment.startsWith('#force '))) { - itr.remove() - reporter.report("Invalid Narrowing: $key") - } - } else if (!entry.desc.contains('(')) { - if (!jcls.fields || !jcls.fields.containsKey(entry.desc)) { - itr.remove() - reporter.report("Invalid: $key") - } else { - final value = jcls.fields[entry.desc] - if (accessLevel(value.access) > accessStr(entry.modifier) && (entry.comment === null || !entry.comment.startsWith('#force '))) { - itr.remove() - reporter.report("Invalid Narrowing: $key - ${entry.comment}") - } - } - } else { - final jdesc = entry.desc.replace('(', ' (') - if (!jcls.methods || !jcls.methods.containsKey(jdesc)) { - itr.remove() - reporter.report("Invalid: $key") - } else { - final value = jcls.methods[jdesc] - if (accessLevel(value.access) > accessStr(entry.modifier) && (entry.comment === null || !entry.comment.startsWith('#force '))) { - itr.remove() - reporter.report("Invalid Narrowing: $key") - } - } - } - } - } - - inheritance.each { tcls, value -> - if (!value.methods || ((value.access & Opcodes.ACC_ABSTRACT) !== 0)) return - String parent = tcls - while (parent !== null) { - constructorGroups[parent]?.tap { entry -> - value.methods.each { mtd, v -> - if (mtd.startsWith('')) { - final child = tcls.replaceAll('/', '\\.') + ' ' + mtd.replace(' ', '') - if (accessLevel(v.access) < 3) { - if (lines.containsKey(child)) { - toRemove.add(child) - } else if (child !in entry.existing) { - reporter.report("Missing group entry: $child") - } - entry.children.add(child) - } else if (lines.containsKey(child)) { - toRemove.add(child) - reporter.report("Found invalid group entry: $child") - } - } - } - } - parent = inheritance[parent]?.superName - } - } - constructorGroups.values().each { entry -> entry.existing.findAll { it !in entry.children }.each{ reporter.report("Found invalid group entry: $it") } } - - toRemove.each(lines.&remove) - - return lines - } - - private static List joinBack(TreeMap lines, Map inheritance) { - final data = [] as List - lines.each { key, value -> - if (!value.group) { - def comment = null //value.comment - data.add(value.modifier + ' ' + key + (comment ? ' ' + comment : '')) - } else { - data.add(('#group ' + value.modifier + ' ' + key + ' ' + (value.comment ?: '')).trim()) - value.children.each { - final line = value.modifier + ' ' + it - final entry = ATParser.parseEntry(line) - final comment = null //entry.comment - data.add(line + (comment ? ' ' + comment : '')) - } - data.add('#endgroup') - } - } - return data - } - - static int accessStr(String access) { - if (access.endsWith('-f') || access.endsWith('+f')) return 4 - switch (access.toLowerCase()) { - case 'public': return 3 - case 'protected': return 2 - case 'default': return 1 - case 'private': return 0 - default: return -1 - } - } - - static int accessLevel(int access) { - if ((access & Opcodes.ACC_PUBLIC) !== 0) return 3 - if ((access & Opcodes.ACC_PROTECTED) !== 0) return 2 - if ((access & Opcodes.ACC_PRIVATE) !== 0) return 0 - return 1 - } -} - -@CompileStatic -class ATParser { - static TreeMap parse(List lines, CheckTask.Reporter reporter) { - TreeMap outLines = new TreeMap<>() - Entry group = null - for (final line : lines) { - if (line.isEmpty()) continue - if (line.startsWith('#group ')) { - final entry = parseEntry(line.substring(7)) - - if (entry.desc != '*' && entry.desc != '*()' && entry.desc != '') { - reporter.report("Invalid group: $line", false) - } - - entry.group = true - entry.children = [] - entry.existing = [] - - group = entry - - if (outLines.containsKey(entry.key)) { - reporter.report("Duplicate group: $line", false) - } - - outLines[entry.key] = group - } else if (group !== null) { - if (line.startsWith('#endgroup')) { - group = null - } else { - final key = parseEntry(line).key - group.existing.add(key) - } - } else if (line.startsWith('#endgroup')) { - reporter.report("Invalid group ending: $line", false) - } else if (line.startsWith('#')) { - //Nom - } else { - final entry = parseEntry(line) - if (outLines.containsKey(entry.key)) { - reporter.report("Found duplicate: $line") - continue - } - outLines[entry.key] = entry - } - } - return outLines - } - - static Entry parseEntry(String line) { - final idx = line.indexOf('#') - final String comment = idx === -1 ? null : line.substring(idx) - if (idx !== -1) line = line.substring(0, idx - 1) - final data = (line.trim() + ' ').split(' ', -1) - data[1] = data[1].replaceAll('/', '.') // Convert to Source names, internal names are fine by spec, but not supported by old AST based AT implementations. - new Entry(data[0], data[1], data[2], comment) - } - - @TupleConstructor - static final class Entry { - String modifier, cls, desc, comment - - Set existing - TreeSet children - boolean group = false - - @Lazy - String key = {cls + (desc.isEmpty() ? '' : ' ' + desc)}() - - Object getAt(String key) { - return getProperty(key) - } - } -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckExcs.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckExcs.groovy deleted file mode 100644 index 8925657539..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckExcs.groovy +++ /dev/null @@ -1,95 +0,0 @@ -package net.minecraftforge.forge.tasks.checks - -import net.minecraftforge.forge.tasks.Util -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.tasks.InputFile -import org.gradle.api.tasks.InputFiles -import org.objectweb.asm.ClassReader -import org.objectweb.asm.ClassVisitor -import org.objectweb.asm.MethodVisitor -import org.objectweb.asm.Type - -import java.util.zip.ZipEntry -import java.util.zip.ZipInputStream - -abstract class CheckExcs extends CheckTask { - - @InputFile abstract RegularFileProperty getBinary() - @InputFiles abstract ConfigurableFileCollection getExcs() - - @Override - void check(Reporter reporter, boolean fix) { - final Set known = [] - collectKnown(known) - - excs.each { f -> - final lines = [] - f.eachLine { line -> - int idx = line.indexOf('#') - if (idx === 0 || line.isEmpty()) { - return - } - - if (idx !== -1) line = line.substring(0, idx - 1) - - if (!line.contains('=')) { - reporter.report("Invalid: $line") - return - } - - def (String key, String value) = line.split('=', 2) - if (!known.contains(key)) { - reporter.report("Unknown: $line") - return - } - - String desc = key.split('\\.', 2)[1] - if (!desc.contains('(')) { - reporter.report("Invalid: $line") - return - } - desc = '(' + desc.split('\\(', 2)[1] - - def (exceptions, String args) = value.contains('|') ? value.split('|', 2) : [value, ''] - - if (args.split(',').length !== Type.getArgumentTypes(desc).length) { - reporter.report("Invalid: $line") - return - } - lines.add(line) - - return - } - - if (fix) f.text = lines.sort().join('\n') - } - } - - private void collectKnown(Collection known) { - binary.get().asFile.withInputStream { i -> - new ZipInputStream(i).withCloseable { zin -> - final visitor = new ClassVisitor(Util.ASM_LEVEL) { - private String cls - @Override - void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - this.cls = name - } - - @Override - MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { - known.add(this.cls + '.' + name + descriptor) - super.visitMethod(access, name, descriptor, signature, exceptions) - } - } - ZipEntry zein - while ((zein = zin.nextEntry) !== null) { - if (zein.name.endsWith('.class')) { - ClassReader reader = new ClassReader(zin) - reader.accept(visitor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES) - } - } - } - } - } -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckMode.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckMode.groovy deleted file mode 100644 index 8580aa64e4..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckMode.groovy +++ /dev/null @@ -1,11 +0,0 @@ -package net.minecraftforge.forge.tasks.checks - -import groovy.transform.CompileStatic - -@CompileStatic -enum CheckMode { - CHECK, - FIX - - CheckMode() {} -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckPatches.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckPatches.groovy deleted file mode 100644 index 89192dff55..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckPatches.groovy +++ /dev/null @@ -1,182 +0,0 @@ -package net.minecraftforge.forge.tasks.checks - -import groovy.transform.CompileStatic -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.provider.ListProperty -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputDirectory -import org.gradle.api.tasks.Optional - -import java.nio.file.Files -import java.nio.file.Path -import java.util.regex.Pattern - -@CompileStatic -abstract class CheckPatches extends CheckTask { - - private static final Pattern HUNK_START_PATTERN = Pattern.compile('^@@ -[0-9,]* \\+[0-9,_]* @@$') - private static final Pattern WHITESPACE_PATTERN = Pattern.compile('^[+\\-]\\s*$') - private static final Pattern IMPORT_PATTERN = Pattern.compile('^[+\\-]\\s*import.*') - private static final Pattern FIELD_PATTERN = Pattern.compile('^[+\\-][\\s]*((public|protected|private)[\\s]*)?(static[\\s]*)?(final)?([^=;]*)(=.*)?;\\s*$') - private static final Pattern METHOD_PATTERN = Pattern.compile('^[+\\-][\\s]*((public|protected|private)[\\s]*)?(static[\\s]*)?(final)?([^(]*)[(]([^)]*)?[)]\\s*[{]\\s*$') - private static final Pattern CLASS_PATTERN = Pattern.compile('^[+\\-][\\s]*((public|protected|private)[\\s]*)?(static[\\s]*)?(final[\\s]*)?(class|interface)([^{]*)[{]\\s*$') - private static final Map ACCESS_MAP = [private: 0, protected: 2, public: 3].tap { it.put(null, 1) } - - @InputDirectory abstract DirectoryProperty getPatchDir() - @Input @Optional abstract ListProperty getPatchesWithS2SArtifact() - - @Override - void check(Reporter reporter, boolean fix) { - final patchDir = getPatchDir().get().asFile.toPath() - Files.walk(patchDir).withCloseable { - it.filter(Files.&isRegularFile).forEach { path -> - final String relativeName = patchDir.relativize(path).toString() - verifyPatch(path, reporter, fix, relativeName, patchesWithS2SArtifact.get().contains(relativeName.replace('\\', '/'))) - } - } - } - - static boolean accessChange(String previous, String current) { - //return ACCESS_MAP[previous] < ACCESS_MAP[current] - return previous != current - } - - void verifyPatch(Path patch, Reporter reporter, boolean fix, String patchPath, boolean hasS2SArtifact) { - int oldFixedErrors = reporter.fixed.size() - - final lines = Files.readAllLines(patch) - - int hunksStart = 0 - boolean onlyWhiteSpace = false - - final List newLines = [] - - // First two lines are file name ++/-- and we do not care - newLines.add(lines[0] + '\n') - newLines.add(lines[1] + '\n') - - int i - for (i = 2; i < lines.size(); ++i) { - def line = lines[i] - newLines.add(line + '\n') - - if (HUNK_START_PATTERN.matcher(line).find()) { - if (onlyWhiteSpace) { - if (!hasS2SArtifact) - reporter.report("Patch contains only white space hunk starting at line ${hunksStart + 1}, file: $patchPath") - int toRemove = i - hunksStart - while (toRemove-- > 0) - newLines.remove(newLines.size() - 1) - } - hunksStart = i - onlyWhiteSpace = true - continue - } - - if (line.startsWithAny('+','-')) { - def prefixChange = false - def prevLine = lines[i - 1] - - if (line.charAt(0) == (char)'+' && prevLine.charAt(0) == (char)'-') { - def prevTrim = prevLine.substring(1).replaceAll("\\s", "") - def currTrim = line.substring(1).replaceAll("\\s", "") - - if (prevTrim == currTrim) { - prefixChange = true - } - - def pMatcher = FIELD_PATTERN.matcher(prevLine) - def cMatcher = FIELD_PATTERN.matcher(line) - - if (pMatcher.find() && cMatcher.find() && - pMatcher.group(6) == cMatcher.group(6) && // = ... - pMatcher.group(5) == cMatcher.group(5) && // field name - pMatcher.group(3) == cMatcher.group(3) && // static - (accessChange(pMatcher.group(2), cMatcher.group(2)) || pMatcher.group(4) != cMatcher.group(4))) { - reporter.report("Patch contains access changes or final removal at line ${i + 1}, file: $patchPath", false) - } - - pMatcher = METHOD_PATTERN.matcher(prevLine) - cMatcher = METHOD_PATTERN.matcher(line) - - if (pMatcher.find() && cMatcher.find() && - pMatcher.group(6) == cMatcher.group(6) && // params - pMatcher.group(5) == cMatcher.group(5) && // void name - pMatcher.group(3) == cMatcher.group(3) && // static - (accessChange(pMatcher.group(2), cMatcher.group(2)) || pMatcher.group(4) != cMatcher.group(4))) { - reporter.report("Patch contains access changes or final removal at line ${i + 1}, file: $patchPath", false) - } - - pMatcher = CLASS_PATTERN.matcher(prevLine) - cMatcher = CLASS_PATTERN.matcher(line) - - if (pMatcher.find() && cMatcher.find() && - pMatcher.group(6) == cMatcher.group(6) && // ClassName<> extends ... - pMatcher.group(5) == cMatcher.group(5) && // class | interface - pMatcher.group(3) == cMatcher.group(3) && // static - (accessChange(pMatcher.group(2), cMatcher.group(2)) || pMatcher.group(4) != cMatcher.group(4))) { - reporter.report("Patch contains access changes or final removal at line ${i + 1}, file: $patchPath", false) - } - } - - if (line.charAt(0) == (char)'-' && i + 1 < lines.size()) { - final nextLine = lines[i + 1] - if (nextLine.charAt(0) == (char)'+') { - final nextTrim = nextLine.substring(1).replaceAll("\\s", "") - final currTrim = line.substring(1).replaceAll("\\s", "") - - if (nextTrim == currTrim) { - prefixChange = true - } - } - } - - final isWhiteSpaceChange = WHITESPACE_PATTERN.matcher(line).find() - - if (!prefixChange && !isWhiteSpaceChange) { - onlyWhiteSpace = hasS2SArtifact && IMPORT_PATTERN.matcher(line).find() - } else if (isWhiteSpaceChange) { - final prevLineChange = prevLine.startsWithAny('+','-') - final nextLineChange = i + 1 < lines.size() && lines[i + 1].startsWithAny('+','-') - - if (!prevLineChange && !nextLineChange) { - reporter.report("Patch contains white space change in valid hunk at line ${i + 1}, file: $patchPath \n$prevLine\n$line\n${lines[i+1]}", false) - } - } - - if (line.contains('\t')) { - reporter.report("Patch contains tabs on line ${i + 1}, file: $patchPath") - line = line.replaceAll('\t', ' ') - newLines.remove(newLines.size() - 1) - newLines.add(line + '\n') - } - - if (IMPORT_PATTERN.matcher(line).find() && !hasS2SArtifact) { - reporter.report("Patch contains import change on line ${i + 1}, file: $patchPath", false) - } - } - } - - if (onlyWhiteSpace) { - if (!hasS2SArtifact) - reporter.report("Patch contains only white space hunk starting at line ${hunksStart + 1}, file: $patchPath") - def toRemove = i - hunksStart; - while (toRemove-- > 0) - newLines.remove(newLines.size() - 1) - } - - if ((reporter.fixed.size() > oldFixedErrors && fix) || hasS2SArtifact) { - if (newLines.size() <= 2) { - logger.lifecycle("Patch is now empty removing, file: {}", patchPath) - Files.delete(patch) - } - else { - if (!hasS2SArtifact) - logger.lifecycle("*** Updating patch file. Please run setup then genPatches again. ***") - Files.newBufferedWriter(patch).withCloseable { - newLines.each { l -> it.write(l) } - } - } - } - } -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckSAS.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckSAS.groovy deleted file mode 100644 index bc93cf05ba..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckSAS.groovy +++ /dev/null @@ -1,110 +0,0 @@ -package net.minecraftforge.forge.tasks.checks - -import groovy.transform.CompileStatic -import net.minecraftforge.forge.tasks.Annotatable -import net.minecraftforge.forge.tasks.InheritanceData -import org.gradle.api.file.ConfigurableFileCollection -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.tasks.InputFile -import org.gradle.api.tasks.InputFiles - -@CompileStatic -abstract class CheckSAS extends CheckTask { - - @InputFile abstract RegularFileProperty getInheritance() - @InputFiles abstract ConfigurableFileCollection getSass() - - @Override - void check(Reporter reporter, boolean fix) { - final inheritance = InheritanceData.parse(this.inheritance.get().asFile) - - sass.each { f -> - final lines = [] - f.eachLine { line -> - if (line[0] == '\t') return // Skip any tabbed lines, those are ones we add - final idx = line.indexOf('#') - if (idx == 0 || line.isEmpty()) { - lines.add(line) - return - } - def comment = idx == -1 ? null : line.substring(idx) - if (idx != -1) line = line.substring(0, idx - 1) - final spl = (line.trim().replace('(', ' (') + ' ').split(' ', -1) - def (String cls, String name, String desc) = [spl[0], spl[1], spl[2]] - cls = cls.replaceAll('\\.', '/') - - if (inheritance[cls] === null) { - reporter.report("Invalid: $line") - } else if (name.isEmpty()) { //Class SAS - final toAdd = [] - final clsSided = isSided(inheritance[cls]) - boolean sided = clsSided - - /* TODO: MergeTool doesn't do fields - if (json[cls]['fields'] != null) { - for (entry in json[cls]['fields']) { - if (isSided(entry.value)) { - sided = true - toAdd.add('\t' + cls + ' ' + entry.key) - } - } - } */ - - final clsInh = inheritance[cls] - if (clsInh.methods) { - for (entry in clsInh.methods) { - if (isSided(entry.value)) { - sided = true - toAdd.add('\t' + cls + ' ' + entry.key.replaceAll(' ', '')) - findChildMethods(inheritance, cls, entry.key).each { lines.add('\t' + it) } - findChildMethods(inheritance, cls, entry.key).each { println(line + ' -- ' + it) } - } else if (clsSided) { - findChildMethods(inheritance, cls, entry.key).each { lines.add('\t' + it) } - findChildMethods(inheritance, cls, entry.key).each { println(line + ' -- ' + it) } - } - } - } - - if (sided) { - lines.add(cls + (comment == null ? '' : ' ' + comment)) - lines.addAll(toAdd.sort()) - } else { - reporter.report("Invalid: $line") - } - - } else if (desc.isEmpty()) { // Fields - /* TODO: MergeTool doesn't do fields - if (json[cls]['fields'] != null && isSided(json[cls]['fields'][name])) - lines.add(cls + ' ' + name + (comment == null ? '' : ' ' + comment)) - else */ - reporter.report("Invalid: $line") - } else { // Methods - final clsInh = inheritance[cls] - if (clsInh.methods === null || !isSided(clsInh.methods[name + ' ' + desc])) - reporter.report("Invalid: $line") - else { - lines.add(cls + ' ' + name + desc + (comment == null ? '' : ' ' + comment)) - findChildMethods(inheritance, cls, name + ' ' + desc).each { println(line + ' -- ' + it) } - findChildMethods(inheritance, cls, name + ' ' + desc).each { lines.add('\t' + it) } - } - } - } - - if (fix) f.text = lines.join('\n') - } - } - - protected static boolean isSided(Annotatable annotatable) { - if (annotatable === null) return false - for (ann in annotatable.annotations) { - if ('Lnet/minecraftforge/api/distmarker/OnlyIn;' == ann.desc) - return true - } - return false - } - - protected static findChildMethods(Map json, String cls, String desc) { - return json.values().findAll{ it.methods !== null && it.methods[desc] !== null && it.methods[desc].override == cls && isSided(it.methods[desc]) } - .collect { it.name + ' ' + desc.replace(' ', '') } as TreeSet - } -} diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckTask.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckTask.groovy deleted file mode 100644 index 62b50abdbf..0000000000 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/checks/CheckTask.groovy +++ /dev/null @@ -1,114 +0,0 @@ -package net.minecraftforge.forge.tasks.checks - -import groovy.transform.CompileStatic -import groovy.transform.stc.ClosureParams -import groovy.transform.stc.ThirdParam -import net.minecraftforge.forge.tasks.Util -import org.gradle.api.Action -import org.gradle.api.DefaultTask -import org.gradle.api.logging.LogLevel -import org.gradle.api.provider.Property -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.TaskAction -import org.gradle.api.tasks.TaskContainer -import org.gradle.api.tasks.VerificationTask - -@CompileStatic -abstract class CheckTask extends DefaultTask implements VerificationTask { - @Input - abstract Property getMode() - - private boolean ignoreFailures = false - - @Input - @Override - boolean getIgnoreFailures() { - return ignoreFailures - } - - @Override - void setIgnoreFailures(boolean ignoreFailures) { - this.ignoreFailures = ignoreFailures - } - - @TaskAction - void run() { - Util.init() - - boolean doFix = getMode().get() === CheckMode.FIX - final Reporter reporter = new Reporter(doFix) - check(reporter, doFix) - - if (reporter.messages) { - if (getMode().get() === CheckMode.CHECK) { - logger.error("Check task '{}' found errors:\n{}", name, reporter.messages.join('\n')) - if (!ignoreFailures) { - throw new IllegalArgumentException("${reporter.messages.size()} errors were found!") - } - } else { - if (logger.isEnabled(LogLevel.DEBUG)) { - logger.warn("Check task '{}' found {} errors and fixed {}:\n{}", name, reporter.messages.size(), reporter.fixed.size(), reporter.fixed.join('\n')) - } else { - logger.warn("Check task '{}' found {} errors and fixed {}.", name, reporter.messages.size(), reporter.fixed.size()) - } - - if (reporter.notFixed) { - logger.error('{} errors could not be fixed:\n{}', reporter.notFixed.size(), reporter.notFixed.join('\n')) - if (!ignoreFailures) { - throw new IllegalArgumentException("${reporter.notFixed.size()} errors which cannot be fixed were found!") - } - } - } - } - } - - abstract void check(Reporter reporter, boolean fix) - - @CompileStatic - static final class Reporter { - final boolean trackFixed - Reporter(boolean trackFixed) { - this.trackFixed = trackFixed - } - - public final List messages = [] - - public final List fixed = [] - public final List notFixed = [] - - void report(String message, boolean canBeFixed = true) { - messages.add(message) - - if (trackFixed) { - if (canBeFixed) { - fixed.add(message) - } else { - notFixed.add(message) - } - } - } - } - - static void registerTask(TaskContainer tasks, String taskName, @DelegatesTo.Target('type') Class clazz, - @DelegatesTo(genericTypeIndex = 0, target = 'type') - @ClosureParams(ThirdParam.FirstGenericType) Closure configuration) { - taskName = taskName.capitalize() - tasks.register("check$taskName", clazz) { CheckTask task -> - def castedTask = task as T - configuration.setDelegate(castedTask) - configuration.call(castedTask) - castedTask.mode.set(CheckMode.CHECK) - castedTask.group = 'checks' - } - tasks.named('checkAll').configure { it.dependsOn("check$taskName") } - - tasks.register("checkAndFix$taskName", clazz) { CheckTask task -> - def castedTask = task as T - configuration.setDelegate(castedTask) - configuration.call(castedTask) - castedTask.mode.set(CheckMode.FIX) - castedTask.group = 'checks' - } - tasks.named('checkAllAndFix').configure { it.dependsOn("checkAndFix$taskName") } - } -} diff --git a/build_clean.gradle b/build_clean.gradle deleted file mode 100644 index 21471fcc6c..0000000000 --- a/build_clean.gradle +++ /dev/null @@ -1,73 +0,0 @@ -plugins { - id 'java-library' - id 'net.minecraftforge.gradle.patcher' -} - -evaluationDependsOn(':mcp') - -repositories { - mavenCentral() - maven gradleutils.forgeMaven - maven gradleutils.minecraftLibsMaven -} - -java.toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION) - -dependencies { - implementation(libs.forgespi) -} - -patcher { - parent = project(':mcp') - mcVersion = MC_VERSION - patchedSrc = file('src/main/java') - - mappings channel: MAPPING_CHANNEL, version: MAPPING_VERSION - - runs { - clean_client { - client true - taskName 'clean_client' - ideaModule "${rootProject.name}.${project.name}.main" - - main 'net.minecraft.client.main.Main' - workingDirectory project.file('run/client') - - args '--gameDir', '.' - args '--version', MC_VERSION - args '--assetsDir', downloadAssets.output - args '--assetIndex', '{asset_index}' - args '--accessToken', '0' - } - - clean_server { - client false - taskName 'clean_server' - ideaModule "${rootProject.name}.${project.name}.main" - - main 'net.minecraft.server.Main' - workingDirectory project.file('run/server') - } - } -} - -tasks.withType(JavaCompile).configureEach { - options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation - options.warnings = false // Shutup deprecated for removal warnings -} - -eclipse.classpath.file.whenMerged { - // Disable optional warnings on the minecraft decompiled source code. It just muddies the warning window and hides warnings in our own codebase - def src = entries.find { it.path == 'src/main/java' } - if (src == null) throw new IllegalStateException("You must run `setup` task before importing") - src.entryAttributes['ignore_optional_problems'] = 'true' -} - -tasks.named('genPatches').configure { - onlyIf { false } -} - -tasks.named('extractRangeMap').configure { - onlyIf { false } - tool = 'net.minecraftforge:Srg2Source:8.1.0:fatjar' -} \ No newline at end of file diff --git a/build_forge.gradle b/build_forge.gradle deleted file mode 100644 index 27c950ac8b..0000000000 --- a/build_forge.gradle +++ /dev/null @@ -1,1021 +0,0 @@ -import de.undercouch.gradle.tasks.download.Download -import net.minecraftforge.forge.tasks.checks.CheckATs -import net.minecraftforge.forge.tasks.checks.CheckExcs -import net.minecraftforge.forge.tasks.checks.CheckPatches -import net.minecraftforge.forge.tasks.checks.CheckSAS -import net.minecraftforge.forge.tasks.checks.CheckTask - -import java.nio.file.Files -import net.minecraftforge.forge.tasks.* -import static net.minecraftforge.forge.tasks.Util.* -import net.minecraftforge.gradle.common.tasks.ApplyBinPatches -import net.minecraftforge.gradle.common.tasks.CheckJarCompatibility -import net.minecraftforge.gradle.common.tasks.DownloadMavenArtifact -import net.minecraftforge.gradle.common.tasks.ExtractInheritance -import net.minecraftforge.gradle.patcher.tasks.FilterNewJar -import net.minecraftforge.gradle.patcher.tasks.GeneratePatches -import net.minecraftforge.gradle.userdev.tasks.RenameJar -import org.apache.tools.ant.filters.ReplaceTokens -import org.objectweb.asm.Opcodes - -plugins { - id 'idea' - id 'eclipse' - id 'java-library' - id 'maven-publish' - id 'net.minecraftforge.licenser' - id 'de.undercouch.download' - id 'net.minecraftforge.gradleutils' - id 'net.minecraftforge.gradle.patcher' - id 'net.minecraftforge.gradlejarsigner' -} - -Util.init() //Init all our extension methods! - -// We depend on all other projects so that we can know their versions for userdev config -rootProject.subprojects.each { sib -> if (sib != project) evaluationDependsOn(sib.path) } - -apply from: rootProject.file('build_shared.gradle') - -java { - toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION) - withSourcesJar() -} - -jarSigner.autoDetect('forge') - -applyPatches { - level 'WARNING' - failOnError = UPDATING != 'true' - rejects = rootProject.layout.projectDirectory.dir('rejects').asFile -} - -sourceSets { - main { - java { - srcDir "$rootDir/src/main/java" - } - resources { - srcDir "$rootDir/src/main/resources" - srcDir "$rootDir/src/main/generated" - } - } - test { - java { - srcDir "$rootDir/src/test/java" - } - resources { - srcDir "$rootDir/src/test/resources" - srcDir "$rootDir/src/test/generated" - } - } -} - -final String SPEC_VERSION = gitversion.info.tag - -// The new versioning sceme is -.. -// ForgeMC is a unique identifier for every MC version we have supported. -// Essentially, the same as the old, except dropping the first number, and the builds are no longer unique. -final def MCP_ARTIFACT = project(':mcp').mcp.config.get() - -final List EXTRA_TXTS = [ - rootProject.file('LICENSE.txt'), - rootProject.tasks.createChangelog.outputFile -] - -ext { - MAVEN_PATH = "${group.toString().replace('.', '/')}/${project.name}/${VERSION}".toString() -} -final String MAVEN_PATH = ext.MAVEN_PATH - -final String BINPATCH_TOOL = 'net.minecraftforge:binarypatcher:1.3.0:fatjar' -final String INSTALLER_TOOLS = 'net.minecraftforge:installertools:1.4.5' -final String FART = 'net.minecraftforge:ForgeAutoRenamingTool:1.0.6' -final String S2S_TOOL = 'net.minecraftforge:Srg2Source:8.2.0:fatjar' - -configurations { - // Don't pull all libraries, if we're missing something, add it to the installer list so the installer knows to download it. - bootstrap { transitive = false } - installer { - extendsFrom(bootstrap) - transitive = false - } - api.extendsFrom(installer) -} - -dependencies { - // These need to actually be on the classpath at the start. This is only used for the server shim jar. - // And this is only needed because custom file systems are REQUIRED to be on the boot classloader. - // This has ASM/BootStrap/Unsafe all because I haven't gotten around to moving UnionFileSystem out to its own project. - bootstrap(libs.jarjar.fs) // JarInJar file system - bootstrap(libs.roimfs) // JarInJar File System - FileSystems need to be on boot loader. - bootstrap(libs.bundles.jimfs) // In memory file system used for ForgeDev launches - bootstrap(libs.securemodules) // Has Union file system in it - bootstrap(libs.unsafe) // Needed by securemodules - bootstrap(libs.bundles.asm) // Needed by securemodules - - implementation(libs.jopt.simple) - - installer(libs.bootstrap) - installer(libs.bootstrap.api) // Needed by securemodules - installer(libs.accesstransformers) - installer(libs.eventbus) - installer(libs.jspecify) // Dep of EventBus - installer(libs.forgespi) - installer(libs.coremods.api) - installer(libs.modlauncher) - installer(libs.mergetool.api) - installer(libs.bundles.night.config) - installer(libs.maven.artifact) - installer(libs.bundles.terminalconsoleappender) - installer(libs.mixin) - installer(libs.mixinextras.forge) - installer(libs.bundles.jarjar) - installer(libs.roimfs) - - installer(project(':fmlcore')) - installer(project(':fmlloader')) - installer(project(':fmlearlydisplay')) - installer(project(':javafmllanguage')) - installer(project(':lowcodelanguage')) - installer(project(':mclanguage')) - installer(project(':forge-transformers')) - - runtimeOnly(libs.bootstrap) - runtimeOnly(libs.bootstrap.dev) - - annotationProcessor(libs.eventbus.validator) -} - -tasks.named('extractRangeMap').configure { - tool = S2S_TOOL -} -tasks.named('applyRangeMap').configure { - tool = S2S_TOOL -} -tasks.named('applyRangeMapBase').configure { - tool = S2S_TOOL -} - -// Disable all tests, we have GameTests not JUnit tests -test { - exclude '**/*' -} - -patcher { - excs.from file("$rootDir/src/main/resources/forge.exc") - parent = project(':mcp') - mcVersion = MC_VERSION - mappings channel: MAPPING_CHANNEL, version: MAPPING_VERSION - patches = file("$rootDir/patches/minecraft") - patchedSrc = file('src/main/java') - srgPatches = false - accessTransformers.from file("$rootDir/src/main/resources/META-INF/accesstransformer.cfg") - sideAnnotationStrippers.from file("$rootDir/src/main/resources/forge.sas") - - runs { - forge_client { - property 'eventbus.api.strictRuntimeChecks', 'true' - property 'org.lwjgl.system.SharedLibraryExtractDirectory', 'lwjgl_dll' - - args '--launchTarget', 'forge_dev_client', - '--username', 'Dev', - '--version', project.name, - '--accessToken', '0', - '--userType', 'mojang', - '--versionType', 'release', - '--assetsDir', downloadAssets.output, - '--assetIndex', "{asset_index}" - } - - forge_client_test { - parent runs.forge_client - source sourceSets.test - } - - forge_server { - args '--launchTarget', 'forge_dev_server' - } - - forge_server_test { - parent runs.forge_server - source sourceSets.test - } - - forge_server_gametest { - args '--launchTarget', 'forge_dev_server_gametest' - args '--uniqueWorld' // Unique world is used so that the world regenerates, as well as the world config isn't influenced by other runs - } - - forge_server_gametest_test { - parent runs.forge_server_gametest - source sourceSets.test - } - - forge_data { - args '--launchTarget', 'forge_dev_data', - '--mod', 'forge', - '--all', - '--output', rootProject.file('src/main/generated/'), - '--existing', sourceSets.main.resources.srcDirs[0], - '--assetsDir', downloadAssets.output, - '--assetIndex', "{asset_index}" - } - - forge_data_test { - source sourceSets.test - args '--launchTarget', 'forge_dev_data', - '--mod', '.+', - '--all', - '--output', rootProject.file('src/test/generated/'), - '--existing', sourceSets.main.resources.srcDirs[0], - '--existing', sourceSets.test.resources.srcDirs[0], - '--assetsDir', downloadAssets.output, - '--assetIndex', "{asset_index}" - } - - forge_client_data { - args '--launchTarget', 'forge_dev_client_data', - '--mod', 'forge', - '--all', - '--output', rootProject.file('src/main/generated/'), - '--existing', sourceSets.main.resources.srcDirs[0], - '--assetsDir', downloadAssets.output, - '--assetIndex', "{asset_index}" - } - - forge_client_data_test { - source sourceSets.test - args '--launchTarget', 'forge_dev', - '--launchEntry', 'minecraft/net.minecraft.client.data.Main', - '--launchData', - '--mod', '.+', - '--all', - '--output', rootProject.file('src/test/generated/'), - '--existing', sourceSets.main.resources.srcDirs[0], - '--existing', sourceSets.test.resources.srcDirs[0], - '--assetsDir', downloadAssets.output, - '--assetIndex', "{asset_index}" - } - } -} - -afterEvaluate { - if (!patcher.srgPatches) { - srg2mcpClean { - dependsOn = [] - input = project(':mcp').setupMCP.output - } - userdevJar { - onlyIf = { t -> true } - } - } -} - -tasks.register('downloadCrowdin', Download) { - src 'https://files.minecraftforge.net/crowdin.zip' - dest file('build/crowdin.zip') - useETag 'all' - onlyIfModified true - quiet true -} - -tasks.userdevConfig.configure { - configurations.installer.allDependencies.forEach { - def dep = it.toString() - if (it instanceof ProjectDependency) - dep = "net.minecraftforge:$it.dependencyProject.name:$it.dependencyProject.version" - libraries.add(dep) - } - - // TODO [ForgeDev][UserDev] Split API/Runtime elements in userdev config - // so we don't gotta keep making exceptions for MixinExtras - addCompileDependency(libs.mixinextras.common) - addAnnotationProcessorDependency(libs.mixinextras.common) - - inject = '' // We don't have a userdev sourceset anymore. Empty as a gradle workaround... - runs { - client { - environment 'MCP_MAPPINGS', '{mcp_mappings}' - property 'forge.enableGameTest', 'true' - args '--launchTarget', "forge_userdev_client" - args '--version', 'MOD_DEV' - args '--assetIndex', '{asset_index}' - args '--assetsDir', '{assets_root}' - } - - clientData { - environment 'MCP_MAPPINGS', '{mcp_mappings}' - args '--launchTarget', "forge_userdev_client_data" - args '--assetIndex', '{asset_index}' - args '--assetsDir', '{assets_root}' - } - - server { - environment 'MCP_MAPPINGS', '{mcp_mappings}' - property 'forge.enableGameTest', 'true' - args '--launchTarget', "forge_userdev_server" - } - - gameTestServer { - environment 'MCP_MAPPINGS', '{mcp_mappings}' - args '--launchTarget', "forge_userdev_server_gametest" - } - - data { - environment 'MCP_MAPPINGS', '{mcp_mappings}' - args '--launchTarget', "forge_userdev_data" - args '--assetIndex', '{asset_index}' - args '--assetsDir', '{assets_root}' - } - } -} - -for (def run in patcher.runs + tasks.userdevConfig.runs) { - if (run.parents) continue // We already added this to the parent run config - //run.property 'bsl.debug', 'true' - run.args '--gameDir', '.' - run.jvmArgs '-Djava.net.preferIPv6Addresses=system', '-XX:+UseCompactObjectHeaders' - run.client run.name.contains('client') - run.main 'net.minecraftforge.bootstrap.ForgeBootstrap' -} - -for (def run : patcher.runs) { - def isTest = run.name.endsWith('_test') - run.taskName = run.name - run.workingDirectory file('run/' + run.name) - run.ideaModule rootProject.name + '.' + project.name + '.' + (isTest ? 'test' : 'main') - run.property 'bsl.debug', 'true' - run.property 'terminal.jline', 'true' - if (isTest) { - run.property 'forge.enableGameTest', 'true' - run.property 'forgedev.enableTestMods', 'true' - } -} - -tasks.register('downloadVersionManifest', Download) { - src 'https://piston-meta.mojang.com/mc/game/version_manifest_v2.json' - dest file('build/versions/version_manifest.json') - useETag 'all' - onlyIfModified true - quiet true -} -tasks.register('downloadJson', Download) { - dependsOn downloadVersionManifest - inputs.file downloadVersionManifest.dest - src { downloadVersionManifest.dest.json.versions.find { it.id == MC_VERSION }.url } - dest file("build/versions/$MC_VERSION/version.json") - useETag 'all' - onlyIfModified true - quiet true -} -tasks.register('downloadClientRaw', Download) { - dependsOn downloadJson - inputs.file downloadJson.dest - src { downloadJson.dest.json.downloads.client.url } - dest file("build/versions/$MC_VERSION/client.jar") - useETag 'all' - onlyIfModified true - quiet true -} -tasks.register('downloadServerRaw', Download) { - dependsOn downloadJson - inputs.file downloadJson.dest - src { downloadJson.dest.json.downloads.server.url } - dest file("build/versions/$MC_VERSION/server-bundled.jar") - useETag 'all' - onlyIfModified true - quiet true -} -tasks.register('extractServer', ExtractFile) { - dependsOn downloadServerRaw - input = downloadServerRaw.dest - target = "META-INF/versions/$MC_VERSION/server-${MC_VERSION}.jar" - output = file("build/versions/$MC_VERSION/server.jar") -} -tasks.register('downloadLibraries', DownloadLibraries) { - dependsOn downloadJson - input = downloadJson.dest - output = rootProject.file('build/libraries/') -} -tasks.register('extractInheritance', ExtractInheritance) { - dependsOn downloadLibraries - tool = INSTALLER_TOOLS + ':fatjar' - args.add '--annotations' - input = genJoinedBinPatches.cleanJar - libraries.addAll downloadLibraries.librariesOutput.map { rf -> - Files.readAllLines(rf.asFile.toPath()).stream().map(File::new).toList() - } -} -tasks.register("findFinalizeSpawnTargets", BytecodePredicateFinder) { - dependsOn downloadClientRaw - jar = downloadClientRaw.dest - output = rootProject.file('forge-transformers/src/main/resources/coremods/finalize_spawn_targets.json') - predicate = { - parent, node, insn -> - return 'net/minecraft/world/level/BaseSpawner' != parent.name // Ignore this class as we special case it. - && insn.getOpcode().equals(Opcodes.INVOKEVIRTUAL) - && insn.name == 'finalizeSpawn' - && insn.desc == '(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/EntitySpawnReason;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;'; - } -} -tasks.register('validateDeprecations', ValidateDeprecations) { - input = tasks.jar.archiveFile - mcVersion = MC_VERSION -} -tasks.named('jar', Jar).configure { - finalizedBy 'validateDeprecations' -} -tasks.register("downloadInstaller", DownloadMavenArtifact) { - artifact = "net.minecraftforge:installer:2.2.+:fatjar" - changing = true -} -tasks.register("downloadServerShim", DownloadMavenArtifact) { - artifact = libs.bootstrap.shim.get().toString() - changing = true -} -tasks.register("createJoinedSRG", DownloadMavenArtifact) { - artifact = "net.minecraft:joined:${MC_VERSION}-${MCP_VERSION}" -} -tasks.named('genClientBinPatches').configure { - dependsOn(downloadClientRaw) - tool = BINPATCH_TOOL - cleanJar = downloadClientRaw.dest - dirtyJar = jar.archiveFile -} -tasks.named('genServerBinPatches').configure { - dependsOn(extractServer) - tool = BINPATCH_TOOL - cleanJar = extractServer.output - dirtyJar = jar.archiveFile -} -tasks.named('genJoinedBinPatches').configure { - tool = BINPATCH_TOOL - cleanJar = createJoinedSRG.output - dirtyJar = jar.archiveFile -} -tasks.register('applyClientBinPatches', ApplyBinPatches) { - dependsOn downloadClientRaw - tool = BINPATCH_TOOL - clean = downloadClientRaw.dest - patch = genClientBinPatches.output - args.addAll(['--data', '--unpatched', '--store', '--marker', '.forge_patched_minecraft']) -} -tasks.register('applyServerBinPatches', ApplyBinPatches) { - dependsOn extractServer - tool = BINPATCH_TOOL - clean = extractServer.output - patch = genServerBinPatches.output - args.addAll(['--data', '--unpatched', '--store']) -} -tasks.register('applyJoinedBinPatches', ApplyBinPatches) { - tool = BINPATCH_TOOL - clean = genJoinedBinPatches.cleanJar - patch = genJoinedBinPatches.output -} -tasks.register('createServerShimClasspath', BundleList) { - dependsOn(downloadServerRaw) - serverBundle = downloadServerRaw.dest -} -tasks.register('createServerShimConfig') { - ext.output = file('build/libs/bootstrap-shim.properties') - doLast { - var cfg = new CleanProperties() - cfg['Main-Class'] = 'net.minecraftforge.bootstrap.ForgeBootstrap' - cfg['Java-Version'] = '25' - cfg['Arguments'] = '--launchTarget forge_server' - cfg.store(output) - } -} -tasks.register('serverShimJar', Jar) { - dependsOn(createServerShimConfig) - from (createServerShimConfig.output) - from (createServerShimClasspath.output) { - rename { 'bootstrap-shim.list' } - } - from (zipTree(downloadServerShim.output)) - manifest { - from { - zipTree(downloadServerShim.output).find { it.name == 'MANIFEST.MF' } - } - - attributes('Class-Path': configurations.bootstrap.resolvedConfiguration.resolvedArtifacts.collect { "libraries/${Util.getMavenInfoFromDep(it).path}" }.join(' ')) - } - archiveClassifier = 'shim' - jarSigner.sign(it) -} -tasks.register('checkAll') { - dependsOn 'checkLicenses' - group = 'checks' -} -tasks.register('checkAllAndFix') { - dependsOn 'findFinalizeSpawnTargets', 'checkLicenses' - group = 'checks' -} - -CheckTask.registerTask(tasks, 'ATs', CheckATs) { - dependsOn extractInheritance - ats.from patcher.accessTransformers - inheritance = extractInheritance.output -} - -CheckTask.registerTask(tasks, 'SAS', CheckSAS) { - dependsOn extractInheritance - sass.from patcher.sideAnnotationStrippers - inheritance = extractInheritance.output -} - -CheckTask.registerTask(tasks, 'Excs', CheckExcs) { - dependsOn jar - binary = jar.archiveFile.get().asFile - excs.from patcher.excs -} - -CheckTask.registerTask(tasks, 'Patches', CheckPatches) { - dependsOn 'genPatches' - patchDir = file("$rootDir/patches") - patchesWithS2SArtifact = [ - 'minecraft/net/minecraft/client/renderer/ViewArea.java.patch', - 'minecraft/net/minecraft/data/models/blockstates/Variant.java.patch', - ] -} - -tasks.named('genPatches', GeneratePatches).configure { - finalizedBy checkAndFixPatches - autoHeader true - lineEnding = '\n' -} - -def baseForgeVersionProperty = project.objects.property(String) -baseForgeVersionProperty.set(project.provider { TeamcityRequests.attemptFindBase(rootDir) ?: getLatestForgeVersion(MC_VERSION) }) -baseForgeVersionProperty.finalizeValueOnRead() -final jarCompatibilityTaskSetup = { Task task -> - task.group = 'jar compatibility' - task.onlyIf { - baseForgeVersionProperty.getOrNull() !== null - } -} - -tasks.register('setupCheckJarCompatibility', SetupCheckJarCompatibility) { - inputVersion = baseForgeVersionProperty -} - -tasks.register('applyBaseCompatibilityJarBinPatches', ApplyBinPatches) { - jarCompatibilityTaskSetup(it) - - clean = project.tasks.createJoinedSRG.output - patch = project.tasks.named('setupCheckJarCompatibility').flatMap { it.baseBinPatchesOutput } - output = project.layout.buildDirectory.dir(name).map { it.file('output.jar') } -} - -tasks.register('mergeBaseForgeJar', MergeJars) { - jarCompatibilityTaskSetup(it) - - inputJars.from(project.tasks.named('applyBaseCompatibilityJarBinPatches').flatMap { it.output }) - inputJars.from(baseForgeVersionProperty.map { inputVersion -> - def output = project.layout.buildDirectory.dir(name).map { it.file("forge-${inputVersion}-universal.jar") }.get().asFile - project.rootProject.extensions.download.run { - src "https://maven.minecraftforge.net/net/minecraftforge/forge/${inputVersion}/forge-${inputVersion}-universal.jar" - dest output - } - return output - }) -} - -tasks.register('checkJarCompatibility', CheckJarCompatibility) { - jarCompatibilityTaskSetup(it) - dependsOn 'setupCheckJarCompatibility' - - baseJar = project.tasks.named('mergeBaseForgeJar').flatMap { it.output } - baseLibraries.from(project.tasks.named('createJoinedSRG').flatMap { it.output }) - - inputJar = project.tasks.named('reobfJar').flatMap { it.output } - - commonLibraries.from(project.configurations.minecraftImplementation) - commonLibraries.from(project.configurations.installer) -} - -tasks.register('launcherJson', LauncherJson).configure { - json.putAll([ - mainClass: 'net.minecraftforge.bootstrap.ForgeBootstrap', - arguments: [ - game: [ - '--launchTarget', 'forge_client' - ], - jvm: [ - '-Djava.net.preferIPv6Addresses=system', - '-XX:+UseCompactObjectHeaders' - ] - ] - ] as LinkedHashMap) -} - -tasks.register('installerJson', InstallerJson) { - icon = rootProject.file('icon.ico') - - // Json to install into the client's launcher - dependsOn(launcherJson) - input.from(launcherJson.output) - - // Get 'base' MC jar, Client is straight download, server is extracted from the bundle - dependsOn(downloadClientRaw, extractServer) - input.from(downloadClientRaw.dest, extractServer.output) - // Apply Binary patches to vanilla jar - dependsOn(applyClientBinPatches, applyServerBinPatches) - input.from(applyClientBinPatches.output, applyServerBinPatches.output, genClientBinPatches.toolJar) - - doFirst { - var libs = libraries - String[] INSTALLER_TOOLS_CLASSPATH = getClasspath(project, libs, INSTALLER_TOOLS) - json.putAll([ - _comment: launcherJson.json._comment, - hideExtract: true, - spec: 1, - profile: project.name, - version: launcherJson.json.id, - path: Util.getMavenInfoFromTask(tasks.serverShimJar).name, - minecraft: MC_VERSION, - serverJarPath: '{LIBRARY_DIR}/net/minecraft/server/{MINECRAFT_VERSION}/server-{MINECRAFT_VERSION}-bundled.jar', - data: [ - MC_UNPACKED: [ - client: "[net.minecraft:client:${MC_VERSION}]", - server: "[net.minecraft:server:${MC_VERSION}:unpacked]" - ], - MC_UNPACKED_SHA: [ - client: "'${downloadClientRaw.dest.sha1}'", - server: "'${extractServer.output.get().asFile.sha1}'" - ], - BINPATCH: [ - client: '/data/client.lzma', - server: '/data/server.lzma' - ], - PATCHED: [ - client: "[${project.group}:${project.name}:${project.version}:client]", - server: "[${project.group}:${project.name}:${project.version}:server]" - ], - PATCHED_SHA: [ - client: "'${applyClientBinPatches.output.get().asFile.sha1}'", - server: "'${applyServerBinPatches.output.get().asFile.sha1}'" - ] - ], - processors: [ - [ - sides: ['server'], - jar: INSTALLER_TOOLS, - classpath: INSTALLER_TOOLS_CLASSPATH, - args: [ - '--task', 'EXTRACT_FILES', - '--archive', '{INSTALLER}', - - '--from', 'data/README.txt', - '--to', '{ROOT}/README.txt', - - '--from', 'data/run.sh', - '--to', '{ROOT}/run.sh', - '--exec', '{ROOT}/run.sh', - - '--from', 'data/run.bat', - '--to', '{ROOT}/run.bat', - - '--from', 'data/user_jvm_args.txt', - '--to', '{ROOT}/user_jvm_args.txt', - '--optional', '{ROOT}/user_jvm_args.txt', - - '--from', 'data/unix_args.txt', - '--to', "{ROOT}/libraries/${MAVEN_PATH}/unix_args.txt", - - '--from', 'data/win_args.txt', - '--to', "{ROOT}/libraries/${MAVEN_PATH}/win_args.txt" - ] - ], [ - sides: ['server'], - jar: INSTALLER_TOOLS, - classpath: INSTALLER_TOOLS_CLASSPATH, - args: [ - '--task', 'BUNDLER_EXTRACT', - '--input', '{MINECRAFT_JAR}', - '--output', '{ROOT}/libraries/', - '--libraries' - ] - ], [ - sides: ['server'], - jar: INSTALLER_TOOLS, - classpath: INSTALLER_TOOLS_CLASSPATH, - args: [ - '--task', 'BUNDLER_EXTRACT', - '--input', '{MINECRAFT_JAR}', - '--output', '{MC_UNPACKED}', - '--jar-only' - ], - outputs: [ - '{MC_UNPACKED}': '{MC_UNPACKED_SHA}' - ] - ], [ - sides: ['server'], - jar: BINPATCH_TOOL.rsplit(':', 1)[0], // remove :fatjar - classpath: getClasspath(project, libs, BINPATCH_TOOL.rsplit(':', 1)[0]), - args: [ - '--clean', '{MC_UNPACKED}', - '--output', '{PATCHED}', - '--apply', '{BINPATCH}', - '--data', '--unpatched', '--store' - ], - outputs: [ - '{PATCHED}': '{PATCHED_SHA}' - ] - ], [ - sides: ['client'], - jar: BINPATCH_TOOL.rsplit(':', 1)[0], // remove :fatjar - classpath: getClasspath(project, libs, BINPATCH_TOOL.rsplit(':', 1)[0]), - args: [ - '--clean', '{MINECRAFT_JAR}', - '--output', '{PATCHED}', - '--apply', '{BINPATCH}', - '--data', '--unpatched', '--store', '--marker', '.forge_patched_minecraft' - ], - outputs: [ - '{PATCHED}': '{PATCHED_SHA}' - ] - ] - ] - ] as LinkedHashMap) - getClasspath(project, libs, MCP_ARTIFACT.descriptor) //Tell it to download mcp_config - } -} - -tasks.register('officialClassesOnly', Zip).configure { - dependsOn(jar) - destinationDirectory = file('build/libs') - archiveClassifier = 'official-classes' - from zipTree(jar.archiveFile).matching { - include '**/*.class' - exclude 'mcp/**' - } -} - -tasks.named('filterJarNew').configure { - dependsOn('officialClassesOnly') - input = officialClassesOnly.archiveFile - filterInners = true -} - -tasks.named('universalJar').configure { - dependsOn downloadCrowdin - from zipTree(downloadCrowdin.dest).matching { - include 'assets/forge/lang/*.json' - } - - from(EXTRA_TXTS) - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - exclude '.cache' - - manifest { - attributes([ - 'Automatic-Module-Name': 'net.minecraftforge.forge' - ] as LinkedHashMap) - attributes([ - 'Specification-Title': 'Forge', - 'Specification-Vendor': 'Forge Development LLC', - 'Specification-Version': SPEC_VERSION, - 'Implementation-Title': project.group, - 'Implementation-Vendor': 'Forge Development LLC', - 'Implementation-Version': FORGE_VERSION - ] as LinkedHashMap, 'net/minecraftforge/versions/forge/') - attributes([ - 'Specification-Title': 'Minecraft', - 'Specification-Vendor': 'Forge Development LLC', - 'Specification-Version': MC_VERSION, - 'Implementation-Title': 'MCP', - 'Implementation-Vendor': 'Forge Development LLC', - 'Implementation-Version': MCP_VERSION - ] as LinkedHashMap, 'net/minecraftforge/versions/mcp/') - } - jarSigner.sign(it) -} - -tasks.named('userdevConfig').configure { - universal = "$project.group:$project.name:$project.version:universal@jar" -} - -tasks.register('installerJar', InstallerJar) { - fat = !System.env.TEAMCITY_VERSION - //offline = true - from(EXTRA_TXTS) - from(rootProject.file('/forge_installer_logo.png')) { - rename { 'big_logo.png' } - } - from(genClientBinPatches.output) { - rename { 'data/client.lzma' } - } - from(genServerBinPatches.output) { - rename { 'data/server.lzma' } - } - - final var argsFile = rootProject.file('server_files/args.txt') - final Map> tokens = [tokens: [ - SHIM_JAR_FILE: serverShimJar.archiveFileName.get(), - MAVEN_PATH: MAVEN_PATH - ]] - from(argsFile) { - filter(tokens, ReplaceTokens) - into 'data' - rename { 'unix_args.txt' } - } - from(argsFile) { - filter(tokens, ReplaceTokens) - into 'data' - rename { 'win_args.txt' } - } - - from(rootProject.file('server_files')) { - filter(tokens, ReplaceTokens) - into 'data' - exclude 'args.txt' - } - - jarSigner.sign(it) -} - -final mdkGradleWrapper = tasks.register('mdkGradleWrapper', Wrapper) { - gradleVersion = '9.3.1' -} - -tasks.register('mdkZip', Zip) { - dependsOn mdkGradleWrapper - - archiveBaseName = project.name - archiveClassifier = 'mdk' - archiveVersion = project.version - destinationDirectory = file('build/libs') - - from mdkGradleWrapper.map(Wrapper.&getScriptFile) - from mdkGradleWrapper.map(Wrapper.&getBatchScript) - from(EXTRA_TXTS) - into('gradle/wrapper/') { - from mdkGradleWrapper.map(Wrapper.&getJarFile) - from mdkGradleWrapper.map(Wrapper.&getPropertiesFile) - } - from(rootProject.file('mdk/')){ - rootProject.file('mdk/gitignore.txt').eachLine { - if (!it.trim().isEmpty() && !it.trim().startsWith('#')) - exclude it - } - - filter(ReplaceTokens, tokens: [ - FORGE_VERSION: FORGE_VERSION, - FORGE_GROUP: project.group, - FORGE_NAME: project.name, - MC_VERSION: MC_VERSION, - MAPPING_CHANNEL: MAPPING_CHANNEL, - MAPPING_VERSION: MAPPING_VERSION, - FORGE_SPEC_VERSION: SPEC_VERSION.split("\\.")[0], - MC_NEXT_VERSION: MC_NEXT_VERSION, - EVENTBUS_VERSION: libs.versions.eventbus.get() - ]) - rename 'gitignore\\.txt', '.gitignore' - rename 'gitattributes\\.txt', '.gitattributes' - } - from(rootProject.file('src/test/java/com/example/examplemod/')) { - into('src/main/java/com/example/examplemod/') - } - from(rootProject.file('src/test/generated/mdk_datagen/')) { - into('src/main/resources/') - exclude '**/.cache/' - } -} - -license { - header = file("$rootDir/LICENSE-header.txt") - - include 'net/minecraftforge/' - exclude 'net/minecraftforge/common/LenientUnboundedMapCodec.java' - - tasks { - main { - files.from files("$rootDir/src/main/java") - } - test { - files.from files("$rootDir/src/test/java") - } - } -} - -tasks.register('genAllData') { - dependsOn 'forge_data', 'forge_data_test', 'forge_client_data_test' -} - -if (project.hasProperty('UPDATE_MAPPINGS')) { - extractRangeMap { - sources.from sourceSets.test.java.srcDirs - addDependencies compileTestJava.classpath - } - applyRangeMap { - sources.from sourceSets.test.java.srcDirs - } - sourceSets.test.java.srcDirs.each { extractMappedNew.addTarget it } -} - -tasks.named('javadoc', Javadoc).configure { - description 'Generates the combined javadocs for the FML projects and the main Forge project' - var includedProjects = [ ':fmlcore', ':fmlloader', ':javafmllanguage', ':mclanguage', ':forge-transformers' ] - source includedProjects.collect { project(it).sourceSets.main.allJava } - classpath = classpath + files(includedProjects.collect { project(it).sourceSets.main.compileClasspath }) - - var docsDir = rootProject.file('src/docs/') - inputs.dir(docsDir) - .withPropertyName('docs resources directory') - .withPathSensitivity(PathSensitivity.RELATIVE) - .optional() - - failOnError = false - - // Exclude the Minecraft classes if not enabled - if (!project.hasProperty('generateAllDocumentation')) { - exclude 'net/minecraft/**' - exclude 'com/mojang/**' - } - exclude 'mcp/**' - - options.addStringOption('Xdoclint:all,-missing', '-public') - options { - stylesheetFile = new File(docsDir, 'stylesheet.css') - - tags = [ - 'apiNote:a:API Note:', - 'implSpec:a:Implementation Requirements:', - 'implNote:a:Implementation Note:' - ] - - groups = [ - 'Forge Mod Loader': [ - 'net.minecraftforge.fml.common.asm*', - 'net.minecraftforge.fml.loading*', - 'net.minecraftforge.fml.server*' - ], - 'FML Core': [ - 'net.minecraftforge.fml', - 'net.minecraftforge.fml.config*', - 'net.minecraftforge.fml.event*', - 'net.minecraftforge.fml.util*' - ], - 'FML Common': [ - 'net.minecraftforge.fml.core', - 'net.minecraftforge.fml.event.config', - 'net.minecraftforge.fml.event.lifecycle' - ], - 'FML Java/MC Language Providers': [ - 'net.minecraftforge.fml.common', - 'net.minecraftforge.fml.javafmlmod', - 'net.minecraftforge.fml.mclanguageprovider' - ], - 'Minecraft Forge API': [ - 'net.minecraftforge*' - ] - ] - - author = false - noSince = true - noHelp = true - - bottom = "Minecraft Forge is an open source modding API for Minecraft: Java Edition, licensed under the Lesser GNU General Public License, version 2.1." - windowTitle = "Minecraft Forge API ${VERSION}" - docTitle = "Minecraft Forge API - ${FORGE_VERSION} for Minecraft ${MC_VERSION}" - header = "
${FORGE_VERSION} for Minecraft ${MC_VERSION}
" - } - - doLast { - project.copy { - from docsDir - exclude '/stylesheet.css' - into destinationDir - } - } -} - -publishing { - publications.register('mavenJava', MavenPublication).configure { - artifact universalJar - artifact installerJar - artifact mdkZip - artifact userdevJar - artifact sourcesJar - artifact serverShimJar - - artifactId = project.name - pom { - name = project.name - description = 'Modifactions to Minecraft to enable mod developers.' - url = 'https://github.com/MinecraftForge/MinecraftForge' - gradleutils.pom.setGitHubDetails(pom, 'MinecraftForge') - license gradleutils.pom.Licenses.LGPLv2_1 - } - } - - repositories { - maven gradleutils.publishingForgeMaven - } -} - -// Make sure we run bin compat checking during local testing. -if ((!System.env.MAVEN_USER || !System.env.MAVEN_PASSWORD) && CHECK_COMPATIBILITY == "true") - tasks.named('publish').configure { dependsOn(':forge:checkJarCompatibility') } diff --git a/build_shared.gradle b/build_shared.gradle deleted file mode 100644 index b988510649..0000000000 --- a/build_shared.gradle +++ /dev/null @@ -1,89 +0,0 @@ -import net.minecraftforge.forge.tasks.CleanProperties - -apply plugin: 'eclipse' -apply plugin: 'idea' -apply plugin: 'net.minecraftforge.gradleutils' - -group = 'net.minecraftforge' -version = VERSION -println("Version: $version") - -repositories { - mavenCentral() - maven gradleutils.forgeMaven - maven gradleutils.minecraftLibsMaven - //mavenLocal() -} - -tasks.withType(Javadoc).configureEach { - options.tags = [ - 'apiNote:a:API Note:', - 'implSpec:a:Implementation Requirements:', - 'implNote:a:Implementation Note:' - ] - options.addStringOption('Xdoclint:all,-missing', '-public') -} - -// We need to write the manifest to the binary file so we have properly versioned packaged at dev time. -tasks.register('writeManifest') { - doLast { - if (plugins.findPlugin('net.minecraftforge.gradle.patcher')) // Forge project - universalJar.manifest.writeTo(rootProject.file('src/main/resources/META-INF/MANIFEST.MF')) - else - jar.manifest.writeTo(project.file('src/main/resources/META-INF/MANIFEST.MF')) - } -} - -tasks.register('generateResources') { - dependsOn('writeManifest') -} - -tasks.named('processResources') { - dependsOn(generateResources) -} - -// Make sure out manifests get written before compiling the code, IDEA calls this task if you tell it to use the gradle build. -tasks.withType(JavaCompile).configureEach { - dependsOn 'generateResources' - dependsOn 'processResources' // Needed because we merge the output of this with the output of the compile task. And gradle detects downstream tasks using the output without a hard dep - options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation - options.warnings = false // Shutup deprecated for removal warnings - options.forkOptions.jvmArgs += '-Xmx6G' // Needed to make compiling faster, and not run out of heap space in some cases. -} - -// Merge the resources and classes into the same directory. We'll need to split them at runtime because -// Minecraft and Forge are in the same sourceSet as they are inter dependent.. for now.. -sourceSets.each { - def dir = layout.buildDirectory.dir("classes/java/$it.name") - it.output.resourcesDir = dir - it.java.destinationDirectory = dir -} - -tasks.register('copyEclipseSettings') { - doLast { - rootProject.fileTree('ide/eclipse/template/.settings/').matching { include '**/*.prefs' }.each { file -> - def target = project.file('.settings/' + file.name) - def temp = new CleanProperties().load(file) - def exst = new CleanProperties().load(target) - exst.put('eclipse.preferences.version', '1') - exst.putAll(temp) - exst.store(target) - } - } -} - -// TODO: [Gradle][IntelliJ] Auto trigger these tasks on import. -eclipse { - // Run everytime eclipse builds the code - //autoBuildTasks writeManifest - // Run when importing the project - synchronizationTasks generateResources, copyEclipseSettings, eclipseClasspath, eclipseProject -} - -idea { - module { - // IntelliJ IDEA does not do this by itself anymore... - downloadJavadoc = true - downloadSources = true - } -} diff --git a/fmlcore/build.gradle b/fmlcore/build.gradle index 2c1153c9c9..d6adcbbea8 100644 --- a/fmlcore/build.gradle +++ b/fmlcore/build.gradle @@ -1,68 +1,78 @@ -import net.minecraftforge.gradleutils.PomUtils - plugins { id 'java-library' id 'maven-publish' - id 'net.minecraftforge.licenser' - id 'net.minecraftforge.gradleutils' + alias libs.plugins.licenser + alias libs.plugins.gradleutils + alias libs.plugins.gitversion + alias libs.plugins.changelog + id 'net.minecraftforge.forge.build.convention' } -apply from: rootProject.file('build_shared.gradle') +gradleutils.displayName = 'FML' +final vendor = 'Forge Development LLC' +description = 'Modifications to Minecraft to enable mod developers.' dependencies { - compileOnly(libs.jetbrains.annotations) + compileOnly libs.jetbrains.annotations - api(libs.eventbus) - annotationProcessor(libs.eventbus.validator) + api libs.eventbus - implementation(project(':fmlloader')) - implementation(libs.commons.io) + implementation projects.fmlloader + implementation libs.commons.io } java { - toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION) + toolchain.languageVersion = JavaLanguageVersion.of(javaVersion) withSourcesJar() } -tasks.named('jar', Jar).configure { - manifest { - attributes([ - 'Automatic-Module-Name': 'net.minecraftforge.fmlcore', - 'FMLModType': 'LIBRARY' - ] as LinkedHashMap) - attributes([ - 'Specification-Title': 'FML', - 'Specification-Vendor': 'Forge Development LLC', - 'Specification-Version': '1', - 'Implementation-Title': 'FML', - 'Implementation-Version': '1.0', - 'Implementation-Vendor': 'Forge Development LLC' - ] as LinkedHashMap, 'net/minecraftforge/fml/') - } +license { + header = rootProject.file('LICENSE-header.txt') +} +changelog { + from changelogBase } tasks.withType(JavaCompile).configureEach { options.compilerArgs << '-Xlint:-unchecked' } -license { - header = rootProject.file('LICENSE-header.txt') +tasks.named('jar', Jar) { + manifest { + attributes([ + 'Automatic-Module-Name': 'net.minecraftforge.fmlcore', + 'FMLModType' : 'LIBRARY' + ]) + attributes([ + 'Specification-Title' : gradleutils.displayName.get(), + 'Specification-Vendor' : vendor, + 'Specification-Version' : '1', + 'Implementation-Title' : gradleutils.displayName.get(), + 'Implementation-Version': '1.0', + 'Implementation-Vendor' : vendor + ], 'net/minecraftforge/fml/') + } } publishing { - publications.register('mavenJava', MavenPublication).configure { - from components.java - artifactId = 'fmlcore' - pom { - name = project.name - description = 'Modifactions to Minecraft to enable mod developers.' - url = 'https://github.com/MinecraftForge/MinecraftForge' - PomUtils.setGitHubDetails(pom, 'MinecraftForge') - license PomUtils.Licenses.LGPLv2_1 - } - } - repositories { maven gradleutils.publishingForgeMaven } + + publications.register('mavenJava', MavenPublication) { + changelog.publish(it) + gradleutils.promote(it) + + from components.java + + pom { + description = project.description + + gradleutils.pom.addRemoteDetails(pom) + + licenses { + license gradleutils.pom.licenses.LGPLv2_1 + } + } + } } diff --git a/fmlearlydisplay/build.gradle b/fmlearlydisplay/build.gradle index 78e8905e8f..b3316d0262 100644 --- a/fmlearlydisplay/build.gradle +++ b/fmlearlydisplay/build.gradle @@ -1,67 +1,74 @@ -import net.minecraftforge.gradleutils.PomUtils +import org.gradle.api.plugins.jvm.JvmTestSuite +import org.gradle.internal.os.OperatingSystem plugins { id 'java-library' + id 'jvm-test-suite' id 'maven-publish' - id 'net.minecraftforge.licenser' - id 'net.minecraftforge.gradleutils' + alias libs.plugins.licenser + alias libs.plugins.gradleutils + alias libs.plugins.gitversion + alias libs.plugins.changelog + id 'net.minecraftforge.forge.build.convention' } -apply from: rootProject.file('build_shared.gradle') - -import org.gradle.internal.os.OperatingSystem switch (OperatingSystem.current()) { - case OperatingSystem.LINUX: - project.ext.lwjglNatives = "natives-linux" - break - case OperatingSystem.MAC_OS: - project.ext.lwjglNatives = "natives-macos" - break - case OperatingSystem.WINDOWS: - project.ext.lwjglNatives = "natives-windows" - break + case OperatingSystem.LINUX: + project.ext.lwjglNatives = "natives-linux" + break + case OperatingSystem.MAC_OS: + project.ext.lwjglNatives = "natives-macos" + break + case OperatingSystem.WINDOWS: + project.ext.lwjglNatives = "natives-windows" + break } +gradleutils.displayName = 'FML Early Display' +final vendor = 'Forge Development LLC' +description = 'A pretty looking, but prone to erroring screen displayed during Forge loading.' + java { - toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION) + toolchain.languageVersion = JavaLanguageVersion.of(javaVersion) withSourcesJar() } +license { + header = rootProject.file('LICENSE-header.txt') +} + +changelog { + from changelogBase +} + dependencies { - compileOnly(libs.jetbrains.annotations) - implementation(project(':fmlloader')) - implementation(project(':fmlcore')) - implementation(libs.bundles.lwjgl) - implementation('org.slf4j:slf4j-api:1.8.0-beta4') - implementation(libs.jopt.simple) - testImplementation('org.junit.jupiter:junit-jupiter-api:5.8.2') - testImplementation('org.powermock:powermock-core:2.0.9') - testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.8.2') - testRuntimeOnly('org.slf4j:slf4j-jdk14:1.8.0-beta4') - testRuntimeOnly("org.lwjgl:lwjgl::$lwjglNatives") - testRuntimeOnly("org.lwjgl:lwjgl-glfw::$lwjglNatives") - testRuntimeOnly("org.lwjgl:lwjgl-opengl::$lwjglNatives") - testRuntimeOnly("org.lwjgl:lwjgl-stb::$lwjglNatives") + compileOnly libs.jetbrains.annotations + + implementation projects.fmlloader + implementation projects.fmlcore + implementation libs.bundles.lwjgl + implementation earlyDisplayLibs.slf4j.api + implementation libs.jopt.simple } -tasks.named('test', Test).configure { - useJUnitPlatform() +// See gradle/gradle#35070 (https://github.com/gradle/gradle/issues/35070) +// We are making the list of providers first BEFORE mapping them to a provider of the resolved objects so that they can be finalized after configuration. +var lwjglTestLibs = [ + dependencies.variantOf(earlyDisplayTestLibs.lwjgl) { classifier lwjglNatives }, + dependencies.variantOf(earlyDisplayTestLibs.lwjgl.glfw) { classifier lwjglNatives }, + dependencies.variantOf(earlyDisplayTestLibs.lwjgl.opengl) { classifier lwjglNatives }, + dependencies.variantOf(earlyDisplayTestLibs.lwjgl.stb) { classifier lwjglNatives } +].with { list -> + provider { list.collect { it.get() } } } -tasks.named('jar', Jar).configure { - manifest { - attributes([ - 'Automatic-Module-Name': 'net.minecraftforge.earlydisplay', - 'Forge-Module-Layer': 'boot' - ] as LinkedHashMap) - attributes([ - 'Specification-Title': 'FML Early Display', - 'Specification-Vendor': 'Forge Development LLC', - 'Specification-Version': '1', - 'Implementation-Title': 'FML Early Display', - 'Implementation-Vendor': 'Forge Development LLC', - 'Implementation-Version': '1.0' - ] as LinkedHashMap, 'net/minecraftforge/fml/earlydisplay/') +testing.suites.named('test', JvmTestSuite) { + useJUnitJupiter('5.8.2') + + dependencies { + implementation earlyDisplayTestLibs.powermock.core + runtimeOnly earlyDisplayLibs.slf4j.jdk14 + runtimeOnly.bundle lwjglTestLibs } } @@ -69,24 +76,42 @@ tasks.withType(JavaCompile).configureEach { options.compilerArgs << '-Xlint:unchecked' } -license { - header = rootProject.file('LICENSE-header.txt') +tasks.named('jar', Jar) { + manifest { + attributes([ + 'Automatic-Module-Name': 'net.minecraftforge.earlydisplay', + 'Forge-Module-Layer' : 'boot' + ]) + attributes([ + 'Specification-Title' : gradleutils.displayName.get(), + 'Specification-Vendor' : vendor, + 'Specification-Version' : '1', + 'Implementation-Title' : gradleutils.displayName.get(), + 'Implementation-Vendor' : vendor, + 'Implementation-Version': '1.0' + ], 'net/minecraftforge/fml/earlydisplay/') + } } publishing { - publications.register('mavenJava', MavenPublication).configure { - from components.java - artifactId = 'fmlearlydisplay' - pom { - name = project.name - description = 'A pretty looking, but prone to erroring screen displayed during Forge loading.' - url = 'https://github.com/MinecraftForge/MinecraftForge' - PomUtils.setGitHubDetails(pom, 'MinecraftForge') - license PomUtils.Licenses.LGPLv2_1 - } - } - repositories { maven gradleutils.publishingForgeMaven } -} + + publications.register('mavenJava', MavenPublication) { + changelog.publish(it) + gradleutils.promote(it) + + from components.java + + pom { + description = project.description + + gradleutils.pom.addRemoteDetails(pom) + + licenses { + license gradleutils.pom.licenses.LGPLv2_1 + } + } + } +} \ No newline at end of file diff --git a/fmlloader/build.gradle b/fmlloader/build.gradle index 1ee709ae2a..21a9112b80 100644 --- a/fmlloader/build.gradle +++ b/fmlloader/build.gradle @@ -1,69 +1,75 @@ -import net.minecraftforge.gradleutils.PomUtils +import groovy.transform.CompileDynamic +import groovy.transform.CompileStatic +import groovy.transform.PackageScope +import net.minecraftforge.forgedev.legacy.tasks.JarJarMetadataOptions +import org.gradle.api.plugins.jvm.JvmTestSuite + +import javax.inject.Inject plugins { id 'java-library' + id 'jvm-test-suite' id 'maven-publish' - id 'net.minecraftforge.licenser' - id 'net.minecraftforge.gradleutils' - alias(libs.plugins.apt) + alias libs.plugins.licenser + alias libs.plugins.gradleutils + alias libs.plugins.gitversion + alias libs.plugins.changelog + alias libs.plugins.apt + id 'net.minecraftforge.forge.build.convention' } -apply from: rootProject.file('build_shared.gradle') - -configurations.forEach{ it.transitive = false } - -dependencies { - compileOnly(libs.jetbrains.annotations) - - api(libs.bundles.asm) // Needed by all the black magic - api(libs.forgespi) - api(libs.mergetool.api) - api(libs.log4j.api) - api(libs.slf4j.api) - api(libs.guava) - api(libs.gson) - api(libs.maven.artifact) - api(libs.apache.commons) - api(libs.bundles.night.config) - api(libs.modlauncher) - api(libs.mojang.logging) - api(libs.jarjar.selector) - api(libs.jarjar.meta) - - implementation(libs.jopt.simple) - implementation(libs.securemodules) - implementation(libs.accesstransformers) - implementation(libs.terminalconsoleappender) - implementation(libs.jimfs) - implementation(libs.roimfs) - - // Needed because we have a custom log4j plugin, and they removed package scanning and require a data file to be generated - implementation(libs.log4j.core) - annotationProcessor(libs.bundles.log4j) - - testCompileOnly(libs.jetbrains.annotations) - testRuntimeOnly(libs.bootstrap) -} +gradleutils.displayName = 'FMLLoader' +final vendor = 'Forge Development LLC' +description = 'Modifications to Minecraft to enable mod developers.' java { - toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION) + toolchain.languageVersion = JavaLanguageVersion.of(javaVersion) withSourcesJar() } -tasks.named('jar', Jar).configure { - manifest { - attributes([ - 'Automatic-Module-Name': 'net.minecraftforge.fmlloader', - 'Forge-Module-Layer': 'boot' - ] as LinkedHashMap) - attributes([ - 'Specification-Title': 'FMLLoader', - 'Specification-Vendor': 'Forge Development LLC', - 'Specification-Version': '1', - 'Implementation-Title': 'FMLLoader', - 'Implementation-Vendor': 'Forge Development LLC', - 'Implementation-Version': FORGE_VERSION - ] as LinkedHashMap, 'net/minecraftforge/fml/loading/') +license { + header = rootProject.file('LICENSE-header.txt') +} + +changelog { + from changelogBase +} + +dependencies { + compileOnly libs.jetbrains.annotations + + // TODO [FMLLoader] Figure out a better way to lock transitive dependencies to the explicit versions shipped by the isntaller + api(libs.bundles.asm ){ transitive = false } // Needed by all the black magic + api(libs.forgespi ){ transitive = false } + api(libs.mergetool.api ){ transitive = false } + api(libs.log4j.api ){ transitive = false } + api(libs.slf4j.api ){ transitive = false } + api(libs.guava ){ transitive = false } + api(libs.gson ){ transitive = false } + api(libs.maven.artifact ){ transitive = false } + api(libs.apache.commons ){ transitive = false } + api(libs.bundles.night.config){ transitive = false } + api(libs.modlauncher ){ transitive = false } + api(libs.mojang.logging ){ transitive = false } + api(libs.jarjar.selector ){ transitive = false } + api(libs.jarjar.meta ){ transitive = false } + + implementation(libs.jopt.simple ){ transitive = false } + implementation(libs.securemodules ){ transitive = false } + implementation(libs.accesstransformers ){ transitive = false } + implementation(libs.terminalconsoleappender){ transitive = false } + implementation(libs.jimfs ){ transitive = false } + implementation(libs.roimfs ){ transitive = false } + + // Needed because we have a custom log4j plugin, and they removed package scanning and require a data file to be generated + implementation(libs.log4j.core ){ transitive = false } + annotationProcessor(libs.bundles.log4j){ transitive = false } +} + +testing.suites.named('test', JvmTestSuite) { + dependencies { + compileOnly libs.jetbrains.annotations + runtimeOnly libs.bootstrap } } @@ -71,39 +77,81 @@ tasks.withType(JavaCompile).configureEach { options.compilerArgs << '-Xlint:unchecked' } -license { - header = rootProject.file('LICENSE-header.txt') +tasks.named('jar', Jar) { + manifest { + attributes([ + 'Automatic-Module-Name': 'net.minecraftforge.fmlloader', + 'Forge-Module-Layer' : 'boot' + ]) + attributes([ + 'Specification-Title' : gradleutils.displayName.get(), + 'Specification-Vendor' : vendor, + 'Specification-Version' : '1', + 'Implementation-Title' : gradleutils.displayName.get(), + 'Implementation-Vendor' : vendor, + 'Implementation-Version': forgeVersion + ], 'net/minecraftforge/fml/loading/') + } } publishing { - publications.register('mavenJava', MavenPublication).configure { - from components.java - artifactId = 'fmlloader' - pom { - name = project.name - description = 'Modifactions to Minecraft to enable mod developers.' - url = 'https://github.com/MinecraftForge/MinecraftForge' - PomUtils.setGitHubDetails(pom, 'MinecraftForge') - license PomUtils.Licenses.LGPLv2_1 - } - } - repositories { maven gradleutils.publishingForgeMaven } -} -tasks.register('writeForgeVersionJson') { - doLast { - file('src/main/resources/forge_version.json').json = [ - forge: FORGE_VERSION, - mc: MC_VERSION, - mcp: MCP_VERSION - ] + publications.register('mavenJava', MavenPublication) { + changelog.publish(it) + gradleutils.promote(it) + + from components.java + + pom { + description = project.description + + gradleutils.pom.addRemoteDetails(pom) + + licenses { + license gradleutils.pom.licenses.LGPLv2_1 + } + } } } -tasks.register('jarJarOptionsJson', net.minecraftforge.forge.tasks.JarJarMetadataOptions) { +// A simple task to write JSON to a file. Using Task#doLast to output files is no longer supported. +// This code may seem verbose, but it's better this way. If more projects need this, we can move it to buildSrc. +@CompileStatic +@PackageScope abstract class WriteForgeVersionJson extends DefaultTask { + abstract @Input Property getForgeVersion() + abstract @Input Property getMinecraftVersion() + abstract @Input Property getMcpVersion() + + abstract @OutputFile RegularFileProperty getOutputFile() + + @Inject + WriteForgeVersionJson() {} + + @TaskAction + @CompileDynamic + void exec() { + var json = new groovy.json.JsonBuilder() + json { + forge this.forgeVersion.get() + mc this.minecraftVersion.get() + mcp this.mcpVersion.get() + } + this.outputFile.asFile.get().text = json.toPrettyString() + } +} + +tasks.register('writeForgeVersionJson', WriteForgeVersionJson) { + forgeVersion = project.forgeVersion + minecraftVersion = project.minecraftVersion + mcpVersion = project.mcpVersion + + outputFile = file('src/main/resources/forge_version.json') +} + +tasks.register('jarJarOptionsJson', JarJarMetadataOptions) { metadataFile = project.file('src/main/resources/jarjar_options.json') // This is resolved too early by cpw.mods.modlauncher.TransformationServicesHandler.discoverServices(DiscoveryData) But eventually... //add(libs.mixin, 'org/spongepowered/asm/mixin/Mixin.class') @@ -118,29 +166,25 @@ tasks.register('jarJarOptionsJson', net.minecraftforge.forge.tasks.JarJarMetadat } } -tasks.named('generateResources').configure { - dependsOn('eclipseJdt') - dependsOn('eclipseJdtApt') - dependsOn('eclipseFactorypath') - dependsOn('writeForgeVersionJson') - dependsOn('jarJarOptionsJson') +tasks.named('generateResources') { + dependsOn( + tasks.named('eclipseJdt'), + tasks.named('eclipseJdtApt'), + tasks.named('eclipseFactorypath'), + tasks.named('writeForgeVersionJson', WriteForgeVersionJson), + tasks.named('jarJarOptionsJson') + ) } -tasks.named('sourcesJar') { - dependsOn('jarJarOptionsJson') -} - -eclipse { - classpath { - // We need to set the default output directory for the log4j annotation processor - // Ideally we'd just set the value, but the eclipse plugin deduplicates the output directories - // So we have to do a hacky whenMerged - //defaultOutputDir = file('bin/main') - file.whenMerged { - entries.each { entry -> - if (entry.kind == 'output' && entry.hasProperty('path')) - entry.path = 'bin/main' - } - } +eclipse.classpath { + // We need to set the default output directory for the log4j annotation processor + // Ideally we'd just set the value, but the eclipse plugin deduplicates the output directories + // So we have to do a hacky whenMerged + //defaultOutputDir = file('bin/main') + file.whenMerged { + entries.each { entry -> + if (entry.kind == 'output' && entry.hasProperty('path')) + entry.path = 'bin/main' + } } } diff --git a/forge-transformers/build.gradle b/forge-transformers/build.gradle index 105a289c88..145d9ed3e9 100644 --- a/forge-transformers/build.gradle +++ b/forge-transformers/build.gradle @@ -1,73 +1,78 @@ -import net.minecraftforge.gradleutils.PomUtils - plugins { id 'java-library' id 'maven-publish' - id 'net.minecraftforge.licenser' - id 'net.minecraftforge.gradleutils' - alias(libs.plugins.apt) + alias libs.plugins.licenser + alias libs.plugins.gradleutils + alias libs.plugins.gitversion + alias libs.plugins.changelog + id 'net.minecraftforge.forge.build.convention' } -apply from: rootProject.file('build_shared.gradle') - -configurations.forEach{ it.transitive = false } - -dependencies { - compileOnly(libs.jetbrains.annotations) - - implementation(libs.bundles.asm) // Needed by all the black magic - implementation(libs.log4j.api) - implementation(libs.gson) - implementation(libs.modlauncher) - implementation(libs.coremods.api) - - testCompileOnly(libs.jetbrains.annotations) -} +gradleutils.displayName = 'Forge Transformers' +final vendor = 'Forge Development LLC' +description = 'Forge-specific transformers unrelated to the FML project.' java { - toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION) + toolchain.languageVersion = JavaLanguageVersion.of(javaVersion) withSourcesJar() } -tasks.named('jar', Jar) { - manifest { - attributes([ - 'Automatic-Module-Name': 'net.minecraftforge.forge.transformers', - 'Forge-Module-Layer': 'boot' - ] as LinkedHashMap) - attributes([ - 'Specification-Title': 'Forge Transformers', - 'Specification-Vendor': 'Forge Development LLC', - 'Specification-Version': '1', - 'Implementation-Title': 'Forge Transformers', - 'Implementation-Vendor': 'Forge Development LLC', - 'Implementation-Version': FORGE_VERSION - ] as LinkedHashMap, 'net/minecraftforge/forge/transformers/') - } -} - -tasks.withType(JavaCompile).configureEach { - options.compilerArgs << '-Xlint:unchecked' -} - license { header = rootProject.file('LICENSE-header.txt') } -publishing { - publications.register('mavenJava', MavenPublication) { - from components.java - artifactId = 'forge-transformers' - pom { - name = project.name - description = 'Forge-specific transformers unrelated to the FML project.' - url = 'https://github.com/MinecraftForge/MinecraftForge' - PomUtils.setGitHubDetails(pom, 'MinecraftForge') - license PomUtils.Licenses.LGPLv2_1 - } - } +changelog { + from changelogBase +} +dependencies { + compileOnly(libs.jetbrains.annotations) + + implementation(libs.bundles.asm ){ transitive = false } // Needed by all the black magic + implementation(libs.log4j.api ){ transitive = false } + implementation(libs.gson ){ transitive = false } + implementation(libs.modlauncher ){ transitive = false } + implementation(libs.coremods.api){ transitive = false } + + testCompileOnly(libs.jetbrains.annotations) +} + +tasks.named('jar', Jar) { + manifest { + attributes([ + 'Automatic-Module-Name': 'net.minecraftforge.forge.transformers', + 'Forge-Module-Layer' : 'boot' + ]) + attributes([ + 'Specification-Title' : gradleutils.displayName.get(), + 'Specification-Vendor' : vendor, + 'Specification-Version' : '1', + 'Implementation-Title' : gradleutils.displayName.get(), + 'Implementation-Vendor' : vendor, + 'Implementation-Version': forgeVersion + ], 'net/minecraftforge/forge/transformers/') + } +} + +publishing { repositories { maven gradleutils.publishingForgeMaven } + + publications.register('mavenJava', MavenPublication) { + changelog.publish(it) + gradleutils.promote(it) + + from components.java + + pom { pom -> + description = project.description + + gradleutils.pom.addRemoteDetails(pom) + + licenses { + license gradleutils.pom.licenses.LGPLv2_1 + } + } + } } diff --git a/forge-transformers/src/main/resources/coremods/finalize_spawn_targets.json b/forge-transformers/src/main/resources/coremods/finalize_spawn_targets.json index c2ed16258c..555238cf0c 100644 --- a/forge-transformers/src/main/resources/coremods/finalize_spawn_targets.json +++ b/forge-transformers/src/main/resources/coremods/finalize_spawn_targets.json @@ -42,12 +42,6 @@ "finalizeSpawn(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/EntitySpawnReason;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;" ] }, - { - "class": "net/minecraft/world/entity/animal/frog/Tadpole", - "methods": [ - - ] - }, { "class": "net/minecraft/world/entity/monster/Strider", "methods": [ @@ -85,24 +79,12 @@ "finalizeSpawn(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/EntitySpawnReason;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;" ] }, - { - "class": "net/minecraft/world/entity/monster/zombie/ZombieVillager", - "methods": [ - - ] - }, { "class": "net/minecraft/world/entity/npc/CatSpawner", "methods": [ "spawnCat(Lnet/minecraft/core/BlockPos;Lnet/minecraft/server/level/ServerLevel;Z)V" ] }, - { - "class": "net/minecraft/world/entity/npc/villager/Villager", - "methods": [ - - ] - }, { "class": "net/minecraft/world/entity/raid/Raid", "methods": [ @@ -158,11 +140,5 @@ "methods": [ "handleDataMarker(Ljava/lang/String;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/util/RandomSource;Lnet/minecraft/world/level/levelgen/structure/BoundingBox;)V" ] - }, - { - "class": "net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate", - "methods": [ - - ] } ] \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index fb411878ff..636e21bfab 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,17 +1,29 @@ +# TODO Re-evaluate # 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=-Xmx6G -org.gradle.daemon=false + +org.gradle.warning.mode=all +org.gradle.caching=true org.gradle.parallel=true +org.gradle.configureondemand=true -JAVA_VERSION=25 -MC_VERSION=26.2 -MC_NEXT_VERSION=26.3 -MCP_VERSION=20260616.103818 -MAPPING_CHANNEL=official -MAPPING_VERSION=26.2 +# TODO [ForgeDev] Enable this once ForgeDev 7 tasks are fully migrated +org.gradle.configuration-cache=false +org.gradle.configuration-cache.parallel=false +#org.gradle.configuration-cache.problems=warn +#org.gradle.configuration-cache.integrity-check=true -# Set to true before the first build of a new MC version, so we don't do compatibility checks -CHECK_COMPATIBILITY=false -# Set to true to allow for fuzzy patching. Useful during updateing -UPDATING=false +net.minecraftforge.gradleutils.ide.automatic.sources=true +net.minecraftforge.gradleutils.compilation.defaults=true + +net.minecraftforge.gradle.merge-source-sets=true + +# Controls if the compatibility checks are auto-added to the 'check' task. +# The check tasks are still created and can be run, they just are not grouped with the normal 'check' task. +# Set to false for the first builds of a new Minecraft version. +net.minecraftforge.forge.build.check.compatibility=false +# Set to true to allow for fuzzy patching. Useful during updating. +net.minecraftforge.forge.build.updating=false +# Set to true to enable the 'validatePublish' task which is currently a work in progress +net.minecraftforge.forgedev.validate.publish=false diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3..61285a659d 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 e18bc253b8..1a704683a0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a4269..adff685a03 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 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. @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # 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 +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -112,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -170,7 +171,6 @@ fi # 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" ) @@ -203,15 +203,14 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 25da30dbde..c4bdd3ab8e 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -68,11 +70,10 @@ goto fail :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 %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/javafmllanguage/build.gradle b/javafmllanguage/build.gradle index e81fd2b59f..8f0b9b76c9 100644 --- a/javafmllanguage/build.gradle +++ b/javafmllanguage/build.gradle @@ -1,66 +1,79 @@ -import net.minecraftforge.gradleutils.PomUtils - plugins { id 'java-library' id 'maven-publish' - id 'net.minecraftforge.licenser' - id 'net.minecraftforge.gradleutils' + alias libs.plugins.licenser + alias libs.plugins.gradleutils + alias libs.plugins.gitversion + alias libs.plugins.changelog + id 'net.minecraftforge.forge.build.convention' } -apply from: rootProject.file('build_shared.gradle') - -dependencies { - compileOnly(libs.jetbrains.annotations) - implementation(project(':fmlloader')) - implementation(project(':fmlcore')) - implementation(libs.unsafe) - implementation(libs.securemodules) -} +gradleutils.displayName = 'JavaFMLMod' +final vendor = 'Forge Development LLC' +description = 'Language provider for Minecraft Forge that provides basic Java mod functionality.' java { - toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION) + toolchain.languageVersion = JavaLanguageVersion.of(javaVersion) withSourcesJar() } -tasks.named('jar', Jar).configure { - manifest { - attributes([ - 'Automatic-Module-Name': 'net.minecraftforge.javafmlmod', - 'FMLModType': 'LANGPROVIDER' - ] as LinkedHashMap) - attributes([ - 'Specification-Title': 'JavaFMLMod', - 'Specification-Vendor': 'Forge Development LLC', - 'Specification-Version': '1', - 'Implementation-Title': 'JavaFMLMod', - 'Implementation-Vendor': 'Forge Development LLC', - 'Implementation-Version': FORGE_VERSION - ] as LinkedHashMap, 'net/minecraftforge/fml/javafmlmod/') - } -} - -tasks.withType(JavaCompile).configureEach { - options.compilerArgs << '-Xlint:unchecked' -} - license { header = rootProject.file('LICENSE-header.txt') } -publishing { - publications.register('mavenJava', MavenPublication).configure { - from components.java - artifactId = 'javafmllanguage' - pom { - name = project.name - description = 'Language provider for Minecraft Forge that provides basic java mod functionality' - url = 'https://github.com/MinecraftForge/MinecraftForge' - PomUtils.setGitHubDetails(pom, 'MinecraftForge') - license PomUtils.Licenses.LGPLv2_1 - } - } +changelog { + from changelogBase +} +dependencies { + compileOnly libs.jetbrains.annotations + + implementation projects.fmlloader + implementation projects.fmlcore + implementation libs.unsafe + implementation libs.securemodules +} + +tasks.withType(JavaCompile).configureEach { + options.compilerArgs << '-Xlint:unchecked' +} + +tasks.named('jar', Jar) { + manifest { + attributes([ + 'Automatic-Module-Name': 'net.minecraftforge.javafmlmod', + 'FMLModType' : 'LANGPROVIDER' + ]) + attributes([ + 'Specification-Title' : gradleutils.displayName.get(), + 'Specification-Vendor' : vendor, + 'Specification-Version' : '1', + 'Implementation-Title' : gradleutils.displayName.get(), + 'Implementation-Vendor' : vendor, + 'Implementation-Version': forgeVersion + ], 'net/minecraftforge/fml/javafmlmod/') + } +} + +publishing { repositories { maven gradleutils.publishingForgeMaven } -} + + publications.register('mavenJava', MavenPublication) { + changelog.publish(it) + gradleutils.promote(it) + + from components.java + + pom { + description = project.description + + gradleutils.pom.addRemoteDetails(pom) + + licenses { + license gradleutils.pom.licenses.LGPLv2_1 + } + } + } +} \ No newline at end of file diff --git a/lowcodelanguage/build.gradle b/lowcodelanguage/build.gradle index f4e92d6233..5681135f79 100644 --- a/lowcodelanguage/build.gradle +++ b/lowcodelanguage/build.gradle @@ -1,65 +1,77 @@ -import net.minecraftforge.gradleutils.PomUtils - plugins { id 'java-library' id 'maven-publish' - id 'net.minecraftforge.licenser' - id 'net.minecraftforge.gradleutils' + alias libs.plugins.licenser + alias libs.plugins.gradleutils + alias libs.plugins.gitversion + alias libs.plugins.changelog + id 'net.minecraftforge.forge.build.convention' } -apply from: rootProject.file('build_shared.gradle') +gradleutils.displayName = 'LowCodeMod' +final vendor = 'Forge Development LLC' +description = 'Language provider for Minecraft Forge that loads mods without a Java entrypoint.' java { - toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION) + toolchain.languageVersion = JavaLanguageVersion.of(javaVersion) withSourcesJar() } -dependencies { - compileOnly(libs.jetbrains.annotations) - - implementation(project(':fmlloader')) - implementation(project(':fmlcore')) -} - -tasks.named('jar', Jar).configure { - manifest { - attributes([ - 'Automatic-Module-Name': 'net.minecraftforge.lowcodemod', - 'FMLModType': 'LANGPROVIDER' - ] as LinkedHashMap) - attributes([ - 'Specification-Title': 'LowCodeMod', - 'Specification-Vendor': 'Forge Development LLC', - 'Specification-Version': '1.0', - 'Implementation-Title': project.name, - 'Implementation-Vendor': 'Forge Development LLC', - 'Implementation-Version': FORGE_VERSION.split('\\.')[0] - ] as java.util.LinkedHashMap, 'net/minecraftforge/fml/lowcodemod/') - } -} - -tasks.withType(JavaCompile).configureEach { - options.compilerArgs << '-Xlint:unchecked' -} - license { header = rootProject.file('LICENSE-header.txt') } -publishing { - publications.register('mavenJava', MavenPublication).configure { - from components.java - artifactId = 'lowcodelanguage' - pom { - name = project.name - description = 'Language provider for Minecraft Forge that loads resource packs as mods' - url = 'https://github.com/MinecraftForge/MinecraftForge' - PomUtils.setGitHubDetails(pom, 'MinecraftForge') - license PomUtils.Licenses.LGPLv2_1 - } +changelog { + from changelogBase +} + +dependencies { + compileOnly libs.jetbrains.annotations + + implementation projects.fmlloader + implementation projects.fmlcore +} + +tasks.withType(JavaCompile).configureEach { + options.compilerArgs << '-Xlint:unchecked' +} + +tasks.named('jar', Jar) { + manifest { + attributes([ + 'Automatic-Module-Name': 'net.minecraftforge.lowcodemod', + 'FMLModType' : 'LANGPROVIDER' + ]) + attributes([ + 'Specification-Title' : gradleutils.displayName.get(), + 'Specification-Vendor' : vendor, + 'Specification-Version' : '1.0', + 'Implementation-Title' : project.name, + 'Implementation-Vendor' : vendor, + 'Implementation-Version': forgeVersion.split('\\.')[0] + ], 'net/minecraftforge/fml/lowcodemod/') } - +} + +publishing { repositories { maven gradleutils.publishingForgeMaven } + + publications.register('mavenJava', MavenPublication) { + changelog.publish(it) + gradleutils.promote(it) + + from components.java + + pom { + description = project.description + + gradleutils.pom.addRemoteDetails(pom) + + licenses { + license gradleutils.pom.licenses.LGPLv2_1 + } + } + } } diff --git a/mclanguage/build.gradle b/mclanguage/build.gradle index abf4e79ed2..7e4ed70a54 100644 --- a/mclanguage/build.gradle +++ b/mclanguage/build.gradle @@ -1,64 +1,77 @@ -import net.minecraftforge.gradleutils.PomUtils - plugins { id 'java-library' id 'maven-publish' - id 'net.minecraftforge.licenser' - id 'net.minecraftforge.gradleutils' + alias libs.plugins.licenser + alias libs.plugins.gradleutils + alias libs.plugins.gitversion + alias libs.plugins.changelog + id 'net.minecraftforge.forge.build.convention' } -apply from: rootProject.file('build_shared.gradle') - -dependencies { - compileOnly(libs.jetbrains.annotations) - implementation(project(':fmlloader')) - implementation(project(':fmlcore')) -} +gradleutils.displayName = 'MCLanguage' +final vendor = 'Forge Development LLC' +description = 'Language provider for Minecraft Forge that provides Minecraft Itself.' java { - toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION) + toolchain.languageVersion = JavaLanguageVersion.of(javaVersion) withSourcesJar() } -tasks.named('jar', Jar).configure { - manifest { - attributes([ - 'Automatic-Module-Name': 'net.minecraftforge.mclanguageprovider', - 'FMLModType': 'LANGPROVIDER' - ] as LinkedHashMap) - attributes([ - 'Specification-Title': 'MCLanguage', - 'Specification-Vendor': 'Forge Development LLC', - 'Specification-Version': '1', - 'Implementation-Title': 'MCLanguage', - 'Implementation-Vendor': 'Forge Development LLC', - 'Implementation-Version': '1.0' - ] as LinkedHashMap, 'net/minecraftforge/fml/mclanguageprovider/') - } -} - -tasks.withType(JavaCompile).configureEach { - options.compilerArgs << '-Xlint:unchecked' -} - license { header = rootProject.file('LICENSE-header.txt') } -publishing { - publications.register('mavenJava', MavenPublication).configure { - from components.java - artifactId = 'mclanguage' - pom { - name = project.name - description = 'Language provider for Minecraft Forge that provides Minecraft Itself' - url = 'https://github.com/MinecraftForge/MinecraftForge' - PomUtils.setGitHubDetails(pom, 'MinecraftForge') - license PomUtils.Licenses.LGPLv2_1 - } +changelog { + from changelogBase +} + +dependencies { + compileOnly libs.jetbrains.annotations + + implementation projects.fmlloader + implementation projects.fmlcore +} + +tasks.withType(JavaCompile).configureEach { + options.compilerArgs << '-Xlint:unchecked' +} + +tasks.named('jar', Jar) { + manifest { + attributes([ + 'Automatic-Module-Name': 'net.minecraftforge.mclanguageprovider', + 'FMLModType' : 'LANGPROVIDER' + ]) + attributes([ + 'Specification-Title' : gradleutils.displayName.get(), + 'Specification-Vendor' : vendor, + 'Specification-Version' : '1', + 'Implementation-Title' : gradleutils.displayName.get(), + 'Implementation-Vendor' : vendor, + 'Implementation-Version': '1.0' + ], 'net/minecraftforge/fml/mclanguageprovider/') } - +} + +publishing { repositories { maven gradleutils.publishingForgeMaven } + + publications.register('mavenJava', MavenPublication) { + changelog.publish(it) + gradleutils.promote(it) + + from components.java + + pom { + description = project.description + + gradleutils.pom.addRemoteDetails(pom) + + licenses { + license gradleutils.pom.licenses.LGPLv2_1 + } + } + } } diff --git a/minecraft.versions.toml b/minecraft.versions.toml new file mode 100644 index 0000000000..a2a4d47b43 --- /dev/null +++ b/minecraft.versions.toml @@ -0,0 +1,6 @@ +[versions] +java = "25" +minecraft = "26.2" +minecraft-next = "26.3" +mcp = "20260616.103818" +changelog-base = "65.0" diff --git a/settings.gradle b/settings.gradle index 631180f095..58eb3b195d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,119 +1,34 @@ -pluginManagement { - repositories { - gradlePluginPortal() - //mavenLocal() - maven { url = 'https://maven.minecraftforge.net/' } - } -} +import groovy.transform.Field -buildscript { - dependencies { - classpath('com.google.code.gson:gson') { - version { - strictly '2.11.0' +pluginManagement { + private static final @Field String FORGEDEV_VERSION = '7.0.0-beta.51' + + if (new File('forgedev/settings.gradle').exists()) { + includeBuild 'forgedev' + } else { + resolutionStrategy.eachPlugin { + // TODO [ForgeDev] Consolidate these entry-points + switch (requested.id.id) { + case 'net.minecraftforge.forgedev': + case 'net.minecraftforge.forge.build.convention': + useVersion(FORGEDEV_VERSION) + break } } } + + repositories { + gradlePluginPortal() + maven { url = 'https://maven.minecraftforge.net/' } + //mavenLocal() + } } plugins { id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0' } -dependencyResolutionManagement { - versionCatalogs { - libs { - plugin('apt', 'com.diffplug.eclipse.apt').version('4.2.0') - - library('forgespi', 'net.minecraftforge:forgespi:8.0.0') // Needs modlauncher - library('modlauncher', 'net.minecraftforge:modlauncher:10.2.4') // Needs securemodules - library('securemodules', 'net.minecraftforge:securemodules:2.2.24') // Needs unsafe - library('unsafe', 'net.minecraftforge:unsafe:0.9.2') - library('accesstransformers', 'net.minecraftforge:accesstransformers:8.2.2') - library('coremods-api', 'net.minecraftforge:coremods-api:5.3.0') - version('eventbus', '7.0.1') - library('eventbus', 'net.minecraftforge', 'eventbus').versionRef('eventbus') - library('eventbus-validator', 'net.minecraftforge', 'eventbus-validator').versionRef('eventbus') - library('mergetool-api', 'net.minecraftforge:mergetool-api:1.0') - - library('roimfs', 'net.minecraftforge:roimfs:1.0.0') // ReadOnlyInMemoryFileSystem - Used for JarInJar extraction at runtime - library('mixin', 'org.spongepowered:mixin:0.8.7') - version('mixinextras', '0.5.3') - library('mixinextras-forge', 'io.github.llamalad7', 'mixinextras-forge').versionRef('mixinextras') - library('mixinextras-common', 'io.github.llamalad7', 'mixinextras-common').versionRef('mixinextras') - library('jetbrains-annotations', 'org.jetbrains:annotations:24.1.0') // for ApiStatus annotations - library('jspecify', 'org.jspecify:jspecify:1.0.0') // for nullability annotations - library('slf4j-api', 'org.slf4j:slf4j-api:2.0.7') - library('maven-artifact', 'org.apache.maven:maven-artifact:3.8.8') - - // Google's InMemory File System. Used by ForgeDev Tests for now, but could be useful for a lot of things. - library('jimfs', 'com.google.jimfs:jimfs:1.3.0') - bundle('jimfs', ['guava', 'failureaccess']) - - version('bootstrap', '2.1.8') - library('bootstrap', 'net.minecraftforge', 'bootstrap' ).versionRef('bootstrap') // Needs modlauncher - library('bootstrap-api', 'net.minecraftforge', 'bootstrap-api' ).versionRef('bootstrap') - library('bootstrap-dev', 'net.minecraftforge', 'bootstrap-dev' ).versionRef('bootstrap') - library('bootstrap-shim', 'net.minecraftforge', 'bootstrap-shim').versionRef('bootstrap') - - // ASM it's used for so many of our hacks - version('asm', '9.9.1') - library('asm', 'org.ow2.asm', 'asm' ).versionRef('asm') - library('asm-tree', 'org.ow2.asm', 'asm-tree' ).versionRef('asm') - library('asm-util', 'org.ow2.asm', 'asm-util' ).versionRef('asm') - library('asm-commons', 'org.ow2.asm', 'asm-commons' ).versionRef('asm') - library('asm-analysis', 'org.ow2.asm', 'asm-analysis').versionRef('asm') - bundle('asm', ['asm', 'asm-tree', 'asm-util', 'asm-commons', 'asm-analysis']) - - // Terminal Console Appender.. essentually make pretty colors in the console, but it's been a PITA - library('terminalconsoleappender', 'net.minecrell:terminalconsoleappender:1.2.0') - version('jline', '3.25.1') - library('jline-reader', 'org.jline', 'jline-reader' ).versionRef('jline') - library('jline-terminal', 'org.jline', 'jline-terminal' ).versionRef('jline') - library('jline-terminal-jna', 'org.jline', 'jline-terminal-jna').versionRef('jline') // Colors and tab completeion - bundle('terminalconsoleappender', ['terminalconsoleappender', 'jline-reader', 'jline-terminal', 'jline-terminal-jna']) - - // The core of our configuration system, it has many flaws, but it works for the most part - version('night-config', '3.7.4') - library('night-config-toml', 'com.electronwill.night-config', 'toml').versionRef('night-config') - library('night-config-core', 'com.electronwill.night-config', 'core').versionRef('night-config') - bundle('night-config', ['night-config-toml', 'night-config-core']) - - // Jar in Jar FileSystem - version('jarjar', '0.4.2') - library('jarjar-fs', 'net.minecraftforge', 'JarJarFileSystems').versionRef('jarjar') - library('jarjar-meta', 'net.minecraftforge', 'JarJarMetadata' ).versionRef('jarjar') - library('jarjar-selector', 'net.minecraftforge', 'JarJarSelector' ).versionRef('jarjar') - bundle('jarjar', ['jarjar-fs', 'jarjar-selector', 'jarjar-meta']) - - // These are libraries shipped by the MC launcher, try and keep them in sync with the manifest - // but honestly if we don't it just means we ship them as normal libraries by adding them to the installer config in the forge project - library('gson', 'com.google.code.gson:gson:2.11.0') - library('guava', 'com.google.guava:guava:33.5.0-jre') - library('failureaccess', 'com.google.guava:failureaccess:1.0.3') - - version('log4j', '2.24.3') - library('log4j-api', 'org.apache.logging.log4j', 'log4j-api' ).versionRef('log4j') - library('log4j-core', 'org.apache.logging.log4j', 'log4j-core').versionRef('log4j') - bundle('log4j', ['log4j-api', 'log4j-core']) - - library('apache-commons', 'org.apache.commons:commons-lang3:3.17.0') - library('mojang-logging', 'com.mojang:logging:1.5.10') - library('jopt-simple', 'net.sf.jopt-simple:jopt-simple:5.0.4') - library('commons-io', 'commons-io:commons-io:2.17.0') - - version('lwjgl', '3.4.1') - library('lwjgl', 'org.lwjgl', 'lwjgl' ).versionRef('lwjgl') - library('lwjgl-glfw', 'org.lwjgl', 'lwjgl-glfw' ).versionRef('lwjgl') - library('lwjgl-opengl', 'org.lwjgl', 'lwjgl-opengl').versionRef('lwjgl') - library('lwjgl-stb', 'org.lwjgl', 'lwjgl-stb' ).versionRef('lwjgl') - library('lwjgl-tinyfd', 'org.lwjgl', 'lwjgl-tinyfd').versionRef('lwjgl') - bundle('lwjgl', ['lwjgl', 'lwjgl-glfw', 'lwjgl-opengl', 'lwjgl-stb', 'lwjgl-tinyfd']) - } - } -} - -rootProject.name = 'ForgeRoot' +rootProject.name = 'forge' include 'fmlloader' include 'fmlcore' @@ -123,15 +38,177 @@ include 'lowcodelanguage' include 'fmlearlydisplay' include 'forge-transformers' -include ':mcp' -project(":mcp").projectDir = file("projects/mcp") +enableFeaturePreview 'TYPESAFE_PROJECT_ACCESSORS' -include ':forge' -project(":forge").projectDir = file("projects/forge") -project(':forge').buildFileName = '../../build_forge.gradle' +gradle.beforeProject { Project project -> + project.pluginManager.withPlugin('net.minecraftforge.forge.build.convention') { + // NOTE: We are defining these variables in here so that the projects can stay isolated, increasing build time. + // See minecraft.versions.toml for the versions where you can change these values. + //@formatter:off + project.ext.javaVersion = project.gradleutils.unpack(project.bootLibs.versions.java) + project.ext.minecraftVersion = project.gradleutils.unpack(project.bootLibs.versions.minecraft) + project.version = project.gitversion.getMCTagOffsetBranch(project.ext.minecraftVersion) + project.ext.forgeVersion = project.version.substring(project.ext.minecraftVersion.length() + 1) + project.ext.minecraftNextVersion = project.gradleutils.unpack(project.bootLibs.versions.minecraft.next) + project.ext.mcpVersion = project.gradleutils.unpack(project.bootLibs.versions.mcp) + project.ext.changelogBase = project.gradleutils.unpack(project.bootLibs.versions.changelog.base) + //@formatter:on + } -if (false && !System.env.TEAMCITY_VERSION) { - include ':clean' - project(':clean').projectDir = file('projects/clean') - project(':clean').buildFileName = '../../build_clean.gradle' + // NOTE: We are adding dependencies to projects instead of through settings, so we don't have to apply forgedev in settings. + // Applying forgedev in settings will break IDE linting support, which makes it very hard to work with. + // We can reconsider this if/when switching to Kotlin DSL, or if JetBrains gets their shit together. + project.repositories { + // Libraries has to be before maven central because Mojang hosts a classifer that central doesn't (org.lwjgl:lwjgl-freetype:3.3.3:natives-macos-patch) + maven { url = 'https://libraries.minecraft.net/' } + mavenCentral() + + project.pluginManager.withPlugin('net.minecraftforge.gradleutils') { + maven project.gradleutils.forgeMaven + } + + project.pluginManager.withPlugin('net.minecraftforge.forgedev') { + maven project.forgedev.mavenizer + } + + mavenLocal() + } +} + +dependencyResolutionManagement.versionCatalogs { + register('bootLibs') { + description = 'Important version numbers that are externally declared for easy modification.' + + // Contains Java, Minecraft, and MCP versions + from(files('minecraft.versions.toml')) + } + + register('buildLibs') { + description = 'Libraries used solely during the build and publish process.' + + library 'binarypatcher', 'net.minecraftforge', 'binarypatcher' version '1.3.4' + library 'installer', 'net.minecraftforge', 'installer' version '2.2.+' + library 'installertools', 'net.minecraftforge', 'installertools' version '1.4.5' + library 'renamer', 'net.minecraftforge', 'ForgeAutoRenamingTool' version '1.0.6' + library 'srg2source', 'net.minecraftforge', 'Srg2Source' version '8.2.0' + } + + //@formatter:off + register('libs') { + description = 'Libraries used by Forge and its subprojects.' + + plugin 'licenser', 'net.minecraftforge.licenser' version '1.2.0' + plugin 'versions', 'com.github.ben-manes.versions' version '0.53.0' + plugin 'gradleutils', 'net.minecraftforge.gradleutils' version '3.3.35' + plugin 'gitversion', 'net.minecraftforge.gitversion' version '3.1.7' + plugin 'changelog', 'net.minecraftforge.changelog' version '3.2.2' + plugin 'renamer', 'net.minecraftforge.renamer' version '1.0.16' + plugin 'download', 'de.undercouch.download' version '5.6.0' + plugin 'jarsigner', 'net.minecraftforge.gradlejarsigner' version '1.2.1' + plugin 'apt', 'com.diffplug.eclipse.apt' version '4.4.1' + + // TODO [Forge][Buildscript We should not be needing to manually add transitive dependencies + // If we need to make strict versions for dependencies, we should do so using dependency constraints + library 'forgespi', 'net.minecraftforge', 'forgespi' version '8.0.0' // Needs modlauncher + library 'modlauncher', 'net.minecraftforge', 'modlauncher' version '10.2.4' // Needs securemodules + library 'securemodules', 'net.minecraftforge', 'securemodules' version '2.2.24' // Needs unsafe + library 'unsafe', 'net.minecraftforge', 'unsafe' version '0.9.2' + library 'accesstransformers', 'net.minecraftforge', 'accesstransformers' version '8.2.2' + library 'coremods-api', 'net.minecraftforge', 'coremods-api' version '5.3.0' + version 'eventbus', '7.0.1' + library 'eventbus', 'net.minecraftforge', 'eventbus' versionRef 'eventbus' + library 'eventbus-validator', 'net.minecraftforge', 'eventbus-validator' versionRef 'eventbus' + library 'mergetool-api', 'net.minecraftforge', 'mergetool-api' version '1.0' + + library 'roimfs', 'net.minecraftforge', 'roimfs' version '1.0.0' // ReadOnlyInMemoryFileSystem - Used for JarInJar extraction at runtime + library 'mixin', 'org.spongepowered', 'mixin' version '0.8.7' + version 'mixinextras', '0.5.3' + library 'mixinextras-forge', 'io.github.llamalad7', 'mixinextras-forge' versionRef 'mixinextras' + library 'mixinextras-common', 'io.github.llamalad7', 'mixinextras-common' versionRef 'mixinextras' + library 'jetbrains-annotations', 'org.jetbrains', 'annotations' version '24.1.0' // for ApiStatus annotations + library 'jspecify', 'org.jspecify', 'jspecify' version '1.0.0' // for nullability annotations + library 'slf4j-api', 'org.slf4j', 'slf4j-api' version '2.0.7' + library 'maven-artifact', 'org.apache.maven', 'maven-artifact' version '3.8.8' + + // Google's InMemory File System. Used by ForgeDev Tests for now, but could be useful for a lot of things. + library 'jimfs', 'com.google.jimfs:jimfs:1.3.0' + bundle 'jimfs', ['guava', 'failureaccess'] + + version 'bootstrap', '2.1.8' + library 'bootstrap', 'net.minecraftforge', 'bootstrap' versionRef 'bootstrap' // Needs modlauncher + library 'bootstrap-api', 'net.minecraftforge', 'bootstrap-api' versionRef 'bootstrap' + library 'bootstrap-dev', 'net.minecraftforge', 'bootstrap-dev' versionRef 'bootstrap' + library 'bootstrap-shim', 'net.minecraftforge', 'bootstrap-shim' versionRef 'bootstrap' + + // ASM it's used for so many of our hacks + version 'asm', '9.9.1' + library 'asm', 'org.ow2.asm', 'asm' versionRef 'asm' + library 'asm-tree', 'org.ow2.asm', 'asm-tree' versionRef 'asm' + library 'asm-util', 'org.ow2.asm', 'asm-util' versionRef 'asm' + library 'asm-commons', 'org.ow2.asm', 'asm-commons' versionRef 'asm' + library 'asm-analysis', 'org.ow2.asm', 'asm-analysis' versionRef 'asm' + bundle 'asm', ['asm', 'asm-tree', 'asm-util', 'asm-commons', 'asm-analysis'] + + // Terminal Console Appender. essentially make pretty colors in the console, but it's been a PITA + library 'terminalconsoleappender', 'net.minecrell', 'terminalconsoleappender' version '1.2.0' + version 'jline', '3.25.1' + library 'jline-reader', 'org.jline', 'jline-reader' versionRef 'jline' + library 'jline-terminal', 'org.jline', 'jline-terminal' versionRef 'jline' + library 'jline-terminal-jna', 'org.jline', 'jline-terminal-jna' versionRef 'jline' // Colors and tab completeion + bundle 'terminalconsoleappender', ['terminalconsoleappender', 'jline-reader', 'jline-terminal', 'jline-terminal-jna'] + + // The core of our configuration system, it has many flaws, but it works for the most part + version 'night-config', '3.7.4' + library 'night-config-toml', 'com.electronwill.night-config', 'toml' versionRef 'night-config' + library 'night-config-core', 'com.electronwill.night-config', 'core' versionRef 'night-config' + bundle 'night-config', ['night-config-toml', 'night-config-core'] + + // Jar in Jar FileSystem + version 'jarjar', '0.4.2' + library 'jarjar-fs', 'net.minecraftforge', 'JarJarFileSystems' versionRef 'jarjar' + library 'jarjar-meta', 'net.minecraftforge', 'JarJarMetadata' versionRef 'jarjar' + library 'jarjar-selector', 'net.minecraftforge', 'JarJarSelector' versionRef 'jarjar' + bundle 'jarjar', ['jarjar-fs', 'jarjar-selector', 'jarjar-meta'] + + // These are libraries shipped by the MC launcher, try and keep them in sync with the manifest + // but honestly if we don't it just means we ship them as normal libraries by adding them to the installer config in the forge project + library 'gson', 'com.google.code.gson', 'gson' version '2.11.0' + library 'guava', 'com.google.guava', 'guava' version '33.5.0-jre' + library 'failureaccess', 'com.google.guava', 'failureaccess' version '1.0.3' + + version 'log4j', '2.24.3' + library 'log4j-api', 'org.apache.logging.log4j', 'log4j-api' versionRef 'log4j' + library 'log4j-core', 'org.apache.logging.log4j', 'log4j-core' versionRef 'log4j' + bundle 'log4j', ['log4j-api', 'log4j-core'] + + library 'apache-commons', 'org.apache.commons', 'commons-lang3' version '3.17.0' + library 'mojang-logging', 'com.mojang', 'logging' version '1.5.10' + library 'jopt-simple', 'net.sf.jopt-simple', 'jopt-simple' version '5.0.4' + library 'commons-io', 'commons-io', 'commons-io' version '2.17.0' + + version 'lwjgl', '3.4.1' + library 'lwjgl', 'org.lwjgl', 'lwjgl' versionRef 'lwjgl' + library 'lwjgl-glfw', 'org.lwjgl', 'lwjgl-glfw' versionRef 'lwjgl' + library 'lwjgl-opengl', 'org.lwjgl', 'lwjgl-opengl' versionRef 'lwjgl' + library 'lwjgl-stb', 'org.lwjgl', 'lwjgl-stb' versionRef 'lwjgl' + library 'lwjgl-tinyfd', 'org.lwjgl', 'lwjgl-tinyfd' versionRef 'lwjgl' + bundle 'lwjgl', ['lwjgl', 'lwjgl-glfw', 'lwjgl-opengl', 'lwjgl-stb', 'lwjgl-tinyfd'] + } + + register('earlyDisplayLibs') { + version 'slf4j', '1.8.0-beta4' + library 'slf4j-api', 'org.slf4j', 'slf4j-api' versionRef 'slf4j' + library 'slf4j-jdk14', 'org.slf4j', 'slf4j-jdk14' versionRef 'slf4j' + } + + register('earlyDisplayTestLibs') { + library 'powermock-core', 'org.powermock', 'powermock-core' version '2.0.9' + + library 'lwjgl', 'org.lwjgl', 'lwjgl' withoutVersion() + library 'lwjgl-glfw', 'org.lwjgl', 'lwjgl-glfw' withoutVersion() + library 'lwjgl-opengl', 'org.lwjgl', 'lwjgl-opengl' withoutVersion() + library 'lwjgl-stb', 'org.lwjgl', 'lwjgl-stb' withoutVersion() + bundle 'lwjgl', ['lwjgl', 'lwjgl-glfw', 'lwjgl-opengl', 'lwjgl-stb'] + } + //@formatter:on }