Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add datapack registration lifecycle event #10711

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
211 changes: 211 additions & 0 deletions patches/api/0477-Add-datapack-registration-lifecycle-event.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
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 7b2ab0be10a21e0496ad1d485ff8cb2c0b92a2cb..e6037cc5b79b5206e5da8d53c5009932e7c81c86 100644
--- a/src/main/java/io/papermc/paper/datapack/Datapack.java
+++ b/src/main/java/io/papermc/paper/datapack/Datapack.java
@@ -29,4 +29,10 @@ public interface Datapack {
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..099383a3649f53cd17b01769f562fae878c73579
--- /dev/null
+++ b/src/main/java/io/papermc/paper/datapack/DatapackRegistrar.java
@@ -0,0 +1,153 @@
+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.function.Consumer;
+import net.kyori.adventure.text.Component;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+
+/**
+ * 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 {
+
+ /**
+ * 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
+ * @throws IOException if any IO error occurs
+ */
+ default void discoverPack(final @NonNull URI uri, final @NonNull String id) throws IOException {
+ 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
+ * @param configurer a configurer for extra options
+ * @throws IOException if any IO error occurs
+ */
+ void 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
+ * @throws IOException if any IO error occurs
+ */
+ default void discoverPack(final @NonNull Path path, final @NonNull String id) throws IOException {
+ 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
+ * @param configurer a configurer for extra options
+ * @throws IOException if any IO error occurs
+ */
+ void 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
+ * @param configurer a configurer for extra options
+ * @throws IOException if any IO error occurs
+ */
+ void 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
+ * @param configurer a configurer for extra options
+ * @throws IOException if any IO error occurs
+ */
+ void 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.
+ *
+ * @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/plugin/lifecycle/event/types/LifecycleEvents.java b/src/main/java/io/papermc/paper/plugin/lifecycle/event/types/LifecycleEvents.java
index 1fab48593c567fe05b085ac6e12dc22556cf0b92..dcff07f8fe1627662726611602bd0f8213e39133 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;
@@ -24,6 +26,13 @@ public final class LifecycleEvents {
*/
public static final LifecycleEventType.Prioritizable<LifecycleEventOwner, ReloadableRegistrarEvent<Commands>> COMMANDS = prioritized("commands", LifecycleEventOwner.class);

+ /**
+ * 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 = prioritized("datapack_discovery", BootstrapContext.class);
+
//<editor-fold desc="helper methods" defaultstate="collapsed">
@ApiStatus.Internal
private static <E extends LifecycleEvent> LifecycleEventType.Monitorable<Plugin, E> plugin(final String name) {
Loading
Loading