From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Connor Linfoot <connorlinfoot@me.com>
Date: Sun, 16 May 2021 15:07:34 +0100
Subject: [PATCH] Add basic Datapack API

Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>

diff --git a/src/main/java/io/papermc/paper/datapack/Datapack.java b/src/main/java/io/papermc/paper/datapack/Datapack.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/datapack/Datapack.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.datapack;
+
+import java.util.Set;
+import net.kyori.adventure.text.Component;
+import org.bukkit.FeatureFlag;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Unmodifiable;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * This is a snapshot of a datapack on the server. It
+ * won't be updated as datapacks are updated.
+ */
+@NullMarked
+public interface Datapack {
+
+    /**
+     * Gets the name/id of this datapack.
+     *
+     * @return the name of the pack
+     */
+    @Contract(pure = true)
+    String getName();
+
+    /**
+     * Gets the title component of this datapack.
+     *
+     * @return the title
+     */
+    Component getTitle();
+
+    /**
+     * Gets the description component of this datapack.
+     *
+     * @return the description
+     */
+    Component getDescription();
+
+    /**
+     * Gets if this datapack is required to be enabled.
+     *
+     * @return true if the pack is required
+     */
+    boolean isRequired();
+
+    /**
+     * Gets the compatibility status of this pack.
+     *
+     * @return the compatibility of the pack
+     */
+    Compatibility getCompatibility();
+
+    /**
+     * Gets the set of required features for this datapack.
+     *
+     * @return the set of required features
+     */
+    @Unmodifiable Set<FeatureFlag> getRequiredFeatures();
+
+    /**
+     * Gets the enabled state of this pack.
+     *
+     * @return whether the pack is currently enabled
+     */
+    boolean isEnabled();
+
+    /**
+     * Changes the enabled state of this pack. Will
+     * cause a reload of resources ({@code /minecraft:reload}) if
+     * any change happens.
+     *
+     * @param enabled true to enable, false to disable
+     * @apiNote This method may be deprecated in the future as setters on a "snapshot" type are undesirable.
+     */
+    void setEnabled(boolean enabled);
+
+    /**
+     * Gets the source for this datapack.
+     *
+     * @return the pack source
+     */
+    DatapackSource getSource();
+
+    /**
+     * Computes the component vanilla Minecraft uses
+     * to display this datapack. Includes the {@link #getSource()},
+     * {@link #getDescription()}, {@link #getName()}, and the enabled state.
+     *
+     * @return a new component
+     */
+    @Contract(pure = true, value = "-> new")
+    Component computeDisplayName();
+
+    enum Compatibility {
+        TOO_OLD,
+        TOO_NEW,
+        COMPATIBLE,
+    }
+}
diff --git a/src/main/java/io/papermc/paper/datapack/DatapackManager.java b/src/main/java/io/papermc/paper/datapack/DatapackManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/datapack/DatapackManager.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.datapack;
+
+import java.util.Collection;
+import org.jetbrains.annotations.Unmodifiable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+@NullMarked
+public interface DatapackManager {
+
+    /**
+     * Triggers a refresh of the available and selected datapacks. This
+     * can find new datapacks, remove old ones, and update the metadata for
+     * existing datapacks. Some of these changes will only take effect
+     * after the next {@link org.bukkit.Server#reloadData()} or {@code /minecraft:reload}.
+     */
+    void refreshPacks();
+
+    /**
+     * Gets a datapack by name. May require calling {@link #refreshPacks()} before
+     * to get the latest pack information.
+     *
+     * @param name the name/id of the datapack
+     * @return the datapack, or null if not found
+     */
+    @Nullable Datapack getPack(String name);
+
+    /**
+     * Gets the available datapacks. May require calling {@link #refreshPacks()} before
+     * to get the latest pack information.
+     *
+     * @return all the packs known to the server
+     */
+    @Unmodifiable Collection<Datapack> getPacks();
+
+    /**
+     * Gets the enabled datapacks. May require calling {@link #refreshPacks()} before
+     * to get the latest pack information.
+     *
+     * @return all the packs which are currently enabled
+     */
+    @Unmodifiable Collection<Datapack> getEnabledPacks();
+}
diff --git a/src/main/java/io/papermc/paper/datapack/DatapackSource.java b/src/main/java/io/papermc/paper/datapack/DatapackSource.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/datapack/DatapackSource.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.datapack;
+
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Source of a datapack.
+ */
+@NullMarked
+public sealed interface DatapackSource permits DatapackSourceImpl {
+
+    DatapackSource DEFAULT = create("default");
+    DatapackSource BUILT_IN = create("built_in");
+    DatapackSource FEATURE = create("feature");
+    DatapackSource WORLD = create("world");
+    DatapackSource SERVER = create("server");
+
+    private static DatapackSource create(final String name) {
+        return new DatapackSourceImpl(name);
+    }
+}
diff --git a/src/main/java/io/papermc/paper/datapack/DatapackSourceImpl.java b/src/main/java/io/papermc/paper/datapack/DatapackSourceImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/datapack/DatapackSourceImpl.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.datapack;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+@ApiStatus.Internal
+@NullMarked
+record DatapackSourceImpl(String name) implements DatapackSource {
+
+    @Override
+    public String toString() {
+        return this.name;
+    }
+}
diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/Bukkit.java
+++ b/src/main/java/org/bukkit/Bukkit.java
@@ -0,0 +0,0 @@ public final class Bukkit {
     /**
      * Get the DataPack Manager.
      *
+     * @deprecated use {@link #getDatapackManager()}
      * @return the manager
      */
     @NotNull
+    @Deprecated(forRemoval = true, since = "1.20")
     public static DataPackManager getDataPackManager() {
         return server.getDataPackManager();
     }
@@ -0,0 +0,0 @@ public final class Bukkit {
     public static com.destroystokyo.paper.entity.ai.MobGoals getMobGoals() {
         return server.getMobGoals();
     }
+
+    /**
+     * @return the datapack manager
+     */
+    @NotNull
+    public static io.papermc.paper.datapack.DatapackManager getDatapackManager() {
+        return server.getDatapackManager();
+    }
     // Paper end
 
     @NotNull
diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/Material.java
+++ b/src/main/java/org/bukkit/Material.java
@@ -0,0 +0,0 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla
      * @param world the world to check
      * @return true if this material can be used in this World.
      */
+    @Deprecated(forRemoval = true, since = "1.20") // Paper
     public boolean isEnabledByFeature(@NotNull World world) {
         if (isItem()) {
             return Bukkit.getDataPackManager().isEnabledByFeature(asItemType(), world);
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -0,0 +0,0 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
     /**
      * Get the DataPack Manager.
      *
+     * @deprecated use {@link #getDatapackManager()}
      * @return the manager
      */
     @NotNull
+    @Deprecated(forRemoval = true, since = "1.20") // Paper
     public DataPackManager getDataPackManager();
 
     /**
@@ -0,0 +0,0 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
      */
     @NotNull
     com.destroystokyo.paper.entity.ai.MobGoals getMobGoals();
+
+    /**
+     * @return the datapack manager
+     */
+    @NotNull
+    io.papermc.paper.datapack.DatapackManager getDatapackManager();
     // Paper end
 }
diff --git a/src/main/java/org/bukkit/entity/EntityType.java b/src/main/java/org/bukkit/entity/EntityType.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/entity/EntityType.java
+++ b/src/main/java/org/bukkit/entity/EntityType.java
@@ -0,0 +0,0 @@ public enum EntityType implements Keyed, Translatable, net.kyori.adventure.trans
      * @param world the world to check
      * @return true if this EntityType can be used to spawn an Entity for this World.
      */
+    @Deprecated(forRemoval = true, since = "1.20") // Paper
     public boolean isEnabledByFeature(@NotNull World world) {
         return Bukkit.getDataPackManager().isEnabledByFeature(this, world);
     }
diff --git a/src/main/java/org/bukkit/packs/DataPack.java b/src/main/java/org/bukkit/packs/DataPack.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/packs/DataPack.java
+++ b/src/main/java/org/bukkit/packs/DataPack.java
@@ -0,0 +0,0 @@ import org.jetbrains.annotations.NotNull;
  * Represents a data pack.
  *
  * @see <a href="https://minecraft.wiki/w/Data_pack">Minecraft wiki</a>
+ * @deprecated use {@link io.papermc.paper.datapack.Datapack}
  */
+@Deprecated(forRemoval = true, since = "1.20") // Paper
 public interface DataPack extends Keyed {
 
     /**
diff --git a/src/main/java/org/bukkit/packs/DataPackManager.java b/src/main/java/org/bukkit/packs/DataPackManager.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/packs/DataPackManager.java
+++ b/src/main/java/org/bukkit/packs/DataPackManager.java
@@ -0,0 +0,0 @@ import org.jetbrains.annotations.Nullable;
 
 /**
  * Manager of data packs.
+ * @deprecated use {@link io.papermc.paper.datapack.DatapackManager}
  */
+@Deprecated(forRemoval = true, since = "1.20") // Paper
 public interface DataPackManager {
 
     /**