package net.minecraft.server;
import javax.annotation.Nullable;
public abstract class NavigationAbstract {
protected EntityInsentient a; public Entity getEntity() { return a; } // Paper - OBFHELPER
protected World b;
@Nullable
protected PathEntity c;
protected double d;
private final AttributeInstance f;
private int g;
private int h;
private Vec3D i;
private Vec3D j;
private long k;
private long l;
private double m;
private float n;
private boolean o;
private long p;
protected PathfinderAbstract e;
private BlockPosition q;
private final Pathfinder r;
public NavigationAbstract(EntityInsentient entityinsentient, World world) {
this.i = Vec3D.a;
this.j = Vec3D.a;
this.n = 0.5F;
this.a = entityinsentient;
this.b = world;
this.f = entityinsentient.getAttributeInstance(GenericAttributes.FOLLOW_RANGE);
this.r = this.a();
}
protected abstract Pathfinder a();
public void a(double d0) {
this.d = d0;
}
public float h() {
return (float) this.f.getValue();
}
public boolean i() {
return this.o;
}
public void j() {
if (this.b.getTime() - this.p > 20L) {
if (this.q != null) {
this.c = null;
this.c = this.a(this.q);
this.p = this.b.getTime();
this.o = false;
}
} else {
this.o = true;
}
}
@Nullable
public final PathEntity a(double d0, double d1, double d2) {
return this.a(new BlockPosition(d0, d1, d2));
}
@Nullable
public PathEntity a(BlockPosition blockposition) {
if (!getEntity().getWorld().getWorldBorder().isInBounds(blockposition)) return null; // Paper - don't path out of world border
if (!this.b()) {
return null;
} else if (this.c != null && !this.c.b() && blockposition.equals(this.q)) {
return this.c;
} else {
if (!new com.destroystokyo.paper.event.entity.EntityPathfindEvent(getEntity().getBukkitEntity(), MCUtil.toLocation(getEntity().world, blockposition), null).callEvent()) { return null; } // Paper
this.q = blockposition;
float f = this.h();
this.b.methodProfiler.a("pathfind");
BlockPosition blockposition1 = new BlockPosition(this.a);
int i = (int) (f + 8.0F);
ChunkCache chunkcache = new ChunkCache(this.b, blockposition1.a(-i, -i, -i), blockposition1.a(i, i, i), 0);
PathEntity pathentity = this.r.a(chunkcache, this.a, this.q, f);
return pathentity;
}
}
@Nullable
public PathEntity a(Entity entity) {
if (!this.b()) {
return null;
} else {
BlockPosition blockposition = new BlockPosition(entity);
if (!getEntity().getWorld().getWorldBorder().isInBounds(blockposition)) return null; // Paper - don't path out of world border
if (this.c != null && !this.c.b() && blockposition.equals(this.q)) {
return this.c;
} else {
if (!new com.destroystokyo.paper.event.entity.EntityPathfindEvent(getEntity().getBukkitEntity(), MCUtil.toLocation(entity.world, blockposition), entity.getBukkitEntity()).callEvent()) { return null; } // Paper
this.q = blockposition;
float f = this.h();
this.b.methodProfiler.a("pathfind");
BlockPosition blockposition1 = (new BlockPosition(this.a)).up();
int i = (int) (f + 16.0F);
ChunkCache chunkcache = new ChunkCache(this.b, blockposition1.a(-i, -i, -i), blockposition1.a(i, i, i), 0);
PathEntity pathentity = this.r.a(chunkcache, this.a, entity, f);
return pathentity;
}
}
}
public boolean a(double d0, double d1, double d2, double d3) {
return this.a(this.a(d0, d1, d2), d3);
}
public boolean a(Entity entity, double d0) {
// Paper start - Pathfinding optimizations
if (this.pathfindFailures > 10 && this.c == null && MinecraftServer.currentTick < this.lastFailure + 40) {
return false;
}
PathEntity pathentity = this.a(entity);
if (pathentity != null && this.a(pathentity, d0)) {
this.lastFailure = 0;
this.pathfindFailures = 0;
return true;
} else {
this.pathfindFailures++;
this.lastFailure = MinecraftServer.currentTick;
return false;
}
}
private int lastFailure = 0;
private int pathfindFailures = 0;
// Paper end
public boolean a(@Nullable PathEntity pathentity, double d0) {
if (pathentity == null) {
this.c = null;
return false;
} else {
if (!pathentity.a(this.c)) {
this.c = pathentity;
}
this.d();
if (this.c.d() == 0) {
return false;
} else {
this.d = d0;
Vec3D vec3d = this.c();
this.h = this.g;
this.i = vec3d;
return true;
}
}
}
@Nullable
public PathEntity k() {
return this.c;
}
public void l() {
++this.g;
if (this.o) {
this.j();
}
if (!this.n()) {
Vec3D vec3d;
if (this.b()) {
this.m();
} else if (this.c != null && this.c.e() < this.c.d()) {
vec3d = this.c();
Vec3D vec3d1 = this.c.a(this.a, this.c.e());
if (vec3d.y > vec3d1.y && !this.a.onGround && MathHelper.floor(vec3d.x) == MathHelper.floor(vec3d1.x) && MathHelper.floor(vec3d.z) == MathHelper.floor(vec3d1.z)) {
this.c.c(this.c.e() + 1);
}
}
if (!this.n()) {
vec3d = this.c.a(this.a);
if (vec3d != null) {
BlockPosition blockposition = (new BlockPosition(vec3d)).down();
AxisAlignedBB axisalignedbb = this.b.getType(blockposition).d(this.b, blockposition);
vec3d = vec3d.a(0.0D, 1.0D - axisalignedbb.e, 0.0D);
this.a.getControllerMove().a(vec3d.x, vec3d.y, vec3d.z, this.d);
}
}
}
}
protected void m() {
Vec3D vec3d = this.c();
int i = this.c.d();
for (int j = this.c.e(); j < this.c.d(); ++j) {
if (this.c.a(j).b != Math.floor(vec3d.y)) {
i = j;
break;
}
}
this.n = this.a.width > 0.75F ? this.a.width / 2.0F : 0.75F - this.a.width / 2.0F;
Vec3D vec3d1 = this.c.f();
if (MathHelper.e((float) (this.a.locX - (vec3d1.x + 0.5D))) < this.n && MathHelper.e((float) (this.a.locZ - (vec3d1.z + 0.5D))) < this.n && Math.abs(this.a.locY - vec3d1.y) < 1.0D) {
this.c.c(this.c.e() + 1);
}
int k = MathHelper.f(this.a.width);
int l = MathHelper.f(this.a.length);
int i1 = k;
for (int j1 = i - 1; j1 >= this.c.e(); --j1) {
if (this.a(vec3d, this.c.a(this.a, j1), k, l, i1)) {
this.c.c(j1);
break;
}
}
this.a(vec3d);
}
protected void a(Vec3D vec3d) {
if (this.g - this.h > 100) {
if (vec3d.distanceSquared(this.i) < 2.25D) {
this.o();
}
this.h = this.g;
this.i = vec3d;
}
if (this.c != null && !this.c.b()) {
Vec3D vec3d1 = this.c.f();
if (vec3d1.equals(this.j)) {
this.k += System.currentTimeMillis() - this.l;
} else {
this.j = vec3d1;
double d0 = vec3d.f(this.j);
this.m = this.a.cq() > 0.0F ? d0 / this.a.cq() * 1000.0D : 0.0D;
}
if (this.m > 0.0D && this.k > this.m * 3.0D) {
this.j = Vec3D.a;
this.k = 0L;
this.m = 0.0D;
this.o();
}
this.l = System.currentTimeMillis();
}
}
public boolean n() {
return this.c == null || this.c.b();
}
public void o() {
this.pathfindFailures = 0; this.lastFailure = 0; // Paper - Pathfinding optimizations
this.c = null;
}
protected abstract Vec3D c();
protected abstract boolean b();
protected boolean p() {
return this.a.isInWater() || this.a.ao();
}
protected void d() {}
protected abstract boolean a(Vec3D vec3d, Vec3D vec3d1, int i, int j, int k);
public boolean b(BlockPosition blockposition) {
return this.b.getType(blockposition.down()).b();
}
public PathfinderAbstract q() {
return this.e;
}
}