From df157b7d6c0979338644003ec18a875f2c9ffad1 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Fri, 14 Jun 2024 14:48:56 -0700 Subject: rebased on 1.21 --- patches/api/0478-Registry-Modification-API.patch | 399 ++++++++++ patches/api/0484-Registry-Modification-API.patch | 399 ---------- patches/server/0237-Optimize-MappedRegistry.patch | 2 +- ...dd-RegistryAccess-for-managing-Registries.patch | 4 +- .../server/0975-Brigadier-based-command-API.patch | 2 +- .../server/0991-Registry-Modification-API.patch | 864 +++++++++++++++++++++ .../server/1054-Registry-Modification-API.patch | 852 -------------------- .../java/io/papermc/testplugin/TestPlugin.java | 14 - .../io/papermc/testplugin/TestPluginBootstrap.java | 23 +- 9 files changed, 1268 insertions(+), 1291 deletions(-) create mode 100644 patches/api/0478-Registry-Modification-API.patch delete mode 100644 patches/api/0484-Registry-Modification-API.patch create mode 100644 patches/server/0991-Registry-Modification-API.patch delete mode 100644 patches/server/1054-Registry-Modification-API.patch diff --git a/patches/api/0478-Registry-Modification-API.patch b/patches/api/0478-Registry-Modification-API.patch new file mode 100644 index 0000000000..70f095bc1f --- /dev/null +++ b/patches/api/0478-Registry-Modification-API.patch @@ -0,0 +1,399 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 2 Mar 2022 13:36:21 -0800 +Subject: [PATCH] Registry Modification API + + +diff --git a/src/main/java/io/papermc/paper/registry/RegistryBuilder.java b/src/main/java/io/papermc/paper/registry/RegistryBuilder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6edf300c1d81c1001756141c9efd022ba0e372cd +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/RegistryBuilder.java +@@ -0,0 +1,13 @@ ++package io.papermc.paper.registry; ++ ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * To be implemented by any type used for modifying registries. ++ * ++ * @param registry value type ++ */ ++@ApiStatus.NonExtendable ++@ApiStatus.Experimental ++public interface RegistryBuilder { ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEvent.java b/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d6722f7b55e260bab4bab5c361f9c0e9888c6752 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEvent.java +@@ -0,0 +1,33 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.TypedKey; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * Event object for {@link RegistryEventProvider#entryAdd()}. This ++ * event is fired right before a specific entry is registered in/added to registry. ++ * It provides a way for plugins to modify parts of this entry. ++ * ++ * @param registry entry type ++ * @param registry entry builder type ++ */ ++@ApiStatus.Experimental ++@ApiStatus.NonExtendable ++public interface RegistryEntryAddEvent> extends RegistryEvent { ++ ++ /** ++ * Gets the builder for the entry being added to the registry. ++ * ++ * @return the object builder ++ */ ++ @NonNull B builder(); ++ ++ /** ++ * Gets the key for this entry in the registry. ++ * ++ * @return the key ++ */ ++ @NonNull TypedKey key(); ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEvent.java b/src/main/java/io/papermc/paper/registry/event/RegistryEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..498c5920926158e86c2aec2bd2129d5e8b8613a3 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryEvent.java +@@ -0,0 +1,23 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; ++import io.papermc.paper.registry.RegistryKey; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * Base type for all registry events. ++ * ++ * @param registry entry type ++ */ ++@ApiStatus.Experimental ++@ApiStatus.NonExtendable ++public interface RegistryEvent extends LifecycleEvent { ++ ++ /** ++ * Get the key for the registry this event pertains to. ++ * ++ * @return the registry key ++ */ ++ @NonNull RegistryKey registryKey(); ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventProvider.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventProvider.java +new file mode 100644 +index 0000000000000000000000000000000000000000..477ed0fd5acc923d429980529876f0dd7dd3a52a +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventProvider.java +@@ -0,0 +1,58 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.LifecycleEventHandlerConfiguration; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfiguration; ++import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.event.type.RegistryEntryAddEventType; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * Provider for registry events for a specific registry. ++ *

++ * Supported events are: ++ *

    ++ *
  • {@link RegistryEntryAddEvent} (via {@link #entryAdd()})
  • ++ *
  • {@link RegistryFreezeEvent} (via {@link #freeze()})
  • ++ *
++ * ++ * @param registry entry type ++ * @param registry entry builder type ++ */ ++@ApiStatus.Experimental ++@ApiStatus.NonExtendable ++public interface RegistryEventProvider> { ++ ++ /** ++ * Gets the event type for {@link RegistryEntryAddEvent} which is fired just before ++ * an object is added to a registry. ++ *

++ * Can be used in {@link io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager#registerEventHandler(LifecycleEventType, LifecycleEventHandler)} ++ * to register a handler for {@link RegistryEntryAddEvent}. ++ * ++ * @return the registry entry add event type ++ */ ++ @NonNull RegistryEntryAddEventType entryAdd(); ++ ++ /** ++ * Gets the event type for {@link RegistryFreezeEvent} which is fired just before ++ * a registry is frozen. It allows for the registration of new objects. ++ *

++ * Can be used in {@link io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager#registerEventHandler(LifecycleEventType, LifecycleEventHandler)} ++ * to register a handler for {@link RegistryFreezeEvent}. ++ * ++ * @return the registry freeze event type ++ */ ++ LifecycleEventType.@NonNull Prioritizable> freeze(); ++ ++ /** ++ * Gets the registry key associated with this event type provider. ++ * ++ * @return the registry key ++ */ ++ @NonNull RegistryKey registryKey(); ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventProviderImpl.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventProviderImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..cfe47c8bd0888db6d00867acfefc8db42ef314aa +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventProviderImpl.java +@@ -0,0 +1,30 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.event.type.RegistryEntryAddEventType; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; ++import org.jetbrains.annotations.ApiStatus; ++ ++@ApiStatus.Internal ++@DefaultQualifier(NonNull.class) ++record RegistryEventProviderImpl>(RegistryKey registryKey) implements RegistryEventProvider { ++ ++ static > RegistryEventProvider create(final RegistryKey registryKey) { ++ return new RegistryEventProviderImpl<>(registryKey); ++ } ++ ++ @Override ++ public RegistryEntryAddEventType entryAdd() { ++ return RegistryEventTypeProvider.provider().registryEntryAdd(this); ++ } ++ ++ @Override ++ public LifecycleEventType.Prioritizable> freeze() { ++ return RegistryEventTypeProvider.provider().registryFreeze(this); ++ } ++ ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProvider.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProvider.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d807bd2f42c98e37a96cf110ad77820dfffc8398 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProvider.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.event.type.RegistryEntryAddEventType; ++import java.util.Optional; ++import java.util.ServiceLoader; ++import org.jetbrains.annotations.ApiStatus; ++ ++@ApiStatus.Internal ++interface RegistryEventTypeProvider { ++ ++ Optional PROVIDER = ServiceLoader.load(RegistryEventTypeProvider.class) ++ .findFirst(); ++ ++ static RegistryEventTypeProvider provider() { ++ return PROVIDER.orElseThrow(() -> new IllegalStateException("Could not find a %s service implementation".formatted(RegistryEventTypeProvider.class.getSimpleName()))); ++ } ++ ++ > RegistryEntryAddEventType registryEntryAdd(RegistryEventProvider type); ++ ++ > LifecycleEventType.Prioritizable> registryFreeze(RegistryEventProvider type); ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java b/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1f89945be2ed68f52a544f41f7a151b8fdfe113e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java +@@ -0,0 +1,14 @@ ++package io.papermc.paper.registry.event; ++ ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * Holds providers for {@link RegistryEntryAddEvent} and {@link RegistryFreezeEvent} ++ * handlers for each applicable registry. ++ */ ++@ApiStatus.Experimental ++public final class RegistryEvents { ++ ++ private RegistryEvents() { ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEvent.java b/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEvent.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3a127b534dc37452b15c5fc5f922f8b6310b3ec0 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEvent.java +@@ -0,0 +1,25 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.registry.RegistryBuilder; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * Event object for {@link RegistryEventProvider#freeze()}. This ++ * event is fired right before a registry is frozen disallowing further changes. ++ * It provides a way for plugins to add new objects to the registry. ++ * ++ * @param registry entry type ++ * @param registry entry builder type ++ */ ++@ApiStatus.Experimental ++@ApiStatus.NonExtendable ++public interface RegistryFreezeEvent> extends RegistryEvent { ++ ++ /** ++ * Get the writable registry. ++ * ++ * @return a writable registry ++ */ ++ @NonNull WritableRegistry registry(); ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/WritableRegistry.java b/src/main/java/io/papermc/paper/registry/event/WritableRegistry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6de377275097f065c38dd59c6db9704018ac81fc +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/WritableRegistry.java +@@ -0,0 +1,27 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.TypedKey; ++import java.util.function.Consumer; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * A registry which supports registering new objects. ++ * ++ * @param registry entry type ++ * @param registry entry builder type ++ */ ++@ApiStatus.NonExtendable ++@ApiStatus.Experimental ++public interface WritableRegistry> { ++ ++ /** ++ * Register a new value with the specified key. This will ++ * fire a {@link RegistryEntryAddEvent} for the new entry. ++ * ++ * @param key the entry's key (must be unique from others) ++ * @param value a consumer for the entry's builder ++ */ ++ void register(@NonNull TypedKey key, @NonNull Consumer value); ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddConfiguration.java b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddConfiguration.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ad54c48ff2de18fe135c29102655f39c84063792 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddConfiguration.java +@@ -0,0 +1,30 @@ ++package io.papermc.paper.registry.event.type; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfiguration; ++import io.papermc.paper.registry.TypedKey; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.jetbrains.annotations.Contract; ++ ++/** ++ * Specific configuration for {@link io.papermc.paper.registry.event.RegistryEntryAddEvent}s. ++ * ++ * @param registry entry type ++ */ ++public interface RegistryEntryAddConfiguration extends PrioritizedLifecycleEventHandlerConfiguration { ++ ++ /** ++ * Only call the handler if the value being added matches the specified key. ++ * ++ * @param key the key to match ++ * @return this configuration ++ */ ++ @Contract(value = "_ -> this", mutates = "this") ++ @NonNull RegistryEntryAddConfiguration onlyFor(@NonNull TypedKey key); ++ ++ @Override ++ @NonNull RegistryEntryAddConfiguration priority(int priority); ++ ++ @Override ++ @NonNull RegistryEntryAddConfiguration monitor(); ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddEventType.java b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddEventType.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f4d4ebf6cbed1b4a9955ceb2d0586782181d97e5 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddEventType.java +@@ -0,0 +1,18 @@ ++package io.papermc.paper.registry.event.type; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.event.RegistryEntryAddEvent; ++import org.jetbrains.annotations.ApiStatus; ++ ++/** ++ * Lifecycle event type for {@link RegistryEntryAddEvent}s. ++ * ++ * @param registry entry type ++ * @param registry entry builder type ++ */ ++@ApiStatus.Experimental ++@ApiStatus.NonExtendable ++public interface RegistryEntryAddEventType> extends LifecycleEventType, RegistryEntryAddConfiguration> { ++} +diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java +index 802511eaf697d703cadb4b418fe51ea6d31ff3c8..85c4f231dc343c73f1678819f1ac95d5a7ffd080 100644 +--- a/src/main/java/org/bukkit/Registry.java ++++ b/src/main/java/org/bukkit/Registry.java +@@ -353,6 +353,27 @@ public interface Registry extends Iterable { + */ + @Nullable + T get(@NotNull NamespacedKey key); ++ // Paper start ++ /** ++ * Get the object by its key. ++ * ++ * @param key non-null key ++ * @return item or null if it does not exist ++ */ ++ default @Nullable T get(final net.kyori.adventure.key.@NotNull Key key) { ++ return key instanceof final NamespacedKey nsKey ? this.get(nsKey) : this.get(new NamespacedKey(key.namespace(), key.value())); ++ } ++ ++ /** ++ * Get the object by its typed key. ++ * ++ * @param typedKey non-null typed key ++ * @return item or null if it does not exist ++ */ ++ default @Nullable T get(final io.papermc.paper.registry.@NotNull TypedKey typedKey) { ++ return this.get(typedKey.key()); ++ } ++ // Paper end + + // Paper start - improve Registry + /** diff --git a/patches/api/0484-Registry-Modification-API.patch b/patches/api/0484-Registry-Modification-API.patch deleted file mode 100644 index ca3b8fdd86..0000000000 --- a/patches/api/0484-Registry-Modification-API.patch +++ /dev/null @@ -1,399 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Wed, 2 Mar 2022 13:36:21 -0800 -Subject: [PATCH] Registry Modification API - - -diff --git a/src/main/java/io/papermc/paper/registry/RegistryBuilder.java b/src/main/java/io/papermc/paper/registry/RegistryBuilder.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6edf300c1d81c1001756141c9efd022ba0e372cd ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/RegistryBuilder.java -@@ -0,0 +1,13 @@ -+package io.papermc.paper.registry; -+ -+import org.jetbrains.annotations.ApiStatus; -+ -+/** -+ * To be implemented by any type used for modifying registries. -+ * -+ * @param registry value type -+ */ -+@ApiStatus.NonExtendable -+@ApiStatus.Experimental -+public interface RegistryBuilder { -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEvent.java b/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d6722f7b55e260bab4bab5c361f9c0e9888c6752 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEvent.java -@@ -0,0 +1,33 @@ -+package io.papermc.paper.registry.event; -+ -+import io.papermc.paper.registry.RegistryBuilder; -+import io.papermc.paper.registry.TypedKey; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.jetbrains.annotations.ApiStatus; -+ -+/** -+ * Event object for {@link RegistryEventProvider#entryAdd()}. This -+ * event is fired right before a specific entry is registered in/added to registry. -+ * It provides a way for plugins to modify parts of this entry. -+ * -+ * @param registry entry type -+ * @param registry entry builder type -+ */ -+@ApiStatus.Experimental -+@ApiStatus.NonExtendable -+public interface RegistryEntryAddEvent> extends RegistryEvent { -+ -+ /** -+ * Gets the builder for the entry being added to the registry. -+ * -+ * @return the object builder -+ */ -+ @NonNull B builder(); -+ -+ /** -+ * Gets the key for this entry in the registry. -+ * -+ * @return the key -+ */ -+ @NonNull TypedKey key(); -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEvent.java b/src/main/java/io/papermc/paper/registry/event/RegistryEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..498c5920926158e86c2aec2bd2129d5e8b8613a3 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/RegistryEvent.java -@@ -0,0 +1,23 @@ -+package io.papermc.paper.registry.event; -+ -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; -+import io.papermc.paper.registry.RegistryKey; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.jetbrains.annotations.ApiStatus; -+ -+/** -+ * Base type for all registry events. -+ * -+ * @param registry entry type -+ */ -+@ApiStatus.Experimental -+@ApiStatus.NonExtendable -+public interface RegistryEvent extends LifecycleEvent { -+ -+ /** -+ * Get the key for the registry this event pertains to. -+ * -+ * @return the registry key -+ */ -+ @NonNull RegistryKey registryKey(); -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventProvider.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventProvider.java -new file mode 100644 -index 0000000000000000000000000000000000000000..477ed0fd5acc923d429980529876f0dd7dd3a52a ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventProvider.java -@@ -0,0 +1,58 @@ -+package io.papermc.paper.registry.event; -+ -+import io.papermc.paper.plugin.bootstrap.BootstrapContext; -+import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; -+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.LifecycleEventHandlerConfiguration; -+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfiguration; -+import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; -+import io.papermc.paper.registry.RegistryBuilder; -+import io.papermc.paper.registry.RegistryKey; -+import io.papermc.paper.registry.event.type.RegistryEntryAddEventType; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.jetbrains.annotations.ApiStatus; -+ -+/** -+ * Provider for registry events for a specific registry. -+ *

-+ * Supported events are: -+ *

    -+ *
  • {@link RegistryEntryAddEvent} (via {@link #entryAdd()})
  • -+ *
  • {@link RegistryFreezeEvent} (via {@link #freeze()})
  • -+ *
-+ * -+ * @param registry entry type -+ * @param registry entry builder type -+ */ -+@ApiStatus.Experimental -+@ApiStatus.NonExtendable -+public interface RegistryEventProvider> { -+ -+ /** -+ * Gets the event type for {@link RegistryEntryAddEvent} which is fired just before -+ * an object is added to a registry. -+ *

-+ * Can be used in {@link io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager#registerEventHandler(LifecycleEventType, LifecycleEventHandler)} -+ * to register a handler for {@link RegistryEntryAddEvent}. -+ * -+ * @return the registry entry add event type -+ */ -+ @NonNull RegistryEntryAddEventType entryAdd(); -+ -+ /** -+ * Gets the event type for {@link RegistryFreezeEvent} which is fired just before -+ * a registry is frozen. It allows for the registration of new objects. -+ *

-+ * Can be used in {@link io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager#registerEventHandler(LifecycleEventType, LifecycleEventHandler)} -+ * to register a handler for {@link RegistryFreezeEvent}. -+ * -+ * @return the registry freeze event type -+ */ -+ LifecycleEventType.@NonNull Prioritizable> freeze(); -+ -+ /** -+ * Gets the registry key associated with this event type provider. -+ * -+ * @return the registry key -+ */ -+ @NonNull RegistryKey registryKey(); -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventProviderImpl.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventProviderImpl.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cfe47c8bd0888db6d00867acfefc8db42ef314aa ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventProviderImpl.java -@@ -0,0 +1,30 @@ -+package io.papermc.paper.registry.event; -+ -+import io.papermc.paper.plugin.bootstrap.BootstrapContext; -+import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; -+import io.papermc.paper.registry.RegistryBuilder; -+import io.papermc.paper.registry.RegistryKey; -+import io.papermc.paper.registry.event.type.RegistryEntryAddEventType; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -+import org.jetbrains.annotations.ApiStatus; -+ -+@ApiStatus.Internal -+@DefaultQualifier(NonNull.class) -+record RegistryEventProviderImpl>(RegistryKey registryKey) implements RegistryEventProvider { -+ -+ static > RegistryEventProvider create(final RegistryKey registryKey) { -+ return new RegistryEventProviderImpl<>(registryKey); -+ } -+ -+ @Override -+ public RegistryEntryAddEventType entryAdd() { -+ return RegistryEventTypeProvider.provider().registryEntryAdd(this); -+ } -+ -+ @Override -+ public LifecycleEventType.Prioritizable> freeze() { -+ return RegistryEventTypeProvider.provider().registryFreeze(this); -+ } -+ -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProvider.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProvider.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d807bd2f42c98e37a96cf110ad77820dfffc8398 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProvider.java -@@ -0,0 +1,24 @@ -+package io.papermc.paper.registry.event; -+ -+import io.papermc.paper.plugin.bootstrap.BootstrapContext; -+import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; -+import io.papermc.paper.registry.RegistryBuilder; -+import io.papermc.paper.registry.event.type.RegistryEntryAddEventType; -+import java.util.Optional; -+import java.util.ServiceLoader; -+import org.jetbrains.annotations.ApiStatus; -+ -+@ApiStatus.Internal -+interface RegistryEventTypeProvider { -+ -+ Optional PROVIDER = ServiceLoader.load(RegistryEventTypeProvider.class) -+ .findFirst(); -+ -+ static RegistryEventTypeProvider provider() { -+ return PROVIDER.orElseThrow(() -> new IllegalStateException("Could not find a %s service implementation".formatted(RegistryEventTypeProvider.class.getSimpleName()))); -+ } -+ -+ > RegistryEntryAddEventType registryEntryAdd(RegistryEventProvider type); -+ -+ > LifecycleEventType.Prioritizable> registryFreeze(RegistryEventProvider type); -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java b/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1f89945be2ed68f52a544f41f7a151b8fdfe113e ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java -@@ -0,0 +1,14 @@ -+package io.papermc.paper.registry.event; -+ -+import org.jetbrains.annotations.ApiStatus; -+ -+/** -+ * Holds providers for {@link RegistryEntryAddEvent} and {@link RegistryFreezeEvent} -+ * handlers for each applicable registry. -+ */ -+@ApiStatus.Experimental -+public final class RegistryEvents { -+ -+ private RegistryEvents() { -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEvent.java b/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3a127b534dc37452b15c5fc5f922f8b6310b3ec0 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEvent.java -@@ -0,0 +1,25 @@ -+package io.papermc.paper.registry.event; -+ -+import io.papermc.paper.registry.RegistryBuilder; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.jetbrains.annotations.ApiStatus; -+ -+/** -+ * Event object for {@link RegistryEventProvider#freeze()}. This -+ * event is fired right before a registry is frozen disallowing further changes. -+ * It provides a way for plugins to add new objects to the registry. -+ * -+ * @param registry entry type -+ * @param registry entry builder type -+ */ -+@ApiStatus.Experimental -+@ApiStatus.NonExtendable -+public interface RegistryFreezeEvent> extends RegistryEvent { -+ -+ /** -+ * Get the writable registry. -+ * -+ * @return a writable registry -+ */ -+ @NonNull WritableRegistry registry(); -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/WritableRegistry.java b/src/main/java/io/papermc/paper/registry/event/WritableRegistry.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6de377275097f065c38dd59c6db9704018ac81fc ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/WritableRegistry.java -@@ -0,0 +1,27 @@ -+package io.papermc.paper.registry.event; -+ -+import io.papermc.paper.registry.RegistryBuilder; -+import io.papermc.paper.registry.TypedKey; -+import java.util.function.Consumer; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.jetbrains.annotations.ApiStatus; -+ -+/** -+ * A registry which supports registering new objects. -+ * -+ * @param registry entry type -+ * @param registry entry builder type -+ */ -+@ApiStatus.NonExtendable -+@ApiStatus.Experimental -+public interface WritableRegistry> { -+ -+ /** -+ * Register a new value with the specified key. This will -+ * fire a {@link RegistryEntryAddEvent} for the new entry. -+ * -+ * @param key the entry's key (must be unique from others) -+ * @param value a consumer for the entry's builder -+ */ -+ void register(@NonNull TypedKey key, @NonNull Consumer value); -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddConfiguration.java b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddConfiguration.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ad54c48ff2de18fe135c29102655f39c84063792 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddConfiguration.java -@@ -0,0 +1,30 @@ -+package io.papermc.paper.registry.event.type; -+ -+import io.papermc.paper.plugin.bootstrap.BootstrapContext; -+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfiguration; -+import io.papermc.paper.registry.TypedKey; -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.jetbrains.annotations.Contract; -+ -+/** -+ * Specific configuration for {@link io.papermc.paper.registry.event.RegistryEntryAddEvent}s. -+ * -+ * @param registry entry type -+ */ -+public interface RegistryEntryAddConfiguration extends PrioritizedLifecycleEventHandlerConfiguration { -+ -+ /** -+ * Only call the handler if the value being added matches the specified key. -+ * -+ * @param key the key to match -+ * @return this configuration -+ */ -+ @Contract(value = "_ -> this", mutates = "this") -+ @NonNull RegistryEntryAddConfiguration onlyFor(@NonNull TypedKey key); -+ -+ @Override -+ @NonNull RegistryEntryAddConfiguration priority(int priority); -+ -+ @Override -+ @NonNull RegistryEntryAddConfiguration monitor(); -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddEventType.java b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddEventType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f4d4ebf6cbed1b4a9955ceb2d0586782181d97e5 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddEventType.java -@@ -0,0 +1,18 @@ -+package io.papermc.paper.registry.event.type; -+ -+import io.papermc.paper.plugin.bootstrap.BootstrapContext; -+import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; -+import io.papermc.paper.registry.RegistryBuilder; -+import io.papermc.paper.registry.event.RegistryEntryAddEvent; -+import org.jetbrains.annotations.ApiStatus; -+ -+/** -+ * Lifecycle event type for {@link RegistryEntryAddEvent}s. -+ * -+ * @param registry entry type -+ * @param registry entry builder type -+ */ -+@ApiStatus.Experimental -+@ApiStatus.NonExtendable -+public interface RegistryEntryAddEventType> extends LifecycleEventType, RegistryEntryAddConfiguration> { -+} -diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java -index 73edd472b62441670653eb7e3c90aa9667792df7..1fe814a1a8f318f922c0047c7b9bfa9abd724146 100644 ---- a/src/main/java/org/bukkit/Registry.java -+++ b/src/main/java/org/bukkit/Registry.java -@@ -353,6 +353,27 @@ public interface Registry extends Iterable { - */ - @Nullable - T get(@NotNull NamespacedKey key); -+ // Paper start -+ /** -+ * Get the object by its key. -+ * -+ * @param key non-null key -+ * @return item or null if it does not exist -+ */ -+ default @Nullable T get(final net.kyori.adventure.key.@NotNull Key key) { -+ return key instanceof final NamespacedKey nsKey ? this.get(nsKey) : this.get(new NamespacedKey(key.namespace(), key.value())); -+ } -+ -+ /** -+ * Get the object by its typed key. -+ * -+ * @param typedKey non-null typed key -+ * @return item or null if it does not exist -+ */ -+ default @Nullable T get(final io.papermc.paper.registry.@NotNull TypedKey typedKey) { -+ return this.get(typedKey.key()); -+ } -+ // Paper end - - // Paper start - improve Registry - /** diff --git a/patches/server/0237-Optimize-MappedRegistry.patch b/patches/server/0237-Optimize-MappedRegistry.patch index 8f45008c5f..17c68f31d7 100644 --- a/patches/server/0237-Optimize-MappedRegistry.patch +++ b/patches/server/0237-Optimize-MappedRegistry.patch @@ -8,7 +8,7 @@ Use larger initial sizes to increase bucket capacity on the BiMap BiMap.get was seen to be using a good bit of CPU time. diff --git a/src/main/java/net/minecraft/core/MappedRegistry.java b/src/main/java/net/minecraft/core/MappedRegistry.java -index 362e49f503f3c792fbecf41ec9f235bbc02644de..6e4d5c168acdb9aaa9fbbee090082e4dc25e89e9 100644 +index 1dcbde18bd9c462cca48887b904a9c43261e1854..edbbafd1705345282e5e6251eb71bfde5793b7d4 100644 --- a/src/main/java/net/minecraft/core/MappedRegistry.java +++ b/src/main/java/net/minecraft/core/MappedRegistry.java @@ -35,11 +35,11 @@ public class MappedRegistry implements WritableRegistry { diff --git a/patches/server/0475-Add-RegistryAccess-for-managing-Registries.patch b/patches/server/0475-Add-RegistryAccess-for-managing-Registries.patch index 65a892ede4..4f2b6f6c28 100644 --- a/patches/server/0475-Add-RegistryAccess-for-managing-Registries.patch +++ b/patches/server/0475-Add-RegistryAccess-for-managing-Registries.patch @@ -12,7 +12,7 @@ public net.minecraft.server.RegistryLayer STATIC_ACCESS diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java new file mode 100644 -index 0000000000000000000000000000000000000000..55feffc03d2924e5ec0f55fc65e8aa148cb0cc62 +index 0000000000000000000000000000000000000000..40ac461d2f1906059377c77229612f540e827d75 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java @@ -0,0 +1,122 @@ @@ -897,7 +897,7 @@ index 0000000000000000000000000000000000000000..b9d00e65639521eecd44bd2be3e01226 + } +} diff --git a/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java b/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java -index e1c14886064cde56be7fcd8f22a6ecb2d222a762..f4da2afd8977030e3200ac5d4bf51b7206a90bd7 100644 +index e1c14886064cde56be7fcd8f22a6ecb2d222a762..69cece1537bb558b80e1947fdb1fe25555e82628 100644 --- a/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java +++ b/src/test/java/io/papermc/paper/registry/RegistryKeyTest.java @@ -1,15 +1,19 @@ diff --git a/patches/server/0975-Brigadier-based-command-API.patch b/patches/server/0975-Brigadier-based-command-API.patch index e551e947aa..357047a96b 100644 --- a/patches/server/0975-Brigadier-based-command-API.patch +++ b/patches/server/0975-Brigadier-based-command-API.patch @@ -1982,7 +1982,7 @@ index 0000000000000000000000000000000000000000..0c3c82b28e581286b798ee58ca4193ef + +} diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventRunner.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventRunner.java -index f84c9c80e701231e5c33ac3c5573f1093e80f38b..6c072e44a8144de6658b4eb818c996f0eac5805b 100644 +index 65c106fbc9ab990ed53cc5f789582c8cccc1a218..618e9c5e48062840e623cccc7ace4e5c3c118e78 100644 --- a/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventRunner.java +++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventRunner.java @@ -9,6 +9,7 @@ import io.papermc.paper.plugin.lifecycle.event.registrar.RegistrarEventImpl; diff --git a/patches/server/0991-Registry-Modification-API.patch b/patches/server/0991-Registry-Modification-API.patch new file mode 100644 index 0000000000..c770d38c3a --- /dev/null +++ b/patches/server/0991-Registry-Modification-API.patch @@ -0,0 +1,864 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 27 Feb 2023 18:28:39 -0800 +Subject: [PATCH] Registry Modification API + +== AT == +public net.minecraft.core.MappedRegistry validateWrite(Lnet/minecraft/resources/ResourceKey;)V + +diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java +index 40ac461d2f1906059377c77229612f540e827d75..7a2fb53ab280893b1c9c886ccb3480b695343cbf 100644 +--- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java +@@ -44,6 +44,7 @@ import org.checkerframework.framework.qual.DefaultQualifier; + + import static io.papermc.paper.registry.entry.RegistryEntry.apiOnly; + import static io.papermc.paper.registry.entry.RegistryEntry.entry; ++import static io.papermc.paper.registry.entry.RegistryEntry.writable; + + @DefaultQualifier(NonNull.class) + public final class PaperRegistries { +diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java +index d591e3a2e19d5358a0d25a5a681368943622d231..f05ebf453406a924da3de6fb250f4793a1b3c612 100644 +--- a/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java +@@ -80,6 +80,14 @@ public class PaperRegistryAccess implements RegistryAccess { + return possiblyUnwrap(registryHolder.get()); + } + ++ public > WritableCraftRegistry getWritableRegistry(final RegistryKey key) { ++ final Registry registry = this.getRegistry(key); ++ if (registry instanceof WritableCraftRegistry) { ++ return (WritableCraftRegistry) registry; ++ } ++ throw new IllegalArgumentException(key + " does not point to a writable registry"); ++ } ++ + private static Registry possiblyUnwrap(final Registry registry) { + if (registry instanceof final DelayedRegistry delayedRegistry) { // if not coming from legacy, unwrap the delayed registry + return delayedRegistry.delegate(); +diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryBuilder.java b/src/main/java/io/papermc/paper/registry/PaperRegistryBuilder.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4cf32102a134ebef67d3893cfd24bf0add321eb9 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistryBuilder.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper.registry; ++ ++import org.checkerframework.checker.nullness.qual.Nullable; ++ ++public interface PaperRegistryBuilder extends RegistryBuilder { ++ ++ M build(); ++ ++ @FunctionalInterface ++ interface Filler> { ++ ++ B fill(final TypedKey key, final @Nullable M nms); ++ ++ default Factory asFactory() { ++ return key -> this.fill(key, null); ++ } ++ } ++ ++ @FunctionalInterface ++ interface Factory> { ++ ++ B create(final TypedKey key); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryListenerManager.java b/src/main/java/io/papermc/paper/registry/PaperRegistryListenerManager.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e2605a9324b9dc91cd910e4bb974d5a911b58b1f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/PaperRegistryListenerManager.java +@@ -0,0 +1,167 @@ ++package io.papermc.paper.registry; ++ ++import com.google.common.base.Preconditions; ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.entrypoint.Entrypoint; ++import io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner; ++import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; ++import io.papermc.paper.registry.entry.RegistryEntry; ++import io.papermc.paper.registry.entry.RegistryEntryInfo; ++import io.papermc.paper.registry.event.RegistryEntryAddEventImpl; ++import io.papermc.paper.registry.event.RegistryEventMap; ++import io.papermc.paper.registry.event.RegistryEventProvider; ++import io.papermc.paper.registry.event.RegistryFreezeEvent; ++import io.papermc.paper.registry.event.RegistryFreezeEventImpl; ++import io.papermc.paper.registry.event.type.RegistryEntryAddEventType; ++import io.papermc.paper.registry.event.type.RegistryEntryAddEventTypeImpl; ++import io.papermc.paper.registry.event.type.RegistryLifecycleEventType; ++import net.kyori.adventure.key.Key; ++import net.minecraft.core.Holder; ++import net.minecraft.core.MappedRegistry; ++import net.minecraft.core.RegistrationInfo; ++import net.minecraft.core.Registry; ++import net.minecraft.core.WritableRegistry; ++import net.minecraft.resources.ResourceKey; ++import net.minecraft.resources.ResourceLocation; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.intellij.lang.annotations.Subst; ++ ++public final class PaperRegistryListenerManager { ++ ++ public static final PaperRegistryListenerManager INSTANCE = new PaperRegistryListenerManager(); ++ ++ public final RegistryEventMap valueAddHooks = new RegistryEventMap("value add"); ++ public final RegistryEventMap freezeHooks = new RegistryEventMap("freeze"); ++ ++ private PaperRegistryListenerManager() { ++ } ++ ++ /** ++ * For {@link Registry#register(Registry, String, Object)} ++ */ ++ public M registerWithListeners(final Registry registry, final String id, final M nms) { ++ return this.registerWithListeners(registry, ResourceLocation.withDefaultNamespace(id), nms); ++ } ++ ++ /** ++ * For {@link Registry#register(Registry, ResourceLocation, Object)} ++ */ ++ public M registerWithListeners(final Registry registry, final ResourceLocation loc, final M nms) { ++ return this.registerWithListeners(registry, ResourceKey.create(registry.key(), loc), nms); ++ } ++ ++ /** ++ * For {@link Registry#register(Registry, ResourceKey, Object)} ++ */ ++ public M registerWithListeners(final Registry registry, final ResourceKey key, final M nms) { ++ return this.registerWithListeners(registry, key, nms, RegistrationInfo.BUILT_IN, PaperRegistryListenerManager::registerWithInstance); ++ } ++ ++ /** ++ * For {@link Registry#registerForHolder(Registry, ResourceLocation, Object)} ++ */ ++ public Holder.Reference registerForHolderWithListeners(final Registry registry, final ResourceLocation loc, final M nms) { ++ return this.registerForHolderWithListeners(registry, ResourceKey.create(registry.key(), loc), nms); ++ } ++ ++ /** ++ * For {@link Registry#registerForHolder(Registry, ResourceKey, Object)} ++ */ ++ public Holder.Reference registerForHolderWithListeners(final Registry registry, final ResourceKey key, final M nms) { ++ return this.registerWithListeners(registry, key, nms, RegistrationInfo.BUILT_IN, WritableRegistry::register); ++ } ++ ++ public > void registerWithListeners( ++ final Registry registry, ++ final ResourceKey key, ++ final M nms, ++ final RegistrationInfo registrationInfo ++ ) { ++ this.registerWithListeners(registry, key, nms, registrationInfo, WritableRegistry::register); ++ } ++ ++ public , R> R registerWithListeners( ++ final Registry registry, ++ final ResourceKey key, ++ final M nms, ++ final RegistrationInfo registrationInfo, ++ final RegisterMethod registerMethod ++ ) { ++ Preconditions.checkState(LaunchEntryPointHandler.INSTANCE.hasEntered(Entrypoint.BOOTSTRAPPER), registry.key() + " tried to run modification listeners before bootstrappers have been called"); // verify that bootstrappers have been called ++ final @Nullable RegistryEntryInfo entry = PaperRegistries.getEntry(registry.key()); ++ if (!(entry instanceof RegistryEntry.Modifiable) || !this.valueAddHooks.hasHooks(entry.apiKey())) { ++ return registerMethod.register((WritableRegistry) registry, key, nms, registrationInfo); ++ } ++ final RegistryEntry.Modifiable modifiableEntry = (RegistryEntry.Modifiable) entry; ++ @SuppressWarnings("PatternValidation") final TypedKey typedKey = TypedKey.create(entry.apiKey(), Key.key(key.location().getNamespace(), key.location().getPath())); ++ final B builder = modifiableEntry.fillBuilder(typedKey, nms); ++ return this.registerWithListeners(registry, modifiableEntry, key, nms, builder, registrationInfo, registerMethod); ++ } ++ ++ public > void registerWithListeners( ++ final Registry registry, ++ final RegistryEntry.Modifiable entry, ++ final ResourceKey key, ++ final @Nullable M oldNms, ++ final B builder, ++ final RegistrationInfo registrationInfo ++ ) { ++ this.registerWithListeners(registry, entry, key, oldNms, builder, registrationInfo, WritableRegistry::register); ++ } ++ ++ public , R> R registerWithListeners( ++ final Registry registry, ++ final RegistryEntry.Modifiable entry, ++ final ResourceKey key, ++ final @Nullable M oldNms, ++ final B builder, ++ final RegistrationInfo registrationInfo, ++ final RegisterMethod registerMethod ++ ) { ++ @Subst("namespace:key") final ResourceLocation beingAdded = key.location(); ++ @SuppressWarnings("PatternValidation") final TypedKey typedKey = TypedKey.create(entry.apiKey(), Key.key(beingAdded.getNamespace(), beingAdded.getPath())); ++ final RegistryEntryAddEventImpl event = entry.createEntryAddEvent(typedKey, builder); ++ LifecycleEventRunner.INSTANCE.callEvent(this.valueAddHooks.getHook(entry.apiKey()), event); ++ if (oldNms != null) { ++ ((MappedRegistry) registry).clearIntrusiveHolder(oldNms); ++ } ++ final M newNms = event.builder().build(); ++ return registerMethod.register((WritableRegistry) registry, key, newNms, registrationInfo); ++ } ++ ++ private static M registerWithInstance(final WritableRegistry writableRegistry, final ResourceKey key, final M value, final RegistrationInfo registrationInfo) { ++ writableRegistry.register(key, value, registrationInfo); ++ return value; ++ } ++ ++ @FunctionalInterface ++ public interface RegisterMethod { ++ ++ R register(WritableRegistry writableRegistry, ResourceKey key, M value, RegistrationInfo registrationInfo); ++ } ++ ++ public > void runFreezeListeners(final ResourceKey> resourceKey) { ++ final @Nullable RegistryEntryInfo entry = PaperRegistries.getEntry(resourceKey); ++ if (!(entry instanceof RegistryEntry.Writable) || !this.freezeHooks.hasHooks(entry.apiKey())) { ++ return; ++ } ++ final RegistryEntry.Writable writableEntry = (RegistryEntry.Writable) entry; ++ final RegistryFreezeEventImpl event = writableEntry.createFreezeEvent(PaperRegistryAccess.instance().getWritableRegistry(entry.apiKey())); ++ LifecycleEventRunner.INSTANCE.callEvent(this.freezeHooks.getHook(entry.apiKey()), event); ++ } ++ ++ public > RegistryEntryAddEventType getRegistryValueAddEventType(final RegistryEventProvider type) { ++ if (!(PaperRegistries.getEntry(type.registryKey()) instanceof RegistryEntry.Modifiable)) { ++ throw new IllegalArgumentException(type.registryKey() + " does not support RegistryAdditionEvent"); ++ } ++ return this.valueAddHooks.getOrCreate(type, RegistryEntryAddEventTypeImpl::new); ++ } ++ ++ public > LifecycleEventType.Prioritizable> getRegistryFreezeEventType(final RegistryEventProvider type) { ++ if (!(PaperRegistries.getEntry(type.registryKey()) instanceof RegistryEntry.Writable)) { ++ throw new IllegalArgumentException(type.registryKey() + " does not support RegistryPreFreezeEvent"); ++ } ++ return this.freezeHooks.getOrCreate(type, RegistryLifecycleEventType::new); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java b/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..aff4895d5add72e22ae9f723b77843435ff044aa +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java +@@ -0,0 +1,85 @@ ++package io.papermc.paper.registry; ++ ++import com.mojang.serialization.Lifecycle; ++import io.papermc.paper.adventure.PaperAdventure; ++import io.papermc.paper.registry.entry.RegistryEntry; ++import io.papermc.paper.registry.event.WritableRegistry; ++import java.util.Optional; ++import java.util.function.BiFunction; ++import java.util.function.Consumer; ++import net.minecraft.core.MappedRegistry; ++import net.minecraft.core.RegistrationInfo; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.craftbukkit.CraftRegistry; ++import org.bukkit.craftbukkit.util.ApiVersion; ++import org.checkerframework.checker.nullness.qual.Nullable; ++ ++public class WritableCraftRegistry> extends CraftRegistry { ++ ++ private static final RegistrationInfo FROM_PLUGIN = new RegistrationInfo(Optional.empty(), Lifecycle.experimental()); ++ ++ private final RegistryEntry.BuilderHolder entry; ++ private final MappedRegistry registry; ++ public final WritableRegistry apiWritableRegistry = new ApiWritableRegistry(); ++ private final PaperRegistryBuilder.Factory builderFactory; ++ private final BiFunction minecraftToBukkit; ++ ++ public WritableCraftRegistry( ++ final RegistryEntry.BuilderHolder entry, ++ final Class classToPreload, ++ final MappedRegistry registry, ++ final BiFunction serializationUpdater, ++ final PaperRegistryBuilder.Factory builderFactory, ++ final BiFunction minecraftToBukkit ++ ) { ++ super(classToPreload, registry, null, serializationUpdater); ++ this.entry = entry; ++ this.registry = registry; ++ this.builderFactory = builderFactory; ++ this.minecraftToBukkit = minecraftToBukkit; ++ } ++ ++ public void register(final TypedKey key, final Consumer value) { ++ final ResourceKey resourceKey = ResourceKey.create(this.registry.key(), PaperAdventure.asVanilla(key.key())); ++ this.registry.validateWrite(resourceKey); ++ final B builder = this.newBuilder(key); ++ value.accept(builder); ++ if (this.entry instanceof final RegistryEntry.Modifiable modifiable && PaperRegistryListenerManager.INSTANCE.valueAddHooks.hasHooks(this.entry.apiKey())) { ++ PaperRegistryListenerManager.INSTANCE.registerWithListeners( ++ this.registry, ++ modifiable, ++ resourceKey, ++ null, ++ builder, ++ FROM_PLUGIN ++ ); ++ } else { ++ this.registry.register(resourceKey, builder.build(), FROM_PLUGIN); ++ } ++ } ++ ++ @Override ++ public final @Nullable T createBukkit(final NamespacedKey namespacedKey, final @Nullable M minecraft) { ++ if (minecraft == null) { ++ return null; ++ } ++ return this.minecraftToBukkit(namespacedKey, minecraft); ++ } ++ ++ public T minecraftToBukkit(final NamespacedKey namespacedKey, final M minecraft) { ++ return this.minecraftToBukkit.apply(namespacedKey, minecraft); ++ } ++ ++ protected B newBuilder(final TypedKey key) { ++ return this.builderFactory.create(key); ++ } ++ ++ public class ApiWritableRegistry implements WritableRegistry { ++ @Override ++ public void register(final TypedKey key, final Consumer value) { ++ WritableCraftRegistry.this.register(key, value); ++ } ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/AddableRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/AddableRegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a0f24d396e3a258be1978b2baa3f8e07ff54538f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/AddableRegistryEntry.java +@@ -0,0 +1,43 @@ ++package io.papermc.paper.registry.entry; ++ ++import io.papermc.paper.registry.PaperRegistryBuilder; ++import io.papermc.paper.registry.RegistryHolder; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.TypedKey; ++import io.papermc.paper.registry.WritableCraftRegistry; ++import java.util.function.BiFunction; ++import net.minecraft.core.MappedRegistry; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++ ++public class AddableRegistryEntry> extends CraftRegistryEntry implements RegistryEntry.Addable { ++ ++ private final PaperRegistryBuilder.Filler builderFiller; ++ ++ protected AddableRegistryEntry( ++ final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Class classToPreload, ++ final BiFunction minecraftToBukkit, ++ final PaperRegistryBuilder.Filler builderFiller ++ ) { ++ super(mcKey, apiKey, classToPreload, minecraftToBukkit); ++ this.builderFiller = builderFiller; ++ } ++ ++ private WritableCraftRegistry createRegistry(final Registry registry) { ++ return new WritableCraftRegistry<>(this, this.classToPreload, (MappedRegistry) registry, this.updater, this.builderFiller.asFactory(), this.minecraftToBukkit); ++ } ++ ++ @Override ++ public RegistryHolder createRegistryHolder(final Registry nmsRegistry) { ++ return new RegistryHolder.Memoized<>(() -> this.createRegistry(nmsRegistry)); ++ } ++ ++ @Override ++ public B fillBuilder(final TypedKey key, final M nms) { ++ return this.builderFiller.fill(key, nms); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/ModifiableRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/ModifiableRegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..df10008f6bde1047c8a13523c0a8fc01222a4e62 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/ModifiableRegistryEntry.java +@@ -0,0 +1,31 @@ ++package io.papermc.paper.registry.entry; ++ ++import io.papermc.paper.registry.PaperRegistryBuilder; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.TypedKey; ++import java.util.function.BiFunction; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++ ++public class ModifiableRegistryEntry> extends CraftRegistryEntry implements RegistryEntry.Modifiable { ++ ++ protected final PaperRegistryBuilder.Filler builderFiller; ++ ++ protected ModifiableRegistryEntry( ++ final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Class toPreload, ++ final BiFunction minecraftToBukkit, ++ final PaperRegistryBuilder.Filler builderFiller ++ ) { ++ super(mcKey, apiKey, toPreload, minecraftToBukkit); ++ this.builderFiller = builderFiller; ++ } ++ ++ @Override ++ public B fillBuilder(final TypedKey key, final M nms) { ++ return this.builderFiller.fill(key, nms); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java +index 15991bf13894d850f360a520d1815711d25973ec..c49170d469dca809dc42421168d14e57e24d734b 100644 +--- a/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java ++++ b/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java +@@ -1,7 +1,12 @@ + package io.papermc.paper.registry.entry; + ++import io.papermc.paper.registry.PaperRegistryBuilder; + import io.papermc.paper.registry.RegistryHolder; + import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.TypedKey; ++import io.papermc.paper.registry.WritableCraftRegistry; ++import io.papermc.paper.registry.event.RegistryEntryAddEventImpl; ++import io.papermc.paper.registry.event.RegistryFreezeEventImpl; + import io.papermc.paper.registry.legacy.DelayedRegistryEntry; + import java.util.function.BiFunction; + import java.util.function.Supplier; +@@ -32,6 +37,37 @@ public interface RegistryEntry extends RegistryEntryInfo(this); + } + ++ interface BuilderHolder> extends RegistryEntryInfo { ++ ++ B fillBuilder(TypedKey key, M nms); ++ } ++ ++ /** ++ * Can mutate values being added to the registry ++ */ ++ interface Modifiable> extends BuilderHolder { ++ ++ default RegistryEntryAddEventImpl createEntryAddEvent(final TypedKey key, final B initialBuilder) { ++ return new RegistryEntryAddEventImpl<>(key, initialBuilder, this.apiKey()); ++ } ++ } ++ ++ /** ++ * Can only add new values to the registry, not modify any values. ++ */ ++ interface Addable> extends BuilderHolder { // TODO remove Keyed ++ ++ default RegistryFreezeEventImpl createFreezeEvent(final WritableCraftRegistry writableRegistry) { ++ return new RegistryFreezeEventImpl<>(this.apiKey(), writableRegistry.apiWritableRegistry); ++ } ++ } ++ ++ /** ++ * Can mutate values and add new values. ++ */ ++ interface Writable> extends Modifiable, Addable { // TODO remove Keyed ++ } ++ + static RegistryEntry entry( + final ResourceKey> mcKey, + final RegistryKey apiKey, +@@ -48,4 +84,24 @@ public interface RegistryEntry extends RegistryEntryInfo(mcKey, apiKey, apiRegistrySupplier); + } ++ ++ static > RegistryEntry modifiable( ++ final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Class toPreload, ++ final BiFunction minecraftToBukkit, ++ final PaperRegistryBuilder.Filler filler ++ ) { ++ return new ModifiableRegistryEntry<>(mcKey, apiKey, toPreload, minecraftToBukkit, filler); ++ } ++ ++ static > RegistryEntry writable( ++ final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Class toPreload, ++ final BiFunction minecraftToBukkit, ++ final PaperRegistryBuilder.Filler filler ++ ) { ++ return new WritableRegistryEntry<>(mcKey, apiKey, toPreload, minecraftToBukkit, filler); ++ } + } +diff --git a/src/main/java/io/papermc/paper/registry/entry/WritableRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/WritableRegistryEntry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..562accce731630327d116afd1c9d559df7e386bd +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/entry/WritableRegistryEntry.java +@@ -0,0 +1,22 @@ ++package io.papermc.paper.registry.entry; ++ ++import io.papermc.paper.registry.PaperRegistryBuilder; ++import io.papermc.paper.registry.RegistryKey; ++import java.util.function.BiFunction; ++import net.minecraft.core.Registry; ++import net.minecraft.resources.ResourceKey; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++ ++public class WritableRegistryEntry> extends AddableRegistryEntry implements RegistryEntry.Writable { // TODO remove Keyed ++ ++ protected WritableRegistryEntry( ++ final ResourceKey> mcKey, ++ final RegistryKey apiKey, ++ final Class classToPreload, ++ final BiFunction minecraftToBukkit, ++ final PaperRegistryBuilder.Filler builderFiller ++ ) { ++ super(mcKey, apiKey, classToPreload, minecraftToBukkit, builderFiller); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEventImpl.java b/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEventImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a1d747c1a46d3aa8bcdef82bebb48f1fd760e61f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEventImpl.java +@@ -0,0 +1,13 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEvent; ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.RegistryKey; ++import io.papermc.paper.registry.TypedKey; ++ ++public record RegistryEntryAddEventImpl>( ++ TypedKey key, ++ B builder, ++ RegistryKey registryKey ++) implements RegistryEntryAddEvent, PaperLifecycleEvent { ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventMap.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventMap.java +new file mode 100644 +index 0000000000000000000000000000000000000000..f5ea23173dcbe491742c3dd051c147ef397307a0 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventMap.java +@@ -0,0 +1,44 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner; ++import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.RegistryKey; ++import java.util.HashMap; ++import java.util.Map; ++import java.util.Objects; ++import java.util.function.BiFunction; ++ ++public final class RegistryEventMap { ++ ++ private final Map, LifecycleEventType, ?>> hooks = new HashMap<>(); ++ private final String name; ++ ++ public RegistryEventMap(final String name) { ++ this.name = name; ++ } ++ ++ @SuppressWarnings("unchecked") ++ public , E extends RegistryEvent, ET extends LifecycleEventType> ET getOrCreate(final RegistryEventProvider type, final BiFunction, ? super String, ET> eventTypeCreator) { ++ final ET registerHook; ++ if (this.hooks.containsKey(type.registryKey())) { ++ registerHook = (ET) this.hooks.get(type.registryKey()); ++ } else { ++ registerHook = eventTypeCreator.apply(type, this.name); ++ LifecycleEventRunner.INSTANCE.addEventType(registerHook); ++ this.hooks.put(type.registryKey(), registerHook); ++ } ++ return registerHook; ++ } ++ ++ @SuppressWarnings("unchecked") ++ public > LifecycleEventType getHook(final RegistryKey registryKey) { ++ return (LifecycleEventType) Objects.requireNonNull(this.hooks.get(registryKey), "No hook for " + registryKey); ++ } ++ ++ public boolean hasHooks(final RegistryKey registryKey) { ++ return this.hooks.containsKey(registryKey); ++ } ++ ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProviderImpl.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProviderImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..34c842ffa355e3c8001dd7b8551bcb49229a6391 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProviderImpl.java +@@ -0,0 +1,24 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; ++import io.papermc.paper.registry.PaperRegistryListenerManager; ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.event.type.RegistryEntryAddEventType; ++ ++public class RegistryEventTypeProviderImpl implements RegistryEventTypeProvider { ++ ++ public static RegistryEventTypeProviderImpl instance() { ++ return (RegistryEventTypeProviderImpl) RegistryEventTypeProvider.provider(); ++ } ++ ++ @Override ++ public > RegistryEntryAddEventType registryEntryAdd(final RegistryEventProvider type) { ++ return PaperRegistryListenerManager.INSTANCE.getRegistryValueAddEventType(type); ++ } ++ ++ @Override ++ public > LifecycleEventType.Prioritizable> registryFreeze(final RegistryEventProvider type) { ++ return PaperRegistryListenerManager.INSTANCE.getRegistryFreezeEventType(type); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEventImpl.java b/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEventImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..2db5d33d0b72ec3c9ff1c3042d9246dfa4344346 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEventImpl.java +@@ -0,0 +1,11 @@ ++package io.papermc.paper.registry.event; ++ ++import io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEvent; ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.RegistryKey; ++ ++public record RegistryFreezeEventImpl>( ++ RegistryKey registryKey, ++ WritableRegistry registry ++) implements RegistryFreezeEvent, PaperLifecycleEvent { ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/package-info.java b/src/main/java/io/papermc/paper/registry/event/package-info.java +new file mode 100644 +index 0000000000000000000000000000000000000000..14d2d9766b8dee763f220c397aba3ad432d02aaa +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/package-info.java +@@ -0,0 +1,5 @@ ++@DefaultQualifier(NonNull.class) ++package io.papermc.paper.registry.event; ++ ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; +diff --git a/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddEventTypeImpl.java b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddEventTypeImpl.java +new file mode 100644 +index 0000000000000000000000000000000000000000..32303ea9b3da736cbe26d06e57f5dcc3aa32a99b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddEventTypeImpl.java +@@ -0,0 +1,32 @@ ++package io.papermc.paper.registry.event.type; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; ++import io.papermc.paper.plugin.lifecycle.event.types.PrioritizableLifecycleEventType; ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.event.RegistryEntryAddEvent; ++import io.papermc.paper.registry.event.RegistryEventProvider; ++import java.util.function.Consumer; ++import java.util.function.Predicate; ++ ++public class RegistryEntryAddEventTypeImpl> extends PrioritizableLifecycleEventType, RegistryEntryAddConfiguration> implements RegistryEntryAddEventType { ++ ++ public RegistryEntryAddEventTypeImpl(final RegistryEventProvider type, final String eventName) { ++ super(type.registryKey() + " / " + eventName, BootstrapContext.class); ++ } ++ ++ @Override ++ public RegistryEntryAddConfiguration newHandler(final LifecycleEventHandler> handler) { ++ return new RegistryEntryAddHandlerConfiguration<>(handler, this); ++ } ++ ++ @Override ++ public void forEachHandler(final RegistryEntryAddEvent event, final Consumer>> consumer, final Predicate>> predicate) { ++ super.forEachHandler(event, consumer, predicate.and(handler -> this.matchesTarget(event, handler))); ++ } ++ ++ private boolean matchesTarget(final RegistryEntryAddEvent event, final RegisteredHandler> handler) { ++ final RegistryEntryAddHandlerConfiguration config = (RegistryEntryAddHandlerConfiguration) handler.config(); ++ return config.target() == null || event.key().equals(config.target()); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddHandlerConfiguration.java b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddHandlerConfiguration.java +new file mode 100644 +index 0000000000000000000000000000000000000000..53df2dd1a9e1cef90bd8504c717b1cc6374b6f4e +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddHandlerConfiguration.java +@@ -0,0 +1,39 @@ ++package io.papermc.paper.registry.event.type; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; ++import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfigurationImpl; ++import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType; ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.TypedKey; ++import io.papermc.paper.registry.event.RegistryEntryAddEvent; ++import org.checkerframework.checker.nullness.qual.Nullable; ++ ++public class RegistryEntryAddHandlerConfiguration> extends PrioritizedLifecycleEventHandlerConfigurationImpl> implements RegistryEntryAddConfiguration { ++ ++ private @Nullable TypedKey target; ++ ++ public RegistryEntryAddHandlerConfiguration(final LifecycleEventHandler> handler, final AbstractLifecycleEventType, ?> eventType) { ++ super(handler, eventType); ++ } ++ ++ public @Nullable TypedKey target() { ++ return this.target; ++ } ++ ++ @Override ++ public RegistryEntryAddConfiguration onlyFor(final TypedKey key) { ++ this.target = key; ++ return this; ++ } ++ ++ @Override ++ public RegistryEntryAddConfiguration priority(final int priority) { ++ return (RegistryEntryAddConfiguration) super.priority(priority); ++ } ++ ++ @Override ++ public RegistryEntryAddConfiguration monitor() { ++ return (RegistryEntryAddConfiguration) super.monitor(); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/event/type/RegistryLifecycleEventType.java b/src/main/java/io/papermc/paper/registry/event/type/RegistryLifecycleEventType.java +new file mode 100644 +index 0000000000000000000000000000000000000000..dcc0f6b337840a78d38abdf2eb3f4bbd1676f58f +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/event/type/RegistryLifecycleEventType.java +@@ -0,0 +1,14 @@ ++package io.papermc.paper.registry.event.type; ++ ++import io.papermc.paper.plugin.bootstrap.BootstrapContext; ++import io.papermc.paper.plugin.lifecycle.event.types.PrioritizableLifecycleEventType; ++import io.papermc.paper.registry.RegistryBuilder; ++import io.papermc.paper.registry.event.RegistryEvent; ++import io.papermc.paper.registry.event.RegistryEventProvider; ++ ++public final class RegistryLifecycleEventType, E extends RegistryEvent> extends PrioritizableLifecycleEventType.Simple { ++ ++ public RegistryLifecycleEventType(final RegistryEventProvider type, final String eventName) { ++ super(type.registryKey() + " / " + eventName, BootstrapContext.class); ++ } ++} +diff --git a/src/main/java/io/papermc/paper/registry/package-info.java b/src/main/java/io/papermc/paper/registry/package-info.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0b80179ff90e085568d7ceafd9b17511789dc99b +--- /dev/null ++++ b/src/main/java/io/papermc/paper/registry/package-info.java +@@ -0,0 +1,5 @@ ++@DefaultQualifier(NonNull.class) ++package io.papermc.paper.registry; ++ ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.framework.qual.DefaultQualifier; +diff --git a/src/main/java/net/minecraft/core/MappedRegistry.java b/src/main/java/net/minecraft/core/MappedRegistry.java +index edbbafd1705345282e5e6251eb71bfde5793b7d4..f22d22ebcedcc9c20225677844c86a1ad27c4211 100644 +--- a/src/main/java/net/minecraft/core/MappedRegistry.java ++++ b/src/main/java/net/minecraft/core/MappedRegistry.java +@@ -441,4 +441,12 @@ public class MappedRegistry implements WritableRegistry { + public HolderLookup.RegistryLookup asLookup() { + return this.lookup; + } ++ // Paper start ++ // used to clear intrusive holders from GameEvent, Item, Block, EntityType, and Fluid from unused instances of those types ++ public void clearIntrusiveHolder(final T instance) { ++ if (this.unregisteredIntrusiveHolders != null) { ++ this.unregisteredIntrusiveHolders.remove(instance); ++ } ++ } ++ // Paper end + } +diff --git a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java +index 44b7927081b476813505cab6b3a2da2ec2942c54..c96bcd815ec9bf76625b5bedef461da49d7240ce 100644 +--- a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java ++++ b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java +@@ -328,6 +328,7 @@ public class BuiltInRegistries { + } + public static void bootStrap(Runnable runnable) { + // Paper end ++ REGISTRY.freeze(); // Paper - freeze main registry early + createContents(); + runnable.run(); // Paper + freeze(); +@@ -346,6 +347,7 @@ public class BuiltInRegistries { + REGISTRY.freeze(); + + for (Registry registry : REGISTRY) { ++ io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.runFreezeListeners(registry.key()); // Paper + registry.freeze(); + } + } +diff --git a/src/main/java/net/minecraft/resources/RegistryDataLoader.java b/src/main/java/net/minecraft/resources/RegistryDataLoader.java +index abadf4abe08dc3bb6612b42cbb3f7df3ffa28ce9..56d8dcf2f3fd042ed1e7ed01a0ce5d90c89ee502 100644 +--- a/src/main/java/net/minecraft/resources/RegistryDataLoader.java ++++ b/src/main/java/net/minecraft/resources/RegistryDataLoader.java +@@ -136,6 +136,7 @@ public class RegistryDataLoader { + list.forEach(loader -> loadable.apply((RegistryDataLoader.Loader)loader, registryInfoLookup)); + list.forEach(loader -> { + Registry registry = loader.registry(); ++ io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.runFreezeListeners(loader.registry.key()); // Paper - run pre-freeze listeners + + try { + registry.freeze(); +@@ -199,7 +200,7 @@ public class RegistryDataLoader { + JsonElement jsonElement = JsonParser.parseReader(reader); + DataResult dataResult = decoder.parse(ops, jsonElement); + E object = dataResult.getOrThrow(); +- registry.register(key, object, entryInfo); ++ io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerWithListeners(registry, key, object, entryInfo); // Paper - register with listeners + } + } + +diff --git a/src/main/java/net/minecraft/server/ReloadableServerRegistries.java b/src/main/java/net/minecraft/server/ReloadableServerRegistries.java +index 397bdacab9517354875ebc0bc68d35059b3c318b..705fe42b52414fbac14ec107fda5ad0989a5a115 100644 +--- a/src/main/java/net/minecraft/server/ReloadableServerRegistries.java ++++ b/src/main/java/net/minecraft/server/ReloadableServerRegistries.java +@@ -66,7 +66,7 @@ public class ReloadableServerRegistries { + SimpleJsonResourceReloadListener.scanDirectory(resourceManager, string, GSON, map); + map.forEach( + (id, json) -> type.deserialize(id, ops, json) +- .ifPresent(value -> writableRegistry.register(ResourceKey.create(type.registryKey(), id), (T)value, DEFAULT_REGISTRATION_INFO)) ++ .ifPresent(value -> io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerWithListeners(writableRegistry, ResourceKey.create(type.registryKey(), id), value, DEFAULT_REGISTRATION_INFO)) // Paper - register with listeners + ); + return writableRegistry; + }, +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +index d21b7e39d71c785f47f790e1ad4be33a8e8e6e51..43d686a9958cff96f5b15d93e920c8f2313aa65b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java +@@ -156,11 +156,11 @@ public class CraftRegistry implements Registry { + private final Map cache = new HashMap<>(); + private final Map byValue = new java.util.IdentityHashMap<>(); // Paper - improve Registry + private final net.minecraft.core.Registry minecraftRegistry; +- private final BiFunction minecraftToBukkit; ++ private final BiFunction minecraftToBukkit; // Paper + private final BiFunction serializationUpdater; // Paper - rename to make it *clear* what it is *only* for + private boolean init; + +- public CraftRegistry(Class bukkitClass, net.minecraft.core.Registry minecraftRegistry, BiFunction minecraftToBukkit, BiFunction serializationUpdater) { // Paper - relax preload class ++ public CraftRegistry(Class bukkitClass, net.minecraft.core.Registry minecraftRegistry, BiFunction minecraftToBukkit, BiFunction serializationUpdater) { // Paper - relax preload class + this.bukkitClass = bukkitClass; + this.minecraftRegistry = minecraftRegistry; + this.minecraftToBukkit = minecraftToBukkit; +diff --git a/src/main/resources/META-INF/services/io.papermc.paper.registry.event.RegistryEventTypeProvider b/src/main/resources/META-INF/services/io.papermc.paper.registry.event.RegistryEventTypeProvider +new file mode 100644 +index 0000000000000000000000000000000000000000..8bee1a5ed877a04e4d027593df1f42cefdd824e7 +--- /dev/null ++++ b/src/main/resources/META-INF/services/io.papermc.paper.registry.event.RegistryEventTypeProvider +@@ -0,0 +1 @@ ++io.papermc.paper.registry.event.RegistryEventTypeProviderImpl diff --git a/patches/server/1054-Registry-Modification-API.patch b/patches/server/1054-Registry-Modification-API.patch deleted file mode 100644 index 6c9b14be60..0000000000 --- a/patches/server/1054-Registry-Modification-API.patch +++ /dev/null @@ -1,852 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 27 Feb 2023 18:28:39 -0800 -Subject: [PATCH] Registry Modification API - -== AT == -public net.minecraft.server.RegistryLayer STATIC_ACCESS -public net.minecraft.core.MappedRegistry validateWrite(Lnet/minecraft/resources/ResourceKey;)V - -diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/src/main/java/io/papermc/paper/registry/PaperRegistries.java -index e68ac2a9710c9e0ac248ce65b6e0d21fa7033fec..9342f034ef590594db046cd9b0810bd4075d8e6b 100644 ---- a/src/main/java/io/papermc/paper/registry/PaperRegistries.java -+++ b/src/main/java/io/papermc/paper/registry/PaperRegistries.java -@@ -42,6 +42,7 @@ import org.checkerframework.framework.qual.DefaultQualifier; - - import static io.papermc.paper.registry.entry.RegistryEntry.apiOnly; - import static io.papermc.paper.registry.entry.RegistryEntry.entry; -+import static io.papermc.paper.registry.entry.RegistryEntry.writable; - - @DefaultQualifier(NonNull.class) - public final class PaperRegistries { -diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java -index c34cffd369ead2b3e43464a02d4f8fb98ca969c1..a70d1d8b2aef96c2dff7e20670afa8b82027ebf3 100644 ---- a/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java -+++ b/src/main/java/io/papermc/paper/registry/PaperRegistryAccess.java -@@ -85,6 +85,14 @@ public class PaperRegistryAccess implements RegistryAccess { - return possiblyUnwrap(registryHolder.get()); - } - -+ public > WritableCraftRegistry getWritableRegistry(final RegistryKey key) { -+ final Registry registry = this.getRegistry(key); -+ if (registry instanceof WritableCraftRegistry) { -+ return (WritableCraftRegistry) registry; -+ } -+ throw new IllegalArgumentException(key + " does not point to a writable registry"); -+ } -+ - private static Registry possiblyUnwrap(final Registry registry) { - if (registry instanceof final DelayedRegistry delayedRegistry) { // if not coming from legacy, unwrap the delayed registry - return delayedRegistry.delegate(); -diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryBuilder.java b/src/main/java/io/papermc/paper/registry/PaperRegistryBuilder.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4cf32102a134ebef67d3893cfd24bf0add321eb9 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/PaperRegistryBuilder.java -@@ -0,0 +1,24 @@ -+package io.papermc.paper.registry; -+ -+import org.checkerframework.checker.nullness.qual.Nullable; -+ -+public interface PaperRegistryBuilder extends RegistryBuilder { -+ -+ M build(); -+ -+ @FunctionalInterface -+ interface Filler> { -+ -+ B fill(final TypedKey key, final @Nullable M nms); -+ -+ default Factory asFactory() { -+ return key -> this.fill(key, null); -+ } -+ } -+ -+ @FunctionalInterface -+ interface Factory> { -+ -+ B create(final TypedKey key); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/PaperRegistryListenerManager.java b/src/main/java/io/papermc/paper/registry/PaperRegistryListenerManager.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6b3ba059b4f530b9e3d1c3d6bbc033e96c6a9bc2 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/PaperRegistryListenerManager.java -@@ -0,0 +1,167 @@ -+package io.papermc.paper.registry; -+ -+import com.google.common.base.Preconditions; -+import io.papermc.paper.plugin.bootstrap.BootstrapContext; -+import io.papermc.paper.plugin.entrypoint.Entrypoint; -+import io.papermc.paper.plugin.entrypoint.LaunchEntryPointHandler; -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner; -+import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; -+import io.papermc.paper.registry.entry.RegistryEntry; -+import io.papermc.paper.registry.entry.RegistryEntryInfo; -+import io.papermc.paper.registry.event.RegistryEntryAddEventImpl; -+import io.papermc.paper.registry.event.RegistryEventMap; -+import io.papermc.paper.registry.event.RegistryEventProvider; -+import io.papermc.paper.registry.event.RegistryFreezeEvent; -+import io.papermc.paper.registry.event.RegistryFreezeEventImpl; -+import io.papermc.paper.registry.event.type.RegistryEntryAddEventType; -+import io.papermc.paper.registry.event.type.RegistryEntryAddEventTypeImpl; -+import io.papermc.paper.registry.event.type.RegistryLifecycleEventType; -+import net.kyori.adventure.key.Key; -+import net.minecraft.core.Holder; -+import net.minecraft.core.MappedRegistry; -+import net.minecraft.core.RegistrationInfo; -+import net.minecraft.core.Registry; -+import net.minecraft.core.WritableRegistry; -+import net.minecraft.resources.ResourceKey; -+import net.minecraft.resources.ResourceLocation; -+import org.checkerframework.checker.nullness.qual.Nullable; -+import org.intellij.lang.annotations.Subst; -+ -+public final class PaperRegistryListenerManager { -+ -+ public static final PaperRegistryListenerManager INSTANCE = new PaperRegistryListenerManager(); -+ -+ public final RegistryEventMap valueAddHooks = new RegistryEventMap("value add"); -+ public final RegistryEventMap freezeHooks = new RegistryEventMap("freeze"); -+ -+ private PaperRegistryListenerManager() { -+ } -+ -+ /** -+ * For {@link Registry#register(Registry, String, Object)} -+ */ -+ public M registerWithListeners(final Registry registry, final String id, final M nms) { -+ return this.registerWithListeners(registry, new ResourceLocation(id), nms); -+ } -+ -+ /** -+ * For {@link Registry#register(Registry, ResourceLocation, Object)} -+ */ -+ public M registerWithListeners(final Registry registry, final ResourceLocation loc, final M nms) { -+ return this.registerWithListeners(registry, ResourceKey.create(registry.key(), loc), nms); -+ } -+ -+ /** -+ * For {@link Registry#register(Registry, ResourceKey, Object)} -+ */ -+ public M registerWithListeners(final Registry registry, final ResourceKey key, final M nms) { -+ return this.registerWithListeners(registry, key, nms, RegistrationInfo.BUILT_IN, PaperRegistryListenerManager::registerWithInstance); -+ } -+ -+ /** -+ * For {@link Registry#registerForHolder(Registry, ResourceLocation, Object)} -+ */ -+ public Holder.Reference registerForHolderWithListeners(final Registry registry, final ResourceLocation loc, final M nms) { -+ return this.registerForHolderWithListeners(registry, ResourceKey.create(registry.key(), loc), nms); -+ } -+ -+ /** -+ * For {@link Registry#registerForHolder(Registry, ResourceKey, Object)} -+ */ -+ public Holder.Reference registerForHolderWithListeners(final Registry registry, final ResourceKey key, final M nms) { -+ return this.registerWithListeners(registry, key, nms, RegistrationInfo.BUILT_IN, WritableRegistry::register); -+ } -+ -+ public > void registerWithListeners( -+ final Registry registry, -+ final ResourceKey key, -+ final M nms, -+ final RegistrationInfo registrationInfo -+ ) { -+ this.registerWithListeners(registry, key, nms, registrationInfo, WritableRegistry::register); -+ } -+ -+ public , R> R registerWithListeners( -+ final Registry registry, -+ final ResourceKey key, -+ final M nms, -+ final RegistrationInfo registrationInfo, -+ final RegisterMethod registerMethod -+ ) { -+ Preconditions.checkState(LaunchEntryPointHandler.INSTANCE.hasEntered(Entrypoint.BOOTSTRAPPER), registry.key() + " tried to run modification listeners before bootstrappers have been called"); // verify that bootstrappers have been called -+ final @Nullable RegistryEntryInfo entry = PaperRegistries.getEntry(registry.key()); -+ if (!(entry instanceof RegistryEntry.Modifiable) || !this.valueAddHooks.hasHooks(entry.apiKey())) { -+ return registerMethod.register((WritableRegistry) registry, key, nms, registrationInfo); -+ } -+ final RegistryEntry.Modifiable modifiableEntry = (RegistryEntry.Modifiable) entry; -+ @SuppressWarnings("PatternValidation") final TypedKey typedKey = TypedKey.create(entry.apiKey(), Key.key(key.location().getNamespace(), key.location().getPath())); -+ final B builder = modifiableEntry.fillBuilder(typedKey, nms); -+ return this.registerWithListeners(registry, modifiableEntry, key, nms, builder, registrationInfo, registerMethod); -+ } -+ -+ public > void registerWithListeners( -+ final Registry registry, -+ final RegistryEntry.Modifiable entry, -+ final ResourceKey key, -+ final @Nullable M oldNms, -+ final B builder, -+ final RegistrationInfo registrationInfo -+ ) { -+ this.registerWithListeners(registry, entry, key, oldNms, builder, registrationInfo, WritableRegistry::register); -+ } -+ -+ public , R> R registerWithListeners( -+ final Registry registry, -+ final RegistryEntry.Modifiable entry, -+ final ResourceKey key, -+ final @Nullable M oldNms, -+ final B builder, -+ final RegistrationInfo registrationInfo, -+ final RegisterMethod registerMethod -+ ) { -+ @Subst("namespace:key") final ResourceLocation beingAdded = key.location(); -+ @SuppressWarnings("PatternValidation") final TypedKey typedKey = TypedKey.create(entry.apiKey(), Key.key(beingAdded.getNamespace(), beingAdded.getPath())); -+ final RegistryEntryAddEventImpl event = entry.createEntryAddEvent(typedKey, builder); -+ LifecycleEventRunner.INSTANCE.callEvent(this.valueAddHooks.getHook(entry.apiKey()), event); -+ if (oldNms != null) { -+ ((MappedRegistry) registry).clearIntrusiveHolder(oldNms); -+ } -+ final M newNms = event.builder().build(); -+ return registerMethod.register((WritableRegistry) registry, key, newNms, registrationInfo); -+ } -+ -+ private static M registerWithInstance(final WritableRegistry writableRegistry, final ResourceKey key, final M value, final RegistrationInfo registrationInfo) { -+ writableRegistry.register(key, value, registrationInfo); -+ return value; -+ } -+ -+ @FunctionalInterface -+ public interface RegisterMethod { -+ -+ R register(WritableRegistry writableRegistry, ResourceKey key, M value, RegistrationInfo registrationInfo); -+ } -+ -+ public > void runFreezeListeners(final ResourceKey> resourceKey) { -+ final @Nullable RegistryEntryInfo entry = PaperRegistries.getEntry(resourceKey); -+ if (!(entry instanceof RegistryEntry.Writable) || !this.freezeHooks.hasHooks(entry.apiKey())) { -+ return; -+ } -+ final RegistryEntry.Writable writableEntry = (RegistryEntry.Writable) entry; -+ final RegistryFreezeEventImpl event = writableEntry.createFreezeEvent(PaperRegistryAccess.instance().getWritableRegistry(entry.apiKey())); -+ LifecycleEventRunner.INSTANCE.callEvent(this.freezeHooks.getHook(entry.apiKey()), event); -+ } -+ -+ public > RegistryEntryAddEventType getRegistryValueAddEventType(final RegistryEventProvider type) { -+ if (!(PaperRegistries.getEntry(type.registryKey()) instanceof RegistryEntry.Modifiable)) { -+ throw new IllegalArgumentException(type.registryKey() + " does not support RegistryAdditionEvent"); -+ } -+ return this.valueAddHooks.getOrCreate(type, RegistryEntryAddEventTypeImpl::new); -+ } -+ -+ public > LifecycleEventType.Prioritizable> getRegistryFreezeEventType(final RegistryEventProvider type) { -+ if (!(PaperRegistries.getEntry(type.registryKey()) instanceof RegistryEntry.Writable)) { -+ throw new IllegalArgumentException(type.registryKey() + " does not support RegistryPreFreezeEvent"); -+ } -+ return this.freezeHooks.getOrCreate(type, RegistryLifecycleEventType::new); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java b/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java -new file mode 100644 -index 0000000000000000000000000000000000000000..aff4895d5add72e22ae9f723b77843435ff044aa ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/WritableCraftRegistry.java -@@ -0,0 +1,85 @@ -+package io.papermc.paper.registry; -+ -+import com.mojang.serialization.Lifecycle; -+import io.papermc.paper.adventure.PaperAdventure; -+import io.papermc.paper.registry.entry.RegistryEntry; -+import io.papermc.paper.registry.event.WritableRegistry; -+import java.util.Optional; -+import java.util.function.BiFunction; -+import java.util.function.Consumer; -+import net.minecraft.core.MappedRegistry; -+import net.minecraft.core.RegistrationInfo; -+import net.minecraft.resources.ResourceKey; -+import org.bukkit.Keyed; -+import org.bukkit.NamespacedKey; -+import org.bukkit.craftbukkit.CraftRegistry; -+import org.bukkit.craftbukkit.util.ApiVersion; -+import org.checkerframework.checker.nullness.qual.Nullable; -+ -+public class WritableCraftRegistry> extends CraftRegistry { -+ -+ private static final RegistrationInfo FROM_PLUGIN = new RegistrationInfo(Optional.empty(), Lifecycle.experimental()); -+ -+ private final RegistryEntry.BuilderHolder entry; -+ private final MappedRegistry registry; -+ public final WritableRegistry apiWritableRegistry = new ApiWritableRegistry(); -+ private final PaperRegistryBuilder.Factory builderFactory; -+ private final BiFunction minecraftToBukkit; -+ -+ public WritableCraftRegistry( -+ final RegistryEntry.BuilderHolder entry, -+ final Class classToPreload, -+ final MappedRegistry registry, -+ final BiFunction serializationUpdater, -+ final PaperRegistryBuilder.Factory builderFactory, -+ final BiFunction minecraftToBukkit -+ ) { -+ super(classToPreload, registry, null, serializationUpdater); -+ this.entry = entry; -+ this.registry = registry; -+ this.builderFactory = builderFactory; -+ this.minecraftToBukkit = minecraftToBukkit; -+ } -+ -+ public void register(final TypedKey key, final Consumer value) { -+ final ResourceKey resourceKey = ResourceKey.create(this.registry.key(), PaperAdventure.asVanilla(key.key())); -+ this.registry.validateWrite(resourceKey); -+ final B builder = this.newBuilder(key); -+ value.accept(builder); -+ if (this.entry instanceof final RegistryEntry.Modifiable modifiable && PaperRegistryListenerManager.INSTANCE.valueAddHooks.hasHooks(this.entry.apiKey())) { -+ PaperRegistryListenerManager.INSTANCE.registerWithListeners( -+ this.registry, -+ modifiable, -+ resourceKey, -+ null, -+ builder, -+ FROM_PLUGIN -+ ); -+ } else { -+ this.registry.register(resourceKey, builder.build(), FROM_PLUGIN); -+ } -+ } -+ -+ @Override -+ public final @Nullable T createBukkit(final NamespacedKey namespacedKey, final @Nullable M minecraft) { -+ if (minecraft == null) { -+ return null; -+ } -+ return this.minecraftToBukkit(namespacedKey, minecraft); -+ } -+ -+ public T minecraftToBukkit(final NamespacedKey namespacedKey, final M minecraft) { -+ return this.minecraftToBukkit.apply(namespacedKey, minecraft); -+ } -+ -+ protected B newBuilder(final TypedKey key) { -+ return this.builderFactory.create(key); -+ } -+ -+ public class ApiWritableRegistry implements WritableRegistry { -+ @Override -+ public void register(final TypedKey key, final Consumer value) { -+ WritableCraftRegistry.this.register(key, value); -+ } -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/entry/AddableRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/AddableRegistryEntry.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a0f24d396e3a258be1978b2baa3f8e07ff54538f ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/entry/AddableRegistryEntry.java -@@ -0,0 +1,43 @@ -+package io.papermc.paper.registry.entry; -+ -+import io.papermc.paper.registry.PaperRegistryBuilder; -+import io.papermc.paper.registry.RegistryHolder; -+import io.papermc.paper.registry.RegistryKey; -+import io.papermc.paper.registry.TypedKey; -+import io.papermc.paper.registry.WritableCraftRegistry; -+import java.util.function.BiFunction; -+import net.minecraft.core.MappedRegistry; -+import net.minecraft.core.Registry; -+import net.minecraft.resources.ResourceKey; -+import org.bukkit.Keyed; -+import org.bukkit.NamespacedKey; -+ -+public class AddableRegistryEntry> extends CraftRegistryEntry implements RegistryEntry.Addable { -+ -+ private final PaperRegistryBuilder.Filler builderFiller; -+ -+ protected AddableRegistryEntry( -+ final ResourceKey> mcKey, -+ final RegistryKey apiKey, -+ final Class classToPreload, -+ final BiFunction minecraftToBukkit, -+ final PaperRegistryBuilder.Filler builderFiller -+ ) { -+ super(mcKey, apiKey, classToPreload, minecraftToBukkit); -+ this.builderFiller = builderFiller; -+ } -+ -+ private WritableCraftRegistry createRegistry(final Registry registry) { -+ return new WritableCraftRegistry<>(this, this.classToPreload, (MappedRegistry) registry, this.updater, this.builderFiller.asFactory(), this.minecraftToBukkit); -+ } -+ -+ @Override -+ public RegistryHolder createRegistryHolder(final Registry nmsRegistry) { -+ return new RegistryHolder.Memoized<>(() -> this.createRegistry(nmsRegistry)); -+ } -+ -+ @Override -+ public B fillBuilder(final TypedKey key, final M nms) { -+ return this.builderFiller.fill(key, nms); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/entry/ModifiableRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/ModifiableRegistryEntry.java -new file mode 100644 -index 0000000000000000000000000000000000000000..df10008f6bde1047c8a13523c0a8fc01222a4e62 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/entry/ModifiableRegistryEntry.java -@@ -0,0 +1,31 @@ -+package io.papermc.paper.registry.entry; -+ -+import io.papermc.paper.registry.PaperRegistryBuilder; -+import io.papermc.paper.registry.RegistryKey; -+import io.papermc.paper.registry.TypedKey; -+import java.util.function.BiFunction; -+import net.minecraft.core.Registry; -+import net.minecraft.resources.ResourceKey; -+import org.bukkit.Keyed; -+import org.bukkit.NamespacedKey; -+ -+public class ModifiableRegistryEntry> extends CraftRegistryEntry implements RegistryEntry.Modifiable { -+ -+ protected final PaperRegistryBuilder.Filler builderFiller; -+ -+ protected ModifiableRegistryEntry( -+ final ResourceKey> mcKey, -+ final RegistryKey apiKey, -+ final Class toPreload, -+ final BiFunction minecraftToBukkit, -+ final PaperRegistryBuilder.Filler builderFiller -+ ) { -+ super(mcKey, apiKey, toPreload, minecraftToBukkit); -+ this.builderFiller = builderFiller; -+ } -+ -+ @Override -+ public B fillBuilder(final TypedKey key, final M nms) { -+ return this.builderFiller.fill(key, nms); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java -index 15991bf13894d850f360a520d1815711d25973ec..c49170d469dca809dc42421168d14e57e24d734b 100644 ---- a/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java -+++ b/src/main/java/io/papermc/paper/registry/entry/RegistryEntry.java -@@ -1,7 +1,12 @@ - package io.papermc.paper.registry.entry; - -+import io.papermc.paper.registry.PaperRegistryBuilder; - import io.papermc.paper.registry.RegistryHolder; - import io.papermc.paper.registry.RegistryKey; -+import io.papermc.paper.registry.TypedKey; -+import io.papermc.paper.registry.WritableCraftRegistry; -+import io.papermc.paper.registry.event.RegistryEntryAddEventImpl; -+import io.papermc.paper.registry.event.RegistryFreezeEventImpl; - import io.papermc.paper.registry.legacy.DelayedRegistryEntry; - import java.util.function.BiFunction; - import java.util.function.Supplier; -@@ -32,6 +37,37 @@ public interface RegistryEntry extends RegistryEntryInfo(this); - } - -+ interface BuilderHolder> extends RegistryEntryInfo { -+ -+ B fillBuilder(TypedKey key, M nms); -+ } -+ -+ /** -+ * Can mutate values being added to the registry -+ */ -+ interface Modifiable> extends BuilderHolder { -+ -+ default RegistryEntryAddEventImpl createEntryAddEvent(final TypedKey key, final B initialBuilder) { -+ return new RegistryEntryAddEventImpl<>(key, initialBuilder, this.apiKey()); -+ } -+ } -+ -+ /** -+ * Can only add new values to the registry, not modify any values. -+ */ -+ interface Addable> extends BuilderHolder { // TODO remove Keyed -+ -+ default RegistryFreezeEventImpl createFreezeEvent(final WritableCraftRegistry writableRegistry) { -+ return new RegistryFreezeEventImpl<>(this.apiKey(), writableRegistry.apiWritableRegistry); -+ } -+ } -+ -+ /** -+ * Can mutate values and add new values. -+ */ -+ interface Writable> extends Modifiable, Addable { // TODO remove Keyed -+ } -+ - static RegistryEntry entry( - final ResourceKey> mcKey, - final RegistryKey apiKey, -@@ -48,4 +84,24 @@ public interface RegistryEntry extends RegistryEntryInfo(mcKey, apiKey, apiRegistrySupplier); - } -+ -+ static > RegistryEntry modifiable( -+ final ResourceKey> mcKey, -+ final RegistryKey apiKey, -+ final Class toPreload, -+ final BiFunction minecraftToBukkit, -+ final PaperRegistryBuilder.Filler filler -+ ) { -+ return new ModifiableRegistryEntry<>(mcKey, apiKey, toPreload, minecraftToBukkit, filler); -+ } -+ -+ static > RegistryEntry writable( -+ final ResourceKey> mcKey, -+ final RegistryKey apiKey, -+ final Class toPreload, -+ final BiFunction minecraftToBukkit, -+ final PaperRegistryBuilder.Filler filler -+ ) { -+ return new WritableRegistryEntry<>(mcKey, apiKey, toPreload, minecraftToBukkit, filler); -+ } - } -diff --git a/src/main/java/io/papermc/paper/registry/entry/WritableRegistryEntry.java b/src/main/java/io/papermc/paper/registry/entry/WritableRegistryEntry.java -new file mode 100644 -index 0000000000000000000000000000000000000000..562accce731630327d116afd1c9d559df7e386bd ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/entry/WritableRegistryEntry.java -@@ -0,0 +1,22 @@ -+package io.papermc.paper.registry.entry; -+ -+import io.papermc.paper.registry.PaperRegistryBuilder; -+import io.papermc.paper.registry.RegistryKey; -+import java.util.function.BiFunction; -+import net.minecraft.core.Registry; -+import net.minecraft.resources.ResourceKey; -+import org.bukkit.Keyed; -+import org.bukkit.NamespacedKey; -+ -+public class WritableRegistryEntry> extends AddableRegistryEntry implements RegistryEntry.Writable { // TODO remove Keyed -+ -+ protected WritableRegistryEntry( -+ final ResourceKey> mcKey, -+ final RegistryKey apiKey, -+ final Class classToPreload, -+ final BiFunction minecraftToBukkit, -+ final PaperRegistryBuilder.Filler builderFiller -+ ) { -+ super(mcKey, apiKey, classToPreload, minecraftToBukkit, builderFiller); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEventImpl.java b/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEventImpl.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a1d747c1a46d3aa8bcdef82bebb48f1fd760e61f ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/RegistryEntryAddEventImpl.java -@@ -0,0 +1,13 @@ -+package io.papermc.paper.registry.event; -+ -+import io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEvent; -+import io.papermc.paper.registry.RegistryBuilder; -+import io.papermc.paper.registry.RegistryKey; -+import io.papermc.paper.registry.TypedKey; -+ -+public record RegistryEntryAddEventImpl>( -+ TypedKey key, -+ B builder, -+ RegistryKey registryKey -+) implements RegistryEntryAddEvent, PaperLifecycleEvent { -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventMap.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventMap.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f5ea23173dcbe491742c3dd051c147ef397307a0 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventMap.java -@@ -0,0 +1,44 @@ -+package io.papermc.paper.registry.event; -+ -+import io.papermc.paper.plugin.bootstrap.BootstrapContext; -+import io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner; -+import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; -+import io.papermc.paper.registry.RegistryBuilder; -+import io.papermc.paper.registry.RegistryKey; -+import java.util.HashMap; -+import java.util.Map; -+import java.util.Objects; -+import java.util.function.BiFunction; -+ -+public final class RegistryEventMap { -+ -+ private final Map, LifecycleEventType, ?>> hooks = new HashMap<>(); -+ private final String name; -+ -+ public RegistryEventMap(final String name) { -+ this.name = name; -+ } -+ -+ @SuppressWarnings("unchecked") -+ public , E extends RegistryEvent, ET extends LifecycleEventType> ET getOrCreate(final RegistryEventProvider type, final BiFunction, ? super String, ET> eventTypeCreator) { -+ final ET registerHook; -+ if (this.hooks.containsKey(type.registryKey())) { -+ registerHook = (ET) this.hooks.get(type.registryKey()); -+ } else { -+ registerHook = eventTypeCreator.apply(type, this.name); -+ LifecycleEventRunner.INSTANCE.addEventType(registerHook); -+ this.hooks.put(type.registryKey(), registerHook); -+ } -+ return registerHook; -+ } -+ -+ @SuppressWarnings("unchecked") -+ public > LifecycleEventType getHook(final RegistryKey registryKey) { -+ return (LifecycleEventType) Objects.requireNonNull(this.hooks.get(registryKey), "No hook for " + registryKey); -+ } -+ -+ public boolean hasHooks(final RegistryKey registryKey) { -+ return this.hooks.containsKey(registryKey); -+ } -+ -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProviderImpl.java b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProviderImpl.java -new file mode 100644 -index 0000000000000000000000000000000000000000..34c842ffa355e3c8001dd7b8551bcb49229a6391 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProviderImpl.java -@@ -0,0 +1,24 @@ -+package io.papermc.paper.registry.event; -+ -+import io.papermc.paper.plugin.bootstrap.BootstrapContext; -+import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType; -+import io.papermc.paper.registry.PaperRegistryListenerManager; -+import io.papermc.paper.registry.RegistryBuilder; -+import io.papermc.paper.registry.event.type.RegistryEntryAddEventType; -+ -+public class RegistryEventTypeProviderImpl implements RegistryEventTypeProvider { -+ -+ public static RegistryEventTypeProviderImpl instance() { -+ return (RegistryEventTypeProviderImpl) RegistryEventTypeProvider.provider(); -+ } -+ -+ @Override -+ public > RegistryEntryAddEventType registryEntryAdd(final RegistryEventProvider type) { -+ return PaperRegistryListenerManager.INSTANCE.getRegistryValueAddEventType(type); -+ } -+ -+ @Override -+ public > LifecycleEventType.Prioritizable> registryFreeze(final RegistryEventProvider type) { -+ return PaperRegistryListenerManager.INSTANCE.getRegistryFreezeEventType(type); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEventImpl.java b/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEventImpl.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2db5d33d0b72ec3c9ff1c3042d9246dfa4344346 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/RegistryFreezeEventImpl.java -@@ -0,0 +1,11 @@ -+package io.papermc.paper.registry.event; -+ -+import io.papermc.paper.plugin.lifecycle.event.PaperLifecycleEvent; -+import io.papermc.paper.registry.RegistryBuilder; -+import io.papermc.paper.registry.RegistryKey; -+ -+public record RegistryFreezeEventImpl>( -+ RegistryKey registryKey, -+ WritableRegistry registry -+) implements RegistryFreezeEvent, PaperLifecycleEvent { -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/package-info.java b/src/main/java/io/papermc/paper/registry/event/package-info.java -new file mode 100644 -index 0000000000000000000000000000000000000000..14d2d9766b8dee763f220c397aba3ad432d02aaa ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/package-info.java -@@ -0,0 +1,5 @@ -+@DefaultQualifier(NonNull.class) -+package io.papermc.paper.registry.event; -+ -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -diff --git a/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddEventTypeImpl.java b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddEventTypeImpl.java -new file mode 100644 -index 0000000000000000000000000000000000000000..32303ea9b3da736cbe26d06e57f5dcc3aa32a99b ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddEventTypeImpl.java -@@ -0,0 +1,32 @@ -+package io.papermc.paper.registry.event.type; -+ -+import io.papermc.paper.plugin.bootstrap.BootstrapContext; -+import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; -+import io.papermc.paper.plugin.lifecycle.event.types.PrioritizableLifecycleEventType; -+import io.papermc.paper.registry.RegistryBuilder; -+import io.papermc.paper.registry.event.RegistryEntryAddEvent; -+import io.papermc.paper.registry.event.RegistryEventProvider; -+import java.util.function.Consumer; -+import java.util.function.Predicate; -+ -+public class RegistryEntryAddEventTypeImpl> extends PrioritizableLifecycleEventType, RegistryEntryAddConfiguration> implements RegistryEntryAddEventType { -+ -+ public RegistryEntryAddEventTypeImpl(final RegistryEventProvider type, final String eventName) { -+ super(type.registryKey() + " / " + eventName, BootstrapContext.class); -+ } -+ -+ @Override -+ public RegistryEntryAddConfiguration newHandler(final LifecycleEventHandler> handler) { -+ return new RegistryEntryAddHandlerConfiguration<>(handler, this); -+ } -+ -+ @Override -+ public void forEachHandler(final RegistryEntryAddEvent event, final Consumer>> consumer, final Predicate>> predicate) { -+ super.forEachHandler(event, consumer, predicate.and(handler -> this.matchesTarget(event, handler))); -+ } -+ -+ private boolean matchesTarget(final RegistryEntryAddEvent event, final RegisteredHandler> handler) { -+ final RegistryEntryAddHandlerConfiguration config = (RegistryEntryAddHandlerConfiguration) handler.config(); -+ return config.target() == null || event.key().equals(config.target()); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddHandlerConfiguration.java b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddHandlerConfiguration.java -new file mode 100644 -index 0000000000000000000000000000000000000000..53df2dd1a9e1cef90bd8504c717b1cc6374b6f4e ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/type/RegistryEntryAddHandlerConfiguration.java -@@ -0,0 +1,39 @@ -+package io.papermc.paper.registry.event.type; -+ -+import io.papermc.paper.plugin.bootstrap.BootstrapContext; -+import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; -+import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfigurationImpl; -+import io.papermc.paper.plugin.lifecycle.event.types.AbstractLifecycleEventType; -+import io.papermc.paper.registry.RegistryBuilder; -+import io.papermc.paper.registry.TypedKey; -+import io.papermc.paper.registry.event.RegistryEntryAddEvent; -+import org.checkerframework.checker.nullness.qual.Nullable; -+ -+public class RegistryEntryAddHandlerConfiguration> extends PrioritizedLifecycleEventHandlerConfigurationImpl> implements RegistryEntryAddConfiguration { -+ -+ private @Nullable TypedKey target; -+ -+ public RegistryEntryAddHandlerConfiguration(final LifecycleEventHandler> handler, final AbstractLifecycleEventType, ?> eventType) { -+ super(handler, eventType); -+ } -+ -+ public @Nullable TypedKey target() { -+ return this.target; -+ } -+ -+ @Override -+ public RegistryEntryAddConfiguration onlyFor(final TypedKey key) { -+ this.target = key; -+ return this; -+ } -+ -+ @Override -+ public RegistryEntryAddConfiguration priority(final int priority) { -+ return (RegistryEntryAddConfiguration) super.priority(priority); -+ } -+ -+ @Override -+ public RegistryEntryAddConfiguration monitor() { -+ return (RegistryEntryAddConfiguration) super.monitor(); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/event/type/RegistryLifecycleEventType.java b/src/main/java/io/papermc/paper/registry/event/type/RegistryLifecycleEventType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..dcc0f6b337840a78d38abdf2eb3f4bbd1676f58f ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/event/type/RegistryLifecycleEventType.java -@@ -0,0 +1,14 @@ -+package io.papermc.paper.registry.event.type; -+ -+import io.papermc.paper.plugin.bootstrap.BootstrapContext; -+import io.papermc.paper.plugin.lifecycle.event.types.PrioritizableLifecycleEventType; -+import io.papermc.paper.registry.RegistryBuilder; -+import io.papermc.paper.registry.event.RegistryEvent; -+import io.papermc.paper.registry.event.RegistryEventProvider; -+ -+public final class RegistryLifecycleEventType, E extends RegistryEvent> extends PrioritizableLifecycleEventType.Simple { -+ -+ public RegistryLifecycleEventType(final RegistryEventProvider type, final String eventName) { -+ super(type.registryKey() + " / " + eventName, BootstrapContext.class); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/registry/package-info.java b/src/main/java/io/papermc/paper/registry/package-info.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0b80179ff90e085568d7ceafd9b17511789dc99b ---- /dev/null -+++ b/src/main/java/io/papermc/paper/registry/package-info.java -@@ -0,0 +1,5 @@ -+@DefaultQualifier(NonNull.class) -+package io.papermc.paper.registry; -+ -+import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.framework.qual.DefaultQualifier; -diff --git a/src/main/java/net/minecraft/core/MappedRegistry.java b/src/main/java/net/minecraft/core/MappedRegistry.java -index 72c0c4a12aea39fa1c1967fa0277ed117471107e..68f575602476dd5127af773e4af098196091ca70 100644 ---- a/src/main/java/net/minecraft/core/MappedRegistry.java -+++ b/src/main/java/net/minecraft/core/MappedRegistry.java -@@ -436,4 +436,12 @@ public class MappedRegistry implements WritableRegistry { - public HolderLookup.RegistryLookup asLookup() { - return this.lookup; - } -+ // Paper start -+ // used to clear intrusive holders from GameEvent, Item, Block, EntityType, and Fluid from unused instances of those types -+ public void clearIntrusiveHolder(final T instance) { -+ if (this.unregisteredIntrusiveHolders != null) { -+ this.unregisteredIntrusiveHolders.remove(instance); -+ } -+ } -+ // Paper end - } -diff --git a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java -index 8daee5a7935e3253834c4cbe81d5e8886f776dad..d7da62360d48d8c12c489296b4ee2ee44c0c2d93 100644 ---- a/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java -+++ b/src/main/java/net/minecraft/core/registries/BuiltInRegistries.java -@@ -310,6 +310,7 @@ public class BuiltInRegistries { - } - public static void bootStrap(Runnable runnable) { - // Paper end -+ REGISTRY.freeze(); // Paper - freeze main registry early - createContents(); - runnable.run(); // Paper - freeze(); -@@ -328,6 +329,7 @@ public class BuiltInRegistries { - REGISTRY.freeze(); - - for (Registry registry : REGISTRY) { -+ io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.runFreezeListeners(registry.key()); // Paper - registry.freeze(); - } - } -diff --git a/src/main/java/net/minecraft/resources/RegistryDataLoader.java b/src/main/java/net/minecraft/resources/RegistryDataLoader.java -index d59356df2d98de873fc5accc749f87fa3d685267..9414cadb2766c3b8f50bf811d3408402e9f57670 100644 ---- a/src/main/java/net/minecraft/resources/RegistryDataLoader.java -+++ b/src/main/java/net/minecraft/resources/RegistryDataLoader.java -@@ -125,6 +125,7 @@ public class RegistryDataLoader { - list.forEach(loader -> loadable.apply((RegistryDataLoader.Loader)loader, registryInfoLookup)); - list.forEach(loader -> { - Registry registry = loader.registry(); -+ io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.runFreezeListeners(loader.registry.key()); // Paper - run pre-freeze listeners - - try { - registry.freeze(); -@@ -188,7 +189,7 @@ public class RegistryDataLoader { - JsonElement jsonElement = JsonParser.parseReader(reader); - DataResult dataResult = decoder.parse(ops, jsonElement); - E object = dataResult.getOrThrow(); -- registry.register(key, object, entryInfo); -+ io.papermc.paper.registry.PaperRegistryListenerManager.INSTANCE.registerWithListeners(registry, key, object, entryInfo); // Paper - } - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -index 4a5778d1751b774c825bbce0e870e2998278afe3..55d459731a9d7ab8debfdd6d27f874dba6c41436 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegistry.java -@@ -155,11 +155,11 @@ public class CraftRegistry implements Registry { - private final Map cache = new HashMap<>(); - private final Map byValue = new java.util.IdentityHashMap<>(); // Paper - improve Registry - private final net.minecraft.core.Registry minecraftRegistry; -- private final BiFunction minecraftToBukkit; -+ private final BiFunction minecraftToBukkit; // Paper - private final BiFunction serializationUpdater; // Paper - rename to make it *clear* what it is *only* for - private boolean init; - -- public CraftRegistry(Class bukkitClass, net.minecraft.core.Registry minecraftRegistry, BiFunction minecraftToBukkit, BiFunction serializationUpdater) { // Paper - relax preload class -+ public CraftRegistry(Class bukkitClass, net.minecraft.core.Registry minecraftRegistry, BiFunction minecraftToBukkit, BiFunction serializationUpdater) { // Paper - relax preload class - this.bukkitClass = bukkitClass; - this.minecraftRegistry = minecraftRegistry; - this.minecraftToBukkit = minecraftToBukkit; -diff --git a/src/main/resources/META-INF/services/io.papermc.paper.registry.event.RegistryEventTypeProvider b/src/main/resources/META-INF/services/io.papermc.paper.registry.event.RegistryEventTypeProvider -new file mode 100644 -index 0000000000000000000000000000000000000000..8bee1a5ed877a04e4d027593df1f42cefdd824e7 ---- /dev/null -+++ b/src/main/resources/META-INF/services/io.papermc.paper.registry.event.RegistryEventTypeProvider -@@ -0,0 +1 @@ -+io.papermc.paper.registry.event.RegistryEventTypeProviderImpl diff --git a/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java b/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java index b8d30202dd..671c37fa40 100644 --- a/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java +++ b/test-plugin/src/main/java/io/papermc/testplugin/TestPlugin.java @@ -1,8 +1,5 @@ package io.papermc.testplugin; -import io.papermc.paper.registry.keys.GameEventKeys; -import org.bukkit.GameEvent; -import org.bukkit.Registry; import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; @@ -13,17 +10,6 @@ public final class TestPlugin extends JavaPlugin implements Listener { this.getServer().getPluginManager().registerEvents(this, this); // io.papermc.testplugin.brigtests.Registration.registerViaOnEnable(this); - - final GameEvent newEvent = Registry.GAME_EVENT.get(TestPluginBootstrap.NEW_EVENT); - if (newEvent == null) { - throw new RuntimeException("could not find new event"); - } else { - System.out.println("New event: " + newEvent.getKey() + " " + newEvent.getRange()); - } - final GameEvent changed = Registry.GAME_EVENT.get(GameEventKeys.BLOCK_OPEN); - System.out.println("changed: " + changed.getRange()); - final GameEvent same = Registry.GAME_EVENT.get(GameEventKeys.CONTAINER_OPEN); - System.out.println("same: " + same.getRange()); } } diff --git a/test-plugin/src/main/java/io/papermc/testplugin/TestPluginBootstrap.java b/test-plugin/src/main/java/io/papermc/testplugin/TestPluginBootstrap.java index 26da106c6c..fe2b287b25 100644 --- a/test-plugin/src/main/java/io/papermc/testplugin/TestPluginBootstrap.java +++ b/test-plugin/src/main/java/io/papermc/testplugin/TestPluginBootstrap.java @@ -2,34 +2,13 @@ package io.papermc.testplugin; import io.papermc.paper.plugin.bootstrap.BootstrapContext; import io.papermc.paper.plugin.bootstrap.PluginBootstrap; -import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; -import io.papermc.paper.registry.RegistryKey; -import io.papermc.paper.registry.TypedKey; -import io.papermc.paper.registry.event.RegistryEvents; -import io.papermc.paper.registry.keys.GameEventKeys; -import net.kyori.adventure.key.Key; -import org.bukkit.GameEvent; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.framework.qual.DefaultQualifier; import org.jetbrains.annotations.NotNull; -@DefaultQualifier(NonNull.class) public class TestPluginBootstrap implements PluginBootstrap { - static final TypedKey NEW_EVENT = TypedKey.create(RegistryKey.GAME_EVENT, Key.key("machine_maker", "best_event")); - @Override public void bootstrap(@NotNull BootstrapContext context) { // io.papermc.testplugin.brigtests.Registration.registerViaBootstrap(context); - - final LifecycleEventManager lifecycleManager = context.getLifecycleManager(); - lifecycleManager.registerEventHandler(RegistryEvents.GAME_EVENT.entryAdd().newHandler(event -> { - event.builder().range(event.builder().range() * 40); - }).priority(10).onlyFor(GameEventKeys.BLOCK_OPEN)); - lifecycleManager.registerEventHandler(RegistryEvents.GAME_EVENT.freeze(), event -> { - event.registry().register(NEW_EVENT, builder -> { - builder.range(2); - }); - }); } + } -- cgit v1.2.3