From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MiniDigger <admin@benndorf.dev>
Date: Fri, 3 Jan 2020 16:24:46 +0100
Subject: [PATCH] Add Mob Goal API


diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java b/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java
new file mode 100644
index 0000000000000000000000000000000000000000..c57c5416c88e2070a082403ab0dda9d7f08d2a57
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java
@@ -0,0 +1,66 @@
+package com.destroystokyo.paper.entity.ai;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.EnumSet;
+
+import org.bukkit.entity.Mob;
+
+/**
+ * Represents an AI goal of an entity
+ */
+public interface Goal<T extends Mob> {
+
+    /**
+     * Checks if this goal should be activated
+     *
+     * @return if this goal should be activated
+     */
+    boolean shouldActivate();
+
+    /**
+     * Checks if this goal should stay active, defaults to {@link Goal#shouldActivate()}
+     *
+     * @return if this goal should stay active
+     */
+    default boolean shouldStayActive() {
+        return shouldActivate();
+    }
+
+    /**
+     * Called when this goal gets activated
+     */
+    default void start() {
+    }
+
+    /**
+     * Called when this goal gets stopped
+     */
+    default void stop() {
+    }
+
+    /**
+     * Called each tick the goal is activated
+     */
+    default void tick() {
+    }
+
+    /**
+     * A unique key that identifies this type of goal. Plugins should use their own namespace, not the minecraft
+     * namespace. Additionally, this key also specifies to what mobs this goal can be applied to
+     *
+     * @return the goal key
+     */
+    @NotNull
+    GoalKey<T> getKey();
+
+    /**
+     * Returns a list of all applicable flags for this goal.<br>
+     *
+     * This method is only called on construction.
+     *
+     * @return the subtypes.
+     */
+    @NotNull
+    EnumSet<GoalType> getTypes();
+}
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java b/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java
new file mode 100644
index 0000000000000000000000000000000000000000..9cd98c6fcfa3eb439d9013ef76ef4661175a0e5a
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java
@@ -0,0 +1,64 @@
+package com.destroystokyo.paper.entity.ai;
+
+import com.google.common.base.Objects;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.StringJoiner;
+
+import org.bukkit.NamespacedKey;
+import org.bukkit.entity.Mob;
+
+/**
+ *
+ * Used to identify a Goal. Consists of a {@link NamespacedKey} and the type of mob the goal can be applied to
+ *
+ * @param <T> the type of mob the goal can be applied to
+ */
+public class GoalKey<T extends Mob> {
+
+    private final Class<T> entityClass;
+    private final NamespacedKey namespacedKey;
+
+    private GoalKey(@NotNull Class<T> entityClass, @NotNull NamespacedKey namespacedKey) {
+        this.entityClass = entityClass;
+        this.namespacedKey = namespacedKey;
+    }
+
+    @NotNull
+    public Class<T> getEntityClass() {
+        return entityClass;
+    }
+
+    @NotNull
+    public NamespacedKey getNamespacedKey() {
+        return namespacedKey;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        GoalKey<?> goalKey = (GoalKey<?>) o;
+        return Objects.equal(entityClass, goalKey.entityClass) &&
+               Objects.equal(namespacedKey, goalKey.namespacedKey);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(entityClass, namespacedKey);
+    }
+
+    @Override
+    public String toString() {
+        return new StringJoiner(", ", GoalKey.class.getSimpleName() + "[", "]")
+            .add("entityClass=" + entityClass)
+            .add("namespacedKey=" + namespacedKey)
+            .toString();
+    }
+
+    @NotNull
+    public static <A extends Mob> GoalKey<A> of(@NotNull Class<A> entityClass, @NotNull NamespacedKey namespacedKey) {
+        return new GoalKey<>(entityClass, namespacedKey);
+    }
+}
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/GoalType.java b/src/main/java/com/destroystokyo/paper/entity/ai/GoalType.java
new file mode 100644
index 0000000000000000000000000000000000000000..7024c8f484d2460abf3abfe65a29771d814105ec
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/GoalType.java
@@ -0,0 +1,17 @@
+package com.destroystokyo.paper.entity.ai;
+
+/**
+ * Represents the subtype of a goal. Used by minecraft to disable certain types of goals if needed.
+ */
+public enum GoalType {
+
+    MOVE,
+    LOOK,
+    JUMP,
+    TARGET,
+    /**
+     * Used to map vanilla goals, that are a behavior goal but don't have a type set...
+     */
+    UNKNOWN_BEHAVIOR,
+
+}
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java
new file mode 100644
index 0000000000000000000000000000000000000000..e21f7574763dd4f13794f91bbef192ef66a8f5e9
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java
@@ -0,0 +1,50 @@
+package com.destroystokyo.paper.entity.ai;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+
+import org.bukkit.entity.Mob;
+
+/**
+ * Represents a part of the "brain" of a mob. It tracks all tasks (running or not), allows adding and removing goals
+ */
+public interface MobGoals {
+
+    <T extends Mob> void addGoal(@NotNull T mob, int priority, @NotNull Goal<T> goal);
+
+    <T extends Mob> void removeGoal(@NotNull T mob, @NotNull Goal<T> goal);
+
+    <T extends Mob> void removeAllGoals(@NotNull T mob);
+
+    <T extends Mob> void removeAllGoals(@NotNull T mob, @NotNull GoalType type);
+
+    <T extends Mob> void removeGoal(@NotNull T mob, @NotNull GoalKey<T> key);
+
+    <T extends Mob> boolean hasGoal(@NotNull T mob, @NotNull GoalKey<T> key);
+
+    @Nullable
+    <T extends Mob> Goal<T> getGoal(@NotNull T mob, @NotNull GoalKey<T> key);
+
+    @NotNull
+    <T extends Mob> Collection<Goal<T>> getGoals(@NotNull T mob, @NotNull GoalKey<T> key);
+
+    @NotNull
+    <T extends Mob> Collection<Goal<T>> getAllGoals(@NotNull T mob);
+
+    @NotNull
+    <T extends Mob> Collection<Goal<T>> getAllGoals(@NotNull T mob, @NotNull GoalType type);
+
+    @NotNull
+    <T extends Mob> Collection<Goal<T>> getAllGoalsWithout(@NotNull T mob, @NotNull GoalType type);
+
+    @NotNull
+    <T extends Mob> Collection<Goal<T>> getRunningGoals(@NotNull T mob);
+
+    @NotNull
+    <T extends Mob> Collection<Goal<T>> getRunningGoals(@NotNull T mob, @NotNull GoalType type);
+
+    @NotNull
+    <T extends Mob> Collection<Goal<T>> getRunningGoalsWithout(@NotNull T mob, @NotNull GoalType type);
+}
diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
index 54626b927444ab3fc6b7d9ac9e326ff368b0cd25..1a671331ec4ab21430d7d52e9a4f45510ef39944 100644
--- a/src/main/java/org/bukkit/Bukkit.java
+++ b/src/main/java/org/bukkit/Bukkit.java
@@ -2560,6 +2560,16 @@ public final class Bukkit {
     public static boolean isStopping() {
         return server.isStopping();
     }
+
+    /**
+     * Returns the {@link com.destroystokyo.paper.entity.ai.MobGoals} manager
+     *
+     * @return the mob goals manager
+     */
+    @NotNull
+    public static com.destroystokyo.paper.entity.ai.MobGoals getMobGoals() {
+        return server.getMobGoals();
+    }
     // Paper end
 
     @NotNull
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
index 0fa9510db6c81e2c712090e1fc7fc56305af8892..7dbd9b32e96c015e3ed757ea0fa7e2bfcf4af85e 100644
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -2232,5 +2232,13 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
      * @return true if server is in the process of being shutdown
      */
     boolean isStopping();
+
+    /**
+     * Returns the {@link com.destroystokyo.paper.entity.ai.MobGoals} manager
+     *
+     * @return the mob goals manager
+     */
+    @NotNull
+    com.destroystokyo.paper.entity.ai.MobGoals getMobGoals();
     // Paper end
 }