mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-27 06:50:12 +01:00
Handle disabled vanilla registry values correctly
This commit is contained in:
parent
aa2c52baac
commit
957f493566
4 changed files with 65 additions and 86 deletions
|
@ -41,6 +41,14 @@
|
||||||
freeze();
|
freeze();
|
||||||
validate(REGISTRY);
|
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 @@
|
@@ -346,6 +_,7 @@
|
||||||
|
|
||||||
for (Registry<?> registry : REGISTRY) {
|
for (Registry<?> registry : REGISTRY) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package io.papermc.paper.registry;
|
package io.papermc.paper.registry;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
import io.papermc.paper.registry.entry.RegistryEntry;
|
import io.papermc.paper.registry.entry.RegistryEntry;
|
||||||
import io.papermc.paper.registry.entry.RegistryEntryMeta;
|
import io.papermc.paper.registry.entry.RegistryEntryMeta;
|
||||||
import io.papermc.paper.registry.legacy.DelayedRegistry;
|
import io.papermc.paper.registry.legacy.DelayedRegistry;
|
||||||
|
@ -13,6 +14,7 @@ import java.util.stream.Collectors;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import org.bukkit.Keyed;
|
import org.bukkit.Keyed;
|
||||||
import org.bukkit.Registry;
|
import org.bukkit.Registry;
|
||||||
|
import org.bukkit.craftbukkit.CraftRegistry;
|
||||||
import org.jetbrains.annotations.VisibleForTesting;
|
import org.jetbrains.annotations.VisibleForTesting;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
@ -104,6 +106,21 @@ public class PaperRegistryAccess implements RegistryAccess {
|
||||||
this.registerRegistry(resourceKey, registry, false);
|
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.
|
@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) {
|
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);
|
final @Nullable RegistryEntry<M, B> entry = PaperRegistries.getEntry(resourceKey);
|
||||||
|
|
|
@ -3,66 +3,26 @@ package org.bukkit.craftbukkit;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import io.papermc.paper.registry.entry.RegistryEntryMeta;
|
import io.papermc.paper.registry.entry.RegistryEntryMeta;
|
||||||
import io.papermc.paper.util.Holderable;
|
import io.papermc.paper.util.Holderable;
|
||||||
|
import io.papermc.paper.util.MCUtil;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.core.HolderOwner;
|
||||||
import net.minecraft.core.RegistryAccess;
|
import net.minecraft.core.RegistryAccess;
|
||||||
import net.minecraft.core.registries.Registries;
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
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.Keyed;
|
||||||
import org.bukkit.MusicInstrument;
|
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.Particle;
|
import org.bukkit.Particle;
|
||||||
import org.bukkit.Registry;
|
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.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.ApiVersion;
|
||||||
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
|
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
|
||||||
import org.bukkit.craftbukkit.util.Handleable;
|
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.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;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
|
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 net.minecraft.core.Registry<M> minecraftRegistry;
|
||||||
private final io.papermc.paper.registry.entry.RegistryTypeMapper<M, B> minecraftToBukkit; // Paper - switch to Holder
|
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 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
|
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
|
// Paper start - switch to Holder
|
||||||
|
@ -217,6 +178,16 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
|
||||||
this.minecraftRegistry = minecraftRegistry;
|
this.minecraftRegistry = minecraftRegistry;
|
||||||
this.minecraftToBukkit = minecraftToBukkit;
|
this.minecraftToBukkit = minecraftToBukkit;
|
||||||
this.serializationUpdater = serializationUpdater;
|
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
|
// 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;
|
return cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that the bukkit class is loaded before creating an instance.
|
final Optional<Holder.Reference<M>> holderOptional = this.minecraftRegistry.get(CraftNamespacedKey.toMinecraft(namespacedKey));
|
||||||
// This ensures that only one instance with a given key is created.
|
final Holder.Reference<M> holder;
|
||||||
//
|
if (holderOptional.isPresent()) {
|
||||||
// Without this code (when bukkit class is not loaded):
|
holder = holderOptional.get();
|
||||||
// Registry#get -> #createBukkit -> (load class -> create default) -> put in cache
|
} else if (!this.lockReferenceHolders && this.minecraftToBukkit.supportsDirectHolders()) { // only works if its Holderable
|
||||||
// Result: Registry#get != <bukkitClass>.<field> for possible one registry item
|
// 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
|
||||||
// With this code (when bukkit class is not loaded):
|
// to create something to fill the API constant fields, so we create a dummy reference holder.
|
||||||
// Registry#get -> (load class -> create default) -> Registry#get -> get from cache
|
holder = Holder.Reference.createStandAlone(this.invalidHolderOwner, MCUtil.toResourceKey(this.minecraftRegistry.key(), namespacedKey));
|
||||||
// Result: Registry#get == <bukkitClass>.<field>
|
} else {
|
||||||
if (!this.init) {
|
holder = null;
|
||||||
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 B bukkit = this.createBukkit(namespacedKey, holder);
|
||||||
B bukkit = this.createBukkit(namespacedKey, this.minecraftRegistry.get(CraftNamespacedKey.toMinecraft(namespacedKey)).orElse(null)); // Paper - switch to Holder
|
|
||||||
if (bukkit == null) {
|
if (bukkit == null) {
|
||||||
return 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);
|
return new io.papermc.paper.registry.set.NamedRegistryKeySetImpl<>(key, namedHolderSet);
|
||||||
}
|
}
|
||||||
// Paper end - RegistrySet API
|
// Paper end - RegistrySet API
|
||||||
|
|
||||||
|
final class InvalidHolderOwner implements HolderOwner<M> {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package org.bukkit.craftbukkit.enchantments;
|
package org.bukkit.craftbukkit.enchantments;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import io.papermc.paper.util.Holderable;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import net.minecraft.Util;
|
import net.minecraft.Util;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.network.chat.contents.TranslatableContents;
|
|
||||||
import net.minecraft.tags.EnchantmentTags;
|
import net.minecraft.tags.EnchantmentTags;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.Registry;
|
import org.bukkit.Registry;
|
||||||
|
@ -13,13 +13,12 @@ import org.bukkit.craftbukkit.CraftRegistry;
|
||||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||||
import org.bukkit.craftbukkit.legacy.FieldRename;
|
import org.bukkit.craftbukkit.legacy.FieldRename;
|
||||||
import org.bukkit.craftbukkit.util.ApiVersion;
|
import org.bukkit.craftbukkit.util.ApiVersion;
|
||||||
import org.bukkit.craftbukkit.util.Handleable;
|
|
||||||
import org.bukkit.enchantments.Enchantment;
|
import org.bukkit.enchantments.Enchantment;
|
||||||
import org.bukkit.enchantments.EnchantmentTarget;
|
import org.bukkit.enchantments.EnchantmentTarget;
|
||||||
import org.bukkit.enchantments.EnchantmentWrapper;
|
import org.bukkit.enchantments.EnchantmentWrapper;
|
||||||
import org.bukkit.inventory.ItemStack;
|
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) {
|
public static Enchantment minecraftToBukkit(net.minecraft.world.item.enchantment.Enchantment minecraft) {
|
||||||
return CraftRegistry.minecraftToBukkit(minecraft, Registries.ENCHANTMENT, Registry.ENCHANTMENT);
|
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);
|
return CraftRegistry.get(Registry.ENCHANTMENT, key, ApiVersion.CURRENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final NamespacedKey key;
|
|
||||||
private final Holder<net.minecraft.world.item.enchantment.Enchantment> handle;
|
private final Holder<net.minecraft.world.item.enchantment.Enchantment> handle;
|
||||||
|
|
||||||
public CraftEnchantment(NamespacedKey key, net.minecraft.world.item.enchantment.Enchantment handle) {
|
public CraftEnchantment(Holder<net.minecraft.world.item.enchantment.Enchantment> holder) {
|
||||||
this.key = key;
|
this.handle = holder;
|
||||||
this.handle = CraftRegistry.getMinecraftRegistry(Registries.ENCHANTMENT).wrapAsHolder(handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public net.minecraft.world.item.enchantment.Enchantment getHandle() {
|
public Holder<net.minecraft.world.item.enchantment.Enchantment> getHolder() {
|
||||||
return this.handle.value();
|
return this.handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NamespacedKey getKey() {
|
public NamespacedKey getKey() {
|
||||||
return this.key;
|
return Holderable.super.getKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -251,24 +248,16 @@ public class CraftEnchantment extends Enchantment implements Handleable<net.mine
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (this == other) {
|
return Holderable.super.implEquals(other);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(other instanceof CraftEnchantment)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.getKey().equals(((Enchantment) other).getKey());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return this.getKey().hashCode();
|
return Holderable.super.implHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "CraftEnchantment[" + this.getKey() + "]";
|
return Holderable.super.implToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue