From 203f3af6305c2b5b113a506cbf16e8b1e54d38da Mon Sep 17 00:00:00 2001 From: Jonathing Date: Thu, 18 Dec 2025 06:13:56 -0500 Subject: [PATCH 1/4] Rework how Minecraft dependencies are handled --- build.gradle | 2 + settings.gradle | 8 +- .../gradle/MinecraftDependency.java | 33 +++- .../gradle/MinecraftExtensionForProject.java | 6 +- .../gradle/internal/ClosureOwnerInternal.java | 12 ++ .../gradle/internal/Constants.java | 2 +- .../gradle/internal/ForgeAttributes.java | 103 ++++++++++++ .../internal/MinecraftDependencyImpl.java | 145 ++++++++-------- .../internal/MinecraftDependencyInternal.java | 12 +- .../internal/MinecraftExtensionImpl.java | 158 ++++++++---------- .../internal/MinecraftExtensionInternal.java | 13 +- .../gradle/internal/OperatingSystemName.java | 30 ---- .../gradle/internal/SlimeLauncherExec.java | 4 +- 13 files changed, 327 insertions(+), 201 deletions(-) create mode 100644 src/main/java/net/minecraftforge/gradle/internal/ForgeAttributes.java delete mode 100644 src/main/java/net/minecraftforge/gradle/internal/OperatingSystemName.java diff --git a/build.gradle b/build.gradle index 254b9d78f..d3669aa8e 100644 --- a/build.gradle +++ b/build.gradle @@ -64,6 +64,7 @@ dependencies { compileOnlyApi libs.accesstransformers.gradle // Utils + implementation libs.maven.artifact implementation libs.bundles.utils } @@ -92,6 +93,7 @@ tasks.named('shadowJar', ShadowJar) { archiveClassifier = null relocationPrefix = 'net.minecraftforge.gradle.shadow' + minimize() dependencies { exclude dependency(projects.runtimeEnvironmentCheck) exclude dependency(libs.annotations.jspecify) diff --git a/settings.gradle b/settings.gradle index c4ee449a9..b244684d8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -17,7 +17,7 @@ gradle.beforeProject { Project project -> mavenCentral() gradlePluginPortal() maven project.gradleutils.forgeMaven - //mavenLocal() + mavenLocal() } } } @@ -43,12 +43,16 @@ dependencyResolutionManagement.versionCatalogs.register('libs') { library 'gradle', 'name.remal.gradle-api', 'gradle-api' versionRef 'gradle' // GradleUtils Shared Base - library 'gradleutils-shared', 'net.minecraftforge', 'gradleutils-shared' versionRef 'gradleutils' + //library 'gradleutils-shared', 'net.minecraftforge', 'gradleutils-shared' versionRef 'gradleutils' + library 'gradleutils-shared', 'net.minecraftforge', 'gradleutils-shared' version '3.3.40' // AccessTransformers Gradle Plugin // https://plugins.gradle.org/plugin/net.minecraftforge.accesstransformers library 'accesstransformers-gradle', 'net.minecraftforge.accesstransformers', 'net.minecraftforge.accesstransformers.gradle.plugin' version '5.0.1' + // Artifact Versioning + library 'maven-artifact', 'org.apache.maven', 'maven-artifact' version '3.9.11' + library 'utils-data', 'net.minecraftforge', 'json-data-utils' version '0.4.1' // https://files.minecraftforge.net/net/minecraftforge/json-data-utils/index.html library 'utils-os', 'net.minecraftforge', 'os-utils' version '0.1.0' // https://files.minecraftforge.net/net/minecraftforge/os-utils/index.html library 'utils-hash', 'net.minecraftforge', 'hash-utils' version '0.1.12' // https://files.minecraftforge.net/net/minecraftforge/hash-utils/index.html diff --git a/src/main/java/net/minecraftforge/gradle/MinecraftDependency.java b/src/main/java/net/minecraftforge/gradle/MinecraftDependency.java index 321882c22..f970bf466 100644 --- a/src/main/java/net/minecraftforge/gradle/MinecraftDependency.java +++ b/src/main/java/net/minecraftforge/gradle/MinecraftDependency.java @@ -4,6 +4,37 @@ */ package net.minecraftforge.gradle; +import groovy.lang.Closure; +import groovy.lang.DelegatesTo; +import groovy.transform.stc.ClosureParams; +import groovy.transform.stc.FromString; +import net.minecraftforge.gradleutils.shared.Closures; +import org.gradle.api.Action; +import org.gradle.api.NamedDomainObjectContainer; + /// The Minecraft dependency contains information essential for how the /// {@linkplain MinecraftExtensionForProject minecraft extension} processes Minecraft dependencies. -public interface MinecraftDependency extends MinecraftMappingsContainer { } +public interface MinecraftDependency extends MinecraftMappingsContainer { + /// The collection of Slime Launcher options with which to create the launcher tasks. + /// + /// @return The collection of run task options + NamedDomainObjectContainer getRuns(); + + /// Configures the Slime Launcher options for this project, which will be used to create the launcher tasks. + /// + /// @param closure The configuring closure + default void runs( + @DelegatesTo(NamedDomainObjectContainer.class) + @ClosureParams(value = FromString.class, options = "org.gradle.api.NamedDomainObjectContainer") + Closure closure + ) { + this.getRuns().configure(closure); + } + + /// Configures the Slime Launcher options for this project, which will be used to create the launcher tasks. + /// + /// @param action The configuring action + default void runs(Action> action) { + this.runs(Closures.action(this, action)); + } +} diff --git a/src/main/java/net/minecraftforge/gradle/MinecraftExtensionForProject.java b/src/main/java/net/minecraftforge/gradle/MinecraftExtensionForProject.java index 4960def27..830a1d7ed 100644 --- a/src/main/java/net/minecraftforge/gradle/MinecraftExtensionForProject.java +++ b/src/main/java/net/minecraftforge/gradle/MinecraftExtensionForProject.java @@ -27,11 +27,13 @@ public interface MinecraftExtensionForProject extends Mi /// Configures the Slime Launcher options for this project, which will be used to create the launcher tasks. /// /// @param closure The configuring closure - void runs( + default void runs( @DelegatesTo(NamedDomainObjectContainer.class) @ClosureParams(value = FromString.class, options = "org.gradle.api.NamedDomainObjectContainer") Closure closure - ); + ) { + this.getRuns().configure(closure); + } /// Configures the Slime Launcher options for this project, which will be used to create the launcher tasks. /// diff --git a/src/main/java/net/minecraftforge/gradle/internal/ClosureOwnerInternal.java b/src/main/java/net/minecraftforge/gradle/internal/ClosureOwnerInternal.java index a32a7e8d7..7f4ce6f33 100644 --- a/src/main/java/net/minecraftforge/gradle/internal/ClosureOwnerInternal.java +++ b/src/main/java/net/minecraftforge/gradle/internal/ClosureOwnerInternal.java @@ -10,7 +10,9 @@ import groovy.transform.NamedParams; import net.minecraftforge.gradle.ClosureOwner; import net.minecraftforge.gradle.MinecraftMappings; +import net.minecraftforge.gradle.SlimeLauncherOptions; import org.gradle.api.Action; +import org.gradle.api.NamedDomainObjectContainer; import org.gradle.api.artifacts.DependencyArtifact; import org.gradle.api.artifacts.ExcludeRule; import org.gradle.api.artifacts.ExternalModuleDependency; @@ -82,6 +84,11 @@ default void mappings( this.getOwnerDelegate().mappings(namedArgs); } + @Override + default NamedDomainObjectContainer getRuns() { + return this.getOwnerDelegate().getRuns(); + } + @Override default boolean isChanging() { throw stub(); @@ -288,6 +295,11 @@ default void mappings( this.getOwnerDelegate().mappings(namedArgs); } + @Override + default NamedDomainObjectContainer getRuns() { + return this.getOwnerDelegate().getRuns(); + } + @Override default boolean isChanging() { throw stub(); diff --git a/src/main/java/net/minecraftforge/gradle/internal/Constants.java b/src/main/java/net/minecraftforge/gradle/internal/Constants.java index 93ab9fe61..2c6bc1183 100644 --- a/src/main/java/net/minecraftforge/gradle/internal/Constants.java +++ b/src/main/java/net/minecraftforge/gradle/internal/Constants.java @@ -20,7 +20,7 @@ final class Constants { static final String SLIMELAUNCHER_MAIN = "net.minecraftforge.launcher.Main"; static final String MAVENIZER_NAME = "mavenizer"; - static final String MAVENIZER_VERSION = "0.4.14"; + static final String MAVENIZER_VERSION = "0.4.15"; static final String MAVENIZER_DL_URL = "https://maven.minecraftforge.net/net/minecraftforge/minecraft-mavenizer/" + MAVENIZER_VERSION + "/minecraft-mavenizer-" + MAVENIZER_VERSION + ".jar"; static final int MAVENIZER_JAVA_VERSION = 25; static final String MAVENIZER_MAIN = "net.minecraftforge.mcmaven.cli.Main"; diff --git a/src/main/java/net/minecraftforge/gradle/internal/ForgeAttributes.java b/src/main/java/net/minecraftforge/gradle/internal/ForgeAttributes.java new file mode 100644 index 000000000..1be8e04e5 --- /dev/null +++ b/src/main/java/net/minecraftforge/gradle/internal/ForgeAttributes.java @@ -0,0 +1,103 @@ +package net.minecraftforge.gradle.internal; + +import net.minecraftforge.util.os.OS; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; +import org.gradle.api.Action; +import org.gradle.api.attributes.Attribute; +import org.gradle.api.attributes.AttributeDisambiguationRule; +import org.gradle.api.attributes.MultipleCandidatesDetails; +import org.gradle.api.provider.SetProperty; +import org.gradle.api.provider.ValueSource; +import org.gradle.api.provider.ValueSourceParameters; +import org.gradle.api.provider.ValueSourceSpec; +import org.jspecify.annotations.NullUnmarked; +import org.jspecify.annotations.Nullable; + +import javax.inject.Inject; +import java.util.Comparator; +import java.util.EnumSet; +import java.util.Set; + +final class ForgeAttributes { + static final class OperatingSystem { + static final Attribute ATTRIBUTE = Attribute.of("net.minecraftforge.native.operatingSystem", String.class); + + static abstract class DisambiguationRule implements AttributeDisambiguationRule { + private final OS current; + + @Inject + public DisambiguationRule(OS current) { + this.current = current; + } + + @Override + public void execute(MultipleCandidatesDetails details) { + var options = details.getCandidateValues().stream().map(OS::byKey).toList(); + + if (options.contains(current)) { + details.closestMatch(current.key()); + return; + } + + for (var os : options) { + var fallback = execute(current, os); + if (fallback != null) { + details.closestMatch(fallback); + return; + } + } + } + + @NullUnmarked + private String execute(OS current, OS os) { + return current == os + ? os.key() + : os != null ? execute(current, os.fallback()) : null; + } + } + + abstract static class CurrentValue implements ValueSource { + interface Parameters extends ValueSourceParameters { + Action> DEFAULT = spec -> spec.getParameters().getAllowedOperatingSystems().set(Set.of(OS.WINDOWS, OS.MACOS, OS.LINUX)); + + SetProperty getAllowedOperatingSystems(); + } + + @Inject + public CurrentValue() { } + + @Override + public @Nullable OS obtain() { + var allowed = getParameters().getAllowedOperatingSystems().getOrElse(EnumSet.noneOf(OS.class)).toArray(new OS[0]); + return allowed.length > 0 + ? OS.current(allowed) + : OS.current(); + } + } + } + + static final class MappingsChannel { + static final Attribute ATTRIBUTE = Attribute.of("net.minecraftforge.mappings.channel", String.class); + + static abstract class DisambiguationRule implements AttributeDisambiguationRule { + @Inject + public DisambiguationRule() { } + + @Override + public void execute(MultipleCandidatesDetails details) { + var options = details.getCandidateValues(); + if (options.contains("official")) { + details.closestMatch("official"); + } else if (options.contains("parchment")) { + details.closestMatch("parchment"); + } + } + } + } + + static final class MappingsVersion { + static final Attribute ATTRIBUTE = Attribute.of("net.minecraftforge.mappings.version", String.class); + + static final Comparator COMPARATOR = Comparator.comparing(DefaultArtifactVersion::new); + } +} diff --git a/src/main/java/net/minecraftforge/gradle/internal/MinecraftDependencyImpl.java b/src/main/java/net/minecraftforge/gradle/internal/MinecraftDependencyImpl.java index 51352b140..9b71d8cd8 100644 --- a/src/main/java/net/minecraftforge/gradle/internal/MinecraftDependencyImpl.java +++ b/src/main/java/net/minecraftforge/gradle/internal/MinecraftDependencyImpl.java @@ -9,12 +9,15 @@ import net.minecraftforge.accesstransformers.gradle.ArtifactAccessTransformer; import net.minecraftforge.gradle.MinecraftDependencyWithAccessTransformers; import net.minecraftforge.gradle.MinecraftExtension; +import net.minecraftforge.gradle.MinecraftExtensionForProject; import net.minecraftforge.gradle.MinecraftExtensionForProjectWithAccessTransformers; import net.minecraftforge.gradle.MinecraftMappings; +import net.minecraftforge.gradle.SlimeLauncherOptions; import net.minecraftforge.gradleutils.shared.Closures; -import net.minecraftforge.util.os.OS; import org.gradle.api.Action; import org.gradle.api.InvalidUserCodeException; +import org.gradle.api.NamedDomainObjectContainer; +import org.gradle.api.NamedDomainObjectSet; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Dependency; @@ -23,8 +26,11 @@ import org.gradle.api.artifacts.type.ArtifactTypeDefinition; import org.gradle.api.attributes.Attribute; import org.gradle.api.attributes.AttributeContainer; +import org.gradle.api.attributes.AttributeDisambiguationRule; import org.gradle.api.attributes.Category; +import org.gradle.api.attributes.MultipleCandidatesDetails; import org.gradle.api.file.Directory; +import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.ProjectLayout; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.flow.FlowProviders; @@ -37,6 +43,7 @@ import org.gradle.api.provider.ProviderFactory; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.TaskProvider; +import org.gradle.plugins.ide.eclipse.model.EclipseModel; import org.jspecify.annotations.Nullable; import javax.inject.Inject; @@ -48,14 +55,17 @@ abstract class MinecraftDependencyImpl implements MinecraftDependencyInternal { // These can be nullable due to configuration caching. private transient @Nullable ExternalModuleDependency delegate; private transient @Nullable TaskProvider mavenizer; + private transient @Nullable NamedDomainObjectContainer runs; + + private final MinecraftExtensionImpl.ForProjectImpl minecraft; final Property asString = getObjects().property(String.class); final Property asPath = getObjects().property(String.class); final Property module = getObjects().property(ModuleIdentifier.class); final Property version = getObjects().property(String.class); - private final Provider mavenizerOutput; - private final Property mappings; + private final DirectoryProperty mavenizerOutput = getObjects().directoryProperty(); + private final Property mappings = this.getObjects().property(MinecraftMappingsImpl.class); private @Nullable String sourceSetName; private final ForgeGradleProblems problems = this.getObjects().newInstance(ForgeGradleProblems.class); @@ -74,10 +84,16 @@ abstract class MinecraftDependencyImpl implements MinecraftDependencyInternal { @Inject public MinecraftDependencyImpl(Provider mavenizerOutput) { - this.mavenizerOutput = mavenizerOutput; - this.mappings = this.getObjects().property(MinecraftMappingsImpl.class).convention( - ((MinecraftExtensionImpl) getProject().getExtensions().getByType(MinecraftExtension.class)).mappings - ); + this.minecraft = ((MinecraftExtensionImpl.ForProjectImpl) getProject().getExtensions().getByType(MinecraftExtensionForProject.class)); + + this.mavenizerOutput.set(mavenizerOutput); + this.mappings.convention(minecraft.mappings); + } + + // Can be nullable due to configuration caching. + @Override + public @Nullable NamedDomainObjectContainer getRuns() { + return this.runs; } // Can be nullable due to configuration caching. @@ -94,6 +110,8 @@ public MinecraftDependencyImpl(Provider mavenizerOutput) { @Override public ExternalModuleDependency init(Object dependencyNotation, Closure closure) { + this.runs = getObjects().domainObjectContainer(SlimeLauncherOptionsImpl.class); + var dependency = (ExternalModuleDependency) getProject().getDependencies().create(dependencyNotation, Closures.function(d -> { if (!(d instanceof ExternalModuleDependency module)) throw this.problems.invalidMinecraftDependencyType(d); @@ -120,68 +138,44 @@ public ExternalModuleDependency init(Object dependencyNotation, Closure closu @Override public Action addAttributes() { - return attributes -> { - attributes.attributeProvider(MinecraftExtensionInternal.AttributesInternal.OS, getProviders().of(OperatingSystemName.class, spec -> spec.parameters(parameters -> parameters.getAllowedOperatingSystems().set(Set.of(OS.WINDOWS, OS.MACOS, OS.LINUX))))); - attributes.attributeProvider(MinecraftExtensionInternal.AttributesInternal.MAPPINGS_CHANNEL, mappings.map(MinecraftMappings::getChannel)); - attributes.attributeProvider(MinecraftExtensionInternal.AttributesInternal.MAPPINGS_VERSION, mappings.map(MinecraftMappings::getVersion)); - }; + return attributes -> { }; } @Override - public void handle(Configuration configuration) { - if (!configuration.isCanBeResolved()) return; - - this.mappings.finalizeValue(); - configuration.getResolutionStrategy().dependencySubstitution(s -> { - var moduleSelector = "%s:%s".formatted(this.module.get(), this.version.get()); - var module = s.module(moduleSelector); - try { - s.substitute(module) - .using(s.variant(module, variant -> variant.attributes(this.addAttributes()))) - .because("Accounts for mappings used and natives variants"); - } catch (InvalidUserCodeException e) { - throw new IllegalStateException("Resolvable configuration '%s' was resolved too early!".formatted(configuration.getName()), e); - } - }); - - var asDependency = this.asDependency(); - if (asDependency == null) return; + public void handle(Configuration configuration) { } - var hierarchy = configuration.getHierarchy(); - - var sourceSet = Util.getSourceSet( - getProject().getConfigurations().matching(hierarchy::contains), - getProject().getExtensions().getByType(JavaPluginExtension.class).getSourceSets(), - asDependency + @Override + public void handle(NamedDomainObjectSet sourceSets, NamedDomainObjectSet allSourceSets) { + allSourceSets.all(sourceSet -> + getProject().getTasks().named(sourceSet.getTaskName("sync", "mavenizer"), task -> task.dependsOn(this.mavenizer)) ); - // Hope that this is handled elsewhere, and that we are transitive. - if (sourceSet != null) { - this.handle(sourceSet); - } - } - - @Override - public void handle(SourceSet sourceSet) { var asString = this.asString.get(); - var dependencyOutput = this.mavenizerOutput.map(dir -> dir.dir(this.asPath)).get().get().getAsFile(); - getFlowScope().always(ForgeGradleFlowAction.MavenizerSyncCheck.class, spec -> { + var dependencyOutput = this.mavenizerOutput.dir(this.asPath); + getFlowScope().always(ForgeGradleFlowAction.MavenizerSyncCheck.class, spec -> spec.parameters(parameters -> { parameters.getFailure().set(getFlowProviders().getBuildWorkResult().map(r -> r.getFailure().orElse(null))); parameters.dependencyOutput.set(dependencyOutput); parameters.dependency.set(asString); + }) + ); + + if (!sourceSets.isEmpty() && this.sourceSetName == null) + this.sourceSetName = sourceSets.iterator().next().getName(); + + var runs = Objects.requireNonNullElseGet(getRuns(), () -> getObjects().domainObjectContainer(SlimeLauncherOptionsImpl.class)); + ((NamedDomainObjectContainer) runs).addAll((NamedDomainObjectContainer) minecraft.getRuns()); + allSourceSets.configureEach(sourceSet -> { + var single = getProject() + .getConfigurations() + .getByName(sourceSet.getRuntimeClasspathConfigurationName()) + .getAllDependencies() + .matching(MinecraftDependencyInternal::is) + .size() == 1; + runs.forEach(options -> { + var task = SlimeLauncherExec.register(getProject(), sourceSet, (SlimeLauncherOptionsImpl) options, module.get(), version.get(), asPath.get(), asString, single, minecraft.getEclipseOutputDir()); }); }); - - if (this.sourceSetName != null) { - if (!this.sourceSetName.equals(sourceSet.getName())) { - throw new IllegalStateException("MinecraftDependency '%s' has already been handled!".formatted(this.asDependency())); - } - - return; - } - - this.sourceSetName = sourceSet.getName(); } @Override @@ -221,25 +215,43 @@ public Action addAttributes() { } @Override - public void handle(SourceSet sourceSet) { - super.handle(sourceSet); + public void handle(Configuration configuration) { + super.handle(configuration); + + if (configuration.isCanBeResolved()) { + configuration.getResolutionStrategy().dependencySubstitution(s -> { + var moduleSelector = "%s:%s".formatted(this.module.get(), this.version.get()); + var module = s.module(moduleSelector); + try { + s.substitute(module) + .using(s.variant(module, variant -> variant.attributes(this.addAttributes()))) + .because("Applies AccessTransformers"); + } catch (InvalidUserCodeException e) { + throw new IllegalStateException("Resolvable configuration '%s' was resolved too early!".formatted(configuration.getName()), e); + } + }); + } + } - var asDependency = this.asDependency(); - if (asDependency == null) return; + @Override + public void handle(NamedDomainObjectSet sourceSets, NamedDomainObjectSet allSourceSets) { + super.handle(sourceSets, allSourceSets); - if (!Util.contains(getProject().getConfigurations(), sourceSet, false, asDependency)) return; - if (!this.atPath.isPresent()) return; + if (!this.atPath.isPresent() || sourceSets.isEmpty()) return; + var sourceSet = sourceSets.iterator().next(); var itor = sourceSet.getResources().getSrcDirs().iterator(); if (itor.hasNext()) { - this.atFile.convention(this.getProjectLayout().file(this.getProviders().provider(() -> new File(itor.next(), this.atPath.get()))).get()); + var file = itor.next(); + this.atFile.convention(this.getProjectLayout().file(this.atPath.map(atPath -> new File(file, atPath)))); } else { // weird edge case where a source set might not have any resources??? // in which case, just best guess the location for accesstransformer.cfg - this.atFile.convention(this.getProjectLayout().getProjectDirectory().file(this.getProviders().provider(() -> "src/%s/resources/%s".formatted(sourceSet.getName(), this.atPath.get()))).get()); + var sourceSetName = sourceSet.getName(); + this.atFile.convention(this.getProjectLayout().getProjectDirectory().file(this.atPath.map(atPath -> "src/" + sourceSetName + "/resources/" + atPath))); } - ArtifactAccessTransformer.validateConfig(getProject(), asDependency, this.atFile); + ArtifactAccessTransformer.validateConfig(getProject(), asDependency(), this.atFile); } private Attribute registerTransform() { @@ -247,8 +259,7 @@ private Attribute registerTransform() { var attribute = Attribute.of("net.minecraftforge.gradle.accesstransformers.automatic." + this.getIndex(), Boolean.class); - dependencies.attributesSchema(attributesSchema -> attributesSchema.attribute(attribute)); - + dependencies.getAttributesSchema().attribute(attribute); dependencies.getArtifactTypes().named( ArtifactTypeDefinition.JAR_TYPE, type -> type.getAttributes().attribute(attribute, false) diff --git a/src/main/java/net/minecraftforge/gradle/internal/MinecraftDependencyInternal.java b/src/main/java/net/minecraftforge/gradle/internal/MinecraftDependencyInternal.java index 467e600a7..f3e0a7d92 100644 --- a/src/main/java/net/minecraftforge/gradle/internal/MinecraftDependencyInternal.java +++ b/src/main/java/net/minecraftforge/gradle/internal/MinecraftDependencyInternal.java @@ -7,7 +7,10 @@ import groovy.lang.Closure; import net.minecraftforge.gradle.MinecraftDependency; import net.minecraftforge.gradle.MinecraftDependencyWithAccessTransformers; +import net.minecraftforge.gradle.SlimeLauncherOptions; import org.gradle.api.Action; +import org.gradle.api.NamedDomainObjectContainer; +import org.gradle.api.NamedDomainObjectSet; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Dependency; import org.gradle.api.artifacts.ExternalModuleDependency; @@ -17,8 +20,11 @@ import org.gradle.api.reflect.TypeOf; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.TaskProvider; +import org.jspecify.annotations.NullUnmarked; import org.jspecify.annotations.Nullable; +import java.util.Set; + interface MinecraftDependencyInternal extends MinecraftDependency, HasPublicType, MinecraftMappingsContainerInternal { String MC_EXT_NAME = "__fg_minecraft_dependency"; String AT_COUNT_NAME = "__fg_minecraft_atcontainers"; @@ -28,6 +34,10 @@ default TypeOf getPublicType() { return TypeOf.typeOf(MinecraftDependency.class); } + @Override + @NullUnmarked + NamedDomainObjectContainer getRuns(); + static boolean is(Dependency dependency) { try { return ((ExtensionAware) dependency).getExtensions().getExtraProperties().has(MC_EXT_NAME); @@ -60,7 +70,7 @@ default Closure closure(Closure closure) { void handle(Configuration configuration); - void handle(SourceSet sourceSet); + void handle(NamedDomainObjectSet sourceSets, NamedDomainObjectSet allSourceSets); interface WithAccessTransformers extends MinecraftDependencyWithAccessTransformers, MinecraftDependencyInternal { @Override diff --git a/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionImpl.java b/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionImpl.java index f966e8313..fccc43fea 100644 --- a/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionImpl.java +++ b/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionImpl.java @@ -6,11 +6,8 @@ import groovy.lang.Closure; import groovy.lang.DelegatesTo; -import groovy.transform.CompileStatic; import groovy.transform.NamedVariant; -import groovy.transform.PackageScope; import groovy.transform.stc.ClosureParams; -import groovy.transform.stc.FromString; import groovy.transform.stc.SimpleType; import net.minecraftforge.gradle.ClosureOwner; import net.minecraftforge.gradle.MinecraftDependency; @@ -21,6 +18,8 @@ import org.gradle.api.Action; import org.gradle.api.NamedDomainObjectContainer; import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.UnknownTaskException; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.ExternalModuleDependency; import org.gradle.api.artifacts.ExternalModuleDependencyBundle; @@ -38,10 +37,11 @@ import org.gradle.api.provider.Property; import org.gradle.api.provider.ProviderFactory; import org.gradle.api.reflect.TypeOf; +import org.gradle.api.tasks.TaskProvider; import org.gradle.plugins.ide.eclipse.model.EclipseModel; +import org.jspecify.annotations.Nullable; import javax.inject.Inject; -import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -62,6 +62,8 @@ abstract class MinecraftExtensionImpl implements MinecraftExtensionInternal { protected abstract @Inject ObjectFactory getObjects(); + protected abstract @Inject ProviderFactory getProviders(); + static void register( ForgeGradlePlugin plugin, ExtensionAware target @@ -126,8 +128,6 @@ public void mappings(String channel, String version) { this.mappings.set(replacement); } - @CompileStatic - @PackageScope static abstract class ForSettingsImpl extends MinecraftExtensionImpl { @Inject public ForSettingsImpl(ForgeGradlePlugin plugin, Settings settings) { @@ -146,8 +146,11 @@ private void finish(Settings settings) { } static abstract class ForProjectImpl extends MinecraftExtensionImpl implements MinecraftExtensionInternal.ForProject { + private @Nullable TaskProvider genEclipseRuns; + final DirectoryProperty eclipseOutputDir = getObjects().directoryProperty().convention(getProjectLayout().getProjectDirectory().dir("bin")); + // Slime Launcher - private final NamedDomainObjectContainer runs; + private final NamedDomainObjectContainer runs = getObjects().domainObjectContainer(SlimeLauncherOptionsImpl.class); // Dependencies final List minecraftDependencies = new ArrayList<>(); @@ -160,16 +163,11 @@ static abstract class ForProjectImpl spec.parameters(parameters -> { parameters.getFailure().set(this.getFlowProviders().getBuildWorkResult().map(p -> p.getFailure().orElse(null))); - parameters.appliedPlugin.set(project.getPluginManager().hasPlugin("net.minecraftforge.accesstransformers")); + parameters.appliedPlugin.set(getProject().getPluginManager().hasPlugin("net.minecraftforge.accesstransformers")); })); - project.getConfigurations() - .matching(Configuration::isCanBeResolved) - .configureEach(c -> c.withDependencies(d -> this.apply(c))); + getProject().getConfigurations().configureEach(c -> c.withDependencies(d -> this.apply(c))); + + getProject().getDependencies().attributesSchema(schema -> { + schema.attribute(ForgeAttributes.OperatingSystem.ATTRIBUTE, strategy -> { + var currentOS = getProviders().of(ForgeAttributes.OperatingSystem.CurrentValue.class, ForgeAttributes.OperatingSystem.CurrentValue.Parameters.DEFAULT).get(); + strategy.getDisambiguationRules().add(ForgeAttributes.OperatingSystem.DisambiguationRule.class, ctor -> ctor.params(currentOS)); + }); + + schema.attribute(ForgeAttributes.MappingsChannel.ATTRIBUTE, strategy -> + strategy.getDisambiguationRules().add(ForgeAttributes.MappingsChannel.DisambiguationRule.class) + ); + + schema.attribute(ForgeAttributes.MappingsVersion.ATTRIBUTE, strategy -> + strategy.ordered(ForgeAttributes.MappingsVersion.COMPARATOR) + ); + }); + + getProject().getPluginManager().withPlugin("eclipse", appliedEclipsePlugin -> { + var eclipse = getProject().getExtensions().getByType(EclipseModel.class); + + this.genEclipseRuns = getProject().getTasks().register("genEclipseRuns", task -> { + task.setGroup("IDE"); + task.setDescription("Generates the run configuration launch files for Eclipse."); + }); + eclipse.synchronizationTasks(genEclipseRuns); + + this.eclipseOutputDir.fileProvider(getProviders().provider(() -> eclipse.getClasspath().getDefaultOutputDir())); + }); // Finish when the project is evaluated - project.afterEvaluate(this::finish); + getProject().afterEvaluate(this::finish); } @Override @@ -203,7 +226,14 @@ public List getRepositories() { : getProject().getRepositories().withType(MavenArtifactRepository.class); } + @Override + public DirectoryProperty getEclipseOutputDir() { + return this.eclipseOutputDir; + } + private void apply(Configuration configuration) { + if (!configuration.isCanBeResolved()) return; + var hierarchy = configuration.getHierarchy(); var minecraftDependencies = hierarchy @@ -213,7 +243,7 @@ private void apply(Configuration configuration) { .collect(Collectors.toSet()); for (var minecraftDependency : minecraftDependencies) { - // This can never be null in production and is only here to make the IDE happy. + // This can never be null and is only here to make the IDE happy. assert minecraftDependency != null; minecraftDependency.handle(configuration); @@ -223,9 +253,20 @@ private void apply(Configuration configuration) { private void finish(Project project) { checkRepos(getRepositories()); + var sourceSets = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets(); var sourceSetsDir = this.getObjects().directoryProperty().value(this.getProjectLayout().getBuildDirectory().dir("sourceSets")); var mergeSourceSets = this.problems.test("net.minecraftforge.gradle.merge-source-sets"); - project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets().configureEach(sourceSet -> { + sourceSets.all(sourceSet -> { + var sourceSetName = sourceSet.getName(); + var syncMavenizer = Util.runFirst(project, project.getTasks().register(sourceSet.getTaskName("sync", "mavenizer"), task -> { + task.setGroup("Build Setup"); + task.setDescription("Synchronizes the Mavenizer output for source set '" + sourceSetName + '.'); + })); + + try { + project.getTasks().named(sourceSet.getCompileJavaTaskName(), task -> task.dependsOn(syncMavenizer)); + } catch (UnknownTaskException ignored) { } + if (mergeSourceSets) { // This is documented in SourceSetOutput's javadoc comment var unifiedDir = sourceSetsDir.dir(sourceSet.getName()); @@ -235,6 +276,8 @@ private void finish(Project project) { project.getPluginManager().withPlugin("eclipse", eclipsePlugin -> { var eclipse = project.getExtensions().getByType(EclipseModel.class); + eclipse.synchronizationTasks(syncMavenizer); + if (mergeSourceSets) eclipse.getClasspath().setDefaultOutputDir(sourceSetsDir.getAsFile().get()); else @@ -242,16 +285,13 @@ private void finish(Project project) { }); }); - if (!this.minecraftDependencies.isEmpty()) { - var syncMavenizer = project.getTasks().register("syncMavenizer", task -> task.setGroup("Build Setup")); - for (var minecraftDependency : this.minecraftDependencies) { - var mavenizer = minecraftDependency.asTask(); - if (mavenizer == null) continue; - - syncMavenizer.configure(task -> task.dependsOn(mavenizer)); - - var dependency = minecraftDependency.asDependency(); - if (dependency == null) continue; + for (var minecraftDependency : this.minecraftDependencies) { + var dependency = minecraftDependency.asDependency(); + if (dependency != null) { + minecraftDependency.handle( + Util.collect(project, false, dependency), + Util.collect(project, true, dependency) + ); // See https://github.com/MinecraftForge/ForgeGradle/issues/1008#issuecomment-3623727384 // Basically, if IntelliJ can't immediately find a sources JAR next to the main jar, it tries to use this scuffed task @@ -277,55 +317,6 @@ private void finish(Project project) { } }); } - - project.getPluginManager().withPlugin("eclipse", eclipsePlugin -> { - var eclipse = project.getExtensions().getByType(EclipseModel.class); - eclipse.synchronizationTasks(syncMavenizer); - }); - - var taskNames = project.getGradle().getStartParameter().getTaskNames(); - taskNames.add(0, syncMavenizer.get().getPath()); - project.getGradle().getStartParameter().setTaskNames(taskNames); - } - - if (!this.runs.isEmpty() && !this.minecraftDependencies.isEmpty()) { - var genEclipseRuns = project.getTasks().register("genEclipseRuns", task -> { - task.setGroup("IDE"); - task.setDescription("Generates the run configuration launch files for Eclipse."); - }); - - File eclipseOutputDir; - var eclipse = project.getExtensions().findByType(EclipseModel.class); - if (eclipse != null) { - eclipse.synchronizationTasks(genEclipseRuns); - eclipseOutputDir = eclipse.getClasspath().getDefaultOutputDir(); - } else { - eclipseOutputDir = getProjectLayout().getProjectDirectory().dir("bin").getAsFile(); - } - - var configurations = project.getConfigurations(); - var sourceSets = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets(); - - sourceSets.configureEach(sourceSet -> { - var minecraftDependencies = configurations - .getByName(sourceSet.getRuntimeClasspathConfigurationName()) - .getAllDependencies() - .matching(MinecraftDependencyInternal::is) - .stream() - .map(MinecraftDependencyInternal::get) - .collect(Collectors.toSet()); - - boolean single = minecraftDependencies.size() == 1; - for (var minecraftDependency : minecraftDependencies) { - // This can never be null in production and is only here to make the IDE happy. - assert minecraftDependency != null; - - var impl = (MinecraftDependencyImpl) minecraftDependency; - this.runs.forEach(options -> { - var task = SlimeLauncherExec.register(project, sourceSet, options, impl.module.get(), impl.version.get(), impl.asPath.get(), impl.asString.get(), single, eclipseOutputDir); - }); - } - }); } } @@ -334,15 +325,6 @@ public NamedDomainObjectContainer getRuns() { return this.runs; } - @Override - public void runs( - @DelegatesTo(NamedDomainObjectContainer.class) - @ClosureParams(value = FromString.class, options = "org.gradle.api.NamedDomainObjectContainer") - Closure closure - ) { - this.runs.configure(closure); - } - Class getMinecraftDependencyClass() { return MinecraftDependencyImpl.class; } diff --git a/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionInternal.java b/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionInternal.java index 3f227d908..f1081389a 100644 --- a/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionInternal.java +++ b/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionInternal.java @@ -10,6 +10,7 @@ import net.minecraftforge.gradle.MinecraftExtensionForProjectWithAccessTransformers; import org.gradle.api.artifacts.repositories.MavenArtifactRepository; import org.gradle.api.attributes.Attribute; +import org.gradle.api.file.DirectoryProperty; import org.gradle.api.reflect.HasPublicType; import org.gradle.api.reflect.TypeOf; @@ -29,23 +30,19 @@ default Attributes getAttributes() { record AttributesInternal() implements Attributes { static AttributesInternal INSTANCE = new AttributesInternal(); - static final Attribute OS = Attribute.of("net.minecraftforge.native.operatingSystem", String.class); - static final Attribute MAPPINGS_CHANNEL = Attribute.of("net.minecraftforge.mappings.channel", String.class); - static final Attribute MAPPINGS_VERSION = Attribute.of("net.minecraftforge.mappings.version", String.class); - @Override public Attribute getOs() { - return OS; + return ForgeAttributes.OperatingSystem.ATTRIBUTE; } @Override public Attribute getMappingsChannel() { - return MAPPINGS_CHANNEL; + return ForgeAttributes.MappingsChannel.ATTRIBUTE; } @Override public Attribute getMappingsVersion() { - return MAPPINGS_VERSION; + return ForgeAttributes.MappingsVersion.ATTRIBUTE; } } @@ -57,6 +54,8 @@ default TypeOf getPublicType() { List getRepositories(); + DirectoryProperty getEclipseOutputDir(); + interface WithAccessTransformers extends MinecraftExtensionForProjectWithAccessTransformers, MinecraftExtensionInternal.ForProject, HasPublicType { @Override default TypeOf getPublicType() { diff --git a/src/main/java/net/minecraftforge/gradle/internal/OperatingSystemName.java b/src/main/java/net/minecraftforge/gradle/internal/OperatingSystemName.java deleted file mode 100644 index d35c9dcf8..000000000 --- a/src/main/java/net/minecraftforge/gradle/internal/OperatingSystemName.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ -package net.minecraftforge.gradle.internal; - -import net.minecraftforge.util.os.OS; -import org.gradle.api.provider.SetProperty; -import org.gradle.api.provider.ValueSource; -import org.gradle.api.provider.ValueSourceParameters; -import org.jspecify.annotations.Nullable; - -import javax.inject.Inject; - -abstract class OperatingSystemName implements ValueSource { - interface Parameters extends ValueSourceParameters { - SetProperty getAllowedOperatingSystems(); - } - - @Inject - public OperatingSystemName() { } - - @Override - public @Nullable String obtain() { - var allowed = getParameters().getAllowedOperatingSystems().get().toArray(new OS[0]); - return allowed.length > 0 - ? OS.current(allowed).key() - : OS.current().key(); - } -} diff --git a/src/main/java/net/minecraftforge/gradle/internal/SlimeLauncherExec.java b/src/main/java/net/minecraftforge/gradle/internal/SlimeLauncherExec.java index 862371d57..fe6aba418 100644 --- a/src/main/java/net/minecraftforge/gradle/internal/SlimeLauncherExec.java +++ b/src/main/java/net/minecraftforge/gradle/internal/SlimeLauncherExec.java @@ -14,6 +14,7 @@ import org.gradle.api.artifacts.ModuleIdentifier; import org.gradle.api.attributes.Usage; import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.Directory; import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.provider.MapProperty; @@ -33,7 +34,6 @@ import org.gradle.work.DisableCachingByDefault; import javax.inject.Inject; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.ArrayList; @@ -42,7 +42,7 @@ @DisableCachingByDefault(because = "Running the game cannot be cached") abstract class SlimeLauncherExec extends JavaExec implements ForgeGradleTask, HasPublicType { - static TaskProvider register(Project project, SourceSet sourceSet, SlimeLauncherOptionsImpl options, ModuleIdentifier module, String version, String asPath, String asString, boolean single, File eclipseOutputDir) { + static TaskProvider register(Project project, SourceSet sourceSet, SlimeLauncherOptionsImpl options, ModuleIdentifier module, String version, String asPath, String asString, boolean single, Provider eclipseOutputDir) { TaskProvider metadata; { TaskProvider t; From b7d8dc3103b14fa70696f950e47a7ccdc9475a53 Mon Sep 17 00:00:00 2001 From: Jonathing Date: Thu, 18 Dec 2025 16:17:24 -0500 Subject: [PATCH 2/4] Use dedicated record for shared data --- .../gradle/internal/ForgeGradleProblems.java | 11 +++ .../internal/ForgeGradleSharedData.java | 12 +++ .../internal/MinecraftExtensionImpl.java | 81 ++++++++++--------- .../internal/MinecraftExtensionInternal.java | 2 + .../internal/MinecraftMappingsImpl.java | 3 + 5 files changed, 70 insertions(+), 39 deletions(-) create mode 100644 src/main/java/net/minecraftforge/gradle/internal/ForgeGradleSharedData.java diff --git a/src/main/java/net/minecraftforge/gradle/internal/ForgeGradleProblems.java b/src/main/java/net/minecraftforge/gradle/internal/ForgeGradleProblems.java index d16e20ce3..017211819 100644 --- a/src/main/java/net/minecraftforge/gradle/internal/ForgeGradleProblems.java +++ b/src/main/java/net/minecraftforge/gradle/internal/ForgeGradleProblems.java @@ -150,6 +150,17 @@ void mavenizerOutOfDate(boolean throwIt, Object dependency) { this.report(name, displayName, problemSpec); } + void reportCannotAccessSettingsRepos(Exception e) { + this.report("cannot-access-settings-repos", "Cannot access Settings repositories", spec -> spec + .details(""" + ForgeGradle is unable to access the repositories defined by the Settings' dependency resolution management. + This is a ForgeGradle bug and needs to be reported to the ForgeGradle issue tracker on GitHub.""") + .severity(Severity.ERROR) + .withException(e) + .solution("For now, only declare repositories in the project.") + .solution(HELP_MESSAGE)); + } + void reportMcMavenNotDeclared() { if (!this.test("net.minecraftforge.gradle.warnings.repository.missing.mavenizer")) return; diff --git a/src/main/java/net/minecraftforge/gradle/internal/ForgeGradleSharedData.java b/src/main/java/net/minecraftforge/gradle/internal/ForgeGradleSharedData.java new file mode 100644 index 000000000..a3f11ac27 --- /dev/null +++ b/src/main/java/net/minecraftforge/gradle/internal/ForgeGradleSharedData.java @@ -0,0 +1,12 @@ +package net.minecraftforge.gradle.internal; + +import org.gradle.api.artifacts.repositories.MavenArtifactRepository; +import org.jspecify.annotations.Nullable; + +import java.util.List; + +record ForgeGradleSharedData( + @Nullable MinecraftMappingsImpl mappings +) { + static final String NAME = "__fg_shared_data"; +} diff --git a/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionImpl.java b/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionImpl.java index fccc43fea..cae476bcc 100644 --- a/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionImpl.java +++ b/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionImpl.java @@ -15,6 +15,7 @@ import net.minecraftforge.gradle.MinecraftExtensionForProject; import net.minecraftforge.gradle.MinecraftMappings; import net.minecraftforge.gradle.SlimeLauncherOptions; +import org.codehaus.groovy.runtime.InvokerHelper; import org.gradle.api.Action; import org.gradle.api.NamedDomainObjectContainer; import org.gradle.api.Project; @@ -49,16 +50,11 @@ import java.util.stream.Collectors; abstract class MinecraftExtensionImpl implements MinecraftExtensionInternal { - private static final String EXT_MAVEN_REPOS = "fg_mc_maven_repos"; - private static final String EXT_MAPPINGS = "fg_mc_mappings"; + private final DirectoryProperty mavenizerOutput = getObjects().directoryProperty(); - final ForgeGradleProblems problems; + final Property mappings = getObjects().property(MinecraftMappingsImpl.class); - // MCMaven - final DirectoryProperty mavenizerOutput; - - // Dependencies - final Property mappings; + final ForgeGradleProblems problems = getObjects().newInstance(ForgeGradleProblems.class); protected abstract @Inject ObjectFactory getObjects(); @@ -72,16 +68,16 @@ static void register( if (target instanceof Project project) { if (project.getPluginManager().hasPlugin("net.minecraftforge.accesstransformers")) { try { - extensions.create(MinecraftExtension.NAME, MinecraftExtensionImpl.ForProjectImpl.WithAccessTransformersImpl.class, plugin); + extensions.create(MinecraftExtension.NAME, ForProjectImpl.WithAccessTransformersImpl.class, plugin); } catch (Exception e) { var problems = project.getObjects().newInstance(ForgeGradleProblems.class); throw problems.accessTransformersNotOnClasspath(e); } } else { - extensions.create(MinecraftExtension.NAME, MinecraftExtensionImpl.ForProjectImpl.class, plugin); + extensions.create(MinecraftExtension.NAME, ForProjectImpl.class, plugin); } } else if (target instanceof Settings) { - extensions.create(MinecraftExtension.NAME, MinecraftExtensionImpl.ForSettingsImpl.class, plugin, target); + extensions.create(MinecraftExtension.NAME, ForSettingsImpl.class, plugin, target); } else { extensions.create(MinecraftExtension.NAME, MinecraftExtensionImpl.class, plugin); } @@ -89,11 +85,7 @@ static void register( @Inject public MinecraftExtensionImpl(ForgeGradlePlugin plugin) { - this.problems = this.getObjects().newInstance(ForgeGradleProblems.class); - - this.mavenizerOutput = this.getObjects().directoryProperty().convention(plugin.localCaches().dir("mavenizer/output").map(this.problems.ensureFileLocation())); - - this.mappings = this.getObjects().property(MinecraftMappingsImpl.class); + this.mavenizerOutput.convention(plugin.localCaches().dir("mavenizer/output").map(this.problems.ensureFileLocation())); } @Override @@ -101,11 +93,16 @@ public TypeOf getPublicType() { return MinecraftExtensionInternal.super.getPublicType(); } + @Override + public DirectoryProperty getMavenizerOutput() { + return this.mavenizerOutput; + } + @Override public Action getMavenizer() { return maven -> { maven.setName("MinecraftMavenizer"); - maven.setUrl(this.mavenizerOutput.getAsFile()); + maven.setUrl(this.getMavenizerOutput()); }; } @@ -114,16 +111,16 @@ public MinecraftMappings getMappings() { try { return this.mappings.get(); } catch (IllegalStateException e) { - throw this.problems.missingMappings(e); + throw problems.missingMappings(e); } } @Override @NamedVariant public void mappings(String channel, String version) { - var replacement = this.getObjects().newInstance(MinecraftMappingsImpl.class, channel, version); + var replacement = getObjects().newInstance(MinecraftMappingsImpl.class, channel, version); if (this.mappings.isPresent()) - this.problems.reportOverriddenMappings(this.mappings.get(), replacement); + problems.reportOverriddenMappings(this.mappings.get(), replacement); this.mappings.set(replacement); } @@ -136,16 +133,16 @@ public ForSettingsImpl(ForgeGradlePlugin plugin, Settings settings) { } private void finish(Settings settings) { - if (!this.mappings.isPresent()) return; - var repositories = settings.getDependencyResolutionManagement().getRepositories().withType(MavenArtifactRepository.class); - - var ext = settings.getGradle().getExtensions().getExtraProperties(); - ext.set(EXT_MAVEN_REPOS, repositories); - ext.set(EXT_MAPPINGS, this.mappings.get()); + settings.getGradle().getExtensions().add( + ForgeGradleSharedData.NAME, + new ForgeGradleSharedData( + this.mappings.getOrNull() + ) + ); } } - static abstract class ForProjectImpl extends MinecraftExtensionImpl implements MinecraftExtensionInternal.ForProject { + static abstract class ForProjectImpl extends MinecraftExtensionImpl implements ForProject { private @Nullable TaskProvider genEclipseRuns; final DirectoryProperty eclipseOutputDir = getObjects().directoryProperty().convention(getProjectLayout().getProjectDirectory().dir("bin")); @@ -167,9 +164,10 @@ static abstract class ForProjectImpl getPublicType() { } @Override - @SuppressWarnings("unchecked") public List getRepositories() { - var ext = getProject().getGradle().getExtensions().getExtraProperties(); - return ext.has(EXT_MAVEN_REPOS) - ? Objects.requireNonNull((List) ext.get(EXT_MAVEN_REPOS)) - : getProject().getRepositories().withType(MavenArtifactRepository.class); + var repositories = getObjects().namedDomainObjectList(MavenArtifactRepository.class); + repositories.addAll(getProject().getRepositories().withType(MavenArtifactRepository.class)); + try { + Settings settings = (Settings) InvokerHelper.getProperty(getProject().getGradle(), "settings"); + repositories.addAll(settings.getDependencyResolutionManagement().getRepositories().withType(MavenArtifactRepository.class)); + } catch (Exception e) { + problems.reportCannotAccessSettingsRepos(e); + } + + return repositories; } @Override @@ -341,7 +344,7 @@ public ExternalModuleDependency dependency( if (value instanceof ExternalModuleDependencyBundle) throw new IllegalArgumentException("Minecraft dependency cannot be a bundle"); - var minecraftDependency = (MinecraftDependencyInternal) this.getObjects().newInstance(this.getMinecraftDependencyClass(), this.mavenizerOutput); + var minecraftDependency = (MinecraftDependencyInternal) this.getObjects().newInstance(this.getMinecraftDependencyClass(), this.getMavenizerOutput()); this.minecraftDependencies.add(minecraftDependency); return minecraftDependency.init(value, closure); } @@ -366,7 +369,7 @@ private void checkRepos(List repos) { }; // Mavenizer - if (!containsExactly.test(ForProjectImpl.this.mavenizerOutput.getAsFile())) { + if (!containsExactly.test(ForProjectImpl.this.getMavenizerOutput().getAsFile())) { problems.reportMcMavenNotDeclared(); } @@ -381,7 +384,7 @@ private void checkRepos(List repos) { } } - static abstract class WithAccessTransformersImpl extends ForProjectImpl implements MinecraftExtensionInternal.ForProject.WithAccessTransformers { + static abstract class WithAccessTransformersImpl extends ForProjectImpl implements WithAccessTransformers { private final Property accessTransformers = this.getObjects().property(String.class); @Inject @@ -391,7 +394,7 @@ public WithAccessTransformersImpl(ForgeGradlePlugin plugin) { @Override public TypeOf getPublicType() { - return MinecraftExtensionInternal.ForProject.WithAccessTransformers.super.getPublicType(); + return WithAccessTransformers.super.getPublicType(); } @Override diff --git a/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionInternal.java b/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionInternal.java index f1081389a..c10f03538 100644 --- a/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionInternal.java +++ b/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionInternal.java @@ -27,6 +27,8 @@ default Attributes getAttributes() { return AttributesInternal.INSTANCE; } + DirectoryProperty getMavenizerOutput(); + record AttributesInternal() implements Attributes { static AttributesInternal INSTANCE = new AttributesInternal(); diff --git a/src/main/java/net/minecraftforge/gradle/internal/MinecraftMappingsImpl.java b/src/main/java/net/minecraftforge/gradle/internal/MinecraftMappingsImpl.java index 4c0ea207e..39d568f36 100644 --- a/src/main/java/net/minecraftforge/gradle/internal/MinecraftMappingsImpl.java +++ b/src/main/java/net/minecraftforge/gradle/internal/MinecraftMappingsImpl.java @@ -7,8 +7,11 @@ import org.gradle.api.model.ObjectFactory; import javax.inject.Inject; +import java.io.Serial; abstract class MinecraftMappingsImpl implements MinecraftMappingsInternal { + private static final @Serial long serialVersionUID = 6944934115402768018L; + private final String channel; private final String version; From dc839dd3fb50ff93af2b389f0d40c5fd4ce2f3e4 Mon Sep 17 00:00:00 2001 From: Jonathing Date: Thu, 18 Dec 2025 16:23:13 -0500 Subject: [PATCH 3/4] Don't use Maven local please --- settings.gradle | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/settings.gradle b/settings.gradle index b244684d8..f53b817e0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -17,14 +17,14 @@ gradle.beforeProject { Project project -> mavenCentral() gradlePluginPortal() maven project.gradleutils.forgeMaven - mavenLocal() + //mavenLocal() } } } //@formatter:off dependencyResolutionManagement.versionCatalogs.register('libs') { - version 'gradleutils', '3.3.39' + version 'gradleutils', '3.3.40' plugin 'licenser', 'net.minecraftforge.licenser' version '1.2.0' // https://plugins.gradle.org/plugin/net.minecraftforge.licenser plugin 'gradleutils', 'net.minecraftforge.gradleutils' versionRef 'gradleutils' @@ -43,8 +43,7 @@ dependencyResolutionManagement.versionCatalogs.register('libs') { library 'gradle', 'name.remal.gradle-api', 'gradle-api' versionRef 'gradle' // GradleUtils Shared Base - //library 'gradleutils-shared', 'net.minecraftforge', 'gradleutils-shared' versionRef 'gradleutils' - library 'gradleutils-shared', 'net.minecraftforge', 'gradleutils-shared' version '3.3.40' + library 'gradleutils-shared', 'net.minecraftforge', 'gradleutils-shared' versionRef 'gradleutils' // AccessTransformers Gradle Plugin // https://plugins.gradle.org/plugin/net.minecraftforge.accesstransformers From bac7c7f6e57226f2e13d6fbfd2e6fc9af4a9782f Mon Sep 17 00:00:00 2001 From: Jonathing Date: Thu, 18 Dec 2025 22:24:37 -0500 Subject: [PATCH 4/4] Forgot to commit this --- .../minecraftforge/gradle/internal/MinecraftExtensionImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionImpl.java b/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionImpl.java index cae476bcc..425b46539 100644 --- a/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionImpl.java +++ b/src/main/java/net/minecraftforge/gradle/internal/MinecraftExtensionImpl.java @@ -150,7 +150,7 @@ static abstract class ForProjectImpl runs = getObjects().domainObjectContainer(SlimeLauncherOptionsImpl.class); // Dependencies - final List minecraftDependencies = new ArrayList<>(); + private final List minecraftDependencies = new ArrayList<>(); protected abstract @Inject Project getProject();