Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ gradle.beforeProject { Project project ->
mavenCentral()
gradlePluginPortal()
maven project.gradleutils.forgeMaven
//mavenLocal()
mavenLocal()
}
}
}
Expand Down Expand Up @@ -45,9 +45,10 @@ dependencyResolutionManagement.versionCatalogs.register('libs') {
// https://plugins.gradle.org/plugin/net.minecraftforge.accesstransformers
library 'accesstransformers-gradle', 'net.minecraftforge.accesstransformers', 'net.minecraftforge.accesstransformers.gradle.plugin' version '5.0.1'

library 'utils-data', 'net.minecraftforge', 'json-data-utils' version '0.3.0' // https://files.minecraftforge.net/net/minecraftforge/json-data-utils/index.html
library 'utils-data', 'net.minecraftforge', 'json-data-utils' version '0.4.0' // 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.10' // https://files.minecraftforge.net/net/minecraftforge/hash-utils/index.html
library 'utils-download', 'net.minecraftforge', 'download-utils' version '0.3.2' // https://files.minecraftforge.net/net/minecraftforge/download-utils/index.html
bundle 'utils', ['utils-data', 'utils-hash', 'utils-download']
bundle 'utils', ['utils-data', 'utils-os', 'utils-hash', 'utils-download']
}
//@formatter:on
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ RuntimeException changingMinecraftDependency(Dependency dependency) {
//endregion

//region Minecraft Maven
RuntimeException mavenizerOutOfDateCompile(Dependency dependency) {
RuntimeException mavenizerOutOfDateCompile(Object dependency) {
return this.throwing(new IllegalStateException(), "mavenizer-out-of-date", "Minecraft Mavenizer is out-of-date", spec -> spec
.details("""
Gradle cannot compile your sources because the Minecraft Mavenizer is out-of-date.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,21 @@
import groovy.transform.NamedVariant;
import net.minecraftforge.accesstransformers.gradle.ArtifactAccessTransformer;
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.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.ExternalModuleDependency;
import org.gradle.api.artifacts.ModuleIdentifier;
import org.gradle.api.artifacts.type.ArtifactTypeDefinition;
import org.gradle.api.attributes.Attribute;
import org.gradle.api.attributes.AttributeContainer;
import org.gradle.api.attributes.Category;
import org.gradle.api.file.Directory;
import org.gradle.api.file.ProjectLayout;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.logging.LogLevel;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.plugins.ExtensionAware;
import org.gradle.api.plugins.JavaPluginExtension;
Expand All @@ -33,19 +34,22 @@
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.internal.os.OperatingSystem;
import org.gradle.nativeplatform.OperatingSystemFamily;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnknownNullability;

import javax.inject.Inject;
import java.io.File;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

abstract class MinecraftDependencyImpl implements MinecraftDependencyInternal {
private @UnknownNullability ExternalModuleDependency delegate;
private @UnknownNullability TaskProvider<SyncMavenizer> mavenizer;
private transient @Nullable("configuration cache") ExternalModuleDependency delegate;
private transient @Nullable("configuration cache") TaskProvider<SyncMavenizer> mavenizer;

final Property<String> asString = getObjects().property(String.class);
final Property<String> asPath = getObjects().property(String.class);
final Property<ModuleIdentifier> module = getObjects().property(ModuleIdentifier.class);
final Property<String> version = getObjects().property(String.class);

private final Provider<? extends Directory> mavenizerOutput;
private final Property<MinecraftMappings> mappings;
Expand All @@ -70,12 +74,12 @@ public MinecraftDependencyImpl(Provider<? extends Directory> mavenizerOutput) {
}

@Override
public ExternalModuleDependency asDependency() {
public @Nullable("configuration cache") ExternalModuleDependency asDependency() {
return this.delegate;
}

@Override
public TaskProvider<SyncMavenizer> asTask() {
public @Nullable("configuration cache") TaskProvider<SyncMavenizer> asTask() {
return this.mavenizer;
}

Expand All @@ -97,13 +101,18 @@ public ExternalModuleDependency init(Object dependencyNotation, Closure<?> closu

this.mavenizer = SyncMavenizer.register(getProject(), dependency, this.mappings, mavenizerOutput);

this.asString.set(dependency.toString());
this.asPath.set(Util.pathify(dependency));
this.module.set(dependency.getModule());
this.version.set(dependency.getVersion());

return this.delegate = dependency;
}

@Override
public Action<? super AttributeContainer> addAttributes() {
return attributes -> {
attributes.attribute(MinecraftExtension.Attributes.os, this.getObjects().named(OperatingSystemFamily.class, OperatingSystem.current().getFamilyName()));
attributes.attributeProvider(MinecraftExtension.Attributes.os, getProviders().of(OperatingSystemName.class, spec -> spec.parameters(parameters -> parameters.getAllowedOperatingSystems().set(Set.of(OS.WINDOWS, OS.MACOS, OS.LINUX)))));
attributes.attributeProvider(MinecraftExtension.Attributes.mappingsChannel, mappings.map(MinecraftMappings::channel));
attributes.attributeProvider(MinecraftExtension.Attributes.mappingsVersion, mappings.map(MinecraftMappings::version));
};
Expand All @@ -114,9 +123,8 @@ public void handle(Configuration configuration) {
if (!configuration.isCanBeResolved()) return;

this.mappings.finalizeValue();
var dependency = this.asDependency();
configuration.getResolutionStrategy().dependencySubstitution(s -> {
var moduleSelector = "%s:%s".formatted(dependency.getModule(), dependency.getVersion());
var moduleSelector = "%s:%s".formatted(this.module.get(), this.version.get());
var module = s.module(moduleSelector);
try {
s.substitute(module)
Expand All @@ -127,12 +135,15 @@ public void handle(Configuration configuration) {
}
});

var asDependency = this.asDependency();
if (asDependency == null) return;

var hierarchy = configuration.getHierarchy();

var sourceSet = Util.getSourceSet(
getProject().getConfigurations().matching(hierarchy::contains),
getProject().getExtensions().getByType(JavaPluginExtension.class).getSourceSets(),
this.asDependency()
asDependency
);

// Hope that this is handled elsewhere, and that we are transitive.
Expand All @@ -145,9 +156,9 @@ public void handle(Configuration configuration) {
public void handle(SourceSet sourceSet) {
getProject().getTasks().named(sourceSet.getCompileJavaTaskName(), JavaCompile.class, task -> {
task.doFirst(t -> {
var file = this.mavenizerOutput.map(dir -> dir.dir(Util.pathify(asDependency()))).get().getAsFile();
var file = this.mavenizerOutput.map(dir -> dir.dir(this.asPath)).get().get().getAsFile();
if (!file.exists())
throw this.problems.mavenizerOutOfDateCompile(asDependency());
throw this.problems.mavenizerOutOfDateCompile(this.asString.get());
});
});

Expand Down Expand Up @@ -223,7 +234,10 @@ public Action<? super AttributeContainer> addAttributes() {
public void handle(SourceSet sourceSet) {
super.handle(sourceSet);

if (!Util.contains(getProject().getConfigurations(), sourceSet, false, this.asDependency())) return;
var asDependency = this.asDependency();
if (asDependency == null) return;

if (!Util.contains(getProject().getConfigurations(), sourceSet, false, asDependency)) return;
if (!this.atPath.isPresent()) return;

var itor = sourceSet.getResources().getSrcDirs().iterator();
Expand All @@ -235,7 +249,7 @@ public void handle(SourceSet sourceSet) {
this.atFile.convention(this.getProjectLayout().getProjectDirectory().file(this.getProviders().provider(() -> "src/%s/resources/%s".formatted(sourceSet.getName(), this.atPath.get()))).get());
}

ArtifactAccessTransformer.validateConfig(getProject(), this.asDependency(), this.atFile);
ArtifactAccessTransformer.validateConfig(getProject(), asDependency, this.atFile);
}

private Attribute<Boolean> registerTransform() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ static boolean is(Dependency dependency) {

ExternalModuleDependency init(Object dependencyNotation, Closure<?> closure);

ExternalModuleDependency asDependency();
@Nullable("configuration cache") ExternalModuleDependency asDependency();

TaskProvider<SyncMavenizer> asTask();
@Nullable("configuration cache") TaskProvider<SyncMavenizer> asTask();

Action<? super AttributeContainer> addAttributes();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ sealed interface Attributes permits MinecraftExtensionInternal.AttributesInterna
/// The [operating system family][OperatingSystemFamily] of the project's host.
///
/// This is used to filter natives from the Minecraft repo.
Attribute<OperatingSystemFamily> os = Attribute.of("net.minecraftforge.native.operatingSystem", OperatingSystemFamily.class);
Attribute<String> os = Attribute.of("net.minecraftforge.native.operatingSystem", String.class);
/// The requested mappings channel of the project.
///
/// This is determined using [MinecraftMappings#channel()] via [#getMappings()]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,10 @@ 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) {
syncMavenizer.configure(task -> task.dependsOn(minecraftDependency.asTask()));
var mavenizer = minecraftDependency.asTask();
if (mavenizer == null) continue;

syncMavenizer.configure(task -> task.dependsOn(mavenizer));
}

project.getPluginManager().withPlugin("eclipse", eclipsePlugin -> {
Expand Down Expand Up @@ -302,8 +305,8 @@ private void finish(Project project) {
// This can never be null in production and is only here to make the IDE happy.
assert minecraftDependency != null;

var dependency = minecraftDependency.asDependency();
this.runs.forEach(options -> SlimeLauncherExec.register(project, sourceSet, options, dependency, single));
var impl = (MinecraftDependencyImpl) minecraftDependency;
this.runs.forEach(options -> SlimeLauncherExec.register(project, sourceSet, options, impl.module.get(), impl.version.get(), impl.asPath.get(), impl.asString.get(), single));
}
});
}
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/net/minecraftforge/gradle/OperatingSystemName.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package net.minecraftforge.gradle;

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;

abstract class OperatingSystemName implements ValueSource<String, OperatingSystemName.Parameters> {
interface Parameters extends ValueSourceParameters {
SetProperty<OS> getAllowedOperatingSystems();
}

@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();
}
}
55 changes: 36 additions & 19 deletions src/main/java/net/minecraftforge/gradle/SlimeLauncherExec.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import org.gradle.api.UnknownDomainObjectException;
import org.gradle.api.UnknownTaskException;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.ModuleIdentifier;
import org.gradle.api.attributes.Usage;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.ListProperty;
Expand All @@ -38,22 +40,27 @@
import java.util.Map;

abstract class SlimeLauncherExec extends JavaExec implements ForgeGradleTask, HasPublicType {
static void register(Project project, SourceSet sourceSet, SlimeLauncherOptionsImpl options, Dependency dependency, boolean single) {
static void register(Project project, SourceSet sourceSet, SlimeLauncherOptionsImpl options, ModuleIdentifier module, String version, String asPath, String asString, boolean single) {
TaskProvider<SlimeLauncherMetadata> metadata;
{
TaskProvider<SlimeLauncherMetadata> t;
var taskName = "slimeLauncherMetadata" + (single ? "" : "for" + Util.dependencyToCamelCase(dependency));
var taskName = "slimeLauncherMetadata" + (single ? "" : "for" + Util.dependencyToCamelCase(module));
try {
t = project.getTasks().named(taskName, SlimeLauncherMetadata.class);
} catch (UnknownDomainObjectException e) {
var metadataZip = project.getObjects().fileProperty().fileProvider(project.getProviders().provider(() ->
project.getConfigurations().detachedConfiguration(
project.getDependencyFactory().create(dependency.getGroup(), dependency.getName(), dependency.getVersion(), "metadata", "zip")
).getSingleFile()
));
var metadataDep = project.getDependencyFactory().create(module.getGroup(), module.getName(), version, "metadata", "zip");
var metadataAttr = project.getObjects().named(Usage.class, "metadata");
var metadataZip = project.getObjects().fileProperty().fileProvider(project.getProviders().provider(() -> {
var configuration = project.getConfigurations().detachedConfiguration(
metadataDep
);
configuration.setTransitive(false);
configuration.attributes(a -> a.attribute(Usage.USAGE_ATTRIBUTE, metadataAttr));
return configuration.getSingleFile();
}));

t = project.getTasks().register(taskName, SlimeLauncherMetadata.class, task -> {
task.setDescription("Extracts the Slime Launcher metadata%s.".formatted(single ? "" : " for '%s'".formatted(Util.toString(dependency))));
task.setDescription("Extracts the Slime Launcher metadata%s.".formatted(single ? "" : " for '%s'".formatted(asString)));

task.getMetadataZip().set(metadataZip);
});
Expand All @@ -62,16 +69,17 @@ static void register(Project project, SourceSet sourceSet, SlimeLauncherOptionsI
metadata = t;
}

var taskName = sourceSet.getTaskName("run", options.getName()) + (single ? "" : "for" + Util.dependencyToCamelCase(dependency));
var taskName = sourceSet.getTaskName("run", options.getName()) + (single ? "" : "for" + Util.dependencyToCamelCase(module));
project.getTasks().register(taskName, SlimeLauncherExec.class, task -> {
task.getRunName().set(options.getName());
task.setDescription("Runs the '%s' Slime Launcher run configuration.".formatted(options.getName()));

task.classpath(task.getObjectFactory().fileCollection().from(task.getProviderFactory().provider(sourceSet::getRuntimeClasspath)));
task.getJavaLauncher().unset();

var caches = task.getObjectFactory().directoryProperty().value(task.globalCaches().dir("slime-launcher/cache/%s".formatted(Util.pathify(dependency))));
var caches = task.getObjectFactory().directoryProperty().value(task.globalCaches().dir("slime-launcher/cache/%s".formatted(asPath)));
task.getCacheDir().set(caches.map(task.problems.ensureFileLocation()));
task.getMetadataZip().set(metadata.flatMap(SlimeLauncherMetadata::getMetadataZip));
task.getRunsJson().set(metadata.flatMap(SlimeLauncherMetadata::getRunsJson));

task.getOptions().set(options);
Expand All @@ -84,9 +92,11 @@ static void register(Project project, SourceSet sourceSet, SlimeLauncherOptionsI

protected abstract @Internal DirectoryProperty getCacheDir();

protected abstract @InputFile RegularFileProperty getMetadataZip();

protected abstract @InputFile RegularFileProperty getRunsJson();

protected abstract @Input Property<String> getDelegateMainClass();
protected abstract @Input @Optional Property<String> getDelegateMainClass();

protected abstract @Input @Optional ListProperty<String> getDelegateArgs();

Expand Down Expand Up @@ -116,7 +126,7 @@ public SlimeLauncherExec() {
@Override
public void exec() {
Provider<String> mainClass;
Provider<List<String>> args;
List<String> args;

//region Launcher Metadata Inheritance
Map<String, RunConfig> configs = Map.of();
Expand All @@ -129,12 +139,12 @@ public void exec() {
// continue
}

var options = (SlimeLauncherOptionsImpl) this.getOptions().get();
options.inherit(configs);
var options = ((SlimeLauncherOptionsInternal) this.getOptions().get()).inherit(configs);

mainClass = this.getDelegateMainClass().orElse(options.getMainClass().filter(Util::isPresent));
args = this.getDelegateArgs().orElse(options.getArgs());
this.jvmArgs(options.getJvmArgs());
args = new ArrayList<>(options.getArgs().getOrElse(List.of()));
args.addAll(this.getDelegateArgs().getOrElse(List.of()));
this.jvmArgs(options.getJvmArgs().get());
if (!options.getClasspath().isEmpty())
this.setClasspath(options.getClasspath());
if (options.getMinHeapSize().filter(Util::isPresent).isPresent())
Expand All @@ -151,11 +161,11 @@ public void exec() {
} else {
this.args("--main", mainClass.get(),
"--cache", this.getCacheDir().get().getAsFile().getAbsolutePath(),
"--metadata", this.getRunsJson().get().getAsFile().getAbsolutePath(),
"--metadata", this.getMetadataZip().get().getAsFile().getAbsolutePath(),
"--");
}

this.args(args.get().toArray());
this.args(args);

if (!this.getClient().getOrElse(false))
this.setStandardInput(System.in);
Expand All @@ -167,6 +177,13 @@ public void exec() {
}

this.getLogger().info("{} {}", this.getClasspath().getAsPath(), String.join(" ", this.getArgs()));
super.exec();
try {
super.exec();
} catch (Exception e) {
this.getLogger().error("Something went wrong! Here is some debug info.");
this.getLogger().error("Args: {}", this.getArgs());
this.getLogger().error("Options: {}", options);
throw e;
}
}
}
Loading