From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jake Potrebic <jake.m.potrebic@gmail.com> Date: Tue, 18 Jul 2023 14:47:02 -0700 Subject: [PATCH] Add Lifecycle Event system This event system is separate from Bukkit's event system and is meant for managing resources across reloads and from points in the PluginBootstrap. diff --git a/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java b/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java index 4c47414fc08e1183b1e59369bacc4d7f7042f262..577a9d5aeae55a3b8452b6d873b51b30384c1fea 100644 --- a/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java +++ b/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java @@ -1,5 +1,7 @@ package io.papermc.paper.plugin.bootstrap; +import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; +import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.NullMarked; @@ -12,5 +14,13 @@ import org.jspecify.annotations.NullMarked; @ApiStatus.Experimental @NullMarked @ApiStatus.NonExtendable -public interface BootstrapContext extends PluginProviderContext { +public interface BootstrapContext extends PluginProviderContext, LifecycleEventOwner { + + /** + * Get the lifecycle event manager for registering handlers + * for lifecycle events allowed on the {@link BootstrapContext}. + * + * @return the lifecycle event manager + */ + LifecycleEventManager<BootstrapContext> getLifecycleManager(); } diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEvent.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..0b8eafd3e79494d4a750cd9182387fbaead24011 --- /dev/null +++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEvent.java @@ -0,0 +1,17 @@ +package io.papermc.paper.plugin.lifecycle.event; + +import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; +import org.jetbrains.annotations.ApiStatus; + +/** + * Base type for all Lifecycle Events. + * <p> + * Lifecycle events are generally fired when the older + * event system is not available, like during early + * server initialization. + * @see LifecycleEvents + */ +@ApiStatus.Experimental +@ApiStatus.NonExtendable +public interface LifecycleEvent { +} diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventManager.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventManager.java new file mode 100644 index 0000000000000000000000000000000000000000..e05cdb7ab166f92e270ea1b85e75f465878d05f2 --- /dev/null +++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventManager.java @@ -0,0 +1,53 @@ +package io.papermc.paper.plugin.lifecycle.event; + +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.types.LifecycleEventType; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Manages a plugin's lifecycle events. Can be obtained + * from {@link org.bukkit.plugin.Plugin} or {@link io.papermc.paper.plugin.bootstrap.BootstrapContext}. + * + * @param <O> the owning type, {@link org.bukkit.plugin.Plugin} or {@link io.papermc.paper.plugin.bootstrap.BootstrapContext} + */ +@ApiStatus.Experimental +@NullMarked +@ApiStatus.NonExtendable +public interface LifecycleEventManager<O extends LifecycleEventOwner> { + + /** + * Registers an event handler for a specific event type. + * <p> + * This is shorthand for creating a new {@link LifecycleEventHandlerConfiguration} and + * just passing in the {@link LifecycleEventHandler}. + * <pre>{@code + * LifecycleEventHandler<RegistrarEvent<Commands>> handler = new Handler(); + * manager.registerEventHandler(LifecycleEvents.COMMANDS, handler); + * }</pre> + * is equivalent to + * <pre>{@code + * LifecycleEventHandler<RegistrarEvent<Commands>> handler = new Handler(); + * manager.registerEventHandler(LifecycleEvents.COMMANDS.newHandler(handler)); + * }</pre> + * + * @param eventType the event type to listen to + * @param eventHandler the handler for that event + * @param <E> the type of the event object + */ + default <E extends LifecycleEvent> void registerEventHandler(final LifecycleEventType<? super O, ? extends E, ?> eventType, final LifecycleEventHandler<? super E> eventHandler) { + this.registerEventHandler(eventType.newHandler(eventHandler)); + } + + /** + * Registers an event handler configuration. + * <p> + * Configurations are created via {@link LifecycleEventType#newHandler(LifecycleEventHandler)}. + * Event types may have different configurations options available on the builder-like object + * returned by {@link LifecycleEventType#newHandler(LifecycleEventHandler)}. + * + * @param handlerConfiguration the handler configuration to register + */ + void registerEventHandler(LifecycleEventHandlerConfiguration<? super O> handlerConfiguration); +} diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventOwner.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventOwner.java new file mode 100644 index 0000000000000000000000000000000000000000..ce5891eb110464a1c0cd7416712110851d010a1b --- /dev/null +++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/LifecycleEventOwner.java @@ -0,0 +1,25 @@ +package io.papermc.paper.plugin.lifecycle.event; + +import io.papermc.paper.plugin.configuration.PluginMeta; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Implemented by types that are considered owners + * of registered handlers for lifecycle events. Generally + * the types that implement this interface also provide + * a {@link LifecycleEventManager} where you can register + * event handlers. + */ +@ApiStatus.Experimental +@NullMarked +@ApiStatus.NonExtendable +public interface LifecycleEventOwner { + + /** + * Get the plugin meta for this plugin. + * + * @return the plugin meta + */ + PluginMeta getPluginMeta(); +} diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/LifecycleEventHandler.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/LifecycleEventHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..3093ef23dd92f86240854065f7a7bb6c11ecf4fe --- /dev/null +++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/LifecycleEventHandler.java @@ -0,0 +1,19 @@ +package io.papermc.paper.plugin.lifecycle.event.handler; + +import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * A handler for a specific event. Can be implemented + * in a concrete class or as a lambda. + * + * @param <E> the event + */ +@ApiStatus.Experimental +@NullMarked +@FunctionalInterface +public interface LifecycleEventHandler<E extends LifecycleEvent> { + + void run(E event); +} diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/LifecycleEventHandlerConfiguration.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/LifecycleEventHandlerConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..9b9f4655f222597b4e00519cfe128147bc438367 --- /dev/null +++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/LifecycleEventHandlerConfiguration.java @@ -0,0 +1,20 @@ +package io.papermc.paper.plugin.lifecycle.event.handler.configuration; + +import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; +import io.papermc.paper.plugin.lifecycle.event.handler.LifecycleEventHandler; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Base type for constructing configured event handlers for + * lifecycle events. Usually created via {@link io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType#newHandler(LifecycleEventHandler)} + * from event types in {@link io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents} + * + * @param <O> + */ +@SuppressWarnings("unused") +@ApiStatus.Experimental +@NullMarked +@ApiStatus.NonExtendable +public interface LifecycleEventHandlerConfiguration<O extends LifecycleEventOwner> { +} diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/MonitorLifecycleEventHandlerConfiguration.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/MonitorLifecycleEventHandlerConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..a2acc6e3867d6805c68e4c630aca3d14aa958a1d --- /dev/null +++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/MonitorLifecycleEventHandlerConfiguration.java @@ -0,0 +1,27 @@ +package io.papermc.paper.plugin.lifecycle.event.handler.configuration; + +import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jspecify.annotations.NullMarked; + +/** + * Handler configuration for event types that allow "monitor" handlers. + * + * @param <O> the required owner type + */ +@ApiStatus.Experimental +@NullMarked +@ApiStatus.NonExtendable +public interface MonitorLifecycleEventHandlerConfiguration<O extends LifecycleEventOwner> extends LifecycleEventHandlerConfiguration<O> { + + /** + * Sets this handler configuration to be considered a "monitor". + * These handlers will run last and should only be used by plugins + * to observe changes from previously run handlers. + * + * @return this configuration for chaining + */ + @Contract("-> this") + MonitorLifecycleEventHandlerConfiguration<O> monitor(); +} diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/PrioritizedLifecycleEventHandlerConfiguration.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/PrioritizedLifecycleEventHandlerConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..100e5d169f1f644e54a042c697649f08fff1e6de --- /dev/null +++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/handler/configuration/PrioritizedLifecycleEventHandlerConfiguration.java @@ -0,0 +1,41 @@ +package io.papermc.paper.plugin.lifecycle.event.handler.configuration; + +import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jspecify.annotations.NullMarked; + +/** + * Handler configuration that allows both "monitor" and prioritized handlers. + * The default priority is 0. + * + * @param <O> the required owner type + */ +@ApiStatus.Experimental +@NullMarked +@ApiStatus.NonExtendable +public interface PrioritizedLifecycleEventHandlerConfiguration<O extends LifecycleEventOwner> extends LifecycleEventHandlerConfiguration<O> { + + /** + * Sets the priority for this handler. Resets + * all previous calls to {@link #monitor()}. A + * lower numeric value correlates to the handler + * being run earlier. + * + * @param priority the numerical priority + * @return this configuration for chaining + */ + @Contract("_ -> this") + PrioritizedLifecycleEventHandlerConfiguration<O> priority(int priority); + + /** + * Sets this handler configuration to be considered a "monitor". + * These handlers will run last and should only be used by plugins + * to observe any changes from previously ran handlers. + * + * @return this configuration for chaining + */ + @Contract("-> this") + PrioritizedLifecycleEventHandlerConfiguration<O> monitor(); + +} diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/Registrar.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/Registrar.java new file mode 100644 index 0000000000000000000000000000000000000000..fd9c3605a8f5e6bdd31e42f18a45154d4074eb67 --- /dev/null +++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/Registrar.java @@ -0,0 +1,12 @@ +package io.papermc.paper.plugin.lifecycle.event.registrar; + +import org.jetbrains.annotations.ApiStatus; + +/** + * To be implemented by types that provide ways to register types + * either on server start or during a reload + */ +@ApiStatus.Experimental +@ApiStatus.NonExtendable +public interface Registrar { +} diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/RegistrarEvent.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/RegistrarEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..7dca6be092a8b5deca9c45b152a96ffe72fe2533 --- /dev/null +++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/RegistrarEvent.java @@ -0,0 +1,28 @@ +package io.papermc.paper.plugin.lifecycle.event.registrar; + +import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jspecify.annotations.NullMarked; + +/** + * A lifecycle event that exposes a {@link Registrar} of some kind + * to allow management of various things. Look at implementations of + * {@link Registrar} for an idea of what uses this event. + * + * @param <R> registrar type + * @see ReloadableRegistrarEvent + */ +@ApiStatus.Experimental +@NullMarked +@ApiStatus.NonExtendable +public interface RegistrarEvent<R extends Registrar> extends LifecycleEvent { + + /** + * Get the registrar related to this event. + * + * @return the registrar + */ + @Contract(pure = true) + R registrar(); +} diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/ReloadableRegistrarEvent.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/ReloadableRegistrarEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..9bce1c13c8092238939fbbec6b499d1ca85e5b89 --- /dev/null +++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/registrar/ReloadableRegistrarEvent.java @@ -0,0 +1,39 @@ +package io.papermc.paper.plugin.lifecycle.event.registrar; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jspecify.annotations.NullMarked; + +/** + * A lifecycle event that exposes a {@link Registrar} that is + * reloadable. + * + * @param <R> the registrar type + * @see RegistrarEvent + */ +@ApiStatus.Experimental +@NullMarked +@ApiStatus.NonExtendable +public interface ReloadableRegistrarEvent<R extends Registrar> extends RegistrarEvent<R> { + + /** + * Get the cause of this reload. + * + * @return the cause + */ + @Contract(pure = true) + Cause cause(); + + @ApiStatus.Experimental + enum Cause { + /** + * The initial load of the server. + */ + INITIAL, + /** + * A reload, triggered via one of the various mechanisms like + * the bukkit or minecraft reload commands. + */ + RELOAD + } +} diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventType.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventType.java new file mode 100644 index 0000000000000000000000000000000000000000..75d9e20f53735ead4fa4aec478b4b72b85ca5e1e --- /dev/null +++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventType.java @@ -0,0 +1,74 @@ +package io.papermc.paper.plugin.lifecycle.event.types; + +import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; +import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; +import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; +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.MonitorLifecycleEventHandlerConfiguration; +import io.papermc.paper.plugin.lifecycle.event.handler.configuration.PrioritizedLifecycleEventHandlerConfiguration; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jspecify.annotations.NullMarked; + +/** + * Base type for all types of lifecycle events. Differs from + * {@link LifecycleEvent} which is the actual event object, whereas + * this is an object representing the type of the event. Used + * to construct subtypes of {@link LifecycleEventHandlerConfiguration} for + * use in {@link LifecycleEventManager} + * + * @param <O> the required owner type + * @param <E> the event object type + * @param <C> the configuration type + */ +@ApiStatus.Experimental +@NullMarked +@ApiStatus.NonExtendable +public interface LifecycleEventType<O extends LifecycleEventOwner, E extends LifecycleEvent, C extends LifecycleEventHandlerConfiguration<O>> { + + /** + * Gets the name of the lifecycle event. + * + * @return the name + */ + @Contract(pure = true) + String name(); + + /** + * Create a configuration for this event with the specified + * handler. + * + * @param handler the event handler + * @return a new configuration + * @see LifecycleEventManager#registerEventHandler(LifecycleEventHandlerConfiguration) + */ + @Contract("_ -> new") + C newHandler(LifecycleEventHandler<? super E> handler); + + /** + * Lifecycle event type that supports separate registration + * of handlers as "monitors" that are run last. Useful + * if a plugin wants to only observe the changes other handlers + * made. + * + * @param <O> the required owner type + * @param <E> the event object type + */ + @ApiStatus.Experimental + @ApiStatus.NonExtendable + interface Monitorable<O extends LifecycleEventOwner, E extends LifecycleEvent> extends LifecycleEventType<O, E, MonitorLifecycleEventHandlerConfiguration<O>> { + } + + /** + * Lifecycle event type that supports both {@link Monitorable "monitors"} and + * specific numeric-based priorities. + * + * @param <O> the required owner type + * @param <E> the event object type + */ + @ApiStatus.Experimental + @ApiStatus.NonExtendable + interface Prioritizable<O extends LifecycleEventOwner, E extends LifecycleEvent> extends LifecycleEventType<O, E, PrioritizedLifecycleEventHandlerConfiguration<O>> { + } +} diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProvider.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..e15e09c2a4d3f43db6a0159fa8af6179362ea8d6 --- /dev/null +++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEventTypeProvider.java @@ -0,0 +1,24 @@ +package io.papermc.paper.plugin.lifecycle.event.types; + +import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; +import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; +import java.util.Optional; +import java.util.ServiceLoader; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +@ApiStatus.Internal +@NullMarked +interface LifecycleEventTypeProvider { + + Optional<LifecycleEventTypeProvider> INSTANCE = ServiceLoader.load(LifecycleEventTypeProvider.class) + .findFirst(); + + static LifecycleEventTypeProvider provider() { + return INSTANCE.orElseThrow(); + } + + <O extends LifecycleEventOwner, E extends LifecycleEvent> LifecycleEventType.Monitorable<O, E> monitor(String name, Class<? extends O> ownerType); + + <O extends LifecycleEventOwner, E extends LifecycleEvent> LifecycleEventType.Prioritizable<O, E> prioritized(String name, Class<? extends O> ownerType); +} diff --git a/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEvents.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEvents.java new file mode 100644 index 0000000000000000000000000000000000000000..f70814de0d6c40b2c1c9921b8abdd1162e1d3995 --- /dev/null +++ b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEvents.java @@ -0,0 +1,54 @@ +package io.papermc.paper.plugin.lifecycle.event.types; + +import io.papermc.paper.plugin.bootstrap.BootstrapContext; +import io.papermc.paper.plugin.lifecycle.event.LifecycleEvent; +import io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager; +import io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Holds various types of lifecycle events for + * use when creating event handler configurations + * in {@link LifecycleEventManager}. + */ +@ApiStatus.Experimental +@NullMarked +public final class LifecycleEvents { + + //<editor-fold desc="helper methods" defaultstate="collapsed"> + @ApiStatus.Internal + static <E extends LifecycleEvent> LifecycleEventType.Monitorable<Plugin, E> plugin(final String name) { + return monitor(name, Plugin.class); + } + + @ApiStatus.Internal + static <E extends LifecycleEvent> LifecycleEventType.Prioritizable<Plugin, E> pluginPrioritized(final String name) { + return prioritized(name, Plugin.class); + } + + @ApiStatus.Internal + static <E extends LifecycleEvent> LifecycleEventType.Monitorable<BootstrapContext, E> bootstrap(final String name) { + return monitor(name, BootstrapContext.class); + } + + @ApiStatus.Internal + static <E extends LifecycleEvent> LifecycleEventType.Prioritizable<BootstrapContext, E> bootstrapPrioritized(final String name) { + return prioritized(name, BootstrapContext.class); + } + + @ApiStatus.Internal + static <O extends LifecycleEventOwner, E extends LifecycleEvent, O2 extends O> LifecycleEventType.Monitorable<O, E> monitor(final String name, final Class<O2> ownerType) { + return LifecycleEventTypeProvider.provider().monitor(name, ownerType); + } + + @ApiStatus.Internal + static <O extends LifecycleEventOwner, E extends LifecycleEvent> LifecycleEventType.Prioritizable<O, E> prioritized(final String name, final Class<? extends O> ownerType) { + return LifecycleEventTypeProvider.provider().prioritized(name, ownerType); + } + //</editor-fold> + + private LifecycleEvents() { + } +} diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java index ffe382002c66d7d3fc539c3269261ca1fab4aa2a..159e96b1eedb0c97b624c338fefa1783336483e3 100644 --- a/src/main/java/org/bukkit/UnsafeValues.java +++ b/src/main/java/org/bukkit/UnsafeValues.java @@ -271,4 +271,12 @@ public interface UnsafeValues { */ @Nullable org.bukkit.Color getSpawnEggLayerColor(org.bukkit.entity.EntityType entityType, int layer); // Paper end - spawn egg color visibility + + // Paper start - lifecycle event API + /** + * @hidden + */ + @org.jetbrains.annotations.ApiStatus.Internal + io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager<org.bukkit.plugin.Plugin> createPluginLifecycleEventManager(final org.bukkit.plugin.java.JavaPlugin plugin, final java.util.function.BooleanSupplier registrationCheck); + // Paper end - lifecycle event API } diff --git a/src/main/java/org/bukkit/plugin/Plugin.java b/src/main/java/org/bukkit/plugin/Plugin.java index 46fc37a36403c8fbc4c0c9f863d4d57eb3896bd4..0ff8b53f900092dc419d61a8ede0a7cd72a2e1e1 100644 --- a/src/main/java/org/bukkit/plugin/Plugin.java +++ b/src/main/java/org/bukkit/plugin/Plugin.java @@ -16,7 +16,7 @@ import org.jetbrains.annotations.Nullable; * <p> * The use of {@link PluginBase} is recommended for actual Implementation */ -public interface Plugin extends TabExecutor { +public interface Plugin extends TabExecutor, io.papermc.paper.plugin.lifecycle.event.LifecycleEventOwner { // Paper /** * Returns the folder that the plugin data files are located in. The * folder may not yet exist. @@ -224,4 +224,14 @@ public interface Plugin extends TabExecutor { */ @NotNull public String getName(); + + // Paper start - lifecycle events + /** + * Get the lifecycle event manager for registering handlers + * for lifecycle events allowed on the {@link Plugin}. + * + * @return the lifecycle event manager + */ + io.papermc.paper.plugin.lifecycle.event.@NotNull LifecycleEventManager<Plugin> getLifecycleManager(); + // Paper end - lifecycle events } diff --git a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java index 2d64fc065d53dcd8c01d05215c3e63aaf4428177..e0203f199700c397961a0667a79792497da7f796 100644 --- a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java +++ b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java @@ -48,6 +48,11 @@ public abstract class JavaPlugin extends PluginBase { private FileConfiguration newConfig = null; private File configFile = null; private Logger logger = null; // Paper - PluginLogger -> Logger + // Paper start - lifecycle events + @SuppressWarnings("deprecation") + private final io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager<org.bukkit.plugin.Plugin> lifecycleEventManager = org.bukkit.Bukkit.getUnsafe().createPluginLifecycleEventManager(this, () -> this.allowsLifecycleRegistration); + private boolean allowsLifecycleRegistration = true; + // Paper end public JavaPlugin() { // Paper start @@ -279,7 +284,9 @@ public abstract class JavaPlugin extends PluginBase { isEnabled = enabled; if (isEnabled) { + try { // Paper - lifecycle events onEnable(); + } finally { this.allowsLifecycleRegistration = false; } // Paper - lifecycle events } else { onDisable(); } @@ -457,4 +464,11 @@ public abstract class JavaPlugin extends PluginBase { } return plugin; } + + // Paper start - lifecycle events + @Override + public final io.papermc.paper.plugin.lifecycle.event.@NotNull LifecycleEventManager<org.bukkit.plugin.Plugin> getLifecycleManager() { + return this.lifecycleEventManager; + } + // Paper end - lifecycle events } diff --git a/src/test/java/org/bukkit/plugin/TestPlugin.java b/src/test/java/org/bukkit/plugin/TestPlugin.java index 43b58e920e739bb949ac0673e9ef73ba7b500dc9..affe88cf8e98a787e197936f5fc443464a2343c6 100644 --- a/src/test/java/org/bukkit/plugin/TestPlugin.java +++ b/src/test/java/org/bukkit/plugin/TestPlugin.java @@ -133,4 +133,11 @@ public class TestPlugin extends PluginBase { public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) { throw new UnsupportedOperationException("Not supported."); } + + // Paper start - lifecycle events + @Override + public io.papermc.paper.plugin.lifecycle.event.LifecycleEventManager<Plugin> getLifecycleManager() { + throw new UnsupportedOperationException("Not supported."); + } + // Paper end - lifecycle events }