Pumpkin/pumpkin/src/entity/ai/goal/target_goal.rs
Alexander Medvedev debb713f3b ai: don't follow invulnerable
Prevents to follow invulnerable players (e.g. Gamemode Creative or Spectator)
2025-01-09 14:05:31 +01:00

71 lines
2.1 KiB
Rust

use std::sync::Arc;
use async_trait::async_trait;
use tokio::sync::Mutex;
use crate::entity::{ai::path::NavigatorGoal, mob::MobEntity, player::Player};
use super::Goal;
pub struct TargetGoal {
// TODO: make this an entity
target: Mutex<Option<Arc<Player>>>,
range: f64,
}
impl TargetGoal {
#[must_use]
pub fn new(range: f64) -> Self {
Self {
target: Mutex::new(None),
range,
}
}
}
#[async_trait]
impl Goal for TargetGoal {
async fn can_start(&self, mob: &MobEntity) -> bool {
// TODO: make this an entity
let mut target = self.target.lock().await;
// gets the closest entity (currently player)
*target = mob
.living_entity
.entity
.world
.get_closest_player(mob.living_entity.entity.pos.load(), self.range)
.await;
// we can't use filter, because of async clousrers
if let Some(player) = target.as_ref() {
if player.abilities.lock().await.invulnerable {
*target = None;
}
}
target.is_some()
}
async fn should_continue(&self, mob: &MobEntity) -> bool {
// if an entity is found, lets check so its in range
if let Some(target) = self.target.lock().await.as_ref() {
let mob_pos = mob.living_entity.entity.pos.load();
let target_pos = target.living_entity.entity.pos.load();
let abilities = target.abilities.lock().await;
return !abilities.invulnerable && mob_pos.squared_distance_to_vec(target_pos) <= (self.range * self.range);
}
false
}
async fn tick(&self, mob: &MobEntity) {
if let Some(target) = self.target.lock().await.as_ref() {
let mut navigator = mob.navigator.lock().await;
let target_player = target.living_entity.entity.pos.load();
navigator.set_progress(NavigatorGoal {
current_progress: mob.living_entity.entity.pos.load(),
destination: target_player,
speed: 0.1,
});
}
}
}