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