diff options
Diffstat (limited to 'patches/server/0574-Add-PaperRegistry.patch')
-rw-r--r-- | patches/server/0574-Add-PaperRegistry.patch | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/patches/server/0574-Add-PaperRegistry.patch b/patches/server/0574-Add-PaperRegistry.patch new file mode 100644 index 0000000000..07bb4192a0 --- /dev/null +++ b/patches/server/0574-Add-PaperRegistry.patch @@ -0,0 +1,220 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic <[email protected]> +Date: Wed, 2 Mar 2022 13:33:08 -0800 +Subject: [PATCH] Add PaperRegistry + +PaperRegistry is a server-backed impl of bukkit's Registry interface + +diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistry.java b/src/main/java/io/papermc/paper/registry/PaperRegistry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..51cec316df8bc0c7d36e0b1dfdf8d9fae04e3606 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistry.java +@@ -0,0 +1,145 @@ ++package io.papermc.paper.registry; ++ ++import com.google.common.base.Preconditions; ++import com.google.common.base.Suppliers; ++import net.minecraft.core.Holder; ++import net.minecraft.core.Registry; ++import net.minecraft.core.RegistryAccess; ++import net.minecraft.resources.ResourceKey; ++import net.minecraft.resources.ResourceLocation; ++import net.minecraft.server.MinecraftServer; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++import java.util.Collections; ++import java.util.HashMap; ++import java.util.Iterator; ++import java.util.Map; ++import java.util.Objects; ++import java.util.Optional; ++import java.util.function.Supplier; ++ ++@DefaultQualifier(NonNull.class) ++public abstract class PaperRegistry<API extends Keyed, MINECRAFT> implements org.bukkit.Registry<API> { ++ ++ @SuppressWarnings("FieldMayBeFinal") // non-final for testing ++ private static Supplier<RegistryAccess> REGISTRY_ACCESS = Suppliers.memoize(() -> MinecraftServer.getServer().registryAccess()); ++ private static final Map<RegistryKey<?, ?>, PaperRegistry<?, ?>> INTERNAL_REGISTRIES = new HashMap<>(); ++ public static final Map<RegistryKey<?, ?>, PaperRegistry<?, ?>> REGISTRIES = Collections.unmodifiableMap(INTERNAL_REGISTRIES); ++ private static final Map<Class<?>, PaperRegistry<?, ?>> REGISTRY_BY_API_CLASS = new HashMap<>(); ++ private static final Map<ResourceKey<? extends Registry<?>>, PaperRegistry<?, ?>> REGISTRY_BY_RES_KEY = new HashMap<>(); ++ ++ private boolean registered; ++ private final RegistryKey<API, MINECRAFT> registryKey; ++ private final Supplier<Registry<MINECRAFT>> registry; ++ private final Map<NamespacedKey, API> cache = new HashMap<>(); ++ ++ public PaperRegistry(RegistryKey<API, MINECRAFT> registryKey) { ++ this.registryKey = registryKey; ++ this.registry = Suppliers.memoize(() -> REGISTRY_ACCESS.get().registryOrThrow(this.registryKey.resourceKey())); ++ } ++ ++ @Override ++ public @Nullable API get(NamespacedKey key) { ++ return this.cache.computeIfAbsent(key, k -> { ++ final @Nullable MINECRAFT nms = this.registry.get().get(CraftNamespacedKey.toMinecraft(k)); ++ if (nms != null) { ++ return this.convertToApi(k, nms); ++ } ++ return null; ++ }); ++ } ++ ++ public abstract API convertToApi(NamespacedKey key, MINECRAFT nms); ++ ++ public API convertToApi(ResourceLocation resourceLocation, MINECRAFT nms) { ++ return this.convertToApi(CraftNamespacedKey.fromMinecraft(resourceLocation), nms); ++ } ++ ++ public API convertToApi(Holder<MINECRAFT> nmsHolder) { ++ final Optional<ResourceKey<MINECRAFT>> key = nmsHolder.unwrapKey(); ++ if (nmsHolder.isBound() && key.isPresent()) { ++ return this.convertToApi(key.get().location(), nmsHolder.value()); ++ } else if (!nmsHolder.isBound() && key.isPresent()) { ++ return this.convertToApi(key.get().location(), this.registry.get().getOrThrow(key.get())); ++ } else if (nmsHolder.isBound() && key.isEmpty()) { ++ final @Nullable ResourceLocation loc = this.registry.get().getKey(nmsHolder.value()); ++ if (loc != null) { ++ return this.convertToApi(loc, nmsHolder.value()); ++ } ++ } ++ throw new IllegalStateException("Cannot convert " + nmsHolder + " to an API type in: " + this.registryKey); ++ } ++ ++ public MINECRAFT getMinecraftValue(API apiValue) { ++ return this.registry.get().getOptional(CraftNamespacedKey.toMinecraft(apiValue.getKey())).orElseThrow(); ++ } ++ ++ public Holder<MINECRAFT> getMinecraftHolder(API apiValue) { ++ return this.registry.get().getHolderOrThrow(ResourceKey.create(this.registryKey.resourceKey(), CraftNamespacedKey.toMinecraft(apiValue.getKey()))); ++ } ++ ++ @Override ++ public Iterator<API> iterator() { ++ return this.registry.get().keySet().stream().map(key -> this.get(CraftNamespacedKey.fromMinecraft(key))).iterator(); ++ } ++ ++ public void clearCache() { ++ this.cache.clear(); ++ } ++ ++ public void register() { ++ if (this.registered) { ++ throw new IllegalStateException("Already registered: " + this.registryKey.apiClass()); ++ } ++ INTERNAL_REGISTRIES.put(this.registryKey, this); ++ REGISTRY_BY_API_CLASS.put(this.registryKey.apiClass(), this); ++ REGISTRY_BY_RES_KEY.put(this.registryKey.resourceKey(), this); ++ this.registered = true; ++ } ++ ++ @Override ++ public boolean equals(@Nullable Object o) { ++ if (this == o) return true; ++ if (o == null || !PaperRegistry.class.isAssignableFrom(o.getClass())) return false; ++ PaperRegistry<?, ?> that = (PaperRegistry<?, ?>) o; ++ return this.registryKey.equals(that.registryKey); ++ } ++ ++ @Override ++ public int hashCode() { ++ return Objects.hash(this.registryKey); ++ } ++ ++ protected static <T> Supplier<Registry<T>> registryFor(ResourceKey<? extends Registry<T>> registryKey) { ++ return Suppliers.memoize(() -> REGISTRY_ACCESS.get().registryOrThrow(registryKey)); ++ } ++ ++ public static void clearCaches() { ++ for (PaperRegistry<?, ?> registry : INTERNAL_REGISTRIES.values()) { ++ registry.clearCache(); ++ } ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static <T extends Keyed> PaperRegistry<T, ?> getRegistry(Class<T> classOfT) { ++ Preconditions.checkArgument(REGISTRY_BY_API_CLASS.containsKey(classOfT), "No registry for that type"); ++ return (PaperRegistry<T, ?>) REGISTRY_BY_API_CLASS.get(classOfT); ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static <T> PaperRegistry<?, T> getRegistry(ResourceKey<? extends Registry<T>> resourceKey) { ++ Preconditions.checkArgument(REGISTRY_BY_RES_KEY.containsKey(resourceKey)); ++ return (PaperRegistry<?, T>) REGISTRY_BY_RES_KEY.get(resourceKey); ++ } ++ ++ @SuppressWarnings("unchecked") ++ public static <A extends Keyed, M> PaperRegistry<A, M> getRegistry(RegistryKey<A, M> registryKey) { ++ Preconditions.checkArgument(INTERNAL_REGISTRIES.containsKey(registryKey)); ++ return (PaperRegistry<A, M>) INTERNAL_REGISTRIES.get(registryKey); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/RegistryKey.java b/src/main/java/io/papermc/paper/registry/RegistryKey.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6f39e343147803e15e7681c993b8797a629702e7 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/RegistryKey.java +@@ -0,0 +1,8 @@ ++package io.papermc.paper.registry; ++ ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++ ++public record RegistryKey<API extends Keyed, MINECRAFT>(Class<API> apiClass, ResourceKey<? extends Registry<MINECRAFT>> resourceKey) { ++} +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 670180dd48a8e04b76c65242d2b316d52ae9090f..14b1524fcd27341eb8257f3925b94715bd4da152 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -2036,6 +2036,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa + this.packRepository.setSelected(dataPacks); + this.worldData.setDataPackConfig(MinecraftServer.getSelectedPacks(this.packRepository)); + this.resources.managers.updateRegistryTags(this.registryAccess()); ++ io.papermc.paper.PaperRegistry.clearCaches(); // Paper + new io.papermc.paper.event.server.ServerResourcesReloadedEvent(cause).callEvent(); // Paper + if (Thread.currentThread() != this.serverThread) return; // Paper + //this.getPlayerList().saveAll(); // Paper - we don't need to do this +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index 7a4ae640aaaf2017ad4f95ca1393b554b0b30302..9374dd74d42e005b7573800d3e9a356e1c57ea86 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -512,6 +512,11 @@ public final class CraftMagicNumbers implements UnsafeValues { + public int nextEntityId() { + return net.minecraft.world.entity.Entity.nextEntityId(); + } ++ ++ @Override ++ public <T extends org.bukkit.Keyed> Registry<T> registryFor(Class<T> classOfT) { ++ return io.papermc.paper.registry.PaperRegistry.getRegistry(classOfT); ++ } + // Paper end + + /** +diff --git a/src/test/java/org/bukkit/support/AbstractTestingBase.java b/src/test/java/org/bukkit/support/AbstractTestingBase.java +index d6b6b7a3d2949126520e8256563afeb2b43bf12c..37934f0da922d696373e7a3a8cf976fcb9015271 100644 +--- a/src/test/java/org/bukkit/support/AbstractTestingBase.java ++++ b/src/test/java/org/bukkit/support/AbstractTestingBase.java +@@ -38,6 +38,15 @@ public abstract class AbstractTestingBase { + MultiPackResourceManager resourceManager = new MultiPackResourceManager(PackType.SERVER_DATA, Collections.singletonList(new VanillaPackResources(ServerPacksSource.BUILT_IN_METADATA, "minecraft"))); + // add tags and loot tables for unit tests + RegistryAccess.Frozen registry = RegistryAccess.builtinCopy().freeze(); ++ // Paper start ++ try { ++ java.lang.reflect.Field field = io.papermc.paper.registry.PaperRegistry.class.getDeclaredField("REGISTRY_ACCESS"); ++ field.trySetAccessible(); ++ field.set(null, com.google.common.base.Suppliers.ofInstance(registry)); ++ } catch (ReflectiveOperationException ex) { ++ throw new IllegalStateException("Could not reflectively set RegistryAccess in PaperRegistry", ex); ++ } ++ // Paper end + // Register vanilla pack + DATA_PACK = ReloadableServerResources.loadResources(resourceManager, registry, Commands.CommandSelection.DEDICATED, 0, MoreExecutors.directExecutor(), MoreExecutors.directExecutor()).join(); + // Bind tags |