mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-21 07:46:55 +00:00
Preserved merged tag order
- Merged datapack tags keep first-seen value order with duplicates removed instead of re-sorting, so world preset tag order is preserved - NeoForge remove lists are kept as the deduplicated union of both tags instead of being dropped
This commit is contained in:
1 parent
038833e614
commit
56ba2e51b7
2 files changed
+80
-16
No files matched your search
+25
-16
@@ -25,12 +25,13 @@ import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
final class ModdedDatapackTagMerge {
|
||||
private static final String REPLACE = "replace";
|
||||
private static final String VALUES = "values";
|
||||
private static final String REMOVE = "remove";
|
||||
|
||||
private ModdedDatapackTagMerge() {
|
||||
}
|
||||
@@ -45,19 +46,27 @@ final class ModdedDatapackTagMerge {
|
||||
static void merge(Path source, Path destination) throws IOException {
|
||||
JSONObject incoming = read(source);
|
||||
JSONObject existing = read(destination);
|
||||
Map<String, Object> values = new TreeMap<>();
|
||||
collect(existing, values, destination);
|
||||
collect(incoming, values, source);
|
||||
JSONArray merged = new JSONArray();
|
||||
for (Object value : values.values()) {
|
||||
merged.put(value);
|
||||
}
|
||||
JSONObject tag = new JSONObject();
|
||||
tag.put(REPLACE, existing.optBoolean(REPLACE, false) || incoming.optBoolean(REPLACE, false));
|
||||
tag.put(VALUES, merged);
|
||||
tag.put(VALUES, union(existing, incoming, VALUES, source, destination));
|
||||
if (existing.has(REMOVE) || incoming.has(REMOVE)) {
|
||||
tag.put(REMOVE, union(existing, incoming, REMOVE, source, destination));
|
||||
}
|
||||
Files.writeString(destination, tag.toString(4), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static JSONArray union(JSONObject existing, JSONObject incoming, String field, Path source, Path destination)
|
||||
throws IOException {
|
||||
Map<String, Object> entries = new LinkedHashMap<>();
|
||||
collect(existing, field, entries, destination);
|
||||
collect(incoming, field, entries, source);
|
||||
JSONArray merged = new JSONArray();
|
||||
for (Object entry : entries.values()) {
|
||||
merged.put(entry);
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
private static JSONObject read(Path tag) throws IOException {
|
||||
try {
|
||||
return new JSONObject(Files.readString(tag, StandardCharsets.UTF_8));
|
||||
@@ -66,18 +75,18 @@ final class ModdedDatapackTagMerge {
|
||||
}
|
||||
}
|
||||
|
||||
private static void collect(JSONObject tag, Map<String, Object> values, Path origin) throws IOException {
|
||||
JSONArray entries = tag.optJSONArray(VALUES);
|
||||
if (entries == null) {
|
||||
private static void collect(JSONObject tag, String field, Map<String, Object> entries, Path origin) throws IOException {
|
||||
JSONArray values = tag.optJSONArray(field);
|
||||
if (values == null) {
|
||||
return;
|
||||
}
|
||||
for (int index = 0; index < entries.length(); index++) {
|
||||
Object entry = entries.get(index);
|
||||
for (int index = 0; index < values.length(); index++) {
|
||||
Object entry = values.get(index);
|
||||
String key = entry instanceof JSONObject object ? object.optString("id", "") : entry.toString();
|
||||
if (key.isBlank()) {
|
||||
throw new IOException("Iris cannot merge datapack tag " + origin + ": entry " + index + " has no id.");
|
||||
throw new IOException("Iris cannot merge datapack tag " + origin + ": " + field + " entry " + index + " has no id.");
|
||||
}
|
||||
values.putIfAbsent(key, entry);
|
||||
entries.putIfAbsent(key, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
+55
@@ -19,6 +19,7 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.volmlib.util.collection.KSet;
|
||||
import art.arcane.volmlib.util.json.JSONArray;
|
||||
import art.arcane.volmlib.util.json.JSONObject;
|
||||
import art.arcane.iris.pack.datapack.DataVersion;
|
||||
import art.arcane.iris.pack.datapack.v1217.DataFixerV1217;
|
||||
@@ -291,6 +292,60 @@ public class ModdedForcedDatapackTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tagMergeKeepsFirstSeenOrderAndUnionsRemoveLists() throws IOException {
|
||||
Path root = Files.createTempDirectory("iris-forced-pack-tag-order");
|
||||
try {
|
||||
Path tag = Path.of("data/minecraft/tags/worldgen/world_preset/normal.json");
|
||||
Path source = root.resolve("source");
|
||||
Path destination = root.resolve("destination");
|
||||
Files.createDirectories(source.resolve(tag).getParent());
|
||||
Files.createDirectories(destination.resolve(tag).getParent());
|
||||
Files.writeString(destination.resolve(tag),
|
||||
"{\"replace\":false,\"values\":[\"irisworldgen:z\",\"irisworldgen:a\"],\"remove\":[\"minecraft:large_biomes\"]}",
|
||||
StandardCharsets.UTF_8);
|
||||
Files.writeString(source.resolve(tag),
|
||||
"{\"replace\":false,\"values\":[\"irisworldgen:m\",\"irisworldgen:a\"],\"remove\":[\"minecraft:amplified\",\"minecraft:large_biomes\"]}",
|
||||
StandardCharsets.UTF_8);
|
||||
|
||||
ModdedForcedDatapack.mergeDirectory(source, destination);
|
||||
|
||||
JSONObject merged = new JSONObject(Files.readString(destination.resolve(tag), StandardCharsets.UTF_8));
|
||||
assertEquals(List.of("irisworldgen:z", "irisworldgen:a", "irisworldgen:m"), strings(merged.getJSONArray("values")));
|
||||
assertEquals(List.of("minecraft:large_biomes", "minecraft:amplified"), strings(merged.getJSONArray("remove")));
|
||||
} finally {
|
||||
deleteTree(root);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tagMergeWithoutRemoveListsWritesNone() throws IOException {
|
||||
Path root = Files.createTempDirectory("iris-forced-pack-tag-no-remove");
|
||||
try {
|
||||
Path tag = Path.of("data/minecraft/tags/worldgen/biome/is_overworld.json");
|
||||
for (String side : List.of("source", "destination")) {
|
||||
Files.createDirectories(root.resolve(side).resolve(tag).getParent());
|
||||
Files.writeString(root.resolve(side).resolve(tag),
|
||||
"{\"replace\":false,\"values\":[\"iris:biomes/" + side + "\"]}", StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
ModdedForcedDatapack.mergeDirectory(root.resolve("source"), root.resolve("destination"));
|
||||
|
||||
JSONObject merged = new JSONObject(Files.readString(root.resolve("destination").resolve(tag), StandardCharsets.UTF_8));
|
||||
assertFalse(merged.has("remove"));
|
||||
} finally {
|
||||
deleteTree(root);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> strings(JSONArray array) {
|
||||
List<String> values = new ArrayList<>();
|
||||
for (int index = 0; index < array.length(); index++) {
|
||||
values.add(array.get(index).toString());
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tagMergeKeepsStrictConflictsForNonTagFilesInTheSameMerge() throws IOException {
|
||||
Path root = Files.createTempDirectory("iris-forced-pack-tag-strict");
|
||||
|
||||
Reference in new issue
Block a user