Skip to content
Merged
20 changes: 19 additions & 1 deletion src/main/java/net/minecraftforge/gradle/MavenizerInstance.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,15 @@ public interface MavenizerInstance extends ProviderConvertible<ExternalModuleDep
/// @return The dependency generated by this instance
@Override Provider<ExternalModuleDependency> asProvider();

/// Gets the mappings channel used by the Mavenizer instance.
///
/// @return The mappings channel used, after all sanitization has been done, should match exactly to the generated maven artifact
/// @see MinecraftMappings#getChannel()
Provider<String> getMappingChannel();

/// Gets the mappings version used by the Mavenizer instance.
///
/// @return The mappings version used
/// @return The mappings version used, after all sanitization has been done, should match exactly to the generated maven artifact
/// @see MinecraftMappings#getVersion()
Provider<String> getMappingVersion();

Expand Down Expand Up @@ -53,4 +59,16 @@ public interface MavenizerInstance extends ProviderConvertible<ExternalModuleDep
/// [org.gradle.api.artifacts.dsl.DependencyFactory#create(CharSequence)] or
/// [org.gradle.api.artifacts.dsl.DependencyHandler#addProvider(String, Provider)].
Provider<File> getToObfFile();

/// Gets the Minecraft Version used by the Mavenizer instance.
/// Only returns a value when Mavenizer is above 0.4.33
///
/// @return The Minecraft Version
Provider<String> getMinecraftVersion();

/// Gets the MCP Config version used by the Mavenizer instance.
/// Only returns a value when Mavenizer is above 0.4.33, and we're targeting
/// an artifact that uses MCP Config. So Forge for Minecraft 1.13+
/// @return The MCP Version
Provider<String> getMCPVersion();
}
11 changes: 11 additions & 0 deletions src/main/java/net/minecraftforge/gradle/SlimeLauncherOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,21 @@ public interface SlimeLauncherOptions extends SlimeLauncherOptionsNested, Named
@Override
@Input String getName();

/// Configures source set-specific attributes for this run.
///
/// Use this, for example, if you need to configure test-specific arguments, properties, or environment variables.
///
/// @param sourceSet The source set to configure this run for
/// @param action The configuring action
default void with(SourceSet sourceSet, Action<? super SlimeLauncherOptionsNested> action) {
this.with(sourceSet.getName(), action);
}

/// Configures source set-specific attributes for this run.
///
/// @param sourceSetName The source set's name to configure this run for
/// @param action The configuring action
/// @see #with(SourceSet, Action)
void with(String sourceSetName, Action<? super SlimeLauncherOptionsNested> action);

/// The classpath to use.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,26 @@
*/
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.Named;
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.Nested;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.SourceSet;

import java.util.List;
import java.util.Map;

public interface SlimeLauncherOptionsNested {
Expand All @@ -24,7 +35,7 @@ public interface SlimeLauncherOptionsNested {
/// @return A property for the main class
@Input @Optional Property<String> getMainClass();

/// Wither or not to inherit arguments from the UserDev provided run configs.
/// Whether or not to inherit arguments from the UserDev provided run configs.
///
/// If you set this to false you must specify all arguments to start the process manually.
///
Expand All @@ -39,7 +50,7 @@ public interface SlimeLauncherOptionsNested {
/// @return A property for the arguments to pass to the main class
@Input @Optional ListProperty<String> getArgs();

/// Wither or not to inherit JVM arguments from the UserDev provided run configs.
/// Whether or not to inherit JVM arguments from the UserDev provided run configs.
///
/// If you set this to false you must specify all JVM arguments to start the process manually.
///
Expand Down Expand Up @@ -203,4 +214,57 @@ public interface SlimeLauncherOptionsNested {
/// add a single variable, use [#environment(String,Object)].
/// @see #getEnvironment()
void environment(Provider<? extends Map<String, ?>> properties);

/// The legacy mod configurations to use.
///
/// This is used to define the mod's source paths for legacy versions when they cannot be interpreted automatically.
/// Use this if you use non-standard source paths for your mod or source set.
///
/// @return The legacy mod configurations.
@Nested NamedDomainObjectContainer<? extends ModConfig> getMods();

/// Configures the legacy mod configurations to use.
///
/// @param closure The configuring closure
/// @see #getMods()
default void mods(
@DelegatesTo(NamedDomainObjectContainer.class)
@ClosureParams(value = FromString.class, options = "org.gradle.api.NamedDomainObjectContainer<net.minecraftforge.gradle.SlimeLauncherOptionsNested$ModConfig>")
Closure<?> closure
) {
this.getMods().configure(closure);
}

/// Configures the legacy mod configurations to use.
///
/// @param action The configuring action
/// @see #getMods()
default void mods(Action<? super NamedDomainObjectContainer<? extends ModConfig>> action) {
this.mods(Closures.action(this, action));
}

/// Represents a legacy mod configuration for older versions of Forge.
///
/// @see #getMods()
interface ModConfig extends Named {
/// Sets the source sets to use for this configuration.
///
/// @param sources The source sets to use
void setSources(List<SourceSet> sources);

/// Adds to the source sets to use for this configuration.
///
/// @param sources The source sets to use
void sources(List<SourceSet> sources);

/// Adds to the source sets to use for this configuration.
///
/// @param sources The source sets to use
void sources(SourceSet... sources);

/// Adds to the source sets to use for this configuration.
///
/// @param source The source set to use
void source(SourceSet source);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import groovy.transform.NamedParam;
import groovy.transform.NamedParams;
import net.minecraftforge.gradle.ClosureOwner;
import net.minecraftforge.gradle.MinecraftDependency;
import net.minecraftforge.gradle.MinecraftMappings;
import net.minecraftforge.gradle.SlimeLauncherOptions;
import org.gradle.api.Action;
Expand All @@ -27,7 +26,6 @@
import org.gradle.api.attributes.AttributeContainer;
import org.gradle.api.capabilities.Capability;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.reflect.HasPublicType;
import org.gradle.api.reflect.TypeOf;
import org.jspecify.annotations.Nullable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,24 +119,4 @@ protected void run(Parameters parameters) {
parameters.problems().reportAccessTransformersNotApplied(e);
}
}

static abstract class MavenizerSyncCheck extends ForgeGradleFlowAction<MavenizerSyncCheck.Parameters> {
static abstract class Parameters extends ForgeGradleFlowAction.Parameters {
final DirectoryProperty dependencyOutput = this.getObjects().directoryProperty();
final Property<String> dependency = this.getObjects().property(String.class);

@Inject
public Parameters() { }
}

@Inject
public MavenizerSyncCheck() { }

@Override
protected void run(Parameters parameters) {
if (parameters.dependencyOutput.getAsFile().get().exists()) return;

parameters.problems().mavenizerOutOfDate(parameters.getFailure().isPresent(), parameters.dependency.get());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.plugins.ExtensionAware;
import org.gradle.util.GradleVersion;
import org.jspecify.annotations.Nullable;

import javax.inject.Inject;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@

import net.minecraftforge.gradle.MinecraftMappings;
import net.minecraftforge.gradleutils.shared.EnhancedProblems;
import org.gradle.api.Action;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.ExternalModuleDependency;
import org.gradle.api.problems.ProblemSpec;
import org.gradle.api.problems.Problems;
import org.gradle.api.problems.Severity;
import org.gradle.api.provider.ProviderFactory;
Expand Down Expand Up @@ -129,27 +127,6 @@ RuntimeException changingMinecraftDependency(Dependency dependency) {
//endregion

//region Minecraft Maven
void mavenizerOutOfDate(boolean throwIt, Object dependency) {
String name = "mavenizer-out-of-date";
String displayName = "Minecraft Mavenizer is out-of-date";
Action<? super ProblemSpec> problemSpec = spec -> spec
.details("""
Gradle cannot compile your sources or run the game because the Minecraft Mavenizer is out-of-date.
The Mavenizer must be re-run in order for the changes made to the Minecraft dependency to take effect.
Affected dependency: '%s'"""
.formatted(dependency))
.severity(Severity.ERROR)
.solution("Re-import your project in your IDE, as this will automatically synchronize the Mavenizer.")
.solution("Run `gradlew` with no arguments, as this will automatically synchronize the Mavenizer.")
.solution("Temporary revert any edits to the Minecraft dependency until the Mavenizer is re-run.")
.solution(HELP_MESSAGE);

if (throwIt)
throw this.throwing(new IllegalStateException(displayName), name, displayName, problemSpec);
else
this.report(name, displayName, problemSpec);
}

void reportMavenizerNotHighestRepository() {
this.report("mavenizer-not-highest-repo", "Mavenizer repository is not the highest", spec -> spec
.details("""
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/net/minecraftforge/gradle/internal/Lazy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) Forge Development LLC and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/
package net.minecraftforge.gradle.internal;

import org.jspecify.annotations.Nullable;

import java.util.function.Supplier;

class Lazy<T> implements Supplier<T> {
private final Supplier<T> supplier;
private boolean computed = false;
private @Nullable T value = null;

public Lazy(final Supplier<T> supplier) {
this.supplier = supplier;
}

@Override
public final @Nullable T get() {
if (this.computed)
return this.value;

synchronized (this) {
if (this.computed)
return this.value;
this.computed = true;
return this.value = supplier.get();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@

import groovy.json.JsonSlurper;
import net.minecraftforge.gradle.MavenizerInstance;
import org.gradle.api.Transformer;
import org.gradle.api.artifacts.ExternalModuleDependency;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Provider;
import org.jspecify.annotations.Nullable;

import java.io.File;
import java.util.List;
import java.util.Map;

class MavenizerInstanceImpl implements MavenizerInstance {
private static final Logger LOGGER = Logging.getLogger(MavenizerInstanceImpl.class);
private final MinecraftExtensionImpl.ForProjectImpl extension;
private final Provider<Boolean> valueSource;
private final ExternalModuleDependency dependency;
Expand Down Expand Up @@ -55,11 +58,29 @@ private Provider<String> get(String key) {
}));
}

private Provider<String> get(String key, @Nullable String _default, String requiredVersion) {
return this.invoke.getting(key)
.orElse(this.extension.getProviders().provider(() -> {
// This should only happen when someone hardcodes their tool version, warn them
var message = "Mavenizer did not output expected json data " + key +", Make sure you're using Mavenizer >= " + requiredVersion;
if (_default != null) {
LOGGER.warn(message);
return _default;
}
throw new IllegalStateException("Mavenizer did not output expected json data " + key +", Make sure you're using Mavenizer >= " + requiredVersion);
}));
}

@Override
public Provider<ExternalModuleDependency> asProvider() {
return this.invoke.map(m -> this.dependency);
}

@Override
public Provider<String> getMappingChannel() {
return get("mappings.channel");
}

@Override
public Provider<String> getMappingVersion() {
return get("mappings.version");
Expand All @@ -84,4 +105,20 @@ public Provider<String> getToObf() {
public Provider<File> getToObfFile() {
return get("mappings.obf.file").map(this.extension.getProject()::file);
}

@Override
public Provider<String> getMinecraftVersion() {
return get("mc.version", "UNKNOWN", "0.4.33");
}

@Override
public Provider<String> getMCPVersion() {
return get("mcp.version", "UNKNOWN", "0.4.33");
}

// Internal, not sure if I want to return
public Provider<List<String>> getPatcherModules() {
return get("patcher.modules", "", "0.4.33")
.map(value -> value.isBlank() ? List.of() : List.of(value.split(",")));
}
}
Loading