minecraft-src/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
2025-07-04 01:41:11 +03:00

139 lines
4 KiB
Java

package net.minecraft.world.entity.ai.goal;
import java.util.EnumSet;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.level.LevelReader;
public abstract class MoveToBlockGoal extends Goal {
private static final int GIVE_UP_TICKS = 1200;
private static final int STAY_TICKS = 1200;
private static final int INTERVAL_TICKS = 200;
protected final PathfinderMob mob;
public final double speedModifier;
/**
* Controls task execution delay
*/
protected int nextStartTick;
protected int tryTicks;
private int maxStayTicks;
/**
* Block to move to
*/
protected BlockPos blockPos = BlockPos.ZERO;
private boolean reachedTarget;
private final int searchRange;
private final int verticalSearchRange;
protected int verticalSearchStart;
public MoveToBlockGoal(PathfinderMob mob, double speedModifier, int searchRange) {
this(mob, speedModifier, searchRange, 1);
}
public MoveToBlockGoal(PathfinderMob mob, double speedModifier, int searchRange, int verticalSearchRange) {
this.mob = mob;
this.speedModifier = speedModifier;
this.searchRange = searchRange;
this.verticalSearchStart = 0;
this.verticalSearchRange = verticalSearchRange;
this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.JUMP));
}
@Override
public boolean canUse() {
if (this.nextStartTick > 0) {
this.nextStartTick--;
return false;
} else {
this.nextStartTick = this.nextStartTick(this.mob);
return this.findNearestBlock();
}
}
protected int nextStartTick(PathfinderMob creature) {
return reducedTickDelay(200 + creature.getRandom().nextInt(200));
}
@Override
public boolean canContinueToUse() {
return this.tryTicks >= -this.maxStayTicks && this.tryTicks <= 1200 && this.isValidTarget(this.mob.level(), this.blockPos);
}
@Override
public void start() {
this.moveMobToBlock();
this.tryTicks = 0;
this.maxStayTicks = this.mob.getRandom().nextInt(this.mob.getRandom().nextInt(1200) + 1200) + 1200;
}
protected void moveMobToBlock() {
this.mob.getNavigation().moveTo(this.blockPos.getX() + 0.5, this.blockPos.getY() + 1, this.blockPos.getZ() + 0.5, this.speedModifier);
}
public double acceptedDistance() {
return 1.0;
}
protected BlockPos getMoveToTarget() {
return this.blockPos.above();
}
@Override
public boolean requiresUpdateEveryTick() {
return true;
}
@Override
public void tick() {
BlockPos blockPos = this.getMoveToTarget();
if (!blockPos.closerToCenterThan(this.mob.position(), this.acceptedDistance())) {
this.reachedTarget = false;
this.tryTicks++;
if (this.shouldRecalculatePath()) {
this.mob.getNavigation().moveTo(blockPos.getX() + 0.5, blockPos.getY(), blockPos.getZ() + 0.5, this.speedModifier);
}
} else {
this.reachedTarget = true;
this.tryTicks--;
}
}
public boolean shouldRecalculatePath() {
return this.tryTicks % 40 == 0;
}
protected boolean isReachedTarget() {
return this.reachedTarget;
}
/**
* Searches and sets new destination block and returns true if a suitable block (specified in {@link #isValidTarget(net.minecraft.world.level.LevelReader, net.minecraft.core.BlockPos)}) can be found.
*/
protected boolean findNearestBlock() {
int i = this.searchRange;
int j = this.verticalSearchRange;
BlockPos blockPos = this.mob.blockPosition();
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
for (int k = this.verticalSearchStart; k <= j; k = k > 0 ? -k : 1 - k) {
for (int l = 0; l < i; l++) {
for (int m = 0; m <= l; m = m > 0 ? -m : 1 - m) {
for (int n = m < l && m > -l ? l : 0; n <= l; n = n > 0 ? -n : 1 - n) {
mutableBlockPos.setWithOffset(blockPos, m, k - 1, n);
if (this.mob.isWithinRestriction(mutableBlockPos) && this.isValidTarget(this.mob.level(), mutableBlockPos)) {
this.blockPos = mutableBlockPos;
return true;
}
}
}
}
}
return false;
}
/**
* Return {@code true} to set given position as destination
*/
protected abstract boolean isValidTarget(LevelReader level, BlockPos pos);
}