/* * 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 implements WritableRegistry { private final ResourceKey> key; private final ObjectList> byId = new ObjectArrayList(256); private final Reference2IntMap toId = (Reference2IntMap)Util.make(new Reference2IntOpenHashMap(), t -> t.defaultReturnValue(-1)); private final Map> byLocation = new HashMap>(); private final Map, Holder.Reference> byKey = new HashMap, Holder.Reference>(); private final Map> byValue = new IdentityHashMap>(); private final Map, RegistrationInfo> registrationInfos = new IdentityHashMap, RegistrationInfo>(); private Lifecycle registryLifecycle; private final Map, HolderSet.Named> frozenTags = new IdentityHashMap, HolderSet.Named>(); private TagSet allTags = TagSet.unbound(); private boolean frozen; private @Nullable Map> unregisteredIntrusiveHolders; @Override public Stream> listTags() { return this.getTags(); } public MappedRegistry(ResourceKey> key, Lifecycle lifecycle) { this(key, lifecycle, false); } public MappedRegistry(ResourceKey> key, Lifecycle initialLifecycle, boolean intrusiveHolders) { this.key = key; this.registryLifecycle = initialLifecycle; if (intrusiveHolders) { this.unregisteredIntrusiveHolders = new IdentityHashMap>(); } } @Override public ResourceKey> 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 key) { if (this.frozen) { throw new IllegalStateException("Registry is already frozen (trying to add key " + String.valueOf(key) + ")"); } } @Override public Holder.Reference register(ResourceKey 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 holder = this.byValue.get(thing); return holder != null ? holder.key().identifier() : null; } @Override public Optional> 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 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> 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> get(Identifier id) { return Optional.ofNullable(this.byLocation.get(id)); } @Override public Optional> get(ResourceKey id) { return Optional.ofNullable(this.byKey.get(id)); } @Override public Optional> getAny() { return this.byId.isEmpty() ? Optional.empty() : Optional.of((Holder.Reference)this.byId.getFirst()); } @Override public Holder wrapAsHolder(T value) { Holder.Reference existingHolder = this.byValue.get(value); return existingHolder != null ? existingHolder : Holder.direct(value); } private Holder.Reference getOrCreateHolderOrThrow(ResourceKey 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)id); return Holder.Reference.createStandAlone(this, id); }); } @Override public int size() { return this.byKey.size(); } @Override public Optional registrationInfo(ResourceKey element) { return Optional.ofNullable(this.registrationInfos.get(element)); } @Override public Lifecycle registryLifecycle() { return this.registryLifecycle; } @Override public Iterator iterator() { return Iterators.transform((Iterator)this.byId.iterator(), Holder::value); } @Override public @Nullable T getValue(@Nullable Identifier key) { Holder.Reference result = this.byLocation.get(key); return MappedRegistry.getValueFromNullable(result); } private static @Nullable T getValueFromNullable(@Nullable Holder.Reference result) { return result != null ? (T)result.value() : null; } @Override public Set keySet() { return Collections.unmodifiableSet(this.byLocation.keySet()); } @Override public Set> registryKeySet() { return Collections.unmodifiableSet(this.byKey.keySet()); } @Override public Set, T>> entrySet() { return Collections.unmodifiableSet(Util.mapValuesLazy(this.byKey, Holder::value).entrySet()); } @Override public Stream> listElements() { return this.byId.stream(); } @Override public Stream> getTags() { return this.allTags.getTags(); } private HolderSet.Named getOrCreateTagForRegistration(TagKey tag) { return this.frozenTags.computeIfAbsent(tag, this::createTag); } private HolderSet.Named createTag(TagKey tag) { return new HolderSet.Named(this, tag); } @Override public boolean isEmpty() { return this.byKey.isEmpty(); } @Override public Optional> 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 key) { return this.byKey.containsKey(key); } @Override public Registry freeze() { if (this.frozen) { return this; } this.frozen = true; this.byValue.forEach((? super K value, ? super V holder) -> holder.bindValue(value)); List 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 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 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> get(TagKey id) { return this.allTags.get(id); } private Holder.Reference validateAndUnwrapTagElement(TagKey id, Holder 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 id, List> values) { this.validateWrite(); this.getOrCreateTagForRegistration(id).bind(values); } private void refreshTagsInHolders() { IdentityHashMap tagsForElement = new IdentityHashMap(); this.byKey.values().forEach(h -> tagsForElement.put((Holder.Reference)h, new ArrayList())); this.allTags.forEach((? super TagKey id, ? super HolderSet.Named values) -> { for (Holder value : values) { Holder.Reference reference = this.validateAndUnwrapTagElement((TagKey)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 createRegistrationLookup() { this.validateWrite(); return new HolderGetter(){ @Override public Optional> get(ResourceKey id) { return Optional.of(this.getOrThrow(id)); } @Override public Holder.Reference getOrThrow(ResourceKey id) { return MappedRegistry.this.getOrCreateHolderOrThrow(id); } @Override public Optional> get(TagKey id) { return Optional.of(this.getOrThrow(id)); } @Override public HolderSet.Named getOrThrow(TagKey id) { return MappedRegistry.this.getOrCreateTagForRegistration(id); } }; } @Override public Registry.PendingTags prepareTagReload(TagLoader.LoadResult 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 tagToAdd = this.frozenTags.get(id); if (tagToAdd == null) { tagToAdd = this.createTag((TagKey)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(){ @Override public HolderLookup.RegistryLookup parent() { return MappedRegistry.this; } @Override public Optional> get(TagKey id) { return Optional.ofNullable((HolderSet.Named)pendingTags.get(id)); } @Override public Stream> listTags() { return pendingTags.values().stream(); } }; return new Registry.PendingTags(){ @Override public ResourceKey> key() { return MappedRegistry.this.key(); } @Override public int size() { return pendingContents.size(); } @Override public HolderLookup.RegistryLookup 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 { public static TagSet unbound() { return new TagSet(){ @Override public boolean isBound() { return false; } @Override public Optional> get(TagKey id) { throw new IllegalStateException("Tags not bound, trying to access " + String.valueOf(id)); } @Override public void forEach(BiConsumer, ? super HolderSet.Named> action) { throw new IllegalStateException("Tags not bound"); } @Override public Stream> getTags() { throw new IllegalStateException("Tags not bound"); } }; } public static TagSet fromMap(final Map, HolderSet.Named> tags) { return new TagSet(){ @Override public boolean isBound() { return true; } @Override public Optional> get(TagKey id) { return Optional.ofNullable((HolderSet.Named)tags.get(id)); } @Override public void forEach(BiConsumer, ? super HolderSet.Named> action) { tags.forEach(action); } @Override public Stream> getTags() { return tags.values().stream(); } }; } public boolean isBound(); public Optional> get(TagKey var1); public void forEach(BiConsumer, ? super HolderSet.Named> var1); public Stream> getTags(); } }