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 closedSet = Sets.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); } }