package net.minecraft.pathfinding;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.attributes.IAttributeInstance;
import net.minecraft.util.BlockPos;
import net.minecraft.util.MathHelper;
import net.minecraft.util.Vec3;
import net.minecraft.world.ChunkCache;
import net.minecraft.world.World;
public abstract class PathNavigate
{
protected EntityLiving theEntity;
protected World worldObj;
/** The PathEntity being followed. */
protected PathEntity currentPath;
protected double speed;
/**
* The number of blocks (extra) +/- in each axis that get pulled out as cache for the pathfinder's search space
*/
private final IAttributeInstance pathSearchRange;
/** Time, in number of ticks, following the current path */
private int totalTicks;
/**
* The time when the last position check was done (to detect successful movement)
*/
private int ticksAtLastPos;
/**
* Coordinates of the entity's position last time a check was done (part of monitoring getting 'stuck')
*/
private Vec3 lastPosCheck = new Vec3(0.0D, 0.0D, 0.0D);
private float field_179682_i = 1.0F;
private final PathFinder field_179681_j;
private static final String __OBFID = "CL_00001627";
public PathNavigate(EntityLiving p_i1671_1_, World worldIn)
{
this.theEntity = p_i1671_1_;
this.worldObj = worldIn;
this.pathSearchRange = p_i1671_1_.getEntityAttribute(SharedMonsterAttributes.followRange);
this.field_179681_j = this.func_179679_a();
}
protected abstract PathFinder func_179679_a();
/**
* Sets the speed
*/
public void setSpeed(double p_75489_1_)
{
this.speed = p_75489_1_;
}
/**
* Gets the maximum distance that the path finding will search in.
*/
public float getPathSearchRange()
{
return (float)this.pathSearchRange.getAttributeValue();
}
/**
* Returns the path to the given coordinates. Args : x, y, z
*/
public final PathEntity getPathToXYZ(double p_75488_1_, double p_75488_3_, double p_75488_5_)
{
return this.func_179680_a(new BlockPos(MathHelper.floor_double(p_75488_1_), (int)p_75488_3_, MathHelper.floor_double(p_75488_5_)));
}
public PathEntity func_179680_a(BlockPos p_179680_1_)
{
if (!this.canNavigate())
{
return null;
}
else
{
float var2 = this.getPathSearchRange();
this.worldObj.theProfiler.startSection("pathfind");
BlockPos var3 = new BlockPos(this.theEntity);
int var4 = (int)(var2 + 8.0F);
ChunkCache var5 = new ChunkCache(this.worldObj, var3.add(-var4, -var4, -var4), var3.add(var4, var4, var4), 0);
PathEntity var6 = this.field_179681_j.func_180782_a(var5, this.theEntity, p_179680_1_, var2);
this.worldObj.theProfiler.endSection();
return var6;
}
}
/**
* Try to find and set a path to XYZ. Returns true if successful. Args : x, y, z, speed
*/
public boolean tryMoveToXYZ(double p_75492_1_, double p_75492_3_, double p_75492_5_, double p_75492_7_)
{
PathEntity var9 = this.getPathToXYZ((double)MathHelper.floor_double(p_75492_1_), (double)((int)p_75492_3_), (double)MathHelper.floor_double(p_75492_5_));
return this.setPath(var9, p_75492_7_);
}
public void func_179678_a(float p_179678_1_)
{
this.field_179682_i = p_179678_1_;
}
/**
* Returns the path to the given EntityLiving. Args : entity
*/
public PathEntity getPathToEntityLiving(Entity p_75494_1_)
{
if (!this.canNavigate())
{
return null;
}
else
{
float var2 = this.getPathSearchRange();
this.worldObj.theProfiler.startSection("pathfind");
BlockPos var3 = (new BlockPos(this.theEntity)).offsetUp();
int var4 = (int)(var2 + 16.0F);
ChunkCache var5 = new ChunkCache(this.worldObj, var3.add(-var4, -var4, -var4), var3.add(var4, var4, var4), 0);
PathEntity var6 = this.field_179681_j.func_176188_a(var5, this.theEntity, p_75494_1_, var2);
this.worldObj.theProfiler.endSection();
return var6;
}
}
/**
* Try to find and set a path to EntityLiving. Returns true if successful. Args : entity, speed
*/
public boolean tryMoveToEntityLiving(Entity p_75497_1_, double p_75497_2_)
{
PathEntity var4 = this.getPathToEntityLiving(p_75497_1_);
return var4 != null ? this.setPath(var4, p_75497_2_) : false;
}
/**
* Sets a new path. If it's diferent from the old path. Checks to adjust path for sun avoiding, and stores start
* coords. Args : path, speed
*/
public boolean setPath(PathEntity p_75484_1_, double p_75484_2_)
{
if (p_75484_1_ == null)
{
this.currentPath = null;
return false;
}
else
{
if (!p_75484_1_.isSamePath(this.currentPath))
{
this.currentPath = p_75484_1_;
}
this.removeSunnyPath();
if (this.currentPath.getCurrentPathLength() == 0)
{
return false;
}
else
{
this.speed = p_75484_2_;
Vec3 var4 = this.getEntityPosition();
this.ticksAtLastPos = this.totalTicks;
this.lastPosCheck = var4;
return true;
}
}
}
/**
* gets the actively used PathEntity
*/
public PathEntity getPath()
{
return this.currentPath;
}
public void onUpdateNavigation()
{
++this.totalTicks;
if (!this.noPath())
{
Vec3 var1;
if (this.canNavigate())
{
this.pathFollow();
}
else if (this.currentPath != null && this.currentPath.getCurrentPathIndex() < this.currentPath.getCurrentPathLength())
{
var1 = this.getEntityPosition();
Vec3 var2 = this.currentPath.getVectorFromIndex(this.theEntity, this.currentPath.getCurrentPathIndex());
if (var1.yCoord > var2.yCoord && !this.theEntity.onGround && MathHelper.floor_double(var1.xCoord) == MathHelper.floor_double(var2.xCoord) && MathHelper.floor_double(var1.zCoord) == MathHelper.floor_double(var2.zCoord))
{
this.currentPath.setCurrentPathIndex(this.currentPath.getCurrentPathIndex() + 1);
}
}
if (!this.noPath())
{
var1 = this.currentPath.getPosition(this.theEntity);
if (var1 != null)
{
this.theEntity.getMoveHelper().setMoveTo(var1.xCoord, var1.yCoord, var1.zCoord, this.speed);
}
}
}
}
protected void pathFollow()
{
Vec3 var1 = this.getEntityPosition();
int var2 = this.currentPath.getCurrentPathLength();
for (int var3 = this.currentPath.getCurrentPathIndex(); var3 < this.currentPath.getCurrentPathLength(); ++var3)
{
if (this.currentPath.getPathPointFromIndex(var3).yCoord != (int)var1.yCoord)
{
var2 = var3;
break;
}
}
float var8 = this.theEntity.width * this.theEntity.width * this.field_179682_i;
int var4;
for (var4 = this.currentPath.getCurrentPathIndex(); var4 < var2; ++var4)
{
Vec3 var5 = this.currentPath.getVectorFromIndex(this.theEntity, var4);
if (var1.squareDistanceTo(var5) < (double)var8)
{
this.currentPath.setCurrentPathIndex(var4 + 1);
}
}
var4 = MathHelper.ceiling_float_int(this.theEntity.width);
int var9 = (int)this.theEntity.height + 1;
int var6 = var4;
for (int var7 = var2 - 1; var7 >= this.currentPath.getCurrentPathIndex(); --var7)
{
if (this.isDirectPathBetweenPoints(var1, this.currentPath.getVectorFromIndex(this.theEntity, var7), var4, var9, var6))
{
this.currentPath.setCurrentPathIndex(var7);
break;
}
}
this.func_179677_a(var1);
}
protected void func_179677_a(Vec3 p_179677_1_)
{
if (this.totalTicks - this.ticksAtLastPos > 100)
{
if (p_179677_1_.squareDistanceTo(this.lastPosCheck) < 2.25D)
{
this.clearPathEntity();
}
this.ticksAtLastPos = this.totalTicks;
this.lastPosCheck = p_179677_1_;
}
}
/**
* If null path or reached the end
*/
public boolean noPath()
{
return this.currentPath == null || this.currentPath.isFinished();
}
/**
* sets active PathEntity to null
*/
public void clearPathEntity()
{
this.currentPath = null;
}
protected abstract Vec3 getEntityPosition();
/**
* If on ground or swimming and can swim
*/
protected abstract boolean canNavigate();
/**
* Returns true if the entity is in water or lava, false otherwise
*/
protected boolean isInLiquid()
{
return this.theEntity.isInWater() || this.theEntity.func_180799_ab();
}
/**
* Trims path data from the end to the first sun covered block
*/
protected void removeSunnyPath() {}
/**
* Returns true when an entity of specified size could safely walk in a straight line between the two points. Args:
* pos1, pos2, entityXSize, entityYSize, entityZSize
*/
protected abstract boolean isDirectPathBetweenPoints(Vec3 p_75493_1_, Vec3 p_75493_2_, int p_75493_3_, int p_75493_4_, int p_75493_5_);
}