diff --git a/xplat/src/main/java/lgbt/greenhouse/config/api/v3/dfu/fix/GreenhouseConfigRelocateFieldsFix.java b/xplat/src/main/java/lgbt/greenhouse/config/api/v3/dfu/fix/GreenhouseConfigRelocateFieldsFix.java index f29e064..8b4befa 100644 --- a/xplat/src/main/java/lgbt/greenhouse/config/api/v3/dfu/fix/GreenhouseConfigRelocateFieldsFix.java +++ b/xplat/src/main/java/lgbt/greenhouse/config/api/v3/dfu/fix/GreenhouseConfigRelocateFieldsFix.java @@ -11,7 +11,11 @@ import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; -// TODO: Javadocs. +import static lgbt.greenhouse.config.impl.dfu.DataFixDynamicImplHelper.*; + +/** + * A data fix template for relocating/renaming fields inside a config. + */ public class GreenhouseConfigRelocateFieldsFix extends DataFix { private final Map oldToNewKeys; @@ -21,10 +25,39 @@ public class GreenhouseConfigRelocateFieldsFix extends DataFix { } + /** + * Creates a data fix that will relocate the specified value. + *
+	 * {@code
+	 * // An example for renaming an inherited value.
+	 * schema -> GreenhouseConfigRelocateFieldsFix.create(schema, "foo", "bar")
+	 *
+	 * // An example for relocating and renaming a map value to another map.
+	 * schema -> GreenhouseConfigRelocateFieldsFix.create(schema, "foo.bar", "chum.bucket")
+	 * }
+	 * 
+ * + * @param outputSchema The output schema, should be the value within the function in which you created this fix from. + * @param oldKey The key to relocate. + * @param newKey The new key to relocate the original key to. + * @return The configured data fix. + * @see Dynamic + */ public static GreenhouseConfigRelocateFieldsFix create(Schema outputSchema, String oldKey, String newKey) { return new GreenhouseConfigRelocateFieldsFix(outputSchema, Map.of(oldKey, newKey)); } + /** + * Creates a data fix that will relocate the specified values. + *

+ * + * + * @param outputSchema The output schema, should be the value within the function in which you created this fix from. + * @param fixData Fix data to be used within this fix. + * @param fixDatas Additional fix data to be used within this fix. + * @return The configured data fix. + * @see Dynamic + */ public static GreenhouseConfigRelocateFieldsFix create(Schema outputSchema, FixData fixData, FixData... fixDatas) { return new GreenhouseConfigRelocateFieldsFix( outputSchema, @@ -38,7 +71,14 @@ public class GreenhouseConfigRelocateFieldsFix extends DataFix { ); } - public static FixData function(String oldKey, String newKey) { + /** + * Creates fix data. Used in place of a map to make sure the result map is ordered correctly. + * @param oldKey A key to relocate. + * @param newKey A new key to relocate the original key to. + * @return A new fix data. + * @see GreenhouseConfigRelocateFieldsFix#create(Schema, FixData, FixData...) + */ + public static FixData data(String oldKey, String newKey) { return new FixData(oldKey, newKey); } @@ -54,21 +94,26 @@ public class GreenhouseConfigRelocateFieldsFix extends DataFix { Dynamic returnValue = dynamic; for (Map.Entry entry : oldToNewKeys.entrySet()) { String oldKey = entry.getKey(); - Dynamic oldValue = getOldValue(oldKey, returnValue, erroringKeys); + Dynamic oldValue = getDynamicValueRecursive(oldKey, returnValue, erroringKeys); if (oldValue == null) continue; String newKey = entry.getValue(); - Dynamic withNewValue = setNewValue(newKey, oldValue, returnValue); - returnValue = removeOldValue(oldKey, withNewValue); + String[] splitKey = splitKey(newKey); + + Deque> deque = setupDynamicDeque(splitKey, returnValue); + Dynamic withNewValue = setDynamicValueRecursive(splitKey, deque, returnValue, oldValue); + returnValue = removeDynamicValue(oldKey, withNewValue); } return returnValue; }); } @Nullable - private Dynamic getOldValue(String oldKey, Dynamic dynamic, List erroringKeys) { + private Dynamic getDynamicValueRecursive(String oldKey, + Dynamic dynamic, + List erroringKeys) { String[] splitOld = oldKey.split("(? oldValue = dynamic; for (int i = 0; i < splitOld.length; ++i) { @@ -83,74 +128,6 @@ public class GreenhouseConfigRelocateFieldsFix extends DataFix { return oldValue; } - private Dynamic setNewValue(String newKey, - Dynamic oldValue, - Dynamic dynamic) { - String[] split = newKey.split("(?> deque = new ArrayDeque<>(); - for (int i = 0; i < split.length - 1; ++i) { - String key = split[i]; - deque.add(dynamic.get(key).orElseEmptyMap()); - } - - Dynamic current = oldValue; - for (int i = split.length - 1; i > 0; --i) { - String key = split[i]; - var operated = deque.removeLast(); - current = operated.set(key, current); - } - return dynamic.set(split[0], current); - } - - private Dynamic removeOldValue(String oldKey, - Dynamic dynamic) { - String[] split = oldKey.split("(?> deque = new ArrayDeque<>(); - deque.addLast(dynamic); - - Dynamic current = dynamic; - for (int i = 0; i < split.length; ++i) { - String key = split[i]; - - if (i == split.length - 1) { - Dynamic last = deque.removeLast(); - Dynamic removed = last.remove(key); - deque.addLast(removed); - current = removed; - break; - } - - var optional = current.get(key).result(); - if (optional.isEmpty()) - break; - - Dynamic traced = optional.get(); - current = traced; - deque.add(traced); - } - - for (int i = deque.size() - 1; i >= 0; --i) { - Dynamic last = deque.removeLast(); - String key = split[i]; - - Dynamic traced; - if (last.get(key).orElseEmptyMap().getMapValues().getOrThrow().isEmpty()) { - traced = last.remove(key); - } else { - traced = last; - } - - if (!deque.isEmpty()) { - Dynamic toReplace = deque.removeLast(); - Dynamic replaceWith = toReplace.set(split[i - 1], traced); - deque.addLast(replaceWith); - } - current = traced; - } - return current; - } - public record FixData(String oldKey, String newKey) { } } diff --git a/xplat/src/main/java/lgbt/greenhouse/config/api/v3/dfu/fix/GreenhouseConfigRemoveFieldsFix.java b/xplat/src/main/java/lgbt/greenhouse/config/api/v3/dfu/fix/GreenhouseConfigRemoveFieldsFix.java index 14545f8..5270913 100644 --- a/xplat/src/main/java/lgbt/greenhouse/config/api/v3/dfu/fix/GreenhouseConfigRemoveFieldsFix.java +++ b/xplat/src/main/java/lgbt/greenhouse/config/api/v3/dfu/fix/GreenhouseConfigRemoveFieldsFix.java @@ -6,11 +6,11 @@ import com.mojang.datafixers.schemas.Schema; import com.mojang.serialization.Dynamic; import lgbt.greenhouse.config.api.v3.dfu.GreenhouseConfigDFUTypeReferences; -import java.util.ArrayDeque; import java.util.Arrays; -import java.util.Deque; import java.util.stream.Stream; +import static lgbt.greenhouse.config.impl.dfu.DataFixDynamicImplHelper.removeDynamicValue; + /** * A data fix template for removing fields inside a config. */ @@ -56,58 +56,9 @@ public class GreenhouseConfigRemoveFieldsFix extends DataFix { dynamic -> { Dynamic returnValue = dynamic; for (String key : toRemove) { - returnValue = removeValue(key, returnValue); + returnValue = removeDynamicValue(key, returnValue); } return returnValue; }); } - - private Dynamic removeValue(String oldKey, - Dynamic dynamic) { - String[] split = oldKey.split("(?> deque = new ArrayDeque<>(); - deque.addLast(dynamic); - - Dynamic current = dynamic; - for (int i = 0; i < split.length; ++i) { - String key = split[i]; - - if (i == split.length - 1) { - Dynamic last = deque.removeLast(); - Dynamic removed = last.remove(key); - deque.addLast(removed); - current = removed; - break; - } - - var optional = current.get(key).result(); - if (optional.isEmpty()) - break; - - Dynamic traced = optional.get(); - current = traced; - deque.add(traced); - } - - for (int i = deque.size() - 1; i >= 0; --i) { - Dynamic last = deque.removeLast(); - String key = split[i]; - - Dynamic traced; - if (last.get(key).orElseEmptyMap().getMapValues().getOrThrow().isEmpty()) { - traced = last.remove(key); - } else { - traced = last; - } - - if (!deque.isEmpty()) { - Dynamic toReplace = deque.removeLast(); - Dynamic replaceWith = toReplace.set(split[i - 1], traced); - deque.addLast(replaceWith); - } - current = traced; - } - return current; - } } diff --git a/xplat/src/main/java/lgbt/greenhouse/config/api/v3/dfu/fix/GreenhouseConfigSetFieldsFix.java b/xplat/src/main/java/lgbt/greenhouse/config/api/v3/dfu/fix/GreenhouseConfigSetFieldsFix.java index 01eef5d..ca3436d 100644 --- a/xplat/src/main/java/lgbt/greenhouse/config/api/v3/dfu/fix/GreenhouseConfigSetFieldsFix.java +++ b/xplat/src/main/java/lgbt/greenhouse/config/api/v3/dfu/fix/GreenhouseConfigSetFieldsFix.java @@ -13,6 +13,8 @@ import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; +import static lgbt.greenhouse.config.impl.dfu.DataFixDynamicImplHelper.*; + /** * A data fix template for adding or updating fields inside a config. */ @@ -58,6 +60,7 @@ public class GreenhouseConfigSetFieldsFix extends DataFix { * @param function The function to use to fix the value at the key. * @return The configured data fix. * @see Dynamic + * @see DataFixDynamicHelper */ public static GreenhouseConfigSetFieldsFix create(Schema outputSchema, String key, FixFunction function) { @@ -72,6 +75,7 @@ public class GreenhouseConfigSetFieldsFix extends DataFix { * @param fixDatas Additional fix data to be used within this fix. * @return The configured data fix. * @see Dynamic + * @see DataFixDynamicHelper */ public static GreenhouseConfigSetFieldsFix create(Schema outputSchema, FixData fixData, FixData... fixDatas) { return new GreenhouseConfigSetFieldsFix(outputSchema, @@ -115,7 +119,7 @@ public class GreenhouseConfigSetFieldsFix extends DataFix { String key = entry.getKey(); FixFunction valueFunction = entry.getValue(); try { - returnValue = setValue(key, valueFunction, returnValue); + returnValue = fixDynamicValue(key, valueFunction, returnValue); } catch (IllegalStateException e) { GreenhouseConfigHolder currentlyLoading = GreenhouseConfigImpl.getCurrentlyLoading(); GreenhouseConfigConstants.CONFIG_DATA_FIX_LOG.warn( @@ -132,23 +136,13 @@ public class GreenhouseConfigSetFieldsFix extends DataFix { }); } - private Dynamic setValue(String fullKey, - FixFunction valueFunction, - Dynamic dynamic) { - String[] split = fullKey.split("(?> deque = new ArrayDeque<>(); - for (int i = 0; i < split.length - 1; ++i) { - String key = split[i]; - deque.add(dynamic.get(key).orElseEmptyMap()); - } - - Dynamic current = valueFunction.apply(dynamic, dynamic.get(split[0]).orElseEmptyMap()); - for (int i = split.length - 1; i > 0; --i) { - String key = split[i]; - var operated = deque.removeLast(); - current = operated.set(key, current); - } - return dynamic.set(split[0], current); + private Dynamic fixDynamicValue(String newKey, + FixFunction valueFunction, + Dynamic existing) { + String[] splitKey = splitKey(newKey); + Deque> deque = setupDynamicDeque(splitKey, existing); + Dynamic value = valueFunction.apply(existing, existing.get(splitKey[0]).orElseEmptyMap()); + return setDynamicValueRecursive(splitKey, deque, existing, value); } } diff --git a/xplat/src/main/java/lgbt/greenhouse/config/impl/dfu/DataFixDynamicImplHelper.java b/xplat/src/main/java/lgbt/greenhouse/config/impl/dfu/DataFixDynamicImplHelper.java new file mode 100644 index 0000000..5f75795 --- /dev/null +++ b/xplat/src/main/java/lgbt/greenhouse/config/impl/dfu/DataFixDynamicImplHelper.java @@ -0,0 +1,84 @@ +package lgbt.greenhouse.config.impl.dfu; + +import com.mojang.serialization.Dynamic; + +import java.util.ArrayDeque; +import java.util.Deque; + +public class DataFixDynamicImplHelper { + public static Dynamic setDynamicValueRecursive(String[] splitKey, + Deque> deque, + Dynamic existing, + Dynamic value) { + Dynamic current = value; + for (int i = splitKey.length - 1; i > 0; --i) { + String key = splitKey[i]; + var operated = deque.removeLast(); + current = operated.set(key, current); + } + return existing.set(splitKey[0], current); + } + + public static Dynamic removeDynamicValue(String oldKey, + Dynamic dynamic) { + String[] split = oldKey.split("(?> deque = new ArrayDeque<>(); + deque.addLast(dynamic); + + Dynamic current = dynamic; + for (int i = 0; i < split.length; ++i) { + String key = split[i]; + + if (i == split.length - 1) { + Dynamic last = deque.removeLast(); + Dynamic removed = last.remove(key); + deque.addLast(removed); + current = removed; + break; + } + + var optional = current.get(key).result(); + if (optional.isEmpty()) + break; + + Dynamic traced = optional.get(); + current = traced; + deque.add(traced); + } + + for (int i = deque.size() - 1; i >= 0; --i) { + Dynamic last = deque.removeLast(); + String key = split[i]; + + Dynamic traced; + if (last.get(key).orElseEmptyMap().getMapValues().getOrThrow().isEmpty()) { + traced = last.remove(key); + } else { + traced = last; + } + + if (!deque.isEmpty()) { + Dynamic toReplace = deque.removeLast(); + Dynamic replaceWith = toReplace.set(split[i - 1], traced); + deque.addLast(replaceWith); + } + current = traced; + } + return current; + } + + public static Deque> setupDynamicDeque(String[] splitKey, + Dynamic dynamic) { + Deque> deque = new ArrayDeque<>(); + for (int i = 0; i < splitKey.length - 1; ++i) { + String key = splitKey[i]; + deque.add(dynamic.get(key).orElseEmptyMap()); + } + return deque; + } + + public static String[] splitKey(String key) { + return key.split("(? GreenhouseConfigRelocateFieldsFix.create( schema, - GreenhouseConfigRelocateFieldsFix.function("blocks", "red_blocks"), - GreenhouseConfigRelocateFieldsFix.function("biomes", "green_biomes"), - GreenhouseConfigRelocateFieldsFix.function("enchantment", "enchantment_opinion.enchantment") + GreenhouseConfigRelocateFieldsFix.data("blocks", "red_blocks"), + GreenhouseConfigRelocateFieldsFix.data("biomes", "green_biomes"), + GreenhouseConfigRelocateFieldsFix.data("enchantment", "enchantment_opinion.enchantment") ) ), DataFixerBuilderFunctions.create( @@ -140,7 +140,7 @@ public record CommonConfig(int silly, GreenhouseConfigSetFieldsFix.function( // Green Biomes is kept from the previous schema. "green_biomes", - (root, field) -> addToList( + (root, field) -> addOrTurnIntoList( field, (dynamic, key) -> dynamic.createString(key.identifier().toString()), Biomes.BAMBOO_JUNGLE,