9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

Merge branch 'Xiao-MoMi:dev' into dev

This commit is contained in:
jhqwqmc
2025-03-13 21:56:13 +08:00
committed by GitHub
8 changed files with 264 additions and 176 deletions

View File

@@ -41,9 +41,11 @@ CraftEngine offers two installation modes: Standard Installation and Mod Mode. A
### 🔧 Install Server Mod ### 🔧 Install Server Mod
- Download the latest [ignite.jar](https://github.com/vectrix-space/ignite/releases) into your server's root directory - Download the latest [ignite.jar](https://github.com/vectrix-space/ignite/releases) into your server's root directory
- Either: - Either:
- Rename your server JAR to `paper.jar` - Rename your server JAR to `paper.jar` and modify startup command to: `-jar ignite.jar`
- Or: - Or:
- Add launch arguments: `-Dignite.locator=paper -Dignite.paper.jar=./paper-xxx.jar` - Use advanced launch arguments
- For paper/folia: `-Dignite.locator=paper -Dignite.paper.jar=./server-xxx.jar -jar ignite.jar`
- For some special paper forks `-Dignite.locator=paper -Dignite.paper.target=cn.dreeam.leaper.QuantumLeaper -Dignite.paper.jar=./leaf-xxx.jar -jar ignite.jar`
- Start the server to generate the `/mods` directory - Start the server to generate the `/mods` directory
- Place the latest [mod.jar](https://github.com/Xiao-MoMi/craft-engine/releases) in `/mods` - Place the latest [mod.jar](https://github.com/Xiao-MoMi/craft-engine/releases) in `/mods`
- Install the plugin by placing its JAR in `/plugins` - Install the plugin by placing its JAR in `/plugins`

View File

@@ -322,13 +322,17 @@ public abstract class AbstractPackManager implements PackManager {
String key = configEntry.getKey(); String key = configEntry.getKey();
try { try {
Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); Key id = Key.withDefaultNamespace(key, cached.pack().namespace());
if (configEntry.getValue() instanceof Map<?, ?> configSection0) { if (isTemplate) {
Map<String, Object> configSection1 = castToMap(configSection0, false); ((TemplateManager) parser).addTemplate(cached.pack(), cached.filePath(), id, configEntry.getValue());
if ((boolean) configSection1.getOrDefault("enable", true)) {
parser.parseSection(cached.pack(), cached.filePath(), id, isTemplate ? configSection1 : plugin.templateManager().applyTemplates(configSection1));
}
} else { } else {
this.plugin.logger().warn(cached.filePath(), "Configuration section is required for " + parser.sectionId() + "." + configEntry.getKey() + " - "); if (configEntry.getValue() instanceof Map<?, ?> configSection0) {
Map<String, Object> configSection1 = castToMap(configSection0, false);
if ((boolean) configSection1.getOrDefault("enable", true)) {
parser.parseSection(cached.pack(), cached.filePath(), id, plugin.templateManager().applyTemplates(configSection1));
}
} else {
this.plugin.logger().warn(cached.filePath(), "Configuration section is required for " + parser.sectionId() + "." + configEntry.getKey() + " - ");
}
} }
} catch (Exception e) { } catch (Exception e) {
this.plugin.logger().warn(cached.filePath(), "Error loading " + parser.sectionId() + "." + key, e); this.plugin.logger().warn(cached.filePath(), "Error loading " + parser.sectionId() + "." + key, e);

View File

@@ -412,6 +412,10 @@ public class ConfigManager implements Reloadable {
return instance.resource_pack$protection$crash_tools$method_3; return instance.resource_pack$protection$crash_tools$method_3;
} }
public static boolean crashTool4() {
return false;
}
public static boolean enableObfuscation() { public static boolean enableObfuscation() {
return instance.resource_pack$protection$obfuscation$enable; return instance.resource_pack$protection$obfuscation$enable;
} }

View File

@@ -0,0 +1,31 @@
package net.momirealms.craftengine.core.plugin.config.template;
import net.momirealms.craftengine.core.util.Key;
import java.util.Map;
public class NullTemplateArgument implements TemplateArgument {
public static final NullTemplateArgument INSTANCE = new NullTemplateArgument();
public static final Factory FACTORY = new Factory();
private NullTemplateArgument() {
}
@Override
public Key type() {
return TemplateArguments.NULL;
}
@Override
public Object get() {
return null;
}
public static class Factory implements TemplateArgumentFactory {
@Override
public TemplateArgument create(Map<String, Object> arguments) {
return NullTemplateArgument.INSTANCE;
}
}
}

View File

@@ -0,0 +1,21 @@
package net.momirealms.craftengine.core.plugin.config.template;
import net.momirealms.craftengine.core.util.Key;
public class ObjectTemplateArgument implements TemplateArgument {
private final Object value;
public ObjectTemplateArgument(Object value) {
this.value = value;
}
@Override
public Key type() {
return TemplateArguments.OBJECT;
}
@Override
public Object get() {
return this.value;
}
}

View File

@@ -14,6 +14,8 @@ public class TemplateArguments {
public static final Key SELF_INCREASE_INT = Key.of("craftengine:self_increase_int"); public static final Key SELF_INCREASE_INT = Key.of("craftengine:self_increase_int");
public static final Key MAP = Key.of("craftengine:map"); public static final Key MAP = Key.of("craftengine:map");
public static final Key LIST = Key.of("craftengine:list"); public static final Key LIST = Key.of("craftengine:list");
public static final Key NULL = Key.of("craftengine:null");
public static final Key OBJECT = Key.of("craftengine:object"); // No Factory, internal use
public static void register(Key key, TemplateArgumentFactory factory) { public static void register(Key key, TemplateArgumentFactory factory) {
Holder.Reference<TemplateArgumentFactory> holder = ((WritableRegistry<TemplateArgumentFactory>) BuiltInRegistries.TEMPLATE_ARGUMENT_FACTORY) Holder.Reference<TemplateArgumentFactory> holder = ((WritableRegistry<TemplateArgumentFactory>) BuiltInRegistries.TEMPLATE_ARGUMENT_FACTORY)
@@ -26,6 +28,7 @@ public class TemplateArguments {
register(SELF_INCREASE_INT, SelfIncreaseIntTemplateArgument.FACTORY); register(SELF_INCREASE_INT, SelfIncreaseIntTemplateArgument.FACTORY);
register(MAP, MapTemplateArgument.FACTORY); register(MAP, MapTemplateArgument.FACTORY);
register(LIST, ListTemplateArgument.FACTORY); register(LIST, ListTemplateArgument.FACTORY);
register(NULL, NullTemplateArgument.FACTORY);
} }
public static TemplateArgument fromMap(Map<String, Object> map) { public static TemplateArgument fromMap(Map<String, Object> map) {

View File

@@ -1,9 +1,12 @@
package net.momirealms.craftengine.core.plugin.config.template; package net.momirealms.craftengine.core.plugin.config.template;
import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.LoadingSequence;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.Reloadable; import net.momirealms.craftengine.core.plugin.Reloadable;
import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser;
import net.momirealms.craftengine.core.util.Key;
import java.nio.file.Path;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -18,6 +21,8 @@ public interface TemplateManager extends Reloadable, ConfigSectionParser {
return CONFIG_SECTION_NAME; return CONFIG_SECTION_NAME;
} }
void addTemplate(Pack pack, Path path, Key id, Object obj);
Map<String, Object> applyTemplates(Map<String, Object> input); Map<String, Object> applyTemplates(Map<String, Object> input);
default int loadingSequence() { default int loadingSequence() {

View File

@@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.plugin.config.template;
import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.GsonHelper;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.PreConditions; import net.momirealms.craftengine.core.util.PreConditions;
@@ -13,16 +14,14 @@ import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import static net.momirealms.craftengine.core.util.MiscUtils.castToList;
import static net.momirealms.craftengine.core.util.MiscUtils.castToMap; import static net.momirealms.craftengine.core.util.MiscUtils.castToMap;
public class TemplateManagerImpl implements TemplateManager { public class TemplateManagerImpl implements TemplateManager {
private static final String EMPTY = "";
private static final String LEFT_BRACKET = "{"; private static final String LEFT_BRACKET = "{";
private static final String RIGHT_BRACKET = "}"; private static final String RIGHT_BRACKET = "}";
private final CraftEngine plugin; private final CraftEngine plugin;
private final Map<Key, Object> templates = new HashMap<>(); private final Map<Key, Object> templates = new HashMap<>();
private final static Set<String> blacklistedKeys = new HashSet<>(Set.of(TEMPLATE, ARGUMENTS, OVERRIDES)); private final static Set<String> NON_TEMPLATE_KEY = new HashSet<>(Set.of(TEMPLATE, ARGUMENTS, OVERRIDES));
public TemplateManagerImpl(CraftEngine plugin) { public TemplateManagerImpl(CraftEngine plugin) {
this.plugin = plugin; this.plugin = plugin;
@@ -34,114 +33,201 @@ public class TemplateManagerImpl implements TemplateManager {
} }
@Override @Override
public void parseSection(Pack pack, public void parseSection(Pack pack, Path path, Key id, Map<String, Object> section) {
Path path, addTemplate(pack, path, id, section);
Key id, }
Map<String, Object> section) {
@Override
public void addTemplate(Pack pack, Path path, Key id, Object obj) {
if (PreConditions.runIfTrue(this.templates.containsKey(id), () -> this.plugin.logger().warn(path, "Template duplicates: " + id))) return; if (PreConditions.runIfTrue(this.templates.containsKey(id), () -> this.plugin.logger().warn(path, "Template duplicates: " + id))) return;
this.templates.put(id, section); this.templates.put(id, obj);
} }
@Override @Override
public Map<String, Object> applyTemplates(Map<String, Object> input) { public Map<String, Object> applyTemplates(Map<String, Object> input) {
Objects.requireNonNull(input, "Input must not be null"); Objects.requireNonNull(input, "Input must not be null");
Map<String, Object> result = new LinkedHashMap<>(); Map<String, Object> result = new LinkedHashMap<>();
applyTemplatesRecursive(EMPTY, input, result, Collections.emptyMap()); processMap(input, Collections.emptyMap(), (obj) -> {
return result; // 当前位于根节点下如果下一级就是模板则应把模板结果与当前map合并
} // 如果模板结果不是map则为非法值因为不可能出现类似于下方的配置
// items:
private void applyTemplatesRecursive(String currentPath, // test:invalid: 111
Map<String, Object> input, if (obj instanceof Map<?,?> mapResult) {
Map<String, Object> result, result.putAll(MiscUtils.castToMap(mapResult, false));
Map<String, Supplier<Object>> parentArguments) {
if (input.containsKey(TEMPLATE)) {
TemplateProcessingResult processingResult = processTemplates(input, parentArguments);
List<Object> templates = processingResult.templates();
Object overrides = processingResult.overrides();
Map<String, Supplier<Object>> arguments = mergeArguments(parentArguments, processingResult.arguments());
for (Object template : templates) {
if (template instanceof Map<?, ?> mapTemplate) {
handleMapTemplate(currentPath, castToMap(mapTemplate, false), overrides, arguments, input, result);
} else if (template instanceof List<?> listTemplate) {
handleListTemplate(currentPath, castToList(listTemplate, false), overrides, arguments, result);
} else if (template instanceof String stringTemplate) {
Object arg = applyArgument(stringTemplate, arguments);
if (arg != null) {
result.put(currentPath, arg);
} else {
result.remove(currentPath);
}
} else {
result.put(currentPath, template);
}
}
} else {
Map<String, Object> innerResult = currentPath.isEmpty() ? result : new LinkedHashMap<>();
if (!currentPath.isEmpty()) {
result.put(currentPath, innerResult);
}
input.forEach((key, value) -> processValue(
value,
processedValue -> {
if (processedValue == null) {
innerResult.remove(key);
} else {
innerResult.put(key, processedValue);
}
},
parentArguments
));
}
}
private TemplateProcessingResult processTemplates(Map<String, Object> input, Map<String, Supplier<Object>> parentArguments) {
List<String> templateIds = MiscUtils.getAsStringList(input.get(TEMPLATE));
List<Object> templateList = new ArrayList<>();
for (String templateId : templateIds) {
Object actualTemplate = templateId.contains(LEFT_BRACKET) && templateId.contains(RIGHT_BRACKET) ? applyArgument(templateId, parentArguments) : templateId;
if (actualTemplate == null) continue;
Object template = Optional.ofNullable(templates.get(Key.of(actualTemplate.toString())))
.orElseThrow(() -> new IllegalArgumentException("Template not found: " + actualTemplate));
templateList.add(template);
}
Map<String, Supplier<Object>> arguments = getArguments(castToMap(input.getOrDefault(ARGUMENTS, Collections.emptyMap()), false), parentArguments);
return new TemplateProcessingResult(
templateList,
input.get(OVERRIDES),
arguments
);
}
private Map<String, Supplier<Object>> getArguments(@NotNull Map<String, Object> argumentMap, @NotNull Map<String, Supplier<Object>> parentArguments) {
Map<String, Supplier<Object>> result = new HashMap<>();
argumentMap.forEach((key, value) -> {
String placeholder = LEFT_BRACKET + key + RIGHT_BRACKET;
if (value instanceof Map<?, ?> nestedMap) {
Map<String, Object> arguments = castToMap(nestedMap, false);
Map<String, Object> nestedResult = new LinkedHashMap<>();
applyTemplatesRecursive(EMPTY, arguments, nestedResult, parentArguments);
result.put(placeholder, TemplateArguments.fromMap(nestedResult));
} else if (value instanceof List<?> nestedList) {
List<Object> arguments = castToList(nestedList, false);
List<Object> nestedResult = new ArrayList<>();
processList(arguments, nestedResult, parentArguments);
result.put(placeholder, new ListTemplateArgument(nestedResult));
} else { } else {
if (value == null) { throw new IllegalArgumentException("Invalid template used. Input: " + GsonHelper.get().toJson(input) + ". Template: " + GsonHelper.get().toJson(obj));
result.put(placeholder, () -> null);
} else {
String valueStr = value.toString();
Object applied = applyArgument(valueStr, parentArguments);
result.put(placeholder, () -> applied);
}
} }
}); });
return result; return result;
} }
private Object applyArgument(String input, Map<String, Supplier<Object>> arguments) { // 对于处理map只有input是已知map而返回值可能并不是
private void processMap(Map<String, Object> input,
Map<String, TemplateArgument> parentArguments,
// 只有当前为模板的时候才会调用callback
Consumer<Object> processCallBack) {
// 传入的input是否含有template这种情况下返回值有可能是非map
if (input.containsKey(TEMPLATE)) {
TemplateProcessingResult processingResult = processTemplates(input, parentArguments);
List<Object> templates = processingResult.templates();
// 你敢保证template里没有template吗
List<Object> processedTemplates = new ArrayList<>();
// 先递归处理后再合并
for (Object template : templates) {
processUnknownTypeMember(template, processingResult.arguments(), processedTemplates::add);
}
Object firstTemplate = processedTemplates.get(0);
// 对于map和list应当对多模板合并
if (firstTemplate instanceof Map<?,?>) {
Map<String, Object> results = new LinkedHashMap<>();
// 仅仅合并list
for (Object processedTemplate : processedTemplates) {
if (processedTemplate instanceof Map<?, ?> anotherMap) {
results.putAll(MiscUtils.castToMap(anotherMap, false));
}
}
results.putAll(processingResult.overrides());
processCallBack.accept(results);
} else if (firstTemplate instanceof List<?>) {
List<Object> results = new ArrayList<>();
// 仅仅合并list
for (Object processedTemplate : processedTemplates) {
if (processedTemplate instanceof List<?> anotherList) {
results.addAll(anotherList);
}
}
processCallBack.accept(results);
} else {
// 其他情况下应当忽略其他的template
processCallBack.accept(firstTemplate);
}
} else {
// 如果不是模板则返回值一定是map
// 依次处理map下的每个参数
Map<String, Object> result = new LinkedHashMap<>();
for (Map.Entry<String, Object> inputEntry : input.entrySet()) {
processUnknownTypeMember(inputEntry.getValue(), parentArguments, (processed) -> result.put(inputEntry.getKey(), processed));
}
processCallBack.accept(result);
}
}
// 处理一个类型未知的值本方法只管将member处理好后传递回调用者
private void processUnknownTypeMember(Object member,
Map<String, TemplateArgument> parentArguments,
Consumer<Object> processCallback) {
if (member instanceof Map<?,?> innerMap) {
// map下面还是个map吗这并不一定
// 比如
// a:
// template: xxx
// 这时候a并不一定是map最终类型取决于template那么应当根据template的结果进行调整所以我们继续交给上方方法处理
processMap(MiscUtils.castToMap(innerMap, false), parentArguments, processCallback);
} else if (member instanceof List<?> innerList) {
// map 下面是个list那么对下面的每个成员再次处理
List<Object> result = new ArrayList<>();
for (Object item : innerList) {
// 处理完以后加入到list内
processUnknownTypeMember(item, parentArguments, result::add);
}
processCallback.accept(result);
} else if (member instanceof String possibleArgument) {
// 如果是个string其可能是 {xxx} 的参数,那么就尝试应用参数后再返回
processCallback.accept(applyArgument(possibleArgument, parentArguments));
} else {
// 对于其他值,直接处理
processCallback.accept(member);
}
}
private TemplateProcessingResult processTemplates(Map<String, Object> input,
Map<String, TemplateArgument> parentArguments) {
// 先获取template节点下所有的模板
List<String> templateIds = MiscUtils.getAsStringList(input.get(TEMPLATE));
List<Object> templateList = new ArrayList<>();
for (String templateId : templateIds) {
// 如果模板id被用了参数则应先应用参数后再查询模板
Object actualTemplate = templateId.contains(LEFT_BRACKET) && templateId.contains(RIGHT_BRACKET) ? applyArgument(templateId, parentArguments) : templateId;
if (actualTemplate == null) continue; // 忽略被null掉的模板
Object template = Optional.ofNullable(templates.get(Key.of(actualTemplate.toString())))
.orElseThrow(() -> new IllegalArgumentException("Template not found: " + actualTemplate));
templateList.add(template);
}
// 将本节点下的参数与父参数合并
Map<String, TemplateArgument> arguments = mergeArguments(
castToMap(input.getOrDefault(ARGUMENTS, Collections.emptyMap()), false),
parentArguments
);
// 对overrides参数应用 本节点 + 父节点 参数
Map<String, Object> overrides = new LinkedHashMap<>();
processMap(MiscUtils.castToMap(input.getOrDefault(OVERRIDES, Map.of()), false), arguments, (obj) -> {
// 如果overrides的下一级就是一个模板则模板必须为map类型
if (obj instanceof Map<?,?> mapResult) {
overrides.putAll(MiscUtils.castToMap(mapResult, false));
} else {
throw new IllegalArgumentException("Invalid template used. Input: " + GsonHelper.get().toJson(input) + ". Template: " + GsonHelper.get().toJson(obj));
}
});
// 会不会有一种可能有笨比用户不会使用overrides把模板和普通配置混合在了一起再次遍历input后处理
for (Map.Entry<String, Object> inputEntry : input.entrySet()) {
String inputKey = inputEntry.getKey();
if (NON_TEMPLATE_KEY.contains(inputKey)) continue;
// 处理那些overrides
processUnknownTypeMember(inputEntry.getValue(), arguments, (processed) -> overrides.put(inputKey, processed));
}
// 返回处理结果
return new TemplateProcessingResult(
templateList,
overrides,
arguments
);
}
// 合并参数
private Map<String, TemplateArgument> mergeArguments(@NotNull Map<String, Object> rawChildArguments,
@NotNull Map<String, TemplateArgument> parentArguments) {
Map<String, TemplateArgument> result = new HashMap<>();
// 我们遍历一下当前节点下的所有参数这些参数可能含有内嵌参数。所以需要对参数map先处理一次后再合并
// arguments:
// argument_1: "{parent_argument}"
for (Map.Entry<String, Object> argumentEntry : rawChildArguments.entrySet()) {
// 获取最终的string形式参数
String placeholder = LEFT_BRACKET + argumentEntry.getKey() + RIGHT_BRACKET;
Object rawArgument = argumentEntry.getValue();
if (rawArgument instanceof Map<?,?> mapArgument) {
// 此参数是一个map那么对map应用模板然后再根据map是否含有type等参数判别其是否为带名特殊参数
Map<String, Object> nestedResult = new LinkedHashMap<>();
processMap(MiscUtils.castToMap(mapArgument, false), parentArguments, (obj) -> {
// 如果有人往arguments下塞了一个模板则模板类型应为map
if (obj instanceof Map<?,?> mapResult) {
nestedResult.putAll(MiscUtils.castToMap(mapResult, false));
} else {
throw new IllegalArgumentException("Invalid template used. Input: " + GsonHelper.get().toJson(mapArgument) + ". Template: " + GsonHelper.get().toJson(obj));
}
});
result.put(placeholder, TemplateArguments.fromMap(nestedResult));
} else if (rawArgument instanceof List<?> listArgument) {
// 此参数是一个list那么只需要应用模板即可
List<Object> nestedResult = new ArrayList<>();
for (Object item : listArgument) {
processUnknownTypeMember(item, parentArguments, nestedResult::add);
}
result.put(placeholder, new ListTemplateArgument(nestedResult));
} else if (rawArgument == null) {
// 使用 null 覆写其父参数内容
result.put(placeholder, NullTemplateArgument.INSTANCE);
} else {
// 将参数字符串化后,应用参数再放入
Object applied = applyArgument(rawArgument.toString(), parentArguments);
result.put(placeholder, new ObjectTemplateArgument(applied));
}
}
return result;
}
// 将某个输入变成最终的结果可以是string->string也可以是string->map/list
private Object applyArgument(String input, Map<String, TemplateArgument> arguments) {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
Matcher matcher = PATTERN.matcher(input); Matcher matcher = PATTERN.matcher(input);
boolean first = true; boolean first = true;
@@ -167,77 +253,9 @@ public class TemplateManagerImpl implements TemplateManager {
return result.toString(); return result.toString();
} }
private void processValue(Object value,
Consumer<Object> resultConsumer,
Map<String, Supplier<Object>> arguments) {
if (value instanceof Map<?, ?> mapValue) {
Map<String, Object> nestedResult = new LinkedHashMap<>();
applyTemplatesRecursive(EMPTY, castToMap(mapValue, false), nestedResult, arguments);
resultConsumer.accept(nestedResult);
} else if (value instanceof List<?> listValue) {
List<Object> nestedList = new ArrayList<>();
processList(castToList(listValue, false), nestedList, arguments);
resultConsumer.accept(nestedList);
} else if (value instanceof String strValue) {
resultConsumer.accept(applyArgument(strValue, arguments));
} else {
resultConsumer.accept(value);
}
}
private void processList(List<Object> inputList, List<Object> resultList, Map<String, Supplier<Object>> arguments) {
for (Object item : inputList) {
processValue(item, r -> {
if (r != null) {
resultList.add(r);
}
}, arguments);
}
}
private void handleMapTemplate(String currentPath,
Map<String, Object> template,
Object overrides,
Map<String, Supplier<Object>> arguments,
Map<String, Object> input,
Map<String, Object> result) {
Map<String, Object> merged = new LinkedHashMap<>(template);
if (overrides != null) {
merged.putAll(castToMap(overrides, false));
}
for (Map.Entry<String, Object> entry : input.entrySet()) {
if (!blacklistedKeys.contains(entry.getKey())) {
merged.put(entry.getKey(), entry.getValue());
}
}
applyTemplatesRecursive(currentPath, merged, result, arguments);
}
private void handleListTemplate(String currentPath,
List<Object> template,
Object overrides,
Map<String, Supplier<Object>> arguments,
Map<String, Object> result) {
List<Object> merged = (overrides instanceof List<?> overrideList && !overrideList.isEmpty())
? castToList(overrideList, false)
: template;
List<Object> processedList = new ArrayList<>();
processList(merged, processedList, arguments);
result.put(currentPath, processedList);
}
private record TemplateProcessingResult( private record TemplateProcessingResult(
List<Object> templates, List<Object> templates,
Object overrides, Map<String, Object> overrides,
Map<String, Supplier<Object>> arguments Map<String, TemplateArgument> arguments
) {} ) {}
private static Map<String, Supplier<Object>> mergeArguments(
Map<String, Supplier<Object>> parent,
Map<String, Supplier<Object>> child
) {
Map<String, Supplier<Object>> merged = new HashMap<>(parent);
merged.putAll(child);
return merged;
}
} }