From 43b324180113d89e8f74554837eec7be7f1b785f Mon Sep 17 00:00:00 2001 From: luisc Date: Tue, 7 Dec 2021 03:57:57 -0600 Subject: [PATCH] Implemented path navigator and move helper for flying NPCs (npc.getNavigator() and npc.getMoveHelper() used to return the default navigator and move helper, added override function). Improved Flying AI getting stuck when trying to get over a block towards the enemy. --- .../npcs/ai/pathfinder/FlyingMoveHelper.java | 98 ++-- .../ai/pathfinder/PathNavigateFlying.java | 502 +++++++++++++++++- .../noppes/npcs/entity/EntityNPCFlying.java | 23 +- .../npcs/entity/EntityNPCInterface.java | 47 +- 4 files changed, 602 insertions(+), 68 deletions(-) diff --git a/src/main/java/noppes/npcs/ai/pathfinder/FlyingMoveHelper.java b/src/main/java/noppes/npcs/ai/pathfinder/FlyingMoveHelper.java index 7031a9e00..078598d75 100644 --- a/src/main/java/noppes/npcs/ai/pathfinder/FlyingMoveHelper.java +++ b/src/main/java/noppes/npcs/ai/pathfinder/FlyingMoveHelper.java @@ -1,5 +1,6 @@ package noppes.npcs.ai.pathfinder; +import net.minecraft.entity.EntityLiving; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.EntityMoveHelper; import net.minecraft.util.AxisAlignedBB; @@ -8,60 +9,83 @@ import noppes.npcs.entity.EntityNPCInterface; // Fly Change -public class FlyingMoveHelper extends EntityMoveHelper { +public class FlyingMoveHelper extends EntityMoveHelper{ private EntityNPCInterface entity; - private int field_179928_h; - protected boolean update; - - public double posX; - public double posY; - public double posZ; + private double posX; + private double posY; + private double posZ; + private double speed; + private boolean update; + private static final String __OBFID = "CL_00001573"; public FlyingMoveHelper(EntityNPCInterface entity){ super(entity); this.entity = entity; + this.posX = entity.posX; + this.posY = entity.posY; + this.posZ = entity.posZ; } - public void onUpdateMoveHelper(){ - if (this.update){ + public void onUpdateMoveHelper() { + this.entity.setMoveForward(0.0F); + + if (this.update) { + this.update = false; + int i = MathHelper.floor_double(this.entity.boundingBox.minY + 0.5D); double d0 = this.posX - this.entity.posX; - double d1 = this.posY - this.entity.posY; - double d2 = this.posZ - this.entity.posZ; - double d3 = d0 * d0 + d1 * d1 + d2 * d2; - - if (this.field_179928_h-- <= 0){ - this.field_179928_h += this.entity.getRNG().nextInt(5) + 2; - d3 = (double) MathHelper.sqrt_double(d3); + double d1 = this.posZ - this.entity.posZ; + double d2 = this.posY - (double)i; + double d3 = d0 * d0 + d2 * d2 + d1 * d1; - if (d3 > 1 && this.func_179926_b(this.posX, this.posY, this.posZ, d3)){ - double speed = entity.getEntityAttribute(SharedMonsterAttributes.movementSpeed).getAttributeValue() / 2.5; - this.entity.motionX += d0 / d3 * speed; - this.entity.motionY += d1 / d3 * speed; - this.entity.motionZ += d2 / d3 * speed; - this.entity.renderYawOffset = this.entity.rotationYaw = -((float)Math.atan2(this.entity.motionX, this.entity.motionZ)) * 180.0F / (float)Math.PI; - } - else{ - this.update = false; + if (d3 >= 2.500000277905201E-7D) { + float f = (float)(Math.atan2(d1, d0) * 180.0D / Math.PI) - 90.0F; + this.entity.rotationYaw = this.limitAngle(this.entity.rotationYaw, f, 30.0F); + this.entity.setAIMoveSpeed((float)(this.speed * this.entity.getEntityAttribute(SharedMonsterAttributes.movementSpeed).getAttributeValue())); + + if (d2 > 0.0D && d0 * d0 + d1 * d1 < 1.0D) { + this.entity.getJumpHelper().setJumping(); } } } } - private boolean func_179926_b(double p_179926_1_, double p_179926_3_, double p_179926_5_, double p_179926_7_){ - double d4 = (p_179926_1_ - this.entity.posX) / p_179926_7_; - double d5 = (p_179926_3_ - this.entity.posY) / p_179926_7_; - double d6 = (p_179926_5_ - this.entity.posZ) / p_179926_7_; - AxisAlignedBB axisalignedbb = this.entity.getBoundingBox(); + private float limitAngle(float p_75639_1_, float p_75639_2_, float p_75639_3_) + { + float f3 = MathHelper.wrapAngleTo180_float(p_75639_2_ - p_75639_1_); - for (int i = 1; (double)i < p_179926_7_; ++i){ - axisalignedbb = axisalignedbb.offset(d4, d5, d6); - - if (!this.entity.worldObj.getCollidingBoundingBoxes(this.entity, axisalignedbb).isEmpty()){ - return false; - } + if (f3 > p_75639_3_) + { + f3 = p_75639_3_; } - return true; + if (f3 < -p_75639_3_) + { + f3 = -p_75639_3_; + } + + return p_75639_1_ + f3; + } + + /** + * Sets the speed and location to move to + */ + public void setMoveTo(double p_75642_1_, double p_75642_3_, double p_75642_5_, double p_75642_7_) + { + this.posX = p_75642_1_; + this.posY = p_75642_3_; + this.posZ = p_75642_5_; + this.speed = p_75642_7_; + this.update = true; + } + + public boolean isUpdating() + { + return this.update; + } + + public double getSpeed() + { + return this.speed; } } diff --git a/src/main/java/noppes/npcs/ai/pathfinder/PathNavigateFlying.java b/src/main/java/noppes/npcs/ai/pathfinder/PathNavigateFlying.java index c2187dbeb..3e0bf41ee 100644 --- a/src/main/java/noppes/npcs/ai/pathfinder/PathNavigateFlying.java +++ b/src/main/java/noppes/npcs/ai/pathfinder/PathNavigateFlying.java @@ -1,25 +1,511 @@ package noppes.npcs.ai.pathfinder; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +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.entity.monster.EntityZombie; +import net.minecraft.entity.passive.EntityChicken; +import net.minecraft.init.Blocks; +import net.minecraft.pathfinding.PathEntity; import net.minecraft.pathfinding.PathFinder; +import net.minecraft.pathfinding.PathNavigate; +import net.minecraft.pathfinding.PathPoint; +import net.minecraft.util.MathHelper; +import net.minecraft.util.Vec3; +import net.minecraft.world.ChunkCache; import net.minecraft.world.World; +import noppes.npcs.entity.EntityNPCInterface; -public class PathNavigateFlying extends PathNavigateSwimmer { +public class PathNavigateFlying extends PathNavigate { + private EntityNPCInterface theEntity; + private World worldObj; + /** The PathEntity being followed. */ + private PathEntity currentPath; + private double speed; + /** The number of blocks (extra) +/- in each axis that get pulled out as cache for the pathfinder's search space */ + private IAttributeInstance pathSearchRange; + private boolean noSunPathfind; + /** Time, in number of ticks, following the current path */ + private 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 Vec3 lastPosCheck = Vec3.createVectorHelper(0.0D, 0.0D, 0.0D); + /** Specifically, if a wooden door block is even considered to be passable by the pathfinder */ + private boolean canPassOpenWoodenDoors = true; + /** If door blocks are considered passable even when closed */ + private boolean canPassClosedWoodenDoors; + /** If water blocks are avoided (at least by the pathfinder) */ + private boolean avoidsWater; + /** + * If the entity can swim. Swimming AI enables this and the pathfinder will also cause the entity to swim straight + * upwards when underwater + */ + private boolean canSwim; + private static final String __OBFID = "CL_00001627"; - public PathNavigateFlying(EntityLiving p_i45873_1_, World worldIn) { - super(p_i45873_1_, worldIn); - } - - protected PathFinder getPathFinder() + public PathNavigateFlying(EntityLiving p_i45873_1_, World worldIn) { + super(p_i45873_1_, worldIn); + this.theEntity = (EntityNPCInterface)p_i45873_1_; + this.worldObj = worldIn; + this.pathSearchRange = p_i45873_1_.getEntityAttribute(SharedMonsterAttributes.followRange); + } + + public void setAvoidsWater(boolean p_75491_1_) { - return new NPCPathFinder(new FlyNodeProcessor()); + this.avoidsWater = p_75491_1_; + } + + public boolean getAvoidsWater() + { + return this.avoidsWater; + } + + public void setBreakDoors(boolean p_75498_1_) + { + this.canPassClosedWoodenDoors = p_75498_1_; + } + + /** + * Sets if the entity can enter open doors + */ + public void setEnterDoors(boolean p_75490_1_) + { + this.canPassOpenWoodenDoors = p_75490_1_; + } + + /** + * Returns true if the entity can break doors, false otherwise + */ + public boolean getCanBreakDoors() + { + return this.canPassClosedWoodenDoors; + } + + /** + * Sets if the path should avoid sunlight + */ + public void setAvoidSun(boolean p_75504_1_) + { + this.noSunPathfind = p_75504_1_; + } + + /** + * Sets the speed + */ + public void setSpeed(double p_75489_1_) + { + this.speed = p_75489_1_; + } + + /** + * Sets if the entity can swim + */ + public void setCanSwim(boolean p_75495_1_) + { + this.canSwim = p_75495_1_; + } + + /** + * Gets the maximum distance that the path finding will search in. + */ + public float getPathSearchRange() + { + return (float)this.pathSearchRange.getAttributeValue(); + } + + /** + * Returns the path to the given coordinates + */ + public PathEntity getPathToXYZ(double p_75488_1_, double p_75488_3_, double p_75488_5_) + { + return !this.canNavigate() ? null : this.getEntityPathToXYZ(this.theEntity, MathHelper.floor_double(p_75488_1_), (int)p_75488_3_, MathHelper.floor_double(p_75488_5_), this.getPathSearchRange(), this.canPassOpenWoodenDoors, this.canPassClosedWoodenDoors, this.avoidsWater, this.canSwim); + } + + /** + * Try to find and set a path to XYZ. Returns true if successful. + */ + public boolean tryMoveToXYZ(double p_75492_1_, double p_75492_3_, double p_75492_5_, double p_75492_7_) + { + PathEntity pathentity = this.getPathToXYZ((double)MathHelper.floor_double(p_75492_1_), (double)((int)p_75492_3_), (double)MathHelper.floor_double(p_75492_5_)); + return this.setPath(pathentity, p_75492_7_); + } + + /** + * Returns the path to the given EntityLiving + */ + public PathEntity getPathToEntityLiving(Entity p_75494_1_) + { + return !this.canNavigate() ? null : this.getPathEntityToEntity(this.theEntity, p_75494_1_, this.getPathSearchRange(), this.canPassOpenWoodenDoors, this.canPassClosedWoodenDoors, this.avoidsWater, this.canSwim); + } + + /** + * Try to find and set a path to EntityLiving. Returns true if successful. + */ + public boolean tryMoveToEntityLiving(Entity p_75497_1_, double p_75497_2_) + { + PathEntity pathentity = this.getPathToEntityLiving(p_75497_1_); + return pathentity != null ? this.setPath(pathentity, p_75497_2_) : false; + } + + /** + * sets the active path data if path is 100% unique compared to old path, checks to adjust path for sun avoiding + * ents and stores end coords + */ + public boolean setPath(PathEntity p_75484_1_, double p_75484_2_) + { + if (p_75484_1_ == null) + { + this.currentPath = null; + return false; + } + else + { + if (!p_75484_1_.isSamePath(this.currentPath)) + { + this.currentPath = p_75484_1_; + } + + if (this.noSunPathfind) + { + this.removeSunnyPath(); + } + + if (this.currentPath.getCurrentPathLength() == 0) + { + return false; + } + else + { + this.speed = p_75484_2_; + Vec3 vec3 = this.getEntityPosition(); + this.ticksAtLastPos = this.totalTicks; + this.lastPosCheck.xCoord = vec3.xCoord; + this.lastPosCheck.yCoord = vec3.yCoord; + this.lastPosCheck.zCoord = vec3.zCoord; + return true; + } + } + } + + /** + * gets the actively used PathEntity + */ + public PathEntity getPath() + { + return this.currentPath; + } + + public void onUpdateNavigation() + { + ++this.totalTicks; + + if (!this.noPath()) + { + if (this.canNavigate()) + { + this.pathFollow(); + } + + if (!this.noPath()) + { + Vec3 vec3 = this.currentPath.getPosition(this.theEntity); + + if (vec3 != null) + { + this.theEntity.getMoveHelper().setMoveTo(vec3.xCoord, vec3.yCoord, vec3.zCoord, this.speed); + } + } + } + } + + private void pathFollow() + { + Vec3 vec3 = this.getEntityPosition(); + int i = this.currentPath.getCurrentPathLength(); + + for (int j = this.currentPath.getCurrentPathIndex(); j < this.currentPath.getCurrentPathLength(); ++j) + { + if (this.currentPath.getPathPointFromIndex(j).yCoord != (int)vec3.yCoord) + { + i = j; + break; + } + } + + float f = this.theEntity.width * this.theEntity.width; + int k; + + for (k = this.currentPath.getCurrentPathIndex(); k < i; ++k) + { + if (vec3.squareDistanceTo(this.currentPath.getVectorFromIndex(this.theEntity, k)) < (double)f) + { + this.currentPath.setCurrentPathIndex(k + 1); + } + } + + k = MathHelper.ceiling_float_int(this.theEntity.width); + int l = (int)this.theEntity.height + 1; + int i1 = k; + + for (int j1 = i - 1; j1 >= this.currentPath.getCurrentPathIndex(); --j1) + { + if (this.isDirectPathBetweenPoints(vec3, this.currentPath.getVectorFromIndex(this.theEntity, j1), k, l, i1)) + { + this.currentPath.setCurrentPathIndex(j1); + break; + } + } + + if (this.totalTicks - this.ticksAtLastPos > 100) + { + if (vec3.squareDistanceTo(this.lastPosCheck) < 2.25D) + { + this.clearPathEntity(); + } + + this.ticksAtLastPos = this.totalTicks; + this.lastPosCheck.xCoord = vec3.xCoord; + this.lastPosCheck.yCoord = vec3.yCoord; + this.lastPosCheck.zCoord = vec3.zCoord; + } + } + + /** + * If null path or reached the end + */ + public boolean noPath() + { + return this.currentPath == null || this.currentPath.isFinished(); + } + + /** + * sets active PathEntity to null + */ + public void clearPathEntity() + { + this.currentPath = null; + } + + private Vec3 getEntityPosition() + { + return Vec3.createVectorHelper(this.theEntity.posX, (double)this.getPathableYPos(), this.theEntity.posZ); + } + + /** + * Gets the safe pathing Y position for the entity depending on if it can path swim or not + */ + private int getPathableYPos() + { + int i = (int)this.theEntity.boundingBox.minY; + Block block = this.worldObj.getBlock(MathHelper.floor_double(this.theEntity.posX), i, MathHelper.floor_double(this.theEntity.posZ)); + int j = 0; + + do + { + if (block != Blocks.air) + { + return i; + } + + ++i; + block = this.worldObj.getBlock(MathHelper.floor_double(this.theEntity.posX), i, MathHelper.floor_double(this.theEntity.posZ)); + ++j; + } + while (j <= 16); + + return (int)(this.theEntity.boundingBox.minY + 0.5D); } /** * If on ground or swimming and can swim */ - protected boolean canNavigate() + private boolean canNavigate() { return true; } + + /** + * Returns true when an entity could stand at a position, including solid blocks under the entire entity. Args: + * xOffset, yOffset, zOffset, entityXSize, entityYSize, entityZSize, originPosition, vecX, vecZ + */ + private boolean isSafeToStandAt(int p_75483_1_, int p_75483_2_, int p_75483_3_, int p_75483_4_, int p_75483_5_, int p_75483_6_, Vec3 p_75483_7_, double p_75483_8_, double p_75483_10_) + { + return true; + } + + /** + * Trims path data from the end to the first sun covered block + */ + private void removeSunnyPath() + { + if (!this.worldObj.canBlockSeeTheSky(MathHelper.floor_double(this.theEntity.posX), (int)(this.theEntity.boundingBox.minY + 0.5D), MathHelper.floor_double(this.theEntity.posZ))) + { + for (int i = 0; i < this.currentPath.getCurrentPathLength(); ++i) + { + PathPoint pathpoint = this.currentPath.getPathPointFromIndex(i); + + if (this.worldObj.canBlockSeeTheSky(pathpoint.xCoord, pathpoint.yCoord, pathpoint.zCoord)) + { + this.currentPath.setCurrentPathLength(i - 1); + return; + } + } + } + } + + /** + * Returns true when an entity of specified size could safely walk in a straight line between the two points. Args: + * pos1, pos2, entityXSize, entityYSize, entityZSize + */ + private boolean isDirectPathBetweenPoints(Vec3 p_75493_1_, Vec3 p_75493_2_, int p_75493_3_, int p_75493_4_, int p_75493_5_) + { + int l = MathHelper.floor_double(p_75493_1_.xCoord); + int i1 = MathHelper.floor_double(p_75493_1_.zCoord); + double d0 = p_75493_2_.xCoord - p_75493_1_.xCoord; + double d1 = p_75493_2_.zCoord - p_75493_1_.zCoord; + double d2 = d0 * d0 + d1 * d1; + + if (d2 < 1.0E-8D) + { + return false; + } + else + { + double d3 = 1.0D / Math.sqrt(d2); + d0 *= d3; + d1 *= d3; + p_75493_3_ += 2; + p_75493_5_ += 2; + + if (!this.isSafeToStandAt(l, (int)p_75493_1_.yCoord, i1, p_75493_3_, p_75493_4_, p_75493_5_, p_75493_1_, d0, d1)) + { + return false; + } + else + { + p_75493_3_ -= 2; + p_75493_5_ -= 2; + double d4 = 1.0D / Math.abs(d0); + double d5 = 1.0D / Math.abs(d1); + double d6 = (double)(l * 1) - p_75493_1_.xCoord; + double d7 = (double)(i1 * 1) - p_75493_1_.zCoord; + + if (d0 >= 0.0D) + { + ++d6; + } + + if (d1 >= 0.0D) + { + ++d7; + } + + d6 /= d0; + d7 /= d1; + int j1 = d0 < 0.0D ? -1 : 1; + int k1 = d1 < 0.0D ? -1 : 1; + int l1 = MathHelper.floor_double(p_75493_2_.xCoord); + int i2 = MathHelper.floor_double(p_75493_2_.zCoord); + int j2 = l1 - l; + int k2 = i2 - i1; + + do + { + if (j2 * j1 <= 0 && k2 * k1 <= 0) + { + return true; + } + + if (d6 < d7) + { + d6 += d4; + l += j1; + j2 = l1 - l; + } + else + { + d7 += d5; + i1 += k1; + k2 = i2 - i1; + } + } + while (this.isSafeToStandAt(l, (int)p_75493_1_.yCoord, i1, p_75493_3_, p_75493_4_, p_75493_5_, p_75493_1_, d0, d1)); + + return false; + } + } + } + + /** + * Returns true if an entity does not collide with any solid blocks at the position. Args: xOffset, yOffset, + * zOffset, entityXSize, entityYSize, entityZSize, originPosition, vecX, vecZ + */ + private boolean isPositionClear(int p_75496_1_, int p_75496_2_, int p_75496_3_, int p_75496_4_, int p_75496_5_, int p_75496_6_, Vec3 p_75496_7_, double p_75496_8_, double p_75496_10_) + { + for (int k1 = p_75496_1_; k1 < p_75496_1_ + p_75496_4_; ++k1) + { + for (int l1 = p_75496_2_; l1 < p_75496_2_ + p_75496_5_; ++l1) + { + for (int i2 = p_75496_3_; i2 < p_75496_3_ + p_75496_6_; ++i2) + { + double d2 = (double)k1 + 0.5D - p_75496_7_.xCoord; + double d3 = (double)i2 + 0.5D - p_75496_7_.zCoord; + + if (d2 * p_75496_8_ + d3 * p_75496_10_ >= 0.0D) + { + Block block = this.worldObj.getBlock(k1, l1, i2); + + if (!block.getBlocksMovement(this.worldObj, k1, l1, i2)) + { + return false; + } + } + } + } + } + + return true; + } + + public PathEntity getPathEntityToEntity(Entity p_72865_1_, Entity p_72865_2_, float p_72865_3_, boolean p_72865_4_, boolean p_72865_5_, boolean p_72865_6_, boolean p_72865_7_) + { + this.theEntity.worldObj.theProfiler.startSection("pathfind"); + int i = MathHelper.floor_double(p_72865_1_.posX); + int j = MathHelper.floor_double(p_72865_1_.posY + 1.0D); + int k = MathHelper.floor_double(p_72865_1_.posZ); + int l = (int)(p_72865_3_ + 16.0F); + int i1 = i - l; + int j1 = j - l; + int k1 = k - l; + int l1 = i + l; + int i2 = j + l; + int j2 = k + l; + ChunkCache chunkcache = new ChunkCache(this.theEntity.worldObj, i1, j1, k1, l1, i2, j2, 0); + PathEntity pathentity = (new PathFinder(chunkcache, p_72865_4_, p_72865_5_, p_72865_6_, p_72865_7_)).createEntityPathTo(p_72865_1_, p_72865_2_, p_72865_3_); + this.theEntity.worldObj.theProfiler.endSection(); + return pathentity; + } + + public PathEntity getEntityPathToXYZ(Entity p_72844_1_, int p_72844_2_, int p_72844_3_, int p_72844_4_, float p_72844_5_, boolean p_72844_6_, boolean p_72844_7_, boolean p_72844_8_, boolean p_72844_9_) + { + this.theEntity.worldObj.theProfiler.startSection("pathfind"); + int l = MathHelper.floor_double(p_72844_1_.posX); + int i1 = MathHelper.floor_double(p_72844_1_.posY); + int j1 = MathHelper.floor_double(p_72844_1_.posZ); + int k1 = (int)(p_72844_5_ + 8.0F); + int l1 = l - k1; + int i2 = i1 - k1; + int j2 = j1 - k1; + int k2 = l + k1; + int l2 = i1 + k1; + int i3 = j1 + k1; + ChunkCache chunkcache = new ChunkCache(this.theEntity.worldObj, l1, i2, j2, k2, l2, i3, 0); + PathEntity pathentity = (new PathFinder(chunkcache, p_72844_6_, p_72844_7_, p_72844_8_, p_72844_9_)).createEntityPathTo(p_72844_1_, p_72844_2_, p_72844_3_, p_72844_4_, p_72844_5_); + this.theEntity.worldObj.theProfiler.endSection(); + return pathentity; + } } diff --git a/src/main/java/noppes/npcs/entity/EntityNPCFlying.java b/src/main/java/noppes/npcs/entity/EntityNPCFlying.java index 610ac8055..85c53a223 100644 --- a/src/main/java/noppes/npcs/entity/EntityNPCFlying.java +++ b/src/main/java/noppes/npcs/entity/EntityNPCFlying.java @@ -31,7 +31,7 @@ public abstract class EntityNPCFlying extends EntityNPCInterface { public void onLivingUpdate() { - if(!canFly()){ + if(!canFly() || this.isJumping){ super.onLivingUpdate(); return; } @@ -41,23 +41,24 @@ public abstract class EntityNPCFlying extends EntityNPCInterface { if(isEntityAlive()) { if (!this.worldObj.isRemote) { - Entity entity = this.getAttackTarget(); - if (entity != null && entity.isEntityAlive()) { - double d0 = entity.posX - this.posX; - double d2 = entity.posZ - this.posZ; - double d3 = d0 * d0 + d2 * d2; + Entity target = this.getAttackTarget(); + if (target != null && target.isEntityAlive()) { + double d0 = target.posX - this.posX; + double d1 = target.posY - this.posY; + double d2 = target.posZ - this.posZ; + double d4 = d0 * d0 + d1 * d1 + d2 * d2; if(this.hurtTime == 0) { - if (this.posY != entity.posY) { - if (this.motionY * Math.signum(this.posY - entity.posY) > 0.0D) { + if (this.posY != target.posY) { + if (this.motionY * Math.signum(this.posY - target.posY) > 0.0D) { this.motionY = 0.0D; } - this.motionY -= Math.signum(this.posY - entity.posY) * (speed * speedMult) * this.ai.flySpeed; + this.motionY -= Math.signum(this.posY - target.posY) * (speed * speedMult) * this.ai.flySpeed; } - if (d3 > 9.0D) { - double d5 = MathHelper.sqrt_double(d3); + if (d4 > 0.5D) { + double d5 = MathHelper.sqrt_double(d4); this.motionX += (d0 / d5 * speed - this.motionX) * speed * speedMult; this.motionZ += (d2 / d5 * speed - this.motionZ) * speed * speedMult; } diff --git a/src/main/java/noppes/npcs/entity/EntityNPCInterface.java b/src/main/java/noppes/npcs/entity/EntityNPCInterface.java index 79c43f23a..2ac01b37e 100644 --- a/src/main/java/noppes/npcs/entity/EntityNPCInterface.java +++ b/src/main/java/noppes/npcs/entity/EntityNPCInterface.java @@ -20,7 +20,6 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.projectile.EntityArrow; import net.minecraft.entity.projectile.EntityThrowable; -import net.minecraft.init.Items; import net.minecraft.item.Item; import net.minecraft.item.ItemBow; import net.minecraft.item.ItemStack; @@ -60,8 +59,8 @@ import noppes.npcs.ai.EntityAIMoveIndoors; import noppes.npcs.ai.EntityAIPanic; import noppes.npcs.ai.EntityAIWander; import noppes.npcs.ai.EntityAIWatchClosest; +import noppes.npcs.ai.pathfinder.FlyingMoveHelper; import noppes.npcs.ai.pathfinder.PathNavigateFlying; -import noppes.npcs.ai.pathfinder.PathNavigateGround; import noppes.npcs.ai.selector.NPCAttackSelector; import noppes.npcs.ai.target.EntityAIClearTarget; import noppes.npcs.ai.target.EntityAIClosestTarget; @@ -96,7 +95,6 @@ import noppes.npcs.roles.RoleCompanion; import noppes.npcs.roles.RoleFollower; import noppes.npcs.roles.RoleInterface; import noppes.npcs.scripted.entity.ScriptNpc; -import noppes.npcs.scripted.entity.ScriptPlayer; import noppes.npcs.scripted.event.ScriptEventAttack; import noppes.npcs.scripted.event.ScriptEventDamaged; import noppes.npcs.scripted.event.ScriptEventKilled; @@ -156,12 +154,19 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti public boolean updateAI = false; // Fly Change - //public EntityMoveHelper moveHelper; - public PathNavigate navigator; + public FlyingMoveHelper flyMoveHelper = new FlyingMoveHelper(this); + public PathNavigate flyNavigator = new PathNavigateFlying(this, worldObj); public EntityNPCInterface(World world) { super(world); try{ + if (canFly()) { + this.getNavigator().setCanSwim(true); + this.tasks.addTask(0, new EntityAISwimming(this)); + } else { + this.tasks.addTask(0, new EntityAIWaterNav(this)); + } + dialogs = new HashMap(); if(!CustomNpcs.DefaultInteractLine.isEmpty()) advanced.interactLines.lines.put(0, new Line(CustomNpcs.DefaultInteractLine)); @@ -405,6 +410,29 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti return true; } + + public PathNavigate getNavigator() { + if(canFly() && !this.onGround) + return this.flyNavigator; + else { + return super.getNavigator(); + } + } + + public EntityMoveHelper getMoveHelper() { + if(canFly() && !this.onGround) + return this.flyMoveHelper; + else { + return super.getMoveHelper(); + } + } + + protected void updateAITasks() + { + super.updateAITasks(); + this.getNavigator().onUpdateNavigation(); + this.getMoveHelper().onUpdateMoveHelper(); + } public void addInteract(EntityLivingBase entity){ if( !ai.stopAndInteract || isAttacking() || !entity.isEntityAlive()) @@ -600,15 +628,10 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti this.targetTasks.addTask(3, new EntityAIOwnerHurtByTarget(this)); this.targetTasks.addTask(4, new EntityAIOwnerHurtTarget(this)); - if(canFly()){ - //this.moveHelper = new FlyingMoveHelper(this); - this.navigator = new PathNavigateFlying(this, worldObj); + if (canFly()) { this.getNavigator().setCanSwim(true); this.tasks.addTask(0, new EntityAISwimming(this)); - } - else{ - //this.moveHelper = new EntityMoveHelper(this); - this.navigator = new PathNavigateGround(this, worldObj); + } else { this.tasks.addTask(0, new EntityAIWaterNav(this)); }