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..2bec1f1d750e796e1d26c3cd090d53de2672170f --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/RegistryBuilder.java @@ -0,0 +1,11 @@ +package io.papermc.paper.registry; + +import org.jetbrains.annotations.ApiStatus; + +/** + * To be implemented by any type used for modifying registries. + */ +@ApiStatus.NonExtendable +@ApiStatus.Experimental +public interface RegistryBuilder { +} diff --git a/src/main/java/io/papermc/paper/registry/RegistryView.java b/src/main/java/io/papermc/paper/registry/RegistryView.java new file mode 100644 index 0000000000000000000000000000000000000000..768f4370fc622b7a6c783fdd67a222f1e0570e1a --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/RegistryView.java @@ -0,0 +1,20 @@ +package io.papermc.paper.registry; + +import net.kyori.adventure.key.Key; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Provides read-only access to a registry. + * + * @param registry object type + */ +@ApiStatus.Experimental +@ApiStatus.NonExtendable +public interface RegistryView extends Iterable { + + @Nullable T get(final @NotNull Key key); + + @NotNull T getOrThrow(final @NotNull Key key); +} diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryAdditionEvent.java b/src/main/java/io/papermc/paper/registry/event/RegistryAdditionEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..e70e0b79f300f6453b8f5a76defdb2300360f688 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/event/RegistryAdditionEvent.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.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +/** + * Event object for {@link RegistryEvents.Provider#addition()}. This + * event is fired right before a specific object is added to a registry. + * It provides a way for plugins to modify parts of this object. + * + * @param object type + * @param object builder type + */ +@ApiStatus.Experimental +@ApiStatus.NonExtendable +public interface RegistryAdditionEvent> extends RegistryEvent { + + /** + * Gets the builder for the object being added to the registry. + * + * @return the object builder + */ + @NotNull B builder(); + + /** + * Gets the key for this object in the registry. + * + * @return the key + */ + @NotNull 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..c4841b63fa4b6bf49d1e04339561d48ba8ae562d --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/event/RegistryEvent.java @@ -0,0 +1,41 @@ +package io.papermc.paper.registry.event; + +import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.RegistryView; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +/** + * Base type for all registry events. + * + * @param object type + */ +@ApiStatus.Experimental +@ApiStatus.NonExtendable +public interface RegistryEvent extends LifecycleEvent { + + /** + * Get the key for the registry this event pertains to. + * + * @return the registry key + */ + @NotNull RegistryKey registryKey(); + + /** + * Get a view of the registry which may or may not + * be complete based on the event. + * + * @return a registry view + */ + @NotNull RegistryView registry(); + + /** + * Get the name of the event. + * + * @return the event name + */ + default @NotNull String eventName() { + return this.getClass().getSimpleName(); + } +} 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..0df562062e6468617597a49abf88e116dd693935 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventProviderImpl.java @@ -0,0 +1,40 @@ +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.plugin.lifecycle.event.handler.LifecycleEventHandler; +import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfiguration; +import io.papermc.paper.registry.RegistryBuilder; +import io.papermc.paper.registry.RegistryKey; +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 RegistryEvents.Provider { + + static > RegistryEvents.Provider create(final RegistryKey registryKey) { + return new RegistryEventProviderImpl<>(registryKey); + } + + @Override + public LifecycleEventType.Prioritizable> addition() { + return RegistryEventTypeProvider.PROVIDER.registryAddition(this); + } + + @Override + public PrioritizedLifecycleEventHandlerConfiguration newAdditionHandler(final LifecycleEventHandler> handler) { + return this.addition().newHandler(handler); + } + + @Override + public LifecycleEventType.Prioritizable> preFreeze() { + return RegistryEventTypeProvider.PROVIDER.registryPreFreeze(this); + } + + @Override + public PrioritizedLifecycleEventHandlerConfiguration newPreFreezeHandler(final LifecycleEventHandler> handler) { + return this.preFreeze().newHandler(handler); + } +} 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..118306c85e7c861a0c4010ba9e37f15ca49498a7 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/event/RegistryEventTypeProvider.java @@ -0,0 +1,20 @@ +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 java.util.ServiceLoader; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +interface RegistryEventTypeProvider { + + RegistryEventTypeProvider PROVIDER = ServiceLoader.load(RegistryEventTypeProvider.class) + .findFirst() + .orElseThrow(); + + + > LifecycleEventType.Prioritizable> registryAddition(RegistryEvents.Provider type); + + > LifecycleEventType.Prioritizable> registryPreFreeze(RegistryEvents.Provider 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..0df2045dab9b19f5456a8946e0b827cbdcf31159 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java @@ -0,0 +1,87 @@ +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 org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import static io.papermc.paper.registry.event.RegistryEventProviderImpl.create; + +/** + * Holds providers for {@link RegistryAdditionEvent} and {@link RegistryPreFreezeEvent} + * handlers for each applicable registry. + */ +@ApiStatus.Experimental +public final class RegistryEvents { + + + /** + * Provider for each registry event type for a specific registry. + * + * @param object type + * @param object builder type + */ + @ApiStatus.Experimental + @ApiStatus.NonExtendable + public interface Provider> { + + /** + * Gets the event type for {@link RegistryAdditionEvent} 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 RegistryAdditionEvent}. + * + * @return the addition event type + */ + LifecycleEventType.@NotNull Prioritizable> addition(); + + /** + * Shortcut for calling {@link #addition()} followed by {@link LifecycleEventType#newHandler(LifecycleEventHandler)}. + *

+ * Can be used in {@link io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager#registerEventHandler(LifecycleEventHandlerConfiguration)} + * to register a handler for {@link RegistryAdditionEvent} + * + * @param handler the event handler for {@link RegistryAdditionEvent} + * @return the configuration for further use + */ + @NotNull PrioritizedLifecycleEventHandlerConfiguration newAdditionHandler(@NotNull LifecycleEventHandler> handler); + + /** + * Gets the event type for {@link RegistryPreFreezeEvent} 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 RegistryPreFreezeEvent}. + * + * @return the pre-freeze event type + */ + LifecycleEventType.@NotNull Prioritizable> preFreeze(); + + /** + * Shortcut for calling {@link #preFreeze()} followed by {@link LifecycleEventType#newHandler(LifecycleEventHandler)}. + *

+ * Can be used in {@link io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager#registerEventHandler(LifecycleEventHandlerConfiguration)} + * to register a handler for {@link RegistryPreFreezeEvent} + * + * @param handler the event handler for {@link RegistryPreFreezeEvent} + * @return the configuration for further use + */ + @NotNull PrioritizedLifecycleEventHandlerConfiguration newPreFreezeHandler(@NotNull LifecycleEventHandler> handler); + + /** + * Gets the registry key associated with this event type provider. + * + * @return the registry key + */ + @NotNull RegistryKey registryKey(); + } + + private RegistryEvents() { + } +} diff --git a/src/main/java/io/papermc/paper/registry/event/RegistryPreFreezeEvent.java b/src/main/java/io/papermc/paper/registry/event/RegistryPreFreezeEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..8ca6cc14b544399e32477c5fbe8b58f3bb4f55c4 --- /dev/null +++ b/src/main/java/io/papermc/paper/registry/event/RegistryPreFreezeEvent.java @@ -0,0 +1,27 @@ +package io.papermc.paper.registry.event; + +import io.papermc.paper.registry.RegistryBuilder; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +/** + * Event object for {@link RegistryEvents.Provider#preFreeze()}. 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 object type + * @param object builder type + */ +@ApiStatus.Experimental +@ApiStatus.NonExtendable +public interface RegistryPreFreezeEvent> extends RegistryEvent { + + /** + * Get a view of the registry which supports + * the registering of new values. + * + * @return a writable registry view + */ + @Override + @NotNull 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..3cab150544f2bd7f8dd483f638817e5a36f462ed --- /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.RegistryView; +import io.papermc.paper.registry.TypedKey; +import java.util.function.Consumer; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +/** + * A registry view which supports registering new objects. + * + * @param object type + * @param object builder type + */ +@ApiStatus.NonExtendable +@ApiStatus.Experimental +public interface WritableRegistry> extends RegistryView { + + /** + * Register a new value with the specified key. + * + * @param key the object's key (must be unique from others) + * @param value a consumer for the object's builder + */ + void register(@NotNull TypedKey key, @NotNull Consumer value); +} diff --git a/src/main/java/org/bukkit/Registry.java b/src/main/java/org/bukkit/Registry.java index c63a2d5d21eb599939ec7ae5e57506ff746e4174..6aecb2d04479439d9d133f723ef160a693f699c6 100644 --- a/src/main/java/org/bukkit/Registry.java +++ b/src/main/java/org/bukkit/Registry.java @@ -331,6 +331,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 /**