diff options
author | Jake Potrebic <[email protected]> | 2024-12-22 22:04:51 -0800 |
---|---|---|
committer | Jake Potrebic <[email protected]> | 2024-12-23 14:50:02 -0800 |
commit | 957f493566248c2fd721bed6219d4ed163bc809d (patch) | |
tree | d02ecea14eeaf37463467d66fd645d495e0ee188 | |
parent | aa2c52baac16acfd3fea91be648587819042554b (diff) | |
download | Paper-957f493566248c2fd721bed6219d4ed163bc809d.tar.gz Paper-957f493566248c2fd721bed6219d4ed163bc809d.zip |
Handle disabled vanilla registry values correctly
4 files changed, 65 insertions, 86 deletions
diff --git a/paper-server/patches/sources/net/minecraft/core/registries/BuiltInRegistries.java.patch b/paper-server/patches/sources/net/minecraft/core/registries/BuiltInRegistries.java.patch index bc224c349b..0d1d444e1b 100644 --- a/paper-server/patches/sources/net/minecraft/core/registries/BuiltInRegistries.java.patch +++ b/paper-server/patches/sources/net/minecraft/core/registries/BuiltInRegistries.java.patch @@ -41,6 +41,14 @@ freeze(); validate(REGISTRY); } +@@ -338,6 +_,7 @@ + if (supplier.get() == null) { + LOGGER.error("Unable to bootstrap registry '{}'", resourceLocation); + } ++ io.papermc.paper.registry.PaperRegistryAccess.instance().lockReferenceHolders(ResourceKey.createRegistryKey(resourceLocation)); // Paper - lock reference holder creation + }); + } + @@ -346,6 +_,7 @@ for (Registry<?> registry : REGISTRY) { diff --git a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java index 3be7e0a1fb..6400df6ea1 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java @@ -1,5 +1,6 @@ package io.papermc.paper.registry; +import com.google.common.base.Preconditions; import io.papermc.paper.registry.entry.RegistryEntry; import io.papermc.paper.registry.entry.RegistryEntryMeta; import io.papermc.paper.registry.legacy.DelayedRegistry; @@ -13,6 +14,7 @@ import java.util.stream.Collectors; import net.minecraft.resources.ResourceKey; import org.bukkit.Keyed; import org.bukkit.Registry; +import org.bukkit.craftbukkit.CraftRegistry; import org.jetbrains.annotations.VisibleForTesting; import org.jspecify.annotations.Nullable; @@ -104,6 +106,21 @@ public class PaperRegistryAccess implements RegistryAccess { this.registerRegistry(resourceKey, registry, false); } + public <M> void lockReferenceHolders(final ResourceKey<? extends net.minecraft.core.Registry<M>> resourceKey) { + final RegistryEntry<M, Keyed> entry = PaperRegistries.getEntry(resourceKey); + if (entry == null || !(entry.meta() instanceof final RegistryEntryMeta.ServerSide<M, Keyed> serverSide) || !serverSide.registryTypeMapper().supportsDirectHolders()) { + return; + } + final CraftRegistry<?, M> registry = (CraftRegistry<?, M>) this.getRegistry(entry.apiKey()); + Preconditions.checkState(registry.isUnloaded(), "Registry %s is already loaded", resourceKey); + try { + Class.forName(serverSide.classToPreload().getName()); // this should always trigger the initialization of the class + } catch (final ClassNotFoundException e) { + throw new IllegalStateException("Failed to load class " + serverSide.classToPreload().getName(), e); + } + registry.lockReferenceHolders(); + } + @SuppressWarnings("unchecked") // this method should be called right after any new MappedRegistry instances are created to later be used by the server. private <M, B extends Keyed, R extends Registry<B>> void registerRegistry(final ResourceKey<? extends net.minecraft.core.Registry<M>> resourceKey, final net.minecraft.core.Registry<M> registry, final boolean replace) { final @Nullable RegistryEntry<M, B> entry = PaperRegistries.getEntry(resourceKey); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java index 332215f8b4..ab0a1eed5c 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java @@ -3,66 +3,26 @@ package org.bukkit.craftbukkit; import com.google.common.base.Preconditions; import io.papermc.paper.registry.entry.RegistryEntryMeta; import io.papermc.paper.util.Holderable; +import io.papermc.paper.util.MCUtil; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.Optional; import java.util.function.BiFunction; import java.util.stream.Stream; import net.minecraft.core.Holder; +import net.minecraft.core.HolderOwner; import net.minecraft.core.RegistryAccess; -import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; -import org.bukkit.Art; -import org.bukkit.Fluid; -import org.bukkit.GameEvent; -import org.bukkit.JukeboxSong; import org.bukkit.Keyed; -import org.bukkit.MusicInstrument; import org.bukkit.NamespacedKey; import org.bukkit.Particle; import org.bukkit.Registry; -import org.bukkit.Sound; -import org.bukkit.attribute.Attribute; -import org.bukkit.block.Biome; -import org.bukkit.block.BlockType; -import org.bukkit.block.banner.PatternType; -import org.bukkit.craftbukkit.attribute.CraftAttribute; -import org.bukkit.craftbukkit.block.CraftBiome; -import org.bukkit.craftbukkit.block.CraftBlockType; -import org.bukkit.craftbukkit.block.banner.CraftPatternType; -import org.bukkit.craftbukkit.damage.CraftDamageType; -import org.bukkit.craftbukkit.enchantments.CraftEnchantment; -import org.bukkit.craftbukkit.entity.CraftCat; -import org.bukkit.craftbukkit.entity.CraftFrog; -import org.bukkit.craftbukkit.entity.CraftVillager; -import org.bukkit.craftbukkit.entity.CraftWolf; -import org.bukkit.craftbukkit.generator.structure.CraftStructure; -import org.bukkit.craftbukkit.generator.structure.CraftStructureType; -import org.bukkit.craftbukkit.inventory.CraftItemType; -import org.bukkit.craftbukkit.inventory.CraftMenuType; -import org.bukkit.craftbukkit.inventory.trim.CraftTrimMaterial; -import org.bukkit.craftbukkit.inventory.trim.CraftTrimPattern; import org.bukkit.craftbukkit.legacy.FieldRename; -import org.bukkit.craftbukkit.map.CraftMapCursor; -import org.bukkit.craftbukkit.potion.CraftPotionEffectType; import org.bukkit.craftbukkit.util.ApiVersion; import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.craftbukkit.util.Handleable; -import org.bukkit.damage.DamageType; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Cat; import org.bukkit.entity.EntityType; -import org.bukkit.entity.Frog; -import org.bukkit.entity.Villager; -import org.bukkit.entity.Wolf; -import org.bukkit.generator.structure.Structure; -import org.bukkit.generator.structure.StructureType; -import org.bukkit.inventory.ItemType; -import org.bukkit.inventory.MenuType; -import org.bukkit.inventory.meta.trim.TrimMaterial; -import org.bukkit.inventory.meta.trim.TrimPattern; -import org.bukkit.map.MapCursor; -import org.bukkit.potion.PotionEffectType; import org.jetbrains.annotations.NotNull; public class CraftRegistry<B extends Keyed, M> implements Registry<B> { @@ -202,7 +162,8 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> { private final net.minecraft.core.Registry<M> minecraftRegistry; private final io.papermc.paper.registry.entry.RegistryTypeMapper<M, B> minecraftToBukkit; // Paper - switch to Holder private final BiFunction<NamespacedKey, ApiVersion, NamespacedKey> serializationUpdater; // Paper - rename to make it *clear* what it is *only* for - private boolean init; + private final InvalidHolderOwner invalidHolderOwner = new InvalidHolderOwner(); + private boolean lockReferenceHolders; public CraftRegistry(Class<?> bukkitClass, net.minecraft.core.Registry<M> minecraftRegistry, BiFunction<? super NamespacedKey, M, B> minecraftToBukkit, BiFunction<NamespacedKey, ApiVersion, NamespacedKey> serializationUpdater) { // Paper - relax preload class // Paper start - switch to Holder @@ -217,6 +178,16 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> { this.minecraftRegistry = minecraftRegistry; this.minecraftToBukkit = minecraftToBukkit; this.serializationUpdater = serializationUpdater; + this.lockReferenceHolders = !this.minecraftToBukkit.supportsDirectHolders(); + } + + public boolean isUnloaded() { + return this.cache.isEmpty(); + } + + public void lockReferenceHolders() { + Preconditions.checkState(!this.lockReferenceHolders, "Reference holders are already locked"); + this.lockReferenceHolders = true; } // Paper - inline into CraftRegistry#get(Registry, NamespacedKey, ApiVersion) above @@ -228,28 +199,19 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> { return cached; } - // Make sure that the bukkit class is loaded before creating an instance. - // This ensures that only one instance with a given key is created. - // - // Without this code (when bukkit class is not loaded): - // Registry#get -> #createBukkit -> (load class -> create default) -> put in cache - // Result: Registry#get != <bukkitClass>.<field> for possible one registry item - // - // With this code (when bukkit class is not loaded): - // Registry#get -> (load class -> create default) -> Registry#get -> get from cache - // Result: Registry#get == <bukkitClass>.<field> - if (!this.init) { - this.init = true; - try { - Class.forName(this.bukkitClass.getName()); - } catch (ClassNotFoundException e) { - throw new RuntimeException("Could not load registry class " + this.bukkitClass, e); - } - - return this.get(namespacedKey); + final Optional<Holder.Reference<M>> holderOptional = this.minecraftRegistry.get(CraftNamespacedKey.toMinecraft(namespacedKey)); + final Holder.Reference<M> holder; + if (holderOptional.isPresent()) { + holder = holderOptional.get(); + } else if (!this.lockReferenceHolders && this.minecraftToBukkit.supportsDirectHolders()) { // only works if its Holderable + // we lock the reference holders after the preload class has been initialized + // this is to support the vanilla mechanic of preventing vanilla registry entries being loaded. We need + // to create something to fill the API constant fields, so we create a dummy reference holder. + holder = Holder.Reference.createStandAlone(this.invalidHolderOwner, MCUtil.toResourceKey(this.minecraftRegistry.key(), namespacedKey)); + } else { + holder = null; } - - B bukkit = this.createBukkit(namespacedKey, this.minecraftRegistry.get(CraftNamespacedKey.toMinecraft(namespacedKey)).orElse(null)); // Paper - switch to Holder + final B bukkit = this.createBukkit(namespacedKey, holder); if (bukkit == null) { return null; } @@ -320,4 +282,7 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> { return new io.papermc.paper.registry.set.NamedRegistryKeySetImpl<>(key, namedHolderSet); } // Paper end - RegistrySet API + + final class InvalidHolderOwner implements HolderOwner<M> { + } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java b/paper-server/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java index 34934f0dbe..36825fb8f0 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/enchantments/CraftEnchantment.java @@ -1,11 +1,11 @@ package org.bukkit.craftbukkit.enchantments; import com.google.common.base.Preconditions; +import io.papermc.paper.util.Holderable; import java.util.Locale; import net.minecraft.Util; import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; -import net.minecraft.network.chat.contents.TranslatableContents; import net.minecraft.tags.EnchantmentTags; import org.bukkit.NamespacedKey; import org.bukkit.Registry; @@ -13,13 +13,12 @@ import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.legacy.FieldRename; import org.bukkit.craftbukkit.util.ApiVersion; -import org.bukkit.craftbukkit.util.Handleable; import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.EnchantmentTarget; import org.bukkit.enchantments.EnchantmentWrapper; import org.bukkit.inventory.ItemStack; -public class CraftEnchantment extends Enchantment implements Handleable<net.minecraft.world.item.enchantment.Enchantment> { +public class CraftEnchantment extends Enchantment implements Holderable<net.minecraft.world.item.enchantment.Enchantment> { public static Enchantment minecraftToBukkit(net.minecraft.world.item.enchantment.Enchantment minecraft) { return CraftRegistry.minecraftToBukkit(minecraft, Registries.ENCHANTMENT, Registry.ENCHANTMENT); @@ -56,22 +55,20 @@ public class CraftEnchantment extends Enchantment implements Handleable<net.mine return CraftRegistry.get(Registry.ENCHANTMENT, key, ApiVersion.CURRENT); } - private final NamespacedKey key; private final Holder<net.minecraft.world.item.enchantment.Enchantment> handle; - public CraftEnchantment(NamespacedKey key, net.minecraft.world.item.enchantment.Enchantment handle) { - this.key = key; - this.handle = CraftRegistry.getMinecraftRegistry(Registries.ENCHANTMENT).wrapAsHolder(handle); + public CraftEnchantment(Holder<net.minecraft.world.item.enchantment.Enchantment> holder) { + this.handle = holder; } @Override - public net.minecraft.world.item.enchantment.Enchantment getHandle() { - return this.handle.value(); + public Holder<net.minecraft.world.item.enchantment.Enchantment> getHolder() { + return this.handle; } @Override public NamespacedKey getKey() { - return this.key; + return Holderable.super.getKey(); } @Override @@ -251,24 +248,16 @@ public class CraftEnchantment extends Enchantment implements Handleable<net.mine @Override public boolean equals(Object other) { - if (this == other) { - return true; - } - - if (!(other instanceof CraftEnchantment)) { - return false; - } - - return this.getKey().equals(((Enchantment) other).getKey()); + return Holderable.super.implEquals(other); } @Override public int hashCode() { - return this.getKey().hashCode(); + return Holderable.super.implHashCode(); } @Override public String toString() { - return "CraftEnchantment[" + this.getKey() + "]"; + return Holderable.super.implToString(); } } |