aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0574-Add-PaperRegistry.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/server/0574-Add-PaperRegistry.patch')
-rw-r--r--patches/server/0574-Add-PaperRegistry.patch220
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