mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-04-03 05:57:42 -05:00
Add DFU for codecs, support NeoForge run config templates
This commit is contained in:
@@ -81,6 +81,7 @@ repositories {
|
||||
excludeGroupByRegex "org\\.eclipse\\.?.*"
|
||||
}
|
||||
}
|
||||
maven { url "https://libraries.minecraft.net/" }
|
||||
}
|
||||
|
||||
configurations {
|
||||
@@ -186,6 +187,7 @@ dependencies {
|
||||
implementation libs.mcinjector
|
||||
implementation libs.opencsv
|
||||
implementation libs.forge.diffpatch
|
||||
implementation 'com.mojang:datafixerupper:6.0.8'
|
||||
|
||||
// Forge mods.toml parsing
|
||||
implementation libs.night.config.toml
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
package net.fabricmc.loom.configuration.providers.forge;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
|
||||
/**
|
||||
* A string or a variable in a Forge configuration file, or an MCPConfig step or function.
|
||||
*/
|
||||
@@ -41,6 +43,16 @@ public sealed interface ConfigValue {
|
||||
*/
|
||||
String LOG = "log";
|
||||
|
||||
Codec<ConfigValue> CODEC = Codec.STRING.xmap(ConfigValue::of, configValue -> {
|
||||
if (configValue instanceof Constant constant) {
|
||||
return constant.value();
|
||||
} else if (configValue instanceof Variable variable) {
|
||||
return "{" + variable.name() + "}";
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unmatched config value");
|
||||
});
|
||||
|
||||
String resolve(Resolver variableResolver);
|
||||
|
||||
static ConfigValue of(String str) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
* Copyright (c) 2022-2023 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
|
||||
@@ -24,18 +24,17 @@
|
||||
|
||||
package net.fabricmc.loom.configuration.providers.forge;
|
||||
|
||||
import java.util.HashMap;
|
||||
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 com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
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(
|
||||
@@ -46,6 +45,51 @@ public record ForgeRunTemplate(
|
||||
Map<String, ConfigValue> env,
|
||||
Map<String, ConfigValue> props
|
||||
) implements Named {
|
||||
public static final Codec<ForgeRunTemplate> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
Codec.STRING.optionalFieldOf("name", "") // note: empty is used since DFU crashes with null
|
||||
.forGetter(ForgeRunTemplate::name),
|
||||
Codec.STRING.fieldOf("main")
|
||||
.forGetter(ForgeRunTemplate::main),
|
||||
ConfigValue.CODEC.listOf().optionalFieldOf("args", List.of())
|
||||
.forGetter(ForgeRunTemplate::args),
|
||||
ConfigValue.CODEC.listOf().optionalFieldOf("jvmArgs", List.of())
|
||||
.forGetter(ForgeRunTemplate::jvmArgs),
|
||||
Codec.unboundedMap(Codec.STRING, ConfigValue.CODEC).optionalFieldOf("env", Map.of())
|
||||
.forGetter(ForgeRunTemplate::env),
|
||||
Codec.unboundedMap(Codec.STRING, ConfigValue.CODEC).optionalFieldOf("props", Map.of())
|
||||
.forGetter(ForgeRunTemplate::props)
|
||||
).apply(instance, ForgeRunTemplate::new));
|
||||
|
||||
public static final Codec<Map<String, ForgeRunTemplate>> MAP_CODEC = Codec.unboundedMap(Codec.STRING, CODEC)
|
||||
.xmap(
|
||||
map -> {
|
||||
final Map<String, ForgeRunTemplate> newMap = new HashMap<>(map);
|
||||
|
||||
// Iterate through all templates and fill in empty names.
|
||||
// The NeoForge format doesn't include the name property, so we'll use the map keys
|
||||
// as a replacement.
|
||||
for (Map.Entry<String, ForgeRunTemplate> entry : newMap.entrySet()) {
|
||||
final ForgeRunTemplate template = entry.getValue();
|
||||
|
||||
if (template.name.isEmpty()) {
|
||||
final ForgeRunTemplate completed = new ForgeRunTemplate(
|
||||
entry.getKey(),
|
||||
template.main,
|
||||
template.args,
|
||||
template.jvmArgs,
|
||||
template.env,
|
||||
template.props
|
||||
);
|
||||
|
||||
entry.setValue(completed);
|
||||
}
|
||||
}
|
||||
|
||||
return newMap;
|
||||
},
|
||||
Function.identity()
|
||||
);
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
@@ -66,29 +110,4 @@ public record ForgeRunTemplate(
|
||||
// Add MOD_CLASSES, this is something that ForgeGradle does
|
||||
settings.getEnvironmentVariables().computeIfAbsent("MOD_CLASSES", $ -> ConfigValue.of("{source_roots}").resolve(configValueResolver));
|
||||
}
|
||||
|
||||
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<ConfigValue> args = json.has("args") ? fromJson(json.getAsJsonArray("args")) : List.of();
|
||||
List<ConfigValue> jvmArgs = json.has("jvmArgs") ? fromJson(json.getAsJsonArray("jvmArgs")) : List.of();
|
||||
Map<String, ConfigValue> env = json.has("env") ? fromJson(json.getAsJsonObject("env"), ConfigValue::of) : Map.of();
|
||||
Map<String, ConfigValue> props = json.has("props") ? fromJson(json.getAsJsonObject("props"), ConfigValue::of) : Map.of();
|
||||
return new ForgeRunTemplate(name, main, args, jvmArgs, env, props);
|
||||
}
|
||||
|
||||
private static List<ConfigValue> fromJson(JsonArray json) {
|
||||
return CollectionUtil.map(json, child -> ConfigValue.of(child.getAsJsonPrimitive().getAsString()));
|
||||
}
|
||||
|
||||
private static <R> Map<String, R> fromJson(JsonObject json, Function<String, R> 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@@ -39,6 +39,7 @@ import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.MultimapBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import org.gradle.api.NamedDomainObjectContainer;
|
||||
import org.gradle.api.NamedDomainObjectSet;
|
||||
import org.gradle.api.Project;
|
||||
@@ -67,10 +68,11 @@ public class ForgeRunsProvider {
|
||||
}
|
||||
|
||||
private void readTemplates() {
|
||||
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject("runs").entrySet()) {
|
||||
ForgeRunTemplate template = ForgeRunTemplate.fromJson(entry.getValue().getAsJsonObject());
|
||||
templates.add(template);
|
||||
}
|
||||
final JsonObject runJson = json.getAsJsonObject("runs");
|
||||
final Collection<ForgeRunTemplate> templates = ForgeRunTemplate.MAP_CODEC.parse(JsonOps.INSTANCE, runJson)
|
||||
.getOrThrow(false, error -> project.getLogger().error("Couldn't read run config templates, {}", error))
|
||||
.values();
|
||||
this.templates.addAll(templates);
|
||||
}
|
||||
|
||||
public NamedDomainObjectSet<ForgeRunTemplate> getTemplates() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
* Copyright (c) 2022-2023 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
|
||||
@@ -29,6 +29,7 @@ import java.nio.file.Path
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.serialization.JsonOps
|
||||
import spock.lang.Specification
|
||||
import spock.lang.TempDir
|
||||
import spock.lang.Unroll
|
||||
@@ -56,7 +57,8 @@ class ForgeRunTemplateTest extends Specification {
|
||||
def json = downloadForgeConfig(gameVersion, forgeVersion)
|
||||
|
||||
when:
|
||||
def template = ForgeRunTemplate.fromJson(json.getAsJsonObject("runs").getAsJsonObject("client"))
|
||||
def result = ForgeRunTemplate.CODEC.parse(JsonOps.INSTANCE, json.getAsJsonObject("runs").getAsJsonObject("client"))
|
||||
def template = result.getOrThrow(false, {})
|
||||
|
||||
then:
|
||||
template.name == template.name() // check that the name gradle sees matches the name read from the json
|
||||
|
||||
Reference in New Issue
Block a user