mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-03 13:36:44 +01:00
1358d1e914
Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: 881e06e5 PR-725: Add Item Unlimited Lifetime APIs CraftBukkit Changes: 74c08312 SPIGOT-6962: Call EntityChangeBlockEvent when when FallingBlockEntity starts to fall 64db5126 SPIGOT-6959: Make /loot command ignore empty items for spawn 2d760831 Increase outdated build delay 9ed7e4fb SPIGOT-6138, SPIGOT-6415: Don't call CreatureSpawnEvent after cross-dimensional travel fc4ad813 SPIGOT-6895: Trees grown with applyBoneMeal() don't fire the StructureGrowthEvent 59733a2e SPIGOT-6961: Actually return a copy of the ItemMeta Spigot Changes: ffceeae3 SPIGOT-6956: Drop unload queue patch as attempt at fixing stop issue e19ddabd PR-1011: Add Item Unlimited Lifetime APIs 34d40b0e SPIGOT-2942: give command fires PlayerDropItemEvent, cancelling it causes Item Duplication
220 lines
11 KiB
Diff
220 lines
11 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
|
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 9abe6de575509d930c3f055e8dc5a14de5f1f49d..696d382283f94335f6e23eb12c6fa209c51cff8c 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -2032,6 +2032,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
|