mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-18 12:48:53 +01:00
278 lines
12 KiB
Diff
278 lines
12 KiB
Diff
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
|
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||
|
Date: Sun, 12 May 2024 17:30:54 -0700
|
||
|
Subject: [PATCH] Add datapack registration lifecycle event
|
||
|
|
||
|
|
||
|
diff --git a/src/main/java/io/papermc/paper/datapack/Datapack.java b/src/main/java/io/papermc/paper/datapack/Datapack.java
|
||
|
index 233a31afa9673c9cb8d9eb52551425ff15f79661..436606dd81ff666d8378c41f45bbb6a674a477dd 100644
|
||
|
--- a/src/main/java/io/papermc/paper/datapack/Datapack.java
|
||
|
+++ b/src/main/java/io/papermc/paper/datapack/Datapack.java
|
||
|
@@ -95,4 +95,11 @@ public interface Datapack {
|
||
|
TOO_NEW,
|
||
|
COMPATIBLE,
|
||
|
}
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Position of the pack in the load order.
|
||
|
+ */
|
||
|
+ enum Position {
|
||
|
+ TOP, BOTTOM
|
||
|
+ }
|
||
|
}
|
||
|
diff --git a/src/main/java/io/papermc/paper/datapack/DatapackRegistrar.java b/src/main/java/io/papermc/paper/datapack/DatapackRegistrar.java
|
||
|
new file mode 100644
|
||
|
index 0000000000000000000000000000000000000000..456c26c9295a19743fdb8ea6d42ff672836a9e7b
|
||
|
--- /dev/null
|
||
|
+++ b/src/main/java/io/papermc/paper/datapack/DatapackRegistrar.java
|
||
|
@@ -0,0 +1,204 @@
|
||
|
+package io.papermc.paper.datapack;
|
||
|
+
|
||
|
+import io.papermc.paper.plugin.configuration.PluginMeta;
|
||
|
+import io.papermc.paper.plugin.lifecycle.event.registrar.Registrar;
|
||
|
+import java.io.IOException;
|
||
|
+import java.net.URI;
|
||
|
+import java.nio.file.Path;
|
||
|
+import java.util.Map;
|
||
|
+import java.util.function.Consumer;
|
||
|
+import net.kyori.adventure.text.Component;
|
||
|
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||
|
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||
|
+import org.jetbrains.annotations.ApiStatus;
|
||
|
+import org.jetbrains.annotations.Contract;
|
||
|
+import org.jetbrains.annotations.Unmodifiable;
|
||
|
+
|
||
|
+/**
|
||
|
+ * The registrar for datapacks. The event for this registrar
|
||
|
+ * is called anytime the game tries to discover datapacks at any of the
|
||
|
+ * configured locations. This means that if a datapack should stay available to the server,
|
||
|
+ * it must always be discovered whenever this event fires.
|
||
|
+ * <p>An example of a plugin loading a datapack from within it's own jar is below</p>
|
||
|
+ * <pre>{@code
|
||
|
+ * public class YourPluginBootstrap implements PluginBootstrap {
|
||
|
+ * @Override
|
||
|
+ * public void bootstrap(BoostrapContext context) {
|
||
|
+ * final LifecycleEventManager<BootstrapContext> manager = context.getLifecycleManager();
|
||
|
+ * manager.registerEventHandler(LifecycleEvents.DATAPACK_DISCOVERY, event -> {
|
||
|
+ * DatapackRegistrar registrar = event.registrar();
|
||
|
+ * try {
|
||
|
+ * final URI uri = Objects.requireNonNull(
|
||
|
+ * YourPluginBootstrap.class.getResource("/pack")
|
||
|
+ * ).toURI();
|
||
|
+ * registrar.discoverPack(uri, "packId");
|
||
|
+ * } catch (final URISyntaxException | IOException e) {
|
||
|
+ * throw new RuntimeException(e);
|
||
|
+ * }
|
||
|
+ * });
|
||
|
+ * }
|
||
|
+ * }
|
||
|
+ * }</pre>
|
||
|
+ * @see io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents#DATAPACK_DISCOVERY
|
||
|
+ */
|
||
|
+@ApiStatus.NonExtendable
|
||
|
+@ApiStatus.Experimental
|
||
|
+public interface DatapackRegistrar extends Registrar {
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Checks if a datapack with the specified name has been discovered.
|
||
|
+ *
|
||
|
+ * @param name the name of the pack
|
||
|
+ * @return true if the pack has been discovered
|
||
|
+ * @see Datapack#getName()
|
||
|
+ */
|
||
|
+ @Contract(pure = true)
|
||
|
+ boolean hasPackDiscovered(@NonNull String name);
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Gets a discovered datapack by its name.
|
||
|
+ *
|
||
|
+ * @param name the name of the pack
|
||
|
+ * @return the datapack
|
||
|
+ * @throws java.util.NoSuchElementException if the pack is not discovered
|
||
|
+ * @see Datapack#getName()
|
||
|
+ */
|
||
|
+ @Contract(pure = true)
|
||
|
+ @NonNull DiscoveredDatapack getDiscoveredPack(@NonNull String name);
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Removes a discovered datapack by its name.
|
||
|
+ *
|
||
|
+ * @param name the name of the pack
|
||
|
+ * @return true if the pack was removed
|
||
|
+ * @see Datapack#getName()
|
||
|
+ */
|
||
|
+ @Contract(mutates = "this")
|
||
|
+ boolean removeDiscoveredPack(@NonNull String name);
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Gets all discovered datapacks.
|
||
|
+ *
|
||
|
+ * @return an unmodifiable map of discovered packs
|
||
|
+ */
|
||
|
+ @Contract(pure = true)
|
||
|
+ @Unmodifiable @NonNull Map<String, DiscoveredDatapack> getDiscoveredPacks();
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Discovers a datapack at the specified {@link URI} with the id.
|
||
|
+ * <p>Symlinks obey the {@code allowed_symlinks.txt} in the server root directory.</p>
|
||
|
+ *
|
||
|
+ * @param uri the location of the pack
|
||
|
+ * @param id a unique id (will be combined with plugin for the datapacks name)
|
||
|
+ * @return the discovered datapack (or null if it failed)
|
||
|
+ * @throws IOException if any IO error occurs
|
||
|
+ */
|
||
|
+ default @Nullable DiscoveredDatapack discoverPack(final @NonNull URI uri, final @NonNull String id) throws IOException {
|
||
|
+ return this.discoverPack(uri, id, c -> {});
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Discovers a datapack at the specified {@link URI} with the id.
|
||
|
+ * <p>Symlinks obey the {@code allowed_symlinks.txt} in the server root directory.</p>
|
||
|
+ *
|
||
|
+ * @param uri the location of the pack
|
||
|
+ * @param id a unique id (will be combined with plugin for the datapacks name)
|
||
|
+ * @param configurer a configurer for extra options
|
||
|
+ * @return the discovered datapack (or null if it failed)
|
||
|
+ * @throws IOException if any IO error occurs
|
||
|
+ */
|
||
|
+ @Nullable DiscoveredDatapack discoverPack(@NonNull URI uri, @NonNull String id, @NonNull Consumer<Configurer> configurer) throws IOException;
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Discovers a datapack at the specified {@link Path} with the id.
|
||
|
+ * <p>Symlinks obey the {@code allowed_symlinks.txt} in the server root directory.</p>
|
||
|
+ *
|
||
|
+ * @param path the location of the pack
|
||
|
+ * @param id a unique id (will be combined with plugin for the datapacks name)
|
||
|
+ * @return the discovered datapack (or null if it failed)
|
||
|
+ * @throws IOException if any IO error occurs
|
||
|
+ */
|
||
|
+ default @Nullable DiscoveredDatapack discoverPack(final @NonNull Path path, final @NonNull String id) throws IOException {
|
||
|
+ return this.discoverPack(path, id, c -> {});
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Discovers a datapack at the specified {@link Path} with the id.
|
||
|
+ * <p>Symlinks obey the {@code allowed_symlinks.txt} in the server root directory.</p>
|
||
|
+ *
|
||
|
+ * @param path the location of the pack
|
||
|
+ * @param id a unique id (will be combined with plugin for the datapacks name)
|
||
|
+ * @param configurer a configurer for extra options
|
||
|
+ * @return the discovered datapack (or null if it failed)
|
||
|
+ * @throws IOException if any IO error occurs
|
||
|
+ */
|
||
|
+ @Nullable DiscoveredDatapack discoverPack(@NonNull Path path, @NonNull String id, @NonNull Consumer<Configurer> configurer) throws IOException;
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Discovers a datapack at the specified {@link URI} with the id.
|
||
|
+ * <p>Symlinks obey the {@code allowed_symlinks.txt} in the server root directory.</p>
|
||
|
+ *
|
||
|
+ * @param pluginMeta the plugin which will be the "owner" of this datapack
|
||
|
+ * @param uri the location of the pack
|
||
|
+ * @param id a unique id (will be combined with plugin for the datapacks name)
|
||
|
+ * @param configurer a configurer for extra options
|
||
|
+ * @return the discovered datapack (or null if it failed)
|
||
|
+ * @throws IOException if any IO error occurs
|
||
|
+ */
|
||
|
+ @Nullable DiscoveredDatapack discoverPack(@NonNull PluginMeta pluginMeta, @NonNull URI uri, @NonNull String id, @NonNull Consumer<Configurer> configurer) throws IOException;
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Discovers a datapack at the specified {@link Path} with the id.
|
||
|
+ * <p>Symlinks obey the {@code allowed_symlinks.txt} in the server root directory.</p>
|
||
|
+ *
|
||
|
+ * @param pluginMeta the plugin which will be the "owner" of this datapack
|
||
|
+ * @param path the location of the pack
|
||
|
+ * @param id a unique id (will be combined with plugin for the datapacks name)
|
||
|
+ * @param configurer a configurer for extra options
|
||
|
+ * @return the discovered datapack (or null if it failed)
|
||
|
+ * @throws IOException if any IO error occurs
|
||
|
+ */
|
||
|
+ @Nullable DiscoveredDatapack discoverPack(@NonNull PluginMeta pluginMeta, @NonNull Path path, @NonNull String id, @NonNull Consumer<Configurer> configurer) throws IOException;
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Configures additional, optional, details about a datapack.
|
||
|
+ */
|
||
|
+ @ApiStatus.NonExtendable
|
||
|
+ @ApiStatus.Experimental
|
||
|
+ interface Configurer {
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Changes the title of the datapack from the default which
|
||
|
+ * is just the "id" in the {@code registerPack} methods.
|
||
|
+ *
|
||
|
+ * @param title the new title
|
||
|
+ * @return the configurer for chaining
|
||
|
+ */
|
||
|
+ @Contract(value = "_ -> this", mutates = "this")
|
||
|
+ @NonNull Configurer title(@NonNull Component title);
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Sets if this pack is required. Defaults to false.
|
||
|
+ * A required pack cannot be disabled once enabled. Marking
|
||
|
+ * a pack as required <b>does not</b> mean it will immediately be enabled
|
||
|
+ * upon discovery. It may be enabled if this event was fired
|
||
|
+ * due to a pending (re)load.
|
||
|
+ *
|
||
|
+ * @param required true to require the pack
|
||
|
+ * @return the configurer for chaining
|
||
|
+ */
|
||
|
+ @Contract(value = "_ -> this", mutates = "this")
|
||
|
+ @NonNull Configurer required(boolean required);
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Configures the position in the
|
||
|
+ * load order of this datapack.
|
||
|
+ *
|
||
|
+ * @param fixed won't move around in the load order as packs are added/removed
|
||
|
+ * @param position try to insert at the top of the order or bottom
|
||
|
+ * @return the configurer for chaining
|
||
|
+ */
|
||
|
+ @Contract(value = "_, _ -> this", mutates = "this")
|
||
|
+ @NonNull Configurer position(boolean fixed, Datapack.@NonNull Position position);
|
||
|
+ }
|
||
|
+}
|
||
|
diff --git a/src/main/java/io/papermc/paper/datapack/DiscoveredDatapack.java b/src/main/java/io/papermc/paper/datapack/DiscoveredDatapack.java
|
||
|
new file mode 100644
|
||
|
index 0000000000000000000000000000000000000000..f0ec90fd08e984995fd3fe48ae3219ce08e2d40a
|
||
|
--- /dev/null
|
||
|
+++ b/src/main/java/io/papermc/paper/datapack/DiscoveredDatapack.java
|
||
|
@@ -0,0 +1,8 @@
|
||
|
+package io.papermc.paper.datapack;
|
||
|
+
|
||
|
+public interface DiscoveredDatapack {
|
||
|
+
|
||
|
+ String getName();
|
||
|
+
|
||
|
+ Datapack.Compatibility getCompatibility();
|
||
|
+}
|
||
|
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
|
||
|
index 720fe2546015838708ce794c291ca187cf7bca9c..6dce88760b954bc898bdc05a64081b1dd1737c3c 100644
|
||
|
--- 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
|
||
|
@@ -1,10 +1,12 @@
|
||
|
package io.papermc.paper.plugin.lifecycle.event.types;
|
||
|
|
||
|
import io.papermc.paper.command.brigadier.Commands;
|
||
|
+import io.papermc.paper.datapack.DatapackRegistrar;
|
||
|
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 io.papermc.paper.plugin.lifecycle.event.registrar.RegistrarEvent;
|
||
|
import io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent;
|
||
|
import org.bukkit.plugin.Plugin;
|
||
|
import org.jetbrains.annotations.ApiStatus;
|
||
|
@@ -30,6 +32,13 @@ public final class LifecycleEvents {
|
||
|
*/
|
||
|
public static final TagEventTypeProvider TAGS = LifecycleEventTypeProvider.provider().tagProvider();
|
||
|
|
||
|
+ /**
|
||
|
+ * This event is for informing the server about any available datapacks from other sources such as inside a plugin's jar. You
|
||
|
+ * can register a handler for this event only in {@link io.papermc.paper.plugin.bootstrap.PluginBootstrap#bootstrap(BootstrapContext)}.
|
||
|
+ * @see DatapackRegistrar an example of a datapack being discovered
|
||
|
+ */
|
||
|
+ public static final LifecycleEventType.Prioritizable<BootstrapContext, RegistrarEvent<DatapackRegistrar>> DATAPACK_DISCOVERY = bootstrapPrioritized("datapack_discovery");
|
||
|
+
|
||
|
//<editor-fold desc="helper methods" defaultstate="collapsed">
|
||
|
@ApiStatus.Internal
|
||
|
static <E extends LifecycleEvent> LifecycleEventType.Monitorable<Plugin, E> plugin(final String name) {
|