package net.minecraft.world.entity.ai.control; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.tags.BlockTags; import net.minecraft.util.Mth; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.navigation.PathNavigation; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.pathfinder.NodeEvaluator; import net.minecraft.world.level.pathfinder.PathType; import net.minecraft.world.phys.shapes.VoxelShape; public class MoveControl implements Control { public static final float MIN_SPEED = 5.0E-4F; public static final float MIN_SPEED_SQR = 2.5000003E-7F; protected static final int MAX_TURN = 90; protected final Mob mob; protected double wantedX; protected double wantedY; protected double wantedZ; protected double speedModifier; protected float strafeForwards; protected float strafeRight; protected MoveControl.Operation operation = MoveControl.Operation.WAIT; public MoveControl(Mob p_24983_) { this.mob = p_24983_; } public boolean hasWanted() { return this.operation == MoveControl.Operation.MOVE_TO; } public double getSpeedModifier() { return this.speedModifier; } public void setWantedPosition(double p_24984_, double p_24985_, double p_24986_, double p_24987_) { this.wantedX = p_24984_; this.wantedY = p_24985_; this.wantedZ = p_24986_; this.speedModifier = p_24987_; if (this.operation != MoveControl.Operation.JUMPING) { this.operation = MoveControl.Operation.MOVE_TO; } } public void strafe(float p_24989_, float p_24990_) { this.operation = MoveControl.Operation.STRAFE; this.strafeForwards = p_24989_; this.strafeRight = p_24990_; this.speedModifier = 0.25; } public void tick() { if (this.operation == MoveControl.Operation.STRAFE) { float f = (float)this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED); float f1 = (float)this.speedModifier * f; float f2 = this.strafeForwards; float f3 = this.strafeRight; float f4 = Mth.sqrt(f2 * f2 + f3 * f3); if (f4 < 1.0F) { f4 = 1.0F; } f4 = f1 / f4; f2 *= f4; f3 *= f4; float f5 = Mth.sin(this.mob.getYRot() * (float) (Math.PI / 180.0)); float f6 = Mth.cos(this.mob.getYRot() * (float) (Math.PI / 180.0)); float f7 = f2 * f6 - f3 * f5; float f8 = f3 * f6 + f2 * f5; if (!this.isWalkable(f7, f8)) { this.strafeForwards = 1.0F; this.strafeRight = 0.0F; } this.mob.setSpeed(f1); this.mob.setZza(this.strafeForwards); this.mob.setXxa(this.strafeRight); this.operation = MoveControl.Operation.WAIT; } else if (this.operation == MoveControl.Operation.MOVE_TO) { this.operation = MoveControl.Operation.WAIT; double d0 = this.wantedX - this.mob.getX(); double d1 = this.wantedZ - this.mob.getZ(); double d2 = this.wantedY - this.mob.getY(); double d3 = d0 * d0 + d2 * d2 + d1 * d1; if (d3 < 2.5000003E-7F) { this.mob.setZza(0.0F); return; } float f9 = (float)(Mth.atan2(d1, d0) * 180.0F / (float)Math.PI) - 90.0F; this.mob.setYRot(this.rotlerp(this.mob.getYRot(), f9, 90.0F)); this.mob.setSpeed((float)(this.speedModifier * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED))); BlockPos blockpos = this.mob.blockPosition(); BlockState blockstate = this.mob.level().getBlockState(blockpos); VoxelShape voxelshape = blockstate.getCollisionShape(this.mob.level(), blockpos); if (d2 > this.mob.maxUpStep() && d0 * d0 + d1 * d1 < Math.max(1.0F, this.mob.getBbWidth()) || !voxelshape.isEmpty() && this.mob.getY() < voxelshape.max(Direction.Axis.Y) + blockpos.getY() && !blockstate.is(BlockTags.DOORS) && !blockstate.is(BlockTags.FENCES)) { this.mob.getJumpControl().jump(); this.operation = MoveControl.Operation.JUMPING; } } else if (this.operation == MoveControl.Operation.JUMPING) { this.mob.setSpeed((float)(this.speedModifier * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED))); if (this.mob.onGround() || this.mob.isInLiquid() && this.mob.isAffectedByFluids()) { this.operation = MoveControl.Operation.WAIT; } } else { this.mob.setZza(0.0F); } } private boolean isWalkable(float p_24997_, float p_24998_) { PathNavigation pathnavigation = this.mob.getNavigation(); if (pathnavigation != null) { NodeEvaluator nodeevaluator = pathnavigation.getNodeEvaluator(); if (nodeevaluator != null && nodeevaluator.getPathType( this.mob, BlockPos.containing(this.mob.getX() + p_24997_, this.mob.getBlockY(), this.mob.getZ() + p_24998_) ) != PathType.WALKABLE) { return false; } } return true; } protected float rotlerp(float p_24992_, float p_24993_, float p_24994_) { float f = Mth.wrapDegrees(p_24993_ - p_24992_); if (f > p_24994_) { f = p_24994_; } if (f < -p_24994_) { f = -p_24994_; } float f1 = p_24992_ + f; if (f1 < 0.0F) { f1 += 360.0F; } else if (f1 > 360.0F) { f1 -= 360.0F; } return f1; } public double getWantedX() { return this.wantedX; } public double getWantedY() { return this.wantedY; } public double getWantedZ() { return this.wantedZ; } protected static enum Operation { WAIT, MOVE_TO, STRAFE, JUMPING; } }