1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 9 Sep 2018 13:30:00 -0400
Subject: [PATCH] Mob Pathfinding API
Implements Pathfinding API for mobs
diff --git a/src/main/java/com/destroystokyo/paper/entity/PaperPathfinder.java b/src/main/java/com/destroystokyo/paper/entity/PaperPathfinder.java
new file mode 100644
index 0000000000000000000000000000000000000000..8c9f0c6c38627beded373ca29f1989ae3ba6f873
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/PaperPathfinder.java
@@ -0,0 +1,139 @@
+package com.destroystokyo.paper.entity;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.entity.CraftLivingEntity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Mob;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import net.minecraft.world.level.pathfinder.Node;
+import net.minecraft.world.level.pathfinder.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+public class PaperPathfinder implements com.destroystokyo.paper.entity.Pathfinder {
+
+ private final net.minecraft.world.entity.Mob entity;
+
+ public PaperPathfinder(net.minecraft.world.entity.Mob entity) {
+ this.entity = entity;
+ }
+
+ @Override
+ public Mob getEntity() {
+ return entity.getBukkitMob();
+ }
+
+ @Override
+ public void stopPathfinding() {
+ entity.getNavigation().stop();
+ }
+
+ @Override
+ public boolean hasPath() {
+ return entity.getNavigation().getPath() != null;
+ }
+
+ @Nullable
+ @Override
+ public PathResult getCurrentPath() {
+ Path path = entity.getNavigation().getPath();
+ return path != null ? new PaperPathResult(path) : null;
+ }
+
+ @Nullable
+ @Override
+ public PathResult findPath(Location loc) {
+ Validate.notNull(loc, "Location can not be null");
+ Path path = entity.getNavigation().createPath(loc.getX(), loc.getY(), loc.getZ(), 0);
+ return path != null ? new PaperPathResult(path) : null;
+ }
+
+ @Nullable
+ @Override
+ public PathResult findPath(LivingEntity target) {
+ Validate.notNull(target, "Target can not be null");
+ Path path = entity.getNavigation().createPath(((CraftLivingEntity) target).getHandle(), 0);
+ return path != null ? new PaperPathResult(path) : null;
+ }
+
+ @Override
+ public boolean moveTo(@Nonnull PathResult path, double speed) {
+ Validate.notNull(path, "PathResult can not be null");
+ Path pathEntity = ((PaperPathResult) path).path;
+ return entity.getNavigation().moveTo(pathEntity, speed);
+ }
+
+ @Override
+ public boolean canOpenDoors() {
+ return entity.getNavigation().pathFinder.nodeEvaluator.canOpenDoors();
+ }
+
+ @Override
+ public void setCanOpenDoors(boolean canOpenDoors) {
+ entity.getNavigation().pathFinder.nodeEvaluator.setCanOpenDoors(canOpenDoors);
+ }
+
+ @Override
+ public boolean canPassDoors() {
+ return entity.getNavigation().pathFinder.nodeEvaluator.canPassDoors();
+ }
+
+ @Override
+ public void setCanPassDoors(boolean canPassDoors) {
+ entity.getNavigation().pathFinder.nodeEvaluator.setCanPassDoors(canPassDoors);
+ }
+
+ @Override
+ public boolean canFloat() {
+ return entity.getNavigation().pathFinder.nodeEvaluator.canFloat();
+ }
+
+ @Override
+ public void setCanFloat(boolean canFloat) {
+ entity.getNavigation().pathFinder.nodeEvaluator.setCanFloat(canFloat);
+ }
+
+ public class PaperPathResult implements com.destroystokyo.paper.entity.PaperPathfinder.PathResult {
+
+ private final Path path;
+ PaperPathResult(Path path) {
+ this.path = path;
+ }
+
+ @Nullable
+ @Override
+ public Location getFinalPoint() {
+ Node point = path.getEndNode();
+ return point != null ? toLoc(point) : null;
+ }
+
+ @Override
+ public List<Location> getPoints() {
+ List<Location> points = new ArrayList<>();
+ for (Node point : path.nodes) {
+ points.add(toLoc(point));
+ }
+ return points;
+ }
+
+ @Override
+ public int getNextPointIndex() {
+ return path.getNextNodeIndex();
+ }
+
+ @Nullable
+ @Override
+ public Location getNextPoint() {
+ if (!path.hasNext()) {
+ return null;
+ }
+ return toLoc(path.nodes.get(path.getNextNodeIndex()));
+ }
+ }
+
+ private Location toLoc(Node point) {
+ return new Location(entity.level.getWorld(), point.x, point.y, point.z);
+ }
+}
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/Path.java b/src/main/java/net/minecraft/world/level/pathfinder/Path.java
index 4ad2ac8d1e9111933fa58c47442fa1f5e8173fd3..2a335f277bd0e4b8ad0f60d8226eb8aaa80a871f 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/Path.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/Path.java
@@ -21,6 +21,7 @@ public class Path {
private final BlockPos target;
private final float distToTarget;
private final boolean reached;
+ public boolean hasNext() { return getNextNodeIndex() < this.nodes.size(); } // Paper
public Path(List<Node> nodes, BlockPos target, boolean reachesTarget) {
this.nodes = nodes;
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java
index 219bdf53a860628335efe92d4f294a5fa52087b2..b0d348061487110993b6c4c8a7dc7208f27361b3 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java
@@ -12,8 +12,11 @@ import org.bukkit.loot.LootTable;
public abstract class CraftMob extends CraftLivingEntity implements Mob {
public CraftMob(CraftServer server, net.minecraft.world.entity.Mob entity) {
super(server, entity);
+ paperPathfinder = new com.destroystokyo.paper.entity.PaperPathfinder(entity); // Paper
}
+ private final com.destroystokyo.paper.entity.PaperPathfinder paperPathfinder; // Paper
+ @Override public com.destroystokyo.paper.entity.Pathfinder getPathfinder() { return paperPathfinder; } // Paper
@Override
public void setTarget(LivingEntity target) {
Preconditions.checkState(!this.getHandle().generation, "Cannot set target during world generation");
|