mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-13 06:37:34 +00:00
687 lines
30 KiB
Java
687 lines
30 KiB
Java
package noppes.npcs.ai.pathfinder;
|
|
|
|
import com.google.common.collect.Maps;
|
|
import com.google.common.collect.Sets;
|
|
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.entity.Entity;
|
|
import net.minecraft.entity.EntityLiving;
|
|
import net.minecraft.init.Blocks;
|
|
import net.minecraft.pathfinding.PathFinder;
|
|
import net.minecraft.util.MathHelper;
|
|
import net.minecraft.util.math.BlockPos;
|
|
import net.minecraft.util.math.IntHashMap;
|
|
import net.minecraft.world.IBlockAccess;
|
|
import noppes.npcs.entity.EntityCustomNpc;
|
|
import noppes.npcs.entity.EntityNPCInterface;
|
|
|
|
import java.util.EnumSet;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
public class FlyPathFinder extends PathFinder {
|
|
private static final float STRAIGHT_COST = 1.0F;
|
|
private static final float DIAGONAL_2D_COST = 1.4142135F;
|
|
private static final float DIAGONAL_3D_COST = 1.7320508F;
|
|
/**
|
|
* Used to find obstacles
|
|
*/
|
|
private IBlockAccess worldMap;
|
|
/**
|
|
* The path being generated
|
|
*/
|
|
private PathHeap path = new PathHeap();
|
|
/**
|
|
* The points in the path
|
|
*/
|
|
protected final IntHashMap<NPCPathPoint> pointMap = new IntHashMap<NPCPathPoint>();
|
|
/**
|
|
* Selection of path points to add to the path
|
|
*/
|
|
private NPCPathPoint[] pathOptions = new NPCPathPoint[32];
|
|
private Entity theEntity;
|
|
private final Map<PathNodeType, Float> mapPathPriority = Maps.newEnumMap(PathNodeType.class);
|
|
|
|
|
|
private boolean isPathingInWater;
|
|
private boolean isMovementBlockAllowed;
|
|
private boolean isWoodenDoorAllowed;
|
|
private boolean canEntityDrown;
|
|
|
|
private int drowningType;
|
|
private boolean immuneToFire;
|
|
|
|
public FlyPathFinder(IBlockAccess _worldMap, boolean doorsAllowed, boolean closedDoors, boolean canPathWater, boolean canDrown, Entity entityIn) {
|
|
super(_worldMap, doorsAllowed, closedDoors, canPathWater, canDrown);
|
|
this.theEntity = entityIn;
|
|
this.worldMap = _worldMap;
|
|
|
|
this.isWoodenDoorAllowed = doorsAllowed;
|
|
this.isMovementBlockAllowed = closedDoors;
|
|
this.isPathingInWater = canPathWater;
|
|
this.canEntityDrown = canDrown;
|
|
}
|
|
|
|
/**
|
|
* Creates a path from one entity to another within a minimum distance
|
|
*/
|
|
public NPCPath createEntityPathTo(Entity entityFrom, Entity entityTo, float distance) {
|
|
return this.createEntityPathTo(entityFrom, entityTo.posX, entityTo.boundingBox.minY, entityTo.posZ, distance);
|
|
}
|
|
|
|
/**
|
|
* Creates a path from an entity to a specified location within a minimum distance
|
|
*/
|
|
public NPCPath createEntityPathTo(Entity entityFrom, int xTo, int yTo, int zTo, float distance) {
|
|
return this.createEntityPathTo(entityFrom, (double) ((float) xTo + 0.5F), (double) ((float) yTo + 0.5F), (double) ((float) zTo + 0.5F), distance);
|
|
}
|
|
|
|
/**
|
|
* Internal implementation of creating a path from an entity to a point
|
|
*/
|
|
|
|
private NPCPath createEntityPathTo(Entity entityIn, double x, double y, double z, float distance) {
|
|
this.path.clearPath();
|
|
this.pointMap.clearMap();
|
|
|
|
this.drowningType = ((EntityNPCInterface) theEntity).stats.drowningType;
|
|
this.immuneToFire = ((EntityNPCInterface) theEntity).stats.immuneToFire;
|
|
|
|
NPCPathPoint pathpoint = this.getStart();
|
|
NPCPathPoint pathpoint1 = this.getPathPointToCoords(entityIn, x, y, z);
|
|
NPCPathPoint pathPoint2 = new NPCPathPoint((int) Math.ceil(entityIn.width), (int) Math.ceil(entityIn.height), (int) Math.ceil(entityIn.width));
|
|
NPCPath pathentity = addToPath(entityIn, pathpoint, pathpoint1, pathPoint2, distance);
|
|
return pathentity;
|
|
}
|
|
|
|
public NPCPathPoint getStart() {
|
|
int i;
|
|
|
|
if (((EntityNPCInterface) theEntity).ais.canSwim && this.theEntity.isInWater()) {
|
|
i = (int) this.theEntity.boundingBox.minY;
|
|
BlockPos.MutableBlockPos muteBlock = new BlockPos.MutableBlockPos(MathHelper.floor_double(this.theEntity.posX), i, MathHelper.floor_double(this.theEntity.posZ));
|
|
|
|
for (Block block = this.worldMap.getBlock(muteBlock.getX(), muteBlock.getY(), muteBlock.getZ()); block == Blocks.flowing_water || block == Blocks.water; block = this.worldMap.getBlock(muteBlock.getX(), muteBlock.getY(), muteBlock.getZ())) {
|
|
++i;
|
|
muteBlock.setPos(MathHelper.floor_double(this.theEntity.posX), i, MathHelper.floor_double(this.theEntity.posZ));
|
|
}
|
|
} else {
|
|
i = MathHelper.floor_double(this.theEntity.boundingBox.minY + 0.5D);
|
|
}
|
|
|
|
BlockPos blockpos1 = new BlockPos(this.theEntity);
|
|
PathNodeType pathnodetype1 = this.getPathNodeType((EntityLiving) this.theEntity, blockpos1.getX(), i, blockpos1.getZ());
|
|
|
|
if (this.getPathPriority(pathnodetype1) < 0.0F) {
|
|
Set<BlockPos> set = Sets.<BlockPos>newHashSet();
|
|
set.add(new BlockPos(this.theEntity.boundingBox.minX, (double) i, this.theEntity.boundingBox.minZ));
|
|
set.add(new BlockPos(this.theEntity.boundingBox.minX, (double) i, this.theEntity.boundingBox.maxZ));
|
|
set.add(new BlockPos(this.theEntity.boundingBox.maxX, (double) i, this.theEntity.boundingBox.minZ));
|
|
set.add(new BlockPos(this.theEntity.boundingBox.maxX, (double) i, this.theEntity.boundingBox.maxZ));
|
|
|
|
for (BlockPos blockpos : set) {
|
|
PathNodeType pathnodetype = this.getPathNodeType((EntityLiving) this.theEntity, blockpos);
|
|
|
|
if (this.getPathPriority(pathnodetype) >= 0.0F) {
|
|
return openPoint(blockpos.getX(), blockpos.getY(), blockpos.getZ());
|
|
}
|
|
}
|
|
}
|
|
|
|
return openPoint(blockpos1.getX(), i, blockpos1.getZ());
|
|
}
|
|
|
|
|
|
public NPCPathPoint getPathPointToCoords(Entity entityIn, double x, double y, double z) {
|
|
return openPoint(MathHelper.floor_double(x), MathHelper.floor_double(y), MathHelper.floor_double(z));
|
|
}
|
|
|
|
|
|
private NPCPath addToPath(Entity p_75861_1_, NPCPathPoint p_75861_2_, NPCPathPoint p_75861_3_, NPCPathPoint p_75861_4_, float p_75861_5_) {
|
|
p_75861_2_.totalPathDistance = 0.0F;
|
|
p_75861_2_.distanceToNext = this.estimateCostToTarget(p_75861_2_, p_75861_3_);
|
|
p_75861_2_.distanceToTarget = p_75861_2_.distanceToNext;
|
|
this.path.clearPath();
|
|
this.path.addPoint(p_75861_2_);
|
|
NPCPathPoint pathpoint3 = p_75861_2_;
|
|
|
|
int x = 0;
|
|
while (!this.path.isPathEmpty()) {
|
|
x++;
|
|
|
|
if (x >= 200) {
|
|
break;
|
|
}
|
|
|
|
NPCPathPoint pathpoint4 = this.path.dequeue();
|
|
|
|
if (pathpoint4.equals(p_75861_3_)) {
|
|
return this.createEntityPath(p_75861_2_, p_75861_3_);
|
|
}
|
|
|
|
if (this.estimateCostToTarget(pathpoint4, p_75861_3_) < this.estimateCostToTarget(pathpoint3, p_75861_3_)) {
|
|
pathpoint3 = pathpoint4;
|
|
}
|
|
|
|
pathpoint4.isFirst = true;
|
|
int i = this.findPathOptions(p_75861_1_, pathpoint4, p_75861_4_, p_75861_3_, p_75861_5_);
|
|
|
|
for (int j = 0; j < i; ++j) {
|
|
NPCPathPoint pathpoint5 = this.pathOptions[j];
|
|
float f1 = pathpoint4.totalPathDistance + this.getTraversalCost(pathpoint4, pathpoint5)
|
|
+ this.getDirectionalPenalty(pathpoint4, pathpoint5, p_75861_3_);
|
|
|
|
if (!pathpoint5.isAssigned() || f1 < pathpoint5.totalPathDistance) {
|
|
pathpoint5.previous = pathpoint4;
|
|
pathpoint5.totalPathDistance = f1;
|
|
pathpoint5.distanceToNext = this.estimateCostToTarget(pathpoint5, p_75861_3_);
|
|
|
|
if (pathpoint5.isAssigned()) {
|
|
this.path.changeDistance(pathpoint5, pathpoint5.totalPathDistance + pathpoint5.distanceToNext);
|
|
} else {
|
|
pathpoint5.distanceToTarget = pathpoint5.totalPathDistance + pathpoint5.distanceToNext;
|
|
this.path.addPoint(pathpoint5);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pathpoint3 == p_75861_2_) {
|
|
return null;
|
|
} else {
|
|
return this.createEntityPath(p_75861_2_, pathpoint3);
|
|
}
|
|
}
|
|
|
|
private float getTraversalCost(NPCPathPoint from, NPCPathPoint to) {
|
|
int dx = Math.abs(to.xCoord - from.xCoord);
|
|
int dy = Math.abs(to.yCoord - from.yCoord);
|
|
int dz = Math.abs(to.zCoord - from.zCoord);
|
|
int changedAxes = dx + dy + dz;
|
|
if (changedAxes <= 1) {
|
|
return STRAIGHT_COST;
|
|
}
|
|
if (changedAxes == 2) {
|
|
return DIAGONAL_2D_COST;
|
|
}
|
|
return DIAGONAL_3D_COST;
|
|
}
|
|
|
|
private float getDirectionalPenalty(NPCPathPoint from, NPCPathPoint to, NPCPathPoint goal) {
|
|
int stepX = to.xCoord - from.xCoord;
|
|
int stepY = to.yCoord - from.yCoord;
|
|
int stepZ = to.zCoord - from.zCoord;
|
|
int goalX = goal.xCoord - from.xCoord;
|
|
int goalY = goal.yCoord - from.yCoord;
|
|
int goalZ = goal.zCoord - from.zCoord;
|
|
int stepLen = Math.abs(stepX) + Math.abs(stepY) + Math.abs(stepZ);
|
|
int goalLen = Math.abs(goalX) + Math.abs(goalY) + Math.abs(goalZ);
|
|
|
|
if (stepLen == 0 || goalLen == 0) {
|
|
return 0.0F;
|
|
}
|
|
|
|
float alignment = (float) (stepX * goalX + stepY * goalY + stepZ * goalZ) / (float) (stepLen * goalLen);
|
|
return (1.0F - alignment) * 0.04F;
|
|
}
|
|
|
|
private float estimateCostToTarget(NPCPathPoint from, NPCPathPoint to) {
|
|
float dx = Math.abs(to.xCoord - from.xCoord);
|
|
float dy = Math.abs(to.yCoord - from.yCoord);
|
|
float dz = Math.abs(to.zCoord - from.zCoord);
|
|
|
|
float max = Math.max(dx, Math.max(dy, dz));
|
|
float min = Math.min(dx, Math.min(dy, dz));
|
|
float mid = dx + dy + dz - max - min;
|
|
|
|
return DIAGONAL_3D_COST * min + DIAGONAL_2D_COST * (mid - min) + STRAIGHT_COST * (max - mid);
|
|
}
|
|
|
|
/**
|
|
* populates pathOptions with available points and returns the number of options found (args: unused1, currentPoint,
|
|
* unused2, targetPoint, maxDistance)
|
|
*/
|
|
private int findPathOptions(Entity entity, NPCPathPoint currentPoint, NPCPathPoint p_75860_3_, NPCPathPoint targetPoint, float maxDistance) {
|
|
int i = 0;
|
|
byte b0 = 0;
|
|
|
|
if (this.getVerticalOffset(entity, currentPoint.xCoord, currentPoint.yCoord + 1, currentPoint.zCoord, p_75860_3_) == 1) {
|
|
b0 = 1;
|
|
}
|
|
|
|
NPCPathPoint pathpoint0 = this.getSafePoint(entity, currentPoint.xCoord, currentPoint.yCoord, currentPoint.zCoord + 1, p_75860_3_, b0);
|
|
NPCPathPoint pathpoint1 = this.getSafePoint(entity, currentPoint.xCoord - 1, currentPoint.yCoord, currentPoint.zCoord, p_75860_3_, b0);
|
|
NPCPathPoint pathpoint2 = this.getSafePoint(entity, currentPoint.xCoord + 1, currentPoint.yCoord, currentPoint.zCoord, p_75860_3_, b0);
|
|
NPCPathPoint pathpoint3 = this.getSafePoint(entity, currentPoint.xCoord, currentPoint.yCoord, currentPoint.zCoord - 1, p_75860_3_, b0);
|
|
NPCPathPoint pathpoint4 = this.getSafePoint(entity, currentPoint.xCoord, currentPoint.yCoord + 1, currentPoint.zCoord, p_75860_3_, b0);
|
|
NPCPathPoint pathpoint5 = this.getSafePoint(entity, currentPoint.xCoord, currentPoint.yCoord - 1, currentPoint.zCoord, p_75860_3_, b0);
|
|
|
|
if (pathpoint0 != null && !pathpoint0.isFirst && pathpoint0.distanceTo(targetPoint) < maxDistance) {
|
|
this.pathOptions[i++] = pathpoint0;
|
|
}
|
|
|
|
if (pathpoint1 != null && !pathpoint1.isFirst && pathpoint1.distanceTo(targetPoint) < maxDistance) {
|
|
this.pathOptions[i++] = pathpoint1;
|
|
}
|
|
|
|
if (pathpoint2 != null && !pathpoint2.isFirst && pathpoint2.distanceTo(targetPoint) < maxDistance) {
|
|
this.pathOptions[i++] = pathpoint2;
|
|
}
|
|
|
|
if (pathpoint3 != null && !pathpoint3.isFirst && pathpoint3.distanceTo(targetPoint) < maxDistance) {
|
|
this.pathOptions[i++] = pathpoint3;
|
|
}
|
|
|
|
if (pathpoint4 != null && !pathpoint4.isFirst && pathpoint4.distanceTo(targetPoint) < maxDistance) {
|
|
this.pathOptions[i++] = pathpoint4;
|
|
}
|
|
|
|
if (pathpoint5 != null && !pathpoint5.isFirst && pathpoint5.distanceTo(targetPoint) < maxDistance) {
|
|
this.pathOptions[i++] = pathpoint5;
|
|
}
|
|
|
|
boolean flag = pathpoint3 != null && pathpoint3.costMalus != 1 && pathpoint3.costMalus != 2;
|
|
boolean flag1 = pathpoint0 != null && pathpoint0.costMalus != 1 && pathpoint0.costMalus != 2;
|
|
boolean flag2 = pathpoint2 != null && pathpoint2.costMalus != 1 && pathpoint2.costMalus != 2;
|
|
boolean flag3 = pathpoint1 != null && pathpoint1.costMalus != 1 && pathpoint1.costMalus != 2;
|
|
boolean flag4 = pathpoint4 != null && pathpoint4.costMalus != 1 && pathpoint4.costMalus != 2;
|
|
boolean flag5 = pathpoint5 != null && pathpoint5.costMalus != 1 && pathpoint5.costMalus != 2;
|
|
|
|
if (flag && flag3) {
|
|
NPCPathPoint pathpoint6 = this.getSafePoint(entity, currentPoint.xCoord - 1, currentPoint.yCoord, currentPoint.zCoord - 1, p_75860_3_, b0);
|
|
|
|
if (pathpoint6 != null && !pathpoint6.isFirst && pathpoint6.distanceTo(targetPoint) < maxDistance) {
|
|
pathOptions[i++] = pathpoint6;
|
|
}
|
|
}
|
|
|
|
if (flag && flag2) {
|
|
NPCPathPoint pathpoint6 = this.getSafePoint(entity, currentPoint.xCoord + 1, currentPoint.yCoord, currentPoint.zCoord - 1, p_75860_3_, b0);
|
|
|
|
if (pathpoint6 != null && !pathpoint6.isFirst && pathpoint6.distanceTo(targetPoint) < maxDistance) {
|
|
pathOptions[i++] = pathpoint6;
|
|
}
|
|
}
|
|
|
|
if (flag1 && flag3) {
|
|
NPCPathPoint pathpoint6 = this.getSafePoint(entity, currentPoint.xCoord - 1, currentPoint.yCoord, currentPoint.zCoord + 1, p_75860_3_, b0);
|
|
|
|
if (pathpoint6 != null && !pathpoint6.isFirst && pathpoint6.distanceTo(targetPoint) < maxDistance) {
|
|
pathOptions[i++] = pathpoint6;
|
|
}
|
|
}
|
|
|
|
if (flag1 && flag2) {
|
|
NPCPathPoint pathpoint6 = this.getSafePoint(entity, currentPoint.xCoord + 1, currentPoint.yCoord, currentPoint.zCoord + 1, p_75860_3_, b0);
|
|
|
|
if (pathpoint6 != null && !pathpoint6.isFirst && pathpoint6.distanceTo(targetPoint) < maxDistance) {
|
|
pathOptions[i++] = pathpoint6;
|
|
}
|
|
}
|
|
|
|
if (flag && flag4) {
|
|
NPCPathPoint pathpoint6 = this.getSafePoint(entity, currentPoint.xCoord, currentPoint.yCoord + 1, currentPoint.zCoord - 1, p_75860_3_, b0);
|
|
|
|
if (pathpoint6 != null && !pathpoint6.isFirst && pathpoint6.distanceTo(targetPoint) < maxDistance) {
|
|
pathOptions[i++] = pathpoint6;
|
|
}
|
|
}
|
|
|
|
if (flag1 && flag4) {
|
|
NPCPathPoint pathpoint6 = this.getSafePoint(entity, currentPoint.xCoord, currentPoint.yCoord + 1, currentPoint.zCoord + 1, p_75860_3_, b0);
|
|
|
|
if (pathpoint6 != null && !pathpoint6.isFirst && pathpoint6.distanceTo(targetPoint) < maxDistance) {
|
|
pathOptions[i++] = pathpoint6;
|
|
}
|
|
}
|
|
|
|
if (flag2 && flag4) {
|
|
NPCPathPoint pathpoint6 = this.getSafePoint(entity, currentPoint.xCoord + 1, currentPoint.yCoord + 1, currentPoint.zCoord, p_75860_3_, b0);
|
|
|
|
if (pathpoint6 != null && !pathpoint6.isFirst && pathpoint6.distanceTo(targetPoint) < maxDistance) {
|
|
pathOptions[i++] = pathpoint6;
|
|
}
|
|
}
|
|
|
|
if (flag3 && flag4) {
|
|
NPCPathPoint pathpoint6 = this.getSafePoint(entity, currentPoint.xCoord - 1, currentPoint.yCoord + 1, currentPoint.zCoord, p_75860_3_, b0);
|
|
|
|
if (pathpoint6 != null && !pathpoint6.isFirst && pathpoint6.distanceTo(targetPoint) < maxDistance) {
|
|
pathOptions[i++] = pathpoint6;
|
|
}
|
|
}
|
|
|
|
if (flag && flag5) {
|
|
NPCPathPoint pathpoint6 = this.getSafePoint(entity, currentPoint.xCoord, currentPoint.yCoord - 1, currentPoint.zCoord - 1, p_75860_3_, b0);
|
|
|
|
if (pathpoint6 != null && !pathpoint6.isFirst && pathpoint6.distanceTo(targetPoint) < maxDistance) {
|
|
pathOptions[i++] = pathpoint6;
|
|
}
|
|
}
|
|
|
|
if (flag1 && flag5) {
|
|
NPCPathPoint pathpoint6 = this.getSafePoint(entity, currentPoint.xCoord, currentPoint.yCoord - 1, currentPoint.zCoord + 1, p_75860_3_, b0);
|
|
|
|
if (pathpoint6 != null && !pathpoint6.isFirst && pathpoint6.distanceTo(targetPoint) < maxDistance) {
|
|
pathOptions[i++] = pathpoint6;
|
|
}
|
|
}
|
|
|
|
if (flag2 && flag5) {
|
|
NPCPathPoint pathpoint6 = this.getSafePoint(entity, currentPoint.xCoord + 1, currentPoint.yCoord - 1, currentPoint.zCoord, p_75860_3_, b0);
|
|
|
|
if (pathpoint6 != null && !pathpoint6.isFirst && pathpoint6.distanceTo(targetPoint) < maxDistance) {
|
|
pathOptions[i++] = pathpoint6;
|
|
}
|
|
}
|
|
|
|
if (flag3 && flag5) {
|
|
NPCPathPoint pathpoint6 = this.getSafePoint(entity, currentPoint.xCoord - 1, currentPoint.yCoord - 1, currentPoint.zCoord, p_75860_3_, b0);
|
|
|
|
if (pathpoint6 != null && !pathpoint6.isFirst && pathpoint6.distanceTo(targetPoint) < maxDistance) {
|
|
pathOptions[i++] = pathpoint6;
|
|
}
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
private NPCPathPoint getSafePoint(Entity entity, int x, int y, int z, NPCPathPoint p_75858_5_, int p_75858_6_) {
|
|
NPCPathPoint pathpoint1 = null;
|
|
PathNodeType pathNodeType1 = this.getPathNodeType(entity, x, y, z);
|
|
int i1 = this.nodeTypeToOffset(pathNodeType1);
|
|
|
|
if (i1 == 2) {
|
|
pathpoint1 = this.openPoint(x, y, z);
|
|
pathpoint1.costMalus = i1;
|
|
pathpoint1.nodeType = pathNodeType1;
|
|
return pathpoint1;
|
|
} else {
|
|
if (i1 == 1) {
|
|
pathpoint1 = this.openPoint(x, y, z);
|
|
pathpoint1.costMalus = i1;
|
|
pathpoint1.nodeType = pathNodeType1;
|
|
}
|
|
|
|
PathNodeType pathNodeType2 = this.getPathNodeType(entity, x, y + p_75858_6_, z);
|
|
int vertOffset2 = this.nodeTypeToOffset(pathNodeType2);
|
|
if (pathpoint1 == null && p_75858_6_ > 0 && i1 != -3 && i1 != -4 && vertOffset2 == 1) {
|
|
pathpoint1 = this.openPoint(x, y + p_75858_6_, z);
|
|
pathpoint1.costMalus = vertOffset2;
|
|
pathpoint1.nodeType = pathNodeType2;
|
|
y += p_75858_6_;
|
|
}
|
|
|
|
if (pathpoint1 != null) {
|
|
int j1 = 0;
|
|
int k1 = 0;
|
|
|
|
while (y > 0) {
|
|
PathNodeType pathNodeType3 = this.getPathNodeType(entity, x, y - 1, z);
|
|
k1 = this.nodeTypeToOffset(pathNodeType3);
|
|
|
|
if (this.isPathingInWater && k1 == -1) {
|
|
return null;
|
|
}
|
|
|
|
if (k1 != 1) {
|
|
break;
|
|
}
|
|
|
|
if (j1++ >= entity.getMaxSafePointTries()) {
|
|
return null;
|
|
}
|
|
|
|
--y;
|
|
|
|
if (y > 0) {
|
|
pathpoint1 = this.openPoint(x, y, z);
|
|
pathpoint1.costMalus = k1;
|
|
pathpoint1.nodeType = pathNodeType3;
|
|
}
|
|
}
|
|
|
|
if (k1 == -2) {
|
|
return null;
|
|
}
|
|
}
|
|
return pathpoint1;
|
|
}
|
|
}
|
|
|
|
private PathNodeType getPathNodeType(Entity entity, int x, int y, int z) {
|
|
return this.getPathNodeType((EntityLiving) entity, new BlockPos(x, y, z));
|
|
}
|
|
|
|
public int nodeTypeToOffset(PathNodeType nodeType) {
|
|
switch (nodeType) {
|
|
case TRAPDOOR:
|
|
return -4;
|
|
case FENCE:
|
|
return -3;
|
|
case LAVA:
|
|
case DAMAGE_FIRE:
|
|
case DAMAGE_CACTUS:
|
|
case DAMAGE_OTHER:
|
|
return -2;
|
|
case WATER:
|
|
case DANGER_FIRE:
|
|
case DANGER_CACTUS:
|
|
case DANGER_OTHER:
|
|
return -1;
|
|
case BLOCKED:
|
|
case DOOR_WOOD_CLOSED:
|
|
case DOOR_IRON_CLOSED:
|
|
return 0;
|
|
case WALKABLE:
|
|
case DOOR_OPEN:
|
|
return 1;
|
|
case OPEN:
|
|
case RAIL:
|
|
return 2;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
protected NPCPathPoint openPoint(int x, int y, int z) {
|
|
int i = NPCPathPoint.makeHash(x, y, z);
|
|
NPCPathPoint pathpoint = this.pointMap.lookup(i);
|
|
|
|
if (pathpoint == null) {
|
|
pathpoint = new NPCPathPoint(x, y, z);
|
|
this.pointMap.addKey(i, pathpoint);
|
|
}
|
|
|
|
return pathpoint;
|
|
}
|
|
|
|
/**
|
|
* Returns a new FlyPathEntity for a given start and end point
|
|
*/
|
|
private NPCPath createEntityPath(NPCPathPoint pathFrom, NPCPathPoint pathTo) {
|
|
int i = 1;
|
|
NPCPathPoint pathpoint2;
|
|
|
|
for (pathpoint2 = pathTo; pathpoint2.previous != null; pathpoint2 = pathpoint2.previous) {
|
|
++i;
|
|
}
|
|
|
|
NPCPathPoint[] apathpoint = new NPCPathPoint[i];
|
|
pathpoint2 = pathTo;
|
|
--i;
|
|
|
|
for (apathpoint[i] = pathTo; pathpoint2.previous != null; apathpoint[i] = pathpoint2) {
|
|
pathpoint2 = pathpoint2.previous;
|
|
--i;
|
|
}
|
|
|
|
return new NPCPath(apathpoint);
|
|
}
|
|
|
|
|
|
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 (getPathPriority(pathnodetype2) < 0.0F) {
|
|
return pathnodetype2;
|
|
}
|
|
|
|
if (getPathPriority(pathnodetype2) >= getPathPriority(pathnodetype1)) {
|
|
pathnodetype1 = pathnodetype2;
|
|
}
|
|
}
|
|
|
|
if (pathnodetype == PathNodeType.OPEN && 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) {
|
|
PathNodeType pathnodetype1 = this.getPathNodeTypeRaw(blockaccessIn, x, y - 1, z);
|
|
|
|
if (pathnodetype1 != PathNodeType.DAMAGE_FIRE && pathnodetype1 != PathNodeType.LAVA) {
|
|
if (pathnodetype1 == PathNodeType.DAMAGE_CACTUS) {
|
|
pathnodetype = PathNodeType.DAMAGE_CACTUS;
|
|
} else if (pathnodetype1 == PathNodeType.DAMAGE_OTHER) pathnodetype = PathNodeType.DAMAGE_OTHER;
|
|
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;
|
|
}
|
|
|
|
public PathNodeType getPathNodeType(IBlockAccess blockAccess, 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(blockAccess, 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 && !(blockAccess.getBlock(p_193577_12_.getX(), p_193577_12_.getY(), p_193577_12_.getZ()) instanceof BlockRailBase) && !(blockAccess.getBlock(p_193577_12_.down().getX(), p_193577_12_.down().getY(), p_193577_12_.down().getZ()) 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 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_) {
|
|
int entitySizeX = MathHelper.floor_double(this.theEntity.width + 1.0F);
|
|
int entitySizeY = MathHelper.floor_double(this.theEntity.height + 1.0F);
|
|
int entitySizeZ = MathHelper.floor_double(this.theEntity.width + 1.0F);
|
|
return this.getPathNodeType(this.worldMap, p_192558_2_, p_192558_3_, p_192558_4_, p_192558_1_, entitySizeX, entitySizeY, entitySizeZ, ((EntityCustomNpc) this.theEntity).ais.doorInteract == 0, ((EntityCustomNpc) this.theEntity).ais.doorInteract == 1);
|
|
}
|
|
|
|
public PathNodeType checkNeighborBlocks(IBlockAccess worldmap, int x, int y, int z, PathNodeType type) {
|
|
BlockPos.PooledMutableBlockPos blockpos$pooledmutableblockpos = BlockPos.PooledMutableBlockPos.retain();
|
|
|
|
if (type == PathNodeType.WALKABLE) {
|
|
for (int i = -1; i <= 1; ++i) {
|
|
for (int j = -1; j <= 1; ++j) {
|
|
if (i != 0 || j != 0) {
|
|
blockpos$pooledmutableblockpos.setPos(i + x, y, j + z);
|
|
Block block = worldmap.getBlock(blockpos$pooledmutableblockpos.getX(), blockpos$pooledmutableblockpos.getY(), blockpos$pooledmutableblockpos.getZ());
|
|
if (block == Blocks.cactus) {
|
|
type = PathNodeType.DANGER_CACTUS;
|
|
} else if (block == Blocks.fire && !immuneToFire) {
|
|
type = PathNodeType.DANGER_FIRE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
blockpos$pooledmutableblockpos.release();
|
|
return type;
|
|
}
|
|
|
|
protected PathNodeType getPathNodeTypeRaw(IBlockAccess worldmap, 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_);
|
|
Block block = worldmap.getBlock(blockpos.getX(), blockpos.getY(), blockpos.getZ());
|
|
Material material = block.getMaterial();
|
|
|
|
if (material == Material.air) {
|
|
return PathNodeType.OPEN;
|
|
} else if (block != Blocks.trapdoor && block != Blocks.waterlily) {
|
|
if (block == Blocks.fire) {
|
|
return immuneToFire ? PathNodeType.OPEN : PathNodeType.DAMAGE_FIRE;
|
|
} else if (block == Blocks.cactus) {
|
|
return PathNodeType.DAMAGE_CACTUS;
|
|
} else if (block instanceof BlockDoor && material == Material.wood && !((BlockDoor) block).getBlocksMovement(this.worldMap, p_189553_2_, p_189553_3_, p_189553_4_)) {
|
|
return PathNodeType.DOOR_WOOD_CLOSED;
|
|
} else if (block instanceof BlockDoor && material == Material.wood && !((BlockDoor) block).getBlocksMovement(this.worldMap, p_189553_2_, p_189553_3_, p_189553_4_)) {
|
|
return PathNodeType.DOOR_IRON_CLOSED;
|
|
} else if (block instanceof BlockDoor && ((BlockDoor) block).getBlocksMovement(this.worldMap, p_189553_2_, p_189553_3_, p_189553_4_)) {
|
|
return PathNodeType.DOOR_OPEN;
|
|
} else if (block instanceof BlockRailBase) {
|
|
return PathNodeType.RAIL;
|
|
} else if (!(block instanceof BlockFence) && !(block instanceof BlockWall) && (!(block instanceof BlockFenceGate))) {
|
|
if (material == Material.water) {
|
|
return ((EntityNPCInterface) this.theEntity).ais.canSwim ? PathNodeType.OPEN : PathNodeType.WATER;
|
|
} else if (material == Material.lava) {
|
|
return immuneToFire ? PathNodeType.OPEN : PathNodeType.LAVA;
|
|
} else {
|
|
return block.getBlocksMovement(worldmap, blockpos.getX(), blockpos.getY(), blockpos.getZ()) ? PathNodeType.OPEN : PathNodeType.BLOCKED;
|
|
}
|
|
} else {
|
|
return PathNodeType.FENCE;
|
|
}
|
|
} else {
|
|
return PathNodeType.TRAPDOOR;
|
|
}
|
|
}
|
|
|
|
public float getPathPriority(PathNodeType nodeType) {
|
|
Float f = this.mapPathPriority.get(nodeType);
|
|
return f == null ? nodeType.getPriority() : f.floatValue();
|
|
}
|
|
}
|