fix: implement OverlayMap to store FallbackI18n without evaluating lower map early
This commit is contained in:
parent
4943127ecc
commit
2c66bc4146
|
@ -1,7 +1,7 @@
|
|||
package io.gitlab.jfronny.respackopts.mixin;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.gitlab.jfronny.respackopts.util.FallbackI18n;
|
||||
import io.gitlab.jfronny.respackopts.util.OverlayMap;
|
||||
import net.minecraft.client.resource.language.LanguageManager;
|
||||
import net.minecraft.client.resource.language.TranslationStorage;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
|
@ -18,8 +18,8 @@ public class LanguageManagerMixin {
|
|||
@Inject(method = "reload(Lnet/minecraft/resource/ResourceManager;)V", at = @At("TAIL"), locals = LocalCapture.CAPTURE_FAILEXCEPTION)
|
||||
private void rpo$appendTranslations(ResourceManager manager, CallbackInfo ci, List<String> list, boolean bl, TranslationStorage translationStorage) {
|
||||
TranslationStorageAccessor storage = (TranslationStorageAccessor) translationStorage;
|
||||
Map<String, String> map = new HashMap<>(storage.getTranslations());
|
||||
Map<String, String> map = new HashMap<>();
|
||||
FallbackI18n.insertInto(map);
|
||||
storage.setTranslations(ImmutableMap.copyOf(map));
|
||||
storage.setTranslations(new OverlayMap<>(storage.getTranslations(), map));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
package io.gitlab.jfronny.respackopts.util;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class OverlayMap<K, V> extends AbstractMap<K, V> {
|
||||
private final Map<K, V> overlay;
|
||||
private final Map<K, V> lower;
|
||||
private final Set<K> masked = new HashSet<>();
|
||||
|
||||
public OverlayMap(Map<K, V> overlay, Map<K, V> lower) {
|
||||
this.overlay = overlay;
|
||||
this.lower = lower;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return overlay.size() + (int) lower.keySet().stream()
|
||||
.filter(s -> !overlay.containsKey(s) && !masked.contains(s))
|
||||
.count();
|
||||
}
|
||||
|
||||
private Stream<K> streamKeys() {
|
||||
return Stream.concat(
|
||||
overlay.keySet().stream(),
|
||||
lower.keySet().stream()
|
||||
.filter(s -> !overlay.containsKey(s) && !masked.contains(s))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return overlay.isEmpty() && (masked.size() >= lower.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return overlay.containsKey(key) || (lower.containsKey(key) && !masked.contains(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return overlay.containsValue(value) || lower.entrySet()
|
||||
.stream()
|
||||
.filter(s -> Objects.equals(s.getValue(), value))
|
||||
.anyMatch(s -> !masked.contains(s.getKey()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
V result = overlay.get(key);
|
||||
if (result == null && !masked.contains(key)) result = lower.get(key);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
V result = overlay.put(key, value);
|
||||
V low = lower.get(key);
|
||||
if (low != null && masked.add(key) && result == null) {
|
||||
result = low;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
V result = overlay.remove(key);
|
||||
V low = lower.get(key);
|
||||
if (low != null && masked.add((K) key) && result == null) {
|
||||
result = low;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
overlay.clear();
|
||||
masked.addAll(lower.keySet());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return entrySet;
|
||||
}
|
||||
|
||||
private final Set<Entry<K, V>> entrySet = new AbstractSet<>() {
|
||||
@Override
|
||||
public int size() {
|
||||
return OverlayMap.this.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return OverlayMap.this.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return o instanceof Map.Entry<?,?> e && Objects.equals(OverlayMap.this.get(e.getKey()), e.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(Entry<K, V> kvEntry) {
|
||||
return OverlayMap.this.put(kvEntry.getKey(), kvEntry.getValue()) == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return o instanceof Map.Entry<?,?> e && OverlayMap.this.remove(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
OverlayMap.this.clear();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<Entry<K, V>> iterator() {
|
||||
return new Iterator<>() {
|
||||
private final Iterator<K> keys = OverlayMap.this.streamKeys().iterator();
|
||||
private K previous = null;
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return keys.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<K, V> next() {
|
||||
previous = keys.next();
|
||||
return new Entry<>() {
|
||||
private final K currentK = previous;
|
||||
private V currentV = OverlayMap.this.get(currentK);
|
||||
|
||||
@Override
|
||||
public K getKey() {
|
||||
return currentK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
return currentV;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V setValue(V value) {
|
||||
V result = OverlayMap.this.put(currentK, value);
|
||||
currentV = value;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (previous == null) throw new IllegalStateException();
|
||||
OverlayMap.this.remove(previous);
|
||||
previous = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue