Remove unfinished/obsolete registry & block optimizations
These patches were unfinished, are known to be buggy, and won't make sense in modern versions of Minecraft, where many of the underlying issues have been addressed in other ways
This commit is contained in:
parent
12d69bec45
commit
ad1e12a3bb
|
|
@ -1,24 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.compact_mojang_registries;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import org.embeddedt.modernfix.annotation.IgnoreOutsideDev;
|
||||
import org.embeddedt.modernfix.registry.DirectStorageRegistryObject;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
@Mixin({ Block.class, Item.class })
|
||||
@IgnoreOutsideDev
|
||||
public class DirectObjectMixin implements DirectStorageRegistryObject {
|
||||
private ResourceLocation mfix$resourceKey;
|
||||
|
||||
@Override
|
||||
public ResourceLocation mfix$getResourceKey() {
|
||||
return mfix$resourceKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mfix$setResourceKey(ResourceLocation key) {
|
||||
mfix$resourceKey = key;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,11 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.compact_mojang_registries;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import net.minecraft.core.MappedRegistry;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.embeddedt.modernfix.annotation.IgnoreOutsideDev;
|
||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
||||
import org.embeddedt.modernfix.registry.DirectStorageRegistryObject;
|
||||
import org.embeddedt.modernfix.registry.LifecycleMap;
|
||||
import org.embeddedt.modernfix.registry.RegistryStorage;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
|
|
@ -29,12 +23,6 @@ public abstract class MappedRegistryMixin<T> extends Registry<T> {
|
|||
@Final
|
||||
@Mutable
|
||||
private Map<T, Lifecycle> lifecycles;
|
||||
@Shadow @Final @Mutable
|
||||
private BiMap<ResourceLocation, T> storage;
|
||||
@Shadow @Final @Mutable
|
||||
private BiMap<ResourceKey<T>, T> keyStorage;
|
||||
|
||||
private static final ImmutableSet<ResourceLocation> MFIX$NEW_STORAGE_KEYS = ImmutableSet.of(new ResourceLocation("block"), new ResourceLocation("item"));
|
||||
|
||||
protected MappedRegistryMixin(ResourceKey<? extends Registry<T>> resourceKey, Lifecycle lifecycle) {
|
||||
super(resourceKey, lifecycle);
|
||||
|
|
@ -43,10 +31,5 @@ public abstract class MappedRegistryMixin<T> extends Registry<T> {
|
|||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void replaceStorage(CallbackInfo ci) {
|
||||
this.lifecycles = new LifecycleMap<>();
|
||||
if(MFIX$NEW_STORAGE_KEYS.contains(this.key().location())) {
|
||||
ModernFixMixinPlugin.instance.logger.info("Using experimental registry storage for {}", this.key());
|
||||
this.storage = (BiMap<ResourceLocation, T>) RegistryStorage.createStorage();
|
||||
this.keyStorage = (BiMap<ResourceKey<T>, T>)RegistryStorage.createKeyStorage(this.key(), (BiMap<ResourceLocation, DirectStorageRegistryObject>)this.storage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_block_codecs;
|
||||
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.StateHolder;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Mixin(StateDefinition.class)
|
||||
public class StateDefinitionMixin<O, S extends StateHolder<O, S>> {
|
||||
@Shadow @Final private O owner;
|
||||
|
||||
@ModifyVariable(method = "<init>", at = @At("HEAD"), ordinal = 0, argsOnly = true)
|
||||
private static <O, S extends StateHolder<O, S>> StateDefinition.Factory<O, S> replaceMapCodec(StateDefinition.Factory<O, S> factory, Function<O, S> function, O object, StateDefinition.Factory<O, S> factory2, Map<String, Property<?>> map) {
|
||||
if(object instanceof Block)
|
||||
return (o, m, c) -> factory.create(o, m, null);
|
||||
return factory;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_block_codecs;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.Decoder;
|
||||
import com.mojang.serialization.Encoder;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.StateHolder;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Mixin(StateHolder.class)
|
||||
public class StateHolderMixin {
|
||||
private static final LoadingCache<Block, MapCodec<BlockState>> MODERNFIX_CODEC_CACHE = CacheBuilder.newBuilder()
|
||||
.maximumSize(100000)
|
||||
.build(new CacheLoader<Block, MapCodec<BlockState>>() {
|
||||
@Override
|
||||
public MapCodec<BlockState> load(Block block) throws Exception {
|
||||
Supplier<BlockState> stateSupplier = block::defaultBlockState;
|
||||
MapCodec<BlockState> mapCodec = MapCodec.of(Encoder.empty(), Decoder.unit(stateSupplier));
|
||||
for(Property<?> property : block.getStateDefinition().getProperties()) {
|
||||
mapCodec = StateDefinition.appendPropertyCodec(mapCodec, stateSupplier, property.getName(), property);
|
||||
}
|
||||
return mapCodec;
|
||||
}
|
||||
});
|
||||
|
||||
@Redirect(method = "codec", at = @At(value = "INVOKE", target = "Lcom/mojang/serialization/Codec;dispatch(Ljava/lang/String;Ljava/util/function/Function;Ljava/util/function/Function;)Lcom/mojang/serialization/Codec;", remap = false))
|
||||
private static <O, S extends StateHolder<O, S>> Codec<S> obtainCodec(Codec<O> codec, String typeKey, Function<S, O> type, Function<O, ? extends Codec<S>> codecFn, Codec<O> codecMethodArg, Function<O, S> stateSupplier) {
|
||||
return codec.dispatch(typeKey, type, block -> {
|
||||
if(block instanceof Block) {
|
||||
S state = stateSupplier.apply(block);
|
||||
if(state.getValues().isEmpty())
|
||||
return Codec.unit(state);
|
||||
MapCodec<S> mapCodec;
|
||||
try {
|
||||
mapCodec = (MapCodec<S>)MODERNFIX_CODEC_CACHE.get((Block)block);
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return mapCodec.fieldOf("Properties").codec();
|
||||
} else {
|
||||
return codecFn.apply(block);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -168,9 +168,7 @@ public class ModernFixEarlyConfig {
|
|||
.put("mixin.perf.dynamic_resources", false)
|
||||
.putConditionally(() -> !isFabric, "mixin.perf.async_jei", false)
|
||||
.put("mixin.perf.reuse_datapacks", false)
|
||||
.put("mixin.perf.dynamic_block_codecs", false)
|
||||
.put("mixin.feature.direct_stack_trace", false)
|
||||
.putConditionally(ModernFixPlatformHooks.INSTANCE::isDevEnv, "mixin.perf.rewrite_registry", false)
|
||||
.put("mixin.perf.clear_mixin_classinfo", false)
|
||||
.put("mixin.bugfix.packet_leak", false)
|
||||
.put("mixin.perf.deduplicate_location", false)
|
||||
|
|
|
|||
|
|
@ -1,184 +0,0 @@
|
|||
package org.embeddedt.modernfix.registry;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class DirectStorageBiMap<K, V> implements BiMap<K, V> {
|
||||
private final Function<V, K> keyGetter;
|
||||
private final BiConsumer<V, K> keySetter;
|
||||
private final Map<K, V> forwardMap;
|
||||
|
||||
public DirectStorageBiMap(Function<V, K> keyGetter, BiConsumer<V, K> keySetter) {
|
||||
Objects.requireNonNull(keyGetter);
|
||||
Objects.requireNonNull(keySetter);
|
||||
this.keyGetter = keyGetter;
|
||||
this.keySetter = keySetter;
|
||||
this.forwardMap = new Object2ObjectOpenHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.forwardMap.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.forwardMap.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object o) {
|
||||
return this.forwardMap.containsKey(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object o) {
|
||||
return o != null && keyGetter.apply((V)o) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object o) {
|
||||
return this.forwardMap.get(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
if(this.forwardMap.containsKey(key) || (value != null && keyGetter.apply(value) != null))
|
||||
throw new IllegalArgumentException("Already have mapping for " + key);
|
||||
return forcePut(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object o) {
|
||||
return put((K)o, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V forcePut(K key, V value) {
|
||||
V previousValue = this.forwardMap.put(key, value);
|
||||
if(previousValue != null)
|
||||
keySetter.accept(previousValue, null);
|
||||
if(value != null)
|
||||
keySetter.accept(value, key);
|
||||
return previousValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> map) {
|
||||
map.forEach(this::put);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
for(V value : this.forwardMap.values()) {
|
||||
if(value != null)
|
||||
keySetter.accept(value, null);
|
||||
}
|
||||
this.forwardMap.clear();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return this.forwardMap.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> values() {
|
||||
return new HashSet<>(this.forwardMap.values());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return this.forwardMap.entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiMap<V, K> inverse() {
|
||||
return new Reverse();
|
||||
}
|
||||
|
||||
class Reverse implements BiMap<V, K> {
|
||||
@Override
|
||||
public int size() {
|
||||
return DirectStorageBiMap.this.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return DirectStorageBiMap.this.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object o) {
|
||||
return DirectStorageBiMap.this.containsValue(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object o) {
|
||||
return DirectStorageBiMap.this.containsKey(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K get(Object o) {
|
||||
return o == null ? null : keyGetter.apply((V)o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K put(V key, K value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K remove(Object o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K forcePut(V key, K value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends V, ? extends K> map) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<V> keySet() {
|
||||
return DirectStorageBiMap.this.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> values() {
|
||||
return DirectStorageBiMap.this.keySet();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Entry<V, K>> entrySet() {
|
||||
return DirectStorageBiMap.this.entrySet().stream()
|
||||
.map(entry -> new AbstractMap.SimpleImmutableEntry<>(entry.getValue(), entry.getKey()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiMap<K, V> inverse() {
|
||||
return DirectStorageBiMap.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
package org.embeddedt.modernfix.registry;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public interface DirectStorageRegistryObject {
|
||||
ResourceLocation mfix$getResourceKey();
|
||||
void mfix$setResourceKey(ResourceLocation key);
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
package org.embeddedt.modernfix.registry;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class RegistryStorage {
|
||||
public static BiMap<ResourceLocation, DirectStorageRegistryObject> createStorage() {
|
||||
return new DirectStorageBiMap<>(DirectStorageRegistryObject::mfix$getResourceKey, DirectStorageRegistryObject::mfix$setResourceKey);
|
||||
}
|
||||
|
||||
public static <T> BiMap<ResourceKey<T>, DirectStorageRegistryObject> createKeyStorage(ResourceKey<? extends Registry<T>> registryKey, BiMap<ResourceLocation, DirectStorageRegistryObject> storage) {
|
||||
if(storage instanceof DirectStorageBiMap) {
|
||||
// silently ignore put/putAll calls on this map
|
||||
return new TransformingBiMap<ResourceLocation, DirectStorageRegistryObject, ResourceKey<T>, DirectStorageRegistryObject>(storage, loc -> ResourceKey.create(registryKey, loc), ResourceKey::location, Function.identity(), Function.identity()) {
|
||||
@Override
|
||||
public DirectStorageRegistryObject put(ResourceKey<T> key, DirectStorageRegistryObject value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends ResourceKey<T>, ? extends DirectStorageRegistryObject> map) {
|
||||
|
||||
}
|
||||
};
|
||||
} else
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,224 +0,0 @@
|
|||
package org.embeddedt.modernfix.registry;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Iterators;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class TransformingBiMap<KFrom, VFrom, KTo, VTo> implements BiMap<KTo, VTo> {
|
||||
private final BiMap<KFrom, VFrom> delegate;
|
||||
private final Function<KFrom, KTo> keyFwd;
|
||||
private final Function<KTo, KFrom> keyBack;
|
||||
private final Function<VFrom, VTo> valueFwd;
|
||||
private final Function<VTo, VFrom> valueBack;
|
||||
|
||||
public TransformingBiMap(BiMap<KFrom, VFrom> map, Function<KFrom, KTo> keyFwd, Function<KTo, KFrom> keyBack, Function<VFrom, VTo> valueFwd, Function<VTo, VFrom> valueBack) {
|
||||
this.delegate = map;
|
||||
this.keyFwd = keyFwd;
|
||||
this.keyBack = keyBack;
|
||||
this.valueFwd = valueFwd;
|
||||
this.valueBack = valueBack;
|
||||
}
|
||||
|
||||
private KFrom keyBack(KTo key) {
|
||||
return key == null ? null : this.keyBack.apply(key);
|
||||
}
|
||||
|
||||
private KTo keyFwd(KFrom key) {
|
||||
return key == null ? null : this.keyFwd.apply(key);
|
||||
}
|
||||
|
||||
private VFrom valueBack(VTo value) {
|
||||
return value == null ? null : this.valueBack.apply(value);
|
||||
}
|
||||
|
||||
private VTo valueFwd(VFrom value) {
|
||||
return value == null ? null : this.valueFwd.apply(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.delegate.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.delegate.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object o) {
|
||||
return this.delegate.containsKey(keyBack((KTo)o));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object o) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VTo get(Object o) {
|
||||
return valueFwd(this.delegate.get(keyBack((KTo)o)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public VTo put(KTo key, VTo value) {
|
||||
return valueFwd(this.delegate.put(keyBack(key), valueBack(value)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public VTo remove(Object o) {
|
||||
return valueFwd(this.delegate.remove(keyBack((KTo)o)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public VTo forcePut(KTo key, VTo value) {
|
||||
return valueFwd(this.delegate.forcePut(keyBack(key), valueBack(value)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends KTo, ? extends VTo> map) {
|
||||
map.forEach((key, value) -> {
|
||||
this.delegate.put(keyBack(key), valueBack(value));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.delegate.clear();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<KTo> keySet() {
|
||||
return new TransformingSet<>(this.delegate.keySet(), this.keyFwd, this.keyBack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<VTo> values() {
|
||||
return new TransformingSet<>(this.delegate.values(), this.valueFwd, this.valueBack);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Entry<KTo, VTo>> entrySet() {
|
||||
return new TransformingSet<>(this.delegate.entrySet(), entry -> {
|
||||
return new AbstractMap.SimpleImmutableEntry<>(keyFwd(entry.getKey()), valueFwd(entry.getValue()));
|
||||
}, entry -> {
|
||||
return new AbstractMap.SimpleImmutableEntry<>(keyBack(entry.getKey()), valueBack(entry.getValue()));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiMap<VTo, KTo> inverse() {
|
||||
return new TransformingBiMap<>(this.delegate.inverse(), this.valueFwd, this.valueBack, this.keyFwd, this.keyBack);
|
||||
}
|
||||
|
||||
static class TransformingSet<TypeFrom, TypeTo> implements Set<TypeTo> {
|
||||
private final Set<TypeFrom> delegate;
|
||||
private final Function<TypeFrom, TypeTo> forward;
|
||||
private final Function<TypeTo, TypeFrom> reverse;
|
||||
|
||||
public TransformingSet(Set<TypeFrom> set, Function<TypeFrom, TypeTo> forward, Function<TypeTo, TypeFrom> reverse) {
|
||||
this.delegate = set;
|
||||
this.forward = forward;
|
||||
this.reverse = reverse;
|
||||
}
|
||||
|
||||
private TypeTo forward(TypeFrom t) {
|
||||
return t == null ? null : this.forward.apply(t);
|
||||
}
|
||||
|
||||
private TypeFrom reverse(TypeTo t) {
|
||||
return t == null ? null : this.reverse.apply(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.delegate.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.delegate.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return this.delegate.contains(reverse((TypeTo)o));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<TypeTo> iterator() {
|
||||
return Iterators.transform(this.delegate.iterator(), this::forward);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
Object[] array = this.delegate.toArray();
|
||||
for(int i = 0; i < array.length; i++) {
|
||||
array[i] = this.forward((TypeFrom)array[i]);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public <T> T[] toArray(@NotNull T[] ts) {
|
||||
if(ts.length >= this.delegate.size()) {
|
||||
Object[] setContents = toArray();
|
||||
System.arraycopy(setContents, 0, ts, 0, Math.min(setContents.length, ts.length));
|
||||
if(ts.length > setContents.length)
|
||||
ts[setContents.length] = null;
|
||||
return ts;
|
||||
} else {
|
||||
T[] realArray = Arrays.copyOf(ts, this.delegate.size());
|
||||
Iterator<TypeTo> iterator = this.iterator();
|
||||
int i = 0;
|
||||
while(iterator.hasNext())
|
||||
realArray[i++] = (T)iterator.next();
|
||||
return realArray;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(TypeTo typeFrom) {
|
||||
return this.delegate.add(reverse(typeFrom));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return this.delegate.remove(reverse((TypeTo)o));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(@NotNull Collection<?> collection) {
|
||||
return this.delegate.containsAll(Collections2.transform(collection, obj -> reverse((TypeTo)obj)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(@NotNull Collection<? extends TypeTo> collection) {
|
||||
return this.delegate.addAll(Collections2.transform(collection, this::reverse));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(@NotNull Collection<?> collection) {
|
||||
return this.delegate.retainAll(Collections2.transform(collection, obj -> reverse((TypeTo)obj)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(@NotNull Collection<?> collection) {
|
||||
return this.delegate.removeAll(Collections2.transform(collection, obj -> reverse((TypeTo)obj)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.delegate.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
package org.embeddedt.modernfix.forge.mixin.perf.rewrite_registry;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.registries.ForgeRegistry;
|
||||
import net.minecraftforge.registries.IForgeRegistryEntry;
|
||||
import org.embeddedt.modernfix.annotation.IgnoreOutsideDev;
|
||||
import org.embeddedt.modernfix.forge.registry.FastForgeRegistry;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(value = ForgeRegistry.class, remap = false)
|
||||
@IgnoreOutsideDev
|
||||
public class ForgeRegistryMixin<V extends IForgeRegistryEntry<V>> {
|
||||
@Shadow
|
||||
@Final
|
||||
@Mutable
|
||||
private BiMap<Integer, V> ids;
|
||||
|
||||
@Shadow @Final @Mutable private BiMap<ResourceKey<V>, V> keys;
|
||||
|
||||
@Shadow @Final private ResourceKey<Registry<V>> key;
|
||||
|
||||
@Shadow @Final @Mutable private BiMap<ResourceLocation, V> names;
|
||||
|
||||
@Shadow @Final @Mutable private BiMap owners;
|
||||
|
||||
private FastForgeRegistry<V> fastRegistry;
|
||||
|
||||
/**
|
||||
* The following code replaces the Forge HashBiMaps with a more efficient data structure based around
|
||||
* an array list for IDs and one HashMap going from value -> information.
|
||||
*/
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void replaceBackingMaps(CallbackInfo ci) {
|
||||
this.fastRegistry = new FastForgeRegistry<>(this.key);
|
||||
this.ids = fastRegistry.getIds();
|
||||
this.keys = fastRegistry.getKeys();
|
||||
this.names = fastRegistry.getNames();
|
||||
this.owners = fastRegistry.getOwners();
|
||||
}
|
||||
|
||||
@Inject(method = "freeze", at = @At("RETURN"))
|
||||
private void optimizeRegistry(CallbackInfo ci) {
|
||||
this.fastRegistry.optimize();
|
||||
}
|
||||
|
||||
@Redirect(method = "sync", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/BiMap;clear()V"))
|
||||
private void clearBiMap(BiMap map) {
|
||||
if(map == this.owners) {
|
||||
this.fastRegistry.clear();
|
||||
} else if(map == this.keys || map == this.names || map == this.ids) {
|
||||
// do nothing, the registry is faster at clearing everything at once
|
||||
} else
|
||||
map.clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
package org.embeddedt.modernfix.forge.mixin.perf.rewrite_registry;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.registries.ForgeRegistry;
|
||||
import org.embeddedt.modernfix.annotation.IgnoreOutsideDev;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@Mixin(ForgeRegistry.Snapshot.class)
|
||||
@IgnoreOutsideDev
|
||||
public class ForgeRegistrySnapshotMixin {
|
||||
@Shadow(remap = false) @Final @Mutable public Map<ResourceLocation, Integer> ids;
|
||||
|
||||
@Shadow(remap = false) @Final @Mutable public Set<ResourceLocation> dummied;
|
||||
|
||||
/**
|
||||
* The only good reason to use tree maps here is to keep the order the same. But we are tracking IDs
|
||||
* anyway so order shouldn't matter. We replace the maps that will be most used.
|
||||
*/
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void replaceSnapshotMaps(CallbackInfo ci) {
|
||||
this.ids = new Object2ObjectOpenHashMap<>();
|
||||
this.dummied = new ObjectOpenHashSet<>();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,602 +0,0 @@
|
|||
package org.embeddedt.modernfix.forge.registry;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.Iterators;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.registries.IForgeRegistryEntry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class FastForgeRegistry<V extends IForgeRegistryEntry<V>> {
|
||||
private final BiMap<Integer, V> ids;
|
||||
private final DataFieldBiMap<ResourceLocation> names;
|
||||
private final DataFieldBiMap<ResourceKey<V>> keys;
|
||||
private final DataFieldBiMap<?> owners;
|
||||
private final ResourceKey<Registry<V>> registryKey;
|
||||
|
||||
private final ObjectArrayList<V> valuesById;
|
||||
private final Object2ObjectOpenHashMap<V, RegistryValueData> infoByValue;
|
||||
|
||||
private void storeId(V value, int id) {
|
||||
RegistryValueData pair = infoByValue.computeIfAbsent(value, k -> new RegistryValueData());
|
||||
pair.id = id;
|
||||
}
|
||||
|
||||
private void updateInfoPairAndClearIfNull(V v, Consumer<RegistryValueData> consumer) {
|
||||
infoByValue.compute(v, (oldValue, oldPair) -> {
|
||||
if(oldPair == null)
|
||||
oldPair = new RegistryValueData();
|
||||
consumer.accept(oldPair);
|
||||
if(oldPair.isEmpty())
|
||||
return null;
|
||||
else
|
||||
return oldPair;
|
||||
});
|
||||
}
|
||||
|
||||
private void ensureArrayCanFitId(int id) {
|
||||
int desiredSize = id + 1;
|
||||
while(valuesById.size() < desiredSize) {
|
||||
valuesById.add(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.infoByValue.clear();
|
||||
for(int i = 0; i < this.valuesById.size(); i++) {
|
||||
this.valuesById.set(i, null);
|
||||
}
|
||||
this.names.clearUnsafe();
|
||||
this.keys.clearUnsafe();
|
||||
this.owners.clearUnsafe();
|
||||
}
|
||||
|
||||
public FastForgeRegistry(ResourceKey<Registry<V>> registryKey) {
|
||||
this.registryKey = registryKey;
|
||||
this.valuesById = new ObjectArrayList<>();
|
||||
this.infoByValue = new Object2ObjectOpenHashMap<>();
|
||||
this.keys = new DataFieldBiMap<>(p -> (ResourceKey<V>) p.key, (p, k) -> p.key = k);
|
||||
this.owners = new DataFieldBiMap<>(p -> p.overrideOwner, (p, k) -> p.overrideOwner = k);
|
||||
this.names = new DataFieldBiMap<>(p -> p.location, (p, l) -> p.location = l);
|
||||
// IDs require a specialized implementation, as we back the K->V direction with an array
|
||||
this.ids = new BiMap<Integer, V>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public V put(@Nullable Integer key, @Nullable V value) {
|
||||
RegistryValueData data = infoByValue.get(value);
|
||||
int unboxedKey = key;
|
||||
if(data != null && data.id != -1 && data.id != unboxedKey)
|
||||
throw new IllegalArgumentException("Existing mapping for ID " + data.id + " value " + value + " when new ID " + unboxedKey + " was requested");
|
||||
ensureArrayCanFitId(unboxedKey);
|
||||
V oldValue = valuesById.set(unboxedKey, value);
|
||||
storeId(value, unboxedKey);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public V forcePut(@Nullable Integer key, @Nullable V value) {
|
||||
ensureArrayCanFitId(key);
|
||||
V oldValue = valuesById.set(key, value);
|
||||
if(oldValue != null) {
|
||||
updateInfoPairAndClearIfNull(oldValue, pair -> pair.id = -1);
|
||||
}
|
||||
storeId(value, key);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends Integer, ? extends V> map) {
|
||||
map.forEach(this::put);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> values() {
|
||||
return Collections.unmodifiableSet(infoByValue.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiMap<V, Integer> inverse() {
|
||||
return new BiMap<V, Integer>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Integer put(@Nullable V key, @Nullable Integer value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Integer forcePut(@Nullable V key, @Nullable Integer value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends V, ? extends Integer> map) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> values() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiMap<Integer, V> inverse() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get(Object key) {
|
||||
RegistryValueData pair = infoByValue.get(key);
|
||||
if(pair == null)
|
||||
return null;
|
||||
return pair.id == -1 ? null : pair.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer remove(Object key) {
|
||||
RegistryValueData pair = infoByValue.get(key);
|
||||
if(pair == null)
|
||||
return null;
|
||||
int id = pair.id;
|
||||
if(id != -1)
|
||||
valuesById.set(id, null);
|
||||
updateInfoPairAndClearIfNull((V)key, p -> p.id = -1);
|
||||
return id == -1 ? null : id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<V> keySet() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Entry<V, Integer>> entrySet() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return infoByValue.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
int id = (Integer)key;
|
||||
if(id < 0 || id >= valuesById.size())
|
||||
return null;
|
||||
else
|
||||
return valuesById.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
valuesById.clear();
|
||||
infoByValue.values().removeIf(pair -> {
|
||||
pair.id = -1;
|
||||
return pair.isEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Integer> keySet() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Entry<Integer, V>> entrySet() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(BiConsumer<? super Integer, ? super V> action) {
|
||||
for(int i = 0 ; i < valuesById.size(); i++) {
|
||||
V val = valuesById.get(i);
|
||||
if(val != null)
|
||||
action.accept(i, val);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void optimize() {
|
||||
this.keys.optimize();
|
||||
this.owners.optimize();
|
||||
this.names.optimize();
|
||||
this.infoByValue.trim();
|
||||
}
|
||||
|
||||
public BiMap<Integer, V> getIds() {
|
||||
return ids;
|
||||
}
|
||||
|
||||
public BiMap<ResourceKey<V>, V> getKeys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
public BiMap<ResourceLocation, V> getNames() {
|
||||
return names;
|
||||
}
|
||||
|
||||
public DataFieldBiMap<?> getOwners() {
|
||||
return owners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom BiMap implementation that uses one internal hash map for the K->V direction, and the shared global
|
||||
* information hash map for the V->K direction.
|
||||
*/
|
||||
class DataFieldBiMap<K> implements BiMap<K, V> {
|
||||
public final Object2ObjectOpenHashMap<K, V> valuesByKey = new Object2ObjectOpenHashMap<>();
|
||||
private final Function<RegistryValueData, K> getter;
|
||||
private final BiConsumer<RegistryValueData, K> setter;
|
||||
|
||||
public DataFieldBiMap(Function<RegistryValueData, K> getter, BiConsumer<RegistryValueData, K> setter) {
|
||||
this.getter = getter;
|
||||
this.setter = setter;
|
||||
}
|
||||
|
||||
public void optimize() {
|
||||
this.valuesByKey.trim();
|
||||
}
|
||||
|
||||
public void clearUnsafe() {
|
||||
this.valuesByKey.clear();
|
||||
}
|
||||
|
||||
private V forcePut(@Nullable K key, @Nullable V value, boolean throwOnExisting) {
|
||||
if(throwOnExisting) {
|
||||
RegistryValueData dataForValue = infoByValue.get(value);
|
||||
// null check could be wrong if null is a valid value but doesn't matter in Forge's use
|
||||
if(dataForValue != null && getter.apply(dataForValue) != null && !Objects.equals(getter.apply(dataForValue), key)) {
|
||||
throw new IllegalArgumentException("Existing mapping for key " + key + " value " + value);
|
||||
}
|
||||
}
|
||||
V oldValue = valuesByKey.put(key, value);
|
||||
if(oldValue != null) {
|
||||
updateInfoPairAndClearIfNull(oldValue, p -> setter.accept(p, null));
|
||||
}
|
||||
updateInfoPairAndClearIfNull(value, p -> setter.accept(p, key));
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public V put(@Nullable K key, @Nullable V value) {
|
||||
return forcePut(key, value, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public V forcePut(@Nullable K key, @Nullable V value) {
|
||||
return forcePut(key, value, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> map) {
|
||||
map.forEach(this::put);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> values() {
|
||||
return Collections.unmodifiableSet(infoByValue.keySet());
|
||||
}
|
||||
|
||||
private DataFieldBiMapInverse<K> inverse = null;
|
||||
|
||||
@Override
|
||||
public BiMap<V, K> inverse() {
|
||||
if(inverse == null)
|
||||
inverse = new DataFieldBiMapInverse<>(this);
|
||||
return inverse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return valuesByKey.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return valuesByKey.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return valuesByKey.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return infoByValue.containsKey(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
return valuesByKey.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
V value = get(key);
|
||||
if(value == null)
|
||||
return null;
|
||||
inverse().remove(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
valuesByKey.values().forEach(v -> updateInfoPairAndClearIfNull(v, p -> p.key = null));
|
||||
valuesByKey.clear();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return Collections.unmodifiableSet(valuesByKey.keySet());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Map.Entry<K, V>> entrySet() {
|
||||
return Collections.unmodifiableSet(valuesByKey.entrySet());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class DataFieldBiMapInverse<K> implements BiMap<V, K> {
|
||||
private final DataFieldBiMap<K> forward;
|
||||
|
||||
public DataFieldBiMapInverse(DataFieldBiMap<K> forward) {
|
||||
this.forward = forward;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public K put(@Nullable V key, @Nullable K value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public K forcePut(@Nullable V key, @Nullable K value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends V, ? extends K> map) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> values() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiMap<K, V> inverse() {
|
||||
return forward;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return infoByValue.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return forward.valuesByKey.containsKey(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K get(Object key) {
|
||||
RegistryValueData pair = infoByValue.get(key);
|
||||
if(pair == null)
|
||||
return null;
|
||||
else
|
||||
return forward.getter.apply(pair);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K remove(Object key) {
|
||||
RegistryValueData pair = infoByValue.get(key);
|
||||
if(pair == null)
|
||||
return null;
|
||||
else {
|
||||
K rk = forward.getter.apply(pair);
|
||||
forward.valuesByKey.remove(rk);
|
||||
updateInfoPairAndClearIfNull((V)key, p -> forward.setter.accept(p, null));
|
||||
return rk;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<V> keySet() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Entry<V, K>> entrySet() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
class FastForgeRegistryLocationSet implements Set<ResourceLocation> {
|
||||
private final Set<ResourceKey<V>> backingSet;
|
||||
|
||||
public FastForgeRegistryLocationSet(Set<ResourceKey<V>> backingSet) {
|
||||
this.backingSet = backingSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return backingSet.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return backingSet.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return backingSet.contains(ResourceKey.create(FastForgeRegistry.this.registryKey, (ResourceLocation)o));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<ResourceLocation> iterator() {
|
||||
return Iterators.transform(backingSet.iterator(), ResourceKey::location);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
Object[] keyArray = backingSet.toArray();
|
||||
for(int i = 0; i < keyArray.length; i++) {
|
||||
keyArray[i] = ((ResourceKey<V>)keyArray[i]).location();
|
||||
}
|
||||
return keyArray;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public <T> T[] toArray(@NotNull T[] a) {
|
||||
Object[] keyArray = backingSet.toArray();
|
||||
T[] finalArray = Arrays.copyOf(a, keyArray.length);
|
||||
for(int i = 0; i < keyArray.length; i++) {
|
||||
finalArray[i] = (T)((ResourceKey<V>)keyArray[i]).location();
|
||||
}
|
||||
return finalArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(ResourceLocation resourceLocation) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(@NotNull Collection<?> c) {
|
||||
for(Object o : c) {
|
||||
if(!contains(o))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(@NotNull Collection<? extends ResourceLocation> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(@NotNull Collection<?> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(@NotNull Collection<?> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
static class RegistryValueData {
|
||||
public ResourceKey<?> key;
|
||||
public ResourceLocation location;
|
||||
public int id = -1;
|
||||
public Object overrideOwner;
|
||||
|
||||
boolean isEmpty() {
|
||||
return key == null && location == null && id == -1 && overrideOwner == null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user