2025-03-11 00:23:54 +01:00
|
|
|
package game.pathfinding;
|
|
|
|
|
|
|
|
import game.block.Block;
|
|
|
|
import game.block.BlockDoor;
|
|
|
|
import game.block.BlockFence;
|
|
|
|
import game.block.BlockFenceGate;
|
|
|
|
import game.block.BlockRailBase;
|
|
|
|
import game.block.BlockWall;
|
|
|
|
import game.entity.Entity;
|
|
|
|
import game.init.Blocks;
|
|
|
|
import game.material.Material;
|
2025-03-11 10:26:48 +01:00
|
|
|
import game.util.ExtMath;
|
2025-03-11 00:23:54 +01:00
|
|
|
import game.world.BlockPos;
|
|
|
|
import game.world.IBlockAccess;
|
|
|
|
|
|
|
|
public class WalkNodeProcessor extends NodeProcessor
|
|
|
|
{
|
|
|
|
private boolean canEnterDoors;
|
|
|
|
private boolean canBreakDoors;
|
|
|
|
private boolean avoidsWater;
|
|
|
|
private boolean canSwim;
|
|
|
|
private boolean shouldAvoidWater;
|
|
|
|
|
|
|
|
public void initProcessor(PathCache iblockaccessIn, Entity entityIn)
|
|
|
|
{
|
|
|
|
super.initProcessor(iblockaccessIn, entityIn);
|
|
|
|
this.shouldAvoidWater = this.avoidsWater;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method is called when all nodes have been processed and PathEntity is created.
|
|
|
|
* {@link game.pathfinding.WalkNodeProcessor WalkNodeProcessor} uses this to change its field {@link
|
|
|
|
* game.pathfinding.WalkNodeProcessor#avoidsWater avoidsWater}
|
|
|
|
*/
|
|
|
|
public void postProcess()
|
|
|
|
{
|
|
|
|
super.postProcess();
|
|
|
|
this.avoidsWater = this.shouldAvoidWater;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns given entity's position as PathPoint
|
|
|
|
*/
|
|
|
|
public PathPoint getPathPointTo(Entity entityIn)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (this.canSwim && entityIn.isInLiquid())
|
|
|
|
{
|
|
|
|
i = (int)entityIn.getEntityBoundingBox().minY;
|
|
|
|
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos(ExtMath.floord(entityIn.posX), i, ExtMath.floord(entityIn.posZ));
|
|
|
|
|
|
|
|
for (Block block = this.blockaccess.getState(blockpos$mutableblockpos).getBlock(); block.getMaterial().isColdLiquid(); block = this.blockaccess.getState(blockpos$mutableblockpos).getBlock())
|
|
|
|
{
|
|
|
|
++i;
|
|
|
|
blockpos$mutableblockpos.set(ExtMath.floord(entityIn.posX), i, ExtMath.floord(entityIn.posZ));
|
|
|
|
}
|
|
|
|
|
|
|
|
this.avoidsWater = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
i = ExtMath.floord(entityIn.getEntityBoundingBox().minY + 0.5D);
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.openPoint(ExtMath.floord(entityIn.getEntityBoundingBox().minX), i, ExtMath.floord(entityIn.getEntityBoundingBox().minZ));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns PathPoint for given coordinates
|
|
|
|
*/
|
|
|
|
public PathPoint getPathPointToCoords(Entity entityIn, double x, double y, double target)
|
|
|
|
{
|
|
|
|
return this.openPoint(ExtMath.floord(x - (double)(entityIn.width / 2.0F)), ExtMath.floord(y), ExtMath.floord(target - (double)(entityIn.width / 2.0F)));
|
|
|
|
}
|
|
|
|
|
|
|
|
public int findPathOptions(PathPoint[] pathOptions, Entity entityIn, PathPoint currentPoint, PathPoint targetPoint, float maxDistance)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
int j = 0;
|
|
|
|
|
|
|
|
if (this.getVerticalOffset(entityIn, currentPoint.xCoord, currentPoint.yCoord + 1, currentPoint.zCoord) == 1)
|
|
|
|
{
|
|
|
|
j = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PathPoint pathpoint = this.getSafePoint(entityIn, currentPoint.xCoord, currentPoint.yCoord, currentPoint.zCoord + 1, j);
|
|
|
|
PathPoint pathpoint1 = this.getSafePoint(entityIn, currentPoint.xCoord - 1, currentPoint.yCoord, currentPoint.zCoord, j);
|
|
|
|
PathPoint pathpoint2 = this.getSafePoint(entityIn, currentPoint.xCoord + 1, currentPoint.yCoord, currentPoint.zCoord, j);
|
|
|
|
PathPoint pathpoint3 = this.getSafePoint(entityIn, currentPoint.xCoord, currentPoint.yCoord, currentPoint.zCoord - 1, j);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a point that the entity can safely move to
|
|
|
|
*/
|
|
|
|
private PathPoint getSafePoint(Entity entityIn, int x, int y, int z, int p_176171_5_)
|
|
|
|
{
|
|
|
|
PathPoint pathpoint = null;
|
|
|
|
int i = this.getVerticalOffset(entityIn, x, y, z);
|
|
|
|
|
|
|
|
if (i == 2)
|
|
|
|
{
|
|
|
|
return this.openPoint(x, y, z);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (i == 1)
|
|
|
|
{
|
|
|
|
pathpoint = this.openPoint(x, y, z);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pathpoint == null && p_176171_5_ > 0 && i != -3 && i != -4 && this.getVerticalOffset(entityIn, x, y + p_176171_5_, z) == 1)
|
|
|
|
{
|
|
|
|
pathpoint = this.openPoint(x, y + p_176171_5_, z);
|
|
|
|
y += p_176171_5_;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pathpoint != null)
|
|
|
|
{
|
|
|
|
int j = 0;
|
|
|
|
int k;
|
|
|
|
|
|
|
|
for (k = 0; y > 0; pathpoint = this.openPoint(x, y, z))
|
|
|
|
{
|
|
|
|
k = this.getVerticalOffset(entityIn, x, y - 1, z);
|
|
|
|
|
|
|
|
if (this.avoidsWater && k == -1)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (k != 1)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j++ >= entityIn.getMaxFallHeight())
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
--y;
|
|
|
|
|
|
|
|
if (y <= 0)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (k == -2)
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 avoids water),
|
|
|
|
* -2 for lava, -3 for fence and wall, -4 for closed trapdoor, 2 if otherwise clear except for open trapdoor or
|
|
|
|
* water(if not avoiding)
|
|
|
|
*/
|
|
|
|
private int getVerticalOffset(Entity entityIn, int x, int y, int z)
|
|
|
|
{
|
|
|
|
return getColliding(this.blockaccess, entityIn, x, y, z, this.entitySizeX, this.entitySizeY, this.entitySizeZ, this.avoidsWater, this.canBreakDoors, this.canEnterDoors);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static int getColliding(IBlockAccess world, Entity entity, int x, int y, int z, int sizeX, int sizeY, int sizeZ, boolean avoidWater, boolean breakDoors, boolean enterDoors)
|
|
|
|
{
|
|
|
|
boolean flag = false;
|
|
|
|
BlockPos blockpos = new BlockPos(entity);
|
|
|
|
BlockPos.MutableBlockPos mpos = new BlockPos.MutableBlockPos();
|
|
|
|
|
|
|
|
for (int i = x; i < x + sizeX; ++i)
|
|
|
|
{
|
|
|
|
for (int j = y; j < y + sizeY; ++j)
|
|
|
|
{
|
|
|
|
for (int k = z; k < z + sizeZ; ++k)
|
|
|
|
{
|
|
|
|
mpos.set(i, j, k);
|
|
|
|
Block block = world.getState(mpos).getBlock();
|
|
|
|
|
|
|
|
if (block.getMaterial() != Material.air)
|
|
|
|
{
|
|
|
|
if (block != Blocks.trapdoor && block != Blocks.iron_trapdoor)
|
|
|
|
{
|
|
|
|
if (!block.getMaterial().isColdLiquid())
|
|
|
|
{
|
|
|
|
if (!enterDoors && block instanceof BlockDoor && block.getMaterial() == Material.wood)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (avoidWater)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
flag = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
flag = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entity.worldObj.getState(mpos).getBlock() instanceof BlockRailBase)
|
|
|
|
{
|
|
|
|
if (!(entity.worldObj.getState(blockpos).getBlock() instanceof BlockRailBase) && !(entity.worldObj.getState(blockpos.down()).getBlock() instanceof BlockRailBase))
|
|
|
|
{
|
|
|
|
return -3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!block.isPassable(world, mpos) && (!breakDoors || !(block instanceof BlockDoor) || block.getMaterial() != Material.wood))
|
|
|
|
{
|
|
|
|
if (block instanceof BlockFence || block instanceof BlockFenceGate || block instanceof BlockWall)
|
|
|
|
{
|
|
|
|
return -3;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (block == Blocks.trapdoor || block == Blocks.iron_trapdoor)
|
|
|
|
{
|
|
|
|
return -4;
|
|
|
|
}
|
|
|
|
|
|
|
|
Material material = block.getMaterial();
|
|
|
|
|
|
|
|
if (!material.isHotLiquid())
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!entity.isInMolten())
|
|
|
|
{
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return flag ? 2 : 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setEnterDoors(boolean canEnterDoorsIn)
|
|
|
|
{
|
|
|
|
this.canEnterDoors = canEnterDoorsIn;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setBreakDoors(boolean canBreakDoorsIn)
|
|
|
|
{
|
|
|
|
this.canBreakDoors = canBreakDoorsIn;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setAvoidsWater(boolean avoidsWaterIn)
|
|
|
|
{
|
|
|
|
this.avoidsWater = avoidsWaterIn;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setCanSwim(boolean canSwimIn)
|
|
|
|
{
|
|
|
|
this.canSwim = canSwimIn;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean getEnterDoors()
|
|
|
|
{
|
|
|
|
return this.canEnterDoors;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean getCanSwim()
|
|
|
|
{
|
|
|
|
return this.canSwim;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean getAvoidsWater()
|
|
|
|
{
|
|
|
|
return this.avoidsWater;
|
|
|
|
}
|
|
|
|
}
|