base mod created
This commit is contained in:
@@ -0,0 +1,426 @@
|
||||
package net.minecraft.pathfinding;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
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.init.Blocks;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.ChunkCache;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public abstract class PathNavigate
|
||||
{
|
||||
protected EntityLiving entity;
|
||||
protected World world;
|
||||
/** The PathEntity being followed. */
|
||||
@Nullable
|
||||
protected Path 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 */
|
||||
protected 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 Vec3d lastPosCheck = Vec3d.ZERO;
|
||||
private Vec3d timeoutCachedNode = Vec3d.ZERO;
|
||||
private long timeoutTimer;
|
||||
private long lastTimeoutCheck;
|
||||
private double timeoutLimit;
|
||||
protected float maxDistanceToWaypoint = 0.5F;
|
||||
protected boolean tryUpdatePath;
|
||||
private long lastTimeUpdated;
|
||||
protected NodeProcessor nodeProcessor;
|
||||
private BlockPos targetPos;
|
||||
private final PathFinder pathFinder;
|
||||
|
||||
public PathNavigate(EntityLiving entityIn, World worldIn)
|
||||
{
|
||||
this.entity = entityIn;
|
||||
this.world = worldIn;
|
||||
this.pathSearchRange = entityIn.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE);
|
||||
this.pathFinder = this.getPathFinder();
|
||||
}
|
||||
|
||||
protected abstract PathFinder getPathFinder();
|
||||
|
||||
/**
|
||||
* Sets the speed
|
||||
*/
|
||||
public void setSpeed(double speedIn)
|
||||
{
|
||||
this.speed = speedIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum distance that the path finding will search in.
|
||||
*/
|
||||
public float getPathSearchRange()
|
||||
{
|
||||
return (float)this.pathSearchRange.getAttributeValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if path can be changed by {@link net.minecraft.pathfinding.PathNavigate#onUpdateNavigation()
|
||||
* onUpdateNavigation()}
|
||||
*/
|
||||
public boolean canUpdatePathOnTimeout()
|
||||
{
|
||||
return this.tryUpdatePath;
|
||||
}
|
||||
|
||||
public void updatePath()
|
||||
{
|
||||
if (this.world.getTotalWorldTime() - this.lastTimeUpdated > 20L)
|
||||
{
|
||||
if (this.targetPos != null)
|
||||
{
|
||||
this.currentPath = null;
|
||||
this.currentPath = this.getPathToPos(this.targetPos);
|
||||
this.lastTimeUpdated = this.world.getTotalWorldTime();
|
||||
this.tryUpdatePath = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.tryUpdatePath = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to the given coordinates. Args : x, y, z
|
||||
*/
|
||||
@Nullable
|
||||
public final Path getPathToXYZ(double x, double y, double z)
|
||||
{
|
||||
return this.getPathToPos(new BlockPos(x, y, z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns path to given BlockPos
|
||||
*/
|
||||
@Nullable
|
||||
public Path getPathToPos(BlockPos pos)
|
||||
{
|
||||
if (!this.canNavigate())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else if (this.currentPath != null && !this.currentPath.isFinished() && pos.equals(this.targetPos))
|
||||
{
|
||||
return this.currentPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.targetPos = pos;
|
||||
float f = this.getPathSearchRange();
|
||||
this.world.profiler.startSection("pathfind");
|
||||
BlockPos blockpos = new BlockPos(this.entity);
|
||||
int i = (int)(f + 8.0F);
|
||||
ChunkCache chunkcache = new ChunkCache(this.world, blockpos.add(-i, -i, -i), blockpos.add(i, i, i), 0);
|
||||
Path path = this.pathFinder.findPath(chunkcache, this.entity, this.targetPos, f);
|
||||
this.world.profiler.endSection();
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to the given EntityLiving. Args : entity
|
||||
*/
|
||||
@Nullable
|
||||
public Path getPathToEntityLiving(Entity entityIn)
|
||||
{
|
||||
if (!this.canNavigate())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockPos blockpos = new BlockPos(entityIn);
|
||||
|
||||
if (this.currentPath != null && !this.currentPath.isFinished() && blockpos.equals(this.targetPos))
|
||||
{
|
||||
return this.currentPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.targetPos = blockpos;
|
||||
float f = this.getPathSearchRange();
|
||||
this.world.profiler.startSection("pathfind");
|
||||
BlockPos blockpos1 = (new BlockPos(this.entity)).up();
|
||||
int i = (int)(f + 16.0F);
|
||||
ChunkCache chunkcache = new ChunkCache(this.world, blockpos1.add(-i, -i, -i), blockpos1.add(i, i, i), 0);
|
||||
Path path = this.pathFinder.findPath(chunkcache, this.entity, entityIn, f);
|
||||
this.world.profiler.endSection();
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find and set a path to XYZ. Returns true if successful. Args : x, y, z, speed
|
||||
*/
|
||||
public boolean tryMoveToXYZ(double x, double y, double z, double speedIn)
|
||||
{
|
||||
return this.setPath(this.getPathToXYZ(x, y, z), speedIn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find and set a path to EntityLiving. Returns true if successful. Args : entity, speed
|
||||
*/
|
||||
public boolean tryMoveToEntityLiving(Entity entityIn, double speedIn)
|
||||
{
|
||||
Path path = this.getPathToEntityLiving(entityIn);
|
||||
return path != null && this.setPath(path, speedIn);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(@Nullable Path pathentityIn, double speedIn)
|
||||
{
|
||||
if (pathentityIn == null)
|
||||
{
|
||||
this.currentPath = null;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!pathentityIn.isSamePath(this.currentPath))
|
||||
{
|
||||
this.currentPath = pathentityIn;
|
||||
}
|
||||
|
||||
this.removeSunnyPath();
|
||||
|
||||
if (this.currentPath.getCurrentPathLength() <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.speed = speedIn;
|
||||
Vec3d vec3d = this.getEntityPosition();
|
||||
this.ticksAtLastPos = this.totalTicks;
|
||||
this.lastPosCheck = vec3d;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the actively used PathEntity
|
||||
*/
|
||||
@Nullable
|
||||
public Path getPath()
|
||||
{
|
||||
return this.currentPath;
|
||||
}
|
||||
|
||||
public void onUpdateNavigation()
|
||||
{
|
||||
++this.totalTicks;
|
||||
|
||||
if (this.tryUpdatePath)
|
||||
{
|
||||
this.updatePath();
|
||||
}
|
||||
|
||||
if (!this.noPath())
|
||||
{
|
||||
if (this.canNavigate())
|
||||
{
|
||||
this.pathFollow();
|
||||
}
|
||||
else if (this.currentPath != null && this.currentPath.getCurrentPathIndex() < this.currentPath.getCurrentPathLength())
|
||||
{
|
||||
Vec3d vec3d = this.getEntityPosition();
|
||||
Vec3d vec3d1 = this.currentPath.getVectorFromIndex(this.entity, this.currentPath.getCurrentPathIndex());
|
||||
|
||||
if (vec3d.y > vec3d1.y && !this.entity.onGround && MathHelper.floor(vec3d.x) == MathHelper.floor(vec3d1.x) && MathHelper.floor(vec3d.z) == MathHelper.floor(vec3d1.z))
|
||||
{
|
||||
this.currentPath.setCurrentPathIndex(this.currentPath.getCurrentPathIndex() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
this.debugPathFinding();
|
||||
|
||||
if (!this.noPath())
|
||||
{
|
||||
Vec3d vec3d2 = this.currentPath.getPosition(this.entity);
|
||||
BlockPos blockpos = (new BlockPos(vec3d2)).down();
|
||||
AxisAlignedBB axisalignedbb = this.world.getBlockState(blockpos).getBoundingBox(this.world, blockpos);
|
||||
vec3d2 = vec3d2.subtract(0.0D, 1.0D - axisalignedbb.maxY, 0.0D);
|
||||
this.entity.getMoveHelper().setMoveTo(vec3d2.x, vec3d2.y, vec3d2.z, this.speed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void debugPathFinding()
|
||||
{
|
||||
}
|
||||
|
||||
protected void pathFollow()
|
||||
{
|
||||
Vec3d vec3d = this.getEntityPosition();
|
||||
int i = this.currentPath.getCurrentPathLength();
|
||||
|
||||
for (int j = this.currentPath.getCurrentPathIndex(); j < this.currentPath.getCurrentPathLength(); ++j)
|
||||
{
|
||||
if ((double)this.currentPath.getPathPointFromIndex(j).y != Math.floor(vec3d.y))
|
||||
{
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.maxDistanceToWaypoint = this.entity.width > 0.75F ? this.entity.width / 2.0F : 0.75F - this.entity.width / 2.0F;
|
||||
Vec3d vec3d1 = this.currentPath.getCurrentPos();
|
||||
|
||||
if (MathHelper.abs((float)(this.entity.posX - (vec3d1.x + 0.5D))) < this.maxDistanceToWaypoint && MathHelper.abs((float)(this.entity.posZ - (vec3d1.z + 0.5D))) < this.maxDistanceToWaypoint && Math.abs(this.entity.posY - vec3d1.y) < 1.0D)
|
||||
{
|
||||
this.currentPath.setCurrentPathIndex(this.currentPath.getCurrentPathIndex() + 1);
|
||||
}
|
||||
|
||||
int k = MathHelper.ceil(this.entity.width);
|
||||
int l = MathHelper.ceil(this.entity.height);
|
||||
int i1 = k;
|
||||
|
||||
for (int j1 = i - 1; j1 >= this.currentPath.getCurrentPathIndex(); --j1)
|
||||
{
|
||||
if (this.isDirectPathBetweenPoints(vec3d, this.currentPath.getVectorFromIndex(this.entity, j1), k, l, i1))
|
||||
{
|
||||
this.currentPath.setCurrentPathIndex(j1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.checkForStuck(vec3d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if entity haven't been moved when last checked and if so, clears current {@link
|
||||
* net.minecraft.pathfinding.PathEntity}
|
||||
*/
|
||||
protected void checkForStuck(Vec3d positionVec3)
|
||||
{
|
||||
if (this.totalTicks - this.ticksAtLastPos > 100)
|
||||
{
|
||||
if (positionVec3.squareDistanceTo(this.lastPosCheck) < 2.25D)
|
||||
{
|
||||
this.clearPath();
|
||||
}
|
||||
|
||||
this.ticksAtLastPos = this.totalTicks;
|
||||
this.lastPosCheck = positionVec3;
|
||||
}
|
||||
|
||||
if (this.currentPath != null && !this.currentPath.isFinished())
|
||||
{
|
||||
Vec3d vec3d = this.currentPath.getCurrentPos();
|
||||
|
||||
if (vec3d.equals(this.timeoutCachedNode))
|
||||
{
|
||||
this.timeoutTimer += System.currentTimeMillis() - this.lastTimeoutCheck;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.timeoutCachedNode = vec3d;
|
||||
double d0 = positionVec3.distanceTo(this.timeoutCachedNode);
|
||||
this.timeoutLimit = this.entity.getAIMoveSpeed() > 0.0F ? d0 / (double)this.entity.getAIMoveSpeed() * 1000.0D : 0.0D;
|
||||
}
|
||||
|
||||
if (this.timeoutLimit > 0.0D && (double)this.timeoutTimer > this.timeoutLimit * 3.0D)
|
||||
{
|
||||
this.timeoutCachedNode = Vec3d.ZERO;
|
||||
this.timeoutTimer = 0L;
|
||||
this.timeoutLimit = 0.0D;
|
||||
this.clearPath();
|
||||
}
|
||||
|
||||
this.lastTimeoutCheck = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If null path or reached the end
|
||||
*/
|
||||
public boolean noPath()
|
||||
{
|
||||
return this.currentPath == null || this.currentPath.isFinished();
|
||||
}
|
||||
|
||||
/**
|
||||
* sets active PathEntity to null
|
||||
*/
|
||||
public void clearPath()
|
||||
{
|
||||
this.currentPath = null;
|
||||
}
|
||||
|
||||
protected abstract Vec3d 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.entity.isInWater() || this.entity.isInLava();
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims path data from the end to the first sun covered block
|
||||
*/
|
||||
protected void removeSunnyPath()
|
||||
{
|
||||
if (this.currentPath != null)
|
||||
{
|
||||
for (int i = 0; i < this.currentPath.getCurrentPathLength(); ++i)
|
||||
{
|
||||
PathPoint pathpoint = this.currentPath.getPathPointFromIndex(i);
|
||||
PathPoint pathpoint1 = i + 1 < this.currentPath.getCurrentPathLength() ? this.currentPath.getPathPointFromIndex(i + 1) : null;
|
||||
IBlockState iblockstate = this.world.getBlockState(new BlockPos(pathpoint.x, pathpoint.y, pathpoint.z));
|
||||
Block block = iblockstate.getBlock();
|
||||
|
||||
if (block == Blocks.CAULDRON)
|
||||
{
|
||||
this.currentPath.setPoint(i, pathpoint.cloneMove(pathpoint.x, pathpoint.y + 1, pathpoint.z));
|
||||
|
||||
if (pathpoint1 != null && pathpoint.y >= pathpoint1.y)
|
||||
{
|
||||
this.currentPath.setPoint(i + 1, pathpoint1.cloneMove(pathpoint1.x, pathpoint.y + 1, pathpoint1.z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified entity can safely walk to the specified location.
|
||||
*/
|
||||
protected abstract boolean isDirectPathBetweenPoints(Vec3d posVec31, Vec3d posVec32, int sizeX, int sizeY, int sizeZ);
|
||||
|
||||
public boolean canEntityStandOnPos(BlockPos pos)
|
||||
{
|
||||
return this.world.getBlockState(pos.down()).isFullBlock();
|
||||
}
|
||||
|
||||
public NodeProcessor getNodeProcessor()
|
||||
{
|
||||
return this.nodeProcessor;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user