Paper/patches/api/0187-Add-Mob-Goal-API.patch
2024-12-03 17:58:41 +01:00

251 lines
7.9 KiB
Diff

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..88f64a84c6b81246a4936e37c9f0410eefc847fd
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java
@@ -0,0 +1,63 @@
+package com.destroystokyo.paper.entity.ai;
+
+import java.util.EnumSet;
+import org.bukkit.entity.Mob;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Represents an AI goal of an entity
+ */
+@NullMarked
+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 this.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
+ */
+ GoalKey<T> getKey();
+
+ /**
+ * Returns a list of all applicable flags for this goal.<br>
+ * <p>
+ * This method is only called on construction.
+ *
+ * @return the subtypes.
+ */
+ 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..fb626065c642a3f43075f2ae751419e23431763c
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java
@@ -0,0 +1,59 @@
+package com.destroystokyo.paper.entity.ai;
+
+import com.google.common.base.Objects;
+import java.util.StringJoiner;
+import org.bukkit.NamespacedKey;
+import org.bukkit.entity.Mob;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * 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
+ */
+@NullMarked
+public final class GoalKey<T extends Mob> {
+
+ private final Class<T> entityClass;
+ private final NamespacedKey namespacedKey;
+
+ private GoalKey(Class<T> entityClass, NamespacedKey namespacedKey) {
+ this.entityClass = entityClass;
+ this.namespacedKey = namespacedKey;
+ }
+
+ public Class<T> getEntityClass() {
+ return this.entityClass;
+ }
+
+ public NamespacedKey getNamespacedKey() {
+ return this.namespacedKey;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || this.getClass() != o.getClass()) return false;
+ GoalKey<?> goalKey = (GoalKey<?>) o;
+ return Objects.equal(this.entityClass, goalKey.entityClass) &&
+ Objects.equal(this.namespacedKey, goalKey.namespacedKey);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(this.entityClass, this.namespacedKey);
+ }
+
+ @Override
+ public String toString() {
+ return new StringJoiner(", ", GoalKey.class.getSimpleName() + "[", "]")
+ .add("entityClass=" + this.entityClass)
+ .add("namespacedKey=" + this.namespacedKey)
+ .toString();
+ }
+
+ public static <A extends Mob> GoalKey<A> of(Class<A> entityClass, 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..0203e7efbb8c729ed378c53c2630a523b697314f
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java
@@ -0,0 +1,42 @@
+package com.destroystokyo.paper.entity.ai;
+
+
+import java.util.Collection;
+import org.bukkit.entity.Mob;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Represents a part of the "brain" of a mob. It tracks all tasks (running or not), allows adding and removing goals
+ */
+@NullMarked
+public interface MobGoals {
+
+ <T extends Mob> void addGoal(T mob, int priority, Goal<T> goal);
+
+ <T extends Mob> void removeGoal(T mob, Goal<T> goal);
+
+ <T extends Mob> void removeAllGoals(T mob);
+
+ <T extends Mob> void removeAllGoals(T mob, GoalType type);
+
+ <T extends Mob> void removeGoal(T mob, GoalKey<T> key);
+
+ <T extends Mob> boolean hasGoal(T mob, GoalKey<T> key);
+
+ <T extends Mob> @Nullable Goal<T> getGoal(T mob, GoalKey<T> key);
+
+ <T extends Mob> Collection<Goal<T>> getGoals(T mob, GoalKey<T> key);
+
+ <T extends Mob> Collection<Goal<T>> getAllGoals(T mob);
+
+ <T extends Mob> Collection<Goal<T>> getAllGoals(T mob, GoalType type);
+
+ <T extends Mob> Collection<Goal<T>> getAllGoalsWithout(T mob, GoalType type);
+
+ <T extends Mob> Collection<Goal<T>> getRunningGoals(T mob);
+
+ <T extends Mob> Collection<Goal<T>> getRunningGoals(T mob, GoalType type);
+
+ <T extends Mob> Collection<Goal<T>> getRunningGoalsWithout(T mob, GoalType type);
+}
diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
index 40d04b4ebecaa0cff8937451568d998a0dfae088..aca049c29cc7397a830883a45b4b24a33863e533 100644
--- a/src/main/java/org/bukkit/Bukkit.java
+++ b/src/main/java/org/bukkit/Bukkit.java
@@ -2584,6 +2584,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 90509d2e4c61de29611312c0864ef7622072d540..89208165cc6b864a9273c364ba4b2d6d86e3c31f 100644
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -2250,5 +2250,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
}