minecraft-src/net/minecraft/world/entity/ai/goal/target/TargetGoal.java
2025-07-04 02:00:41 +03:00

146 lines
3.7 KiB
Java

package net.minecraft.world.entity.ai.goal.target;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
import net.minecraft.world.level.pathfinder.Node;
import net.minecraft.world.level.pathfinder.Path;
import net.minecraft.world.scores.Team;
import org.jetbrains.annotations.Nullable;
public abstract class TargetGoal extends Goal {
private static final int EMPTY_REACH_CACHE = 0;
private static final int CAN_REACH_CACHE = 1;
private static final int CANT_REACH_CACHE = 2;
/**
* The entity that this goal belongs to
*/
protected final Mob mob;
protected final boolean mustSee;
private final boolean mustReach;
private int reachCache;
private int reachCacheTime;
private int unseenTicks;
@Nullable
protected LivingEntity targetMob;
protected int unseenMemoryTicks = 60;
public TargetGoal(Mob mob, boolean mustSee) {
this(mob, mustSee, false);
}
public TargetGoal(Mob mob, boolean mustSee, boolean mustReach) {
this.mob = mob;
this.mustSee = mustSee;
this.mustReach = mustReach;
}
@Override
public boolean canContinueToUse() {
LivingEntity livingEntity = this.mob.getTarget();
if (livingEntity == null) {
livingEntity = this.targetMob;
}
if (livingEntity == null) {
return false;
} else if (!this.mob.canAttack(livingEntity)) {
return false;
} else {
Team team = this.mob.getTeam();
Team team2 = livingEntity.getTeam();
if (team != null && team2 == team) {
return false;
} else {
double d = this.getFollowDistance();
if (this.mob.distanceToSqr(livingEntity) > d * d) {
return false;
} else {
if (this.mustSee) {
if (this.mob.getSensing().hasLineOfSight(livingEntity)) {
this.unseenTicks = 0;
} else if (++this.unseenTicks > reducedTickDelay(this.unseenMemoryTicks)) {
return false;
}
}
this.mob.setTarget(livingEntity);
return true;
}
}
}
}
protected double getFollowDistance() {
return this.mob.getAttributeValue(Attributes.FOLLOW_RANGE);
}
@Override
public void start() {
this.reachCache = 0;
this.reachCacheTime = 0;
this.unseenTicks = 0;
}
@Override
public void stop() {
this.mob.setTarget(null);
this.targetMob = null;
}
/**
* Checks if this is a suitable target.
*/
protected boolean canAttack(@Nullable LivingEntity potentialTarget, TargetingConditions targetPredicate) {
if (potentialTarget == null) {
return false;
} else if (!targetPredicate.test(getServerLevel(this.mob), this.mob, potentialTarget)) {
return false;
} else if (!this.mob.isWithinRestriction(potentialTarget.blockPosition())) {
return false;
} else {
if (this.mustReach) {
if (--this.reachCacheTime <= 0) {
this.reachCache = 0;
}
if (this.reachCache == 0) {
this.reachCache = this.canReach(potentialTarget) ? 1 : 2;
}
if (this.reachCache == 2) {
return false;
}
}
return true;
}
}
/**
* Checks to see if this entity can find a short path to the given target.
*/
private boolean canReach(LivingEntity target) {
this.reachCacheTime = reducedTickDelay(10 + this.mob.getRandom().nextInt(5));
Path path = this.mob.getNavigation().createPath(target, 0);
if (path == null) {
return false;
} else {
Node node = path.getEndNode();
if (node == null) {
return false;
} else {
int i = node.x - target.getBlockX();
int j = node.z - target.getBlockZ();
return i * i + j * j <= 2.25;
}
}
}
public TargetGoal setUnseenMemoryTicks(int unseenMemoryTicks) {
this.unseenMemoryTicks = unseenMemoryTicks;
return this;
}
}