base mod created

This commit is contained in:
Mohammad-Ali Minaie
2018-10-08 09:07:47 -04:00
parent 0a7700c356
commit b86dedad2f
7848 changed files with 584664 additions and 1 deletions

View File

@@ -0,0 +1,359 @@
package net.minecraft.pathfinding;
import com.google.common.collect.Sets;
import java.util.EnumSet;
import java.util.Set;
import javax.annotation.Nullable;
import net.minecraft.block.Block;
import net.minecraft.entity.EntityLiving;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.IBlockAccess;
public class FlyingNodeProcessor extends WalkNodeProcessor
{
public void init(IBlockAccess sourceIn, EntityLiving mob)
{
super.init(sourceIn, mob);
this.avoidsWater = mob.getPathPriority(PathNodeType.WATER);
}
/**
* This method is called when all nodes have been processed and PathEntity is created.
* {@link net.minecraft.world.pathfinder.WalkNodeProcessor WalkNodeProcessor} uses this to change its field {@link
* net.minecraft.world.pathfinder.WalkNodeProcessor#avoidsWater avoidsWater}
*/
public void postProcess()
{
this.entity.setPathPriority(PathNodeType.WATER, this.avoidsWater);
super.postProcess();
}
public PathPoint getStart()
{
int i;
if (this.getCanSwim() && this.entity.isInWater())
{
i = (int)this.entity.getEntityBoundingBox().minY;
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos(MathHelper.floor(this.entity.posX), i, MathHelper.floor(this.entity.posZ));
for (Block block = this.blockaccess.getBlockState(blockpos$mutableblockpos).getBlock(); block == Blocks.FLOWING_WATER || block == Blocks.WATER; block = this.blockaccess.getBlockState(blockpos$mutableblockpos).getBlock())
{
++i;
blockpos$mutableblockpos.setPos(MathHelper.floor(this.entity.posX), i, MathHelper.floor(this.entity.posZ));
}
}
else
{
i = MathHelper.floor(this.entity.getEntityBoundingBox().minY + 0.5D);
}
BlockPos blockpos1 = new BlockPos(this.entity);
PathNodeType pathnodetype1 = this.getPathNodeType(this.entity, blockpos1.getX(), i, blockpos1.getZ());
if (this.entity.getPathPriority(pathnodetype1) < 0.0F)
{
Set<BlockPos> set = Sets.<BlockPos>newHashSet();
set.add(new BlockPos(this.entity.getEntityBoundingBox().minX, (double)i, this.entity.getEntityBoundingBox().minZ));
set.add(new BlockPos(this.entity.getEntityBoundingBox().minX, (double)i, this.entity.getEntityBoundingBox().maxZ));
set.add(new BlockPos(this.entity.getEntityBoundingBox().maxX, (double)i, this.entity.getEntityBoundingBox().minZ));
set.add(new BlockPos(this.entity.getEntityBoundingBox().maxX, (double)i, this.entity.getEntityBoundingBox().maxZ));
for (BlockPos blockpos : set)
{
PathNodeType pathnodetype = this.getPathNodeType(this.entity, blockpos);
if (this.entity.getPathPriority(pathnodetype) >= 0.0F)
{
return super.openPoint(blockpos.getX(), blockpos.getY(), blockpos.getZ());
}
}
}
return super.openPoint(blockpos1.getX(), i, blockpos1.getZ());
}
/**
* Returns PathPoint for given coordinates
*/
public PathPoint getPathPointToCoords(double x, double y, double z)
{
return super.openPoint(MathHelper.floor(x), MathHelper.floor(y), MathHelper.floor(z));
}
public int findPathOptions(PathPoint[] pathOptions, PathPoint currentPoint, PathPoint targetPoint, float maxDistance)
{
int i = 0;
PathPoint pathpoint = this.openPoint(currentPoint.x, currentPoint.y, currentPoint.z + 1);
PathPoint pathpoint1 = this.openPoint(currentPoint.x - 1, currentPoint.y, currentPoint.z);
PathPoint pathpoint2 = this.openPoint(currentPoint.x + 1, currentPoint.y, currentPoint.z);
PathPoint pathpoint3 = this.openPoint(currentPoint.x, currentPoint.y, currentPoint.z - 1);
PathPoint pathpoint4 = this.openPoint(currentPoint.x, currentPoint.y + 1, currentPoint.z);
PathPoint pathpoint5 = this.openPoint(currentPoint.x, currentPoint.y - 1, currentPoint.z);
if (pathpoint != null && !pathpoint.visited && pathpoint.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint;
}
if (pathpoint1 != null && !pathpoint1.visited && pathpoint1.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint1;
}
if (pathpoint2 != null && !pathpoint2.visited && pathpoint2.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint2;
}
if (pathpoint3 != null && !pathpoint3.visited && pathpoint3.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint3;
}
if (pathpoint4 != null && !pathpoint4.visited && pathpoint4.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint4;
}
if (pathpoint5 != null && !pathpoint5.visited && pathpoint5.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint5;
}
boolean flag = pathpoint3 == null || pathpoint3.costMalus != 0.0F;
boolean flag1 = pathpoint == null || pathpoint.costMalus != 0.0F;
boolean flag2 = pathpoint2 == null || pathpoint2.costMalus != 0.0F;
boolean flag3 = pathpoint1 == null || pathpoint1.costMalus != 0.0F;
boolean flag4 = pathpoint4 == null || pathpoint4.costMalus != 0.0F;
boolean flag5 = pathpoint5 == null || pathpoint5.costMalus != 0.0F;
if (flag && flag3)
{
PathPoint pathpoint6 = this.openPoint(currentPoint.x - 1, currentPoint.y, currentPoint.z - 1);
if (pathpoint6 != null && !pathpoint6.visited && pathpoint6.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint6;
}
}
if (flag && flag2)
{
PathPoint pathpoint7 = this.openPoint(currentPoint.x + 1, currentPoint.y, currentPoint.z - 1);
if (pathpoint7 != null && !pathpoint7.visited && pathpoint7.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint7;
}
}
if (flag1 && flag3)
{
PathPoint pathpoint8 = this.openPoint(currentPoint.x - 1, currentPoint.y, currentPoint.z + 1);
if (pathpoint8 != null && !pathpoint8.visited && pathpoint8.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint8;
}
}
if (flag1 && flag2)
{
PathPoint pathpoint9 = this.openPoint(currentPoint.x + 1, currentPoint.y, currentPoint.z + 1);
if (pathpoint9 != null && !pathpoint9.visited && pathpoint9.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint9;
}
}
if (flag && flag4)
{
PathPoint pathpoint10 = this.openPoint(currentPoint.x, currentPoint.y + 1, currentPoint.z - 1);
if (pathpoint10 != null && !pathpoint10.visited && pathpoint10.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint10;
}
}
if (flag1 && flag4)
{
PathPoint pathpoint11 = this.openPoint(currentPoint.x, currentPoint.y + 1, currentPoint.z + 1);
if (pathpoint11 != null && !pathpoint11.visited && pathpoint11.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint11;
}
}
if (flag2 && flag4)
{
PathPoint pathpoint12 = this.openPoint(currentPoint.x + 1, currentPoint.y + 1, currentPoint.z);
if (pathpoint12 != null && !pathpoint12.visited && pathpoint12.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint12;
}
}
if (flag3 && flag4)
{
PathPoint pathpoint13 = this.openPoint(currentPoint.x - 1, currentPoint.y + 1, currentPoint.z);
if (pathpoint13 != null && !pathpoint13.visited && pathpoint13.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint13;
}
}
if (flag && flag5)
{
PathPoint pathpoint14 = this.openPoint(currentPoint.x, currentPoint.y - 1, currentPoint.z - 1);
if (pathpoint14 != null && !pathpoint14.visited && pathpoint14.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint14;
}
}
if (flag1 && flag5)
{
PathPoint pathpoint15 = this.openPoint(currentPoint.x, currentPoint.y - 1, currentPoint.z + 1);
if (pathpoint15 != null && !pathpoint15.visited && pathpoint15.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint15;
}
}
if (flag2 && flag5)
{
PathPoint pathpoint16 = this.openPoint(currentPoint.x + 1, currentPoint.y - 1, currentPoint.z);
if (pathpoint16 != null && !pathpoint16.visited && pathpoint16.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint16;
}
}
if (flag3 && flag5)
{
PathPoint pathpoint17 = this.openPoint(currentPoint.x - 1, currentPoint.y - 1, currentPoint.z);
if (pathpoint17 != null && !pathpoint17.visited && pathpoint17.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint17;
}
}
return i;
}
/**
* Returns a mapped point or creates and adds one
*/
@Nullable
protected PathPoint openPoint(int x, int y, int z)
{
PathPoint pathpoint = null;
PathNodeType pathnodetype = this.getPathNodeType(this.entity, x, y, z);
float f = this.entity.getPathPriority(pathnodetype);
if (f >= 0.0F)
{
pathpoint = super.openPoint(x, y, z);
pathpoint.nodeType = pathnodetype;
pathpoint.costMalus = Math.max(pathpoint.costMalus, f);
if (pathnodetype == PathNodeType.WALKABLE)
{
++pathpoint.costMalus;
}
}
return pathnodetype != PathNodeType.OPEN && pathnodetype != PathNodeType.WALKABLE ? pathpoint : pathpoint;
}
public PathNodeType getPathNodeType(IBlockAccess blockaccessIn, int x, int y, int z, EntityLiving entitylivingIn, int xSize, int ySize, int zSize, boolean canBreakDoorsIn, boolean canEnterDoorsIn)
{
EnumSet<PathNodeType> enumset = EnumSet.<PathNodeType>noneOf(PathNodeType.class);
PathNodeType pathnodetype = PathNodeType.BLOCKED;
BlockPos blockpos = new BlockPos(entitylivingIn);
pathnodetype = this.getPathNodeType(blockaccessIn, x, y, z, xSize, ySize, zSize, canBreakDoorsIn, canEnterDoorsIn, enumset, pathnodetype, blockpos);
if (enumset.contains(PathNodeType.FENCE))
{
return PathNodeType.FENCE;
}
else
{
PathNodeType pathnodetype1 = PathNodeType.BLOCKED;
for (PathNodeType pathnodetype2 : enumset)
{
if (entitylivingIn.getPathPriority(pathnodetype2) < 0.0F)
{
return pathnodetype2;
}
if (entitylivingIn.getPathPriority(pathnodetype2) >= entitylivingIn.getPathPriority(pathnodetype1))
{
pathnodetype1 = pathnodetype2;
}
}
if (pathnodetype == PathNodeType.OPEN && entitylivingIn.getPathPriority(pathnodetype1) == 0.0F)
{
return PathNodeType.OPEN;
}
else
{
return pathnodetype1;
}
}
}
public PathNodeType getPathNodeType(IBlockAccess blockaccessIn, int x, int y, int z)
{
PathNodeType pathnodetype = this.getPathNodeTypeRaw(blockaccessIn, x, y, z);
if (pathnodetype == PathNodeType.OPEN && y >= 1)
{
Block block = blockaccessIn.getBlockState(new BlockPos(x, y - 1, z)).getBlock();
PathNodeType pathnodetype1 = this.getPathNodeTypeRaw(blockaccessIn, x, y - 1, z);
if (pathnodetype1 != PathNodeType.DAMAGE_FIRE && block != Blocks.MAGMA && pathnodetype1 != PathNodeType.LAVA)
{
if (pathnodetype1 == PathNodeType.DAMAGE_CACTUS)
{
pathnodetype = PathNodeType.DAMAGE_CACTUS;
}
else
{
pathnodetype = pathnodetype1 != PathNodeType.WALKABLE && pathnodetype1 != PathNodeType.OPEN && pathnodetype1 != PathNodeType.WATER ? PathNodeType.WALKABLE : PathNodeType.OPEN;
}
}
else
{
pathnodetype = PathNodeType.DAMAGE_FIRE;
}
}
pathnodetype = this.checkNeighborBlocks(blockaccessIn, x, y, z, pathnodetype);
return pathnodetype;
}
private PathNodeType getPathNodeType(EntityLiving p_192559_1_, BlockPos p_192559_2_)
{
return this.getPathNodeType(p_192559_1_, p_192559_2_.getX(), p_192559_2_.getY(), p_192559_2_.getZ());
}
private PathNodeType getPathNodeType(EntityLiving p_192558_1_, int p_192558_2_, int p_192558_3_, int p_192558_4_)
{
return this.getPathNodeType(this.blockaccess, p_192558_2_, p_192558_3_, p_192558_4_, p_192558_1_, this.entitySizeX, this.entitySizeY, this.entitySizeZ, this.getCanOpenDoors(), this.getCanEnterDoors());
}
}

View File

@@ -0,0 +1,100 @@
package net.minecraft.pathfinding;
import net.minecraft.entity.EntityLiving;
import net.minecraft.util.IntHashMap;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.IBlockAccess;
public abstract class NodeProcessor
{
protected IBlockAccess blockaccess;
protected EntityLiving entity;
protected final IntHashMap<PathPoint> pointMap = new IntHashMap<PathPoint>();
protected int entitySizeX;
protected int entitySizeY;
protected int entitySizeZ;
protected boolean canEnterDoors;
protected boolean canOpenDoors;
protected boolean canSwim;
public void init(IBlockAccess sourceIn, EntityLiving mob)
{
this.blockaccess = sourceIn;
this.entity = mob;
this.pointMap.clearMap();
this.entitySizeX = MathHelper.floor(mob.width + 1.0F);
this.entitySizeY = MathHelper.floor(mob.height + 1.0F);
this.entitySizeZ = MathHelper.floor(mob.width + 1.0F);
}
/**
* This method is called when all nodes have been processed and PathEntity is created.
* {@link net.minecraft.world.pathfinder.WalkNodeProcessor WalkNodeProcessor} uses this to change its field {@link
* net.minecraft.world.pathfinder.WalkNodeProcessor#avoidsWater avoidsWater}
*/
public void postProcess()
{
this.blockaccess = null;
this.entity = null;
}
/**
* Returns a mapped point or creates and adds one
*/
protected PathPoint openPoint(int x, int y, int z)
{
int i = PathPoint.makeHash(x, y, z);
PathPoint pathpoint = this.pointMap.lookup(i);
if (pathpoint == null)
{
pathpoint = new PathPoint(x, y, z);
this.pointMap.addKey(i, pathpoint);
}
return pathpoint;
}
public abstract PathPoint getStart();
/**
* Returns PathPoint for given coordinates
*/
public abstract PathPoint getPathPointToCoords(double x, double y, double z);
public abstract int findPathOptions(PathPoint[] pathOptions, PathPoint currentPoint, PathPoint targetPoint, float maxDistance);
public abstract PathNodeType getPathNodeType(IBlockAccess blockaccessIn, int x, int y, int z, EntityLiving entitylivingIn, int xSize, int ySize, int zSize, boolean canBreakDoorsIn, boolean canEnterDoorsIn);
public abstract PathNodeType getPathNodeType(IBlockAccess blockaccessIn, int x, int y, int z);
public void setCanEnterDoors(boolean canEnterDoorsIn)
{
this.canEnterDoors = canEnterDoorsIn;
}
public void setCanOpenDoors(boolean canOpenDoorsIn)
{
this.canOpenDoors = canOpenDoorsIn;
}
public void setCanSwim(boolean canSwimIn)
{
this.canSwim = canSwimIn;
}
public boolean getCanEnterDoors()
{
return this.canEnterDoors;
}
public boolean getCanOpenDoors()
{
return this.canOpenDoors;
}
public boolean getCanSwim()
{
return this.canSwim;
}
}

View File

@@ -0,0 +1,190 @@
package net.minecraft.pathfinding;
import javax.annotation.Nullable;
import net.minecraft.entity.Entity;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class Path
{
/** The actual points in the path */
private final PathPoint[] points;
private PathPoint[] openSet = new PathPoint[0];
private PathPoint[] closedSet = new PathPoint[0];
@SideOnly(Side.CLIENT)
private PathPoint target;
/** PathEntity Array Index the Entity is currently targeting */
private int currentPathIndex;
/** The total length of the path */
private int pathLength;
public Path(PathPoint[] pathpoints)
{
this.points = pathpoints;
this.pathLength = pathpoints.length;
}
/**
* Directs this path to the next point in its array
*/
public void incrementPathIndex()
{
++this.currentPathIndex;
}
/**
* Returns true if this path has reached the end
*/
public boolean isFinished()
{
return this.currentPathIndex >= this.pathLength;
}
/**
* returns the last PathPoint of the Array
*/
@Nullable
public PathPoint getFinalPathPoint()
{
return this.pathLength > 0 ? this.points[this.pathLength - 1] : null;
}
/**
* return the PathPoint located at the specified PathIndex, usually the current one
*/
public PathPoint getPathPointFromIndex(int index)
{
return this.points[index];
}
public void setPoint(int index, PathPoint point)
{
this.points[index] = point;
}
public int getCurrentPathLength()
{
return this.pathLength;
}
public void setCurrentPathLength(int length)
{
this.pathLength = length;
}
public int getCurrentPathIndex()
{
return this.currentPathIndex;
}
public void setCurrentPathIndex(int currentPathIndexIn)
{
this.currentPathIndex = currentPathIndexIn;
}
/**
* Gets the vector of the PathPoint associated with the given index.
*/
public Vec3d getVectorFromIndex(Entity entityIn, int index)
{
double d0 = (double)this.points[index].x + (double)((int)(entityIn.width + 1.0F)) * 0.5D;
double d1 = (double)this.points[index].y;
double d2 = (double)this.points[index].z + (double)((int)(entityIn.width + 1.0F)) * 0.5D;
return new Vec3d(d0, d1, d2);
}
/**
* returns the current PathEntity target node as Vec3D
*/
public Vec3d getPosition(Entity entityIn)
{
return this.getVectorFromIndex(entityIn, this.currentPathIndex);
}
public Vec3d getCurrentPos()
{
PathPoint pathpoint = this.points[this.currentPathIndex];
return new Vec3d((double)pathpoint.x, (double)pathpoint.y, (double)pathpoint.z);
}
/**
* Returns true if the EntityPath are the same. Non instance related equals.
*/
public boolean isSamePath(Path pathentityIn)
{
if (pathentityIn == null)
{
return false;
}
else if (pathentityIn.points.length != this.points.length)
{
return false;
}
else
{
for (int i = 0; i < this.points.length; ++i)
{
if (this.points[i].x != pathentityIn.points[i].x || this.points[i].y != pathentityIn.points[i].y || this.points[i].z != pathentityIn.points[i].z)
{
return false;
}
}
return true;
}
}
@SideOnly(Side.CLIENT)
public PathPoint[] getOpenSet()
{
return this.openSet;
}
@SideOnly(Side.CLIENT)
public PathPoint[] getClosedSet()
{
return this.closedSet;
}
@SideOnly(Side.CLIENT)
public PathPoint getTarget()
{
return this.target;
}
@SideOnly(Side.CLIENT)
public static Path read(PacketBuffer buf)
{
int i = buf.readInt();
PathPoint pathpoint = PathPoint.createFromBuffer(buf);
PathPoint[] apathpoint = new PathPoint[buf.readInt()];
for (int j = 0; j < apathpoint.length; ++j)
{
apathpoint[j] = PathPoint.createFromBuffer(buf);
}
PathPoint[] apathpoint1 = new PathPoint[buf.readInt()];
for (int k = 0; k < apathpoint1.length; ++k)
{
apathpoint1[k] = PathPoint.createFromBuffer(buf);
}
PathPoint[] apathpoint2 = new PathPoint[buf.readInt()];
for (int l = 0; l < apathpoint2.length; ++l)
{
apathpoint2[l] = PathPoint.createFromBuffer(buf);
}
Path path = new Path(apathpoint);
path.openSet = apathpoint1;
path.closedSet = apathpoint2;
path.target = pathpoint;
path.currentPathIndex = i;
return path;
}
}

View File

@@ -0,0 +1,148 @@
package net.minecraft.pathfinding;
import com.google.common.collect.Sets;
import java.util.Set;
import javax.annotation.Nullable;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
public class PathFinder
{
/** The path being generated */
private final PathHeap path = new PathHeap();
private final Set<PathPoint> closedSet = Sets.<PathPoint>newHashSet();
/** Selection of path points to add to the path */
private final PathPoint[] pathOptions = new PathPoint[32];
private final NodeProcessor nodeProcessor;
public PathFinder(NodeProcessor processor)
{
this.nodeProcessor = processor;
}
@Nullable
public Path findPath(IBlockAccess worldIn, EntityLiving entitylivingIn, Entity targetEntity, float maxDistance)
{
return this.findPath(worldIn, entitylivingIn, targetEntity.posX, targetEntity.getEntityBoundingBox().minY, targetEntity.posZ, maxDistance);
}
@Nullable
public Path findPath(IBlockAccess worldIn, EntityLiving entitylivingIn, BlockPos targetPos, float maxDistance)
{
return this.findPath(worldIn, entitylivingIn, (double)((float)targetPos.getX() + 0.5F), (double)((float)targetPos.getY() + 0.5F), (double)((float)targetPos.getZ() + 0.5F), maxDistance);
}
@Nullable
private Path findPath(IBlockAccess worldIn, EntityLiving entitylivingIn, double x, double y, double z, float maxDistance)
{
this.path.clearPath();
this.nodeProcessor.init(worldIn, entitylivingIn);
PathPoint pathpoint = this.nodeProcessor.getStart();
PathPoint pathpoint1 = this.nodeProcessor.getPathPointToCoords(x, y, z);
Path path = this.findPath(pathpoint, pathpoint1, maxDistance);
this.nodeProcessor.postProcess();
return path;
}
@Nullable
private Path findPath(PathPoint pathFrom, PathPoint pathTo, float maxDistance)
{
pathFrom.totalPathDistance = 0.0F;
pathFrom.distanceToNext = pathFrom.distanceManhattan(pathTo);
pathFrom.distanceToTarget = pathFrom.distanceToNext;
this.path.clearPath();
this.closedSet.clear();
this.path.addPoint(pathFrom);
PathPoint pathpoint = pathFrom;
int i = 0;
while (!this.path.isPathEmpty())
{
++i;
if (i >= 200)
{
break;
}
PathPoint pathpoint1 = this.path.dequeue();
if (pathpoint1.equals(pathTo))
{
pathpoint = pathTo;
break;
}
if (pathpoint1.distanceManhattan(pathTo) < pathpoint.distanceManhattan(pathTo))
{
pathpoint = pathpoint1;
}
pathpoint1.visited = true;
int j = this.nodeProcessor.findPathOptions(this.pathOptions, pathpoint1, pathTo, maxDistance);
for (int k = 0; k < j; ++k)
{
PathPoint pathpoint2 = this.pathOptions[k];
float f = pathpoint1.distanceManhattan(pathpoint2);
pathpoint2.distanceFromOrigin = pathpoint1.distanceFromOrigin + f;
pathpoint2.cost = f + pathpoint2.costMalus;
float f1 = pathpoint1.totalPathDistance + pathpoint2.cost;
if (pathpoint2.distanceFromOrigin < maxDistance && (!pathpoint2.isAssigned() || f1 < pathpoint2.totalPathDistance))
{
pathpoint2.previous = pathpoint1;
pathpoint2.totalPathDistance = f1;
pathpoint2.distanceToNext = pathpoint2.distanceManhattan(pathTo) + pathpoint2.costMalus;
if (pathpoint2.isAssigned())
{
this.path.changeDistance(pathpoint2, pathpoint2.totalPathDistance + pathpoint2.distanceToNext);
}
else
{
pathpoint2.distanceToTarget = pathpoint2.totalPathDistance + pathpoint2.distanceToNext;
this.path.addPoint(pathpoint2);
}
}
}
}
if (pathpoint == pathFrom)
{
return null;
}
else
{
Path path = this.createPath(pathFrom, pathpoint);
return path;
}
}
/**
* Returns a new PathEntity for a given start and end point
*/
private Path createPath(PathPoint start, PathPoint end)
{
int i = 1;
for (PathPoint pathpoint = end; pathpoint.previous != null; pathpoint = pathpoint.previous)
{
++i;
}
PathPoint[] apathpoint = new PathPoint[i];
PathPoint pathpoint1 = end;
--i;
for (apathpoint[i] = end; pathpoint1.previous != null; apathpoint[i] = pathpoint1)
{
pathpoint1 = pathpoint1.previous;
--i;
}
return new Path(apathpoint);
}
}

View File

@@ -0,0 +1,174 @@
package net.minecraft.pathfinding;
public class PathHeap
{
/** Contains the points in this path */
private PathPoint[] pathPoints = new PathPoint[128];
/** The number of points in this path */
private int count;
/**
* Adds a point to the path
*/
public PathPoint addPoint(PathPoint point)
{
if (point.index >= 0)
{
throw new IllegalStateException("OW KNOWS!");
}
else
{
if (this.count == this.pathPoints.length)
{
PathPoint[] apathpoint = new PathPoint[this.count << 1];
System.arraycopy(this.pathPoints, 0, apathpoint, 0, this.count);
this.pathPoints = apathpoint;
}
this.pathPoints[this.count] = point;
point.index = this.count;
this.sortBack(this.count++);
return point;
}
}
/**
* Clears the path
*/
public void clearPath()
{
this.count = 0;
}
/**
* Returns and removes the first point in the path
*/
public PathPoint dequeue()
{
PathPoint pathpoint = this.pathPoints[0];
this.pathPoints[0] = this.pathPoints[--this.count];
this.pathPoints[this.count] = null;
if (this.count > 0)
{
this.sortForward(0);
}
pathpoint.index = -1;
return pathpoint;
}
/**
* Changes the provided point's distance to target
*/
public void changeDistance(PathPoint point, float distance)
{
float f = point.distanceToTarget;
point.distanceToTarget = distance;
if (distance < f)
{
this.sortBack(point.index);
}
else
{
this.sortForward(point.index);
}
}
/**
* Sorts a point to the left
*/
private void sortBack(int index)
{
PathPoint pathpoint = this.pathPoints[index];
int i;
for (float f = pathpoint.distanceToTarget; index > 0; index = i)
{
i = index - 1 >> 1;
PathPoint pathpoint1 = this.pathPoints[i];
if (f >= pathpoint1.distanceToTarget)
{
break;
}
this.pathPoints[index] = pathpoint1;
pathpoint1.index = index;
}
this.pathPoints[index] = pathpoint;
pathpoint.index = index;
}
/**
* Sorts a point to the right
*/
private void sortForward(int index)
{
PathPoint pathpoint = this.pathPoints[index];
float f = pathpoint.distanceToTarget;
while (true)
{
int i = 1 + (index << 1);
int j = i + 1;
if (i >= this.count)
{
break;
}
PathPoint pathpoint1 = this.pathPoints[i];
float f1 = pathpoint1.distanceToTarget;
PathPoint pathpoint2;
float f2;
if (j >= this.count)
{
pathpoint2 = null;
f2 = Float.POSITIVE_INFINITY;
}
else
{
pathpoint2 = this.pathPoints[j];
f2 = pathpoint2.distanceToTarget;
}
if (f1 < f2)
{
if (f1 >= f)
{
break;
}
this.pathPoints[index] = pathpoint1;
pathpoint1.index = index;
index = i;
}
else
{
if (f2 >= f)
{
break;
}
this.pathPoints[index] = pathpoint2;
pathpoint2.index = index;
index = j;
}
}
this.pathPoints[index] = pathpoint;
pathpoint.index = index;
}
/**
* Returns true if this path contains no points
*/
public boolean isPathEmpty()
{
return this.count == 0;
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,79 @@
package net.minecraft.pathfinding;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
public class PathNavigateClimber extends PathNavigateGround
{
/** Current path navigation target */
private BlockPos targetPosition;
public PathNavigateClimber(EntityLiving entityLivingIn, World worldIn)
{
super(entityLivingIn, worldIn);
}
/**
* Returns path to given BlockPos
*/
public Path getPathToPos(BlockPos pos)
{
this.targetPosition = pos;
return super.getPathToPos(pos);
}
/**
* Returns the path to the given EntityLiving. Args : entity
*/
public Path getPathToEntityLiving(Entity entityIn)
{
this.targetPosition = new BlockPos(entityIn);
return super.getPathToEntityLiving(entityIn);
}
/**
* 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);
if (path != null)
{
return this.setPath(path, speedIn);
}
else
{
this.targetPosition = new BlockPos(entityIn);
this.speed = speedIn;
return true;
}
}
public void onUpdateNavigation()
{
if (!this.noPath())
{
super.onUpdateNavigation();
}
else
{
if (this.targetPosition != null)
{
double d0 = (double)(this.entity.width * this.entity.width);
if (this.entity.getDistanceSqToCenter(this.targetPosition) >= d0 && (this.entity.posY <= (double)this.targetPosition.getY() || this.entity.getDistanceSqToCenter(new BlockPos(this.targetPosition.getX(), MathHelper.floor(this.entity.posY), this.targetPosition.getZ())) >= d0))
{
this.entity.getMoveHelper().setMoveTo((double)this.targetPosition.getX(), (double)this.targetPosition.getY(), (double)this.targetPosition.getZ(), this.speed);
}
else
{
this.targetPosition = null;
}
}
}
}
}

View File

@@ -0,0 +1,188 @@
package net.minecraft.pathfinding;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class PathNavigateFlying extends PathNavigate
{
public PathNavigateFlying(EntityLiving p_i47412_1_, World p_i47412_2_)
{
super(p_i47412_1_, p_i47412_2_);
}
protected PathFinder getPathFinder()
{
this.nodeProcessor = new FlyingNodeProcessor();
this.nodeProcessor.setCanEnterDoors(true);
return new PathFinder(this.nodeProcessor);
}
/**
* If on ground or swimming and can swim
*/
protected boolean canNavigate()
{
return this.canFloat() && this.isInLiquid() || !this.entity.isRiding();
}
protected Vec3d getEntityPosition()
{
return new Vec3d(this.entity.posX, this.entity.posY, this.entity.posZ);
}
/**
* Returns the path to the given EntityLiving. Args : entity
*/
public Path getPathToEntityLiving(Entity entityIn)
{
return this.getPathToPos(new BlockPos(entityIn));
}
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.currentPath.getVectorFromIndex(this.entity, this.currentPath.getCurrentPathIndex());
if (MathHelper.floor(this.entity.posX) == MathHelper.floor(vec3d.x) && MathHelper.floor(this.entity.posY) == MathHelper.floor(vec3d.y) && MathHelper.floor(this.entity.posZ) == MathHelper.floor(vec3d.z))
{
this.currentPath.setCurrentPathIndex(this.currentPath.getCurrentPathIndex() + 1);
}
}
this.debugPathFinding();
if (!this.noPath())
{
Vec3d vec3d1 = this.currentPath.getPosition(this.entity);
this.entity.getMoveHelper().setMoveTo(vec3d1.x, vec3d1.y, vec3d1.z, this.speed);
}
}
}
/**
* Checks if the specified entity can safely walk to the specified location.
*/
protected boolean isDirectPathBetweenPoints(Vec3d posVec31, Vec3d posVec32, int sizeX, int sizeY, int sizeZ)
{
int i = MathHelper.floor(posVec31.x);
int j = MathHelper.floor(posVec31.y);
int k = MathHelper.floor(posVec31.z);
double d0 = posVec32.x - posVec31.x;
double d1 = posVec32.y - posVec31.y;
double d2 = posVec32.z - posVec31.z;
double d3 = d0 * d0 + d1 * d1 + d2 * d2;
if (d3 < 1.0E-8D)
{
return false;
}
else
{
double d4 = 1.0D / Math.sqrt(d3);
d0 = d0 * d4;
d1 = d1 * d4;
d2 = d2 * d4;
double d5 = 1.0D / Math.abs(d0);
double d6 = 1.0D / Math.abs(d1);
double d7 = 1.0D / Math.abs(d2);
double d8 = (double)i - posVec31.x;
double d9 = (double)j - posVec31.y;
double d10 = (double)k - posVec31.z;
if (d0 >= 0.0D)
{
++d8;
}
if (d1 >= 0.0D)
{
++d9;
}
if (d2 >= 0.0D)
{
++d10;
}
d8 = d8 / d0;
d9 = d9 / d1;
d10 = d10 / d2;
int l = d0 < 0.0D ? -1 : 1;
int i1 = d1 < 0.0D ? -1 : 1;
int j1 = d2 < 0.0D ? -1 : 1;
int k1 = MathHelper.floor(posVec32.x);
int l1 = MathHelper.floor(posVec32.y);
int i2 = MathHelper.floor(posVec32.z);
int j2 = k1 - i;
int k2 = l1 - j;
int l2 = i2 - k;
while (j2 * l > 0 || k2 * i1 > 0 || l2 * j1 > 0)
{
if (d8 < d10 && d8 <= d9)
{
d8 += d5;
i += l;
j2 = k1 - i;
}
else if (d9 < d8 && d9 <= d10)
{
d9 += d6;
j += i1;
k2 = l1 - j;
}
else
{
d10 += d7;
k += j1;
l2 = i2 - k;
}
}
return true;
}
}
public void setCanOpenDoors(boolean p_192879_1_)
{
this.nodeProcessor.setCanOpenDoors(p_192879_1_);
}
public void setCanEnterDoors(boolean p_192878_1_)
{
this.nodeProcessor.setCanEnterDoors(p_192878_1_);
}
public void setCanFloat(boolean p_192877_1_)
{
this.nodeProcessor.setCanSwim(p_192877_1_);
}
public boolean canFloat()
{
return this.nodeProcessor.getCanSwim();
}
public boolean canEntityStandOnPos(BlockPos pos)
{
return this.world.getBlockState(pos).isTopSolid();
}
}

View File

@@ -0,0 +1,346 @@
package net.minecraft.pathfinding;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class PathNavigateGround extends PathNavigate
{
private boolean shouldAvoidSun;
public PathNavigateGround(EntityLiving entitylivingIn, World worldIn)
{
super(entitylivingIn, worldIn);
}
protected PathFinder getPathFinder()
{
this.nodeProcessor = new WalkNodeProcessor();
this.nodeProcessor.setCanEnterDoors(true);
return new PathFinder(this.nodeProcessor);
}
/**
* If on ground or swimming and can swim
*/
protected boolean canNavigate()
{
return this.entity.onGround || this.getCanSwim() && this.isInLiquid() || this.entity.isRiding();
}
protected Vec3d getEntityPosition()
{
return new Vec3d(this.entity.posX, (double)this.getPathablePosY(), this.entity.posZ);
}
/**
* Returns path to given BlockPos
*/
public Path getPathToPos(BlockPos pos)
{
if (this.world.getBlockState(pos).getMaterial() == Material.AIR)
{
BlockPos blockpos;
for (blockpos = pos.down(); blockpos.getY() > 0 && this.world.getBlockState(blockpos).getMaterial() == Material.AIR; blockpos = blockpos.down())
{
;
}
if (blockpos.getY() > 0)
{
return super.getPathToPos(blockpos.up());
}
while (blockpos.getY() < this.world.getHeight() && this.world.getBlockState(blockpos).getMaterial() == Material.AIR)
{
blockpos = blockpos.up();
}
pos = blockpos;
}
if (!this.world.getBlockState(pos).getMaterial().isSolid())
{
return super.getPathToPos(pos);
}
else
{
BlockPos blockpos1;
for (blockpos1 = pos.up(); blockpos1.getY() < this.world.getHeight() && this.world.getBlockState(blockpos1).getMaterial().isSolid(); blockpos1 = blockpos1.up())
{
;
}
return super.getPathToPos(blockpos1);
}
}
/**
* Returns the path to the given EntityLiving. Args : entity
*/
public Path getPathToEntityLiving(Entity entityIn)
{
return this.getPathToPos(new BlockPos(entityIn));
}
/**
* Gets the safe pathing Y position for the entity depending on if it can path swim or not
*/
private int getPathablePosY()
{
if (this.entity.isInWater() && this.getCanSwim())
{
int i = (int)this.entity.getEntityBoundingBox().minY;
Block block = this.world.getBlockState(new BlockPos(MathHelper.floor(this.entity.posX), i, MathHelper.floor(this.entity.posZ))).getBlock();
int j = 0;
while (block == Blocks.FLOWING_WATER || block == Blocks.WATER)
{
++i;
block = this.world.getBlockState(new BlockPos(MathHelper.floor(this.entity.posX), i, MathHelper.floor(this.entity.posZ))).getBlock();
++j;
if (j > 16)
{
return (int)this.entity.getEntityBoundingBox().minY;
}
}
return i;
}
else
{
return (int)(this.entity.getEntityBoundingBox().minY + 0.5D);
}
}
/**
* Trims path data from the end to the first sun covered block
*/
protected void removeSunnyPath()
{
super.removeSunnyPath();
if (this.shouldAvoidSun)
{
if (this.world.canSeeSky(new BlockPos(MathHelper.floor(this.entity.posX), (int)(this.entity.getEntityBoundingBox().minY + 0.5D), MathHelper.floor(this.entity.posZ))))
{
return;
}
for (int i = 0; i < this.currentPath.getCurrentPathLength(); ++i)
{
PathPoint pathpoint = this.currentPath.getPathPointFromIndex(i);
if (this.world.canSeeSky(new BlockPos(pathpoint.x, pathpoint.y, pathpoint.z)))
{
this.currentPath.setCurrentPathLength(i - 1);
return;
}
}
}
}
/**
* Checks if the specified entity can safely walk to the specified location.
*/
protected boolean isDirectPathBetweenPoints(Vec3d posVec31, Vec3d posVec32, int sizeX, int sizeY, int sizeZ)
{
int i = MathHelper.floor(posVec31.x);
int j = MathHelper.floor(posVec31.z);
double d0 = posVec32.x - posVec31.x;
double d1 = posVec32.z - posVec31.z;
double d2 = d0 * d0 + d1 * d1;
if (d2 < 1.0E-8D)
{
return false;
}
else
{
double d3 = 1.0D / Math.sqrt(d2);
d0 = d0 * d3;
d1 = d1 * d3;
sizeX = sizeX + 2;
sizeZ = sizeZ + 2;
if (!this.isSafeToStandAt(i, (int)posVec31.y, j, sizeX, sizeY, sizeZ, posVec31, d0, d1))
{
return false;
}
else
{
sizeX = sizeX - 2;
sizeZ = sizeZ - 2;
double d4 = 1.0D / Math.abs(d0);
double d5 = 1.0D / Math.abs(d1);
double d6 = (double)i - posVec31.x;
double d7 = (double)j - posVec31.z;
if (d0 >= 0.0D)
{
++d6;
}
if (d1 >= 0.0D)
{
++d7;
}
d6 = d6 / d0;
d7 = d7 / d1;
int k = d0 < 0.0D ? -1 : 1;
int l = d1 < 0.0D ? -1 : 1;
int i1 = MathHelper.floor(posVec32.x);
int j1 = MathHelper.floor(posVec32.z);
int k1 = i1 - i;
int l1 = j1 - j;
while (k1 * k > 0 || l1 * l > 0)
{
if (d6 < d7)
{
d6 += d4;
i += k;
k1 = i1 - i;
}
else
{
d7 += d5;
j += l;
l1 = j1 - j;
}
if (!this.isSafeToStandAt(i, (int)posVec31.y, j, sizeX, sizeY, sizeZ, posVec31, d0, d1))
{
return false;
}
}
return true;
}
}
}
/**
* Returns true when an entity could stand at a position, including solid blocks under the entire entity.
*/
private boolean isSafeToStandAt(int x, int y, int z, int sizeX, int sizeY, int sizeZ, Vec3d vec31, double p_179683_8_, double p_179683_10_)
{
int i = x - sizeX / 2;
int j = z - sizeZ / 2;
if (!this.isPositionClear(i, y, j, sizeX, sizeY, sizeZ, vec31, p_179683_8_, p_179683_10_))
{
return false;
}
else
{
for (int k = i; k < i + sizeX; ++k)
{
for (int l = j; l < j + sizeZ; ++l)
{
double d0 = (double)k + 0.5D - vec31.x;
double d1 = (double)l + 0.5D - vec31.z;
if (d0 * p_179683_8_ + d1 * p_179683_10_ >= 0.0D)
{
PathNodeType pathnodetype = this.nodeProcessor.getPathNodeType(this.world, k, y - 1, l, this.entity, sizeX, sizeY, sizeZ, true, true);
if (pathnodetype == PathNodeType.WATER)
{
return false;
}
if (pathnodetype == PathNodeType.LAVA)
{
return false;
}
if (pathnodetype == PathNodeType.OPEN)
{
return false;
}
pathnodetype = this.nodeProcessor.getPathNodeType(this.world, k, y, l, this.entity, sizeX, sizeY, sizeZ, true, true);
float f = this.entity.getPathPriority(pathnodetype);
if (f < 0.0F || f >= 8.0F)
{
return false;
}
if (pathnodetype == PathNodeType.DAMAGE_FIRE || pathnodetype == PathNodeType.DANGER_FIRE || pathnodetype == PathNodeType.DAMAGE_OTHER)
{
return false;
}
}
}
}
return true;
}
}
/**
* Returns true if an entity does not collide with any solid blocks at the position.
*/
private boolean isPositionClear(int x, int y, int z, int sizeX, int sizeY, int sizeZ, Vec3d p_179692_7_, double p_179692_8_, double p_179692_10_)
{
for (BlockPos blockpos : BlockPos.getAllInBox(new BlockPos(x, y, z), new BlockPos(x + sizeX - 1, y + sizeY - 1, z + sizeZ - 1)))
{
double d0 = (double)blockpos.getX() + 0.5D - p_179692_7_.x;
double d1 = (double)blockpos.getZ() + 0.5D - p_179692_7_.z;
if (d0 * p_179692_8_ + d1 * p_179692_10_ >= 0.0D)
{
Block block = this.world.getBlockState(blockpos).getBlock();
if (!block.isPassable(this.world, blockpos))
{
return false;
}
}
}
return true;
}
public void setBreakDoors(boolean canBreakDoors)
{
this.nodeProcessor.setCanOpenDoors(canBreakDoors);
}
public void setEnterDoors(boolean enterDoors)
{
this.nodeProcessor.setCanEnterDoors(enterDoors);
}
public boolean getEnterDoors()
{
return this.nodeProcessor.getCanEnterDoors();
}
public void setCanSwim(boolean canSwim)
{
this.nodeProcessor.setCanSwim(canSwim);
}
public boolean getCanSwim()
{
return this.nodeProcessor.getCanSwim();
}
public void setAvoidSun(boolean avoidSun)
{
this.shouldAvoidSun = avoidSun;
}
}

View File

@@ -0,0 +1,72 @@
package net.minecraft.pathfinding;
import net.minecraft.entity.EntityLiving;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class PathNavigateSwimmer extends PathNavigate
{
public PathNavigateSwimmer(EntityLiving entitylivingIn, World worldIn)
{
super(entitylivingIn, worldIn);
}
protected PathFinder getPathFinder()
{
return new PathFinder(new SwimNodeProcessor());
}
/**
* If on ground or swimming and can swim
*/
protected boolean canNavigate()
{
return this.isInLiquid();
}
protected Vec3d getEntityPosition()
{
return new Vec3d(this.entity.posX, this.entity.posY + (double)this.entity.height * 0.5D, this.entity.posZ);
}
protected void pathFollow()
{
Vec3d vec3d = this.getEntityPosition();
float f = this.entity.width * this.entity.width;
int i = 6;
if (vec3d.squareDistanceTo(this.currentPath.getVectorFromIndex(this.entity, this.currentPath.getCurrentPathIndex())) < (double)f)
{
this.currentPath.incrementPathIndex();
}
for (int j = Math.min(this.currentPath.getCurrentPathIndex() + 6, this.currentPath.getCurrentPathLength() - 1); j > this.currentPath.getCurrentPathIndex(); --j)
{
Vec3d vec3d1 = this.currentPath.getVectorFromIndex(this.entity, j);
if (vec3d1.squareDistanceTo(vec3d) <= 36.0D && this.isDirectPathBetweenPoints(vec3d, vec3d1, 0, 0, 0))
{
this.currentPath.setCurrentPathIndex(j);
break;
}
}
this.checkForStuck(vec3d);
}
/**
* Checks if the specified entity can safely walk to the specified location.
*/
protected boolean isDirectPathBetweenPoints(Vec3d posVec31, Vec3d posVec32, int sizeX, int sizeY, int sizeZ)
{
RayTraceResult raytraceresult = this.world.rayTraceBlocks(posVec31, new Vec3d(posVec32.x, posVec32.y + (double)this.entity.height * 0.5D, posVec32.z), false, true, false);
return raytraceresult == null || raytraceresult.typeOfHit == RayTraceResult.Type.MISS;
}
public boolean canEntityStandOnPos(BlockPos pos)
{
return !this.world.getBlockState(pos).isFullBlock();
}
}

View File

@@ -0,0 +1,34 @@
package net.minecraft.pathfinding;
public enum PathNodeType
{
BLOCKED(-1.0F),
OPEN(0.0F),
WALKABLE(0.0F),
TRAPDOOR(0.0F),
FENCE(-1.0F),
LAVA(-1.0F),
WATER(8.0F),
RAIL(0.0F),
DANGER_FIRE(8.0F),
DAMAGE_FIRE(16.0F),
DANGER_CACTUS(8.0F),
DAMAGE_CACTUS(-1.0F),
DANGER_OTHER(8.0F),
DAMAGE_OTHER(-1.0F),
DOOR_OPEN(0.0F),
DOOR_WOOD_CLOSED(-1.0F),
DOOR_IRON_CLOSED(-1.0F);
private final float priority;
private PathNodeType(float priorityIn)
{
this.priority = priorityIn;
}
public float getPriority()
{
return this.priority;
}
}

View File

@@ -0,0 +1,137 @@
package net.minecraft.pathfinding;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class PathPoint
{
/** The x coordinate of this point */
public final int x;
/** The y coordinate of this point */
public final int y;
/** The z coordinate of this point */
public final int z;
/** A hash of the coordinates used to identify this point */
private final int hash;
/** The index of this point in its assigned path */
public int index = -1;
/** The distance along the path to this point */
public float totalPathDistance;
/** The linear distance to the next point */
public float distanceToNext;
/** The distance to the target */
public float distanceToTarget;
/** The point preceding this in its assigned path */
public PathPoint previous;
/** True if the pathfinder has already visited this point */
public boolean visited;
public float distanceFromOrigin;
public float cost;
public float costMalus;
public PathNodeType nodeType = PathNodeType.BLOCKED;
public PathPoint(int x, int y, int z)
{
this.x = x;
this.y = y;
this.z = z;
this.hash = makeHash(x, y, z);
}
public PathPoint cloneMove(int x, int y, int z)
{
PathPoint pathpoint = new PathPoint(x, y, z);
pathpoint.index = this.index;
pathpoint.totalPathDistance = this.totalPathDistance;
pathpoint.distanceToNext = this.distanceToNext;
pathpoint.distanceToTarget = this.distanceToTarget;
pathpoint.previous = this.previous;
pathpoint.visited = this.visited;
pathpoint.distanceFromOrigin = this.distanceFromOrigin;
pathpoint.cost = this.cost;
pathpoint.costMalus = this.costMalus;
pathpoint.nodeType = this.nodeType;
return pathpoint;
}
public static int makeHash(int x, int y, int z)
{
return y & 255 | (x & 32767) << 8 | (z & 32767) << 24 | (x < 0 ? Integer.MIN_VALUE : 0) | (z < 0 ? 32768 : 0);
}
/**
* Returns the linear distance to another path point
*/
public float distanceTo(PathPoint pathpointIn)
{
float f = (float)(pathpointIn.x - this.x);
float f1 = (float)(pathpointIn.y - this.y);
float f2 = (float)(pathpointIn.z - this.z);
return MathHelper.sqrt(f * f + f1 * f1 + f2 * f2);
}
/**
* Returns the squared distance to another path point
*/
public float distanceToSquared(PathPoint pathpointIn)
{
float f = (float)(pathpointIn.x - this.x);
float f1 = (float)(pathpointIn.y - this.y);
float f2 = (float)(pathpointIn.z - this.z);
return f * f + f1 * f1 + f2 * f2;
}
public float distanceManhattan(PathPoint p_186281_1_)
{
float f = (float)Math.abs(p_186281_1_.x - this.x);
float f1 = (float)Math.abs(p_186281_1_.y - this.y);
float f2 = (float)Math.abs(p_186281_1_.z - this.z);
return f + f1 + f2;
}
public boolean equals(Object p_equals_1_)
{
if (!(p_equals_1_ instanceof PathPoint))
{
return false;
}
else
{
PathPoint pathpoint = (PathPoint)p_equals_1_;
return this.hash == pathpoint.hash && this.x == pathpoint.x && this.y == pathpoint.y && this.z == pathpoint.z;
}
}
public int hashCode()
{
return this.hash;
}
/**
* Returns true if this point has already been assigned to a path
*/
public boolean isAssigned()
{
return this.index >= 0;
}
public String toString()
{
return this.x + ", " + this.y + ", " + this.z;
}
@SideOnly(Side.CLIENT)
public static PathPoint createFromBuffer(PacketBuffer buf)
{
PathPoint pathpoint = new PathPoint(buf.readInt(), buf.readInt(), buf.readInt());
pathpoint.distanceFromOrigin = buf.readFloat();
pathpoint.cost = buf.readFloat();
pathpoint.costMalus = buf.readFloat();
pathpoint.visited = buf.readBoolean();
pathpoint.nodeType = PathNodeType.values()[buf.readInt()];
pathpoint.distanceToTarget = buf.readFloat();
return pathpoint;
}
}

View File

@@ -0,0 +1,120 @@
package net.minecraft.pathfinding;
import com.google.common.collect.Lists;
import java.util.List;
import javax.annotation.Nullable;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorldEventListener;
import net.minecraft.world.World;
public class PathWorldListener implements IWorldEventListener
{
private final List<PathNavigate> navigations = Lists.<PathNavigate>newArrayList();
public void notifyBlockUpdate(World worldIn, BlockPos pos, IBlockState oldState, IBlockState newState, int flags)
{
if (this.didBlockChange(worldIn, pos, oldState, newState))
{
int i = 0;
for (int j = this.navigations.size(); i < j; ++i)
{
PathNavigate pathnavigate = this.navigations.get(i);
if (pathnavigate != null && !pathnavigate.canUpdatePathOnTimeout())
{
Path path = pathnavigate.getPath();
if (path != null && !path.isFinished() && path.getCurrentPathLength() != 0)
{
PathPoint pathpoint = pathnavigate.currentPath.getFinalPathPoint();
double d0 = pos.distanceSq(((double)pathpoint.x + pathnavigate.entity.posX) / 2.0D, ((double)pathpoint.y + pathnavigate.entity.posY) / 2.0D, ((double)pathpoint.z + pathnavigate.entity.posZ) / 2.0D);
int k = (path.getCurrentPathLength() - path.getCurrentPathIndex()) * (path.getCurrentPathLength() - path.getCurrentPathIndex());
if (d0 < (double)k)
{
pathnavigate.updatePath();
}
}
}
}
}
}
protected boolean didBlockChange(World worldIn, BlockPos pos, IBlockState oldState, IBlockState newState)
{
AxisAlignedBB axisalignedbb = oldState.getCollisionBoundingBox(worldIn, pos);
AxisAlignedBB axisalignedbb1 = newState.getCollisionBoundingBox(worldIn, pos);
return axisalignedbb != axisalignedbb1 && (axisalignedbb == null || !axisalignedbb.equals(axisalignedbb1));
}
public void notifyLightSet(BlockPos pos)
{
}
/**
* On the client, re-renders all blocks in this range, inclusive. On the server, does nothing.
*/
public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2)
{
}
public void playSoundToAllNearExcept(@Nullable EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch)
{
}
public void spawnParticle(int particleID, boolean ignoreRange, double xCoord, double yCoord, double zCoord, double xSpeed, double ySpeed, double zSpeed, int... parameters)
{
}
public void spawnParticle(int id, boolean ignoreRange, boolean p_190570_3_, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed, int... parameters)
{
}
/**
* Called on all IWorldAccesses when an entity is created or loaded. On client worlds, starts downloading any
* necessary textures. On server worlds, adds the entity to the entity tracker.
*/
public void onEntityAdded(Entity entityIn)
{
if (entityIn instanceof EntityLiving)
{
this.navigations.add(((EntityLiving)entityIn).getNavigator());
}
}
/**
* Called on all IWorldAccesses when an entity is unloaded or destroyed. On client worlds, releases any downloaded
* textures. On server worlds, removes the entity from the entity tracker.
*/
public void onEntityRemoved(Entity entityIn)
{
if (entityIn instanceof EntityLiving)
{
this.navigations.remove(((EntityLiving)entityIn).getNavigator());
}
}
public void playRecord(SoundEvent soundIn, BlockPos pos)
{
}
public void broadcastSound(int soundID, BlockPos pos, int data)
{
}
public void playEvent(EntityPlayer player, int type, BlockPos blockPosIn, int data)
{
}
public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress)
{
}
}

View File

@@ -0,0 +1,83 @@
package net.minecraft.pathfinding;
import javax.annotation.Nullable;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLiving;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.IBlockAccess;
public class SwimNodeProcessor extends NodeProcessor
{
public PathPoint getStart()
{
return this.openPoint(MathHelper.floor(this.entity.getEntityBoundingBox().minX), MathHelper.floor(this.entity.getEntityBoundingBox().minY + 0.5D), MathHelper.floor(this.entity.getEntityBoundingBox().minZ));
}
/**
* Returns PathPoint for given coordinates
*/
public PathPoint getPathPointToCoords(double x, double y, double z)
{
return this.openPoint(MathHelper.floor(x - (double)(this.entity.width / 2.0F)), MathHelper.floor(y + 0.5D), MathHelper.floor(z - (double)(this.entity.width / 2.0F)));
}
public int findPathOptions(PathPoint[] pathOptions, PathPoint currentPoint, PathPoint targetPoint, float maxDistance)
{
int i = 0;
for (EnumFacing enumfacing : EnumFacing.values())
{
PathPoint pathpoint = this.getWaterNode(currentPoint.x + enumfacing.getFrontOffsetX(), currentPoint.y + enumfacing.getFrontOffsetY(), currentPoint.z + enumfacing.getFrontOffsetZ());
if (pathpoint != null && !pathpoint.visited && pathpoint.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint;
}
}
return i;
}
public PathNodeType getPathNodeType(IBlockAccess blockaccessIn, int x, int y, int z, EntityLiving entitylivingIn, int xSize, int ySize, int zSize, boolean canBreakDoorsIn, boolean canEnterDoorsIn)
{
return PathNodeType.WATER;
}
public PathNodeType getPathNodeType(IBlockAccess blockaccessIn, int x, int y, int z)
{
return PathNodeType.WATER;
}
@Nullable
private PathPoint getWaterNode(int p_186328_1_, int p_186328_2_, int p_186328_3_)
{
PathNodeType pathnodetype = this.isFree(p_186328_1_, p_186328_2_, p_186328_3_);
return pathnodetype == PathNodeType.WATER ? this.openPoint(p_186328_1_, p_186328_2_, p_186328_3_) : null;
}
private PathNodeType isFree(int p_186327_1_, int p_186327_2_, int p_186327_3_)
{
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
for (int i = p_186327_1_; i < p_186327_1_ + this.entitySizeX; ++i)
{
for (int j = p_186327_2_; j < p_186327_2_ + this.entitySizeY; ++j)
{
for (int k = p_186327_3_; k < p_186327_3_ + this.entitySizeZ; ++k)
{
IBlockState iblockstate = this.blockaccess.getBlockState(blockpos$mutableblockpos.setPos(i, j, k));
if (iblockstate.getMaterial() != Material.WATER)
{
return PathNodeType.BLOCKED;
}
}
}
}
return PathNodeType.WATER;
}
}

View File

@@ -0,0 +1,516 @@
package net.minecraft.pathfinding;
import com.google.common.collect.Sets;
import java.util.EnumSet;
import java.util.Set;
import javax.annotation.Nullable;
import net.minecraft.block.Block;
import net.minecraft.block.BlockDoor;
import net.minecraft.block.BlockFence;
import net.minecraft.block.BlockFenceGate;
import net.minecraft.block.BlockRailBase;
import net.minecraft.block.BlockWall;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLiving;
import net.minecraft.init.Blocks;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.IBlockAccess;
public class WalkNodeProcessor extends NodeProcessor
{
protected float avoidsWater;
public void init(IBlockAccess sourceIn, EntityLiving mob)
{
super.init(sourceIn, mob);
this.avoidsWater = mob.getPathPriority(PathNodeType.WATER);
}
/**
* This method is called when all nodes have been processed and PathEntity is created.
* {@link net.minecraft.world.pathfinder.WalkNodeProcessor WalkNodeProcessor} uses this to change its field {@link
* net.minecraft.world.pathfinder.WalkNodeProcessor#avoidsWater avoidsWater}
*/
public void postProcess()
{
this.entity.setPathPriority(PathNodeType.WATER, this.avoidsWater);
super.postProcess();
}
public PathPoint getStart()
{
int i;
if (this.getCanSwim() && this.entity.isInWater())
{
i = (int)this.entity.getEntityBoundingBox().minY;
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos(MathHelper.floor(this.entity.posX), i, MathHelper.floor(this.entity.posZ));
for (Block block = this.blockaccess.getBlockState(blockpos$mutableblockpos).getBlock(); block == Blocks.FLOWING_WATER || block == Blocks.WATER; block = this.blockaccess.getBlockState(blockpos$mutableblockpos).getBlock())
{
++i;
blockpos$mutableblockpos.setPos(MathHelper.floor(this.entity.posX), i, MathHelper.floor(this.entity.posZ));
}
}
else if (this.entity.onGround)
{
i = MathHelper.floor(this.entity.getEntityBoundingBox().minY + 0.5D);
}
else
{
BlockPos blockpos;
for (blockpos = new BlockPos(this.entity); (this.blockaccess.getBlockState(blockpos).getMaterial() == Material.AIR || this.blockaccess.getBlockState(blockpos).getBlock().isPassable(this.blockaccess, blockpos)) && blockpos.getY() > 0; blockpos = blockpos.down())
{
;
}
i = blockpos.up().getY();
}
BlockPos blockpos2 = new BlockPos(this.entity);
PathNodeType pathnodetype1 = this.getPathNodeType(this.entity, blockpos2.getX(), i, blockpos2.getZ());
if (this.entity.getPathPriority(pathnodetype1) < 0.0F)
{
Set<BlockPos> set = Sets.<BlockPos>newHashSet();
set.add(new BlockPos(this.entity.getEntityBoundingBox().minX, (double)i, this.entity.getEntityBoundingBox().minZ));
set.add(new BlockPos(this.entity.getEntityBoundingBox().minX, (double)i, this.entity.getEntityBoundingBox().maxZ));
set.add(new BlockPos(this.entity.getEntityBoundingBox().maxX, (double)i, this.entity.getEntityBoundingBox().minZ));
set.add(new BlockPos(this.entity.getEntityBoundingBox().maxX, (double)i, this.entity.getEntityBoundingBox().maxZ));
for (BlockPos blockpos1 : set)
{
PathNodeType pathnodetype = this.getPathNodeType(this.entity, blockpos1);
if (this.entity.getPathPriority(pathnodetype) >= 0.0F)
{
return this.openPoint(blockpos1.getX(), blockpos1.getY(), blockpos1.getZ());
}
}
}
return this.openPoint(blockpos2.getX(), i, blockpos2.getZ());
}
/**
* Returns PathPoint for given coordinates
*/
public PathPoint getPathPointToCoords(double x, double y, double z)
{
return this.openPoint(MathHelper.floor(x), MathHelper.floor(y), MathHelper.floor(z));
}
public int findPathOptions(PathPoint[] pathOptions, PathPoint currentPoint, PathPoint targetPoint, float maxDistance)
{
int i = 0;
int j = 0;
PathNodeType pathnodetype = this.getPathNodeType(this.entity, currentPoint.x, currentPoint.y + 1, currentPoint.z);
if (this.entity.getPathPriority(pathnodetype) >= 0.0F)
{
j = MathHelper.floor(Math.max(1.0F, this.entity.stepHeight));
}
BlockPos blockpos = (new BlockPos(currentPoint.x, currentPoint.y, currentPoint.z)).down();
double d0 = (double)currentPoint.y - (1.0D - this.blockaccess.getBlockState(blockpos).getBoundingBox(this.blockaccess, blockpos).maxY);
PathPoint pathpoint = this.getSafePoint(currentPoint.x, currentPoint.y, currentPoint.z + 1, j, d0, EnumFacing.SOUTH);
PathPoint pathpoint1 = this.getSafePoint(currentPoint.x - 1, currentPoint.y, currentPoint.z, j, d0, EnumFacing.WEST);
PathPoint pathpoint2 = this.getSafePoint(currentPoint.x + 1, currentPoint.y, currentPoint.z, j, d0, EnumFacing.EAST);
PathPoint pathpoint3 = this.getSafePoint(currentPoint.x, currentPoint.y, currentPoint.z - 1, j, d0, EnumFacing.NORTH);
if (pathpoint != null && !pathpoint.visited && pathpoint.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint;
}
if (pathpoint1 != null && !pathpoint1.visited && pathpoint1.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint1;
}
if (pathpoint2 != null && !pathpoint2.visited && pathpoint2.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint2;
}
if (pathpoint3 != null && !pathpoint3.visited && pathpoint3.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint3;
}
boolean flag = pathpoint3 == null || pathpoint3.nodeType == PathNodeType.OPEN || pathpoint3.costMalus != 0.0F;
boolean flag1 = pathpoint == null || pathpoint.nodeType == PathNodeType.OPEN || pathpoint.costMalus != 0.0F;
boolean flag2 = pathpoint2 == null || pathpoint2.nodeType == PathNodeType.OPEN || pathpoint2.costMalus != 0.0F;
boolean flag3 = pathpoint1 == null || pathpoint1.nodeType == PathNodeType.OPEN || pathpoint1.costMalus != 0.0F;
if (flag && flag3)
{
PathPoint pathpoint4 = this.getSafePoint(currentPoint.x - 1, currentPoint.y, currentPoint.z - 1, j, d0, EnumFacing.NORTH);
if (pathpoint4 != null && !pathpoint4.visited && pathpoint4.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint4;
}
}
if (flag && flag2)
{
PathPoint pathpoint5 = this.getSafePoint(currentPoint.x + 1, currentPoint.y, currentPoint.z - 1, j, d0, EnumFacing.NORTH);
if (pathpoint5 != null && !pathpoint5.visited && pathpoint5.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint5;
}
}
if (flag1 && flag3)
{
PathPoint pathpoint6 = this.getSafePoint(currentPoint.x - 1, currentPoint.y, currentPoint.z + 1, j, d0, EnumFacing.SOUTH);
if (pathpoint6 != null && !pathpoint6.visited && pathpoint6.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint6;
}
}
if (flag1 && flag2)
{
PathPoint pathpoint7 = this.getSafePoint(currentPoint.x + 1, currentPoint.y, currentPoint.z + 1, j, d0, EnumFacing.SOUTH);
if (pathpoint7 != null && !pathpoint7.visited && pathpoint7.distanceTo(targetPoint) < maxDistance)
{
pathOptions[i++] = pathpoint7;
}
}
return i;
}
/**
* Returns a point that the entity can safely move to
*/
@Nullable
private PathPoint getSafePoint(int x, int y, int z, int p_186332_4_, double p_186332_5_, EnumFacing facing)
{
PathPoint pathpoint = null;
BlockPos blockpos = new BlockPos(x, y, z);
BlockPos blockpos1 = blockpos.down();
double d0 = (double)y - (1.0D - this.blockaccess.getBlockState(blockpos1).getBoundingBox(this.blockaccess, blockpos1).maxY);
if (d0 - p_186332_5_ > 1.125D)
{
return null;
}
else
{
PathNodeType pathnodetype = this.getPathNodeType(this.entity, x, y, z);
float f = this.entity.getPathPriority(pathnodetype);
double d1 = (double)this.entity.width / 2.0D;
if (f >= 0.0F)
{
pathpoint = this.openPoint(x, y, z);
pathpoint.nodeType = pathnodetype;
pathpoint.costMalus = Math.max(pathpoint.costMalus, f);
}
if (pathnodetype == PathNodeType.WALKABLE)
{
return pathpoint;
}
else
{
if (pathpoint == null && p_186332_4_ > 0 && pathnodetype != PathNodeType.FENCE && pathnodetype != PathNodeType.TRAPDOOR)
{
pathpoint = this.getSafePoint(x, y + 1, z, p_186332_4_ - 1, p_186332_5_, facing);
if (pathpoint != null && (pathpoint.nodeType == PathNodeType.OPEN || pathpoint.nodeType == PathNodeType.WALKABLE) && this.entity.width < 1.0F)
{
double d2 = (double)(x - facing.getFrontOffsetX()) + 0.5D;
double d3 = (double)(z - facing.getFrontOffsetZ()) + 0.5D;
AxisAlignedBB axisalignedbb = new AxisAlignedBB(d2 - d1, (double)y + 0.001D, d3 - d1, d2 + d1, (double)((float)y + this.entity.height), d3 + d1);
AxisAlignedBB axisalignedbb1 = this.blockaccess.getBlockState(blockpos).getBoundingBox(this.blockaccess, blockpos);
AxisAlignedBB axisalignedbb2 = axisalignedbb.expand(0.0D, axisalignedbb1.maxY - 0.002D, 0.0D);
if (this.entity.world.collidesWithAnyBlock(axisalignedbb2))
{
pathpoint = null;
}
}
}
if (pathnodetype == PathNodeType.OPEN)
{
AxisAlignedBB axisalignedbb3 = new AxisAlignedBB((double)x - d1 + 0.5D, (double)y + 0.001D, (double)z - d1 + 0.5D, (double)x + d1 + 0.5D, (double)((float)y + this.entity.height), (double)z + d1 + 0.5D);
if (this.entity.world.collidesWithAnyBlock(axisalignedbb3))
{
return null;
}
if (this.entity.width >= 1.0F)
{
PathNodeType pathnodetype1 = this.getPathNodeType(this.entity, x, y - 1, z);
if (pathnodetype1 == PathNodeType.BLOCKED)
{
pathpoint = this.openPoint(x, y, z);
pathpoint.nodeType = PathNodeType.WALKABLE;
pathpoint.costMalus = Math.max(pathpoint.costMalus, f);
return pathpoint;
}
}
int i = 0;
while (y > 0 && pathnodetype == PathNodeType.OPEN)
{
--y;
if (i++ >= this.entity.getMaxFallHeight())
{
return null;
}
pathnodetype = this.getPathNodeType(this.entity, x, y, z);
f = this.entity.getPathPriority(pathnodetype);
if (pathnodetype != PathNodeType.OPEN && f >= 0.0F)
{
pathpoint = this.openPoint(x, y, z);
pathpoint.nodeType = pathnodetype;
pathpoint.costMalus = Math.max(pathpoint.costMalus, f);
break;
}
if (f < 0.0F)
{
return null;
}
}
}
return pathpoint;
}
}
}
public PathNodeType getPathNodeType(IBlockAccess blockaccessIn, int x, int y, int z, EntityLiving entitylivingIn, int xSize, int ySize, int zSize, boolean canBreakDoorsIn, boolean canEnterDoorsIn)
{
EnumSet<PathNodeType> enumset = EnumSet.<PathNodeType>noneOf(PathNodeType.class);
PathNodeType pathnodetype = PathNodeType.BLOCKED;
double d0 = (double)entitylivingIn.width / 2.0D;
BlockPos blockpos = new BlockPos(entitylivingIn);
pathnodetype = this.getPathNodeType(blockaccessIn, x, y, z, xSize, ySize, zSize, canBreakDoorsIn, canEnterDoorsIn, enumset, pathnodetype, blockpos);
if (enumset.contains(PathNodeType.FENCE))
{
return PathNodeType.FENCE;
}
else
{
PathNodeType pathnodetype1 = PathNodeType.BLOCKED;
for (PathNodeType pathnodetype2 : enumset)
{
if (entitylivingIn.getPathPriority(pathnodetype2) < 0.0F)
{
return pathnodetype2;
}
if (entitylivingIn.getPathPriority(pathnodetype2) >= entitylivingIn.getPathPriority(pathnodetype1))
{
pathnodetype1 = pathnodetype2;
}
}
if (pathnodetype == PathNodeType.OPEN && entitylivingIn.getPathPriority(pathnodetype1) == 0.0F)
{
return PathNodeType.OPEN;
}
else
{
return pathnodetype1;
}
}
}
public PathNodeType getPathNodeType(IBlockAccess p_193577_1_, int x, int y, int z, int xSize, int ySize, int zSize, boolean canOpenDoorsIn, boolean canEnterDoorsIn, EnumSet<PathNodeType> p_193577_10_, PathNodeType p_193577_11_, BlockPos p_193577_12_)
{
for (int i = 0; i < xSize; ++i)
{
for (int j = 0; j < ySize; ++j)
{
for (int k = 0; k < zSize; ++k)
{
int l = i + x;
int i1 = j + y;
int j1 = k + z;
PathNodeType pathnodetype = this.getPathNodeType(p_193577_1_, l, i1, j1);
if (pathnodetype == PathNodeType.DOOR_WOOD_CLOSED && canOpenDoorsIn && canEnterDoorsIn)
{
pathnodetype = PathNodeType.WALKABLE;
}
if (pathnodetype == PathNodeType.DOOR_OPEN && !canEnterDoorsIn)
{
pathnodetype = PathNodeType.BLOCKED;
}
if (pathnodetype == PathNodeType.RAIL && !(p_193577_1_.getBlockState(p_193577_12_).getBlock() instanceof BlockRailBase) && !(p_193577_1_.getBlockState(p_193577_12_.down()).getBlock() instanceof BlockRailBase))
{
pathnodetype = PathNodeType.FENCE;
}
if (i == 0 && j == 0 && k == 0)
{
p_193577_11_ = pathnodetype;
}
p_193577_10_.add(pathnodetype);
}
}
}
return p_193577_11_;
}
private PathNodeType getPathNodeType(EntityLiving entitylivingIn, BlockPos pos)
{
return this.getPathNodeType(entitylivingIn, pos.getX(), pos.getY(), pos.getZ());
}
private PathNodeType getPathNodeType(EntityLiving entitylivingIn, int x, int y, int z)
{
return this.getPathNodeType(this.blockaccess, x, y, z, entitylivingIn, this.entitySizeX, this.entitySizeY, this.entitySizeZ, this.getCanOpenDoors(), this.getCanEnterDoors());
}
public PathNodeType getPathNodeType(IBlockAccess blockaccessIn, int x, int y, int z)
{
PathNodeType pathnodetype = this.getPathNodeTypeRaw(blockaccessIn, x, y, z);
if (pathnodetype == PathNodeType.OPEN && y >= 1)
{
Block block = blockaccessIn.getBlockState(new BlockPos(x, y - 1, z)).getBlock();
PathNodeType pathnodetype1 = this.getPathNodeTypeRaw(blockaccessIn, x, y - 1, z);
pathnodetype = pathnodetype1 != PathNodeType.WALKABLE && pathnodetype1 != PathNodeType.OPEN && pathnodetype1 != PathNodeType.WATER && pathnodetype1 != PathNodeType.LAVA ? PathNodeType.WALKABLE : PathNodeType.OPEN;
if (pathnodetype1 == PathNodeType.DAMAGE_FIRE || block == Blocks.MAGMA)
{
pathnodetype = PathNodeType.DAMAGE_FIRE;
}
if (pathnodetype1 == PathNodeType.DAMAGE_CACTUS)
{
pathnodetype = PathNodeType.DAMAGE_CACTUS;
}
}
pathnodetype = this.checkNeighborBlocks(blockaccessIn, x, y, z, pathnodetype);
return pathnodetype;
}
public PathNodeType checkNeighborBlocks(IBlockAccess p_193578_1_, int p_193578_2_, int p_193578_3_, int p_193578_4_, PathNodeType p_193578_5_)
{
BlockPos.PooledMutableBlockPos blockpos$pooledmutableblockpos = BlockPos.PooledMutableBlockPos.retain();
if (p_193578_5_ == PathNodeType.WALKABLE)
{
for (int i = -1; i <= 1; ++i)
{
for (int j = -1; j <= 1; ++j)
{
if (i != 0 || j != 0)
{
Block block = p_193578_1_.getBlockState(blockpos$pooledmutableblockpos.setPos(i + p_193578_2_, p_193578_3_, j + p_193578_4_)).getBlock();
if (block == Blocks.CACTUS)
{
p_193578_5_ = PathNodeType.DANGER_CACTUS;
}
else if (block == Blocks.FIRE)
{
p_193578_5_ = PathNodeType.DANGER_FIRE;
}
else if(block.isBurning(p_193578_1_,blockpos$pooledmutableblockpos)) p_193578_5_ = PathNodeType.DAMAGE_FIRE;
}
}
}
}
blockpos$pooledmutableblockpos.release();
return p_193578_5_;
}
protected PathNodeType getPathNodeTypeRaw(IBlockAccess p_189553_1_, int p_189553_2_, int p_189553_3_, int p_189553_4_)
{
BlockPos blockpos = new BlockPos(p_189553_2_, p_189553_3_, p_189553_4_);
IBlockState iblockstate = p_189553_1_.getBlockState(blockpos);
Block block = iblockstate.getBlock();
Material material = iblockstate.getMaterial();
PathNodeType type = block.getAiPathNodeType(iblockstate, p_189553_1_, blockpos);
if (type != null) return type;
if (material == Material.AIR)
{
return PathNodeType.OPEN;
}
else if (block != Blocks.TRAPDOOR && block != Blocks.IRON_TRAPDOOR && block != Blocks.WATERLILY)
{
if (block == Blocks.FIRE)
{
return PathNodeType.DAMAGE_FIRE;
}
else if (block == Blocks.CACTUS)
{
return PathNodeType.DAMAGE_CACTUS;
}
else if (block instanceof BlockDoor && material == Material.WOOD && !((Boolean)iblockstate.getValue(BlockDoor.OPEN)).booleanValue())
{
return PathNodeType.DOOR_WOOD_CLOSED;
}
else if (block instanceof BlockDoor && material == Material.IRON && !((Boolean)iblockstate.getValue(BlockDoor.OPEN)).booleanValue())
{
return PathNodeType.DOOR_IRON_CLOSED;
}
else if (block instanceof BlockDoor && ((Boolean)iblockstate.getValue(BlockDoor.OPEN)).booleanValue())
{
return PathNodeType.DOOR_OPEN;
}
else if (block instanceof BlockRailBase)
{
return PathNodeType.RAIL;
}
else if (!(block instanceof BlockFence) && !(block instanceof BlockWall) && (!(block instanceof BlockFenceGate) || ((Boolean)iblockstate.getValue(BlockFenceGate.OPEN)).booleanValue()))
{
if (material == Material.WATER)
{
return PathNodeType.WATER;
}
else if (material == Material.LAVA)
{
return PathNodeType.LAVA;
}
else
{
return block.isPassable(p_189553_1_, blockpos) ? PathNodeType.OPEN : PathNodeType.BLOCKED;
}
}
else
{
return PathNodeType.FENCE;
}
}
else
{
return PathNodeType.TRAPDOOR;
}
}
}

View File

@@ -0,0 +1,7 @@
// Auto generated package-info by MCP
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
package net.minecraft.pathfinding;
import mcp.MethodsReturnNonnullByDefault;
import javax.annotation.ParametersAreNonnullByDefault;