From b13edf5bee0543744fef9baf67e66e4d8144b3cd Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sun, 13 Oct 2024 01:11:25 +0200 Subject: [PATCH 01/24] Add legacy support for Forge 1.17 to 1.20.1 Co-authored-by: Matyrobbrt <65940752+matyrobbrt@users.noreply.github.com> --- .github/workflows/build-prs.yml | 9 +- LEGACY.md | 100 +++++++ build.gradle | 31 +-- gradle/wrapper/gradle-wrapper.jar | Bin 43504 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 0 legacytest/.gitignore | 3 + legacytest/build.gradle | 41 +++ legacytest/forge/build.gradle | 49 ++++ .../forge/src/main/java/mymod/JeiCompat.java | 20 ++ .../forge/src/main/java/mymod/MyMod.java | 9 + .../src/main/resources/META-INF/mods.toml | 12 + legacytest/gradle.properties | 1 + legacytest/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + legacytest/gradlew | 249 ++++++++++++++++++ legacytest/gradlew.bat | 92 +++++++ legacytest/settings.gradle | 4 + .../src/main/java/legacytest/LegacyTest.java | 19 ++ .../moddevgradle/boot/LegacyModDevPlugin.java | 9 + .../moddevgradle/internal/LegacyInternal.java | 10 + .../legacy/LegacyForgeMetadataTransform.java | 106 ++++++++ .../legacy/LegacyMetadataTransform.java | 52 ++++ .../legacy/LegacyModDevPlugin.java | 135 ++++++++++ .../legacy/McpMetadataTransform.java | 88 +++++++ .../moddevgradle/legacy/MixinExtension.java | 91 +++++++ .../moddevgradle/legacy/Obfuscation.java | 111 ++++++++ .../moddevgradle/legacy/RemapJarTask.java | 46 ++++ .../moddevgradle/legacy/RemapParameters.java | 94 +++++++ .../legacy/RemappingTransform.java | 65 +++++ .../moddevgradle/dsl/NeoForgeExtension.java | 25 +- .../internal/EclipseIntegration.java | 5 +- .../internal/IntelliJIntegration.java | 6 +- .../moddevgradle/internal/ModDevPlugin.java | 40 ++- .../moddevgradle/internal/RunUtils.java | 43 ++- .../moddevgradle/internal/UserDevConfig.java | 22 ++ .../internal/VsCodeIntegration.java | 4 +- .../nfrtgradle/NeoFormRuntimeExtension.java | 2 +- testproject/gradle/wrapper/gradle-wrapper.jar | Bin 43504 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 +- testproject/oldneo/build.gradle | 8 + testproject/settings.gradle | 1 + 42 files changed, 1559 insertions(+), 54 deletions(-) create mode 100644 LEGACY.md mode change 100644 => 100755 gradlew create mode 100644 legacytest/.gitignore create mode 100644 legacytest/build.gradle create mode 100644 legacytest/forge/build.gradle create mode 100644 legacytest/forge/src/main/java/mymod/JeiCompat.java create mode 100644 legacytest/forge/src/main/java/mymod/MyMod.java create mode 100644 legacytest/forge/src/main/resources/META-INF/mods.toml create mode 100644 legacytest/gradle.properties create mode 100644 legacytest/gradle/wrapper/gradle-wrapper.jar create mode 100644 legacytest/gradle/wrapper/gradle-wrapper.properties create mode 100755 legacytest/gradlew create mode 100644 legacytest/gradlew.bat create mode 100644 legacytest/settings.gradle create mode 100644 legacytest/src/main/java/legacytest/LegacyTest.java create mode 100644 src/java8/java/net/neoforged/moddevgradle/boot/LegacyModDevPlugin.java create mode 100644 src/legacy/java/net/neoforged/moddevgradle/internal/LegacyInternal.java create mode 100644 src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyForgeMetadataTransform.java create mode 100644 src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyMetadataTransform.java create mode 100644 src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyModDevPlugin.java create mode 100644 src/legacy/java/net/neoforged/moddevgradle/legacy/McpMetadataTransform.java create mode 100644 src/legacy/java/net/neoforged/moddevgradle/legacy/MixinExtension.java create mode 100644 src/legacy/java/net/neoforged/moddevgradle/legacy/Obfuscation.java create mode 100644 src/legacy/java/net/neoforged/moddevgradle/legacy/RemapJarTask.java create mode 100644 src/legacy/java/net/neoforged/moddevgradle/legacy/RemapParameters.java create mode 100644 src/legacy/java/net/neoforged/moddevgradle/legacy/RemappingTransform.java create mode 100644 testproject/oldneo/build.gradle diff --git a/.github/workflows/build-prs.yml b/.github/workflows/build-prs.yml index 681bd716..21e4db2c 100644 --- a/.github/workflows/build-prs.yml +++ b/.github/workflows/build-prs.yml @@ -28,8 +28,9 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] + project: [testproject, legacytest] runs-on: ${{ matrix.os }} - name: Test on ${{ matrix.os }} + name: Test ${{ matrix.project }} on ${{ matrix.os }} steps: - name: Checkout project sources uses: actions/checkout@v4 @@ -47,12 +48,12 @@ jobs: - name: Run build run: ./gradlew build neoForgeIdeSync - working-directory: ./testproject + working-directory: ./${{ matrix.project }} - name: Ensure clean, build and test work in the same run run: ./gradlew clean build check - working-directory: ./testproject + working-directory: ./${{ matrix.project }} - name: Ensure runData runs run: ./gradlew runData - working-directory: ./testproject + working-directory: ./${{ matrix.project }} diff --git a/LEGACY.md b/LEGACY.md new file mode 100644 index 00000000..a1459c1f --- /dev/null +++ b/LEGACY.md @@ -0,0 +1,100 @@ +# ModDevGradle Legacy Plugin +ModDevGradle has a secondary plugin (ID: `net.neoforged.moddevgradle.legacy`, released alongside the normal plugin with the same version) +that adds support for developing mods against MinecraftForge and Vanilla Minecraft versions 1.17 up to 1.20.1. + +The legacy plugin is an "addon" plugin, meaning it operates on top of the normal plugin. This means that the APIs normally used +are also available when using the legacy plugin. + +## Basic Usage for MinecraftForge Mods +An example `build.gradle` file for developing a mod against MinecraftForge for 1.20.1 is provided below: +```groovy +plugins { + // Apply the plugin. You can find the latest version at https://projects.neoforged.net/neoforged/ModDevGradle + id 'net.neoforged.moddev.legacy' version '2.0.28-beta' +} + +neoForge { + // Develop against MinecraftForge version 47.3.0 for 1.20.1 (the versions can be found at https://files.minecraftforge.net/) + version = "1.20.1-47.3.0" + + // Validate AT files and raise errors when they have invalid targets + // This option is false by default, but turning it on is recommended + validateAccessTransformers = true + + runs { + client { + client() + } + data { + data() + } + server { + server() + } + } + + mods { + testproject { + sourceSet sourceSets.main + } + } +} +``` + +## Reobfuscating artifacts +Forge used SRG mappings as intermediary mappings in 1.20.1 and below. While your mod is developed against the mappings provided +by Mojang (known as official mappings), you need to reobfuscate it to SRG mappings for it to work in production. +Reobfuscation will automatically be configured for the `jar` task; the non-obfuscated jar will have a `-dev` classifier +and will not be published in favour of the reobfuscated variant. You should upload the `reobfJar` task's output when using a +task to upload to a mod hosting platform, or otherwise the jar without a `-dev` classifier if you're uploading it manually. + +You may reobfuscate other jar tasks using `obfuscation.reobfuscate(TaskProvider, SourceSet, Action)`. +For instance, if you want to reobfuscate a `shadowJar` task: +```groovy +shadowJar { + // Change the classifier of the shadow jar to be -dev-all as it's not mapped in intermediary and not usable for production + archiveClassifier = 'dev-all' +} + +obfuscation { + // Reobfuscate the shadowJar task, using the classpath of the main sourceset for properly remapping inherited members + reobfuscate(tasks.named('shadowJar'), sourceSets.main) { + // Make the reobfuscated shadowJar have the all classifier + // You could also change it to an empty string if you want it to not have a classifier (in that case, you will also need to change the classifier of the slim `reobfJar` task + archiveClassifier = 'all' + } +} +``` + +When reobfuscating a jar, it will be replaced in publications with the obfuscated version to avoid publishing jars that aren't mapped to SRG. + +## Remapping mod dependencies +As published mods are using intermediary mappings, you must remap them to official mappings before being able to use them as a dependencies. +ModDevGradle creates configurations that will automatically remap dependencies added to them from SRG mappings to official mappings. +The following configurations are created automatically and are children of the configurations without the `mod` prefix: +- `modImplementation` +- `modRuntimeOnly` +- `modCompileOnly` +- `modApi` (only if the `java-library` plugin is applied) +- `modCompileOnlyApi` (only if the `java-library` plugin is applied) + +You may create your own remapping configurations using `obfuscation.createRemappingConfiguration(Configuration)`: +```groovy +configurations { + // Create a custom configuration named "custom" + custom +} + +obfuscation { + // Create a configuration named "modCustom" that remaps its dependencies and then adds them to the "custom" configuration + createRemappingConfiguration(configurations.custom) +} +``` + +## Effects of applying the legacy plugin +When applied, the legacy plugin will change the base NeoForm and NeoForge artifact coordinates of the `neoForge` extension to +`de.oceanlabs.mcp:mcp_config` and `net.minecraftforge:forge`. +It will also trigger the creation of various intermediary (SRG) to named (official) mapping files used by various parts of the toolchain, such as +mod reobfuscation and runtime naming services. +Reobfuscation to the intermediary mappings will automatically be configured for the `jar` task, the non-obfuscated jar will have a `-dev` classifier +and will not be published in favour of the reobfuscated variant. diff --git a/build.gradle b/build.gradle index a6f51f7a..9d9b59e6 100644 --- a/build.gradle +++ b/build.gradle @@ -70,6 +70,7 @@ sourceSets { compileClasspath += java8.output runtimeClasspath += java8.output } + legacy } configurations { @@ -77,6 +78,7 @@ configurations { shaded // Place shaded dependencies into `compileOnly` so that they do not leak into our publications' dependencies. compileOnly.extendsFrom shaded + legacyCompileOnly.extendsFrom shaded testCompileOnly.extendsFrom shaded testRuntimeOnly.extendsFrom shaded shadowRuntimeElements { @@ -123,6 +125,10 @@ dependencies { testImplementation gradleTestKit() testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + legacyImplementation(sourceSets.main.output) + legacyImplementation(sourceSets.java8.output) + legacyImplementation gradleApi() } java { @@ -135,12 +141,14 @@ java { jar { archiveClassifier = 'slim' from sourceSets.java8.output + from sourceSets.legacy.output } shadowJar { archiveClassifier = "" // Required for the Plugin Publish Plugin to publish this jar from sourceSets.java8.output + from sourceSets.legacy.output configurations = [project.configurations.shaded] enableRelocation = true @@ -188,6 +196,13 @@ gradlePlugin { description = "This plugin helps you create Minecraft mods using the NeoForge platform" tags = ["minecraft", "neoforge", "java", "mod"] } + legacy { + id = 'net.neoforged.moddev.legacy' + implementationClass = 'net.neoforged.moddevgradle.boot.LegacyModDevPlugin' + displayName = "NeoForge Legacy Mod Development Plugin" + description = "This plugin helps you create Minecraft mods using the Forge platform, up to 1.20.1" + tags = ["minecraft", "neoforge", "forge", "java", "mod"] + } repositories { id = 'net.neoforged.moddev.repositories' implementationClass = 'net.neoforged.moddevgradle.boot.RepositoriesPlugin' @@ -212,21 +227,7 @@ artifacts { publishing { repositories { - maven { - name = 'NeoForge' - if (System.getenv('MAVEN_USER') && System.getenv('MAVEN_PASSWORD')) { - it.url = "https://maven.neoforged.net/releases/" - it.authentication { - it.create('basic', BasicAuthentication) - } - it.credentials { credentials -> - credentials.username = System.getenv('MAVEN_USER') - credentials.password = System.getenv('MAVEN_PASSWORD') - } - } else { - it.url = 'file://' + file("repo").getAbsolutePath() - } - } + maven(gradleutils.publishingMaven) } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 2c3521197d7c4586c843d1d3e9090525f1898cde..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 3990 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index dedd5d1e..9355b415 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.9-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/legacytest/.gitignore b/legacytest/.gitignore new file mode 100644 index 00000000..fd4afddd --- /dev/null +++ b/legacytest/.gitignore @@ -0,0 +1,3 @@ +run/ +repo/ +*.log diff --git a/legacytest/build.gradle b/legacytest/build.gradle new file mode 100644 index 00000000..12e2ef4e --- /dev/null +++ b/legacytest/build.gradle @@ -0,0 +1,41 @@ +plugins { + id 'maven-publish' + id 'net.neoforged.moddev.legacy' +} + +group = 'com.example.legacy' +version = '1.0.0' + +repositories { + mavenLocal() + maven { + name 'cursemaven' + url 'https://cursemaven.com' + content { + includeGroup "curse.maven" + } + } +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +neoForge { + neoFormVersion = '1.19.2' +} + +publishing { + publications { + maven(MavenPublication) { + from components.java + } + } + repositories { + maven { + url file('local') + } + } +} diff --git a/legacytest/forge/build.gradle b/legacytest/forge/build.gradle new file mode 100644 index 00000000..fe40c6ac --- /dev/null +++ b/legacytest/forge/build.gradle @@ -0,0 +1,49 @@ +plugins { + id 'net.neoforged.moddev.legacy' +} + +repositories { + mavenLocal() + maven { + name = "Jared's maven" + url = "https://maven.blamejared.com/" + } + maven { + name 'cursemaven' + url 'https://cursemaven.com' + content { + includeGroup "curse.maven" + } + } +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +dependencies { + modCompileOnly('mezz.jei:jei-1.20.1-forge:15.17.0.76') { + transitive = false + } + modRuntimeOnly('curse.maven:mekanism-268560:5662583') + modImplementation('curse.maven:applied-energistics-2-223794:5641282') +} + +neoForge { + version = '1.20.1-47.3.0' + runs { + client { + client() + } + data { + data() + } + } + mods { + myMod { + sourceSet(sourceSets.main) + } + } +} diff --git a/legacytest/forge/src/main/java/mymod/JeiCompat.java b/legacytest/forge/src/main/java/mymod/JeiCompat.java new file mode 100644 index 00000000..36fc21e3 --- /dev/null +++ b/legacytest/forge/src/main/java/mymod/JeiCompat.java @@ -0,0 +1,20 @@ +package mymod; + +import mezz.jei.api.IModPlugin; +import mezz.jei.api.JeiPlugin; +import mezz.jei.api.registration.ISubtypeRegistration; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Items; + +@JeiPlugin +public class JeiCompat implements IModPlugin { + @Override + public ResourceLocation getPluginUid() { + return new ResourceLocation("mymod:mymod"); + } + + @Override + public void registerItemSubtypes(ISubtypeRegistration registration) { + registration.registerSubtypeInterpreter(Items.ALLIUM, (ingredient, context) -> "allium"); + } +} diff --git a/legacytest/forge/src/main/java/mymod/MyMod.java b/legacytest/forge/src/main/java/mymod/MyMod.java new file mode 100644 index 00000000..c62f187e --- /dev/null +++ b/legacytest/forge/src/main/java/mymod/MyMod.java @@ -0,0 +1,9 @@ +package mymod; + +import net.minecraftforge.fml.common.Mod; + +@Mod("mymod") +public class MyMod { + public void run() { + } +} diff --git a/legacytest/forge/src/main/resources/META-INF/mods.toml b/legacytest/forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 00000000..0843d268 --- /dev/null +++ b/legacytest/forge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,12 @@ +modLoader="javafml" #mandatory +loaderVersion="*" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. +license="ARR" +[[mods]] #mandatory +# The modid of the mod +modId="mymod" #mandatory +# The version number of the mod +version="1.0" #mandatory +# A display name for the mod +displayName="My Mod" #mandatory +authors="MDG" #optional +description='''Hi.''' diff --git a/legacytest/gradle.properties b/legacytest/gradle.properties new file mode 100644 index 00000000..5ad69748 --- /dev/null +++ b/legacytest/gradle.properties @@ -0,0 +1 @@ +org.gradle.configuration-cache=true diff --git a/legacytest/gradle/wrapper/gradle-wrapper.jar b/legacytest/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/legacytest/gradle/wrapper/gradle-wrapper.properties b/legacytest/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..66cd5a0e --- /dev/null +++ b/legacytest/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-all.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/legacytest/gradlew b/legacytest/gradlew new file mode 100755 index 00000000..1aa94a42 --- /dev/null +++ b/legacytest/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# 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 + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, 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 \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/legacytest/gradlew.bat b/legacytest/gradlew.bat new file mode 100644 index 00000000..93e3f59f --- /dev/null +++ b/legacytest/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +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 %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/legacytest/settings.gradle b/legacytest/settings.gradle new file mode 100644 index 00000000..31c788ef --- /dev/null +++ b/legacytest/settings.gradle @@ -0,0 +1,4 @@ + +includeBuild '..' + +include 'forge' diff --git a/legacytest/src/main/java/legacytest/LegacyTest.java b/legacytest/src/main/java/legacytest/LegacyTest.java new file mode 100644 index 00000000..1496c7e1 --- /dev/null +++ b/legacytest/src/main/java/legacytest/LegacyTest.java @@ -0,0 +1,19 @@ +package legacytest; + +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.DetectedVersion; +import net.minecraft.client.main.Main; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +public class LegacyTest { + public static void main(String[] args) { + System.out.println(DetectedVersion.tryDetectVersion()); + Main.main(new String[]{ + + }); + + System.out.println(new ItemStack(Items.ACACIA_LEAVES).getCount()); + RenderSystem.disableBlend(); + } +} diff --git a/src/java8/java/net/neoforged/moddevgradle/boot/LegacyModDevPlugin.java b/src/java8/java/net/neoforged/moddevgradle/boot/LegacyModDevPlugin.java new file mode 100644 index 00000000..e8fd0f65 --- /dev/null +++ b/src/java8/java/net/neoforged/moddevgradle/boot/LegacyModDevPlugin.java @@ -0,0 +1,9 @@ +package net.neoforged.moddevgradle.boot; + +import org.gradle.api.Project; + +public class LegacyModDevPlugin extends TrampolinePlugin { + public LegacyModDevPlugin() { + super("net.neoforged.moddevgradle.legacy.LegacyModDevPlugin"); + } +} diff --git a/src/legacy/java/net/neoforged/moddevgradle/internal/LegacyInternal.java b/src/legacy/java/net/neoforged/moddevgradle/internal/LegacyInternal.java new file mode 100644 index 00000000..60bc8f0c --- /dev/null +++ b/src/legacy/java/net/neoforged/moddevgradle/internal/LegacyInternal.java @@ -0,0 +1,10 @@ +package net.neoforged.moddevgradle.internal; + +import net.neoforged.moddevgradle.dsl.RunModel; +import org.gradle.api.Project; + +public class LegacyInternal { + public static void configureRun(Project project, RunModel run) { + run.getEnvironment().put("MOD_CLASSES", RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null).getClassesArgument()); + } +} diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyForgeMetadataTransform.java b/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyForgeMetadataTransform.java new file mode 100644 index 00000000..427981c1 --- /dev/null +++ b/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyForgeMetadataTransform.java @@ -0,0 +1,106 @@ +package net.neoforged.moddevgradle.legacy; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.gradle.api.Action; +import org.gradle.api.artifacts.ComponentMetadataContext; +import org.gradle.api.artifacts.DirectDependenciesMetadata; +import org.gradle.api.artifacts.DirectDependencyMetadata; +import org.gradle.api.artifacts.MutableVariantFilesMetadata; +import org.gradle.api.artifacts.repositories.RepositoryResourceAccessor; +import org.gradle.api.attributes.Bundling; +import org.gradle.api.attributes.Category; +import org.gradle.api.attributes.Usage; +import org.gradle.api.model.ObjectFactory; + +import javax.inject.Inject; + +// @CacheableTransform +class LegacyForgeMetadataTransform extends LegacyMetadataTransform { + @Inject + public LegacyForgeMetadataTransform(ObjectFactory objects, RepositoryResourceAccessor repositoryResourceAccessor) { + super(objects, repositoryResourceAccessor); + } + + @Override + public void execute(ComponentMetadataContext context) { + executeWithConfig(context, createPath(context, "userdev", "jar")); + } + + @Override + public void adaptWithConfig(ComponentMetadataContext context, JsonObject config) { + var details = context.getDetails(); + var id = details.getId(); + + var userdevJarName = id.getName() + "-" + id.getVersion() + "-userdev.jar"; + + Action vanillaDependencies = deps -> { + deps.add("de.oceanlabs.mcp:mcp_config:" + id.getVersion().split("-")[0]); + deps.add("net.neoforged:minecraft-dependencies:" + id.getVersion().split("-")[0]); + }; + + details.addVariant("modDevConfig", variantMetadata -> { + variantMetadata.withFiles(metadata -> metadata.addFile(userdevJarName, userdevJarName)); + variantMetadata.withCapabilities(capabilities -> { + capabilities.addCapability("net.neoforged", "neoforge-moddev-config", id.getVersion()); + }); + }); + details.addVariant("modDevBundle", variantMetadata -> { + variantMetadata.withFiles(metadata -> metadata.addFile(userdevJarName, userdevJarName)); + variantMetadata.withDependencies(vanillaDependencies); + variantMetadata.withCapabilities(capabilities -> { + capabilities.addCapability("net.neoforged", "neoforge-moddev-bundle", id.getVersion()); + }); + }); + details.addVariant("modDevModulePath", variantMetadata -> { + variantMetadata.withDependencies(dependencies -> { + var modules = config.getAsJsonArray("modules"); + for (JsonElement module : modules) { + dependencies.add(module.getAsString()); + } + }); + variantMetadata.withCapabilities(capabilities -> { + capabilities.addCapability("net.neoforged", "neoforge-moddev-module-path", id.getVersion()); + }); + }); + details.addVariant("modDevApiElements", variantMetadata -> { + variantMetadata.attributes(attributes -> { + attributes.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.class, Category.LIBRARY)); + attributes.attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.class, Bundling.EXTERNAL)); + attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.class, Usage.JAVA_API)); + }); + variantMetadata.withDependencies(dependencies -> { + var libraries = config.getAsJsonArray("libraries"); + for (JsonElement library : libraries) { + dependencies.add(library.getAsString()); + } + }); + variantMetadata.withDependencies(vanillaDependencies); + variantMetadata.withCapabilities(capabilities -> { + capabilities.addCapability("net.neoforged", "neoforge-dependencies", id.getVersion()); + }); + }); + details.withVariant("runtime", variantMetadata -> { + variantMetadata.attributes(attributes -> { + attributes.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.class, Category.LIBRARY)); + attributes.attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.class, Bundling.EXTERNAL)); + attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.class, Usage.JAVA_RUNTIME)); + }); + variantMetadata.withCapabilities(capabilities -> { + capabilities.addCapability("net.neoforged", "neoforge-dependencies", id.getVersion()); + }); + variantMetadata.withDependencies(vanillaDependencies); + variantMetadata.withFiles(MutableVariantFilesMetadata::removeAllFiles); + variantMetadata.withDependencies(dependencies -> { + var modules = config.getAsJsonArray("modules"); + for (JsonElement module : modules) { + dependencies.add(module.getAsString()); + } + var libraries = config.getAsJsonArray("libraries"); + for (JsonElement library : libraries) { + dependencies.add(library.getAsString()); + } + }); + }); + } +} diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyMetadataTransform.java b/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyMetadataTransform.java new file mode 100644 index 00000000..34e44fad --- /dev/null +++ b/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyMetadataTransform.java @@ -0,0 +1,52 @@ +package net.neoforged.moddevgradle.legacy; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import org.gradle.api.GradleException; +import org.gradle.api.artifacts.ComponentMetadataContext; +import org.gradle.api.artifacts.ComponentMetadataRule; +import org.gradle.api.artifacts.repositories.RepositoryResourceAccessor; +import org.gradle.api.model.ObjectFactory; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.jar.JarInputStream; + +abstract class LegacyMetadataTransform implements ComponentMetadataRule { + protected final ObjectFactory objects; + private final RepositoryResourceAccessor repositoryResourceAccessor; + + LegacyMetadataTransform(ObjectFactory objects, RepositoryResourceAccessor repositoryResourceAccessor) { + this.objects = objects; + this.repositoryResourceAccessor = repositoryResourceAccessor; + } + + protected final void executeWithConfig(ComponentMetadataContext context, String path) { + JsonObject[] configRootHolder = new JsonObject[1]; + repositoryResourceAccessor.withResource(path, inputStream -> { + try (var zin = new JarInputStream(new BufferedInputStream(inputStream))) { + for (var entry = zin.getNextJarEntry(); entry != null; entry = zin.getNextJarEntry()) { + if (entry.getName().equals("config.json")) { + var configJson = new String(zin.readAllBytes(), StandardCharsets.UTF_8); + configRootHolder[0] = new Gson().fromJson(configJson, JsonObject.class); + } + } + } catch (IOException e) { + throw new GradleException("Failed to read " + path); + } + }); + + if (configRootHolder[0] == null) { + throw new GradleException("Couldn't find config.json in " + path); + } + adaptWithConfig(context, configRootHolder[0]); + } + + protected abstract void adaptWithConfig(ComponentMetadataContext context, JsonObject config); + + protected final String createPath(ComponentMetadataContext context, String classifier, String extension) { + var id = context.getDetails().getId(); + return id.getGroup().replace('.', '/') + "/" + id.getName() + "/" + id.getVersion() + "/" + (id.getName() + "-" + id.getVersion() + (classifier.isBlank() ? "" : "-" + classifier) + "." + extension); + } +} diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyModDevPlugin.java b/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyModDevPlugin.java new file mode 100644 index 00000000..89a0b94d --- /dev/null +++ b/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyModDevPlugin.java @@ -0,0 +1,135 @@ +package net.neoforged.moddevgradle.legacy; + +import net.neoforged.moddevgradle.dsl.NeoForgeExtension; +import net.neoforged.moddevgradle.internal.LegacyInternal; +import net.neoforged.moddevgradle.internal.ModDevPlugin; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.artifacts.type.ArtifactTypeDefinition; +import org.gradle.api.attributes.Attribute; +import org.gradle.api.file.RegularFile; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceSetContainer; +import org.gradle.jvm.tasks.Jar; + +import java.net.URI; +import java.util.Map; +import java.util.stream.Stream; + +public class LegacyModDevPlugin implements Plugin { + public static final Attribute REMAPPED = Attribute.of("net.neoforged.moddevgradle.legacy.remapped", Boolean.class); + + @Override + public void apply(Project project) { + project.getPlugins().apply(ModDevPlugin.class); + + project.getRepositories().maven(repo -> { + repo.setName("MinecraftForge"); + repo.setUrl(URI.create("https://maven.minecraftforge.net/")); + }); + + project.getDependencies().getComponents().withModule("net.neoforged:forge", LegacyForgeMetadataTransform.class); + project.getDependencies().getComponents().withModule("net.minecraftforge:forge", LegacyForgeMetadataTransform.class); + project.getDependencies().getComponents().withModule("de.oceanlabs.mcp:mcp_config", McpMetadataTransform.class); + + var depFactory = project.getDependencyFactory(); + var autoRenamingToolRuntime = project.getConfigurations().create("autoRenamingToolRuntime", spec -> { + spec.setDescription("The AutoRenamingTool CLI tool"); + spec.setCanBeConsumed(false); + spec.setCanBeResolved(true); + spec.setTransitive(false); + spec.defaultDependencies(dependencies -> dependencies.add(depFactory.create("net.neoforged:AutoRenamingTool:2.0.4:all"))); + }); + var installerToolsRuntime = project.getConfigurations().create("installerToolsRuntime", spec -> { + spec.setDescription("The InstallerTools CLI tool"); + spec.setCanBeConsumed(false); + spec.setCanBeResolved(true); + spec.setTransitive(false); + spec.defaultDependencies(dependencies -> dependencies.add(depFactory.create("net.neoforged.installertools:installertools:2.1.7:fatjar"))); + }); + + // We use this directory to store intermediate files used during moddev + var modDevBuildDir = project.getLayout().getBuildDirectory().dir("moddev"); + var namedToIntermediate = modDevBuildDir.map(d -> d.file("namedToIntermediate.tsrg")); + var intermediateToNamed = modDevBuildDir.map(d -> d.file("intermediateToNamed.srg")); + var mappingsCsv = modDevBuildDir.map(d -> d.file("intermediateToNamed.zip")); + + var obf = project.getExtensions().create("obfuscation", Obfuscation.class, project, namedToIntermediate, mappingsCsv, autoRenamingToolRuntime, installerToolsRuntime); + var mixin = project.getExtensions().create("mixin", MixinExtension.class, project, namedToIntermediate); + + project.getExtensions().configure(NeoForgeExtension.class, extension -> { + extension.getNeoForgeArtifact().set(extension.getVersion().map(version -> "net.minecraftforge:forge:" + version)); + extension.getNeoFormArtifact().set(extension.getNeoFormVersion().map(version -> "de.oceanlabs.mcp:mcp_config:" + version)); + + extension.getAdditionalMinecraftArtifacts().put("namedToIntermediaryMapping", namedToIntermediate.map(RegularFile::getAsFile)); + extension.getAdditionalMinecraftArtifacts().put("intermediaryToNamedMapping", intermediateToNamed.map(RegularFile::getAsFile)); + extension.getAdditionalMinecraftArtifacts().put("csvMapping", mappingsCsv.map(RegularFile::getAsFile)); + + extension.getRuns().configureEach(run -> { + LegacyInternal.configureRun(project, run); + + // Mixin needs the intermediate (SRG) -> named (Mojang, MCP) mapping file in SRG (TSRG is not supported) to be able to ignore the refmaps of dependencies + run.getSystemProperties().put("mixin.env.remapRefMap", "true"); + run.getSystemProperties().put("mixin.env.refMapRemappingFile", intermediateToNamed.map(f -> f.getAsFile().getAbsolutePath())); + + run.getProgramArguments().addAll(mixin.getConfigs().map(cfgs -> cfgs.stream().flatMap(config -> Stream.of("--mixin.config", config)).toList())); + }); + }); + + var reobfJar = obf.reobfuscate( + project.getTasks().named(JavaPlugin.JAR_TASK_NAME, Jar.class), + project.getExtensions().getByType(SourceSetContainer.class).getByName(SourceSet.MAIN_SOURCE_SET_NAME), + remapJarTask -> remapJarTask.getArchiveClassifier().set("") + ); + + project.getTasks().named(JavaPlugin.JAR_TASK_NAME, Jar.class).configure(jar -> jar.getArchiveClassifier().set("dev")); + project.getTasks().named("assemble", assemble -> assemble.dependsOn(reobfJar)); + + // Forge expects the mapping csv files on the root classpath + project.getConfigurations().getByName(ModDevPlugin.CONFIGURATION_RUNTIME_DEPENDENCIES) + .getDependencies().add(project.getDependencyFactory().create(project.files(mappingsCsv))); + + // Forge expects to find the Forge and client-extra jar on the legacy classpath + project.getConfigurations().getByName("additionalRuntimeClasspath") + .extendsFrom(project.getConfigurations().getByName(ModDevPlugin.CONFIGURATION_RUNTIME_DEPENDENCIES)) + .exclude(Map.of("group", "net.neoforged", "module", "DevLaunch")); + + project.getDependencies().attributesSchema(schema -> schema.attribute(REMAPPED)); + project.getDependencies().getArtifactTypes().named("jar", a -> a.getAttributes().attribute(REMAPPED, false)); + + var remapDeps = project.getConfigurations().create("remappingDependencies", spec -> { + spec.setDescription("An internal configuration that contains the Minecraft dependencies, used for remapping mods"); + spec.setCanBeConsumed(false); + spec.setCanBeDeclared(false); + spec.setCanBeResolved(true); + spec.extendsFrom(project.getConfigurations().getByName(ModDevPlugin.CONFIGURATION_RUNTIME_DEPENDENCIES)); + }); + + project.getDependencies().registerTransform(RemappingTransform.class, params -> { + params.parameters(parameters -> { + parameters.getParameters().set(project.provider(() -> { + var p = project.getObjects().newInstance(RemapParameters.class); + p.from(obf, RemapParameters.ToolType.INSTALLER_TOOLS); + return p; + })); + parameters.getMinecraftDependencies().from(remapDeps); + }); + params.getFrom() + .attribute(REMAPPED, false) + .attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, ArtifactTypeDefinition.JAR_TYPE); + params.getTo() + .attribute(REMAPPED, true) + .attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, ArtifactTypeDefinition.JAR_TYPE); + }); + + obf.createRemappingConfiguration(project.getConfigurations().getByName(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME)); + obf.createRemappingConfiguration(project.getConfigurations().getByName(JavaPlugin.RUNTIME_ONLY_CONFIGURATION_NAME)); + obf.createRemappingConfiguration(project.getConfigurations().getByName(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME)); + + project.getPlugins().withId("java-library", plugin -> { + obf.createRemappingConfiguration(project.getConfigurations().getByName(JavaPlugin.API_CONFIGURATION_NAME)); + obf.createRemappingConfiguration(project.getConfigurations().getByName(JavaPlugin.COMPILE_ONLY_API_CONFIGURATION_NAME)); + }); + } +} diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/McpMetadataTransform.java b/src/legacy/java/net/neoforged/moddevgradle/legacy/McpMetadataTransform.java new file mode 100644 index 00000000..6cc8d7d2 --- /dev/null +++ b/src/legacy/java/net/neoforged/moddevgradle/legacy/McpMetadataTransform.java @@ -0,0 +1,88 @@ +package net.neoforged.moddevgradle.legacy; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.gradle.api.Action; +import org.gradle.api.artifacts.ComponentMetadataContext; +import org.gradle.api.artifacts.DirectDependenciesMetadata; +import org.gradle.api.artifacts.repositories.RepositoryResourceAccessor; +import org.gradle.api.attributes.Usage; +import org.gradle.api.attributes.java.TargetJvmVersion; +import org.gradle.api.model.ObjectFactory; + +import javax.inject.Inject; + +/** + * Given an implicit Metadata object by Gradle (which results from reading in a pom.xml from Maven for MCP data, + * which is basically empty), we build metadata that is equivalent to NeoForms Gradle module metadata. + *

+ * Example for NeoForm: + * https://maven.neoforged.net/releases/net/neoforged/neoform/1.21-20240613.152323/neoform-1.21-20240613.152323.module + */ +// @CacheableTransform +class McpMetadataTransform extends LegacyMetadataTransform { + @Inject + public McpMetadataTransform(ObjectFactory objects, RepositoryResourceAccessor repositoryResourceAccessor) { + super(objects, repositoryResourceAccessor); + } + + @Override + public void execute(ComponentMetadataContext context) { + executeWithConfig(context, createPath(context, "", "zip")); + } + + @Override + protected void adaptWithConfig(ComponentMetadataContext context, JsonObject config) { + var details = context.getDetails(); + var id = details.getId(); + + var zipDataName = id.getName() + "-" + id.getVersion() + ".zip"; + + var javaTarget = config.getAsJsonPrimitive("java_target").getAsInt(); + + // a.k.a. "neoformData" + // Primarily pulled to use for NFRT manifest + details.addVariant("mcpData", variantMetadata -> { + variantMetadata.withFiles(files -> files.addFile(zipDataName)); + variantMetadata.attributes(attributes -> { + attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, javaTarget); + }); + // Add tools required by this version of MCP as dependencies of this variant + variantMetadata.withDependencies(dependencies -> { + var functions = config.getAsJsonObject("functions"); + for (var function : functions.entrySet()) { + var toolCoordinate = ((JsonObject) function.getValue()).getAsJsonPrimitive("version").getAsString(); + dependencies.add(toolCoordinate); + } + }); + variantMetadata.withCapabilities(capabilities -> { + capabilities.addCapability("net.neoforged", "neoform", id.getVersion()); + }); + }); + + dependencies(context, "mcpRuntimeElements", javaTarget, Usage.JAVA_RUNTIME, deps -> {}); + + dependencies(context, "mcpApiElements", javaTarget, Usage.JAVA_API, dependencies -> { + var libraries = config.getAsJsonObject("libraries").getAsJsonArray("joined"); + for (JsonElement library : libraries) { + dependencies.add(library.getAsString()); + } + }); + } + + private void dependencies(ComponentMetadataContext context, String name, int javaTarget, String usage, Action deps) { + context.getDetails().addVariant(name, variantMetadata -> { + variantMetadata.attributes(attributes -> { + attributes.attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, javaTarget); + attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.class, usage)); + }); + variantMetadata.withDependencies(dependencies -> { + deps.execute(dependencies); + dependencies.add("net.neoforged:minecraft-dependencies:" + context.getDetails().getId().getVersion()); + }); + variantMetadata.withCapabilities(capabilities -> { + capabilities.addCapability("net.neoforged", "neoform-dependencies", context.getDetails().getId().getVersion()); + }); + }); + } +} diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/MixinExtension.java b/src/legacy/java/net/neoforged/moddevgradle/legacy/MixinExtension.java new file mode 100644 index 00000000..3e2c4f1f --- /dev/null +++ b/src/legacy/java/net/neoforged/moddevgradle/legacy/MixinExtension.java @@ -0,0 +1,91 @@ +package net.neoforged.moddevgradle.legacy; + +import org.gradle.api.Project; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.RegularFile; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.PathSensitivity; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.compile.JavaCompile; +import org.gradle.jvm.tasks.Jar; +import org.gradle.process.CommandLineArgumentProvider; + +import javax.inject.Inject; +import java.util.List; + +public abstract class MixinExtension { + private final Project project; + private final Provider officialToSrg; + + @Inject + public MixinExtension(Project project, Provider officialToSrg) { + this.project = project; + this.officialToSrg = officialToSrg; + } + + public abstract ListProperty getConfigs(); + + protected abstract ConfigurableFileCollection getExtraMappingFiles(); + + public void config(String name) { + getConfigs().add(name); + } + + public Provider add(SourceSet sourceSet, String refmap) { + var mappingFile = project.getLayout().getBuildDirectory().dir("mixin").map(d -> d.file(refmap + ".mappings.tsrg")); + var refMapFile = project.getLayout().getBuildDirectory().dir("mixin").map(d -> d.file(refmap)); + + var compilerArgs = project.getObjects().newInstance(MixinCompilerArgs.class); + compilerArgs.getRefmap().set(refMapFile); + compilerArgs.getOutMappings().set(mappingFile); + compilerArgs.getInMappings().set(officialToSrg); + + getExtraMappingFiles().from(mappingFile); + + project.getTasks().named(sourceSet.getCompileJavaTaskName(), JavaCompile.class).configure(compile -> { + compile.getOptions().getCompilerArgumentProviders().add(compilerArgs); + }); + + // We use matching because there's no guarantee each sourceset will have a jar task + project.getTasks().withType(Jar.class).matching(jar -> jar.getName().equals(sourceSet.getJarTaskName())).configureEach(jar -> { + jar.from(refMapFile); + }); + + return refMapFile; + } +} + +abstract class MixinCompilerArgs implements CommandLineArgumentProvider { + @Inject + public MixinCompilerArgs() {} + + @OutputFile + protected abstract RegularFileProperty getOutMappings(); + + @OutputFile + protected abstract RegularFileProperty getRefmap(); + + /** + * {@return official -> SRG TSRGv2 mappings file of the game} + */ + @InputFile + @PathSensitive(PathSensitivity.NAME_ONLY) + protected abstract RegularFileProperty getInMappings(); + + @Override + public Iterable asArguments() { + return List.of( + "-AreobfTsrgFile=" + getInMappings().get().getAsFile().getAbsolutePath(), + "-AoutTsrgFile=" + getOutMappings().get().getAsFile().getAbsolutePath(), + "-AoutRefMapFile=" + getRefmap().get().getAsFile().getAbsolutePath(), + "-AmappingTypes=tsrg", + "-ApluginVersion=0.7", // Not sure what this is used for, but MixinGradle gives it to the AP. Latest as of time of writing + "-AdefaultObfuscationEnv=searge" + ); + } +} diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/Obfuscation.java b/src/legacy/java/net/neoforged/moddevgradle/legacy/Obfuscation.java new file mode 100644 index 00000000..b741f879 --- /dev/null +++ b/src/legacy/java/net/neoforged/moddevgradle/legacy/Obfuscation.java @@ -0,0 +1,111 @@ +package net.neoforged.moddevgradle.legacy; + +import org.apache.commons.lang3.StringUtils; +import org.gradle.api.Action; +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.ExternalModuleDependency; +import org.gradle.api.artifacts.FileCollectionDependency; +import org.gradle.api.artifacts.ProjectDependency; +import org.gradle.api.component.AdhocComponentWithVariants; +import org.gradle.api.file.RegularFile; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.TaskProvider; +import org.gradle.api.tasks.bundling.AbstractArchiveTask; + +import javax.inject.Inject; +import java.util.List; + +public abstract class Obfuscation { + private final Project project; + final Provider officialToSrg, mappingsCsv; + final Configuration autoRenamingToolRuntime; + final Configuration installerToolsRuntime; + + @Inject + public Obfuscation(Project project, Provider officialToSrg, Provider mappingsCsv, Configuration autoRenamingToolRuntime, Configuration installerToolsRuntime) { + this.project = project; + this.officialToSrg = officialToSrg; + this.mappingsCsv = mappingsCsv; + this.autoRenamingToolRuntime = autoRenamingToolRuntime; + this.installerToolsRuntime = installerToolsRuntime; + } + + /** + * Create a configure a reobfuscation task. + * + * @param jar the jar task to reobfuscate + * @param sourceSet the source set whose classpath to use when remapping inherited methods + * @param configuration an action used to configure the rebfuscation task + * @return a provider of the created task + */ + public TaskProvider reobfuscate(TaskProvider jar, SourceSet sourceSet, Action configuration) { + var extraMappings = project.getExtensions().getByType(MixinExtension.class).getExtraMappingFiles(); + var reobf = project.getTasks().register("reobf" + StringUtils.capitalize(jar.getName()), RemapJarTask.class, task -> { + task.getInput().set(jar.flatMap(AbstractArchiveTask::getArchiveFile)); + task.getDestinationDirectory().convention(jar.flatMap(AbstractArchiveTask::getDestinationDirectory)); + task.getArchiveBaseName().convention(jar.flatMap(AbstractArchiveTask::getArchiveBaseName)); + task.getArchiveVersion().convention(jar.flatMap(AbstractArchiveTask::getArchiveVersion)); + task.getArchiveClassifier().convention(jar.flatMap(AbstractArchiveTask::getArchiveClassifier).map(c -> c + "-reobf")); + task.getArchiveAppendix().convention(jar.flatMap(AbstractArchiveTask::getArchiveAppendix)); + task.getLibraries().from(sourceSet.getCompileClasspath()); + task.getParameters().from(this, RemapParameters.ToolType.ART); + task.getParameters().getMappings().from(extraMappings); + configuration.execute(task); + }); + + jar.configure(jarTask -> jarTask.finalizedBy(reobf)); + + var java = (AdhocComponentWithVariants) project.getComponents().getByName("java"); + for (var configurationNames : List.of(JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME, JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME)) { + project.getArtifacts().add(configurationNames, reobf); + + java.withVariantsFromConfiguration(project.getConfigurations().getByName(configurationNames), variant -> { + variant.getConfigurationVariant().getArtifacts().removeIf(artifact -> artifact.getFile().equals(jar.get().getArchiveFile().get().getAsFile())); + }); + } + + return reobf; + } + + /** + * Creates a configuration that will remap its dependencies, and adds it as a children of the provided {@code parent}. + */ + public Configuration createRemappingConfiguration(Configuration parent) { + var remappingConfig = project.getConfigurations().create("mod" + StringUtils.capitalize(parent.getName()), spec -> { + spec.setDescription("Configuration for dependencies of " + parent.getName() + " that needs to be remapped"); + spec.attributes(attributeContainer -> { + attributeContainer.attribute(LegacyModDevPlugin.REMAPPED, true); + }); + + // Unfortunately, if we simply try to make the parent extend this config, transformations will not run because the parent doesn't request remapped deps + // If the parent were to request remapped deps, we'd be remapping everything in it. + // Therefore we use a slight "hack" that imposes a constraint over all dependencies in this configuration: to be remapped + spec.withDependencies(dependencies -> dependencies.forEach(dep -> { + if (dep instanceof ExternalModuleDependency externalModuleDependency) { + project.getDependencies().constraints(constraints -> { + constraints.add(parent.getName(), externalModuleDependency.getGroup() + ":" + externalModuleDependency.getName() + ":" + externalModuleDependency.getVersion(), c -> { + c.attributes(a -> a.attribute(LegacyModDevPlugin.REMAPPED, true)); + }); + }); + } else if (dep instanceof FileCollectionDependency fileCollectionDependency) { + project.getDependencies().constraints(constraints -> { + constraints.add(parent.getName(), fileCollectionDependency.getFiles(), c -> { + c.attributes(a -> a.attribute(LegacyModDevPlugin.REMAPPED, true)); + }); + }); + } else if (dep instanceof ProjectDependency projectDependency) { + project.getDependencies().constraints(constraints -> { + constraints.add(parent.getName(), projectDependency.getDependencyProject(), c -> { + c.attributes(a -> a.attribute(LegacyModDevPlugin.REMAPPED, true)); + }); + }); + } + })); + }); + parent.extendsFrom(remappingConfig); + return remappingConfig; + } +} diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/RemapJarTask.java b/src/legacy/java/net/neoforged/moddevgradle/legacy/RemapJarTask.java new file mode 100644 index 00000000..37d51e69 --- /dev/null +++ b/src/legacy/java/net/neoforged/moddevgradle/legacy/RemapJarTask.java @@ -0,0 +1,46 @@ +package net.neoforged.moddevgradle.legacy; + +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.gradle.api.tasks.Nested; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.TaskAction; +import org.gradle.jvm.tasks.Jar; +import org.gradle.process.ExecOperations; + +import javax.inject.Inject; +import java.io.IOException; + +/** + * Task used to remap a jar using AutoRenamingTool. + */ +public abstract class RemapJarTask extends Jar { + + @Nested + protected abstract RemapParameters getParameters(); + + @Inject + public RemapJarTask() { + super(); + } + + /** + * The libraries to use for inheritance data during the renaming process. + */ + @Optional + @InputFiles + public abstract ConfigurableFileCollection getLibraries(); + + @InputFile + public abstract RegularFileProperty getInput(); + + @Inject + protected abstract ExecOperations getExecOperations(); + + @TaskAction + public void remap() throws IOException { + getParameters().execute(getExecOperations(), getInput().getAsFile().get(), getArchiveFile().get().getAsFile(), getLibraries()); + } +} diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/RemapParameters.java b/src/legacy/java/net/neoforged/moddevgradle/legacy/RemapParameters.java new file mode 100644 index 00000000..cf030f86 --- /dev/null +++ b/src/legacy/java/net/neoforged/moddevgradle/legacy/RemapParameters.java @@ -0,0 +1,94 @@ +package net.neoforged.moddevgradle.legacy; + +import net.neoforged.moddevgradle.internal.utils.NetworkSettingPassthrough; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.FileCollection; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Classpath; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.Internal; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.PathSensitivity; +import org.gradle.process.ExecOperations; + +import javax.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Serializable; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +abstract class RemapParameters implements Serializable { + @Inject + public RemapParameters() {} + + @Classpath + @InputFiles + protected abstract ConfigurableFileCollection getToolClasspath(); + + @InputFiles + @PathSensitive(PathSensitivity.NONE) + public abstract ConfigurableFileCollection getMappings(); + + @Internal + public abstract RegularFileProperty getLogFile(); + + @Input + public abstract Property getToolType(); + + public void from(Obfuscation reobfuscation, ToolType toolType) { + getToolType().set(toolType); + if (toolType == ToolType.ART) { + getToolClasspath().from(reobfuscation.autoRenamingToolRuntime); + getMappings().from(reobfuscation.officialToSrg); + } else { + getToolClasspath().from(reobfuscation.installerToolsRuntime); + getMappings().from(reobfuscation.mappingsCsv); + } + } + + public void execute(ExecOperations operations, File input, File output, FileCollection libraries) throws IOException { + final List args = new ArrayList<>(); + + args.addAll(Arrays.asList("--input", input.getAbsolutePath())); + args.addAll(Arrays.asList("--output", output.getAbsolutePath())); + if (getToolType().get() == ToolType.ART) { + getMappings().forEach(file -> args.addAll(Arrays.asList("--names", file.getAbsolutePath()))); + libraries.forEach(lib -> args.addAll(Arrays.asList("--lib", lib.getAbsolutePath()))); + args.add("--disable-abstract-param"); + args.add("--strip-sigs"); + } else { + args.addAll(Arrays.asList("--task", "SRG_TO_MCP")); + getMappings().forEach(file -> args.addAll(Arrays.asList("--mcp", file.getAbsolutePath()))); + args.add("--strip-signatures"); + } + + try (var log = getLogFile().isPresent() ? Files.newOutputStream(getLogFile().get().getAsFile().toPath()) : new OutputStream() { + @Override + public void write(int b) { + } + }) { + operations.javaexec(execSpec -> { + // Pass through network properties + execSpec.systemProperties(NetworkSettingPassthrough.getNetworkSystemProperties()); + + // See https://github.com/gradle/gradle/issues/28959 + execSpec.jvmArgs("-Dstdout.encoding=UTF-8", "-Dstderr.encoding=UTF-8"); + + execSpec.classpath(getToolClasspath()); + execSpec.args(args); + execSpec.setStandardOutput(log); + }).rethrowFailure().assertNormalExitValue(); + } + } + + public enum ToolType { + ART, + INSTALLER_TOOLS + } +} diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/RemappingTransform.java b/src/legacy/java/net/neoforged/moddevgradle/legacy/RemappingTransform.java new file mode 100644 index 00000000..a962ae2a --- /dev/null +++ b/src/legacy/java/net/neoforged/moddevgradle/legacy/RemappingTransform.java @@ -0,0 +1,65 @@ +package net.neoforged.moddevgradle.legacy; + +import org.gradle.api.artifacts.transform.CacheableTransform; +import org.gradle.api.artifacts.transform.InputArtifact; +import org.gradle.api.artifacts.transform.InputArtifactDependencies; +import org.gradle.api.artifacts.transform.TransformAction; +import org.gradle.api.artifacts.transform.TransformOutputs; +import org.gradle.api.artifacts.transform.TransformParameters; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.FileCollection; +import org.gradle.api.file.FileSystemLocation; +import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.CompileClasspath; +import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.Nested; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.PathSensitivity; +import org.gradle.process.ExecOperations; + +import javax.inject.Inject; +import java.io.IOException; + +@CacheableTransform +public abstract class RemappingTransform implements TransformAction { + @InputArtifact + @PathSensitive(PathSensitivity.NONE) + public abstract Provider getInputArtifact(); + + @CompileClasspath + @InputArtifactDependencies + public abstract FileCollection getDependencies(); + + @Inject + protected abstract ExecOperations getExecOperations(); + + @Override + public void transform(TransformOutputs outputs) { + var inputFile = getInputArtifact().get().getAsFile(); + // The file may not yet exist if i.e. IntelliJ requests it during indexing + if (!inputFile.exists()) return; + + var mappedFile = outputs.file(inputFile.getName()); + try { + getParameters().getParameters().get() + .execute( + getExecOperations(), + inputFile, + mappedFile, + getDependencies().plus(getParameters().getMinecraftDependencies()) + ); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public interface Parameters extends TransformParameters { + @Nested + Property getParameters(); + + @InputFiles + @PathSensitive(PathSensitivity.NONE) + ConfigurableFileCollection getMinecraftDependencies(); + } +} diff --git a/src/main/java/net/neoforged/moddevgradle/dsl/NeoForgeExtension.java b/src/main/java/net/neoforged/moddevgradle/dsl/NeoForgeExtension.java index 03c043e8..312d7a54 100644 --- a/src/main/java/net/neoforged/moddevgradle/dsl/NeoForgeExtension.java +++ b/src/main/java/net/neoforged/moddevgradle/dsl/NeoForgeExtension.java @@ -38,6 +38,9 @@ public NeoForgeExtension(Project project, DataFileCollection accessTransformers, runs = project.container(RunModel.class, name -> project.getObjects().newInstance(RunModel.class, name, project, mods)); parchment = project.getObjects().newInstance(Parchment.class); unitTest = project.getObjects().newInstance(UnitTest.class); + getNeoForgeArtifact().convention(getVersion().map(version -> "net.neoforged:neoforge:" + version)); + getNeoFormArtifact().convention(getNeoFormVersion().map(version -> "net.neoforged:neoform:" + version)); + this.accessTransformers = accessTransformers; this.interfaceInjectionData = interfaceInjectionData; getValidateAccessTransformers().convention(false); @@ -62,7 +65,8 @@ public void addModdingDependenciesTo(SourceSet sourceSet) { } /** - * NeoForge version number. You have to set either this or {@link #getNeoFormVersion()}. + * NeoForge version number. You have to set either this, {@link #getNeoFormVersion()} + * or {@link #getNeoFormArtifact()}. */ public abstract Property getVersion(); @@ -70,9 +74,28 @@ public void addModdingDependenciesTo(SourceSet sourceSet) { * You can set this property to a version of NeoForm * to either override the version used in the version of NeoForge you set, or to compile against * Vanilla artifacts that have no NeoForge code added. + *

+ * This property is mutually exclusive with {@link #getNeoFormArtifact()}. */ public abstract Property getNeoFormVersion(); + /** + * Is derived automatically from {@link #getVersion()}. + * + * @return Maven artifact coordinate (group:module:version) + */ + public abstract Property getNeoForgeArtifact(); + + /** + * Derived automatically from the {@link #getNeoFormVersion()}. + * You can override this property to use i.e. MCP for up to 1.20.1. + *

+ * This property is mutually exclusive with {@link #getNeoForgeArtifact()}. + * + * @return Maven artifact coordinate (group:module:version) + */ + public abstract Property getNeoFormArtifact(); + /** * The list of additional access transformers that should be applied to the Minecraft source code. *

diff --git a/src/main/java/net/neoforged/moddevgradle/internal/EclipseIntegration.java b/src/main/java/net/neoforged/moddevgradle/internal/EclipseIntegration.java index 7a05e1d0..0b75953b 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/EclipseIntegration.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/EclipseIntegration.java @@ -158,13 +158,14 @@ private void addEclipseLaunchConfiguration(Project project, } // This is the actual main launch configuration that launches the game + var modFoldersProvider = getModFoldersProvider(project, run.getLoadedMods(), null); var config = JavaApplicationLaunchConfig.builder(eclipseProjectName) .vmArgs( RunUtils.escapeJvmArg(RunUtils.getArgFileParameter(prepareTask.getVmArgsFile().get())), - RunUtils.escapeJvmArg(getModFoldersProvider(project, run.getLoadedMods(), null).getArgument()) + RunUtils.escapeJvmArg(modFoldersProvider.getArgument()) ) .args(RunUtils.escapeJvmArg(RunUtils.getArgFileParameter(prepareTask.getProgramArgsFile().get()))) - .envVar(run.getEnvironment().get()) + .envVar(RunUtils.replaceModClassesEnv(run, () -> modFoldersProvider)) .workingDirectory(run.getGameDirectory().get().getAsFile().getAbsolutePath()) .build(RunUtils.DEV_LAUNCH_MAIN_CLASS); writeEclipseLaunchConfig(project, launchConfigName, config); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/IntelliJIntegration.java b/src/main/java/net/neoforged/moddevgradle/internal/IntelliJIntegration.java index 58619843..a8b1dfbe 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/IntelliJIntegration.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/IntelliJIntegration.java @@ -189,12 +189,12 @@ private static void addIntelliJRunConfiguration(Project project, } appRun.setModuleName(getIntellijModuleName(project, sourceSet)); appRun.setWorkingDirectory(run.getGameDirectory().get().getAsFile().getAbsolutePath()); - appRun.setEnvs(run.getEnvironment().get()); - + var modFoldersProvider = getModFoldersProvider(project, outputDirectory, run.getLoadedMods(), null); + appRun.setEnvs(RunUtils.replaceModClassesEnv(run, () -> modFoldersProvider)); appRun.setJvmArgs( RunUtils.escapeJvmArg(RunUtils.getArgFileParameter(prepareTask.getVmArgsFile().get())) + " " - + RunUtils.escapeJvmArg(getModFoldersProvider(project, outputDirectory, run.getLoadedMods(), null).getArgument()) + + RunUtils.escapeJvmArg(modFoldersProvider.getArgument()) ); appRun.setMainClass(RunUtils.DEV_LAUNCH_MAIN_CLASS); appRun.setProgramParameters(RunUtils.escapeJvmArg(RunUtils.getArgFileParameter(prepareTask.getProgramArgsFile().get()))); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java index 12319032..a60edd49 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java @@ -23,6 +23,7 @@ import org.gradle.api.attributes.AttributeContainer; import org.gradle.api.attributes.Category; import org.gradle.api.attributes.DocsType; +import org.gradle.api.attributes.LibraryElements; import org.gradle.api.attributes.Usage; import org.gradle.api.component.AdhocComponentWithVariants; import org.gradle.api.file.ConfigurableFileCollection; @@ -153,13 +154,13 @@ public void apply(Project project) { // When a NeoForge version is specified, we use the dependencies published by that, and otherwise // we fall back to a potentially specified NeoForm version, which allows us to run in "Vanilla" mode. - var neoForgeModDevLibrariesDependency = extension.getVersion().map(version -> { - return dependencyFactory.create("net.neoforged:neoforge:" + version) + var neoForgeModDevLibrariesDependency = extension.getNeoForgeArtifact().map(artifactId -> { + return dependencyFactory.create(artifactId) .capabilities(caps -> { caps.requireCapability("net.neoforged:neoforge-dependencies"); }); - }).orElse(extension.getNeoFormVersion().map(version -> { - return dependencyFactory.create("net.neoforged:neoform:" + version) + }).orElse(extension.getNeoFormArtifact().map(artifact -> { + return dependencyFactory.create(artifact) .capabilities(caps -> { caps.requireCapability("net.neoforged:neoform-dependencies"); }); @@ -196,13 +197,24 @@ public void apply(Project project) { Function> jarPathFactory = suffix -> { return minecraftArtifactsDir.zip( // It's helpful to be able to differentiate the Vanilla jar and the NeoForge jar in classic multiloader setups. - extension.getVersion().map(v -> "neoforge-" + v).orElse(extension.getNeoFormVersion().map(v -> "vanilla-" + v)), + extension.getNeoForgeArtifact().map(art -> { + var split = art.split(":", 3); + return split[1] + "-" + split[2]; + }) + .orElse(extension.getNeoFormArtifact().map(v -> "vanilla-" + v.split(":", 3)[2])), (dir, prefix) -> dir.file(prefix + "-minecraft" + suffix + ".jar")); }; task.getCompiledArtifact().set(jarPathFactory.apply("")); task.getCompiledWithSourcesArtifact().set(jarPathFactory.apply("-merged")); task.getSourcesArtifact().set(jarPathFactory.apply("-sources")); - task.getResourcesArtifact().set(jarPathFactory.apply("-resources-aka-client-extra")); + task.getResourcesArtifact().set(minecraftArtifactsDir.zip( + extension.getNeoForgeArtifact().map(art -> { + var split = art.split(":", 3); + return split[2] + "-" + split[1]; + }) + .orElse(extension.getNeoFormArtifact().map(v -> "vanilla-" + v.split(":", 3)[2])), + (dir, prefix) -> dir.file("client-extra-aka-minecraft-resources-" + prefix + ".jar") + )); task.getNeoForgeArtifact().set(getNeoForgeUserDevDependencyNotation(extension)); task.getNeoFormArtifact().set(getNeoFormDataDependencyNotation(extension)); @@ -273,8 +285,8 @@ public void apply(Project project) { spec.setCanBeResolved(true); spec.setCanBeConsumed(false); spec.setTransitive(false); - spec.getDependencies().addLater(extension.getVersion().map(version -> { - return dependencyFactory.create("net.neoforged:neoforge:" + version) + spec.getDependencies().addLater(extension.getNeoForgeArtifact().map(artifact -> { + return dependencyFactory.create(artifact) .capabilities(caps -> { caps.requireCapability("net.neoforged:neoforge-moddev-config"); }); @@ -378,11 +390,11 @@ private static void addClientResources(Project project, Configuration spec, Task } private static Provider getNeoFormDataDependencyNotation(NeoForgeExtension extension) { - return extension.getNeoFormVersion().map(version -> "net.neoforged:neoform:" + version + "@zip"); + return extension.getNeoFormArtifact().map(art -> art + "@zip"); } private static Provider getNeoForgeUserDevDependencyNotation(NeoForgeExtension extension) { - return extension.getVersion().map(version -> "net.neoforged:neoforge:" + version + ":userdev"); + return extension.getNeoForgeArtifact().map(art -> art + ":userdev"); } /** @@ -394,8 +406,8 @@ private List configureArtifactManifestConfigurations(Project proj var configurationPrefix = "neoFormRuntimeDependencies"; - Provider neoForgeDependency = extension.getVersion().map(version -> dependencyFactory.create("net.neoforged:neoforge:" + version)); - Provider neoFormDependency = extension.getNeoFormVersion().map(version -> dependencyFactory.create("net.neoforged:neoform:" + version)); + Provider neoForgeDependency = extension.getNeoForgeArtifact().map(dependencyFactory::create); + Provider neoFormDependency = extension.getNeoFormArtifact().map(dependencyFactory::create); // Gradle prevents us from having dependencies with "incompatible attributes" in the same configuration. // What constitutes incompatible cannot be overridden on a per-configuration basis. @@ -453,7 +465,7 @@ private List configureArtifactManifestConfigurations(Project proj spec.setDescription("Dependencies needed for running NeoFormRuntime for the selected NeoForge/NeoForm version (Classpath)"); spec.setCanBeConsumed(false); spec.setCanBeResolved(true); - spec.getDependencies().addLater(neoForgeDependency); // Universal Jar + spec.getDependencies().addLater(extension.getNeoForgeArtifact().map(a -> a + ":universal").map(dependencyFactory::create)); // Universal Jar spec.getDependencies().addLater(neoForgeDependency.map(dependency -> dependency.copy() .capabilities(caps -> { caps.requireCapability("net.neoforged:neoforge-dependencies"); @@ -466,6 +478,8 @@ private List configureArtifactManifestConfigurations(Project proj spec.attributes(attributes -> { setNamedAttribute(attributes, Usage.USAGE_ATTRIBUTE, Usage.JAVA_RUNTIME); setNamedAttribute(attributes, MinecraftDistribution.ATTRIBUTE, MinecraftDistribution.CLIENT); + setNamedAttribute(attributes, Category.CATEGORY_ATTRIBUTE, Category.LIBRARY); + setNamedAttribute(attributes, LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, LibraryElements.JAR); }); }); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java index f6501eb9..cbeb9461 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java @@ -12,6 +12,7 @@ import org.gradle.api.file.Directory; import org.gradle.api.file.RegularFile; import org.gradle.api.provider.MapProperty; +import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.Classpath; import org.gradle.api.tasks.InputFiles; @@ -30,12 +31,15 @@ import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Properties; import java.util.Set; import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Collectors; final class RunUtils { @@ -194,7 +198,7 @@ public static String getArgFileParameter(RegularFile argFile) { } public static ModFoldersProvider getGradleModFoldersProvider(Project project, Provider> modsProvider, Provider testedMod) { - var modFoldersProvider = project.getObjects().newInstance(ModFoldersProvider.class); + var modFoldersProvider = project.getObjects().newInstance(ModFoldersProvider.class, project); modFoldersProvider.getModFolders().set(getModFoldersForGradle(project, modsProvider, testedMod)); return modFoldersProvider; } @@ -219,6 +223,16 @@ public static Project findSourceSetProject(Project someProject, SourceSet source throw new IllegalArgumentException("Could not find project for source set " + someProject); } + public static Map replaceModClassesEnv(RunModel model, Supplier newProvider) { + var vars = model.getEnvironment().get(); + if (vars.containsKey("MOD_CLASSES")) { + final var copy = new HashMap<>(vars); + copy.put("MOD_CLASSES", newProvider.get().getClassesArgument().get()); + return copy; + } + return vars; + } + public static Provider> getModFoldersForGradle(Project project, Provider> modsProvider, @Nullable Provider testedMod) { @@ -279,24 +293,29 @@ record AssetProperties(String assetIndex, String assetsRoot) { abstract class ModFoldersProvider implements CommandLineArgumentProvider { @Inject - public ModFoldersProvider() { + public ModFoldersProvider(Project project) { + getClassesArgument().set(project.provider(() -> { + var stringModFolderMap = getModFolders().get(); + return stringModFolderMap.entrySet().stream() + .mapMulti((entry, output) -> { + for (var directory : entry.getValue().getFolders()) { + // Resources + output.accept(entry.getKey() + "%%" + directory.getAbsolutePath()); + } + }) + .collect(Collectors.joining(File.pathSeparator)); + })); } @Nested abstract MapProperty getModFolders(); + @Internal + abstract Property getClassesArgument(); + @Internal public String getArgument() { - var stringModFolderMap = getModFolders().get(); - return "-Dfml.modFolders=%s".formatted( - stringModFolderMap.entrySet().stream() - .mapMulti((entry, output) -> { - for (var directory : entry.getValue().getFolders()) { - // Resources - output.accept(entry.getKey() + "%%" + directory.getAbsolutePath()); - } - }) - .collect(Collectors.joining(File.pathSeparator))); + return "-Dfml.modFolders=%s".formatted(getClassesArgument().get()); } @Override diff --git a/src/main/java/net/neoforged/moddevgradle/internal/UserDevConfig.java b/src/main/java/net/neoforged/moddevgradle/internal/UserDevConfig.java index 4327c8d6..486aceaa 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/UserDevConfig.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/UserDevConfig.java @@ -3,16 +3,38 @@ import com.google.gson.Gson; import org.gradle.api.GradleException; +import java.io.BufferedReader; import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; import java.io.Serializable; import java.nio.file.Files; import java.util.Map; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; /** * Sourced from the userdev config json. The run templates are the only thing that we use. */ public record UserDevConfig(Map runs) implements Serializable { public static UserDevConfig from(File userDevFile) { + // For backwards compatibility reasons we also support loading this from the userdev jar + if (userDevFile.getName().endsWith(".jar")) { + try (var zf = new ZipFile(userDevFile)) { + var configJson = zf.getEntry("config.json"); + if (configJson != null) { + try (var in = zf.getInputStream(configJson); + var reader = new BufferedReader(new InputStreamReader(in))) { + return new Gson().fromJson(reader, UserDevConfig.class); + } catch (Exception e) { + throw new GradleException("Failed to read NeoForge config file from " + userDevFile, e); + } + } + } catch (IOException e) { + throw new GradleException("Failed to read NeoForge config file from " + userDevFile, e); + } + } + try (var reader = Files.newBufferedReader(userDevFile.toPath())) { return new Gson().fromJson(reader, UserDevConfig.class); } catch (Exception e) { diff --git a/src/main/java/net/neoforged/moddevgradle/internal/VsCodeIntegration.java b/src/main/java/net/neoforged/moddevgradle/internal/VsCodeIntegration.java index 2961997d..827761b0 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/VsCodeIntegration.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/VsCodeIntegration.java @@ -68,13 +68,15 @@ private void addVscodeLaunchConfiguration(Project project, eclipseModel.autoBuildTasks(run.getTasksBefore().toArray()); } + var modFoldersProvider = getModFoldersProvider(project, run.getLoadedMods(), null); launchWriter.createGroup("Mod Development - " + project.getName(), WritingMode.REMOVE_EXISTING) .createLaunchConfiguration() .withName(runIdeName) .withProjectName(eclipseProjectName) .withArguments(List.of(RunUtils.getArgFileParameter(prepareTask.getProgramArgsFile().get()))) .withAdditionalJvmArgs(List.of(RunUtils.getArgFileParameter(prepareTask.getVmArgsFile().get()), - getModFoldersProvider(project, run.getLoadedMods(), null).getArgument())) + modFoldersProvider.getArgument())) + .withEnvironmentVariables(RunUtils.replaceModClassesEnv(run, () -> modFoldersProvider)) .withMainClass(RunUtils.DEV_LAUNCH_MAIN_CLASS) .withShortenCommandLine(ShortCmdBehaviour.NONE) .withConsoleType(ConsoleType.INTERNAL_CONSOLE) diff --git a/src/main/java/net/neoforged/nfrtgradle/NeoFormRuntimeExtension.java b/src/main/java/net/neoforged/nfrtgradle/NeoFormRuntimeExtension.java index 4ee3f302..e0020640 100644 --- a/src/main/java/net/neoforged/nfrtgradle/NeoFormRuntimeExtension.java +++ b/src/main/java/net/neoforged/nfrtgradle/NeoFormRuntimeExtension.java @@ -13,7 +13,7 @@ public abstract class NeoFormRuntimeExtension { public static final String NAME = "neoFormRuntime"; - private static final String DEFAULT_NFRT_VERSION = "1.0.6"; + private static final String DEFAULT_NFRT_VERSION = "1.0.9"; @Inject public NeoFormRuntimeExtension(Project project) { diff --git a/testproject/gradle/wrapper/gradle-wrapper.jar b/testproject/gradle/wrapper/gradle-wrapper.jar index 2c3521197d7c4586c843d1d3e9090525f1898cde..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 3990 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 diff --git a/testproject/gradle/wrapper/gradle-wrapper.properties b/testproject/gradle/wrapper/gradle-wrapper.properties index dedd5d1e..66cd5a0e 100644 --- a/testproject/gradle/wrapper/gradle-wrapper.properties +++ b/testproject/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/testproject/oldneo/build.gradle b/testproject/oldneo/build.gradle new file mode 100644 index 00000000..73dd3654 --- /dev/null +++ b/testproject/oldneo/build.gradle @@ -0,0 +1,8 @@ + +plugins { + id 'net.neoforged.moddev' +} + +neoForge { + version = "20.4.237" +} diff --git a/testproject/settings.gradle b/testproject/settings.gradle index 952a551e..7b293c2d 100644 --- a/testproject/settings.gradle +++ b/testproject/settings.gradle @@ -21,5 +21,6 @@ include 'subproject' include 'common' include 'jijtest' include 'coremod' +//include 'oldneo' enableFeaturePreview "STABLE_CONFIGURATION_CACHE" From d18176f51ecad1872f8b9e2d5c0ccc7a1b17ef6a Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Fri, 29 Nov 2024 01:26:47 +0100 Subject: [PATCH 02/24] Post-rebase fixes --- .../net/neoforged/moddevgradle/internal/ModDevPlugin.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java index a60edd49..dfbc942e 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java @@ -304,8 +304,8 @@ public void apply(Project project) { // This defines the module path for runs // NOTE: When running in vanilla mode, this provider is undefined and will not result in an actual dependency - var modulePathDependency = extension.getVersion().map(version -> { - return dependencyFactory.create("net.neoforged:neoforge:" + version) + var modulePathDependency = extension.getNeoForgeArtifact().map(artifactId -> { + return dependencyFactory.create(artifactId) .capabilities(caps -> { caps.requireCapability("net.neoforged:neoforge-moddev-module-path"); }) @@ -338,8 +338,8 @@ public void apply(Project project) { config.setDescription("Additional JUnit helpers provided by NeoForge"); config.setCanBeResolved(false); config.setCanBeConsumed(false); - config.getDependencies().addLater(extension.getVersion().map(version -> { - return dependencyFactory.create("net.neoforged:neoforge:" + version) + config.getDependencies().addLater(extension.getNeoForgeArtifact().map(artifact -> { + return dependencyFactory.create(artifact) .capabilities(caps -> { caps.requireCapability("net.neoforged:neoforge-moddev-test-fixtures"); }); From f4d21aca5fe3befca56a4d24a9ceba67bb7c41c8 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Fri, 29 Nov 2024 21:10:19 +0100 Subject: [PATCH 03/24] Bump Gradle --- gradle/wrapper/gradle-wrapper.properties | 2 +- legacytest/gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9355b415..e2847c82 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.10-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/legacytest/gradle/wrapper/gradle-wrapper.properties b/legacytest/gradle/wrapper/gradle-wrapper.properties index 66cd5a0e..c1d5e018 100644 --- a/legacytest/gradle/wrapper/gradle-wrapper.properties +++ b/legacytest/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 800820117473628ba90f8ccbe0c47e846b2d9c27 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sat, 30 Nov 2024 01:26:59 +0100 Subject: [PATCH 04/24] Add foojay --- legacytest/settings.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/legacytest/settings.gradle b/legacytest/settings.gradle index 31c788ef..f40601cb 100644 --- a/legacytest/settings.gradle +++ b/legacytest/settings.gradle @@ -1,4 +1,8 @@ +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' +} + includeBuild '..' include 'forge' From c02903a123d0ddb9ee8af7eb746e60deee39b8ea Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sat, 30 Nov 2024 01:43:11 +0100 Subject: [PATCH 05/24] Bump Gradle --- gradle/wrapper/gradle-wrapper.properties | 2 +- testproject/gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e2847c82..c1d5e018 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.11.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/testproject/gradle/wrapper/gradle-wrapper.properties b/testproject/gradle/wrapper/gradle-wrapper.properties index 66cd5a0e..c1d5e018 100644 --- a/testproject/gradle/wrapper/gradle-wrapper.properties +++ b/testproject/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 9a710546d50bb15532cabd1cad322e6b88b348a2 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sat, 30 Nov 2024 02:11:44 +0100 Subject: [PATCH 06/24] Move launch scripts back to old approach and make them sync no more --- .../internal/CreateLaunchScriptTask.java | 13 +++++++++---- .../moddevgradle/internal/ModDevPlugin.java | 17 ++--------------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/main/java/net/neoforged/moddevgradle/internal/CreateLaunchScriptTask.java b/src/main/java/net/neoforged/moddevgradle/internal/CreateLaunchScriptTask.java index 5af6172e..cf0ef447 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/CreateLaunchScriptTask.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/CreateLaunchScriptTask.java @@ -6,13 +6,15 @@ import net.neoforged.moddevgradle.internal.utils.OperatingSystem; import net.neoforged.moddevgradle.internal.utils.StringUtils; import org.gradle.api.DefaultTask; +import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.plugins.JavaPluginExtension; -import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Classpath; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; import org.gradle.jvm.toolchain.JavaToolchainService; @@ -59,8 +61,9 @@ abstract class CreateLaunchScriptTask extends DefaultTask { /** * Set to the desired Java runtime classpath. */ - @Input - abstract ListProperty getRuntimeClasspath(); + @Classpath + @InputFiles + abstract ConfigurableFileCollection getRuntimeClasspath(); @Input abstract Property getModFolders(); @@ -122,7 +125,9 @@ private void writeClasspathArguments() throws IOException { return; } - var classpathFileList = String.join(File.pathSeparator, getRuntimeClasspath().get()); + var classpathFileList = getRuntimeClasspath().getFiles().stream() + .map(File::getAbsolutePath) + .collect(Collectors.joining(File.pathSeparator)); var lines = List.of( "-classpath", diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java index dfbc942e..508e6dc5 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java @@ -612,24 +612,12 @@ private static TaskProvider setupRunInGradle( }); ideIntegration.runTaskOnProjectSync(prepareRunTask); - var createLaunchScriptTask = tasks.register(InternalModelHelper.nameOfRun(run, "create", "launchScript"), CreateLaunchScriptTask.class, task -> { + tasks.register(InternalModelHelper.nameOfRun(run, "create", "launchScript"), CreateLaunchScriptTask.class, task -> { task.setGroup(branding.internalTaskGroup()); task.setDescription("Creates a bash/shell-script to launch the " + run.getName() + " Minecraft run from outside Gradle or your IDE."); task.getWorkingDirectory().set(run.getGameDirectory().map(d -> d.getAsFile().getAbsolutePath())); - // Use a provider indirection to NOT capture a task dependency on the runtimeClasspath. - // Resolving the classpath could require compiling some code depending on the runtimeClasspath setup. - // We don't want to do that on IDE sync! - // In that case, we can't use an @InputFiles ConfigurableFileCollection or Gradle might complain: - // Reason: Task ':createClient2LaunchScript' uses this output of task ':compileApiJava' without - // declaring an explicit or implicit dependency. This can lead to incorrect results being produced, - // depending on what order the tasks are executed. - // So we pass the absolute paths directly... - task.getRuntimeClasspath().set(project.provider(() -> { - return runtimeClasspathConfig.get().getFiles().stream() - .map(File::getAbsolutePath) - .toList(); - })); + task.getRuntimeClasspath().setFrom(runtimeClasspathConfig); task.getLaunchScript().set(RunUtils.getLaunchScript(argFileDir, run)); task.getClasspathArgsFile().set(RunUtils.getArgFile(argFileDir, run, RunUtils.RunArgFile.CLASSPATH)); task.getVmArgsFile().set(prepareRunTask.get().getVmArgsFile().map(d -> d.getAsFile().getAbsolutePath())); @@ -637,7 +625,6 @@ private static TaskProvider setupRunInGradle( task.getEnvironment().set(run.getEnvironment()); task.getModFolders().set(RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null)); }); - ideIntegration.runTaskOnProjectSync(createLaunchScriptTask); tasks.register(InternalModelHelper.nameOfRun(run, "run", ""), RunGameTask.class, task -> { task.setGroup(branding.publicTaskGroup()); From 9e2275a250c7800d9d9101c2c5cab65019708ab4 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sat, 30 Nov 2024 11:20:29 +0100 Subject: [PATCH 07/24] Fix deprecation --- legacytest/build.gradle | 11 ----------- .../neoforged/moddevgradle/legacy/Obfuscation.java | 2 +- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/legacytest/build.gradle b/legacytest/build.gradle index 12e2ef4e..8f55054e 100644 --- a/legacytest/build.gradle +++ b/legacytest/build.gradle @@ -6,17 +6,6 @@ plugins { group = 'com.example.legacy' version = '1.0.0' -repositories { - mavenLocal() - maven { - name 'cursemaven' - url 'https://cursemaven.com' - content { - includeGroup "curse.maven" - } - } -} - java { toolchain { languageVersion = JavaLanguageVersion.of(17) diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/Obfuscation.java b/src/legacy/java/net/neoforged/moddevgradle/legacy/Obfuscation.java index b741f879..4438543e 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacy/Obfuscation.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacy/Obfuscation.java @@ -98,7 +98,7 @@ public Configuration createRemappingConfiguration(Configuration parent) { }); } else if (dep instanceof ProjectDependency projectDependency) { project.getDependencies().constraints(constraints -> { - constraints.add(parent.getName(), projectDependency.getDependencyProject(), c -> { + constraints.add(parent.getName(), project.project(projectDependency.getPath()), c -> { c.attributes(a -> a.attribute(LegacyModDevPlugin.REMAPPED, true)); }); }); From bf1b6dfa2e22ad2e7781147f539cbb380fa01b1e Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sat, 30 Nov 2024 12:12:35 +0100 Subject: [PATCH 08/24] Review comments --- legacytest/forge/build.gradle | 2 +- .../forge/src/main/java/mymod/JeiCompat.java | 1 + .../legacy/LegacyForgeMetadataTransform.java | 4 +-- .../legacy/McpMetadataTransform.java | 3 +- .../internal/PrepareRunOrTest.java | 27 ++++++++++++++- .../moddevgradle/internal/RunUtils.java | 25 +++++++------- .../moddevgradle/internal/UserDevConfig.java | 33 +++---------------- testproject/oldneo/build.gradle | 8 ----- testproject/settings.gradle | 1 - 9 files changed, 47 insertions(+), 57 deletions(-) delete mode 100644 testproject/oldneo/build.gradle diff --git a/legacytest/forge/build.gradle b/legacytest/forge/build.gradle index fe40c6ac..719d248c 100644 --- a/legacytest/forge/build.gradle +++ b/legacytest/forge/build.gradle @@ -25,7 +25,7 @@ java { dependencies { modCompileOnly('mezz.jei:jei-1.20.1-forge:15.17.0.76') { - transitive = false + transitive = false // JEI publishes dependencies on its subprojects that are already included in this Jar } modRuntimeOnly('curse.maven:mekanism-268560:5662583') modImplementation('curse.maven:applied-energistics-2-223794:5641282') diff --git a/legacytest/forge/src/main/java/mymod/JeiCompat.java b/legacytest/forge/src/main/java/mymod/JeiCompat.java index 36fc21e3..9ed51416 100644 --- a/legacytest/forge/src/main/java/mymod/JeiCompat.java +++ b/legacytest/forge/src/main/java/mymod/JeiCompat.java @@ -15,6 +15,7 @@ public ResourceLocation getPluginUid() { @Override public void registerItemSubtypes(ISubtypeRegistration registration) { + // Calling this method tests that JEI was remapped correctly, since the method has an "ItemStack" argument registration.registerSubtypeInterpreter(Items.ALLIUM, (ingredient, context) -> "allium"); } } diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyForgeMetadataTransform.java b/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyForgeMetadataTransform.java index 427981c1..caa1818b 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyForgeMetadataTransform.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyForgeMetadataTransform.java @@ -5,9 +5,9 @@ import org.gradle.api.Action; import org.gradle.api.artifacts.ComponentMetadataContext; import org.gradle.api.artifacts.DirectDependenciesMetadata; -import org.gradle.api.artifacts.DirectDependencyMetadata; import org.gradle.api.artifacts.MutableVariantFilesMetadata; import org.gradle.api.artifacts.repositories.RepositoryResourceAccessor; +import org.gradle.api.artifacts.transform.CacheableTransform; import org.gradle.api.attributes.Bundling; import org.gradle.api.attributes.Category; import org.gradle.api.attributes.Usage; @@ -15,7 +15,7 @@ import javax.inject.Inject; -// @CacheableTransform +@CacheableTransform class LegacyForgeMetadataTransform extends LegacyMetadataTransform { @Inject public LegacyForgeMetadataTransform(ObjectFactory objects, RepositoryResourceAccessor repositoryResourceAccessor) { diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/McpMetadataTransform.java b/src/legacy/java/net/neoforged/moddevgradle/legacy/McpMetadataTransform.java index 6cc8d7d2..4f2dcdc3 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacy/McpMetadataTransform.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacy/McpMetadataTransform.java @@ -6,6 +6,7 @@ import org.gradle.api.artifacts.ComponentMetadataContext; import org.gradle.api.artifacts.DirectDependenciesMetadata; import org.gradle.api.artifacts.repositories.RepositoryResourceAccessor; +import org.gradle.api.artifacts.transform.CacheableTransform; import org.gradle.api.attributes.Usage; import org.gradle.api.attributes.java.TargetJvmVersion; import org.gradle.api.model.ObjectFactory; @@ -19,7 +20,7 @@ * Example for NeoForm: * https://maven.neoforged.net/releases/net/neoforged/neoform/1.21-20240613.152323/neoform-1.21-20240613.152323.module */ -// @CacheableTransform +@CacheableTransform class McpMetadataTransform extends LegacyMetadataTransform { @Inject public McpMetadataTransform(ObjectFactory objects, RepositoryResourceAccessor repositoryResourceAccessor) { diff --git a/src/main/java/net/neoforged/moddevgradle/internal/PrepareRunOrTest.java b/src/main/java/net/neoforged/moddevgradle/internal/PrepareRunOrTest.java index 759144a1..3663ac34 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/PrepareRunOrTest.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/PrepareRunOrTest.java @@ -5,6 +5,7 @@ import net.neoforged.moddevgradle.internal.utils.StringUtils; import net.neoforged.moddevgradle.internal.utils.VersionUtils; import org.gradle.api.DefaultTask; +import org.gradle.api.GradleException; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.RegularFileProperty; @@ -34,6 +35,7 @@ import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; +import java.util.zip.ZipFile; /** * Performs preparation for running the game or running a test. @@ -145,7 +147,7 @@ public void prepareRun() throws IOException { if (getRunTypeTemplatesSource().isEmpty()) { runConfig = resolveRunType(getSimulatedUserDevConfigForVanilla()); } else { - var userDevConfig = UserDevConfig.from(getRunTypeTemplatesSource().getSingleFile()); + var userDevConfig = loadUserDevConfig(getRunTypeTemplatesSource().getSingleFile()); runConfig = resolveRunType(userDevConfig); } @@ -153,6 +155,29 @@ public void prepareRun() throws IOException { writeProgramArguments(runConfig); } + private UserDevConfig loadUserDevConfig(File userDevFile) { + // For backwards compatibility reasons we also support loading this from the userdev jar, + // for NeoForge and Forge versions that didn't publish the configuration as a separate JSON to Maven + if (userDevFile.getName().endsWith(".jar")) { + try (var zf = new ZipFile(userDevFile)) { + var configJson = zf.getEntry("config.json"); + if (configJson != null) { + try (var in = zf.getInputStream(configJson)) { + return UserDevConfig.from(in); + } + } + } catch (IOException e) { + throw new GradleException("Failed to read userdev config file from Jar-file " + userDevFile, e); + } + } + + try (var in = Files.newInputStream(userDevFile.toPath())) { + return UserDevConfig.from(in); + } catch (Exception e) { + throw new GradleException("Failed to read userdev config file from " + userDevFile, e); + } + } + private UserDevConfig getSimulatedUserDevConfigForVanilla() { var clientArgs = List.of("--gameDir", ".", "--assetIndex", "{asset_index}", "--assetsDir", "{assets_root}", "--accessToken", "NotValid", "--version", "ModDevGradle"); var commonArgs = List.of(); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java index cbeb9461..fafb3c96 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java @@ -38,7 +38,6 @@ import java.util.Properties; import java.util.Set; import java.util.function.BiConsumer; -import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -198,7 +197,7 @@ public static String getArgFileParameter(RegularFile argFile) { } public static ModFoldersProvider getGradleModFoldersProvider(Project project, Provider> modsProvider, Provider testedMod) { - var modFoldersProvider = project.getObjects().newInstance(ModFoldersProvider.class, project); + var modFoldersProvider = project.getObjects().newInstance(ModFoldersProvider.class); modFoldersProvider.getModFolders().set(getModFoldersForGradle(project, modsProvider, testedMod)); return modFoldersProvider; } @@ -293,18 +292,16 @@ record AssetProperties(String assetIndex, String assetsRoot) { abstract class ModFoldersProvider implements CommandLineArgumentProvider { @Inject - public ModFoldersProvider(Project project) { - getClassesArgument().set(project.provider(() -> { - var stringModFolderMap = getModFolders().get(); - return stringModFolderMap.entrySet().stream() - .mapMulti((entry, output) -> { - for (var directory : entry.getValue().getFolders()) { - // Resources - output.accept(entry.getKey() + "%%" + directory.getAbsolutePath()); - } - }) - .collect(Collectors.joining(File.pathSeparator)); - })); + public ModFoldersProvider() { + var classesArgument = getModFolders().map(map -> map.entrySet().stream() + .mapMulti((entry, output) -> { + for (var directory : entry.getValue().getFolders()) { + // Resources + output.accept(entry.getKey() + "%%" + directory.getAbsolutePath()); + } + }) + .collect(Collectors.joining(File.pathSeparator))); + getClassesArgument().set(classesArgument); } @Nested diff --git a/src/main/java/net/neoforged/moddevgradle/internal/UserDevConfig.java b/src/main/java/net/neoforged/moddevgradle/internal/UserDevConfig.java index 486aceaa..29745a68 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/UserDevConfig.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/UserDevConfig.java @@ -1,45 +1,20 @@ package net.neoforged.moddevgradle.internal; import com.google.gson.Gson; -import org.gradle.api.GradleException; import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.Serializable; -import java.nio.file.Files; +import java.nio.charset.StandardCharsets; import java.util.Map; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; /** * Sourced from the userdev config json. The run templates are the only thing that we use. */ public record UserDevConfig(Map runs) implements Serializable { - public static UserDevConfig from(File userDevFile) { - // For backwards compatibility reasons we also support loading this from the userdev jar - if (userDevFile.getName().endsWith(".jar")) { - try (var zf = new ZipFile(userDevFile)) { - var configJson = zf.getEntry("config.json"); - if (configJson != null) { - try (var in = zf.getInputStream(configJson); - var reader = new BufferedReader(new InputStreamReader(in))) { - return new Gson().fromJson(reader, UserDevConfig.class); - } catch (Exception e) { - throw new GradleException("Failed to read NeoForge config file from " + userDevFile, e); - } - } - } catch (IOException e) { - throw new GradleException("Failed to read NeoForge config file from " + userDevFile, e); - } - } - - try (var reader = Files.newBufferedReader(userDevFile.toPath())) { - return new Gson().fromJson(reader, UserDevConfig.class); - } catch (Exception e) { - throw new GradleException("Failed to read NeoForge config file from " + userDevFile, e); - } + public static UserDevConfig from(InputStream in) { + return new Gson().fromJson(new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)), UserDevConfig.class); } } diff --git a/testproject/oldneo/build.gradle b/testproject/oldneo/build.gradle deleted file mode 100644 index 73dd3654..00000000 --- a/testproject/oldneo/build.gradle +++ /dev/null @@ -1,8 +0,0 @@ - -plugins { - id 'net.neoforged.moddev' -} - -neoForge { - version = "20.4.237" -} diff --git a/testproject/settings.gradle b/testproject/settings.gradle index 7b293c2d..952a551e 100644 --- a/testproject/settings.gradle +++ b/testproject/settings.gradle @@ -21,6 +21,5 @@ include 'subproject' include 'common' include 'jijtest' include 'coremod' -//include 'oldneo' enableFeaturePreview "STABLE_CONFIGURATION_CACHE" From 8d22d528d77cfd10633473ae1c7b88647c8c56a6 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sat, 30 Nov 2024 18:39:49 +0100 Subject: [PATCH 09/24] More internal, moved to internal/dsl packages --- LEGACY.md | 6 +-- build.gradle | 8 ++-- legacytest/build.gradle | 2 +- legacytest/forge/build.gradle | 3 +- .../boot/LegacyForgeModDevPlugin.java | 9 ++++ .../moddevgradle/boot/LegacyModDevPlugin.java | 9 ---- ...cyInternal.java => LegacyForgeFacade.java} | 2 +- .../legacyforge/dsl/MixinCompilerArgs.java | 42 ++++++++++++++++ .../dsl}/MixinExtension.java | 48 +++---------------- .../LegacyForgeMetadataTransform.java | 2 +- .../internal/LegacyForgeModDevPlugin.java} | 18 ++++--- .../internal}/LegacyMetadataTransform.java | 2 +- .../internal}/McpMetadataTransform.java | 2 +- .../internal}/Obfuscation.java | 18 +++---- .../internal}/RemapJarTask.java | 4 +- .../internal}/RemapParameters.java | 2 +- .../internal}/RemappingTransform.java | 8 +++- 17 files changed, 102 insertions(+), 83 deletions(-) create mode 100644 src/java8/java/net/neoforged/moddevgradle/boot/LegacyForgeModDevPlugin.java delete mode 100644 src/java8/java/net/neoforged/moddevgradle/boot/LegacyModDevPlugin.java rename src/legacy/java/net/neoforged/moddevgradle/internal/{LegacyInternal.java => LegacyForgeFacade.java} (91%) create mode 100644 src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/MixinCompilerArgs.java rename src/legacy/java/net/neoforged/moddevgradle/{legacy => legacyforge/dsl}/MixinExtension.java (52%) rename src/legacy/java/net/neoforged/moddevgradle/{legacy => legacyforge/internal}/LegacyForgeMetadataTransform.java (98%) rename src/legacy/java/net/neoforged/moddevgradle/{legacy/LegacyModDevPlugin.java => legacyforge/internal/LegacyForgeModDevPlugin.java} (92%) rename src/legacy/java/net/neoforged/moddevgradle/{legacy => legacyforge/internal}/LegacyMetadataTransform.java (97%) rename src/legacy/java/net/neoforged/moddevgradle/{legacy => legacyforge/internal}/McpMetadataTransform.java (98%) rename src/legacy/java/net/neoforged/moddevgradle/{legacy => legacyforge/internal}/Obfuscation.java (91%) rename src/legacy/java/net/neoforged/moddevgradle/{legacy => legacyforge/internal}/RemapJarTask.java (92%) rename src/legacy/java/net/neoforged/moddevgradle/{legacy => legacyforge/internal}/RemapParameters.java (98%) rename src/legacy/java/net/neoforged/moddevgradle/{legacy => legacyforge/internal}/RemappingTransform.java (91%) diff --git a/LEGACY.md b/LEGACY.md index a1459c1f..92a0e70e 100644 --- a/LEGACY.md +++ b/LEGACY.md @@ -1,5 +1,5 @@ -# ModDevGradle Legacy Plugin -ModDevGradle has a secondary plugin (ID: `net.neoforged.moddevgradle.legacy`, released alongside the normal plugin with the same version) +# ModDevGradle Legacy Forge Plugin +ModDevGradle has a secondary plugin (ID: `net.neoforged.moddev.legacyforge`, released alongside the normal plugin with the same version) that adds support for developing mods against MinecraftForge and Vanilla Minecraft versions 1.17 up to 1.20.1. The legacy plugin is an "addon" plugin, meaning it operates on top of the normal plugin. This means that the APIs normally used @@ -10,7 +10,7 @@ An example `build.gradle` file for developing a mod against MinecraftForge for 1 ```groovy plugins { // Apply the plugin. You can find the latest version at https://projects.neoforged.net/neoforged/ModDevGradle - id 'net.neoforged.moddev.legacy' version '2.0.28-beta' + id 'net.neoforged.moddev.legacyforge' version '2.0.28-beta' } neoForge { diff --git a/build.gradle b/build.gradle index 9d9b59e6..da5721a1 100644 --- a/build.gradle +++ b/build.gradle @@ -196,10 +196,10 @@ gradlePlugin { description = "This plugin helps you create Minecraft mods using the NeoForge platform" tags = ["minecraft", "neoforge", "java", "mod"] } - legacy { - id = 'net.neoforged.moddev.legacy' - implementationClass = 'net.neoforged.moddevgradle.boot.LegacyModDevPlugin' - displayName = "NeoForge Legacy Mod Development Plugin" + legacyforge { + id = 'net.neoforged.moddev.legacyforge' + implementationClass = 'net.neoforged.moddevgradle.boot.LegacyForgeModDevPlugin' + displayName = "Mod Development Plugin for Legacy Forge" description = "This plugin helps you create Minecraft mods using the Forge platform, up to 1.20.1" tags = ["minecraft", "neoforge", "forge", "java", "mod"] } diff --git a/legacytest/build.gradle b/legacytest/build.gradle index 8f55054e..95b0ef83 100644 --- a/legacytest/build.gradle +++ b/legacytest/build.gradle @@ -1,6 +1,6 @@ plugins { id 'maven-publish' - id 'net.neoforged.moddev.legacy' + id 'net.neoforged.moddev.legacyforge' } group = 'com.example.legacy' diff --git a/legacytest/forge/build.gradle b/legacytest/forge/build.gradle index 719d248c..49f558e9 100644 --- a/legacytest/forge/build.gradle +++ b/legacytest/forge/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'net.neoforged.moddev.legacy' + id 'net.neoforged.moddev.legacyforge' } repositories { @@ -29,6 +29,7 @@ dependencies { } modRuntimeOnly('curse.maven:mekanism-268560:5662583') modImplementation('curse.maven:applied-energistics-2-223794:5641282') + modImplementation('curse.maven:gregtechceu-modern-890405:5641637') } neoForge { diff --git a/src/java8/java/net/neoforged/moddevgradle/boot/LegacyForgeModDevPlugin.java b/src/java8/java/net/neoforged/moddevgradle/boot/LegacyForgeModDevPlugin.java new file mode 100644 index 00000000..4abd0d00 --- /dev/null +++ b/src/java8/java/net/neoforged/moddevgradle/boot/LegacyForgeModDevPlugin.java @@ -0,0 +1,9 @@ +package net.neoforged.moddevgradle.boot; + +import org.gradle.api.Project; + +public class LegacyForgeModDevPlugin extends TrampolinePlugin { + public LegacyForgeModDevPlugin() { + super("net.neoforged.moddevgradle.legacyforge.internal.LegacyForgeModDevPlugin"); + } +} diff --git a/src/java8/java/net/neoforged/moddevgradle/boot/LegacyModDevPlugin.java b/src/java8/java/net/neoforged/moddevgradle/boot/LegacyModDevPlugin.java deleted file mode 100644 index e8fd0f65..00000000 --- a/src/java8/java/net/neoforged/moddevgradle/boot/LegacyModDevPlugin.java +++ /dev/null @@ -1,9 +0,0 @@ -package net.neoforged.moddevgradle.boot; - -import org.gradle.api.Project; - -public class LegacyModDevPlugin extends TrampolinePlugin { - public LegacyModDevPlugin() { - super("net.neoforged.moddevgradle.legacy.LegacyModDevPlugin"); - } -} diff --git a/src/legacy/java/net/neoforged/moddevgradle/internal/LegacyInternal.java b/src/legacy/java/net/neoforged/moddevgradle/internal/LegacyForgeFacade.java similarity index 91% rename from src/legacy/java/net/neoforged/moddevgradle/internal/LegacyInternal.java rename to src/legacy/java/net/neoforged/moddevgradle/internal/LegacyForgeFacade.java index 60bc8f0c..eac0518d 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/internal/LegacyInternal.java +++ b/src/legacy/java/net/neoforged/moddevgradle/internal/LegacyForgeFacade.java @@ -3,7 +3,7 @@ import net.neoforged.moddevgradle.dsl.RunModel; import org.gradle.api.Project; -public class LegacyInternal { +public class LegacyForgeFacade { public static void configureRun(Project project, RunModel run) { run.getEnvironment().put("MOD_CLASSES", RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null).getClassesArgument()); } diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/MixinCompilerArgs.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/MixinCompilerArgs.java new file mode 100644 index 00000000..451dcc2d --- /dev/null +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/MixinCompilerArgs.java @@ -0,0 +1,42 @@ +package net.neoforged.moddevgradle.legacyforge.dsl; + +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.PathSensitivity; +import org.gradle.process.CommandLineArgumentProvider; + +import javax.inject.Inject; +import java.util.List; + +abstract class MixinCompilerArgs implements CommandLineArgumentProvider { + @Inject + public MixinCompilerArgs() { + } + + @OutputFile + protected abstract RegularFileProperty getOutMappings(); + + @OutputFile + protected abstract RegularFileProperty getRefmap(); + + /** + * {@return official -> SRG TSRGv2 mappings file of the game} + */ + @InputFile + @PathSensitive(PathSensitivity.NAME_ONLY) + protected abstract RegularFileProperty getInMappings(); + + @Override + public Iterable asArguments() { + return List.of( + "-AreobfTsrgFile=" + getInMappings().get().getAsFile().getAbsolutePath(), + "-AoutTsrgFile=" + getOutMappings().get().getAsFile().getAbsolutePath(), + "-AoutRefMapFile=" + getRefmap().get().getAsFile().getAbsolutePath(), + "-AmappingTypes=tsrg", + "-ApluginVersion=0.7", // Not sure what this is used for, but MixinGradle gives it to the AP. Latest as of time of writing + "-AdefaultObfuscationEnv=searge" + ); + } +} diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/MixinExtension.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/MixinExtension.java similarity index 52% rename from src/legacy/java/net/neoforged/moddevgradle/legacy/MixinExtension.java rename to src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/MixinExtension.java index 3e2c4f1f..cf703f02 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacy/MixinExtension.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/MixinExtension.java @@ -1,37 +1,32 @@ -package net.neoforged.moddevgradle.legacy; +package net.neoforged.moddevgradle.legacyforge.dsl; import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.RegularFile; -import org.gradle.api.file.RegularFileProperty; import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Provider; -import org.gradle.api.tasks.InputFile; -import org.gradle.api.tasks.OutputFile; -import org.gradle.api.tasks.PathSensitive; -import org.gradle.api.tasks.PathSensitivity; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.compile.JavaCompile; import org.gradle.jvm.tasks.Jar; -import org.gradle.process.CommandLineArgumentProvider; import javax.inject.Inject; -import java.util.List; public abstract class MixinExtension { private final Project project; private final Provider officialToSrg; + private final ConfigurableFileCollection extraMappingFiles; @Inject - public MixinExtension(Project project, Provider officialToSrg) { + public MixinExtension(Project project, + Provider officialToSrg, + ConfigurableFileCollection extraMappingFiles) { this.project = project; this.officialToSrg = officialToSrg; + this.extraMappingFiles = extraMappingFiles; } public abstract ListProperty getConfigs(); - protected abstract ConfigurableFileCollection getExtraMappingFiles(); - public void config(String name) { getConfigs().add(name); } @@ -45,7 +40,7 @@ public Provider add(SourceSet sourceSet, String refmap) { compilerArgs.getOutMappings().set(mappingFile); compilerArgs.getInMappings().set(officialToSrg); - getExtraMappingFiles().from(mappingFile); + extraMappingFiles.from(mappingFile); project.getTasks().named(sourceSet.getCompileJavaTaskName(), JavaCompile.class).configure(compile -> { compile.getOptions().getCompilerArgumentProviders().add(compilerArgs); @@ -60,32 +55,3 @@ public Provider add(SourceSet sourceSet, String refmap) { } } -abstract class MixinCompilerArgs implements CommandLineArgumentProvider { - @Inject - public MixinCompilerArgs() {} - - @OutputFile - protected abstract RegularFileProperty getOutMappings(); - - @OutputFile - protected abstract RegularFileProperty getRefmap(); - - /** - * {@return official -> SRG TSRGv2 mappings file of the game} - */ - @InputFile - @PathSensitive(PathSensitivity.NAME_ONLY) - protected abstract RegularFileProperty getInMappings(); - - @Override - public Iterable asArguments() { - return List.of( - "-AreobfTsrgFile=" + getInMappings().get().getAsFile().getAbsolutePath(), - "-AoutTsrgFile=" + getOutMappings().get().getAsFile().getAbsolutePath(), - "-AoutRefMapFile=" + getRefmap().get().getAsFile().getAbsolutePath(), - "-AmappingTypes=tsrg", - "-ApluginVersion=0.7", // Not sure what this is used for, but MixinGradle gives it to the AP. Latest as of time of writing - "-AdefaultObfuscationEnv=searge" - ); - } -} diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyForgeMetadataTransform.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeMetadataTransform.java similarity index 98% rename from src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyForgeMetadataTransform.java rename to src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeMetadataTransform.java index caa1818b..4e02a017 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyForgeMetadataTransform.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeMetadataTransform.java @@ -1,4 +1,4 @@ -package net.neoforged.moddevgradle.legacy; +package net.neoforged.moddevgradle.legacyforge.internal; import com.google.gson.JsonElement; import com.google.gson.JsonObject; diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyModDevPlugin.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java similarity index 92% rename from src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyModDevPlugin.java rename to src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java index 89a0b94d..e235b6be 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyModDevPlugin.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java @@ -1,8 +1,9 @@ -package net.neoforged.moddevgradle.legacy; +package net.neoforged.moddevgradle.legacyforge.internal; import net.neoforged.moddevgradle.dsl.NeoForgeExtension; -import net.neoforged.moddevgradle.internal.LegacyInternal; +import net.neoforged.moddevgradle.internal.LegacyForgeFacade; import net.neoforged.moddevgradle.internal.ModDevPlugin; +import net.neoforged.moddevgradle.legacyforge.dsl.MixinExtension; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.artifacts.type.ArtifactTypeDefinition; @@ -17,7 +18,7 @@ import java.util.Map; import java.util.stream.Stream; -public class LegacyModDevPlugin implements Plugin { +public class LegacyForgeModDevPlugin implements Plugin { public static final Attribute REMAPPED = Attribute.of("net.neoforged.moddevgradle.legacy.remapped", Boolean.class); @Override @@ -56,7 +57,9 @@ public void apply(Project project) { var mappingsCsv = modDevBuildDir.map(d -> d.file("intermediateToNamed.zip")); var obf = project.getExtensions().create("obfuscation", Obfuscation.class, project, namedToIntermediate, mappingsCsv, autoRenamingToolRuntime, installerToolsRuntime); - var mixin = project.getExtensions().create("mixin", MixinExtension.class, project, namedToIntermediate); + + var extraMixinMappings = project.files(); + var mixin = project.getExtensions().create("mixin", MixinExtension.class, project, namedToIntermediate, extraMixinMappings); project.getExtensions().configure(NeoForgeExtension.class, extension -> { extension.getNeoForgeArtifact().set(extension.getVersion().map(version -> "net.minecraftforge:forge:" + version)); @@ -67,7 +70,7 @@ public void apply(Project project) { extension.getAdditionalMinecraftArtifacts().put("csvMapping", mappingsCsv.map(RegularFile::getAsFile)); extension.getRuns().configureEach(run -> { - LegacyInternal.configureRun(project, run); + LegacyForgeFacade.configureRun(project, run); // Mixin needs the intermediate (SRG) -> named (Mojang, MCP) mapping file in SRG (TSRG is not supported) to be able to ignore the refmaps of dependencies run.getSystemProperties().put("mixin.env.remapRefMap", "true"); @@ -80,7 +83,10 @@ public void apply(Project project) { var reobfJar = obf.reobfuscate( project.getTasks().named(JavaPlugin.JAR_TASK_NAME, Jar.class), project.getExtensions().getByType(SourceSetContainer.class).getByName(SourceSet.MAIN_SOURCE_SET_NAME), - remapJarTask -> remapJarTask.getArchiveClassifier().set("") + task -> { + task.getArchiveClassifier().set(""); + task.getParameters().getMappings().from(extraMixinMappings); + } ); project.getTasks().named(JavaPlugin.JAR_TASK_NAME, Jar.class).configure(jar -> jar.getArchiveClassifier().set("dev")); diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyMetadataTransform.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyMetadataTransform.java similarity index 97% rename from src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyMetadataTransform.java rename to src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyMetadataTransform.java index 34e44fad..cef027e7 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacy/LegacyMetadataTransform.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyMetadataTransform.java @@ -1,4 +1,4 @@ -package net.neoforged.moddevgradle.legacy; +package net.neoforged.moddevgradle.legacyforge.internal; import com.google.gson.Gson; import com.google.gson.JsonObject; diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/McpMetadataTransform.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/McpMetadataTransform.java similarity index 98% rename from src/legacy/java/net/neoforged/moddevgradle/legacy/McpMetadataTransform.java rename to src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/McpMetadataTransform.java index 4f2dcdc3..befa890f 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacy/McpMetadataTransform.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/McpMetadataTransform.java @@ -1,4 +1,4 @@ -package net.neoforged.moddevgradle.legacy; +package net.neoforged.moddevgradle.legacyforge.internal; import com.google.gson.JsonElement; import com.google.gson.JsonObject; diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/Obfuscation.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java similarity index 91% rename from src/legacy/java/net/neoforged/moddevgradle/legacy/Obfuscation.java rename to src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java index 4438543e..9d70ff0b 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacy/Obfuscation.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java @@ -1,4 +1,4 @@ -package net.neoforged.moddevgradle.legacy; +package net.neoforged.moddevgradle.legacyforge.internal; import org.apache.commons.lang3.StringUtils; import org.gradle.api.Action; @@ -18,7 +18,7 @@ import javax.inject.Inject; import java.util.List; -public abstract class Obfuscation { +abstract class Obfuscation { private final Project project; final Provider officialToSrg, mappingsCsv; final Configuration autoRenamingToolRuntime; @@ -41,8 +41,9 @@ public Obfuscation(Project project, Provider officialToSrg, Provide * @param configuration an action used to configure the rebfuscation task * @return a provider of the created task */ - public TaskProvider reobfuscate(TaskProvider jar, SourceSet sourceSet, Action configuration) { - var extraMappings = project.getExtensions().getByType(MixinExtension.class).getExtraMappingFiles(); + public TaskProvider reobfuscate(TaskProvider jar, + SourceSet sourceSet, + Action configuration) { var reobf = project.getTasks().register("reobf" + StringUtils.capitalize(jar.getName()), RemapJarTask.class, task -> { task.getInput().set(jar.flatMap(AbstractArchiveTask::getArchiveFile)); task.getDestinationDirectory().convention(jar.flatMap(AbstractArchiveTask::getDestinationDirectory)); @@ -52,7 +53,6 @@ public TaskProvider reobfuscate(TaskProvider { spec.setDescription("Configuration for dependencies of " + parent.getName() + " that needs to be remapped"); spec.attributes(attributeContainer -> { - attributeContainer.attribute(LegacyModDevPlugin.REMAPPED, true); + attributeContainer.attribute(LegacyForgeModDevPlugin.REMAPPED, true); }); // Unfortunately, if we simply try to make the parent extend this config, transformations will not run because the parent doesn't request remapped deps @@ -87,19 +87,19 @@ public Configuration createRemappingConfiguration(Configuration parent) { if (dep instanceof ExternalModuleDependency externalModuleDependency) { project.getDependencies().constraints(constraints -> { constraints.add(parent.getName(), externalModuleDependency.getGroup() + ":" + externalModuleDependency.getName() + ":" + externalModuleDependency.getVersion(), c -> { - c.attributes(a -> a.attribute(LegacyModDevPlugin.REMAPPED, true)); + c.attributes(a -> a.attribute(LegacyForgeModDevPlugin.REMAPPED, true)); }); }); } else if (dep instanceof FileCollectionDependency fileCollectionDependency) { project.getDependencies().constraints(constraints -> { constraints.add(parent.getName(), fileCollectionDependency.getFiles(), c -> { - c.attributes(a -> a.attribute(LegacyModDevPlugin.REMAPPED, true)); + c.attributes(a -> a.attribute(LegacyForgeModDevPlugin.REMAPPED, true)); }); }); } else if (dep instanceof ProjectDependency projectDependency) { project.getDependencies().constraints(constraints -> { constraints.add(parent.getName(), project.project(projectDependency.getPath()), c -> { - c.attributes(a -> a.attribute(LegacyModDevPlugin.REMAPPED, true)); + c.attributes(a -> a.attribute(LegacyForgeModDevPlugin.REMAPPED, true)); }); }); } diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/RemapJarTask.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapJarTask.java similarity index 92% rename from src/legacy/java/net/neoforged/moddevgradle/legacy/RemapJarTask.java rename to src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapJarTask.java index 37d51e69..1d2b850a 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacy/RemapJarTask.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapJarTask.java @@ -1,4 +1,4 @@ -package net.neoforged.moddevgradle.legacy; +package net.neoforged.moddevgradle.legacyforge.internal; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.RegularFileProperty; @@ -16,7 +16,7 @@ /** * Task used to remap a jar using AutoRenamingTool. */ -public abstract class RemapJarTask extends Jar { +abstract class RemapJarTask extends Jar { @Nested protected abstract RemapParameters getParameters(); diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/RemapParameters.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapParameters.java similarity index 98% rename from src/legacy/java/net/neoforged/moddevgradle/legacy/RemapParameters.java rename to src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapParameters.java index cf030f86..c4809a57 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacy/RemapParameters.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapParameters.java @@ -1,4 +1,4 @@ -package net.neoforged.moddevgradle.legacy; +package net.neoforged.moddevgradle.legacyforge.internal; import net.neoforged.moddevgradle.internal.utils.NetworkSettingPassthrough; import org.gradle.api.file.ConfigurableFileCollection; diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacy/RemappingTransform.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemappingTransform.java similarity index 91% rename from src/legacy/java/net/neoforged/moddevgradle/legacy/RemappingTransform.java rename to src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemappingTransform.java index a962ae2a..9e3c845b 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacy/RemappingTransform.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemappingTransform.java @@ -1,4 +1,4 @@ -package net.neoforged.moddevgradle.legacy; +package net.neoforged.moddevgradle.legacyforge.internal; import org.gradle.api.artifacts.transform.CacheableTransform; import org.gradle.api.artifacts.transform.InputArtifact; @@ -22,7 +22,7 @@ import java.io.IOException; @CacheableTransform -public abstract class RemappingTransform implements TransformAction { +abstract class RemappingTransform implements TransformAction { @InputArtifact @PathSensitive(PathSensitivity.NONE) public abstract Provider getInputArtifact(); @@ -34,6 +34,10 @@ public abstract class RemappingTransform implements TransformAction Date: Sat, 30 Nov 2024 18:51:30 +0100 Subject: [PATCH 10/24] More internal, moved to internal/dsl packages --- legacytest/forge/build.gradle | 4 +++- .../legacyforge/internal/LegacyForgeModDevPlugin.java | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/legacytest/forge/build.gradle b/legacytest/forge/build.gradle index 49f558e9..73239afb 100644 --- a/legacytest/forge/build.gradle +++ b/legacytest/forge/build.gradle @@ -29,7 +29,9 @@ dependencies { } modRuntimeOnly('curse.maven:mekanism-268560:5662583') modImplementation('curse.maven:applied-energistics-2-223794:5641282') - modImplementation('curse.maven:gregtechceu-modern-890405:5641637') + // This is an example for a mod that does NOT work with FG or MDG since its JiJ dependencies are + // packages into /META-INF/jars while installertools will only remap /META-INF/jarjar/*.jar + // modImplementation('curse.maven:gregtechceu-modern-890405:5641637') } neoForge { diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java index e235b6be..a0f873d9 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java @@ -40,14 +40,14 @@ public void apply(Project project) { spec.setCanBeConsumed(false); spec.setCanBeResolved(true); spec.setTransitive(false); - spec.defaultDependencies(dependencies -> dependencies.add(depFactory.create("net.neoforged:AutoRenamingTool:2.0.4:all"))); + spec.getDependencies().add(depFactory.create("net.neoforged:AutoRenamingTool:2.0.4:all")); }); var installerToolsRuntime = project.getConfigurations().create("installerToolsRuntime", spec -> { spec.setDescription("The InstallerTools CLI tool"); spec.setCanBeConsumed(false); spec.setCanBeResolved(true); spec.setTransitive(false); - spec.defaultDependencies(dependencies -> dependencies.add(depFactory.create("net.neoforged.installertools:installertools:2.1.7:fatjar"))); + spec.getDependencies().add(depFactory.create("net.neoforged.installertools:installertools:2.1.7:fatjar")); }); // We use this directory to store intermediate files used during moddev From 84a82bc18de7a63610f8fdb68ec04668be7fc5ea Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sat, 30 Nov 2024 19:25:43 +0100 Subject: [PATCH 11/24] Review comment --- .../legacyforge/internal/LegacyForgeModDevPlugin.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java index a0f873d9..18398a5e 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java @@ -30,6 +30,7 @@ public void apply(Project project) { repo.setUrl(URI.create("https://maven.minecraftforge.net/")); }); + // This module is for supporting NeoForge 1.20.1, which is technically the same as Legacy Forge 1.20.1 project.getDependencies().getComponents().withModule("net.neoforged:forge", LegacyForgeMetadataTransform.class); project.getDependencies().getComponents().withModule("net.minecraftforge:forge", LegacyForgeMetadataTransform.class); project.getDependencies().getComponents().withModule("de.oceanlabs.mcp:mcp_config", McpMetadataTransform.class); From 1e1752a1c6e4c93ce93563eb367e3257ef51962f Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sun, 1 Dec 2024 00:51:49 +0100 Subject: [PATCH 12/24] Review comments --- legacytest/forge/build.gradle | 14 ++++++++ .../internal/LegacyForgeFacade.java | 1 + .../internal/LegacyForgeModDevPlugin.java | 3 +- .../legacyforge/internal/Obfuscation.java | 32 ++++++++++++------- .../{RemapJarTask.java => RemapJar.java} | 13 +++++--- 5 files changed, 46 insertions(+), 17 deletions(-) rename src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/{RemapJarTask.java => RemapJar.java} (79%) diff --git a/legacytest/forge/build.gradle b/legacytest/forge/build.gradle index 73239afb..3a272150 100644 --- a/legacytest/forge/build.gradle +++ b/legacytest/forge/build.gradle @@ -1,5 +1,6 @@ plugins { id 'net.neoforged.moddev.legacyforge' + id 'maven-publish' } repositories { @@ -50,3 +51,16 @@ neoForge { } } } + +publishing { + publications { + maven(MavenPublication) { + from components.java + } + } + repositories { + maven { + url rootProject.file('repo') + } + } +} diff --git a/src/legacy/java/net/neoforged/moddevgradle/internal/LegacyForgeFacade.java b/src/legacy/java/net/neoforged/moddevgradle/internal/LegacyForgeFacade.java index eac0518d..639e5911 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/internal/LegacyForgeFacade.java +++ b/src/legacy/java/net/neoforged/moddevgradle/internal/LegacyForgeFacade.java @@ -5,6 +5,7 @@ public class LegacyForgeFacade { public static void configureRun(Project project, RunModel run) { + // This will explicitly be replaced in RunUtils to make this work for IDEs run.getEnvironment().put("MOD_CLASSES", RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null).getClassesArgument()); } } diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java index 18398a5e..f00d420a 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java @@ -85,7 +85,6 @@ public void apply(Project project) { project.getTasks().named(JavaPlugin.JAR_TASK_NAME, Jar.class), project.getExtensions().getByType(SourceSetContainer.class).getByName(SourceSet.MAIN_SOURCE_SET_NAME), task -> { - task.getArchiveClassifier().set(""); task.getParameters().getMappings().from(extraMixinMappings); } ); @@ -98,6 +97,8 @@ public void apply(Project project) { .getDependencies().add(project.getDependencyFactory().create(project.files(mappingsCsv))); // Forge expects to find the Forge and client-extra jar on the legacy classpath + // Newer FML versions also search for it on the java.class.path. + // MDG already adds cilent-extra, but the forge jar is missing. project.getConfigurations().getByName("additionalRuntimeClasspath") .extendsFrom(project.getConfigurations().getByName(ModDevPlugin.CONFIGURATION_RUNTIME_DEPENDENCIES)) .exclude(Map.of("group", "net.neoforged", "module", "DevLaunch")); diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java index 9d70ff0b..dd075e44 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java @@ -16,6 +16,7 @@ import org.gradle.api.tasks.bundling.AbstractArchiveTask; import javax.inject.Inject; +import java.io.File; import java.util.List; abstract class Obfuscation { @@ -41,16 +42,25 @@ public Obfuscation(Project project, Provider officialToSrg, Provide * @param configuration an action used to configure the rebfuscation task * @return a provider of the created task */ - public TaskProvider reobfuscate(TaskProvider jar, - SourceSet sourceSet, - Action configuration) { - var reobf = project.getTasks().register("reobf" + StringUtils.capitalize(jar.getName()), RemapJarTask.class, task -> { - task.getInput().set(jar.flatMap(AbstractArchiveTask::getArchiveFile)); - task.getDestinationDirectory().convention(jar.flatMap(AbstractArchiveTask::getDestinationDirectory)); - task.getArchiveBaseName().convention(jar.flatMap(AbstractArchiveTask::getArchiveBaseName)); - task.getArchiveVersion().convention(jar.flatMap(AbstractArchiveTask::getArchiveVersion)); - task.getArchiveClassifier().convention(jar.flatMap(AbstractArchiveTask::getArchiveClassifier).map(c -> c + "-reobf")); - task.getArchiveAppendix().convention(jar.flatMap(AbstractArchiveTask::getArchiveAppendix)); + public TaskProvider reobfuscate(TaskProvider jar, + SourceSet sourceSet, + Action configuration) { + var reobf = project.getTasks().register("reobf" + StringUtils.capitalize(jar.getName()), RemapJar.class, task -> { + var jarFile = jar.flatMap(AbstractArchiveTask::getArchiveFile); + task.getInput().set(jarFile); + task.getOutput().convention(jarFile.flatMap(regularFile -> { + var f = regularFile.getAsFile(); + String newFilename; + var extSep = f.getName().lastIndexOf('.'); + if (extSep != -1) { + newFilename = f.getName().substring(0, extSep) + + "-reobf" + f.getName().substring(extSep); + } else { + newFilename = f.getName() + "-reobf"; + } + return jar.flatMap(AbstractArchiveTask::getDestinationDirectory) + .map(dir -> dir.file(newFilename)); + })); task.getLibraries().from(sourceSet.getCompileClasspath()); task.getParameters().from(this, RemapParameters.ToolType.ART); configuration.execute(task); @@ -60,8 +70,8 @@ public TaskProvider reobfuscate(TaskProvider { variant.getConfigurationVariant().getArtifacts().removeIf(artifact -> artifact.getFile().equals(jar.get().getArchiveFile().get().getAsFile())); }); diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapJarTask.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapJar.java similarity index 79% rename from src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapJarTask.java rename to src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapJar.java index 1d2b850a..b285083b 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapJarTask.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapJar.java @@ -1,13 +1,14 @@ package net.neoforged.moddevgradle.legacyforge.internal; +import org.gradle.api.DefaultTask; 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.gradle.api.tasks.Nested; import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; -import org.gradle.jvm.tasks.Jar; import org.gradle.process.ExecOperations; import javax.inject.Inject; @@ -16,14 +17,13 @@ /** * Task used to remap a jar using AutoRenamingTool. */ -abstract class RemapJarTask extends Jar { +abstract class RemapJar extends DefaultTask { @Nested protected abstract RemapParameters getParameters(); @Inject - public RemapJarTask() { - super(); + public RemapJar() { } /** @@ -36,11 +36,14 @@ public RemapJarTask() { @InputFile public abstract RegularFileProperty getInput(); + @OutputFile + public abstract RegularFileProperty getOutput(); + @Inject protected abstract ExecOperations getExecOperations(); @TaskAction public void remap() throws IOException { - getParameters().execute(getExecOperations(), getInput().getAsFile().get(), getArchiveFile().get().getAsFile(), getLibraries()); + getParameters().execute(getExecOperations(), getInput().getAsFile().get(), getOutput().get().getAsFile(), getLibraries()); } } From def3521eec557f3353f9100a31d9c2f26de6648b Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sun, 1 Dec 2024 00:55:09 +0100 Subject: [PATCH 13/24] Review comments --- .../moddevgradle/legacyforge/internal/Obfuscation.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java index dd075e44..5741962a 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java @@ -69,10 +69,10 @@ public TaskProvider reobfuscate(TaskProvider jarTask.finalizedBy(reobf)); var java = (AdhocComponentWithVariants) project.getComponents().getByName("java"); - for (var configurationNames : List.of(JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME, JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME)) { + for (var configurationName : List.of(JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME, JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME)) { // Ensure that the published jar is the obfuscated jar, not the plain one - project.getArtifacts().add(configurationNames, reobf); - java.withVariantsFromConfiguration(project.getConfigurations().getByName(configurationNames), variant -> { + project.getArtifacts().add(configurationName, reobf); + java.withVariantsFromConfiguration(project.getConfigurations().getByName(configurationName), variant -> { variant.getConfigurationVariant().getArtifacts().removeIf(artifact -> artifact.getFile().equals(jar.get().getArchiveFile().get().getAsFile())); }); } From aacf6cbd7dbd5b9df6bfee6c859e1328bc199d2b Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sun, 1 Dec 2024 01:08:49 +0100 Subject: [PATCH 14/24] Review comments --- .../legacyforge/internal/LegacyForgeMetadataTransform.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeMetadataTransform.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeMetadataTransform.java index 4e02a017..43318fbb 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeMetadataTransform.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeMetadataTransform.java @@ -80,6 +80,7 @@ public void adaptWithConfig(ComponentMetadataContext context, JsonObject config) capabilities.addCapability("net.neoforged", "neoforge-dependencies", id.getVersion()); }); }); + // repurpose the existing runtime variant to be the equivalent of NeoForges modDevRuntimeElements details.withVariant("runtime", variantMetadata -> { variantMetadata.attributes(attributes -> { attributes.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.class, Category.LIBRARY)); From d7b5f773f65269ec3e413cd77e9a4bd3db24a601 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sun, 1 Dec 2024 03:01:44 +0100 Subject: [PATCH 15/24] Review comments --- .../LegacyForgeMetadataTransform.java | 31 ++++++++++++++++--- .../internal/McpMetadataTransform.java | 3 +- .../moddevgradle/internal/ModDevPlugin.java | 5 +-- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeMetadataTransform.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeMetadataTransform.java index 43318fbb..3df281da 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeMetadataTransform.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeMetadataTransform.java @@ -3,19 +3,21 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import org.gradle.api.Action; +import org.gradle.api.artifacts.CacheableRule; import org.gradle.api.artifacts.ComponentMetadataContext; import org.gradle.api.artifacts.DirectDependenciesMetadata; import org.gradle.api.artifacts.MutableVariantFilesMetadata; import org.gradle.api.artifacts.repositories.RepositoryResourceAccessor; -import org.gradle.api.artifacts.transform.CacheableTransform; import org.gradle.api.attributes.Bundling; import org.gradle.api.attributes.Category; +import org.gradle.api.attributes.LibraryElements; import org.gradle.api.attributes.Usage; import org.gradle.api.model.ObjectFactory; import javax.inject.Inject; +import java.util.List; -@CacheableTransform +@CacheableRule class LegacyForgeMetadataTransform extends LegacyMetadataTransform { @Inject public LegacyForgeMetadataTransform(ObjectFactory objects, RepositoryResourceAccessor repositoryResourceAccessor) { @@ -33,6 +35,7 @@ public void adaptWithConfig(ComponentMetadataContext context, JsonObject config) var id = details.getId(); var userdevJarName = id.getName() + "-" + id.getVersion() + "-userdev.jar"; + var universalJarName = id.getName() + "-" + id.getVersion() + "-universal.jar"; Action vanillaDependencies = deps -> { deps.add("de.oceanlabs.mcp:mcp_config:" + id.getVersion().split("-")[0]); @@ -80,14 +83,14 @@ public void adaptWithConfig(ComponentMetadataContext context, JsonObject config) capabilities.addCapability("net.neoforged", "neoforge-dependencies", id.getVersion()); }); }); - // repurpose the existing runtime variant to be the equivalent of NeoForges modDevRuntimeElements - details.withVariant("runtime", variantMetadata -> { + details.addVariant("modDevRuntimeElements", variantMetadata -> { variantMetadata.attributes(attributes -> { attributes.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.class, Category.LIBRARY)); attributes.attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.class, Bundling.EXTERNAL)); attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.class, Usage.JAVA_RUNTIME)); }); variantMetadata.withCapabilities(capabilities -> { + capabilities.removeCapability(id.getGroup(), id.getName()); capabilities.addCapability("net.neoforged", "neoforge-dependencies", id.getVersion()); }); variantMetadata.withDependencies(vanillaDependencies); @@ -103,5 +106,25 @@ public void adaptWithConfig(ComponentMetadataContext context, JsonObject config) } }); }); + + details.addVariant("universalJar", variantMetadata -> { + variantMetadata.attributes(attributes -> { + attributes.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.class, Category.LIBRARY)); + attributes.attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.class, Bundling.EXTERNAL)); + attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.class, Usage.JAVA_RUNTIME)); + attributes.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.class, LibraryElements.JAR)); + }); + variantMetadata.withFiles(metadata -> metadata.addFile(universalJarName, universalJarName)); + }); + + // Use a fake capability to make it impossible for the implicit variants to be selected + for (var implicitVariantName : List.of("compile", "runtime")) { + details.withVariant(implicitVariantName, variant -> { + variant.withCapabilities(caps -> { + caps.removeCapability(id.getGroup(), id.getName()); + caps.addCapability("___dummy___", "___dummy___", "___dummy___"); + }); + }); + } } } diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/McpMetadataTransform.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/McpMetadataTransform.java index befa890f..db7c0546 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/McpMetadataTransform.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/McpMetadataTransform.java @@ -3,6 +3,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import org.gradle.api.Action; +import org.gradle.api.artifacts.CacheableRule; import org.gradle.api.artifacts.ComponentMetadataContext; import org.gradle.api.artifacts.DirectDependenciesMetadata; import org.gradle.api.artifacts.repositories.RepositoryResourceAccessor; @@ -20,7 +21,7 @@ * Example for NeoForm: * https://maven.neoforged.net/releases/net/neoforged/neoform/1.21-20240613.152323/neoform-1.21-20240613.152323.module */ -@CacheableTransform +@CacheableRule class McpMetadataTransform extends LegacyMetadataTransform { @Inject public McpMetadataTransform(ObjectFactory objects, RepositoryResourceAccessor repositoryResourceAccessor) { diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java index 508e6dc5..7d77ebe0 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java @@ -23,7 +23,6 @@ import org.gradle.api.attributes.AttributeContainer; import org.gradle.api.attributes.Category; import org.gradle.api.attributes.DocsType; -import org.gradle.api.attributes.LibraryElements; import org.gradle.api.attributes.Usage; import org.gradle.api.component.AdhocComponentWithVariants; import org.gradle.api.file.ConfigurableFileCollection; @@ -465,7 +464,7 @@ private List configureArtifactManifestConfigurations(Project proj spec.setDescription("Dependencies needed for running NeoFormRuntime for the selected NeoForge/NeoForm version (Classpath)"); spec.setCanBeConsumed(false); spec.setCanBeResolved(true); - spec.getDependencies().addLater(extension.getNeoForgeArtifact().map(a -> a + ":universal").map(dependencyFactory::create)); // Universal Jar + spec.getDependencies().addLater(neoForgeDependency); // Universal Jar spec.getDependencies().addLater(neoForgeDependency.map(dependency -> dependency.copy() .capabilities(caps -> { caps.requireCapability("net.neoforged:neoforge-dependencies"); @@ -478,8 +477,6 @@ private List configureArtifactManifestConfigurations(Project proj spec.attributes(attributes -> { setNamedAttribute(attributes, Usage.USAGE_ATTRIBUTE, Usage.JAVA_RUNTIME); setNamedAttribute(attributes, MinecraftDistribution.ATTRIBUTE, MinecraftDistribution.CLIENT); - setNamedAttribute(attributes, Category.CATEGORY_ATTRIBUTE, Category.LIBRARY); - setNamedAttribute(attributes, LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, LibraryElements.JAR); }); }); From 25a4bb7aec5fed6b3b0e4200300c47638429ec9d Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sun, 1 Dec 2024 03:16:06 +0100 Subject: [PATCH 16/24] Review comments --- gradle/wrapper/gradle-wrapper.properties | 2 +- .../legacyforge/internal/LegacyForgeModDevPlugin.java | 7 ++----- .../net/neoforged/moddevgradle/internal/ModDevPlugin.java | 1 + testproject/gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c1d5e018..dedd5d1e 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.11.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java index f00d420a..eb5364a0 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java @@ -134,10 +134,7 @@ public void apply(Project project) { obf.createRemappingConfiguration(project.getConfigurations().getByName(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME)); obf.createRemappingConfiguration(project.getConfigurations().getByName(JavaPlugin.RUNTIME_ONLY_CONFIGURATION_NAME)); obf.createRemappingConfiguration(project.getConfigurations().getByName(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME)); - - project.getPlugins().withId("java-library", plugin -> { - obf.createRemappingConfiguration(project.getConfigurations().getByName(JavaPlugin.API_CONFIGURATION_NAME)); - obf.createRemappingConfiguration(project.getConfigurations().getByName(JavaPlugin.COMPILE_ONLY_API_CONFIGURATION_NAME)); - }); + obf.createRemappingConfiguration(project.getConfigurations().getByName(JavaPlugin.API_CONFIGURATION_NAME)); + obf.createRemappingConfiguration(project.getConfigurations().getByName(JavaPlugin.COMPILE_ONLY_API_CONFIGURATION_NAME)); } } diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java index 7d77ebe0..533df39d 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java @@ -212,6 +212,7 @@ public void apply(Project project) { return split[2] + "-" + split[1]; }) .orElse(extension.getNeoFormArtifact().map(v -> "vanilla-" + v.split(":", 3)[2])), + // (dir, prefix) -> dir.file("client-extra-aka-minecraft-resources-" + prefix + ".jar") )); diff --git a/testproject/gradle/wrapper/gradle-wrapper.properties b/testproject/gradle/wrapper/gradle-wrapper.properties index c1d5e018..dedd5d1e 100644 --- a/testproject/gradle/wrapper/gradle-wrapper.properties +++ b/testproject/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 72143fe0ee33106fc251ac4acef609d1746b15b3 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sun, 1 Dec 2024 03:19:25 +0100 Subject: [PATCH 17/24] Review comments --- gradle/wrapper/gradle-wrapper.jar | Bin 43583 -> 43504 bytes .../legacyforge/internal/Obfuscation.java | 2 +- testproject/gradle/wrapper/gradle-wrapper.jar | Bin 43583 -> 43504 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a4b76b9530d66f5e68d973ea569d8e19de379189..2c3521197d7c4586c843d1d3e9090525f1898cde 100644 GIT binary patch delta 3889 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 delta 3990 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 wpAeHLsTu { - constraints.add(parent.getName(), project.project(projectDependency.getPath()), c -> { + constraints.add(parent.getName(), projectDependency.getDependencyProject(), c -> { c.attributes(a -> a.attribute(LegacyForgeModDevPlugin.REMAPPED, true)); }); }); diff --git a/testproject/gradle/wrapper/gradle-wrapper.jar b/testproject/gradle/wrapper/gradle-wrapper.jar index a4b76b9530d66f5e68d973ea569d8e19de379189..2c3521197d7c4586c843d1d3e9090525f1898cde 100644 GIT binary patch delta 3889 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 delta 3990 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 wpAeHLsTu Date: Sun, 1 Dec 2024 15:37:28 +0100 Subject: [PATCH 18/24] Review comments --- .../internal/LegacyForgeModDevPlugin.java | 1 - .../legacyforge/internal/Obfuscation.java | 36 +++++++++---------- .../legacyforge/internal/RemapJar.java | 11 +++--- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java index eb5364a0..3c9c36cb 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java @@ -89,7 +89,6 @@ public void apply(Project project) { } ); - project.getTasks().named(JavaPlugin.JAR_TASK_NAME, Jar.class).configure(jar -> jar.getArchiveClassifier().set("dev")); project.getTasks().named("assemble", assemble -> assemble.dependsOn(reobfJar)); // Forge expects the mapping csv files on the root classpath diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java index 8fa7e3a2..83e2b259 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java @@ -16,7 +16,6 @@ import org.gradle.api.tasks.bundling.AbstractArchiveTask; import javax.inject.Inject; -import java.io.File; import java.util.List; abstract class Obfuscation { @@ -43,34 +42,31 @@ public Obfuscation(Project project, Provider officialToSrg, Provide * @return a provider of the created task */ public TaskProvider reobfuscate(TaskProvider jar, - SourceSet sourceSet, - Action configuration) { + SourceSet sourceSet, + Action configuration) { + + var reobf = project.getTasks().register("reobf" + StringUtils.capitalize(jar.getName()), RemapJar.class, task -> { - var jarFile = jar.flatMap(AbstractArchiveTask::getArchiveFile); - task.getInput().set(jarFile); - task.getOutput().convention(jarFile.flatMap(regularFile -> { - var f = regularFile.getAsFile(); - String newFilename; - var extSep = f.getName().lastIndexOf('.'); - if (extSep != -1) { - newFilename = f.getName().substring(0, extSep) - + "-reobf" + f.getName().substring(extSep); - } else { - newFilename = f.getName() + "-reobf"; - } - return jar.flatMap(AbstractArchiveTask::getDestinationDirectory) - .map(dir -> dir.file(newFilename)); - })); + task.getInput().set(jar.flatMap(AbstractArchiveTask::getArchiveFile)); + task.getDestinationDirectory().convention(task.getProject().getLayout().getBuildDirectory()); + task.getArchiveBaseName().convention(jar.flatMap(AbstractArchiveTask::getArchiveBaseName)); + task.getArchiveVersion().convention(jar.flatMap(AbstractArchiveTask::getArchiveVersion)); + task.getArchiveClassifier().convention(jar.flatMap(AbstractArchiveTask::getArchiveClassifier)); + task.getArchiveAppendix().convention(jar.flatMap(AbstractArchiveTask::getArchiveAppendix)); task.getLibraries().from(sourceSet.getCompileClasspath()); task.getParameters().from(this, RemapParameters.ToolType.ART); configuration.execute(task); }); - jar.configure(jarTask -> jarTask.finalizedBy(reobf)); + jar.configure(task -> { + task.finalizedBy(reobf); + // Move plain jars into a subdirectory to be able to maintain the same classifier for the reobfuscated version + task.getDestinationDirectory().set(task.getProject().getLayout().getBuildDirectory().dir("devlibs")); + }); + // Replace the publication of the jar task with the reobfuscated jar var java = (AdhocComponentWithVariants) project.getComponents().getByName("java"); for (var configurationName : List.of(JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME, JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME)) { - // Ensure that the published jar is the obfuscated jar, not the plain one project.getArtifacts().add(configurationName, reobf); java.withVariantsFromConfiguration(project.getConfigurations().getByName(configurationName), variant -> { variant.getConfigurationVariant().getArtifacts().removeIf(artifact -> artifact.getFile().equals(jar.get().getArchiveFile().get().getAsFile())); diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapJar.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapJar.java index b285083b..061fd6a2 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapJar.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapJar.java @@ -1,14 +1,13 @@ package net.neoforged.moddevgradle.legacyforge.internal; -import org.gradle.api.DefaultTask; 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.gradle.api.tasks.Nested; import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.bundling.Jar; import org.gradle.process.ExecOperations; import javax.inject.Inject; @@ -17,7 +16,7 @@ /** * Task used to remap a jar using AutoRenamingTool. */ -abstract class RemapJar extends DefaultTask { +abstract class RemapJar extends Jar { @Nested protected abstract RemapParameters getParameters(); @@ -36,14 +35,12 @@ public RemapJar() { @InputFile public abstract RegularFileProperty getInput(); - @OutputFile - public abstract RegularFileProperty getOutput(); - @Inject protected abstract ExecOperations getExecOperations(); @TaskAction public void remap() throws IOException { - getParameters().execute(getExecOperations(), getInput().getAsFile().get(), getOutput().get().getAsFile(), getLibraries()); + + getParameters().execute(getExecOperations(), getInput().getAsFile().get(), getArchiveFile().get().getAsFile(), getLibraries()); } } From f586cddbb65a5b41f64cf9bb1e43ec7db41b4ea2 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sun, 1 Dec 2024 16:07:49 +0100 Subject: [PATCH 19/24] Review comments --- .../java/net/neoforged/moddevgradle/internal/ModDevPlugin.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java index 533df39d..bd236ed2 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java @@ -212,7 +212,8 @@ public void apply(Project project) { return split[2] + "-" + split[1]; }) .orElse(extension.getNeoFormArtifact().map(v -> "vanilla-" + v.split(":", 3)[2])), - // + // To support older versions of FML, that pick up the Minecraft jar by looking on the LCP for "forge-", + // we have to ensure client-extra does *not* start with "forge-". (dir, prefix) -> dir.file("client-extra-aka-minecraft-resources-" + prefix + ".jar") )); From 13a0a6b48f519d2aadc45d695e3329499043f5d6 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sun, 1 Dec 2024 16:16:31 +0100 Subject: [PATCH 20/24] Review comments --- .../internal/EclipseIntegration.java | 2 +- .../internal/IntelliJIntegration.java | 2 +- .../moddevgradle/internal/ModDevPlugin.java | 20 ++++++++++++++----- .../moddevgradle/internal/RunUtils.java | 10 ++++++++-- .../internal/VsCodeIntegration.java | 2 +- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/main/java/net/neoforged/moddevgradle/internal/EclipseIntegration.java b/src/main/java/net/neoforged/moddevgradle/internal/EclipseIntegration.java index 0b75953b..3a7e7324 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/EclipseIntegration.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/EclipseIntegration.java @@ -165,7 +165,7 @@ private void addEclipseLaunchConfiguration(Project project, RunUtils.escapeJvmArg(modFoldersProvider.getArgument()) ) .args(RunUtils.escapeJvmArg(RunUtils.getArgFileParameter(prepareTask.getProgramArgsFile().get()))) - .envVar(RunUtils.replaceModClassesEnv(run, () -> modFoldersProvider)) + .envVar(RunUtils.replaceModClassesEnv(run, modFoldersProvider)) .workingDirectory(run.getGameDirectory().get().getAsFile().getAbsolutePath()) .build(RunUtils.DEV_LAUNCH_MAIN_CLASS); writeEclipseLaunchConfig(project, launchConfigName, config); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/IntelliJIntegration.java b/src/main/java/net/neoforged/moddevgradle/internal/IntelliJIntegration.java index a8b1dfbe..0f8ed346 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/IntelliJIntegration.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/IntelliJIntegration.java @@ -190,7 +190,7 @@ private static void addIntelliJRunConfiguration(Project project, appRun.setModuleName(getIntellijModuleName(project, sourceSet)); appRun.setWorkingDirectory(run.getGameDirectory().get().getAsFile().getAbsolutePath()); var modFoldersProvider = getModFoldersProvider(project, outputDirectory, run.getLoadedMods(), null); - appRun.setEnvs(RunUtils.replaceModClassesEnv(run, () -> modFoldersProvider)); + appRun.setEnvs(RunUtils.replaceModClassesEnv(run, modFoldersProvider)); appRun.setJvmArgs( RunUtils.escapeJvmArg(RunUtils.getArgFileParameter(prepareTask.getVmArgsFile().get())) + " " diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java index bd236ed2..0938d0d8 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java @@ -16,6 +16,7 @@ import org.gradle.api.Named; import org.gradle.api.Plugin; import org.gradle.api.Project; +import org.gradle.api.Task; import org.gradle.api.artifacts.ConfigurablePublishArtifact; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.ExternalModuleDependency; @@ -212,7 +213,7 @@ public void apply(Project project) { return split[2] + "-" + split[1]; }) .orElse(extension.getNeoFormArtifact().map(v -> "vanilla-" + v.split(":", 3)[2])), - // To support older versions of FML, that pick up the Minecraft jar by looking on the LCP for "forge-", + // To support older versions of FML, which pick up the Minecraft jar by looking on the LCP for "forge-", // we have to ensure client-extra does *not* start with "forge-". (dir, prefix) -> dir.file("client-extra-aka-minecraft-resources-" + prefix + ".jar") )); @@ -503,6 +504,12 @@ static void setupRuns(Project project, spec.getDependencies().add(project.getDependencyFactory().create(RunUtils.DEV_LAUNCH_GAV)); }); + // Create an empty task similar to "assemble" which can be used to generate all launch scripts at once + var createLaunchScriptsTask= project.getTasks().register("createLaunchScripts", Task.class, task -> { + task.setGroup(branding.publicTaskGroup()); + task.setDescription("Creates batch files/shell scripts to launch the game from outside of Gradle (i.e. Renderdoc, NVidia Nsight, etc.)"); + }); + Map> prepareRunTasks = new IdentityHashMap<>(); runs.all(run -> { var prepareRunTask = setupRunInGradle( @@ -515,7 +522,8 @@ static void setupRuns(Project project, configureLegacyClasspath, assetPropertiesFile, devLaunchConfig, - neoFormVersion + neoFormVersion, + createLaunchScriptsTask ); prepareRunTasks.put(run, prepareRunTask); }); @@ -527,6 +535,7 @@ static void setupRuns(Project project, * to a single file that is * @param configureLegacyClasspath Callback to add entries to the legacy classpath. * @param assetPropertiesFile File that contains the asset properties file produced by NFRT. + * @param createLaunchScriptsTask */ private static TaskProvider setupRunInGradle( Project project, @@ -538,8 +547,8 @@ private static TaskProvider setupRunInGradle( Consumer configureLegacyClasspath, // TODO: can be removed in favor of directly passing a configuration for the moddev libraries Provider assetPropertiesFile, Configuration devLaunchConfig, - Provider neoFormVersion - ) { + Provider neoFormVersion, + TaskProvider createLaunchScriptsTask) { var ideIntegration = IdeIntegration.of(project, branding); var configurations = project.getConfigurations(); var javaExtension = ExtensionUtils.getExtension(project, "java", JavaPluginExtension.class); @@ -611,7 +620,7 @@ private static TaskProvider setupRunInGradle( }); ideIntegration.runTaskOnProjectSync(prepareRunTask); - tasks.register(InternalModelHelper.nameOfRun(run, "create", "launchScript"), CreateLaunchScriptTask.class, task -> { + var launchScriptTask = tasks.register(InternalModelHelper.nameOfRun(run, "create", "launchScript"), CreateLaunchScriptTask.class, task -> { task.setGroup(branding.internalTaskGroup()); task.setDescription("Creates a bash/shell-script to launch the " + run.getName() + " Minecraft run from outside Gradle or your IDE."); @@ -624,6 +633,7 @@ private static TaskProvider setupRunInGradle( task.getEnvironment().set(run.getEnvironment()); task.getModFolders().set(RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null)); }); + createLaunchScriptsTask.configure(task -> task.dependsOn(launchScriptTask)); tasks.register(InternalModelHelper.nameOfRun(run, "run", ""), RunGameTask.class, task -> { task.setGroup(branding.publicTaskGroup()); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java index fafb3c96..6b6c1017 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java @@ -222,11 +222,17 @@ public static Project findSourceSetProject(Project someProject, SourceSet source throw new IllegalArgumentException("Could not find project for source set " + someProject); } - public static Map replaceModClassesEnv(RunModel model, Supplier newProvider) { + /** + * In the run model, the environment variable "MOD_CLASSES" is set to the gradle output folders by the legacy plugin, + * since MDG itself completely ignores run-type specific environment variables. + * To ensure that in IDE runs, the IDE output folders are used, we replace the MOD_CLASSES environment variable + * explicitly. + */ + public static Map replaceModClassesEnv(RunModel model, ModFoldersProvider modFoldersProvider) { var vars = model.getEnvironment().get(); if (vars.containsKey("MOD_CLASSES")) { final var copy = new HashMap<>(vars); - copy.put("MOD_CLASSES", newProvider.get().getClassesArgument().get()); + copy.put("MOD_CLASSES", modFoldersProvider.getClassesArgument().get()); return copy; } return vars; diff --git a/src/main/java/net/neoforged/moddevgradle/internal/VsCodeIntegration.java b/src/main/java/net/neoforged/moddevgradle/internal/VsCodeIntegration.java index 827761b0..e3e35cf5 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/VsCodeIntegration.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/VsCodeIntegration.java @@ -76,7 +76,7 @@ private void addVscodeLaunchConfiguration(Project project, .withArguments(List.of(RunUtils.getArgFileParameter(prepareTask.getProgramArgsFile().get()))) .withAdditionalJvmArgs(List.of(RunUtils.getArgFileParameter(prepareTask.getVmArgsFile().get()), modFoldersProvider.getArgument())) - .withEnvironmentVariables(RunUtils.replaceModClassesEnv(run, () -> modFoldersProvider)) + .withEnvironmentVariables(RunUtils.replaceModClassesEnv(run, modFoldersProvider)) .withMainClass(RunUtils.DEV_LAUNCH_MAIN_CLASS) .withShortenCommandLine(ShortCmdBehaviour.NONE) .withConsoleType(ConsoleType.INTERNAL_CONSOLE) From 1baf59ed07cb0a224decf9c1a549e3b094f43030 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sun, 1 Dec 2024 16:37:51 +0100 Subject: [PATCH 21/24] call publishing as part of running the tests --- .github/workflows/build-prs.yml | 2 +- testproject/build.gradle | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-prs.yml b/.github/workflows/build-prs.yml index 21e4db2c..b5c506a1 100644 --- a/.github/workflows/build-prs.yml +++ b/.github/workflows/build-prs.yml @@ -47,7 +47,7 @@ jobs: uses: gradle/actions/setup-gradle@v3 - name: Run build - run: ./gradlew build neoForgeIdeSync + run: ./gradlew build neoForgeIdeSync publish working-directory: ./${{ matrix.project }} - name: Ensure clean, build and test work in the same run diff --git a/testproject/build.gradle b/testproject/build.gradle index b5cdd805..44cdcbe5 100644 --- a/testproject/build.gradle +++ b/testproject/build.gradle @@ -1,5 +1,6 @@ plugins { id 'net.neoforged.moddev' + id 'maven-publish' } evaluationDependsOn(":subproject") // Because of the sourceset reference @@ -8,6 +9,8 @@ sourceSets { api } +group = "mdgtestproject" + dependencies { testImplementation(enforcedPlatform("org.junit:junit-bom:5.10.2")) testImplementation 'org.junit.jupiter:junit-jupiter' @@ -87,3 +90,16 @@ neoFormRuntime { // enableCache = false // verbose = true } + +publishing { + publications { + maven(MavenPublication) { + from components.java + } + } + repositories { + maven { + url rootProject.file('repo') + } + } +} From 45f57d82ff85f7aa35488f3eec842537a55e0a02 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sun, 1 Dec 2024 17:04:15 +0100 Subject: [PATCH 22/24] Review comments --- .../{internal => dsl}/Obfuscation.java | 45 ++++++++++++++----- .../internal/LegacyForgeModDevPlugin.java | 18 ++++---- .../internal/McpMetadataTransform.java | 1 - .../internal/RemappingTransform.java | 6 +-- .../{internal => tasks}/RemapJar.java | 17 ++++--- .../RemapOperation.java} | 31 +++++-------- .../moddevgradle/dsl/InternalModelHelper.java | 1 - .../moddevgradle/internal/RunGameTask.java | 1 - .../moddevgradle/internal/RunUtils.java | 1 - .../internal/WriteLegacyClasspath.java | 2 - .../jarjar/ResolvedJarJarArtifact.java | 1 - .../functional/KotlinScriptTest.java | 5 --- .../functional/ValidationTests.java | 2 - 13 files changed, 65 insertions(+), 66 deletions(-) rename src/legacy/java/net/neoforged/moddevgradle/legacyforge/{internal => dsl}/Obfuscation.java (76%) rename src/legacy/java/net/neoforged/moddevgradle/legacyforge/{internal => tasks}/RemapJar.java (76%) rename src/legacy/java/net/neoforged/moddevgradle/legacyforge/{internal/RemapParameters.java => tasks/RemapOperation.java} (79%) diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/Obfuscation.java similarity index 76% rename from src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java rename to src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/Obfuscation.java index 83e2b259..deb32126 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/Obfuscation.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/Obfuscation.java @@ -1,5 +1,8 @@ -package net.neoforged.moddevgradle.legacyforge.internal; +package net.neoforged.moddevgradle.legacyforge.dsl; +import net.neoforged.moddevgradle.legacyforge.internal.LegacyForgeModDevPlugin; +import net.neoforged.moddevgradle.legacyforge.tasks.RemapJar; +import net.neoforged.moddevgradle.legacyforge.tasks.RemapOperation; import org.apache.commons.lang3.StringUtils; import org.gradle.api.Action; import org.gradle.api.Project; @@ -14,18 +17,24 @@ import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.TaskProvider; import org.gradle.api.tasks.bundling.AbstractArchiveTask; +import org.jetbrains.annotations.ApiStatus; import javax.inject.Inject; import java.util.List; -abstract class Obfuscation { +public abstract class Obfuscation { private final Project project; - final Provider officialToSrg, mappingsCsv; - final Configuration autoRenamingToolRuntime; - final Configuration installerToolsRuntime; + private final Provider officialToSrg; + private final Provider mappingsCsv; + private final Configuration autoRenamingToolRuntime; + private final Configuration installerToolsRuntime; @Inject - public Obfuscation(Project project, Provider officialToSrg, Provider mappingsCsv, Configuration autoRenamingToolRuntime, Configuration installerToolsRuntime) { + public Obfuscation(Project project, + Provider officialToSrg, + Provider mappingsCsv, + Configuration autoRenamingToolRuntime, + Configuration installerToolsRuntime) { this.project = project; this.officialToSrg = officialToSrg; this.mappingsCsv = mappingsCsv; @@ -33,8 +42,22 @@ public Obfuscation(Project project, Provider officialToSrg, Provide this.installerToolsRuntime = installerToolsRuntime; } + @ApiStatus.Internal + public void configureAutoRenamingToolOperation(RemapOperation operation) { + operation.getToolType().set(RemapOperation.ToolType.ART); + operation.getToolClasspath().from(autoRenamingToolRuntime); + operation.getMappings().from(officialToSrg); + } + + @ApiStatus.Internal + public void configureInstallerToolsOperation(RemapOperation operation) { + operation.getToolType().set(RemapOperation.ToolType.INSTALLER_TOOLS); + operation.getToolClasspath().from(installerToolsRuntime); + operation.getMappings().from(mappingsCsv); + } + /** - * Create a configure a reobfuscation task. + * Create and configure a reobfuscation task. * * @param jar the jar task to reobfuscate * @param sourceSet the source set whose classpath to use when remapping inherited methods @@ -42,9 +65,8 @@ public Obfuscation(Project project, Provider officialToSrg, Provide * @return a provider of the created task */ public TaskProvider reobfuscate(TaskProvider jar, - SourceSet sourceSet, - Action configuration) { - + SourceSet sourceSet, + Action configuration) { var reobf = project.getTasks().register("reobf" + StringUtils.capitalize(jar.getName()), RemapJar.class, task -> { task.getInput().set(jar.flatMap(AbstractArchiveTask::getArchiveFile)); @@ -54,7 +76,7 @@ public TaskProvider reobfuscate(TaskProvider reobfuscate(TaskProvider { diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java index 3c9c36cb..0b7d6daf 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java @@ -4,6 +4,7 @@ import net.neoforged.moddevgradle.internal.LegacyForgeFacade; import net.neoforged.moddevgradle.internal.ModDevPlugin; import net.neoforged.moddevgradle.legacyforge.dsl.MixinExtension; +import net.neoforged.moddevgradle.legacyforge.dsl.Obfuscation; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.artifacts.type.ArtifactTypeDefinition; @@ -13,14 +14,19 @@ import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSetContainer; import org.gradle.jvm.tasks.Jar; +import org.jetbrains.annotations.ApiStatus; import java.net.URI; import java.util.Map; import java.util.stream.Stream; +@ApiStatus.Internal public class LegacyForgeModDevPlugin implements Plugin { public static final Attribute REMAPPED = Attribute.of("net.neoforged.moddevgradle.legacy.remapped", Boolean.class); + public static final String CONFIGURATION_TOOL_ART = "autoRenamingToolRuntime"; + public static final String CONFIGURATION_TOOL_INSTALLERTOOLS = "installerToolsRuntime"; + @Override public void apply(Project project) { project.getPlugins().apply(ModDevPlugin.class); @@ -36,14 +42,14 @@ public void apply(Project project) { project.getDependencies().getComponents().withModule("de.oceanlabs.mcp:mcp_config", McpMetadataTransform.class); var depFactory = project.getDependencyFactory(); - var autoRenamingToolRuntime = project.getConfigurations().create("autoRenamingToolRuntime", spec -> { + var autoRenamingToolRuntime = project.getConfigurations().create(CONFIGURATION_TOOL_ART, spec -> { spec.setDescription("The AutoRenamingTool CLI tool"); spec.setCanBeConsumed(false); spec.setCanBeResolved(true); spec.setTransitive(false); spec.getDependencies().add(depFactory.create("net.neoforged:AutoRenamingTool:2.0.4:all")); }); - var installerToolsRuntime = project.getConfigurations().create("installerToolsRuntime", spec -> { + var installerToolsRuntime = project.getConfigurations().create(CONFIGURATION_TOOL_INSTALLERTOOLS, spec -> { spec.setDescription("The InstallerTools CLI tool"); spec.setCanBeConsumed(false); spec.setCanBeResolved(true); @@ -85,7 +91,7 @@ public void apply(Project project) { project.getTasks().named(JavaPlugin.JAR_TASK_NAME, Jar.class), project.getExtensions().getByType(SourceSetContainer.class).getByName(SourceSet.MAIN_SOURCE_SET_NAME), task -> { - task.getParameters().getMappings().from(extraMixinMappings); + task.getRemapOperation().getMappings().from(extraMixinMappings); } ); @@ -115,11 +121,7 @@ public void apply(Project project) { project.getDependencies().registerTransform(RemappingTransform.class, params -> { params.parameters(parameters -> { - parameters.getParameters().set(project.provider(() -> { - var p = project.getObjects().newInstance(RemapParameters.class); - p.from(obf, RemapParameters.ToolType.INSTALLER_TOOLS); - return p; - })); + obf.configureInstallerToolsOperation(parameters.getRemapOperation()); parameters.getMinecraftDependencies().from(remapDeps); }); params.getFrom() diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/McpMetadataTransform.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/McpMetadataTransform.java index db7c0546..5578c17b 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/McpMetadataTransform.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/McpMetadataTransform.java @@ -7,7 +7,6 @@ import org.gradle.api.artifacts.ComponentMetadataContext; import org.gradle.api.artifacts.DirectDependenciesMetadata; import org.gradle.api.artifacts.repositories.RepositoryResourceAccessor; -import org.gradle.api.artifacts.transform.CacheableTransform; import org.gradle.api.attributes.Usage; import org.gradle.api.attributes.java.TargetJvmVersion; import org.gradle.api.model.ObjectFactory; diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemappingTransform.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemappingTransform.java index 9e3c845b..114b7134 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemappingTransform.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemappingTransform.java @@ -1,5 +1,6 @@ package net.neoforged.moddevgradle.legacyforge.internal; +import net.neoforged.moddevgradle.legacyforge.tasks.RemapOperation; import org.gradle.api.artifacts.transform.CacheableTransform; import org.gradle.api.artifacts.transform.InputArtifact; import org.gradle.api.artifacts.transform.InputArtifactDependencies; @@ -9,7 +10,6 @@ import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileSystemLocation; -import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.CompileClasspath; import org.gradle.api.tasks.InputFiles; @@ -46,7 +46,7 @@ public void transform(TransformOutputs outputs) { var mappedFile = outputs.file(inputFile.getName()); try { - getParameters().getParameters().get() + getParameters().getRemapOperation() .execute( getExecOperations(), inputFile, @@ -60,7 +60,7 @@ public void transform(TransformOutputs outputs) { public interface Parameters extends TransformParameters { @Nested - Property getParameters(); + RemapOperation getRemapOperation(); @InputFiles @PathSensitive(PathSensitivity.NONE) diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapJar.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/tasks/RemapJar.java similarity index 76% rename from src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapJar.java rename to src/legacy/java/net/neoforged/moddevgradle/legacyforge/tasks/RemapJar.java index 061fd6a2..a3a3786b 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapJar.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/tasks/RemapJar.java @@ -1,4 +1,4 @@ -package net.neoforged.moddevgradle.legacyforge.internal; +package net.neoforged.moddevgradle.legacyforge.tasks; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.RegularFileProperty; @@ -16,14 +16,10 @@ /** * Task used to remap a jar using AutoRenamingTool. */ -abstract class RemapJar extends Jar { +public abstract class RemapJar extends Jar { @Nested - protected abstract RemapParameters getParameters(); - - @Inject - public RemapJar() { - } + public abstract RemapOperation getRemapOperation(); /** * The libraries to use for inheritance data during the renaming process. @@ -38,9 +34,12 @@ public RemapJar() { @Inject protected abstract ExecOperations getExecOperations(); + @Inject + public RemapJar() { + } + @TaskAction public void remap() throws IOException { - - getParameters().execute(getExecOperations(), getInput().getAsFile().get(), getArchiveFile().get().getAsFile(), getLibraries()); + getRemapOperation().execute(getExecOperations(), getInput().getAsFile().get(), getArchiveFile().get().getAsFile(), getLibraries()); } } diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapParameters.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/tasks/RemapOperation.java similarity index 79% rename from src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapParameters.java rename to src/legacy/java/net/neoforged/moddevgradle/legacyforge/tasks/RemapOperation.java index c4809a57..312a071a 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/RemapParameters.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/tasks/RemapOperation.java @@ -1,4 +1,4 @@ -package net.neoforged.moddevgradle.legacyforge.internal; +package net.neoforged.moddevgradle.legacyforge.tasks; import net.neoforged.moddevgradle.internal.utils.NetworkSettingPassthrough; import org.gradle.api.file.ConfigurableFileCollection; @@ -23,35 +23,24 @@ import java.util.Arrays; import java.util.List; -abstract class RemapParameters implements Serializable { +public abstract class RemapOperation implements Serializable { @Inject - public RemapParameters() {} + public RemapOperation() {} + + @Input + public abstract Property getToolType(); @Classpath @InputFiles - protected abstract ConfigurableFileCollection getToolClasspath(); + public abstract ConfigurableFileCollection getToolClasspath(); + + @Internal + protected abstract RegularFileProperty getLogFile(); @InputFiles @PathSensitive(PathSensitivity.NONE) public abstract ConfigurableFileCollection getMappings(); - @Internal - public abstract RegularFileProperty getLogFile(); - - @Input - public abstract Property getToolType(); - - public void from(Obfuscation reobfuscation, ToolType toolType) { - getToolType().set(toolType); - if (toolType == ToolType.ART) { - getToolClasspath().from(reobfuscation.autoRenamingToolRuntime); - getMappings().from(reobfuscation.officialToSrg); - } else { - getToolClasspath().from(reobfuscation.installerToolsRuntime); - getMappings().from(reobfuscation.mappingsCsv); - } - } - public void execute(ExecOperations operations, File input, File output, FileCollection libraries) throws IOException { final List args = new ArrayList<>(); diff --git a/src/main/java/net/neoforged/moddevgradle/dsl/InternalModelHelper.java b/src/main/java/net/neoforged/moddevgradle/dsl/InternalModelHelper.java index 1650b2c9..aaa18a70 100644 --- a/src/main/java/net/neoforged/moddevgradle/dsl/InternalModelHelper.java +++ b/src/main/java/net/neoforged/moddevgradle/dsl/InternalModelHelper.java @@ -1,7 +1,6 @@ package net.neoforged.moddevgradle.dsl; import net.neoforged.moddevgradle.internal.utils.StringUtils; -import org.gradle.api.artifacts.Configuration; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/net/neoforged/moddevgradle/internal/RunGameTask.java b/src/main/java/net/neoforged/moddevgradle/internal/RunGameTask.java index 88e70af8..518f2a28 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/RunGameTask.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/RunGameTask.java @@ -15,7 +15,6 @@ import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.Files; -import java.util.HashMap; /** * By extending JavaExec, we allow IntelliJ to automatically attach a debugger to the forked JVM, making diff --git a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java index 6b6c1017..aa9375a1 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java @@ -38,7 +38,6 @@ import java.util.Properties; import java.util.Set; import java.util.function.BiConsumer; -import java.util.function.Supplier; import java.util.stream.Collectors; final class RunUtils { diff --git a/src/main/java/net/neoforged/moddevgradle/internal/WriteLegacyClasspath.java b/src/main/java/net/neoforged/moddevgradle/internal/WriteLegacyClasspath.java index 9941e147..3f6ad03e 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/WriteLegacyClasspath.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/WriteLegacyClasspath.java @@ -2,11 +2,9 @@ import net.neoforged.moddevgradle.internal.utils.FileUtils; import org.gradle.api.DefaultTask; -import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.provider.ListProperty; import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; diff --git a/src/main/java/net/neoforged/moddevgradle/internal/jarjar/ResolvedJarJarArtifact.java b/src/main/java/net/neoforged/moddevgradle/internal/jarjar/ResolvedJarJarArtifact.java index 5c2aa1b1..7a774e92 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/jarjar/ResolvedJarJarArtifact.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/jarjar/ResolvedJarJarArtifact.java @@ -10,7 +10,6 @@ import org.gradle.api.tasks.InputFile; import org.gradle.api.tasks.PathSensitive; import org.gradle.api.tasks.PathSensitivity; -import org.gradle.api.tasks.SourceSet; import java.io.File; import java.io.IOException; diff --git a/src/test/java/net/neoforged/moddevgradle/functional/KotlinScriptTest.java b/src/test/java/net/neoforged/moddevgradle/functional/KotlinScriptTest.java index e82f5705..1b2cafa1 100644 --- a/src/test/java/net/neoforged/moddevgradle/functional/KotlinScriptTest.java +++ b/src/test/java/net/neoforged/moddevgradle/functional/KotlinScriptTest.java @@ -3,13 +3,8 @@ import org.gradle.testkit.runner.BuildResult; import org.gradle.testkit.runner.GradleRunner; import org.gradle.testkit.runner.TaskOutcome; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; import java.io.IOException; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/net/neoforged/moddevgradle/functional/ValidationTests.java b/src/test/java/net/neoforged/moddevgradle/functional/ValidationTests.java index 4e657890..ac493d71 100644 --- a/src/test/java/net/neoforged/moddevgradle/functional/ValidationTests.java +++ b/src/test/java/net/neoforged/moddevgradle/functional/ValidationTests.java @@ -4,9 +4,7 @@ import org.gradle.testkit.runner.GradleRunner; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; -import java.io.File; import java.io.IOException; import java.nio.file.Files; From 46172f3cf3189fc25e7e384e4fb0d1112e902332 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sun, 1 Dec 2024 17:05:20 +0100 Subject: [PATCH 23/24] Review comments --- .../neoforged/moddevgradle/legacyforge/dsl/Obfuscation.java | 6 +++--- .../legacyforge/internal/LegacyForgeModDevPlugin.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/Obfuscation.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/Obfuscation.java index deb32126..895d7258 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/Obfuscation.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/Obfuscation.java @@ -43,14 +43,14 @@ public Obfuscation(Project project, } @ApiStatus.Internal - public void configureAutoRenamingToolOperation(RemapOperation operation) { + public void configureSrgToNamedOperation(RemapOperation operation) { operation.getToolType().set(RemapOperation.ToolType.ART); operation.getToolClasspath().from(autoRenamingToolRuntime); operation.getMappings().from(officialToSrg); } @ApiStatus.Internal - public void configureInstallerToolsOperation(RemapOperation operation) { + public void configureNamedToSrgOperation(RemapOperation operation) { operation.getToolType().set(RemapOperation.ToolType.INSTALLER_TOOLS); operation.getToolClasspath().from(installerToolsRuntime); operation.getMappings().from(mappingsCsv); @@ -76,7 +76,7 @@ public TaskProvider reobfuscate(TaskProvider { params.parameters(parameters -> { - obf.configureInstallerToolsOperation(parameters.getRemapOperation()); + obf.configureNamedToSrgOperation(parameters.getRemapOperation()); parameters.getMinecraftDependencies().from(remapDeps); }); params.getFrom() From eebbfd7387ab4e6fe1a7995ac2b5b6ae13b59946 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sun, 1 Dec 2024 17:17:14 +0100 Subject: [PATCH 24/24] Review comments --- .../neoforged/moddevgradle/legacyforge/dsl/Obfuscation.java | 6 +++--- .../legacyforge/internal/LegacyForgeModDevPlugin.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/Obfuscation.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/Obfuscation.java index 895d7258..d417b2de 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/Obfuscation.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/dsl/Obfuscation.java @@ -43,14 +43,14 @@ public Obfuscation(Project project, } @ApiStatus.Internal - public void configureSrgToNamedOperation(RemapOperation operation) { + public void configureNamedToSrgOperation(RemapOperation operation) { operation.getToolType().set(RemapOperation.ToolType.ART); operation.getToolClasspath().from(autoRenamingToolRuntime); operation.getMappings().from(officialToSrg); } @ApiStatus.Internal - public void configureNamedToSrgOperation(RemapOperation operation) { + public void configureSrgToNamedOperation(RemapOperation operation) { operation.getToolType().set(RemapOperation.ToolType.INSTALLER_TOOLS); operation.getToolClasspath().from(installerToolsRuntime); operation.getMappings().from(mappingsCsv); @@ -76,7 +76,7 @@ public TaskProvider reobfuscate(TaskProvider { params.parameters(parameters -> { - obf.configureNamedToSrgOperation(parameters.getRemapOperation()); + obf.configureSrgToNamedOperation(parameters.getRemapOperation()); parameters.getMinecraftDependencies().from(remapDeps); }); params.getFrom()