mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-24 19:46:21 +01:00
267 lines
9.4 KiB
Diff
267 lines
9.4 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Aikar <aikar@aikar.co>
|
|
Date: Sun, 9 Sep 2018 12:39:06 -0400
|
|
Subject: [PATCH] Mob Pathfinding API
|
|
|
|
Adds an API to allow plugins to instruct a Mob to Pathfind to a Location or Entity
|
|
|
|
This does not do anything to stop other AI rules from changing the location, so
|
|
it is still up to the plugin to control that or override after another goal changed
|
|
the location.
|
|
|
|
You can use EntityPathfindEvent to cancel new pathfinds from overriding your current.
|
|
|
|
diff --git a/src/main/java/com/destroystokyo/paper/entity/Pathfinder.java b/src/main/java/com/destroystokyo/paper/entity/Pathfinder.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..5f6d6e222f9f1ac1648a11b6d4a240371c4f07e9
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/entity/Pathfinder.java
|
|
@@ -0,0 +1,221 @@
|
|
+package com.destroystokyo.paper.entity;
|
|
+
|
|
+import java.util.List;
|
|
+import org.bukkit.Location;
|
|
+import org.bukkit.entity.LivingEntity;
|
|
+import org.bukkit.entity.Mob;
|
|
+import org.jspecify.annotations.NullMarked;
|
|
+import org.jspecify.annotations.Nullable;
|
|
+
|
|
+/**
|
|
+ * Handles pathfinding operations for an Entity
|
|
+ */
|
|
+@NullMarked
|
|
+public interface Pathfinder {
|
|
+
|
|
+ /**
|
|
+ * @return The entity that is controlled by this pathfinder
|
|
+ */
|
|
+ Mob getEntity();
|
|
+
|
|
+ /**
|
|
+ * Instructs the Entity to stop trying to navigate to its current desired location
|
|
+ */
|
|
+ void stopPathfinding();
|
|
+
|
|
+ /**
|
|
+ * If the entity is currently trying to navigate to a destination, this will return true
|
|
+ *
|
|
+ * @return true if the entity is navigating to a destination
|
|
+ */
|
|
+ boolean hasPath();
|
|
+
|
|
+ /**
|
|
+ * @return The location the entity is trying to navigate to, or null if there is no destination
|
|
+ */
|
|
+ @Nullable PathResult getCurrentPath();
|
|
+
|
|
+ /**
|
|
+ * Calculates a destination for the Entity to navigate to, but does not set it
|
|
+ * as the current target. Useful for calculating what would happen before setting it.
|
|
+ *
|
|
+ * @param loc Location to navigate to
|
|
+ * @return The closest Location the Entity can get to for this navigation, or null if no path could be calculated
|
|
+ */
|
|
+ @Nullable PathResult findPath(Location loc);
|
|
+
|
|
+ /**
|
|
+ * Calculates a destination for the Entity to navigate to to reach the target entity,
|
|
+ * but does not set it as the current target.
|
|
+ * Useful for calculating what would happen before setting it.
|
|
+ * <p>
|
|
+ * The behavior of this PathResult is subject to the games pathfinding rules, and may
|
|
+ * result in the pathfinding automatically updating to follow the target Entity.
|
|
+ * <p>
|
|
+ * However, this behavior is not guaranteed, and is subject to the games behavior.
|
|
+ *
|
|
+ * @param target the Entity to navigate to
|
|
+ * @return The closest Location the Entity can get to for this navigation, or null if no path could be calculated
|
|
+ */
|
|
+ @Nullable PathResult findPath(LivingEntity target);
|
|
+
|
|
+ /**
|
|
+ * Calculates a destination for the Entity to navigate to, and sets it with default speed
|
|
+ * as the current target.
|
|
+ *
|
|
+ * @param loc Location to navigate to
|
|
+ * @return If the pathfinding was successfully started
|
|
+ */
|
|
+ default boolean moveTo(Location loc) {
|
|
+ return this.moveTo(loc, 1);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Calculates a destination for the Entity to navigate to, with desired speed
|
|
+ * as the current target.
|
|
+ *
|
|
+ * @param loc Location to navigate to
|
|
+ * @param speed Speed multiplier to navigate at, where 1 is 'normal'
|
|
+ * @return If the pathfinding was successfully started
|
|
+ */
|
|
+ default boolean moveTo(Location loc, double speed) {
|
|
+ PathResult path = this.findPath(loc);
|
|
+ return path != null && this.moveTo(path, speed);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Calculates a destination for the Entity to navigate to to reach the target entity,
|
|
+ * and sets it with default speed.
|
|
+ * <p>
|
|
+ * The behavior of this PathResult is subject to the games pathfinding rules, and may
|
|
+ * result in the pathfinding automatically updating to follow the target Entity.
|
|
+ * <p>
|
|
+ * However, this behavior is not guaranteed, and is subject to the games behavior.
|
|
+ *
|
|
+ * @param target the Entity to navigate to
|
|
+ * @return If the pathfinding was successfully started
|
|
+ */
|
|
+ default boolean moveTo(LivingEntity target) {
|
|
+ return this.moveTo(target, 1);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Calculates a destination for the Entity to navigate to to reach the target entity,
|
|
+ * and sets it with specified speed.
|
|
+ * <p>
|
|
+ * The behavior of this PathResult is subject to the games pathfinding rules, and may
|
|
+ * result in the pathfinding automatically updating to follow the target Entity.
|
|
+ * <p>
|
|
+ * However, this behavior is not guaranteed, and is subject to the games behavior.
|
|
+ *
|
|
+ * @param target the Entity to navigate to
|
|
+ * @param speed Speed multiplier to navigate at, where 1 is 'normal'
|
|
+ * @return If the pathfinding was successfully started
|
|
+ */
|
|
+ default boolean moveTo(LivingEntity target, double speed) {
|
|
+ PathResult path = this.findPath(target);
|
|
+ return path != null && this.moveTo(path, speed);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Takes the result of a previous pathfinding calculation and sets it
|
|
+ * as the active pathfinding with default speed.
|
|
+ *
|
|
+ * @param path The Path to start following
|
|
+ * @return If the pathfinding was successfully started
|
|
+ */
|
|
+ default boolean moveTo(PathResult path) {
|
|
+ return this.moveTo(path, 1);
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Takes the result of a previous pathfinding calculation and sets it
|
|
+ * as the active pathfinding,
|
|
+ *
|
|
+ * @param path The Path to start following
|
|
+ * @param speed Speed multiplier to navigate at, where 1 is 'normal'
|
|
+ * @return If the pathfinding was successfully started
|
|
+ */
|
|
+ boolean moveTo(PathResult path, double speed);
|
|
+
|
|
+ /**
|
|
+ * Checks if this pathfinder allows passing through closed doors.
|
|
+ *
|
|
+ * @return if this pathfinder allows passing through closed doors
|
|
+ */
|
|
+ boolean canOpenDoors();
|
|
+
|
|
+ /**
|
|
+ * Allows this pathfinder to pass through closed doors, or not
|
|
+ *
|
|
+ * @param canOpenDoors if the mob can pass through closed doors, or not
|
|
+ */
|
|
+ void setCanOpenDoors(boolean canOpenDoors);
|
|
+
|
|
+ /**
|
|
+ * Checks if this pathfinder allows passing through open doors.
|
|
+ *
|
|
+ * @return if this pathfinder allows passing through open doors
|
|
+ */
|
|
+ boolean canPassDoors();
|
|
+
|
|
+ /**
|
|
+ * Allows this pathfinder to pass through open doors, or not
|
|
+ *
|
|
+ * @param canPassDoors if the mob can pass through open doors, or not
|
|
+ */
|
|
+ void setCanPassDoors(boolean canPassDoors);
|
|
+
|
|
+ /**
|
|
+ * Checks if this pathfinder assumes that the mob can float
|
|
+ *
|
|
+ * @return if this pathfinder assumes that the mob can float
|
|
+ */
|
|
+ boolean canFloat();
|
|
+
|
|
+ /**
|
|
+ * Makes this pathfinder assume that the mob can float, or not
|
|
+ *
|
|
+ * @param canFloat if the mob can float, or not
|
|
+ */
|
|
+ void setCanFloat(boolean canFloat);
|
|
+
|
|
+ /**
|
|
+ * Represents the result of a pathfinding calculation
|
|
+ */
|
|
+ interface PathResult {
|
|
+
|
|
+ /**
|
|
+ * All currently calculated points to follow along the path to reach the destination location
|
|
+ * <p>
|
|
+ * Will return points the entity has already moved past, see {@link #getNextPointIndex()}
|
|
+ *
|
|
+ * @return List of points
|
|
+ */
|
|
+ List<Location> getPoints();
|
|
+
|
|
+ /**
|
|
+ * @return Returns the index of the current point along the points returned in {@link #getPoints()} the entity
|
|
+ * is trying to reach. This value will be higher than the maximum index of {@link #getPoints()} if this path finding is done.
|
|
+ */
|
|
+ int getNextPointIndex();
|
|
+
|
|
+ /**
|
|
+ * @return The next location in the path points the entity is trying to reach, or null if there is no next point
|
|
+ */
|
|
+ @Nullable Location getNextPoint();
|
|
+
|
|
+ /**
|
|
+ * @return The closest point the path can get to the target location
|
|
+ */
|
|
+ @Nullable Location getFinalPoint();
|
|
+
|
|
+ /**
|
|
+ * Checks whether the final point can be reached
|
|
+ *
|
|
+ * @return whether the final point can be reached
|
|
+ * @see #getFinalPoint()
|
|
+ */
|
|
+ boolean canReachFinalPoint();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/org/bukkit/entity/Mob.java b/src/main/java/org/bukkit/entity/Mob.java
|
|
index ad5dbf310fe7b34c997bb339f09697222f862005..63a14bec00d0b23431d1d002139f48a7d0bc2a88 100644
|
|
--- a/src/main/java/org/bukkit/entity/Mob.java
|
|
+++ b/src/main/java/org/bukkit/entity/Mob.java
|
|
@@ -2,6 +2,7 @@ package org.bukkit.entity;
|
|
|
|
import org.bukkit.Sound;
|
|
import org.bukkit.loot.Lootable;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
/**
|
|
@@ -12,6 +13,13 @@ public interface Mob extends LivingEntity, Lootable {
|
|
// Paper start
|
|
@Override
|
|
org.bukkit.inventory.@org.jetbrains.annotations.NotNull EntityEquipment getEquipment();
|
|
+
|
|
+ /**
|
|
+ * Enables access to control the pathing of an Entity
|
|
+ * @return Pathfinding Manager for this entity
|
|
+ */
|
|
+ @NotNull
|
|
+ com.destroystokyo.paper.entity.Pathfinder getPathfinder();
|
|
// Paper end
|
|
/**
|
|
* Instructs this Mob to set the specified LivingEntity as its target.
|