diff --git a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java index 35401ac2..75112529 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java +++ b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java @@ -42,6 +42,7 @@ import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile; import net.fabricmc.loom.configuration.processors.JarProcessorManager; import net.fabricmc.loom.configuration.providers.forge.DependencyProviders; import net.fabricmc.loom.configuration.providers.forge.ForgeProvider; +import net.fabricmc.loom.configuration.providers.forge.ForgeRunsProvider; import net.fabricmc.loom.configuration.providers.forge.ForgeUniversalProvider; import net.fabricmc.loom.configuration.providers.forge.ForgeUserdevProvider; import net.fabricmc.loom.configuration.providers.forge.PatchProvider; @@ -173,4 +174,7 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { default ForgeProvider getForgeProvider() { return getDependencyProviders().getProvider(ForgeProvider.class); } + + ForgeRunsProvider getForgeRunsProvider(); + void setForgeRunsProvider(ForgeRunsProvider forgeRunsProvider); } diff --git a/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java b/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java index 4ae7af98..4add29d5 100644 --- a/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java +++ b/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java @@ -46,7 +46,6 @@ import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider; import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder; import net.fabricmc.loom.configuration.ide.RunConfig; import net.fabricmc.loom.configuration.ide.RunConfigSettings; -import net.fabricmc.loom.configuration.launch.LaunchProviderSettings; import net.fabricmc.loom.configuration.processors.JarProcessor; import net.fabricmc.loom.configuration.providers.mappings.NoOpIntermediateMappingsProvider; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration; @@ -230,10 +229,6 @@ public interface LoomGradleExtensionAPI { boolean shouldGenerateSrgTiny(); - void launches(Action> action); - - NamedDomainObjectContainer getLaunchConfigs(); - default void addTaskBeforeRun(String task) { this.getTasksBeforeRun().add(task); } diff --git a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java index 739cf758..5546f71c 100644 --- a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java @@ -300,7 +300,7 @@ public final class CompileConfiguration { mappingsProvider.applyToProject(project, mappingsDep); if (extension.isForge()) { - ForgeRunsProvider.provide(project); + extension.setForgeRunsProvider(ForgeRunsProvider.create(project)); } if (minecraftProvider instanceof ForgeMinecraftProvider patched) { diff --git a/src/main/java/net/fabricmc/loom/configuration/ide/RunConfigSettings.java b/src/main/java/net/fabricmc/loom/configuration/ide/RunConfigSettings.java index d267fb40..fc42fba2 100644 --- a/src/main/java/net/fabricmc/loom/configuration/ide/RunConfigSettings.java +++ b/src/main/java/net/fabricmc/loom/configuration/ide/RunConfigSettings.java @@ -39,8 +39,11 @@ import org.gradle.api.tasks.SourceSet; import org.jetbrains.annotations.ApiStatus; import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.configuration.providers.forge.ForgeRunTemplate; +import net.fabricmc.loom.configuration.providers.forge.ForgeRunsProvider; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets; import net.fabricmc.loom.util.Constants; +import net.fabricmc.loom.util.ModPlatform; import net.fabricmc.loom.util.OperatingSystem; import net.fabricmc.loom.util.gradle.SourceSetHelper; @@ -103,6 +106,7 @@ public final class RunConfigSettings implements Named { private final LoomGradleExtension extension; public final Map envVariables = new HashMap<>(); private List evaluateLater = new ArrayList<>(); + private boolean evaluated = false; public RunConfigSettings(Project project, String baseName) { this.baseName = baseName; @@ -130,6 +134,15 @@ public final class RunConfigSettings implements Named { } this.evaluateLater.clear(); + evaluated = true; + } + + private void evaluateNowOrLater(Runnable runnable) { + if (evaluated) { + runnable.run(); + } else { + evaluateLater(runnable); + } } public Project getProject() { @@ -292,7 +305,11 @@ public final class RunConfigSettings implements Named { public void client() { startFirstThread(); environment("client"); - defaultMainClass(getExtension().isForge() ? Constants.Forge.LAUNCH_TESTING : Constants.Knot.KNOT_CLIENT); + defaultMainClass(Constants.Knot.KNOT_CLIENT); + + if (getExtension().isForge()) { + forgeTemplate("client"); + } } /** @@ -301,7 +318,11 @@ public final class RunConfigSettings implements Named { public void server() { programArg("nogui"); environment("server"); - defaultMainClass(getExtension().isForge() ? Constants.Forge.LAUNCH_TESTING : Constants.Knot.KNOT_SERVER); + defaultMainClass(Constants.Knot.KNOT_SERVER); + + if (getExtension().isForge()) { + forgeTemplate("server"); + } } /** @@ -309,7 +330,36 @@ public final class RunConfigSettings implements Named { */ public void data() { environment("data"); - defaultMainClass(getExtension().isForge() ? Constants.Forge.LAUNCH_TESTING : Constants.Knot.KNOT_SERVER); + defaultMainClass(Constants.Knot.KNOT_SERVER); + + if (getExtension().isForge()) { + forgeTemplate("data"); + } + } + + /** + * Applies a Forge run config template to these settings. + * + *

Calling this method resets the {@link #getDefaultMainClass() defaultMainClass} of this + * run config. If you don't want to use Forge's default main class, you need to specify one manually afterwards. + * + * @param templateName the template name (usually one of {@code server}, {@code client}, {@code data}) + * @since 1.0 + */ + public void forgeTemplate(String templateName) { + ModPlatform.assertPlatform(getExtension(), ModPlatform.FORGE); + defaultMainClass(Constants.Forge.UNDETERMINED_MAIN_CLASS); + // Evaluate later if Forge hasn't been resolved yet. + evaluateNowOrLater(() -> { + ForgeRunsProvider runsProvider = getExtension().getForgeRunsProvider(); + ForgeRunTemplate template = runsProvider.getTemplates().findByName(templateName); + + if (template != null) { + template.applyTo(this, runsProvider); + } else { + project.getLogger().warn("Could not find Forge run template with name '{}'", templateName); + } + }); } /** diff --git a/src/main/java/net/fabricmc/loom/configuration/launch/LaunchProviderSettings.java b/src/main/java/net/fabricmc/loom/configuration/launch/LaunchProviderSettings.java deleted file mode 100644 index 0ac814b5..00000000 --- a/src/main/java/net/fabricmc/loom/configuration/launch/LaunchProviderSettings.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 2021 FabricMC - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package net.fabricmc.loom.configuration.launch; - -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import org.gradle.api.Named; -import org.gradle.api.Project; -import org.jetbrains.annotations.ApiStatus; - -public class LaunchProviderSettings implements Named { - private final String name; - private List> properties = new ArrayList<>(); - private List arguments = new ArrayList<>(); - private List evaluateLater = new ArrayList<>(); - - public LaunchProviderSettings(Project project, String name) { - this.name = name; - } - - @Override - public String getName() { - return name; - } - - @ApiStatus.Internal - public void evaluateLater(Runnable runnable) { - this.evaluateLater.add(runnable); - } - - @ApiStatus.Internal - public void evaluateNow() { - for (Runnable runnable : this.evaluateLater) { - runnable.run(); - } - - this.evaluateLater.clear(); - } - - public void arg(String argument) { - this.arguments.add(argument); - } - - public void arg(String... arguments) { - this.arguments.addAll(Arrays.asList(arguments)); - } - - public void arg(Collection arguments) { - this.arguments.addAll(arguments); - } - - public void property(String key, String value) { - this.properties.add(new AbstractMap.SimpleEntry<>(key, value)); - } - - public void properties(Map arguments) { - this.properties.addAll(arguments.entrySet()); - } - - public List> getProperties() { - return properties; - } - - public List getArguments() { - return arguments; - } -} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/ConfigValue.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/ConfigValue.java similarity index 65% rename from src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/ConfigValue.java rename to src/main/java/net/fabricmc/loom/configuration/providers/forge/ConfigValue.java index a72ee987..ca7b36fd 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/ConfigValue.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/ConfigValue.java @@ -22,28 +22,26 @@ * SOFTWARE. */ -package net.fabricmc.loom.configuration.providers.forge.mcpconfig; - -import java.util.function.Function; +package net.fabricmc.loom.configuration.providers.forge; /** - * A string or a variable in an MCPConfig step or function. - * - *

The special config value variable {@value #OUTPUT} is treated - * as the current step's output path. - * - *

The suffix {@value #PREVIOUS_OUTPUT_SUFFIX} can be used to suffix step names - * to get their output paths. + * A string or a variable in a Forge configuration file, or an MCPConfig step or function. */ public sealed interface ConfigValue { + /** + * The variable that refers to the current MCP step's output path. + */ String OUTPUT = "output"; + /** + * A suffix that is appended to the name of an MCP step to get its output path. + */ String PREVIOUS_OUTPUT_SUFFIX = "Output"; /** - * A special config value that is the path to a log file if absent. + * The variable that refers to a log file for the MCP executor. */ String LOG = "log"; - R fold(Function constant, Function variable); + String resolve(Resolver variableResolver); static ConfigValue of(String str) { if (str.startsWith("{") && str.endsWith("}")) { @@ -53,17 +51,22 @@ public sealed interface ConfigValue { return new Constant(str); } + @FunctionalInterface + interface Resolver { + String resolve(Variable variable); + } + record Constant(String value) implements ConfigValue { @Override - public R fold(Function constant, Function variable) { - return constant.apply(this); + public String resolve(Resolver variableResolver) { + return value; } } record Variable(String name) implements ConfigValue { @Override - public R fold(Function constant, Function variable) { - return variable.apply(this); + public String resolve(Resolver variableResolver) { + return variableResolver.resolve(this); } } } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeRunTemplate.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeRunTemplate.java new file mode 100644 index 00000000..512f089d --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeRunTemplate.java @@ -0,0 +1,91 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2022 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.configuration.providers.forge; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import org.gradle.api.Named; + +import net.fabricmc.loom.configuration.ide.RunConfigSettings; +import net.fabricmc.loom.util.Constants; +import net.fabricmc.loom.util.Pair; +import net.fabricmc.loom.util.function.CollectionUtil; + +public record ForgeRunTemplate( + String name, + String main, + List args, + List jvmArgs, + Map env, + Map props +) implements Named { + @Override + public String getName() { + return name; + } + + public void applyTo(RunConfigSettings settings, ConfigValue.Resolver configValueResolver) { + if (settings.getDefaultMainClass().equals(Constants.Forge.UNDETERMINED_MAIN_CLASS)) { + settings.defaultMainClass(main); + } + + settings.vmArgs(jvmArgs); + + env.forEach((key, value) -> { + String resolved = value.resolve(configValueResolver); + settings.getEnvironmentVariables().putIfAbsent(key, resolved); + }); + } + + public static ForgeRunTemplate fromJson(JsonObject json) { + if (json.has("parents") && !json.getAsJsonArray("parents").isEmpty()) { + throw new IllegalArgumentException("Non-empty parents for run config template not supported!"); + } + + String name = json.getAsJsonPrimitive("name").getAsString(); + String main = json.getAsJsonPrimitive("main").getAsString(); + List args = json.has("args") ? fromJson(json.getAsJsonArray("args")) : List.of(); + List jvmArgs = json.has("jvmArgs") ? fromJson(json.getAsJsonArray("jvmArgs")) : List.of(); + Map env = json.has("env") ? fromJson(json.getAsJsonObject("env"), ConfigValue::of) : Map.of(); + Map props = json.has("props") ? fromJson(json.getAsJsonObject("props"), ConfigValue::of) : Map.of(); + return new ForgeRunTemplate(name, main, args, jvmArgs, env, props); + } + + private static List fromJson(JsonArray json) { + return CollectionUtil.map(json, child -> child.getAsJsonPrimitive().getAsString()); + } + + private static Map fromJson(JsonObject json, Function converter) { + return json.entrySet().stream().map(entry -> { + String value = entry.getValue().getAsJsonPrimitive().getAsString(); + return new Pair<>(entry.getKey(), converter.apply(value)); + }).collect(Collectors.toMap(Pair::left, Pair::right)); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeRunsProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeRunsProvider.java index 329e449a..bf30cce2 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeRunsProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeRunsProvider.java @@ -39,79 +39,45 @@ import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import org.gradle.api.NamedDomainObjectSet; import org.gradle.api.Project; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.ModSettings; -import net.fabricmc.loom.configuration.ide.RunConfigSettings; -import net.fabricmc.loom.configuration.launch.LaunchProviderSettings; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.DependencyDownloader; import net.fabricmc.loom.util.gradle.SourceSetHelper; -public class ForgeRunsProvider { +public class ForgeRunsProvider implements ConfigValue.Resolver { private final Project project; private final LoomGradleExtension extension; private final JsonObject json; + private final NamedDomainObjectSet templates; public ForgeRunsProvider(Project project, JsonObject json) { this.project = project; this.extension = LoomGradleExtension.get(project); this.json = json; + this.templates = project.getObjects().namedDomainObjectSet(ForgeRunTemplate.class); + readTemplates(); } - public static void provide(Project project) { - LoomGradleExtension extension = LoomGradleExtension.get(project); - JsonObject json = extension.getForgeUserdevProvider().getJson(); - ForgeRunsProvider provider = new ForgeRunsProvider(project, json); - + private void readTemplates() { for (Map.Entry entry : json.getAsJsonObject("runs").entrySet()) { - LaunchProviderSettings launchSettings = extension.getLaunchConfigs().findByName(entry.getKey()); - RunConfigSettings settings = extension.getRunConfigs().findByName(entry.getKey()); - JsonObject value = entry.getValue().getAsJsonObject(); - - if (launchSettings != null) { - launchSettings.evaluateLater(() -> { - if (value.has("args")) { - launchSettings.arg(StreamSupport.stream(value.getAsJsonArray("args").spliterator(), false) - .map(JsonElement::getAsString) - .map(provider::processTemplates) - .collect(Collectors.toList())); - } - - if (value.has("props")) { - for (Map.Entry props : value.getAsJsonObject("props").entrySet()) { - String string = provider.processTemplates(props.getValue().getAsString()); - - launchSettings.property(props.getKey(), string); - } - } - }); - } - - if (settings != null) { - settings.evaluateLater(() -> { - settings.defaultMainClass(value.getAsJsonPrimitive("main").getAsString()); - - if (value.has("jvmArgs")) { - settings.vmArgs(StreamSupport.stream(value.getAsJsonArray("jvmArgs").spliterator(), false) - .map(JsonElement::getAsString) - .map(provider::processTemplates) - .collect(Collectors.toList())); - } - - if (value.has("env")) { - for (Map.Entry env : value.getAsJsonObject("env").entrySet()) { - String string = provider.processTemplates(env.getValue().getAsString()); - - settings.envVariables.put(env.getKey(), string); - } - } - }); - } + ForgeRunTemplate template = ForgeRunTemplate.fromJson(entry.getValue().getAsJsonObject()); + templates.add(template); } } + public NamedDomainObjectSet getTemplates() { + return templates; + } + + public static ForgeRunsProvider create(Project project) { + JsonObject json = LoomGradleExtension.get(project).getForgeUserdevProvider().getJson(); + return new ForgeRunsProvider(project, json); + } + public String processTemplates(String string) { if (string.startsWith("{")) { String key = string.substring(1, string.length() - 1); @@ -207,4 +173,9 @@ public class ForgeRunsProvider { private Set minecraftClasspath() { return DependencyDownloader.resolveFiles(project, project.getConfigurations().getByName(Constants.Configurations.FORGE_RUNTIME_LIBRARY), true); } + + @Override + public String resolve(ConfigValue.Variable variable) { + return processTemplates(variable.name()); + } } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/DependencySet.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/DependencySet.java index a1373359..a65f83ca 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/DependencySet.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/DependencySet.java @@ -24,7 +24,7 @@ package net.fabricmc.loom.configuration.providers.forge.mcpconfig; -import static net.fabricmc.loom.configuration.providers.forge.mcpconfig.ConfigValue.PREVIOUS_OUTPUT_SUFFIX; +import static net.fabricmc.loom.configuration.providers.forge.ConfigValue.PREVIOUS_OUTPUT_SUFFIX; import java.util.ArrayDeque; import java.util.ArrayList; @@ -40,6 +40,7 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; +import net.fabricmc.loom.configuration.providers.forge.ConfigValue; import net.fabricmc.loom.util.function.CollectionUtil; public final class DependencySet { diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/McpConfigFunction.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/McpConfigFunction.java index beb294da..8ae7e2c1 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/McpConfigFunction.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/McpConfigFunction.java @@ -29,6 +29,7 @@ import java.util.List; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import net.fabricmc.loom.configuration.providers.forge.ConfigValue; import net.fabricmc.loom.util.function.CollectionUtil; /** diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/McpConfigStep.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/McpConfigStep.java index 0cb45f5f..2b9295a1 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/McpConfigStep.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/McpConfigStep.java @@ -29,6 +29,8 @@ import java.util.Map; import com.google.common.collect.ImmutableMap; import com.google.gson.JsonObject; +import net.fabricmc.loom.configuration.providers.forge.ConfigValue; + public record McpConfigStep(String type, String name, Map config) { private static final String TYPE_KEY = "type"; private static final String NAME_KEY = "name"; diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/McpExecutor.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/McpExecutor.java index a0492536..eb36cafe 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/McpExecutor.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/McpExecutor.java @@ -52,6 +52,7 @@ import org.gradle.process.JavaExecSpec; import org.jetbrains.annotations.Nullable; import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.configuration.providers.forge.ConfigValue; import net.fabricmc.loom.configuration.providers.forge.mcpconfig.steplogic.ConstantLogic; import net.fabricmc.loom.configuration.providers.forge.mcpconfig.steplogic.DownloadManifestFileLogic; import net.fabricmc.loom.configuration.providers.forge.mcpconfig.steplogic.FunctionLogic; @@ -141,7 +142,7 @@ public final class McpExecutor { } private String resolve(McpConfigStep step, ConfigValue value) { - return value.fold(ConfigValue.Constant::value, variable -> { + return value.resolve(variable -> { String name = variable.name(); @Nullable ConfigValue valueFromStep = step.config().get(name); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/steplogic/InjectLogic.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/steplogic/InjectLogic.java index 7bd432dd..ea812986 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/steplogic/InjectLogic.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/steplogic/InjectLogic.java @@ -32,7 +32,7 @@ import java.nio.file.StandardCopyOption; import java.util.Iterator; import java.util.stream.Stream; -import net.fabricmc.loom.configuration.providers.forge.mcpconfig.ConfigValue; +import net.fabricmc.loom.configuration.providers.forge.ConfigValue; import net.fabricmc.loom.util.FileSystemUtil; public final class InjectLogic implements StepLogic { diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/steplogic/PatchLogic.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/steplogic/PatchLogic.java index 06bd3aab..1e4fe546 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/steplogic/PatchLogic.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/steplogic/PatchLogic.java @@ -33,7 +33,7 @@ import codechicken.diffpatch.util.LoggingOutputStream; import codechicken.diffpatch.util.PatchMode; import org.gradle.api.logging.LogLevel; -import net.fabricmc.loom.configuration.providers.forge.mcpconfig.ConfigValue; +import net.fabricmc.loom.configuration.providers.forge.ConfigValue; public final class PatchLogic implements StepLogic { @Override diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/steplogic/StepLogic.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/steplogic/StepLogic.java index ad0b93bc..373211c8 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/steplogic/StepLogic.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/steplogic/StepLogic.java @@ -35,7 +35,7 @@ import org.gradle.api.Action; import org.gradle.api.logging.Logger; import org.gradle.process.JavaExecSpec; -import net.fabricmc.loom.configuration.providers.forge.mcpconfig.ConfigValue; +import net.fabricmc.loom.configuration.providers.forge.ConfigValue; import net.fabricmc.loom.util.download.DownloadBuilder; import net.fabricmc.loom.util.function.CollectionUtil; diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/steplogic/StripLogic.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/steplogic/StripLogic.java index 59074768..cf8df4d5 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/steplogic/StripLogic.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/mcpconfig/steplogic/StripLogic.java @@ -33,7 +33,7 @@ import java.nio.file.StandardCopyOption; import java.util.Set; import java.util.stream.Collectors; -import net.fabricmc.loom.configuration.providers.forge.mcpconfig.ConfigValue; +import net.fabricmc.loom.configuration.providers.forge.ConfigValue; import net.fabricmc.loom.util.FileSystemUtil; import net.fabricmc.loom.util.ThreadingUtils; diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java index f7b883bd..dd57850e 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java @@ -59,7 +59,6 @@ import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder; import net.fabricmc.loom.configuration.RemapConfigurations; import net.fabricmc.loom.configuration.ide.RunConfig; import net.fabricmc.loom.configuration.ide.RunConfigSettings; -import net.fabricmc.loom.configuration.launch.LaunchProviderSettings; import net.fabricmc.loom.configuration.processors.JarProcessor; import net.fabricmc.loom.configuration.providers.mappings.GradleMappingContext; import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec; @@ -112,7 +111,6 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA public Boolean generateSrgTiny = null; private final List tasksBeforeRun = Collections.synchronizedList(new ArrayList<>()); public final List> settingsPostEdit = new ArrayList<>(); - private NamedDomainObjectContainer launchConfigs; protected LoomGradleExtensionApiImpl(Project project, LoomFiles directories) { this.jarProcessors = project.getObjects().listProperty(JarProcessor.class) @@ -189,8 +187,6 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA return ModPlatform.FABRIC; })::get); - this.launchConfigs = project.container(LaunchProviderSettings.class, - baseName -> new LaunchProviderSettings(project, baseName)); } @Override @@ -435,16 +431,6 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA return isForge(); } - @Override - public void launches(Action> action) { - action.execute(launchConfigs); - } - - @Override - public NamedDomainObjectContainer getLaunchConfigs() { - return launchConfigs; - } - @Override public List getTasksBeforeRun() { return tasksBeforeRun; diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java index d96cbbdf..2653a685 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java @@ -47,6 +47,7 @@ import net.fabricmc.loom.configuration.LoomDependencyManager; import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile; import net.fabricmc.loom.configuration.processors.JarProcessorManager; import net.fabricmc.loom.configuration.providers.forge.DependencyProviders; +import net.fabricmc.loom.configuration.providers.forge.ForgeRunsProvider; import net.fabricmc.loom.configuration.providers.mappings.IntermediaryMappingsProvider; import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider; @@ -82,6 +83,7 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen // | Architectury Loom | // +-------------------+ private DependencyProviders dependencyProviders; + private ForgeRunsProvider forgeRunsProvider; public LoomGradleExtensionImpl(Project project, LoomFiles files) { super(project, files); @@ -303,4 +305,16 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen public void setDependencyProviders(DependencyProviders dependencyProviders) { this.dependencyProviders = dependencyProviders; } + + @Override + public ForgeRunsProvider getForgeRunsProvider() { + ModPlatform.assertPlatform(this, ModPlatform.FORGE); + return forgeRunsProvider; + } + + @Override + public void setForgeRunsProvider(ForgeRunsProvider forgeRunsProvider) { + ModPlatform.assertPlatform(this, ModPlatform.FORGE); + this.forgeRunsProvider = forgeRunsProvider; + } } diff --git a/src/main/java/net/fabricmc/loom/task/LoomTasks.java b/src/main/java/net/fabricmc/loom/task/LoomTasks.java index 1c4eae99..c0bb9651 100644 --- a/src/main/java/net/fabricmc/loom/task/LoomTasks.java +++ b/src/main/java/net/fabricmc/loom/task/LoomTasks.java @@ -86,7 +86,6 @@ public final class LoomTasks { registerIDETasks(tasks); registerRunTasks(tasks, project); - registerLaunchSettings(project); // Must be done in afterEvaluate to allow time for the build script to configure the jar config. GradleUtils.afterSuccessfulEvaluation(project, () -> { @@ -191,17 +190,6 @@ public final class LoomTasks { }); } - private static void registerLaunchSettings(Project project) { - LoomGradleExtension extension = LoomGradleExtension.get(project); - Preconditions.checkArgument(extension.getLaunchConfigs().size() == 0, "Launch configurations must not be registered before loom"); - extension.getLaunchConfigs().create("client"); - extension.getLaunchConfigs().create("server"); - - if (extension.isForge()) { - extension.getLaunchConfigs().create("data"); - } - } - public static Provider getIDELaunchConfigureTaskName(Project project) { return project.provider(() -> { final MinecraftJarConfiguration jarConfiguration = LoomGradleExtension.get(project).getMinecraftJarConfiguration().get(); diff --git a/src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java b/src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java index 895ae27e..49e1cffa 100644 --- a/src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java +++ b/src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java @@ -40,7 +40,9 @@ import org.apache.commons.io.FileUtils; import org.gradle.api.logging.configuration.ConsoleOutput; import org.gradle.api.tasks.TaskAction; -import net.fabricmc.loom.configuration.launch.LaunchProviderSettings; +import net.fabricmc.loom.configuration.providers.forge.ForgeRunTemplate; +import net.fabricmc.loom.configuration.providers.forge.ForgeRunsProvider; +import net.fabricmc.loom.configuration.providers.forge.ConfigValue; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta; import net.fabricmc.loom.configuration.providers.minecraft.mapped.MappedMinecraftProvider; import net.fabricmc.loom.task.AbstractLoomTask; @@ -132,17 +134,17 @@ public abstract class GenerateDLIConfigTask extends AbstractLoomTask { launchConfig.argument(config); } } - } - for (LaunchProviderSettings settings : getExtension().getLaunchConfigs()) { - settings.evaluateNow(); + ForgeRunsProvider forgeRunsProvider = getExtension().getForgeRunsProvider(); - for (String argument : settings.getArguments()) { - launchConfig.argument(settings.getName(), argument); - } + for (ForgeRunTemplate template : forgeRunsProvider.getTemplates()) { + for (String argument : template.args()) { + launchConfig.argument(template.name(), argument); + } - for (Map.Entry property : settings.getProperties()) { - launchConfig.property(settings.getName(), property.getKey(), property.getValue()); + for (Map.Entry property : template.props().entrySet()) { + launchConfig.property(template.name(), property.getKey(), property.getValue().resolve(forgeRunsProvider)); + } } } diff --git a/src/main/java/net/fabricmc/loom/util/Constants.java b/src/main/java/net/fabricmc/loom/util/Constants.java index 4547c88f..b6f93620 100644 --- a/src/main/java/net/fabricmc/loom/util/Constants.java +++ b/src/main/java/net/fabricmc/loom/util/Constants.java @@ -177,7 +177,7 @@ public class Constants { } public static final class Forge { - public static final String LAUNCH_TESTING = "net.minecraftforge.userdev.LaunchTesting"; + public static final String UNDETERMINED_MAIN_CLASS = "[Forge] Main class has not been determined yet!"; public static final String ACCESS_TRANSFORMER_PATH = "META-INF/accesstransformer.cfg"; public static final String MIXIN_CONFIGS_MANIFEST_KEY = "MixinConfigs"; diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/forge/ConfigValueTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/forge/ConfigValueTest.groovy new file mode 100644 index 00000000..8a410151 --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/unit/forge/ConfigValueTest.groovy @@ -0,0 +1,76 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2022 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.test.unit.forge + +import net.fabricmc.loom.configuration.providers.forge.ConfigValue +import spock.lang.Specification + +class ConfigValueTest extends Specification { + def "bare value is constant"() { + when: + def value = ConfigValue.of('hello') + then: + value instanceof ConfigValue.Constant + (value as ConfigValue.Constant).value() == 'hello' + } + + def "value with opening brace is constant"() { + when: + def value = ConfigValue.of('{hello') + then: + value instanceof ConfigValue.Constant + (value as ConfigValue.Constant).value() == '{hello' + } + + def "value with closing brace is constant"() { + when: + def value = ConfigValue.of('hello}') + then: + value instanceof ConfigValue.Constant + (value as ConfigValue.Constant).value() == 'hello}' + } + + def "value with braces is variable"() { + when: + def value = ConfigValue.of('{hello}') + then: + value instanceof ConfigValue.Variable + (value as ConfigValue.Variable).name() == 'hello' + } + + def "resolving a constant should yield the constant"() { + when: + def value = ConfigValue.of('constant') + then: + value.resolve { throw new AssertionError('should not be called!' as Object) } == 'constant' + } + + def "resolving a variable"() { + when: + def value = ConfigValue.of('{variable}') + then: + value.resolve { it.name().toUpperCase(Locale.ROOT) } == 'VARIABLE' + } +} diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/forge/DependencySetTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/forge/DependencySetTest.groovy index d2ae5e42..8f6e993d 100644 --- a/src/test/groovy/net/fabricmc/loom/test/unit/forge/DependencySetTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/unit/forge/DependencySetTest.groovy @@ -24,7 +24,7 @@ package net.fabricmc.loom.test.unit.forge -import net.fabricmc.loom.configuration.providers.forge.mcpconfig.ConfigValue +import net.fabricmc.loom.configuration.providers.forge.ConfigValue import net.fabricmc.loom.configuration.providers.forge.mcpconfig.DependencySet import net.fabricmc.loom.configuration.providers.forge.mcpconfig.McpConfigStep import spock.lang.Shared diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/forge/ForgeRunTemplateTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/forge/ForgeRunTemplateTest.groovy new file mode 100644 index 00000000..a99d78a2 --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/unit/forge/ForgeRunTemplateTest.groovy @@ -0,0 +1,74 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2022 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.test.unit.forge + +import com.google.gson.Gson +import com.google.gson.JsonObject +import net.fabricmc.loom.configuration.providers.forge.ForgeRunTemplate +import net.fabricmc.loom.util.ZipUtils +import net.fabricmc.loom.util.download.Download +import spock.lang.Specification +import spock.lang.TempDir +import spock.lang.Unroll + +import java.nio.charset.StandardCharsets +import java.nio.file.Path + +class ForgeRunTemplateTest extends Specification { + @TempDir + Path temp + + private JsonObject downloadForgeConfig(String mc, String forge) { + def version = "$mc-$forge" + def url = "https://maven.minecraftforge.net/net/minecraftforge/forge/$version/forge-$version-userdev.jar" + def targetPath = temp.resolve("forge-$version-userdev.jar") + Download.create(url).downloadPath(targetPath) + def text = new String(ZipUtils.unpack(targetPath, 'config.json'), StandardCharsets.UTF_8) + return new Gson().fromJson(text, JsonObject) + } + + @Unroll + def "test #gameVersion #forgeVersion"() { + setup: + def json = downloadForgeConfig(gameVersion, forgeVersion) + + when: + def template = ForgeRunTemplate.fromJson(json.getAsJsonObject("runs").getAsJsonObject("client")) + + then: + template.name == template.name() // check that the name gradle sees matches the name read from the json + template.name() == 'client' + template.main() == mainClass + + where: + gameVersion | forgeVersion | mainClass + '1.14.4' | '28.2.26' | 'net.minecraftforge.userdev.LaunchTesting' + '1.15.2' | '31.2.57' | 'net.minecraftforge.userdev.LaunchTesting' + '1.16.5' | '36.2.39' | 'net.minecraftforge.userdev.LaunchTesting' + '1.17.1' | '37.1.1' | 'cpw.mods.bootstraplauncher.BootstrapLauncher' + '1.18.2' | '40.1.80' | 'cpw.mods.bootstraplauncher.BootstrapLauncher' + '1.19.2' | '43.1.25' | 'cpw.mods.bootstraplauncher.BootstrapLauncher' + } +}