From 42472a8ab82e5e96d3e2fa56b3793663a046b43a Mon Sep 17 00:00:00 2001 From: SizableShrimp Date: Wed, 6 Apr 2022 16:13:17 -0500 Subject: [PATCH] Expose `getHolder()` method on RegistryObject, as helper for when absolutely necessary to pass into Vanilla code. (#8548) It is recommended you avoid if you can. --- .../minecraft/core/MappedRegistry.java.patch | 24 ++-- .../registries/RegistryObject.java | 104 ++++++++++++++++-- 2 files changed, 112 insertions(+), 16 deletions(-) diff --git a/patches/minecraft/net/minecraft/core/MappedRegistry.java.patch b/patches/minecraft/net/minecraft/core/MappedRegistry.java.patch index 6d8f8740e7..851cccdbe1 100644 --- a/patches/minecraft/net/minecraft/core/MappedRegistry.java.patch +++ b/patches/minecraft/net/minecraft/core/MappedRegistry.java.patch @@ -1,17 +1,27 @@ --- a/net/minecraft/core/MappedRegistry.java +++ b/net/minecraft/core/MappedRegistry.java -@@ -279,6 +_,14 @@ - return this.f_205842_.containsKey(p_175392_); - } +@@ -90,7 +_,8 @@ + this.f_122672_.size(Math.max(this.f_122672_.size(), p_205858_ + 1)); + this.f_122673_.put(p_205860_, p_205858_); + this.f_211051_ = null; +- if (p_205862_ && this.f_205842_.containsKey(p_205859_)) { ++ // Forge: Fix bug where a key is considered a duplicate if getOrCreateHolder was called before the entry was registered ++ if (p_205862_ && this.f_205842_.containsKey(p_205859_) && this.f_205842_.get(p_205859_).m_203633_()) { + Util.m_143785_("Adding duplicate key '" + p_205859_ + "' to registry"); + } +@@ -277,6 +_,14 @@ + + public boolean m_142003_(ResourceKey p_175392_) { + return this.f_205842_.containsKey(p_175392_); ++ } ++ + /** @deprecated Forge: For internal use only. Use the Register events when registering values. */ + @Deprecated + public void unfreeze() { + this.f_205845_ = false; + if (this.f_205846_ != null && this.f_205847_ == null) + this.f_205847_ = new IdentityHashMap<>(); -+ } -+ + } + public Registry m_203521_() { - this.f_205845_ = true; - List list = this.f_205842_.entrySet().stream().filter((p_211055_) -> { diff --git a/src/main/java/net/minecraftforge/registries/RegistryObject.java b/src/main/java/net/minecraftforge/registries/RegistryObject.java index 60fab715cc..f2e6ef868b 100644 --- a/src/main/java/net/minecraftforge/registries/RegistryObject.java +++ b/src/main/java/net/minecraftforge/registries/RegistryObject.java @@ -5,13 +5,13 @@ package net.minecraftforge.registries; +import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.data.BuiltinRegistries; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Objects; import java.util.Optional; @@ -23,10 +23,15 @@ import java.util.stream.Stream; public final class RegistryObject implements Supplier { + @Nullable private final ResourceLocation name; + @Nullable + private ResourceKey key; private final boolean optionalRegistry; @Nullable private T value; + @Nullable + private Holder holder; /** * @deprecated The uniqueness of registry super types will not be guaranteed starting in 1.19. @@ -193,7 +198,7 @@ public final class RegistryObject implements Supplier return new RegistryObject<>(name, registryName, modid, true); } - private static RegistryObject EMPTY = new RegistryObject<>(); + private static final RegistryObject EMPTY = new RegistryObject<>(); private static RegistryObject empty() { @SuppressWarnings("unchecked") @@ -268,6 +273,7 @@ public final class RegistryObject implements Supplier private RegistryObject(final ResourceLocation name, final ResourceLocation registryName, final String modid, boolean optionalRegistry) { this.name = name; + this.key = ResourceKey.create(ResourceKey.createRegistryKey(registryName), name); this.optionalRegistry = optionalRegistry; final Throwable callerStack = new Throwable("Calling Site from mod: " + modid); ObjectHolderRegistry.addHandler(new Consumer<>() @@ -297,11 +303,17 @@ public final class RegistryObject implements Supplier } /** - * Directly retrieves the wrapped Registry Object. This value will automatically be updated when the backing registry is updated. - * Will throw NPE if the value is null, use isPresent to check first. Or use any of the other guarded functions. + * Retrieves the wrapped object in the registry. + * This value will automatically be updated when the backing registry is updated. + * + * @throws NullPointerException If the value is null. Use {@link #isPresent()} to check if the value exists first. + * @see #isPresent() + * @see #orElse(Object) + * @see #orElseGet(Supplier) + * @see #orElseThrow(Supplier) */ + @NotNull @Override - @Nonnull public T get() { T ret = this.value; @@ -309,20 +321,50 @@ public final class RegistryObject implements Supplier return ret; } + @SuppressWarnings("unchecked") @Deprecated(since = "1.18.1") // TODO: make package-private public void updateReference(IForgeRegistry registry) { - this.value = registry.containsKey(this.name) ? registry.getValue(this.name) : null; + if (this.name == null) + return; + if (registry.containsKey(this.name)) + { + this.value = registry.getValue(this.name); + if (this.key == null) + this.key = (ResourceKey) ResourceKey.create(registry.getRegistryKey(), this.name); + this.holder = (Holder) registry.getHolder(this.name).orElse(null); + } + else + { + this.value = null; + this.holder = null; + } } + @SuppressWarnings("unchecked") void updateReference(Registry registry) { - this.value = registry.containsKey(this.name) ? registry.get(this.name) : null; + if (this.name == null) + return; + if (registry.containsKey(this.name)) + { + this.value = registry.get(this.name); + if (this.key == null) + this.key = (ResourceKey) ResourceKey.create(registry.key(), this.name); + this.holder = ((Registry) registry).getHolder(this.key).orElse(null); + } + else + { + this.value = null; + this.holder = null; + } } @SuppressWarnings("unchecked") void updateReference(ResourceLocation registryName) { + if (this.name == null) + return; IForgeRegistry forgeRegistry = RegistryManager.ACTIVE.getRegistry(registryName); if (forgeRegistry != null) { @@ -345,6 +387,7 @@ public final class RegistryObject implements Supplier } this.value = null; + this.holder = null; } private static boolean registryExists(ResourceLocation registryName) @@ -359,6 +402,18 @@ public final class RegistryObject implements Supplier return this.name; } + /** + * Returns the resource key that points to the registry and name of this registry object. + * Nullable only when the deprecated factories {@link #of(ResourceLocation, Class, String)} or {@link #of(ResourceLocation, Supplier)} are used. + * + * @return the resource key that points to the registry and name of this registry object + */ + @Nullable + public ResourceKey getKey() + { + return this.key; + } + public Stream stream() { return isPresent() ? Stream.of(get()) : Stream.of(); } @@ -523,6 +578,37 @@ public final class RegistryObject implements Supplier } } + /** + * Returns an optional {@link Holder} instance pointing to this RegistryObject's name and value. + *

+ * This should only be used in cases where vanilla code requires passing in a Holder. + * Mod-written code should rely on RegistryObjects or Suppliers instead. + *

+ * The returned optional will be empty if the registry does not exist + * or if the deprecated factories {@link #of(ResourceLocation, Class, String)} + * or {@link #of(ResourceLocation, Supplier)} are used. + * Otherwise, the optional Holder will be present even if {@link #isPresent()} returns false. + * + * @return an optional {@link Holder} instance pointing to this RegistryObject's name and value + */ + @SuppressWarnings("unchecked") + @NotNull + public Optional> getHolder() + { + if (this.holder == null && this.key != null && registryExists(this.key.registry())) + { + ResourceLocation registryName = this.key.registry(); + Registry registry = (Registry) Registry.REGISTRY.get(registryName); + if (registry == null) + registry = (Registry) BuiltinRegistries.REGISTRY.get(registryName); + + if (registry != null) + this.holder = registry.getOrCreateHolder(this.key); + } + + return Optional.ofNullable(this.holder); + } + @Override public boolean equals(Object obj) {