package net.minecraft.pathfinding; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.monster.EntityZombie; import net.minecraft.entity.passive.EntityChicken; import net.minecraft.init.Blocks; import net.minecraft.util.BlockPos; import net.minecraft.util.MathHelper; import net.minecraft.util.Vec3; import net.minecraft.world.World; import net.minecraft.world.pathfinder.WalkNodeProcessor; /**+ * This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code. * * Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!" * Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team * * EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ public class PathNavigateGround extends PathNavigate { protected WalkNodeProcessor nodeProcessor; private boolean shouldAvoidSun; public PathNavigateGround(EntityLiving entitylivingIn, World worldIn) { super(entitylivingIn, worldIn); } protected PathFinder getPathFinder() { this.nodeProcessor = new WalkNodeProcessor(); this.nodeProcessor.setEnterDoors(true); return new PathFinder(this.nodeProcessor); } /**+ * If on ground or swimming and can swim */ protected boolean canNavigate() { return this.theEntity.onGround || this.getCanSwim() && this.isInLiquid() || this.theEntity.isRiding() && this.theEntity instanceof EntityZombie && this.theEntity.ridingEntity instanceof EntityChicken; } protected Vec3 getEntityPosition() { return new Vec3(this.theEntity.posX, (double) this.getPathablePosY(), this.theEntity.posZ); } /**+ * Gets the safe pathing Y position for the entity depending on * if it can path swim or not */ private int getPathablePosY() { if (this.theEntity.isInWater() && this.getCanSwim()) { int i = (int) this.theEntity.getEntityBoundingBox().minY; Block block = this.worldObj.getBlockState(new BlockPos(MathHelper.floor_double(this.theEntity.posX), i, MathHelper.floor_double(this.theEntity.posZ))).getBlock(); int j = 0; while (block == Blocks.flowing_water || block == Blocks.water) { ++i; block = this.worldObj.getBlockState(new BlockPos(MathHelper.floor_double(this.theEntity.posX), i, MathHelper.floor_double(this.theEntity.posZ))).getBlock(); ++j; if (j > 16) { return (int) this.theEntity.getEntityBoundingBox().minY; } } return i; } else { return (int) (this.theEntity.getEntityBoundingBox().minY + 0.5D); } } /**+ * Trims path data from the end to the first sun covered block */ protected void removeSunnyPath() { super.removeSunnyPath(); if (this.shouldAvoidSun) { if (this.worldObj.canSeeSky(new BlockPos(MathHelper.floor_double(this.theEntity.posX), (int) (this.theEntity.getEntityBoundingBox().minY + 0.5D), MathHelper.floor_double(this.theEntity.posZ)))) { return; } for (int i = 0; i < this.currentPath.getCurrentPathLength(); ++i) { PathPoint pathpoint = this.currentPath.getPathPointFromIndex(i); if (this.worldObj.canSeeSky(new BlockPos(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 */ protected boolean isDirectPathBetweenPoints(Vec3 posVec31, Vec3 posVec32, int sizeX, int sizeY, int sizeZ) { int i = MathHelper.floor_double(posVec31.xCoord); int j = MathHelper.floor_double(posVec31.zCoord); double d0 = posVec32.xCoord - posVec31.xCoord; double d1 = posVec32.zCoord - posVec31.zCoord; double d2 = d0 * d0 + d1 * d1; if (d2 < 1.0E-8D) { return false; } else { double d3 = 1.0D / Math.sqrt(d2); d0 = d0 * d3; d1 = d1 * d3; sizeX = sizeX + 2; sizeZ = sizeZ + 2; if (!this.isSafeToStandAt(i, (int) posVec31.yCoord, j, sizeX, sizeY, sizeZ, posVec31, d0, d1)) { return false; } else { sizeX = sizeX - 2; sizeZ = sizeZ - 2; double d4 = 1.0D / Math.abs(d0); double d5 = 1.0D / Math.abs(d1); double d6 = (double) (i * 1) - posVec31.xCoord; double d7 = (double) (j * 1) - posVec31.zCoord; if (d0 >= 0.0D) { ++d6; } if (d1 >= 0.0D) { ++d7; } d6 = d6 / d0; d7 = d7 / d1; int k = d0 < 0.0D ? -1 : 1; int l = d1 < 0.0D ? -1 : 1; int i1 = MathHelper.floor_double(posVec32.xCoord); int j1 = MathHelper.floor_double(posVec32.zCoord); int k1 = i1 - i; int l1 = j1 - j; while (k1 * k > 0 || l1 * l > 0) { if (d6 < d7) { d6 += d4; i += k; k1 = i1 - i; } else { d7 += d5; j += l; l1 = j1 - j; } if (!this.isSafeToStandAt(i, (int) posVec31.yCoord, j, sizeX, sizeY, sizeZ, posVec31, d0, d1)) { return false; } } return true; } } } /**+ * Returns true when an entity could stand at a position, * including solid blocks under the entire entity. */ private boolean isSafeToStandAt(int x, int y, int z, int sizeX, int sizeY, int sizeZ, Vec3 vec31, double parDouble1, double parDouble2) { int i = x - sizeX / 2; int j = z - sizeZ / 2; if (!this.isPositionClear(i, y, j, sizeX, sizeY, sizeZ, vec31, parDouble1, parDouble2)) { return false; } else { for (int k = i; k < i + sizeX; ++k) { for (int l = j; l < j + sizeZ; ++l) { double d0 = (double) k + 0.5D - vec31.xCoord; double d1 = (double) l + 0.5D - vec31.zCoord; if (d0 * parDouble1 + d1 * parDouble2 >= 0.0D) { Block block = this.worldObj.getBlockState(new BlockPos(k, y - 1, l)).getBlock(); Material material = block.getMaterial(); if (material == Material.air) { return false; } if (material == Material.water && !this.theEntity.isInWater()) { return false; } if (material == Material.lava) { return false; } } } } return true; } } /**+ * Returns true if an entity does not collide with any solid * blocks at the position. */ private boolean isPositionClear(int parInt1, int parInt2, int parInt3, int parInt4, int parInt5, int parInt6, Vec3 parVec3_1, double parDouble1, double parDouble2) { for (BlockPos blockpos : BlockPos.getAllInBox(new BlockPos(parInt1, parInt2, parInt3), new BlockPos(parInt1 + parInt4 - 1, parInt2 + parInt5 - 1, parInt3 + parInt6 - 1))) { double d0 = (double) blockpos.getX() + 0.5D - parVec3_1.xCoord; double d1 = (double) blockpos.getZ() + 0.5D - parVec3_1.zCoord; if (d0 * parDouble1 + d1 * parDouble2 >= 0.0D) { Block block = this.worldObj.getBlockState(blockpos).getBlock(); if (!block.isPassable(this.worldObj, blockpos)) { return false; } } } return true; } public void setAvoidsWater(boolean avoidsWater) { this.nodeProcessor.setAvoidsWater(avoidsWater); } public boolean getAvoidsWater() { return this.nodeProcessor.getAvoidsWater(); } public void setBreakDoors(boolean canBreakDoors) { this.nodeProcessor.setBreakDoors(canBreakDoors); } public void setEnterDoors(boolean par1) { this.nodeProcessor.setEnterDoors(par1); } public boolean getEnterDoors() { return this.nodeProcessor.getEnterDoors(); } public void setCanSwim(boolean canSwim) { this.nodeProcessor.setCanSwim(canSwim); } public boolean getCanSwim() { return this.nodeProcessor.getCanSwim(); } public void setAvoidSun(boolean par1) { this.shouldAvoidSun = par1; } }