From 2147bd00d0b227a90e051c4a25ae615a9fb7cdfc Mon Sep 17 00:00:00 2001 From: luisc Date: Wed, 8 Dec 2021 04:00:28 -0600 Subject: [PATCH] Pathing classes for NPC flying added. NPCs can now follow tactical variants while flying, and their pathing is a LOT better. --- .../noppes/npcs/ai/pathfinder/FlyPath.java | 173 +++++++ .../npcs/ai/pathfinder/FlyPathEntity.java | 130 +++++ .../npcs/ai/pathfinder/FlyPathFinder.java | 448 ++++++++++++++++++ .../npcs/ai/pathfinder/FlyPathPoint.java | 96 ++++ .../npcs/ai/pathfinder/FlyingMoveHelper.java | 36 +- .../ai/pathfinder/PathNavigateFlying.java | 27 +- .../noppes/npcs/entity/EntityNPCFlying.java | 43 +- .../npcs/entity/EntityNPCInterface.java | 4 +- 8 files changed, 888 insertions(+), 69 deletions(-) create mode 100644 src/main/java/noppes/npcs/ai/pathfinder/FlyPath.java create mode 100644 src/main/java/noppes/npcs/ai/pathfinder/FlyPathEntity.java create mode 100644 src/main/java/noppes/npcs/ai/pathfinder/FlyPathFinder.java create mode 100644 src/main/java/noppes/npcs/ai/pathfinder/FlyPathPoint.java diff --git a/src/main/java/noppes/npcs/ai/pathfinder/FlyPath.java b/src/main/java/noppes/npcs/ai/pathfinder/FlyPath.java new file mode 100644 index 000000000..1f36db860 --- /dev/null +++ b/src/main/java/noppes/npcs/ai/pathfinder/FlyPath.java @@ -0,0 +1,173 @@ +package noppes.npcs.ai.pathfinder; + +public class FlyPath { + private FlyPathPoint[] pathPoints = new FlyPathPoint[1024]; + /** The number of points in this path */ + private int count; + private static final String __OBFID = "CL_00000573"; + + /** + * Adds a point to the path + */ + public FlyPathPoint addPoint(FlyPathPoint p_75849_1_) + { + if (p_75849_1_.index >= 0) + { + throw new IllegalStateException("OW KNOWS!"); + } + else + { + if (this.count == this.pathPoints.length) + { + FlyPathPoint[] apathpoint = new FlyPathPoint[this.count << 1]; + System.arraycopy(this.pathPoints, 0, apathpoint, 0, this.count); + this.pathPoints = apathpoint; + } + + this.pathPoints[this.count] = p_75849_1_; + p_75849_1_.index = this.count; + this.sortBack(this.count++); + return p_75849_1_; + } + } + + /** + * Clears the path + */ + public void clearPath() + { + this.count = 0; + } + + /** + * Returns and removes the first point in the path + */ + public FlyPathPoint dequeue() + { + FlyPathPoint pathpoint = this.pathPoints[0]; + this.pathPoints[0] = this.pathPoints[--this.count]; + this.pathPoints[this.count] = null; + + if (this.count > 0) + { + this.sortForward(0); + } + + pathpoint.index = -1; + return pathpoint; + } + + /** + * Changes the provided point's distance to target + */ + public void changeDistance(FlyPathPoint p_75850_1_, float p_75850_2_) + { + float f1 = p_75850_1_.distanceToTarget; + p_75850_1_.distanceToTarget = p_75850_2_; + + if (p_75850_2_ < f1) + { + this.sortBack(p_75850_1_.index); + } + else + { + this.sortForward(p_75850_1_.index); + } + } + + /** + * Sorts a point to the left + */ + private void sortBack(int p_75847_1_) + { + FlyPathPoint pathpoint = this.pathPoints[p_75847_1_]; + int j; + + for (float f = pathpoint.distanceToTarget; p_75847_1_ > 0; p_75847_1_ = j) + { + j = p_75847_1_ - 1 >> 1; + FlyPathPoint pathpoint1 = this.pathPoints[j]; + + if (f >= pathpoint1.distanceToTarget) + { + break; + } + + this.pathPoints[p_75847_1_] = pathpoint1; + pathpoint1.index = p_75847_1_; + } + + this.pathPoints[p_75847_1_] = pathpoint; + pathpoint.index = p_75847_1_; + } + + /** + * Sorts a point to the right + */ + private void sortForward(int p_75846_1_) + { + FlyPathPoint pathpoint = this.pathPoints[p_75846_1_]; + float f = pathpoint.distanceToTarget; + + while (true) + { + int j = 1 + (p_75846_1_ << 1); + int k = j + 1; + + if (j >= this.count) + { + break; + } + + FlyPathPoint pathpoint1 = this.pathPoints[j]; + float f1 = pathpoint1.distanceToTarget; + FlyPathPoint pathpoint2; + float f2; + + if (k >= this.count) + { + pathpoint2 = null; + f2 = Float.POSITIVE_INFINITY; + } + else + { + pathpoint2 = this.pathPoints[k]; + f2 = pathpoint2.distanceToTarget; + } + + if (f1 < f2) + { + if (f1 >= f) + { + break; + } + + this.pathPoints[p_75846_1_] = pathpoint1; + pathpoint1.index = p_75846_1_; + p_75846_1_ = j; + } + else + { + if (f2 >= f) + { + break; + } + + this.pathPoints[p_75846_1_] = pathpoint2; + pathpoint2.index = p_75846_1_; + p_75846_1_ = k; + } + } + + this.pathPoints[p_75846_1_] = pathpoint; + pathpoint.index = p_75846_1_; + } + + /** + * Returns true if this path contains no points + */ + public boolean isPathEmpty() + { + return this.count == 0; + } +} diff --git a/src/main/java/noppes/npcs/ai/pathfinder/FlyPathEntity.java b/src/main/java/noppes/npcs/ai/pathfinder/FlyPathEntity.java new file mode 100644 index 000000000..a6715e6c6 --- /dev/null +++ b/src/main/java/noppes/npcs/ai/pathfinder/FlyPathEntity.java @@ -0,0 +1,130 @@ +package noppes.npcs.ai.pathfinder; + +import net.minecraft.entity.Entity; +import net.minecraft.pathfinding.PathEntity; +import net.minecraft.pathfinding.PathPoint; +import net.minecraft.util.Vec3; + +public class FlyPathEntity extends PathEntity{ + public final PathPoint[] points; + /** PathEntity Array Index the Entity is currently targeting */ + public int currentPathIndex; + /** The total length of the path */ + public int pathLength; + private static final String __OBFID = "CL_00000575"; + + public FlyPathEntity(PathPoint[] p_i2136_1_) + { + super(p_i2136_1_); + this.points = p_i2136_1_; + this.pathLength = p_i2136_1_.length; + } + + /** + * Directs this path to the next point in its array + */ + public void incrementPathIndex() + { + ++this.currentPathIndex; + } + + /** + * Returns true if this path has reached the end + */ + public boolean isFinished() + { + return this.currentPathIndex >= this.pathLength; + } + + /** + * returns the last PathPoint of the Array + */ + public PathPoint getFinalPathPoint() + { + return this.pathLength > 0 ? this.points[this.pathLength - 1] : null; + } + + /** + * return the PathPoint located at the specified PathIndex, usually the current one + */ + public PathPoint getPathPointFromIndex(int p_75877_1_) + { + return this.points[p_75877_1_]; + } + + public int getCurrentPathLength() + { + return this.pathLength; + } + + public void setCurrentPathLength(int p_75871_1_) + { + this.pathLength = p_75871_1_; + } + + public int getCurrentPathIndex() + { + return this.currentPathIndex; + } + + public void setCurrentPathIndex(int p_75872_1_) + { + this.currentPathIndex = p_75872_1_; + } + + /** + * Gets the vector of the PathPoint associated with the given index. + */ + public Vec3 getVectorFromIndex(Entity p_75881_1_, int p_75881_2_) + { + double d0 = (double)this.points[p_75881_2_].xCoord + (double)((int)(p_75881_1_.width + 1.0F)) * 0.5D; + double d1 = (double)this.points[p_75881_2_].yCoord; + double d2 = (double)this.points[p_75881_2_].zCoord + (double)((int)(p_75881_1_.width + 1.0F)) * 0.5D; + return Vec3.createVectorHelper(d0, d1, d2); + } + + /** + * returns the current PathEntity target node as Vec3D + */ + public Vec3 getPosition(Entity p_75878_1_) + { + return this.getVectorFromIndex(p_75878_1_, this.currentPathIndex); + } + + /** + * Returns true if the EntityPath are the same. Non instance related equals. + */ + public boolean isSamePath(PathEntity pathEntity) + { + FlyPathEntity p_75876_1_ = (FlyPathEntity) pathEntity; + if (p_75876_1_ == null) + { + return false; + } + else if (p_75876_1_.points.length != this.points.length) + { + return false; + } + else + { + for (int i = 0; i < this.points.length; ++i) + { + if (this.points[i].xCoord != p_75876_1_.points[i].xCoord || this.points[i].yCoord != p_75876_1_.points[i].yCoord || this.points[i].zCoord != p_75876_1_.points[i].zCoord) + { + return false; + } + } + + return true; + } + } + + /** + * Returns true if the final PathPoint in the PathEntity is equal to Vec3D coords. + */ + public boolean isDestinationSame(Vec3 p_75880_1_) + { + PathPoint pathpoint = this.getFinalPathPoint(); + return pathpoint == null ? false : pathpoint.xCoord == (int)p_75880_1_.xCoord && pathpoint.zCoord == (int)p_75880_1_.zCoord; + } +} diff --git a/src/main/java/noppes/npcs/ai/pathfinder/FlyPathFinder.java b/src/main/java/noppes/npcs/ai/pathfinder/FlyPathFinder.java new file mode 100644 index 000000000..9673520d5 --- /dev/null +++ b/src/main/java/noppes/npcs/ai/pathfinder/FlyPathFinder.java @@ -0,0 +1,448 @@ +package noppes.npcs.ai.pathfinder; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.entity.Entity; +import net.minecraft.init.Blocks; +import net.minecraft.pathfinding.PathFinder; +import net.minecraft.util.IntHashMap; +import net.minecraft.util.MathHelper; +import net.minecraft.world.IBlockAccess; + +public class FlyPathFinder extends PathFinder +{ + /** Used to find obstacles */ + private IBlockAccess worldMap; + /** The path being generated */ + private FlyPath path = new FlyPath(); + /** The points in the path */ + private IntHashMap pointMap = new IntHashMap(); + /** Selection of path points to add to the path */ + private FlyPathPoint[] pathOptions = new FlyPathPoint[32]; + /** should the PathFinder go through wodden door blocks */ + private boolean isWoddenDoorAllowed; + /** should the PathFinder disregard BlockMovement type materials in its path */ + private boolean isMovementBlockAllowed; + private boolean isPathingInWater; + /** tells the FathFinder to not stop pathing underwater */ + private boolean canEntityDrown; + private static final String __OBFID = "CL_00000576"; + + public FlyPathFinder(IBlockAccess p_i2137_1_, boolean p_i2137_2_, boolean p_i2137_3_, boolean p_i2137_4_, boolean p_i2137_5_) + { + super(p_i2137_1_,p_i2137_2_,p_i2137_3_,p_i2137_4_,p_i2137_5_); + this.worldMap = p_i2137_1_; + this.isWoddenDoorAllowed = p_i2137_2_; + this.isMovementBlockAllowed = p_i2137_3_; + this.isPathingInWater = p_i2137_4_; + this.canEntityDrown = p_i2137_5_; + } + + /** + * Creates a path from one entity to another within a minimum distance + */ + public FlyPathEntity createEntityPathTo(Entity p_75856_1_, Entity p_75856_2_, float p_75856_3_) + { + return this.createEntityPathTo(p_75856_1_, p_75856_2_.posX, p_75856_2_.boundingBox.minY, p_75856_2_.posZ, p_75856_3_); + } + + /** + * Creates a path from an entity to a specified location within a minimum distance + */ + public FlyPathEntity createEntityPathTo(Entity p_75859_1_, int p_75859_2_, int p_75859_3_, int p_75859_4_, float p_75859_5_) + { + return this.createEntityPathTo(p_75859_1_, (double)((float)p_75859_2_ + 0.5F), (double)((float)p_75859_3_ + 0.5F), (double)((float)p_75859_4_ + 0.5F), p_75859_5_); + } + + /** + * Internal implementation of creating a path from an entity to a point + */ + private FlyPathEntity createEntityPathTo(Entity p_75857_1_, double p_75857_2_, double p_75857_4_, double p_75857_6_, float p_75857_8_) + { + this.path.clearPath(); + this.pointMap.clearMap(); + boolean flag = this.isPathingInWater; + int i = MathHelper.floor_double(p_75857_1_.boundingBox.minY + 0.5D); + + if (this.canEntityDrown && p_75857_1_.isInWater()) + { + i = (int)p_75857_1_.boundingBox.minY; + + for (Block block = this.worldMap.getBlock(MathHelper.floor_double(p_75857_1_.posX), i, MathHelper.floor_double(p_75857_1_.posZ)); block == Blocks.flowing_water || block == Blocks.water; block = this.worldMap.getBlock(MathHelper.floor_double(p_75857_1_.posX), i, MathHelper.floor_double(p_75857_1_.posZ))) + { + ++i; + } + + flag = this.isPathingInWater; + this.isPathingInWater = false; + } + else + { + i = MathHelper.floor_double(p_75857_1_.boundingBox.minY + 0.5D); + } + + FlyPathPoint pathpoint2 = this.openPoint(MathHelper.floor_double(p_75857_1_.boundingBox.minX), i, MathHelper.floor_double(p_75857_1_.boundingBox.minZ)); + FlyPathPoint pathpoint = this.openPoint(MathHelper.floor_double(p_75857_2_ - (double)(p_75857_1_.width / 2.0F)), MathHelper.floor_double(p_75857_4_), MathHelper.floor_double(p_75857_6_ - (double)(p_75857_1_.width / 2.0F))); + FlyPathPoint pathpoint1 = new FlyPathPoint(MathHelper.floor_float(p_75857_1_.width + 1.0F), MathHelper.floor_float(p_75857_1_.height + 1.0F), MathHelper.floor_float(p_75857_1_.width + 1.0F)); + FlyPathEntity pathentity = this.addToPath(p_75857_1_, pathpoint2, pathpoint, pathpoint1, p_75857_8_); + this.isPathingInWater = flag; + return pathentity; + } + + /** + * Adds a path from start to end and returns the whole path (args: unused, start, end, unused, maxDistance) + */ + private FlyPathEntity addToPath(Entity p_75861_1_, FlyPathPoint p_75861_2_, FlyPathPoint p_75861_3_, FlyPathPoint p_75861_4_, float p_75861_5_) + { + p_75861_2_.totalPathDistance = 0.0F; + p_75861_2_.distanceToNext = p_75861_2_.distanceToSquared(p_75861_3_); + p_75861_2_.distanceToTarget = p_75861_2_.distanceToNext; + this.path.clearPath(); + this.path.addPoint(p_75861_2_); + FlyPathPoint pathpoint3 = p_75861_2_; + + while (!this.path.isPathEmpty()) + { + FlyPathPoint pathpoint4 = this.path.dequeue(); + + if (pathpoint4.equals(p_75861_3_)) + { + return this.createEntityPath(p_75861_2_, p_75861_3_); + } + + if (pathpoint4.distanceToSquared(p_75861_3_) < pathpoint3.distanceToSquared(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) + { + FlyPathPoint pathpoint5 = this.pathOptions[j]; + float f1 = pathpoint4.totalPathDistance + pathpoint4.distanceToSquared(pathpoint5); + + if (!pathpoint5.isAssigned() || f1 < pathpoint5.totalPathDistance) + { + pathpoint5.previous = pathpoint4; + pathpoint5.totalPathDistance = f1; + pathpoint5.distanceToNext = pathpoint5.distanceToSquared(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); + } + } + + /** + * populates pathOptions with available points and returns the number of options found (args: unused1, currentPoint, + * unused2, targetPoint, maxDistance) + */ + private int findPathOptions(Entity p_75860_1_, FlyPathPoint p_75860_2_, FlyPathPoint p_75860_3_, FlyPathPoint p_75860_4_, float p_75860_5_) + { + int i = 0; + byte b0 = 0; + + if (this.getVerticalOffset(p_75860_1_, p_75860_2_.xCoord, p_75860_2_.yCoord + 1, p_75860_2_.zCoord, p_75860_3_) == 1) + { + b0 = 1; + } + + FlyPathPoint pathpoint3 = this.getSafePoint(p_75860_1_, p_75860_2_.xCoord, p_75860_2_.yCoord, p_75860_2_.zCoord + 1, p_75860_3_, b0); + FlyPathPoint pathpoint4 = this.getSafePoint(p_75860_1_, p_75860_2_.xCoord - 1, p_75860_2_.yCoord, p_75860_2_.zCoord, p_75860_3_, b0); + FlyPathPoint pathpoint5 = this.getSafePoint(p_75860_1_, p_75860_2_.xCoord + 1, p_75860_2_.yCoord, p_75860_2_.zCoord, p_75860_3_, b0); + FlyPathPoint pathpoint6 = this.getSafePoint(p_75860_1_, p_75860_2_.xCoord, p_75860_2_.yCoord, p_75860_2_.zCoord - 1, p_75860_3_, b0); + + FlyPathPoint pathpoint7 = this.getSafePoint(p_75860_1_, p_75860_2_.xCoord, p_75860_2_.yCoord + 1, p_75860_2_.zCoord + 1, p_75860_3_, b0); + FlyPathPoint pathpoint8 = this.getSafePoint(p_75860_1_, p_75860_2_.xCoord - 1, p_75860_2_.yCoord + 1, p_75860_2_.zCoord, p_75860_3_, b0); + FlyPathPoint pathpoint9 = this.getSafePoint(p_75860_1_, p_75860_2_.xCoord + 1, p_75860_2_.yCoord + 1, p_75860_2_.zCoord, p_75860_3_, b0); + FlyPathPoint pathpoint10 = this.getSafePoint(p_75860_1_, p_75860_2_.xCoord, p_75860_2_.yCoord + 1, p_75860_2_.zCoord - 1, p_75860_3_, b0); + + FlyPathPoint pathpoint11 = this.getSafePoint(p_75860_1_, p_75860_2_.xCoord, p_75860_2_.yCoord - 1, p_75860_2_.zCoord + 1, p_75860_3_, b0); + FlyPathPoint pathpoint12 = this.getSafePoint(p_75860_1_, p_75860_2_.xCoord - 1, p_75860_2_.yCoord - 1, p_75860_2_.zCoord, p_75860_3_, b0); + FlyPathPoint pathpoint13 = this.getSafePoint(p_75860_1_, p_75860_2_.xCoord + 1, p_75860_2_.yCoord - 1, p_75860_2_.zCoord, p_75860_3_, b0); + FlyPathPoint pathpoint14 = this.getSafePoint(p_75860_1_, p_75860_2_.xCoord, p_75860_2_.yCoord - 1, p_75860_2_.zCoord - 1, p_75860_3_, b0); + + if (pathpoint3 != null && !pathpoint3.isFirst && pathpoint3.distanceTo(p_75860_4_) < p_75860_5_) + { + this.pathOptions[i++] = pathpoint3; + } + + if (pathpoint4 != null && !pathpoint4.isFirst && pathpoint4.distanceTo(p_75860_4_) < p_75860_5_) + { + this.pathOptions[i++] = pathpoint4; + } + + if (pathpoint5 != null && !pathpoint5.isFirst && pathpoint5.distanceTo(p_75860_4_) < p_75860_5_) + { + this.pathOptions[i++] = pathpoint5; + } + + if (pathpoint6 != null && !pathpoint6.isFirst && pathpoint6.distanceTo(p_75860_4_) < p_75860_5_) + { + this.pathOptions[i++] = pathpoint6; + } + + if (pathpoint7 != null && !pathpoint7.isFirst && pathpoint7.distanceTo(p_75860_4_) < p_75860_5_) + { + this.pathOptions[i++] = pathpoint7; + } + + if (pathpoint8 != null && !pathpoint8.isFirst && pathpoint8.distanceTo(p_75860_4_) < p_75860_5_) + { + this.pathOptions[i++] = pathpoint8; + } + + if (pathpoint9 != null && !pathpoint9.isFirst && pathpoint9.distanceTo(p_75860_4_) < p_75860_5_) + { + this.pathOptions[i++] = pathpoint9; + } + + if (pathpoint10 != null && !pathpoint10.isFirst && pathpoint10.distanceTo(p_75860_4_) < p_75860_5_) + { + this.pathOptions[i++] = pathpoint10; + } + + if (pathpoint11 != null && !pathpoint11.isFirst && pathpoint11.distanceTo(p_75860_4_) < p_75860_5_) + { + this.pathOptions[i++] = pathpoint11; + } + + if (pathpoint12 != null && !pathpoint12.isFirst && pathpoint12.distanceTo(p_75860_4_) < p_75860_5_) + { + this.pathOptions[i++] = pathpoint12; + } + + if (pathpoint13 != null && !pathpoint13.isFirst && pathpoint13.distanceTo(p_75860_4_) < p_75860_5_) + { + this.pathOptions[i++] = pathpoint13; + } + + if (pathpoint14 != null && !pathpoint14.isFirst && pathpoint14.distanceTo(p_75860_4_) < p_75860_5_) + { + this.pathOptions[i++] = pathpoint14; + } + + return i; + } + + /** + * Returns a point that the entity can safely move to + */ + private FlyPathPoint getSafePoint(Entity entity, int blockX, int blockY, int blockZ, FlyPathPoint pathPoint, int verticalOffsetFlag) + { + FlyPathPoint pathpoint1 = null; + int verticalOffset = this.getVerticalOffset(entity, blockX, blockY, blockZ, pathPoint); + + if (verticalOffset == 2) + { + return this.openPoint(blockX, blockY, blockZ); + } + else + { + if (verticalOffset == 1) + { + pathpoint1 = this.openPoint(blockX, blockY, blockZ); + } + + if (pathpoint1 == null && verticalOffsetFlag > 0 && verticalOffset != -3 && verticalOffset != -4 && this.getVerticalOffset(entity, blockX, blockY + verticalOffsetFlag, blockZ, pathPoint) == 1) + { + pathpoint1 = this.openPoint(blockX, blockY + verticalOffsetFlag, blockZ); + blockY += verticalOffsetFlag; + } + + if (pathpoint1 != null) + { + int j1 = 0; + int k1 = 0; + + while (blockY > 0) + { + k1 = this.getVerticalOffset(entity, blockX, blockY - 1, blockZ, pathPoint); + + if (this.isPathingInWater && k1 == -1) + { + return null; + } + + if (k1 != 1) + { + break; + } + + if (j1++ >= entity.getMaxSafePointTries()) + { + return null; + } + + --blockY; + + if (blockY > 0) + { + pathpoint1 = this.openPoint(blockX, blockY, blockZ); + } + } + + if (k1 == -2) + { + return null; + } + } + + return pathpoint1; + } + } + + /** + * Returns a mapped point or creates and adds one + */ + private final FlyPathPoint openPoint(int p_75854_1_, int p_75854_2_, int p_75854_3_) + { + int l = FlyPathPoint.makeHash(p_75854_1_, p_75854_2_, p_75854_3_); + FlyPathPoint pathpoint = (FlyPathPoint)this.pointMap.lookup(l); + + if (pathpoint == null) + { + pathpoint = new FlyPathPoint(p_75854_1_, p_75854_2_, p_75854_3_); + this.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 p_75855_1_, int p_75855_2_, int p_75855_3_, int p_75855_4_, FlyPathPoint p_75855_5_) + { + return canEntityStandAt(p_75855_1_, p_75855_2_, p_75855_3_, p_75855_4_, p_75855_5_, this.isPathingInWater, this.isMovementBlockAllowed, this.isWoddenDoorAllowed); + } + + public static int canEntityStandAt(Entity entity, int blockX, int blockY, int blockZ, FlyPathPoint pathPoint, boolean isPathingInWater, boolean isMovementBlockAllowed, boolean isWoddenDoorAllowed) + { + boolean flag3 = false; + + for (int l = blockX; l < blockX + pathPoint.xCoord; ++l) + { + for (int i1 = blockY; i1 < blockY + pathPoint.yCoord; ++i1) + { + for (int j1 = blockZ; j1 < blockZ + pathPoint.zCoord; ++j1) + { + Block block = entity.worldObj.getBlock(l, i1, j1); + + if(block == Blocks.air) + { + return 2; + } + + if (block == Blocks.trapdoor) + { + flag3 = true; + } + else if (block != Blocks.flowing_water && block != Blocks.water) + { + if (!isWoddenDoorAllowed && block == Blocks.wooden_door) + { + return 0; + } + } + else + { + if (isPathingInWater) + { + return -1; + } + + flag3 = true; + } + + int k1 = block.getRenderType(); + + if (entity.worldObj.getBlock(l, i1, j1).getRenderType() == 9) + { + int j2 = MathHelper.floor_double(entity.posX); + int l1 = MathHelper.floor_double(entity.posY); + int i2 = MathHelper.floor_double(entity.posZ); + + if (entity.worldObj.getBlock(j2, l1, i2).getRenderType() != 9 && entity.worldObj.getBlock(j2, l1 - 1, i2).getRenderType() != 9) + { + return -3; + } + } + else if (!block.getBlocksMovement(entity.worldObj, l, i1, j1) && (!isMovementBlockAllowed || block != Blocks.wooden_door)) + { + if (k1 == 11 || block == Blocks.fence_gate || k1 == 32) + { + return -3; + } + + if (block == Blocks.trapdoor) + { + return -4; + } + + Material material = block.getMaterial(); + + if (material != Material.lava) + { + return 0; + } + + if (!entity.handleLavaMovement()) + { + return -2; + } + } + } + } + } + + return flag3 ? 2 : 1; + } + + /** + * Returns a new FlyPathEntity for a given start and end point + */ + private FlyPathEntity createEntityPath(FlyPathPoint p_75853_1_, FlyPathPoint p_75853_2_) + { + int i = 1; + FlyPathPoint pathpoint2; + + for (pathpoint2 = p_75853_2_; pathpoint2.previous != null; pathpoint2 = pathpoint2.previous) + { + ++i; + } + + FlyPathPoint[] apathpoint = new FlyPathPoint[i]; + pathpoint2 = p_75853_2_; + --i; + + for (apathpoint[i] = p_75853_2_; pathpoint2.previous != null; apathpoint[i] = pathpoint2) + { + pathpoint2 = pathpoint2.previous; + --i; + } + + return new FlyPathEntity(apathpoint); + } +} diff --git a/src/main/java/noppes/npcs/ai/pathfinder/FlyPathPoint.java b/src/main/java/noppes/npcs/ai/pathfinder/FlyPathPoint.java new file mode 100644 index 000000000..87af78ae7 --- /dev/null +++ b/src/main/java/noppes/npcs/ai/pathfinder/FlyPathPoint.java @@ -0,0 +1,96 @@ +package noppes.npcs.ai.pathfinder; + +import net.minecraft.pathfinding.PathPoint; +import net.minecraft.util.MathHelper; + +public class FlyPathPoint extends PathPoint +{ + /** The x coordinate of this point */ + public final int xCoord; + /** The y coordinate of this point */ + public final int yCoord; + /** The z coordinate of this point */ + public final int zCoord; + /** A hash of the coordinates used to identify this point */ + public final int hash; + /** The index of this point in its assigned path */ + public int index = -1; + /** The distance along the path to this point */ + public float totalPathDistance; + /** The linear distance to the next point */ + public float distanceToNext; + /** The distance to the target */ + public float distanceToTarget; + /** The point preceding this in its assigned path */ + public FlyPathPoint previous; + /** Indicates this is the origin */ + public boolean isFirst; + private static final String __OBFID = "CL_00000574"; + + public FlyPathPoint(int p_i2135_1_, int p_i2135_2_, int p_i2135_3_) + { + super(p_i2135_1_,p_i2135_2_,p_i2135_3_); + this.xCoord = p_i2135_1_; + this.yCoord = p_i2135_2_; + this.zCoord = p_i2135_3_; + this.hash = makeHash(p_i2135_1_, p_i2135_2_, p_i2135_3_); + } + + public static int makeHash(int p_75830_0_, int p_75830_1_, int p_75830_2_) + { + return p_75830_1_ & 255 | (p_75830_0_ & 32767) << 8 | (p_75830_2_ & 32767) << 24 | (p_75830_0_ < 0 ? Integer.MIN_VALUE : 0) | (p_75830_2_ < 0 ? 32768 : 0); + } + + /** + * Returns the linear distance to another path point + */ + public float distanceTo(net.minecraft.pathfinding.PathPoint p_75829_1_) + { + float f = (float)(p_75829_1_.xCoord - this.xCoord); + float f1 = (float)(p_75829_1_.yCoord - this.yCoord); + float f2 = (float)(p_75829_1_.zCoord - this.zCoord); + return MathHelper.sqrt_float(f * f + f1 * f1 + f2 * f2); + } + + /** + * Returns the squared distance to another path point + */ + public float distanceToSquared(net.minecraft.pathfinding.PathPoint p_75832_1_) + { + float f = (float)(p_75832_1_.xCoord - this.xCoord); + float f1 = (float)(p_75832_1_.yCoord - this.yCoord); + float f2 = (float)(p_75832_1_.zCoord - this.zCoord); + return f * f + f1 * f1 + f2 * f2; + } + + public boolean equals(Object p_equals_1_) + { + if (!(p_equals_1_ instanceof FlyPathPoint)) + { + return false; + } + else + { + FlyPathPoint pathpoint = (FlyPathPoint)p_equals_1_; + return this.hash == pathpoint.hash && this.xCoord == pathpoint.xCoord && this.yCoord == pathpoint.yCoord && this.zCoord == pathpoint.zCoord; + } + } + + public int hashCode() + { + return this.hash; + } + + /** + * Returns true if this point has already been assigned to a path + */ + public boolean isAssigned() + { + return this.index >= 0; + } + + public String toString() + { + return this.xCoord + ", " + this.yCoord + ", " + this.zCoord; + } +} \ No newline at end of file diff --git a/src/main/java/noppes/npcs/ai/pathfinder/FlyingMoveHelper.java b/src/main/java/noppes/npcs/ai/pathfinder/FlyingMoveHelper.java index 078598d75..e50e53eb3 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.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.EntityMoveHelper; @@ -28,25 +29,36 @@ public class FlyingMoveHelper extends EntityMoveHelper{ } 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 speed = this.entity.getEntityAttribute(SharedMonsterAttributes.movementSpeed).getAttributeValue(); + double speedMult = 0.6000000238418579D / 0.5D; + double d0 = this.posX - this.entity.posX; - double d1 = this.posZ - this.entity.posZ; - double d2 = this.posY - (double)i; - double d3 = d0 * d0 + d2 * d2 + d1 * d1; + double d1 = this.posY - this.entity.posY; + double d2 = this.posZ - this.entity.posZ; + double d4 = d0 * d0 + d1 * d1 + d2 * d2; - 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 (this.entity.hurtTime == 0 && d4 > 0.5D) { + if (this.posY != this.entity.posY) { + if (this.entity.motionY * Math.signum(this.entity.posY - this.posY) > 0.0D) { + this.entity.motionY = 0.0D; + } - if (d2 > 0.0D && d0 * d0 + d1 * d1 < 1.0D) { - this.entity.getJumpHelper().setJumping(); + double verticalSpeed = Math.abs(this.entity.posY - this.posY); + if(verticalSpeed > speed * speedMult) + verticalSpeed = speed * speedMult; + + this.entity.motionY -= Math.signum(this.entity.posY - this.posY) * verticalSpeed * this.entity.ai.flySpeed; } + + double d5 = MathHelper.sqrt_double(d4); + this.entity.motionX += (d0 / d5 * speed - this.entity.motionX) * speed * speedMult; + this.entity.motionZ += (d2 / d5 * speed - this.entity.motionZ) * speed * speedMult; } + + this.entity.rotationYaw = this.limitAngle(this.entity.rotationYaw,(float) ((Math.atan2(-d0, -d2) + Math.PI) * -(180F / Math.PI)),30.0F); } } diff --git a/src/main/java/noppes/npcs/ai/pathfinder/PathNavigateFlying.java b/src/main/java/noppes/npcs/ai/pathfinder/PathNavigateFlying.java index 3e0bf41ee..f1027e02a 100644 --- a/src/main/java/noppes/npcs/ai/pathfinder/PathNavigateFlying.java +++ b/src/main/java/noppes/npcs/ai/pathfinder/PathNavigateFlying.java @@ -1,16 +1,12 @@ 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; @@ -23,7 +19,7 @@ public class PathNavigateFlying extends PathNavigate { private EntityNPCInterface theEntity; private World worldObj; /** The PathEntity being followed. */ - private PathEntity currentPath; + private FlyPathEntity 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; @@ -120,7 +116,7 @@ public class PathNavigateFlying extends PathNavigate { /** * Returns the path to the given coordinates */ - public PathEntity getPathToXYZ(double p_75488_1_, double p_75488_3_, double p_75488_5_) + public FlyPathEntity 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); } @@ -130,14 +126,14 @@ public class PathNavigateFlying extends PathNavigate { */ 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_)); + FlyPathEntity 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_) + public FlyPathEntity 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); } @@ -147,16 +143,17 @@ public class PathNavigateFlying extends PathNavigate { */ 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; + FlyPathEntity pathentity = this.getPathToEntityLiving(p_75497_1_); + return pathentity != null && this.setPath(pathentity, p_75497_2_); } /** * 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_) + public boolean setPath(PathEntity pathEntity, double p_75484_2_) { + FlyPathEntity p_75484_1_ = (FlyPathEntity) pathEntity; if (p_75484_1_ == null) { this.currentPath = null; @@ -471,7 +468,7 @@ public class PathNavigateFlying extends PathNavigate { 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_) + public FlyPathEntity 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); @@ -485,12 +482,12 @@ public class PathNavigateFlying extends PathNavigate { 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_); + FlyPathEntity pathentity = (new FlyPathFinder(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_) + public FlyPathEntity 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); @@ -504,7 +501,7 @@ public class PathNavigateFlying extends PathNavigate { 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_); + FlyPathEntity pathentity = (new FlyPathFinder(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 85c53a223..a740a771f 100644 --- a/src/main/java/noppes/npcs/entity/EntityNPCFlying.java +++ b/src/main/java/noppes/npcs/entity/EntityNPCFlying.java @@ -36,46 +36,9 @@ public abstract class EntityNPCFlying extends EntityNPCInterface { return; } - double speed = this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).getAttributeValue(); - double speedMult = 0.6000000238418579D/0.5D; - - if(isEntityAlive()) { - if (!this.worldObj.isRemote) { - 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 != target.posY) { - if (this.motionY * Math.signum(this.posY - target.posY) > 0.0D) { - this.motionY = 0.0D; - } - - this.motionY -= Math.signum(this.posY - target.posY) * (speed * speedMult) * this.ai.flySpeed; - } - - 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; - } - } - - this.rotationYaw = (float) ((Math.atan2(-d0, -d2) + Math.PI) * -(180F / Math.PI)); - } else { - if (!this.onGround && this.motionY < 0.0D) - { - this.motionY *= 0.6D; - } - } - } - - if (this.motionX * this.motionX + this.motionZ * this.motionZ > 0.05000000074505806D && isEntityAlive()) { - this.rotationYaw = (float) Math.atan2(this.motionZ, this.motionX) * (180F / (float) Math.PI) - 90.0F; - } + if (!this.onGround && !this.getMoveHelper().isUpdating()) + { + this.motionY *= 0.0D; } super.onLivingUpdate(); diff --git a/src/main/java/noppes/npcs/entity/EntityNPCInterface.java b/src/main/java/noppes/npcs/entity/EntityNPCInterface.java index 2ac01b37e..c384260d8 100644 --- a/src/main/java/noppes/npcs/entity/EntityNPCInterface.java +++ b/src/main/java/noppes/npcs/entity/EntityNPCInterface.java @@ -412,7 +412,7 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti } public PathNavigate getNavigator() { - if(canFly() && !this.onGround) + if(canFly()) return this.flyNavigator; else { return super.getNavigator(); @@ -420,7 +420,7 @@ public abstract class EntityNPCInterface extends EntityCreature implements IEnti } public EntityMoveHelper getMoveHelper() { - if(canFly() && !this.onGround) + if(canFly()) return this.flyMoveHelper; else { return super.getMoveHelper();