diff --git a/src/main/java/com/gregtechceu/gtceu/api/registry/GTRegistry.java b/src/main/java/com/gregtechceu/gtceu/api/registry/GTRegistry.java index 2f1c40bfbbc..2bdf1ea25b9 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/registry/GTRegistry.java +++ b/src/main/java/com/gregtechceu/gtceu/api/registry/GTRegistry.java @@ -25,6 +25,7 @@ public abstract class GTRegistry implements Iterable { protected final Map keyToValue; protected final Map valueToKey; + protected final Map alias; @Getter protected final ResourceLocation registryName; @Getter @@ -33,13 +34,14 @@ public abstract class GTRegistry implements Iterable { public GTRegistry(ResourceLocation registryName) { this.keyToValue = new HashMap<>(); this.valueToKey = new HashMap<>(); + this.alias = new HashMap<>(); this.registryName = registryName; REGISTERED.put(registryName, this); } public boolean containKey(K key) { - return keyToValue.containsKey(key); + return keyToValue.containsKey(key) || alias.containsKey(key); } public boolean containValue(V value) { @@ -87,21 +89,46 @@ public T register(K key, T value) { return registerOrOverride(key, value); } - public void remap(K oldKey, K newKey) { + /** + * Creates an alias between two keys. Used for migration. + * + * @param alias The migrated-out key used as the alias + * @param key The proper key in the current registry + */ + public void alias(K alias, K key) { if (frozen) { throw new IllegalStateException("[register] registry %s has been frozen".formatted(registryName)); } - if (keyToValue.containsKey(oldKey)) { - GTCEu.LOGGER.warn("[remap] cannot remap existing key {} in registry {}", oldKey, registryName); + if (keyToValue.containsKey(alias)) { + GTCEu.LOGGER.warn("[alias] cannot create alias using existing key {} in registry {}", alias, registryName); return; } - if (!keyToValue.containsKey(newKey)) { - GTCEu.LOGGER.warn("[remap] couldn't find value for key {} in registry {}", newKey, registryName); + if (!keyToValue.containsKey(key)) { + GTCEu.LOGGER.warn("[alias] couldn't find existing key {} in registry {}", key, registryName); return; } - V newValue = keyToValue.get(newKey); - keyToValue.put(oldKey, newValue); + this.alias.put(alias, key); + } + + /** + * Remaps an existing value to a new key + */ + public T remap(K newKey, T value) { + if (frozen) { + throw new IllegalStateException("[register] registry %s has been frozen".formatted(registryName)); + } + + if (!valueToKey.containsKey(value)) { + GTCEu.LOGGER.warn("[remap] couldn't find existing value {} in registry {}", value, registryName); + } else { + remove(getKey(value)); + } + if (keyToValue.containsKey(newKey)) { + GTCEu.LOGGER.warn("[remap] key {} already exists in registry {}", newKey, registryName); + remove(newKey); + } + return registerOrOverride(newKey, value); } @Nullable @@ -145,21 +172,28 @@ public T registerOrOverride(K key, T value) { return Collections.unmodifiableMap(keyToValue); } + public @UnmodifiableView Map aliases() { + return Collections.unmodifiableMap(alias); + } + public void clear() { if (frozen) { throw new IllegalArgumentException("Registry is frozen!"); } keyToValue.clear(); valueToKey.clear(); + alias.clear(); } @Nullable public V get(K key) { - return keyToValue.get(key); + return (keyToValue.containsKey(key) ? keyToValue.get(key) : keyToValue.get(alias.get(key))); } public V getOrDefault(K key, V defaultValue) { - return keyToValue.getOrDefault(key, defaultValue); + return (keyToValue.containsKey(key) ? + keyToValue.get(key) : + keyToValue.getOrDefault(alias.get(key), defaultValue)); } public K getKey(V value) { @@ -170,6 +204,10 @@ public K getOrDefaultKey(V value, K defaultKey) { return valueToKey.getOrDefault(value, defaultKey); } + public K getAliasedKey(K aliasKey) { + return alias.get(aliasKey); + } + public abstract void writeBuf(V value, FriendlyByteBuf buf); @Nullable @@ -180,15 +218,71 @@ public K getOrDefaultKey(V value, K defaultKey) { @Nullable public abstract V loadFromNBT(Tag tag); + /** + * Removes a key-value pair from the registry. + * If the key to be removed was an alias, also removes the original key. + * To only remove an alias, use + * + * @return if the registry contained the key to be removed + */ public boolean remove(K name) { + if (frozen) { + throw new IllegalArgumentException("Registry is frozen!"); + } var value = keyToValue.remove(name); if (value != null) { valueToKey.remove(value); + if (alias.containsValue(name)) removeAliasesForKey(name); return true; } + if (alias.containsKey(name)) { + return remove(alias.remove(name)); + } + return false; } + /** + * Removes an alias + * + * @return if the registry contained this alias + */ + public boolean removeAlias(K name) { + if (frozen) { + throw new IllegalArgumentException("Registry is frozen!"); + } + if (!alias.containsKey(name)) + return false; + alias.remove(name); + + return true; + } + + /** + * Removes all aliases for a registry key + * + * @param name the name to find and remove aliases to + * @return if any aliases existed for that name + */ + public boolean removeAliasesForKey(K name) { + if (frozen) { + throw new IllegalArgumentException("Registry is frozen!"); + } + if (!alias.containsValue(name)) + return false; + + var aliasesOfName = new ArrayList(); + for (K aliasOfName : alias.keySet()) { + if (alias.get(aliasOfName).equals(name)) + aliasesOfName.add(aliasOfName); + } + for (K aliasOfName : aliasesOfName) { + alias.remove(aliasOfName); + } + + return true; + } + public abstract Codec codec(); // ************************ Built-in Registry ************************// diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeConditions.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeConditions.java index cb655156172..b2fe3a0d3a9 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeConditions.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipeConditions.java @@ -50,7 +50,7 @@ public static void init() { HERACLES_QUEST = register("heracles_quest", HeraclesQuestCondition::new, HeraclesQuestCondition.CODEC); } // fix the rock breaker condition's ID - GTRegistries.RECIPE_CONDITIONS.remap("rock_breaker", "adjacent_fluid"); + GTRegistries.RECIPE_CONDITIONS.alias("rock_breaker", "adjacent_fluid"); // noinspection unchecked ModLoader.get().postEvent(new GTCEuAPI.RegisterEvent<>(GTRegistries.RECIPE_CONDITIONS,