mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-03-28 04:07:01 -05:00
Port Forge run templates to the new classpath group system
This commit is contained in:
@@ -35,6 +35,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import dev.architectury.loom.forge.dependency.ForgeModClassesService;
|
||||
import dev.architectury.loom.util.collection.CollectionUtil;
|
||||
import org.gradle.api.Named;
|
||||
|
||||
@@ -118,7 +119,7 @@ public record ForgeRunTemplate(
|
||||
});
|
||||
|
||||
// Add MOD_CLASSES, this is something that ForgeGradle does
|
||||
settings.getEnvironmentVariables().computeIfAbsent("MOD_CLASSES", $ -> ConfigValue.of("{source_roots}").resolve(configValueResolver));
|
||||
settings.getEnvironmentVariables().putIfAbsent(ForgeModClassesService.ENVIRONMENT_VARIABLE, ForgeModClassesService.VARIABLE_KEY);
|
||||
}
|
||||
|
||||
public Resolved resolve(ConfigValue.Resolver configValueResolver) {
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package dev.architectury.loom.forge.dependency;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import dev.architectury.loom.util.Version;
|
||||
import dev.architectury.loom.util.collection.Multimap;
|
||||
import org.gradle.api.NamedDomainObjectContainer;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
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.Nested;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.ModSettings;
|
||||
import net.fabricmc.loom.configuration.classpathgroups.ClasspathGroup;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
||||
import net.fabricmc.loom.task.service.ClasspathGroupService;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.service.Service;
|
||||
import net.fabricmc.loom.util.service.ServiceFactory;
|
||||
import net.fabricmc.loom.util.service.ServiceType;
|
||||
|
||||
public final class ForgeModClassesService extends Service<ForgeModClassesService.Options> {
|
||||
public static final ServiceType<ForgeModClassesService.Options, ForgeModClassesService> TYPE = new ServiceType<>(ForgeModClassesService.Options.class, ForgeModClassesService.class);
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ForgeModClassesService.class);
|
||||
|
||||
public static final String ENVIRONMENT_VARIABLE = "MOD_CLASSES";
|
||||
public static final String VARIABLE_KEY = "{source_roots}";
|
||||
|
||||
public interface Options extends Service.Options {
|
||||
@Nested
|
||||
MapProperty<String, ClasspathGroupService.Options> getClasspathGroupOptions();
|
||||
|
||||
@Input
|
||||
Property<String> getSourceRootsSeparator();
|
||||
}
|
||||
|
||||
public static Provider<Options> createOptions(Project project) {
|
||||
return TYPE.maybeCreate(project, options -> {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
|
||||
if (!extension.isForgeLike()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (RunConfigSettings runConfigSettings : extension.getRunConfigs()) {
|
||||
NamedDomainObjectContainer<ModSettings> modOverrides = runConfigSettings.getMods();
|
||||
NamedDomainObjectContainer<ModSettings> modSettings = !modOverrides.isEmpty() ? modOverrides : extension.getMods();
|
||||
options.getClasspathGroupOptions().put(runConfigSettings.getName(), ClasspathGroupService.create(project, modSettings));
|
||||
}
|
||||
|
||||
options.getSourceRootsSeparator().set(getSourceRootsSeparator(project));
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private static String getSourceRootsSeparator(Project project) {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
|
||||
// Some versions of Forge 49+ requires a different separator
|
||||
if (!extension.isForge() || extension.getForgeProvider().getVersion().getMajorVersion() < Constants.Forge.MIN_BOOTSTRAP_DEV_VERSION) {
|
||||
return File.pathSeparator;
|
||||
}
|
||||
|
||||
for (Dependency dependency : project.getConfigurations().getByName(Constants.Configurations.FORGE_DEPENDENCIES).getDependencies()) {
|
||||
if (dependency.getGroup().equals("net.minecraftforge") && dependency.getName().equals("bootstrap-dev")) {
|
||||
Version version = Version.parse(dependency.getVersion());
|
||||
return version.compareTo(Version.parse("2.1.4")) >= 0 ? File.pathSeparator : ";";
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.warn("Failed to find bootstrap-dev in forge dependencies, using File.pathSeparator as separator");
|
||||
return File.pathSeparator;
|
||||
}
|
||||
|
||||
public ForgeModClassesService(Options options, ServiceFactory serviceFactory) {
|
||||
super(options, serviceFactory);
|
||||
}
|
||||
|
||||
public String getModClasses(String runConfig) {
|
||||
// Use a set-valued multimap for deduplicating paths.
|
||||
Multimap<String, String> modClasses = Multimap.setMultimap();
|
||||
String separator = getOptions().getSourceRootsSeparator().get();
|
||||
ClasspathGroupService classpathGroupService = getServiceFactory().get(getOptions().getClasspathGroupOptions().getting(runConfig));
|
||||
|
||||
for (ClasspathGroup group : classpathGroupService.getClasspathGroups()) {
|
||||
// Note: In Forge 1.16.5, resources have to come first to find mods.toml
|
||||
if (group.resourceDir() != null) {
|
||||
modClasses.put(group.name(), group.resourceDir());
|
||||
}
|
||||
|
||||
for (File file : classpathGroupService.getClasspath(group)) {
|
||||
modClasses.put(group.name(), file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
return modClasses.streamEntries()
|
||||
.map(entry -> entry.left() + "%%" + entry.right())
|
||||
.collect(Collectors.joining(separator));
|
||||
}
|
||||
}
|
||||
@@ -40,22 +40,13 @@ import dev.architectury.loom.forge.config.ConfigValue;
|
||||
import dev.architectury.loom.forge.config.ForgeRunTemplate;
|
||||
import dev.architectury.loom.forge.config.UserdevConfig;
|
||||
import dev.architectury.loom.util.DependencyDownloader;
|
||||
import dev.architectury.loom.util.Version;
|
||||
import dev.architectury.loom.util.collection.Multimap;
|
||||
import org.gradle.api.NamedDomainObjectContainer;
|
||||
import org.gradle.api.NamedDomainObjectSet;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.ModSettings;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.gradle.SourceSetHelper;
|
||||
import net.fabricmc.loom.util.gradle.SourceSetReference;
|
||||
|
||||
public class ForgeRunsProvider {
|
||||
public class ForgeRunsProvider implements ConfigValue.Resolver {
|
||||
private final Project project;
|
||||
private final LoomGradleExtension extension;
|
||||
private final JsonObject json;
|
||||
@@ -78,11 +69,8 @@ public class ForgeRunsProvider {
|
||||
return new ForgeRunsProvider(project, userdevProvider.getJson(), userdevProvider.getConfig());
|
||||
}
|
||||
|
||||
public ConfigValue.Resolver getResolver(@Nullable RunConfigSettings runConfig) {
|
||||
return variable -> resolve(runConfig, variable);
|
||||
}
|
||||
|
||||
private String resolve(@Nullable RunConfigSettings runConfig, ConfigValue.Variable variable) {
|
||||
@Override
|
||||
public String resolve(ConfigValue.Variable variable) {
|
||||
String key = variable.name();
|
||||
String string = '{' + key + '}';
|
||||
|
||||
@@ -128,37 +116,11 @@ public class ForgeRunsProvider {
|
||||
} else if (key.equals("natives")) {
|
||||
string = extension.getFiles().getNativesDirectory(project).getAbsolutePath();
|
||||
} else if (key.equals("source_roots")) {
|
||||
// Use a set-valued multimap for deduplicating paths.
|
||||
Multimap<String, String> modClasses = Multimap.setMultimap();
|
||||
NamedDomainObjectContainer<ModSettings> mods = extension.getMods();
|
||||
String separator = getSourceRootsSeparator();
|
||||
|
||||
if (runConfig != null && !runConfig.getMods().isEmpty()) {
|
||||
mods = runConfig.getMods();
|
||||
}
|
||||
|
||||
for (ModSettings mod : mods) {
|
||||
// Note: In Forge 1.16.5, resources have to come first to find mods.toml
|
||||
for (SourceSetReference modSourceSet : mod.getModSourceSets().get()) {
|
||||
File resourcesDir = modSourceSet.sourceSet().getOutput().getResourcesDir();
|
||||
modClasses.put(mod.getName(), resourcesDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
for (File file : SourceSetHelper.getClasspath(mod, project)) {
|
||||
modClasses.put(mod.getName(), file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
string = modClasses.entrySet().stream()
|
||||
.map(entry -> entry.getKey() + "%%" + entry.getValue())
|
||||
.collect(Collectors.joining(separator));
|
||||
// ignored, handled later using ForgeModClassesService
|
||||
} else if (key.equals("mcp_mappings")) {
|
||||
string = "loom.stub";
|
||||
} else if (json.has(key)) {
|
||||
JsonElement element = json.get(key);
|
||||
|
||||
if (element.isJsonArray()) {
|
||||
string = StreamSupport.stream(element.getAsJsonArray().spliterator(), false)
|
||||
} else if (key.equals("modules")) {
|
||||
string = StreamSupport.stream(json.getAsJsonArray("modules").spliterator(), false)
|
||||
.map(JsonElement::getAsString)
|
||||
.flatMap(str -> {
|
||||
if (str.contains(":")) {
|
||||
@@ -170,9 +132,9 @@ public class ForgeRunsProvider {
|
||||
return Stream.of(str);
|
||||
})
|
||||
.collect(Collectors.joining(File.pathSeparator));
|
||||
} else {
|
||||
} else if (json.has(key)) {
|
||||
JsonElement element = json.get(key);
|
||||
string = element.toString();
|
||||
}
|
||||
} else {
|
||||
project.getLogger().warn("Unrecognized template! " + string);
|
||||
}
|
||||
@@ -188,21 +150,4 @@ public class ForgeRunsProvider {
|
||||
private Set<File> minecraftClasspath() {
|
||||
return DependencyDownloader.resolveFiles(project, project.getConfigurations().getByName(Constants.Configurations.FORGE_RUNTIME_LIBRARY), true);
|
||||
}
|
||||
|
||||
private String getSourceRootsSeparator() {
|
||||
// Some versions of Forge 49+ requires a different separator
|
||||
if (!extension.isForge() || extension.getForgeProvider().getVersion().getMajorVersion() < Constants.Forge.MIN_BOOTSTRAP_DEV_VERSION) {
|
||||
return File.pathSeparator;
|
||||
}
|
||||
|
||||
for (Dependency dependency : project.getConfigurations().getByName(Constants.Configurations.FORGE_DEPENDENCIES).getDependencies()) {
|
||||
if (dependency.getGroup().equals("net.minecraftforge") && dependency.getName().equals("bootstrap-dev")) {
|
||||
Version version = Version.parse(dependency.getVersion());
|
||||
return version.compareTo(Version.parse("2.1.4")) >= 0 ? File.pathSeparator : ";";
|
||||
}
|
||||
}
|
||||
|
||||
project.getLogger().warn("Failed to find bootstrap-dev in forge dependencies, using File.pathSeparator as separator");
|
||||
return File.pathSeparator;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SequencedSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import net.fabricmc.loom.util.Pair;
|
||||
|
||||
public interface Multimap<K, V> {
|
||||
static <K, V> Specialized<K, V, SequencedSet<V>> setMultimap() {
|
||||
@@ -26,6 +29,11 @@ public interface Multimap<K, V> {
|
||||
Map<K, ? extends Collection<V>> asMap();
|
||||
Set<? extends Map.Entry<K, ? extends Collection<V>>> entrySet();
|
||||
|
||||
default Stream<Pair<K, V>> streamEntries() {
|
||||
return entrySet().stream()
|
||||
.flatMap(entry -> entry.getValue().stream().map(value -> new Pair<>(entry.getKey(), value)));
|
||||
}
|
||||
|
||||
interface Specialized<K, V, C extends Collection<V>> extends Multimap<K, V> {
|
||||
@Override
|
||||
C get(K key);
|
||||
|
||||
@@ -34,6 +34,7 @@ import net.fabricmc.loom.util.Constants;
|
||||
|
||||
public class LoomCompanionGradlePlugin implements Plugin<Project> {
|
||||
public static final String NAME = "dev.architectury.loom-companion";
|
||||
public static final String UPSTREAM_NAME = "net.fabricmc.fabric-loom-companion";
|
||||
|
||||
@Override
|
||||
public void apply(@NotNull Project project) {
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
import org.gradle.api.artifacts.ProjectDependency;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.file.DirectoryProperty;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
@@ -54,6 +55,13 @@ public abstract class ModSettings implements Named {
|
||||
*/
|
||||
public abstract ConfigurableFileCollection getModFiles();
|
||||
|
||||
/**
|
||||
* The main resource directory in the mod.
|
||||
* On Forge and NeoForge, this is the resource directory that contains mods.toml.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public abstract DirectoryProperty getMainResourceDirectory();
|
||||
|
||||
@Inject
|
||||
public ModSettings() {
|
||||
getExternalGroups().finalizeValueOnRead();
|
||||
@@ -125,6 +133,14 @@ public abstract class ModSettings implements Named {
|
||||
SourceSetReference ref = new SourceSetReference(SourceSetHelper.getSourceSetByName(sourceSetName, getProject()), getProject());
|
||||
List<File> classpath = SourceSetHelper.getClasspath(ref, false);
|
||||
getModFiles().from(classpath);
|
||||
|
||||
// Arch: store resource dir
|
||||
File resourcesDir = ref.sourceSet().getOutput().getResourcesDir();
|
||||
|
||||
if (resourcesDir != null && !getMainResourceDirectory().isPresent()) {
|
||||
getMainResourceDirectory().set(resourcesDir);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,15 +30,20 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.gradle.api.file.FileSystemLocation;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.loom.api.ModSettings;
|
||||
|
||||
public record ClasspathGroup(List<String> paths, List<ExternalClasspathGroup> externalGroups) implements Serializable {
|
||||
public record ClasspathGroup(String name, @Nullable String resourceDir, List<String> paths, List<ExternalClasspathGroup> externalGroups) implements Serializable {
|
||||
public static List<ClasspathGroup> fromModSettings(Set<ModSettings> modSettings) {
|
||||
return modSettings.stream().map(s -> new ClasspathGroup(getPaths(s), s.getExternalGroups().get())).toList();
|
||||
return modSettings.stream().map(s -> new ClasspathGroup(s.getName(), getAbsolutePath(s.getMainResourceDirectory().getOrNull()), getPaths(s), s.getExternalGroups().get())).toList();
|
||||
}
|
||||
|
||||
// TODO remove this constructor when updating to Gradle 9.0, works around an issue where config cache cannot serialize immutable lists
|
||||
public ClasspathGroup(List<String> paths, List<ExternalClasspathGroup> externalGroups) {
|
||||
public ClasspathGroup(String name, @Nullable String resourceDir, List<String> paths, List<ExternalClasspathGroup> externalGroups) {
|
||||
this.name = name;
|
||||
this.resourceDir = resourceDir;
|
||||
this.paths = new ArrayList<>(paths);
|
||||
this.externalGroups = new ArrayList<>(externalGroups);
|
||||
}
|
||||
@@ -50,4 +55,12 @@ public record ClasspathGroup(List<String> paths, List<ExternalClasspathGroup> ex
|
||||
.map(File::getAbsolutePath)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private static @Nullable String getAbsolutePath(@Nullable FileSystemLocation location) {
|
||||
if (location == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return location.getAsFile().getAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ public class RunConfig {
|
||||
public Map<String, Object> environmentVariables;
|
||||
public String projectName;
|
||||
public String folderName;
|
||||
public String name;
|
||||
|
||||
// Turns camelCase/PascalCase into Capital Case
|
||||
// caseConversionExample -> Case Conversion Example
|
||||
@@ -135,6 +136,7 @@ public class RunConfig {
|
||||
boolean appendProjectPath = settings.getAppendProjectPathToConfigName().get();
|
||||
RunConfig runConfig = new RunConfig();
|
||||
runConfig.configName = configName;
|
||||
runConfig.name = name;
|
||||
|
||||
if (appendProjectPath && !GradleUtils.isRootProject(project)) {
|
||||
runConfig.configName += " (" + project.getPath() + ")";
|
||||
|
||||
@@ -446,7 +446,7 @@ public abstract class RunConfigSettings implements Named {
|
||||
ForgeRunTemplate template = runsProvider.getTemplates().findByName(templateName);
|
||||
|
||||
if (template != null) {
|
||||
template.applyTo(this, runsProvider.getResolver(this));
|
||||
template.applyTo(this, runsProvider);
|
||||
} else {
|
||||
project.getLogger().warn("Could not find Forge run template with name '{}'", templateName);
|
||||
}
|
||||
|
||||
@@ -43,12 +43,14 @@ import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
|
||||
import dev.architectury.loom.forge.dependency.ForgeModClassesService;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.Input;
|
||||
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.jetbrains.annotations.VisibleForTesting;
|
||||
@@ -64,6 +66,7 @@ import net.fabricmc.loom.configuration.ide.RunConfig;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
||||
import net.fabricmc.loom.task.AbstractLoomTask;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.service.ScopedServiceFactory;
|
||||
|
||||
public abstract class IdeaSyncTask extends AbstractLoomTask {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(IdeaSyncTask.class);
|
||||
@@ -71,16 +74,29 @@ public abstract class IdeaSyncTask extends AbstractLoomTask {
|
||||
@Nested
|
||||
protected abstract ListProperty<IntelijRunConfig> getIdeaRunConfigs();
|
||||
|
||||
@Nested
|
||||
@Optional
|
||||
protected abstract Property<ForgeModClassesService.Options> getModClassesOptions();
|
||||
|
||||
@Inject
|
||||
public IdeaSyncTask() {
|
||||
setGroup(Constants.TaskGroup.IDE);
|
||||
getIdeaRunConfigs().set(getProject().provider(this::getRunConfigs));
|
||||
getModClassesOptions().set(ForgeModClassesService.createOptions(getProject()));
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
public void runTask() throws IOException {
|
||||
for (IntelijRunConfig config : getIdeaRunConfigs().get()) {
|
||||
config.writeLaunchFile();
|
||||
|
||||
if (getModClassesOptions().isPresent()) {
|
||||
try (var serviceFactory = new ScopedServiceFactory()) {
|
||||
ForgeModClassesService modClassesService = serviceFactory.get(getModClassesOptions());
|
||||
Path launchFile = config.getLaunchFile().get().getAsFile().toPath();
|
||||
setForgeModClasses(launchFile, modClassesService.getModClasses(config.getName().get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +125,7 @@ public abstract class IdeaSyncTask extends AbstractLoomTask {
|
||||
irc.getRunConfigXml().set(runConfigXml);
|
||||
irc.getExcludedLibraryPaths().set(excludedLibraryPaths);
|
||||
irc.getLaunchFile().set(runConfigFile);
|
||||
irc.getName().set(settings.getName());
|
||||
configs.add(irc);
|
||||
|
||||
settings.makeRunDir();
|
||||
@@ -127,6 +144,9 @@ public abstract class IdeaSyncTask extends AbstractLoomTask {
|
||||
@OutputFile
|
||||
RegularFileProperty getLaunchFile();
|
||||
|
||||
@Input
|
||||
Property<String> getName();
|
||||
|
||||
default void writeLaunchFile() throws IOException {
|
||||
Path launchFile = getLaunchFile().get().getAsFile().toPath();
|
||||
|
||||
@@ -160,6 +180,15 @@ public abstract class IdeaSyncTask extends AbstractLoomTask {
|
||||
}
|
||||
}
|
||||
|
||||
public static void setForgeModClasses(Path runConfig, String modClasses) throws IOException {
|
||||
final String inputXml = Files.readString(runConfig, StandardCharsets.UTF_8);
|
||||
final String outputXml = inputXml.replace(ForgeModClassesService.VARIABLE_KEY, modClasses);
|
||||
|
||||
if (!inputXml.equals(outputXml)) {
|
||||
Files.writeString(runConfig, outputXml, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static String setClasspathModificationsInXml(String input, List<String> exclusions) throws Exception {
|
||||
final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
|
||||
@@ -37,6 +37,7 @@ import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import dev.architectury.loom.forge.dependency.ForgeModClassesService;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
@@ -48,6 +49,10 @@ import org.gradle.api.specs.Spec;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputFiles;
|
||||
import org.gradle.api.tasks.JavaExec;
|
||||
import org.gradle.api.tasks.Nested;
|
||||
import org.gradle.api.tasks.Optional;
|
||||
import org.gradle.process.ProcessForkOptions;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -55,6 +60,7 @@ import org.slf4j.LoggerFactory;
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfig;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.service.ScopedServiceFactory;
|
||||
|
||||
public abstract class AbstractRunTask extends JavaExec {
|
||||
private static final CharsetEncoder ASCII_ENCODER = StandardCharsets.US_ASCII.newEncoder();
|
||||
@@ -78,6 +84,15 @@ public abstract class AbstractRunTask extends JavaExec {
|
||||
@InputFiles
|
||||
protected abstract ConfigurableFileCollection getInternalClasspath();
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Nested
|
||||
@Optional
|
||||
protected abstract Property<ForgeModClassesService.Options> getModClassesOptions();
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Input
|
||||
protected abstract Property<String> getRunConfigName();
|
||||
|
||||
public AbstractRunTask(Function<Project, RunConfig> configProvider) {
|
||||
super();
|
||||
setGroup(Constants.TaskGroup.FABRIC);
|
||||
@@ -103,6 +118,9 @@ public abstract class AbstractRunTask extends JavaExec {
|
||||
File buildCache = LoomGradleExtension.get(getProject()).getFiles().getProjectBuildCache();
|
||||
File argFile = new File(buildCache, "argFiles/" + getName());
|
||||
getArgFilePath().set(argFile.getAbsolutePath());
|
||||
|
||||
getModClassesOptions().set(ForgeModClassesService.createOptions(getProject()));
|
||||
getRunConfigName().set(config.map(runConfig -> runConfig.name));
|
||||
}
|
||||
|
||||
private boolean canUseArgFile() {
|
||||
@@ -134,10 +152,23 @@ public abstract class AbstractRunTask extends JavaExec {
|
||||
|
||||
setWorkingDir(new File(getProjectDir().get(), getInternalRunDir().get()));
|
||||
environment(getInternalEnvironmentVars().get());
|
||||
configureForgeModClasses(this);
|
||||
|
||||
super.exec();
|
||||
}
|
||||
|
||||
protected void configureForgeModClasses(ProcessForkOptions forkOptions) {
|
||||
try (var serviceFactory = new ScopedServiceFactory()) {
|
||||
ForgeModClassesService service = serviceFactory.getOrNull(getModClassesOptions());
|
||||
|
||||
if (service != null && ForgeModClassesService.VARIABLE_KEY.equals(forkOptions.getEnvironment().get(ForgeModClassesService.ENVIRONMENT_VARIABLE))) {
|
||||
forkOptions.environment(ForgeModClassesService.ENVIRONMENT_VARIABLE, service.getModClasses(getRunConfigName().get()));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWorkingDir(File dir) {
|
||||
if (!dir.exists()) {
|
||||
|
||||
@@ -35,35 +35,54 @@ import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dev.architectury.loom.forge.dependency.ForgeModClassesService;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.Input;
|
||||
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.plugins.ide.eclipse.model.EclipseModel;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfig;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
||||
import net.fabricmc.loom.configuration.ide.idea.IdeaSyncTask;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.service.ScopedServiceFactory;
|
||||
|
||||
public abstract class GenEclipseRunsTask extends AbstractLoomTask {
|
||||
@Nested
|
||||
protected abstract ListProperty<EclipseRunConfig> getEclipseRunConfigs();
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Nested
|
||||
@Optional
|
||||
protected abstract Property<ForgeModClassesService.Options> getModClassesOptions();
|
||||
|
||||
@Inject
|
||||
public GenEclipseRunsTask() {
|
||||
setGroup(Constants.TaskGroup.IDE);
|
||||
getEclipseRunConfigs().set(getProject().provider(() -> getRunConfigs(getProject())));
|
||||
getModClassesOptions().set(ForgeModClassesService.createOptions(getProject()));
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
public void genRuns() throws IOException {
|
||||
for (EclipseRunConfig runConfig : getEclipseRunConfigs().get()) {
|
||||
runConfig.writeLaunchFile();
|
||||
|
||||
if (getModClassesOptions().isPresent()) {
|
||||
try (var serviceFactory = new ScopedServiceFactory()) {
|
||||
ForgeModClassesService modClassesService = serviceFactory.get(getModClassesOptions());
|
||||
Path launchFile = runConfig.getLaunchFile().get().getAsFile().toPath();
|
||||
IdeaSyncTask.setForgeModClasses(launchFile, modClassesService.getModClasses(runConfig.getName().get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +111,7 @@ public abstract class GenEclipseRunsTask extends AbstractLoomTask {
|
||||
EclipseRunConfig eclipseRunConfig = project.getObjects().newInstance(EclipseRunConfig.class);
|
||||
eclipseRunConfig.getLaunchContent().set(config);
|
||||
eclipseRunConfig.getLaunchFile().set(project.file(configs));
|
||||
eclipseRunConfig.getName().set(name);
|
||||
runConfigs.add(eclipseRunConfig);
|
||||
|
||||
settings.makeRunDir();
|
||||
@@ -107,6 +127,9 @@ public abstract class GenEclipseRunsTask extends AbstractLoomTask {
|
||||
@OutputFile
|
||||
RegularFileProperty getLaunchFile();
|
||||
|
||||
@Input
|
||||
Property<String> getName();
|
||||
|
||||
default void writeLaunchFile() throws IOException {
|
||||
Path launchFile = getLaunchFile().get().getAsFile().toPath();
|
||||
|
||||
|
||||
@@ -41,20 +41,25 @@ import javax.inject.Inject;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import dev.architectury.loom.forge.dependency.ForgeModClassesService;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.services.ServiceReference;
|
||||
import org.gradle.api.tasks.Input;
|
||||
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.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfig;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.gradle.SyncTaskBuildService;
|
||||
import net.fabricmc.loom.util.service.ScopedServiceFactory;
|
||||
|
||||
// Recommended vscode plugin pack:
|
||||
// https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack
|
||||
@@ -69,11 +74,17 @@ public abstract class GenVsCodeProjectTask extends AbstractLoomTask {
|
||||
@OutputFile
|
||||
protected abstract RegularFileProperty getLaunchJson();
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Nested
|
||||
@Optional
|
||||
protected abstract Property<ForgeModClassesService.Options> getModClassesOptions();
|
||||
|
||||
@Inject
|
||||
public GenVsCodeProjectTask() {
|
||||
setGroup(Constants.TaskGroup.IDE);
|
||||
getLaunchConfigurations().set(getProject().provider(this::getConfigurations));
|
||||
getLaunchJson().convention(getProject().getRootProject().getLayout().getProjectDirectory().file(".vscode/launch.json"));
|
||||
getModClassesOptions().set(ForgeModClassesService.createOptions(getProject()));
|
||||
}
|
||||
|
||||
private List<VsCodeConfiguration> getConfigurations() {
|
||||
@@ -120,6 +131,18 @@ public abstract class GenVsCodeProjectTask extends AbstractLoomTask {
|
||||
for (VsCodeConfiguration configuration : getLaunchConfigurations().get()) {
|
||||
JsonObject configurationJson = LoomGradlePlugin.GSON.toJsonTree(configuration).getAsJsonObject();
|
||||
configurationJson.remove("runDir");
|
||||
configurationJson.remove("id");
|
||||
|
||||
if (getModClassesOptions().isPresent()) {
|
||||
try (var serviceFactory = new ScopedServiceFactory()) {
|
||||
ForgeModClassesService service = serviceFactory.get(getModClassesOptions());
|
||||
JsonObject env = configurationJson.getAsJsonObject("env");
|
||||
|
||||
if (env != null && env.has(ForgeModClassesService.ENVIRONMENT_VARIABLE)) {
|
||||
env.addProperty(ForgeModClassesService.ENVIRONMENT_VARIABLE, service.getModClasses(configuration.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final List<JsonElement> toRemove = new LinkedList<>();
|
||||
|
||||
@@ -151,6 +174,7 @@ public abstract class GenVsCodeProjectTask extends AbstractLoomTask {
|
||||
public record VsCodeConfiguration(
|
||||
String type,
|
||||
String name,
|
||||
String id,
|
||||
String request,
|
||||
String cwd,
|
||||
String console,
|
||||
@@ -168,6 +192,7 @@ public abstract class GenVsCodeProjectTask extends AbstractLoomTask {
|
||||
return new VsCodeConfiguration(
|
||||
"java",
|
||||
runConfig.configName,
|
||||
runConfig.name,
|
||||
"launch",
|
||||
"${workspaceFolder}/" + relativeRunDir,
|
||||
"integratedTerminal",
|
||||
|
||||
@@ -67,6 +67,7 @@ public abstract class RenderDocRunTask extends RunGameTask {
|
||||
ExecResult result = getExecOperations().exec(exec -> {
|
||||
exec.workingDir(new File(getProjectDir().get(), getInternalRunDir().get()));
|
||||
exec.environment(getInternalEnvironmentVars().get());
|
||||
configureForgeModClasses(exec);
|
||||
|
||||
exec.commandLine(getRenderDocExecutable().get().getAsFile());
|
||||
exec.args(getRenderDocArgs().get());
|
||||
|
||||
@@ -40,7 +40,6 @@ import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import dev.architectury.loom.forge.config.ConfigValue;
|
||||
import dev.architectury.loom.forge.config.ForgeRunTemplate;
|
||||
import dev.architectury.loom.forge.dependency.ForgeRunsProvider;
|
||||
import org.gradle.api.Project;
|
||||
@@ -64,10 +63,9 @@ import net.fabricmc.loom.build.IntermediaryNamespaces;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.MappedMinecraftProvider;
|
||||
import net.fabricmc.loom.task.AbstractLoomTask;
|
||||
import net.fabricmc.loom.task.service.ClasspathGroupService;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.ModPlatform;
|
||||
import net.fabricmc.loom.util.gradle.SourceSetHelper;
|
||||
import net.fabricmc.loom.task.service.ClasspathGroupService;
|
||||
import net.fabricmc.loom.util.service.ScopedServiceFactory;
|
||||
|
||||
public abstract class GenerateDLIConfigTask extends AbstractLoomTask {
|
||||
@@ -155,10 +153,9 @@ public abstract class GenerateDLIConfigTask extends AbstractLoomTask {
|
||||
if (getExtension().isForgeLike()) {
|
||||
getRunTemplates().addAll(getProject().provider(() -> {
|
||||
final ForgeRunsProvider forgeRunsProvider = getExtension().getForgeRunsProvider();
|
||||
final ConfigValue.Resolver configResolver = forgeRunsProvider.getResolver(null);
|
||||
return forgeRunsProvider.getTemplates()
|
||||
.stream()
|
||||
.map(template -> template.resolve(configResolver))
|
||||
.map(template -> template.resolve(forgeRunsProvider))
|
||||
.toList();
|
||||
}));
|
||||
|
||||
|
||||
@@ -69,10 +69,11 @@ public class ClasspathGroupService extends Service<ClasspathGroupService.Options
|
||||
}
|
||||
|
||||
public static Provider<Options> create(Project project) {
|
||||
return TYPE.create(project, options -> {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
NamedDomainObjectContainer<ModSettings> modSettings = extension.getMods();
|
||||
return create(project, LoomGradleExtension.get(project).getMods());
|
||||
}
|
||||
|
||||
public static Provider<Options> create(Project project, NamedDomainObjectContainer<ModSettings> modSettings) {
|
||||
return TYPE.create(project, options -> {
|
||||
if (modSettings.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -159,4 +160,8 @@ public class ClasspathGroupService extends Service<ClasspathGroupService.Options
|
||||
public boolean hasGroups() {
|
||||
return getOptions().getClasspathGroups().isPresent() && !getOptions().getClasspathGroups().get().isEmpty();
|
||||
}
|
||||
|
||||
public List<ClasspathGroup> getClasspathGroups() {
|
||||
return getOptions().getClasspathGroups().get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.gradle.api.provider.Provider;
|
||||
import net.fabricmc.loom.LoomCompanionGradlePlugin;
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
public final class GradleUtils {
|
||||
private GradleUtils() {
|
||||
@@ -66,7 +65,7 @@ public final class GradleUtils {
|
||||
}
|
||||
|
||||
public static boolean isLoomCompanionProject(Project project) {
|
||||
return project.getPluginManager().hasPlugin(LoomCompanionGradlePlugin.NAME);
|
||||
return project.getPluginManager().hasPlugin(LoomCompanionGradlePlugin.NAME) || project.getPluginManager().hasPlugin(LoomCompanionGradlePlugin.UPSTREAM_NAME);
|
||||
}
|
||||
|
||||
public static Provider<Boolean> getBooleanPropertyProvider(Project project, String key) {
|
||||
|
||||
Reference in New Issue
Block a user