514 lines
18 KiB
Java
514 lines
18 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* com.google.common.collect.ImmutableMap
|
|
* com.google.common.collect.ImmutableMap$Builder
|
|
* com.google.common.collect.Iterators
|
|
* com.mojang.serialization.Lifecycle
|
|
* it.unimi.dsi.fastutil.objects.ObjectArrayList
|
|
* it.unimi.dsi.fastutil.objects.ObjectList
|
|
* it.unimi.dsi.fastutil.objects.Reference2IntMap
|
|
* it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap
|
|
* org.jspecify.annotations.Nullable
|
|
*/
|
|
package net.minecraft.core;
|
|
|
|
import com.google.common.collect.ImmutableMap;
|
|
import com.google.common.collect.Iterators;
|
|
import com.mojang.serialization.Lifecycle;
|
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
|
import it.unimi.dsi.fastutil.objects.ObjectList;
|
|
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
|
|
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.HashMap;
|
|
import java.util.IdentityHashMap;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Objects;
|
|
import java.util.Optional;
|
|
import java.util.Set;
|
|
import java.util.function.BiConsumer;
|
|
import java.util.stream.Stream;
|
|
import net.minecraft.core.Holder;
|
|
import net.minecraft.core.HolderGetter;
|
|
import net.minecraft.core.HolderLookup;
|
|
import net.minecraft.core.HolderSet;
|
|
import net.minecraft.core.RegistrationInfo;
|
|
import net.minecraft.core.Registry;
|
|
import net.minecraft.core.WritableRegistry;
|
|
import net.minecraft.resources.Identifier;
|
|
import net.minecraft.resources.ResourceKey;
|
|
import net.minecraft.tags.TagKey;
|
|
import net.minecraft.tags.TagLoader;
|
|
import net.minecraft.util.RandomSource;
|
|
import net.minecraft.util.Util;
|
|
import org.jspecify.annotations.Nullable;
|
|
|
|
public class MappedRegistry<T>
|
|
implements WritableRegistry<T> {
|
|
private final ResourceKey<? extends Registry<T>> key;
|
|
private final ObjectList<Holder.Reference<T>> byId = new ObjectArrayList(256);
|
|
private final Reference2IntMap<T> toId = (Reference2IntMap)Util.make(new Reference2IntOpenHashMap(), t -> t.defaultReturnValue(-1));
|
|
private final Map<Identifier, Holder.Reference<T>> byLocation = new HashMap<Identifier, Holder.Reference<T>>();
|
|
private final Map<ResourceKey<T>, Holder.Reference<T>> byKey = new HashMap<ResourceKey<T>, Holder.Reference<T>>();
|
|
private final Map<T, Holder.Reference<T>> byValue = new IdentityHashMap<T, Holder.Reference<T>>();
|
|
private final Map<ResourceKey<T>, RegistrationInfo> registrationInfos = new IdentityHashMap<ResourceKey<T>, RegistrationInfo>();
|
|
private Lifecycle registryLifecycle;
|
|
private final Map<TagKey<T>, HolderSet.Named<T>> frozenTags = new IdentityHashMap<TagKey<T>, HolderSet.Named<T>>();
|
|
private TagSet<T> allTags = TagSet.unbound();
|
|
private boolean frozen;
|
|
private @Nullable Map<T, Holder.Reference<T>> unregisteredIntrusiveHolders;
|
|
|
|
@Override
|
|
public Stream<HolderSet.Named<T>> listTags() {
|
|
return this.getTags();
|
|
}
|
|
|
|
public MappedRegistry(ResourceKey<? extends Registry<T>> key, Lifecycle lifecycle) {
|
|
this(key, lifecycle, false);
|
|
}
|
|
|
|
public MappedRegistry(ResourceKey<? extends Registry<T>> key, Lifecycle initialLifecycle, boolean intrusiveHolders) {
|
|
this.key = key;
|
|
this.registryLifecycle = initialLifecycle;
|
|
if (intrusiveHolders) {
|
|
this.unregisteredIntrusiveHolders = new IdentityHashMap<T, Holder.Reference<T>>();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public ResourceKey<? extends Registry<T>> key() {
|
|
return this.key;
|
|
}
|
|
|
|
public String toString() {
|
|
return "Registry[" + String.valueOf(this.key) + " (" + String.valueOf(this.registryLifecycle) + ")]";
|
|
}
|
|
|
|
private void validateWrite() {
|
|
if (this.frozen) {
|
|
throw new IllegalStateException("Registry is already frozen");
|
|
}
|
|
}
|
|
|
|
private void validateWrite(ResourceKey<T> key) {
|
|
if (this.frozen) {
|
|
throw new IllegalStateException("Registry is already frozen (trying to add key " + String.valueOf(key) + ")");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Holder.Reference<T> register(ResourceKey<T> key, T value, RegistrationInfo registrationInfo) {
|
|
Holder.Reference holder;
|
|
this.validateWrite(key);
|
|
Objects.requireNonNull(key);
|
|
Objects.requireNonNull(value);
|
|
if (this.byLocation.containsKey(key.identifier())) {
|
|
throw Util.pauseInIde(new IllegalStateException("Adding duplicate key '" + String.valueOf(key) + "' to registry"));
|
|
}
|
|
if (this.byValue.containsKey(value)) {
|
|
throw Util.pauseInIde(new IllegalStateException("Adding duplicate value '" + String.valueOf(value) + "' to registry"));
|
|
}
|
|
if (this.unregisteredIntrusiveHolders != null) {
|
|
holder = this.unregisteredIntrusiveHolders.remove(value);
|
|
if (holder == null) {
|
|
throw new AssertionError((Object)("Missing intrusive holder for " + String.valueOf(key) + ":" + String.valueOf(value)));
|
|
}
|
|
holder.bindKey(key);
|
|
} else {
|
|
holder = this.byKey.computeIfAbsent(key, k -> Holder.Reference.createStandAlone(this, k));
|
|
}
|
|
this.byKey.put(key, holder);
|
|
this.byLocation.put(key.identifier(), holder);
|
|
this.byValue.put(value, holder);
|
|
int newId = this.byId.size();
|
|
this.byId.add((Object)holder);
|
|
this.toId.put(value, newId);
|
|
this.registrationInfos.put(key, registrationInfo);
|
|
this.registryLifecycle = this.registryLifecycle.add(registrationInfo.lifecycle());
|
|
return holder;
|
|
}
|
|
|
|
@Override
|
|
public @Nullable Identifier getKey(T thing) {
|
|
Holder.Reference<T> holder = this.byValue.get(thing);
|
|
return holder != null ? holder.key().identifier() : null;
|
|
}
|
|
|
|
@Override
|
|
public Optional<ResourceKey<T>> getResourceKey(T thing) {
|
|
return Optional.ofNullable(this.byValue.get(thing)).map(Holder.Reference::key);
|
|
}
|
|
|
|
@Override
|
|
public int getId(@Nullable T thing) {
|
|
return this.toId.getInt(thing);
|
|
}
|
|
|
|
@Override
|
|
public @Nullable T getValue(@Nullable ResourceKey<T> key) {
|
|
return MappedRegistry.getValueFromNullable(this.byKey.get(key));
|
|
}
|
|
|
|
@Override
|
|
public @Nullable T byId(int id) {
|
|
if (id < 0 || id >= this.byId.size()) {
|
|
return null;
|
|
}
|
|
return ((Holder.Reference)this.byId.get(id)).value();
|
|
}
|
|
|
|
@Override
|
|
public Optional<Holder.Reference<T>> get(int id) {
|
|
if (id < 0 || id >= this.byId.size()) {
|
|
return Optional.empty();
|
|
}
|
|
return Optional.ofNullable((Holder.Reference)this.byId.get(id));
|
|
}
|
|
|
|
@Override
|
|
public Optional<Holder.Reference<T>> get(Identifier id) {
|
|
return Optional.ofNullable(this.byLocation.get(id));
|
|
}
|
|
|
|
@Override
|
|
public Optional<Holder.Reference<T>> get(ResourceKey<T> id) {
|
|
return Optional.ofNullable(this.byKey.get(id));
|
|
}
|
|
|
|
@Override
|
|
public Optional<Holder.Reference<T>> getAny() {
|
|
return this.byId.isEmpty() ? Optional.empty() : Optional.of((Holder.Reference)this.byId.getFirst());
|
|
}
|
|
|
|
@Override
|
|
public Holder<T> wrapAsHolder(T value) {
|
|
Holder.Reference<T> existingHolder = this.byValue.get(value);
|
|
return existingHolder != null ? existingHolder : Holder.direct(value);
|
|
}
|
|
|
|
private Holder.Reference<T> getOrCreateHolderOrThrow(ResourceKey<T> key) {
|
|
return this.byKey.computeIfAbsent(key, id -> {
|
|
if (this.unregisteredIntrusiveHolders != null) {
|
|
throw new IllegalStateException("This registry can't create new holders without value");
|
|
}
|
|
this.validateWrite((ResourceKey<T>)id);
|
|
return Holder.Reference.createStandAlone(this, id);
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public int size() {
|
|
return this.byKey.size();
|
|
}
|
|
|
|
@Override
|
|
public Optional<RegistrationInfo> registrationInfo(ResourceKey<T> element) {
|
|
return Optional.ofNullable(this.registrationInfos.get(element));
|
|
}
|
|
|
|
@Override
|
|
public Lifecycle registryLifecycle() {
|
|
return this.registryLifecycle;
|
|
}
|
|
|
|
@Override
|
|
public Iterator<T> iterator() {
|
|
return Iterators.transform((Iterator)this.byId.iterator(), Holder::value);
|
|
}
|
|
|
|
@Override
|
|
public @Nullable T getValue(@Nullable Identifier key) {
|
|
Holder.Reference<T> result = this.byLocation.get(key);
|
|
return MappedRegistry.getValueFromNullable(result);
|
|
}
|
|
|
|
private static <T> @Nullable T getValueFromNullable(@Nullable Holder.Reference<T> result) {
|
|
return result != null ? (T)result.value() : null;
|
|
}
|
|
|
|
@Override
|
|
public Set<Identifier> keySet() {
|
|
return Collections.unmodifiableSet(this.byLocation.keySet());
|
|
}
|
|
|
|
@Override
|
|
public Set<ResourceKey<T>> registryKeySet() {
|
|
return Collections.unmodifiableSet(this.byKey.keySet());
|
|
}
|
|
|
|
@Override
|
|
public Set<Map.Entry<ResourceKey<T>, T>> entrySet() {
|
|
return Collections.unmodifiableSet(Util.mapValuesLazy(this.byKey, Holder::value).entrySet());
|
|
}
|
|
|
|
@Override
|
|
public Stream<Holder.Reference<T>> listElements() {
|
|
return this.byId.stream();
|
|
}
|
|
|
|
@Override
|
|
public Stream<HolderSet.Named<T>> getTags() {
|
|
return this.allTags.getTags();
|
|
}
|
|
|
|
private HolderSet.Named<T> getOrCreateTagForRegistration(TagKey<T> tag) {
|
|
return this.frozenTags.computeIfAbsent(tag, this::createTag);
|
|
}
|
|
|
|
private HolderSet.Named<T> createTag(TagKey<T> tag) {
|
|
return new HolderSet.Named<T>(this, tag);
|
|
}
|
|
|
|
@Override
|
|
public boolean isEmpty() {
|
|
return this.byKey.isEmpty();
|
|
}
|
|
|
|
@Override
|
|
public Optional<Holder.Reference<T>> getRandom(RandomSource random) {
|
|
return Util.getRandomSafe(this.byId, random);
|
|
}
|
|
|
|
@Override
|
|
public boolean containsKey(Identifier key) {
|
|
return this.byLocation.containsKey(key);
|
|
}
|
|
|
|
@Override
|
|
public boolean containsKey(ResourceKey<T> key) {
|
|
return this.byKey.containsKey(key);
|
|
}
|
|
|
|
@Override
|
|
public Registry<T> freeze() {
|
|
if (this.frozen) {
|
|
return this;
|
|
}
|
|
this.frozen = true;
|
|
this.byValue.forEach((? super K value, ? super V holder) -> holder.bindValue(value));
|
|
List<Identifier> unboundEntries = this.byKey.entrySet().stream().filter(e -> !((Holder.Reference)e.getValue()).isBound()).map(e -> ((ResourceKey)e.getKey()).identifier()).sorted().toList();
|
|
if (!unboundEntries.isEmpty()) {
|
|
throw new IllegalStateException("Unbound values in registry " + String.valueOf(this.key()) + ": " + String.valueOf(unboundEntries));
|
|
}
|
|
if (this.unregisteredIntrusiveHolders != null) {
|
|
if (!this.unregisteredIntrusiveHolders.isEmpty()) {
|
|
throw new IllegalStateException("Some intrusive holders were not registered: " + String.valueOf(this.unregisteredIntrusiveHolders.values()));
|
|
}
|
|
this.unregisteredIntrusiveHolders = null;
|
|
}
|
|
if (this.allTags.isBound()) {
|
|
throw new IllegalStateException("Tags already present before freezing");
|
|
}
|
|
List<Identifier> unboundTags = this.frozenTags.entrySet().stream().filter(e -> !((HolderSet.Named)e.getValue()).isBound()).map(e -> ((TagKey)e.getKey()).location()).sorted().toList();
|
|
if (!unboundTags.isEmpty()) {
|
|
throw new IllegalStateException("Unbound tags in registry " + String.valueOf(this.key()) + ": " + String.valueOf(unboundTags));
|
|
}
|
|
this.allTags = TagSet.fromMap(this.frozenTags);
|
|
this.refreshTagsInHolders();
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public Holder.Reference<T> createIntrusiveHolder(T value) {
|
|
if (this.unregisteredIntrusiveHolders == null) {
|
|
throw new IllegalStateException("This registry can't create intrusive holders");
|
|
}
|
|
this.validateWrite();
|
|
return this.unregisteredIntrusiveHolders.computeIfAbsent(value, v -> Holder.Reference.createIntrusive(this, v));
|
|
}
|
|
|
|
@Override
|
|
public Optional<HolderSet.Named<T>> get(TagKey<T> id) {
|
|
return this.allTags.get(id);
|
|
}
|
|
|
|
private Holder.Reference<T> validateAndUnwrapTagElement(TagKey<T> id, Holder<T> value) {
|
|
if (!value.canSerializeIn(this)) {
|
|
throw new IllegalStateException("Can't create named set " + String.valueOf(id) + " containing value " + String.valueOf(value) + " from outside registry " + String.valueOf(this));
|
|
}
|
|
if (value instanceof Holder.Reference) {
|
|
Holder.Reference reference = (Holder.Reference)value;
|
|
return reference;
|
|
}
|
|
throw new IllegalStateException("Found direct holder " + String.valueOf(value) + " value in tag " + String.valueOf(id));
|
|
}
|
|
|
|
@Override
|
|
public void bindTag(TagKey<T> id, List<Holder<T>> values) {
|
|
this.validateWrite();
|
|
this.getOrCreateTagForRegistration(id).bind(values);
|
|
}
|
|
|
|
private void refreshTagsInHolders() {
|
|
IdentityHashMap<Holder.Reference, List> tagsForElement = new IdentityHashMap<Holder.Reference, List>();
|
|
this.byKey.values().forEach(h -> tagsForElement.put((Holder.Reference)h, new ArrayList()));
|
|
this.allTags.forEach((? super TagKey<T> id, ? super HolderSet.Named<T> values) -> {
|
|
for (Holder value : values) {
|
|
Holder.Reference reference = this.validateAndUnwrapTagElement((TagKey<T>)id, value);
|
|
((List)tagsForElement.get(reference)).add(id);
|
|
}
|
|
});
|
|
tagsForElement.forEach(Holder.Reference::bindTags);
|
|
}
|
|
|
|
public void bindAllTagsToEmpty() {
|
|
this.validateWrite();
|
|
this.frozenTags.values().forEach(e -> e.bind(List.of()));
|
|
}
|
|
|
|
@Override
|
|
public HolderGetter<T> createRegistrationLookup() {
|
|
this.validateWrite();
|
|
return new HolderGetter<T>(){
|
|
|
|
@Override
|
|
public Optional<Holder.Reference<T>> get(ResourceKey<T> id) {
|
|
return Optional.of(this.getOrThrow(id));
|
|
}
|
|
|
|
@Override
|
|
public Holder.Reference<T> getOrThrow(ResourceKey<T> id) {
|
|
return MappedRegistry.this.getOrCreateHolderOrThrow(id);
|
|
}
|
|
|
|
@Override
|
|
public Optional<HolderSet.Named<T>> get(TagKey<T> id) {
|
|
return Optional.of(this.getOrThrow(id));
|
|
}
|
|
|
|
@Override
|
|
public HolderSet.Named<T> getOrThrow(TagKey<T> id) {
|
|
return MappedRegistry.this.getOrCreateTagForRegistration(id);
|
|
}
|
|
};
|
|
}
|
|
|
|
@Override
|
|
public Registry.PendingTags<T> prepareTagReload(TagLoader.LoadResult<T> tags) {
|
|
if (!this.frozen) {
|
|
throw new IllegalStateException("Invalid method used for tag loading");
|
|
}
|
|
ImmutableMap.Builder pendingTagsBuilder = ImmutableMap.builder();
|
|
final HashMap pendingContents = new HashMap();
|
|
tags.tags().forEach((? super K id, ? super V contents) -> {
|
|
HolderSet.Named<T> tagToAdd = this.frozenTags.get(id);
|
|
if (tagToAdd == null) {
|
|
tagToAdd = this.createTag((TagKey<T>)id);
|
|
}
|
|
pendingTagsBuilder.put(id, tagToAdd);
|
|
pendingContents.put(id, List.copyOf(contents));
|
|
});
|
|
final ImmutableMap pendingTags = pendingTagsBuilder.build();
|
|
final HolderLookup.RegistryLookup.Delegate patchedHolder = new HolderLookup.RegistryLookup.Delegate<T>(){
|
|
|
|
@Override
|
|
public HolderLookup.RegistryLookup<T> parent() {
|
|
return MappedRegistry.this;
|
|
}
|
|
|
|
@Override
|
|
public Optional<HolderSet.Named<T>> get(TagKey<T> id) {
|
|
return Optional.ofNullable((HolderSet.Named)pendingTags.get(id));
|
|
}
|
|
|
|
@Override
|
|
public Stream<HolderSet.Named<T>> listTags() {
|
|
return pendingTags.values().stream();
|
|
}
|
|
};
|
|
return new Registry.PendingTags<T>(){
|
|
|
|
@Override
|
|
public ResourceKey<? extends Registry<? extends T>> key() {
|
|
return MappedRegistry.this.key();
|
|
}
|
|
|
|
@Override
|
|
public int size() {
|
|
return pendingContents.size();
|
|
}
|
|
|
|
@Override
|
|
public HolderLookup.RegistryLookup<T> lookup() {
|
|
return patchedHolder;
|
|
}
|
|
|
|
@Override
|
|
public void apply() {
|
|
pendingTags.forEach((id, tag) -> {
|
|
List values = pendingContents.getOrDefault(id, List.of());
|
|
tag.bind(values);
|
|
});
|
|
MappedRegistry.this.allTags = TagSet.fromMap(pendingTags);
|
|
MappedRegistry.this.refreshTagsInHolders();
|
|
}
|
|
};
|
|
}
|
|
|
|
private static interface TagSet<T> {
|
|
public static <T> TagSet<T> unbound() {
|
|
return new TagSet<T>(){
|
|
|
|
@Override
|
|
public boolean isBound() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public Optional<HolderSet.Named<T>> get(TagKey<T> id) {
|
|
throw new IllegalStateException("Tags not bound, trying to access " + String.valueOf(id));
|
|
}
|
|
|
|
@Override
|
|
public void forEach(BiConsumer<? super TagKey<T>, ? super HolderSet.Named<T>> action) {
|
|
throw new IllegalStateException("Tags not bound");
|
|
}
|
|
|
|
@Override
|
|
public Stream<HolderSet.Named<T>> getTags() {
|
|
throw new IllegalStateException("Tags not bound");
|
|
}
|
|
};
|
|
}
|
|
|
|
public static <T> TagSet<T> fromMap(final Map<TagKey<T>, HolderSet.Named<T>> tags) {
|
|
return new TagSet<T>(){
|
|
|
|
@Override
|
|
public boolean isBound() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public Optional<HolderSet.Named<T>> get(TagKey<T> id) {
|
|
return Optional.ofNullable((HolderSet.Named)tags.get(id));
|
|
}
|
|
|
|
@Override
|
|
public void forEach(BiConsumer<? super TagKey<T>, ? super HolderSet.Named<T>> action) {
|
|
tags.forEach(action);
|
|
}
|
|
|
|
@Override
|
|
public Stream<HolderSet.Named<T>> getTags() {
|
|
return tags.values().stream();
|
|
}
|
|
};
|
|
}
|
|
|
|
public boolean isBound();
|
|
|
|
public Optional<HolderSet.Named<T>> get(TagKey<T> var1);
|
|
|
|
public void forEach(BiConsumer<? super TagKey<T>, ? super HolderSet.Named<T>> var1);
|
|
|
|
public Stream<HolderSet.Named<T>> getTags();
|
|
}
|
|
}
|
|
|