package net.minecraft.pathfinding;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.init.Blocks;
import net.minecraft.util.IntHashMap;
import net.minecraft.util.MathHelper;
import net.minecraft.world.IBlockAccess;
import net.minecraftforge.common.util.ForgeDirection;
import pneumaticCraft.common.entity.living.EntityDrone;
/**
* This class is highly derived from Minecraft's PathFinder class. As that class contains mostly I didn't see a way to making this class a subclass
* of PathFinder. And yes, there are accesstransformers, but I think copying a class is better than editing a base class. Let me know if you know
* better ways to do this.
*/
public class PathFinderDrone{
private final EntityDrone drone;
/** Used to find obstacles */
private final IBlockAccess worldMap;
/** The path being generated */
private final Path path = new Path();
/** The points in the path */
private final IntHashMap pointMap = new IntHashMap();
/** Selection of path points to add to the path */
private final PathPoint[] pathOptions = new PathPoint[32];
/** should the PathFinder go through wodden door blocks */
// private final boolean isWoddenDoorAllowed;
/**
* should the PathFinder disregard BlockMovement type materials in its path
*/
// private final boolean isMovementBlockAllowed;
private boolean isPathingInWater;
/** tells the FathFinder to not stop pathing underwater */
private final boolean canEntityDrown;
public PathFinderDrone(EntityDrone drone, IBlockAccess world, boolean pathFindThroughWoodenDoor,
boolean movementBlockAllowed, boolean pathFindThroughWater, boolean canDrown){
this.drone = drone;
worldMap = world;
//isWoddenDoorAllowed = pathFindThroughWoodenDoor;
// isMovementBlockAllowed = movementBlockAllowed;
isPathingInWater = pathFindThroughWater;
canEntityDrown = canDrown;
}
/**
* Creates a path from one entity to another within a minimum distance
*/
public PathEntity createEntityPathTo(Entity par1Entity, Entity par2Entity, float par3){
return this.createEntityPathTo(par1Entity, par2Entity.posX, par2Entity.boundingBox.minY, par2Entity.posZ, par3);
}
/**
* Creates a path from an entity to a specified location within a minimum distance
*/
public PathEntity createEntityPathTo(Entity par1Entity, int par2, int par3, int par4, float par5){
return this.createEntityPathTo(par1Entity, par2 + 0.5F, par3 + 0.5F, par4 + 0.5F, par5);
}
/**
* Internal implementation of creating a path from an entity to a point
*/
private PathEntity createEntityPathTo(Entity par1Entity, double par2, double par4, double par6, float par8){
path.clearPath();
pointMap.clearMap();
boolean flag = isPathingInWater;
int i = MathHelper.floor_double(par1Entity.boundingBox.minY + 0.5D);
if(canEntityDrown && par1Entity.isInWater()) {
i = (int)par1Entity.boundingBox.minY;
for(Block j = worldMap.getBlock(MathHelper.floor_double(par1Entity.posX), i, MathHelper.floor_double(par1Entity.posZ)); j == Blocks.water || j == Blocks.flowing_water; j = worldMap.getBlock(MathHelper.floor_double(par1Entity.posX), i, MathHelper.floor_double(par1Entity.posZ))) {
++i;
}
flag = isPathingInWater;
isPathingInWater = false;
} else {
i = MathHelper.floor_double(par1Entity.boundingBox.minY + 0.5D);
}
PathPoint pathpoint = openPoint(MathHelper.floor_double(par1Entity.boundingBox.minX), i, MathHelper.floor_double(par1Entity.boundingBox.minZ));
PathPoint pathpoint1 = openPoint(MathHelper.floor_double(par2 - par1Entity.width / 2.0F), MathHelper.floor_double(par4), MathHelper.floor_double(par6 - par1Entity.width / 2.0F));
PathPoint pathpoint2 = new PathPoint(MathHelper.floor_float(par1Entity.width + 1.0F), MathHelper.floor_float(par1Entity.height + 1.0F), MathHelper.floor_float(par1Entity.width + 1.0F));
PathEntity pathentity = addToPath(par1Entity, pathpoint, pathpoint1, pathpoint2, par8);
isPathingInWater = flag;
return pathentity;
}
/**
* Adds a path from start to end and returns the whole path (args: unused, start, end, unused, maxDistance)
*/
private PathEntity addToPath(Entity par1Entity, PathPoint par2PathPoint, PathPoint par3PathPoint, PathPoint par4PathPoint, float par5){
par2PathPoint.totalPathDistance = 0.0F;
par2PathPoint.distanceToNext = par2PathPoint.distanceTo(par3PathPoint);
par2PathPoint.distanceToTarget = par2PathPoint.distanceToNext;
path.clearPath();
path.addPoint(par2PathPoint);
PathPoint pathpoint3 = par2PathPoint;
while(!path.isPathEmpty()) {
PathPoint pathpoint4 = path.dequeue();
if(pathpoint4.equals(par3PathPoint)) {
return createEntityPath(par2PathPoint, par3PathPoint);
}
if(pathpoint4.distanceTo(par3PathPoint) < pathpoint3.distanceTo(par3PathPoint)) {
pathpoint3 = pathpoint4;
}
pathpoint4.isFirst = true;
int i = findPathOptions(par1Entity, pathpoint4, par4PathPoint, par3PathPoint, par5);
for(int j = 0; j < i; ++j) {
PathPoint pathpoint5 = pathOptions[j];
float f1 = pathpoint4.totalPathDistance + pathpoint4.distanceTo(pathpoint5);
if(!pathpoint5.isAssigned() || f1 < pathpoint5.totalPathDistance) {
pathpoint5.previous = pathpoint4;
pathpoint5.totalPathDistance = f1;
pathpoint5.distanceToNext = pathpoint5.distanceTo(par3PathPoint);
if(pathpoint5.isAssigned()) {
path.changeDistance(pathpoint5, pathpoint5.totalPathDistance + pathpoint5.distanceToNext);
} else {
pathpoint5.distanceToTarget = pathpoint5.totalPathDistance + pathpoint5.distanceToNext;
path.addPoint(pathpoint5);
}
}
}
}
if(pathpoint3 == par2PathPoint) {
return null;
} else {
return createEntityPath(par2PathPoint, pathpoint3);
}
}
/**
* populates pathOptions with available points and returns the number of options found (args: unused1, currentPoint,
* unused2, targetPoint, maxDistance)
*/
private int findPathOptions(Entity par1Entity, PathPoint par2PathPoint, PathPoint par3PathPoint, PathPoint par4PathPoint, float par5){
int i = 0;
byte b0 = 0;
if(getVerticalOffset(par1Entity, par2PathPoint.xCoord, par2PathPoint.yCoord + 1, par2PathPoint.zCoord, par3PathPoint) == 1) {
b0 = 1;
}
for(ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
PathPoint safePoint = getSafePoint(par1Entity, par2PathPoint.xCoord + dir.offsetX, par2PathPoint.yCoord + dir.offsetY, par2PathPoint.zCoord + dir.offsetZ, par3PathPoint, b0);
if(safePoint != null && !safePoint.isFirst && safePoint.distanceTo(par4PathPoint) < par5) {
pathOptions[i++] = safePoint;
}
}
return i;
}
/**
* Returns a point that the entity can safely move to
*/
private PathPoint getSafePoint(Entity par1Entity, int par2, int par3, int par4, PathPoint par5PathPoint, int par6){
PathPoint pathpoint1 = null;
/* int i1 = getVerticalOffset(par1Entity, par2, par3, par4, par5PathPoint);
if(i1 == 2) {
return openPoint(par2, par3, par4);
} else {
if(i1 == 1) {
pathpoint1 = openPoint(par2, par3, par4);
}
if(pathpoint1 == null && par6 > 0 && i1 != -3 && i1 != -4 && getVerticalOffset(par1Entity, par2, par3 + par6, par4, par5PathPoint) == 1) {
pathpoint1 = openPoint(par2, par3 + par6, par4);
par3 += par6;
}
if(pathpoint1 != null) {
int j1 = 0;
int k1 = 0;
while(par3 > 0) {
k1 = getVerticalOffset(par1Entity, par2, par3 - 1, par4, par5PathPoint);
if(isPathingInWater && k1 == -1) {
return null;
}
if(k1 != 1) {
break;
}
if(j1++ >= par1Entity.getMaxSafePointTries()) {
// return null;
}
--par3;
if(par3 > 0) {
pathpoint1 = openPoint(par2, par3, par4);
}
}
if(k1 == -2) {
return null;
}
}*/
if(drone.isBlockValidPathfindBlock(par2, par3, par4)) pathpoint1 = openPoint(par2, par3, par4);
return pathpoint1;
}
/**
* Returns a mapped point or creates and adds one
*/
private final PathPoint openPoint(int par1, int par2, int par3){
int l = PathPoint.makeHash(par1, par2, par3);
PathPoint pathpoint = (PathPoint)pointMap.lookup(l);
if(pathpoint == null) {
pathpoint = new PathPoint(par1, par2, par3);
pointMap.addKey(l, pathpoint);
}
return pathpoint;
}
/**
* Checks if an entity collides with blocks at a position. Returns 1 if clear, 0 for colliding with any solid block,
* -1 for water(if avoiding water) but otherwise clear, -2 for lava, -3 for fence, -4 for closed trapdoor, 2 if
* otherwise clear except for open trapdoor or water(if not avoiding)
*/
public int getVerticalOffset(Entity par1Entity, int par2, int par3, int par4, PathPoint par5PathPoint){
return 1;
// return func_82565_a(par1Entity, par2, par3, par4, par5PathPoint, isPathingInWater, isMovementBlockAllowed, isWoddenDoorAllowed);
}
/**
* Returns a new PathEntity for a given start and end point
*/
private PathEntity createEntityPath(PathPoint par1PathPoint, PathPoint par2PathPoint){
int i = 1;
PathPoint pathpoint2;
for(pathpoint2 = par2PathPoint; pathpoint2.previous != null; pathpoint2 = pathpoint2.previous) {
++i;
}
PathPoint[] apathpoint = new PathPoint[i];
pathpoint2 = par2PathPoint;
--i;
for(apathpoint[i] = par2PathPoint; pathpoint2.previous != null; apathpoint[i] = pathpoint2) {
pathpoint2 = pathpoint2.previous;
--i;
}
return new PathEntity(apathpoint);
}
}