Pumpkin/pumpkin/src/entity/ai/goal/track_target.rs
2026-01-15 20:29:30 +01:00

147 lines
4.2 KiB
Rust

use super::{Controls, Goal, to_goal_ticks};
use crate::entity::ai::goal::GoalFuture;
use crate::entity::ai::target_predicate::TargetPredicate;
use crate::entity::living::LivingEntity;
use crate::entity::mob::Mob;
use crate::entity::{EntityBase, mob::MobEntity};
use rand::Rng;
use std::sync::Arc;
const UNSET: i32 = 0;
const CAN_TRACK: i32 = 1;
const CANNOT_TRACK: i32 = 2;
#[expect(dead_code)]
pub struct TrackTargetGoal {
goal_control: Controls,
target: Option<Arc<dyn EntityBase>>,
check_visibility: bool,
check_can_navigate: bool,
can_navigate_flag: i32,
check_can_navigate_cooldown: i32,
time_without_visibility: i32,
max_time_without_visibility: i32, // Default 60
}
#[expect(dead_code)]
impl TrackTargetGoal {
#[must_use]
pub fn new(check_visibility: bool, check_can_navigate: bool) -> Self {
Self {
goal_control: Controls::TARGET,
target: None,
check_visibility,
check_can_navigate,
can_navigate_flag: UNSET,
check_can_navigate_cooldown: 0,
time_without_visibility: 0,
max_time_without_visibility: 60,
}
}
pub fn with_default(check_visibility: bool) -> Self {
Self::new(check_visibility, false)
}
// TODO: get from entity attribute
pub fn get_follow_range(_mob: &MobEntity) -> f32 {
32.0
}
fn can_navigate_to_entity(&mut self, mob: &dyn Mob, _target: &LivingEntity) -> bool {
self.check_can_navigate_cooldown = to_goal_ticks(10 + mob.get_random().random_range(0..5));
// TODO: after implementing path
false
}
pub fn can_track(
&mut self,
mob: &dyn Mob,
target: Option<&LivingEntity>,
target_predicate: &TargetPredicate,
) -> bool {
if target.is_none() {
return false;
}
let mob_entity = mob.get_mob_entity();
let target = target.unwrap();
let world = &mob_entity.living_entity.entity.world;
if !target_predicate.test(world.clone(), Some(&mob_entity.living_entity), target) {
return false;
} /*else if (!this.mob.isInPositionTargetRange(target.getBlockPos())) {
return false;
}*/
// TODO: implement this
if self.check_can_navigate {
self.check_can_navigate_cooldown -= 1;
if self.check_can_navigate_cooldown <= 0 {
self.can_navigate_flag = UNSET;
}
if self.can_navigate_flag == UNSET {
let value = if self.can_navigate_to_entity(mob, target) {
CAN_TRACK
} else {
CANNOT_TRACK
};
self.can_navigate_flag = value;
}
if self.can_navigate_flag == CANNOT_TRACK {
return false;
}
}
true
}
}
impl Goal for TrackTargetGoal {
fn should_continue<'a>(&'a self, mob: &'a dyn Mob) -> GoalFuture<'a, bool> {
Box::pin(async {
let mob = mob.get_mob_entity();
let mob_target = mob.target.lock().await;
// We need to decide which target to use for the check
let target = if mob_target.is_some() {
(*mob_target).clone()
} else {
self.target.clone()
};
// Drop the guard immediately after access to release the lock
drop(mob_target);
if target.is_none() {
return false;
} // TODO: continue when scoreboard team are implemented
true
})
}
fn start<'a>(&'a mut self, _mob: &'a dyn Mob) -> GoalFuture<'a, ()> {
Box::pin(async {
self.can_navigate_flag = 0;
self.check_can_navigate_cooldown = 0;
self.time_without_visibility = 0;
// No await needed here
})
}
fn stop<'a>(&'a mut self, mob: &'a dyn Mob) -> GoalFuture<'a, ()> {
Box::pin(async {
let mob = mob.get_mob_entity();
let mut mob_target = mob.target.lock().await;
*mob_target = None;
self.target = None;
})
}
fn controls(&self) -> Controls {
self.goal_control
}
}