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..af1bac9680028130e99c5e7130f258c196b33275
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/PaperPathfinder.java
@@ -0,0 +1,141 @@
+package com.destroystokyo.paper.entity;
+
+import net.minecraft.server.EntityInsentient;
+import net.minecraft.server.PathEntity;
+import net.minecraft.server.PathPoint;
+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 java.util.ArrayList;
+import java.util.List;
+
+public class PaperPathfinder implements com.destroystokyo.paper.entity.Pathfinder {
+
+    private final EntityInsentient entity;
+
+    public PaperPathfinder(EntityInsentient entity) {
+        this.entity = entity;
+    }
+
+    @Override
+    public Mob getEntity() {
+        return entity.getBukkitMob();
+    }
+
+    @Override
+    public void stopPathfinding() {
+        entity.getNavigation().stopPathfinding();
+    }
+
+    @Override
+    public boolean hasPath() {
+        return entity.getNavigation().getPathEntity() != null;
+    }
+
+    @Nullable
+    @Override
+    public PathResult getCurrentPath() {
+        PathEntity path = entity.getNavigation().getPathEntity();
+        return path != null ? new PaperPathResult(path) : null;
+    }
+
+    @Nullable
+    @Override
+    public PathResult findPath(Location loc) {
+        Validate.notNull(loc, "Location can not be null");
+        PathEntity path = entity.getNavigation().calculateDestination(loc.getX(), loc.getY(), loc.getZ());
+        return path != null ? new PaperPathResult(path) : null;
+    }
+
+    @Nullable
+    @Override
+    public PathResult findPath(LivingEntity target) {
+        Validate.notNull(target, "Target can not be null");
+        PathEntity path = entity.getNavigation().calculateDestination(((CraftLivingEntity) target).getHandle());
+        return path != null ? new PaperPathResult(path) : null;
+    }
+
+    @Override
+    public boolean moveTo(@Nonnull PathResult path, double speed) {
+        Validate.notNull(path, "PathResult can not be null");
+        PathEntity pathEntity = ((PaperPathResult) path).path;
+        return entity.getNavigation().setDestination(pathEntity, speed);
+    }
+
+    @Override
+    public boolean canOpenDoors() {
+        return entity.getNavigation().getPathfinder().getPathfinder().shouldOpenDoors();
+    }
+
+    @Override
+    public void setCanOpenDoors(boolean canOpenDoors) {
+        entity.getNavigation().getPathfinder().getPathfinder().setShouldOpenDoors(canOpenDoors);
+    }
+
+    @Override
+    public boolean canPassDoors() {
+        return entity.getNavigation().getPathfinder().getPathfinder().shouldPassDoors();
+    }
+
+    @Override
+    public void setCanPassDoors(boolean canPassDoors) {
+        entity.getNavigation().getPathfinder().getPathfinder().setShouldPassDoors(canPassDoors);
+    }
+
+    @Override
+    public boolean canFloat() {
+        return entity.getNavigation().getPathfinder().getPathfinder().shouldFloat();
+    }
+
+    @Override
+    public void setCanFloat(boolean canFloat) {
+        entity.getNavigation().getPathfinder().getPathfinder().setShouldFloat(canFloat);
+    }
+
+    public class PaperPathResult implements com.destroystokyo.paper.entity.PaperPathfinder.PathResult {
+
+        private final PathEntity path;
+        PaperPathResult(PathEntity path) {
+            this.path = path;
+        }
+
+        @Nullable
+        @Override
+        public Location getFinalPoint() {
+            PathPoint point = path.getFinalPoint();
+            return point != null ? toLoc(point) : null;
+        }
+
+        @Override
+        public List<Location> getPoints() {
+            List<Location> points = new ArrayList<>();
+            for (PathPoint point : path.getPoints()) {
+                points.add(toLoc(point));
+            }
+            return points;
+        }
+
+        @Override
+        public int getNextPointIndex() {
+            return path.getNextIndex();
+        }
+
+        @Nullable
+        @Override
+        public Location getNextPoint() {
+            if (!path.hasNext()) {
+                return null;
+            }
+            return toLoc(path.getPoints().get(path.getNextIndex()));
+        }
+    }
+
+    private Location toLoc(PathPoint point) {
+        return new Location(entity.world.getWorld(), point.getX(), point.getY(), point.getZ());
+    }
+}
diff --git a/src/main/java/net/minecraft/server/NavigationAbstract.java b/src/main/java/net/minecraft/server/NavigationAbstract.java
index b06c76a369f1dc9de8d782272c3ff0573af89361..cca6242e38fc286eea810eb8f2e4d1ab5429b9df 100644
--- a/src/main/java/net/minecraft/server/NavigationAbstract.java
+++ b/src/main/java/net/minecraft/server/NavigationAbstract.java
@@ -78,7 +78,7 @@ public abstract class NavigationAbstract {
     }
 
     @Nullable
-    public final PathEntity a(double d0, double d1, double d2, int i) {
+    public final PathEntity calculateDestination(double d0, double d1, double d2) { return a(d0, d1, d2, 0); } public final PathEntity a(double d0, double d1, double d2, int i) { // Paper - OBFHELPER
         return this.a(new BlockPosition(d0, d1, d2), i);
     }
 
@@ -103,7 +103,7 @@ public abstract class NavigationAbstract {
     }
 
     @Nullable
-    public PathEntity a(Entity entity, int i) {
+    public final PathEntity calculateDestination(Entity entity) { return a(entity, 0); }  public PathEntity a(Entity entity, int i) {
         return this.a(ImmutableSet.of(entity.getChunkCoordinates()), entity, 16, true, i); // Paper
     }
 
@@ -168,6 +168,7 @@ public abstract class NavigationAbstract {
         return pathentity != null && this.a(pathentity, d0);
     }
 
+    public boolean setDestination(@Nullable PathEntity pathentity, double speed) { return a(pathentity, speed); } // Paper - OBFHELPER
     public boolean a(@Nullable PathEntity pathentity, double d0) {
         if (pathentity == null) {
             this.c = null;
@@ -195,7 +196,7 @@ public abstract class NavigationAbstract {
         }
     }
 
-    @Nullable
+    @Nullable public PathEntity getPathEntity() { return k(); } @Nullable // Paper - OBFHELPER
     public PathEntity k() {
         return this.c;
     }
@@ -311,6 +312,7 @@ public abstract class NavigationAbstract {
         return !this.m();
     }
 
+    public void stopPathfinding() { o(); } // Paper - OBFHELPER
     public void o() {
         this.c = null;
     }
diff --git a/src/main/java/net/minecraft/server/PathEntity.java b/src/main/java/net/minecraft/server/PathEntity.java
index 662932360bc7a9391fde99a88b60aac47f29467e..9154c01a22bc7b6d2dd390bb7b6e21ef52c8006c 100644
--- a/src/main/java/net/minecraft/server/PathEntity.java
+++ b/src/main/java/net/minecraft/server/PathEntity.java
@@ -5,13 +5,14 @@ import javax.annotation.Nullable;
 
 public class PathEntity {
 
-    private final List<PathPoint> a;
+    private final List<PathPoint> a; public List<PathPoint> getPoints() { return a; } // Paper - OBFHELPER
     private PathPoint[] b = new PathPoint[0];
     private PathPoint[] c = new PathPoint[0];
-    private int e;
+    private int e; public int getNextIndex() { return this.e; } // Paper - OBFHELPER
     private final BlockPosition f;
     private final float g;
     private final boolean h;
+    public boolean hasNext() { return getNextIndex() < getPoints().size(); } // Paper
 
     public PathEntity(List<PathPoint> list, BlockPosition blockposition, boolean flag) {
         this.a = list;
@@ -28,8 +29,7 @@ public class PathEntity {
         return this.e >= this.a.size();
     }
 
-    @Nullable
-    public PathPoint c() {
+    public PathPoint getFinalPoint() { return c(); } @Nullable public PathPoint c() { // Paper - OBFHELPER
         return !this.a.isEmpty() ? (PathPoint) this.a.get(this.a.size() - 1) : null;
     }
 
@@ -77,7 +77,7 @@ public class PathEntity {
         return this.a(entity, this.e);
     }
 
-    public BaseBlockPosition g() {
+    public BaseBlockPosition getNext() { return g(); } public BaseBlockPosition g() { // Paper - OBFHELPER
         PathPoint pathpoint = this.h();
 
         return new BaseBlockPosition(pathpoint.a, pathpoint.b, pathpoint.c);
diff --git a/src/main/java/net/minecraft/server/PathPoint.java b/src/main/java/net/minecraft/server/PathPoint.java
index b69d6bc433711e94e3fbfa2a89c091209c95484d..e9fb295bdf727cd4543cbe5a18447ceba3d41ee0 100644
--- a/src/main/java/net/minecraft/server/PathPoint.java
+++ b/src/main/java/net/minecraft/server/PathPoint.java
@@ -2,9 +2,9 @@ package net.minecraft.server;
 
 public class PathPoint {
 
-    public final int a;
-    public final int b;
-    public final int c;
+    public final int a; public final int getX() { return a; } // Paper - OBFHELPER
+    public final int b; public final int getY() { return b; } // Paper - OBFHELPER
+    public final int c; public final int getZ() { return c; } // Paper - OBFHELPER
     private final int m;
     public int d = -1;
     public float e;
diff --git a/src/main/java/net/minecraft/server/PathfinderAbstract.java b/src/main/java/net/minecraft/server/PathfinderAbstract.java
index fca9ed99d6c11badb85e0c06cd6872dca85d6f8d..5cfcac3bc29e3f3d139b10209f5082cba292a434 100644
--- a/src/main/java/net/minecraft/server/PathfinderAbstract.java
+++ b/src/main/java/net/minecraft/server/PathfinderAbstract.java
@@ -11,9 +11,9 @@ public abstract class PathfinderAbstract {
     protected int d;
     protected int e;
     protected int f;
-    protected boolean g;
-    protected boolean h;
-    protected boolean i;
+    protected boolean g; public boolean shouldPassDoors() { return g; } public void setShouldPassDoors(boolean b) { g = b; } // Paper - obfhelper
+    protected boolean h; public boolean shouldOpenDoors() { return h; } public void setShouldOpenDoors(boolean b) { h = b; } // Paper - obfhelper
+    protected boolean i; public boolean shouldFloat() { return i; } public void setShouldFloat(boolean b) { i = b; } // Paper - obfhelper
 
     public PathfinderAbstract() {}
 
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java
index 90e63fbf292488732434ed9cf20645d8306eb21d..c89bc7024b650c3b6d2c551f0e4e156975570cca 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, EntityInsentient 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) {
         EntityInsentient entity = getHandle();