139 lines
4 KiB
Java
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);
|
|
}
|