-
-
Notifications
You must be signed in to change notification settings - Fork 164
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add initial path finding * Make everything work :D
- Loading branch information
Showing
9 changed files
with
198 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
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; | ||
|
||
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(); | ||
return 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, | ||
}); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
pub mod goal; | ||
pub mod path; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
use pumpkin_core::math::vector3::Vector3; | ||
use pumpkin_protocol::client::play::CUpdateEntityPos; | ||
|
||
use crate::entity::living::LivingEntity; | ||
|
||
#[derive(Default)] | ||
pub struct Navigator { | ||
current_goal: Option<NavigatorGoal>, | ||
} | ||
|
||
pub struct NavigatorGoal { | ||
pub current_progress: Vector3<f64>, | ||
pub destination: Vector3<f64>, | ||
pub speed: f64, | ||
} | ||
|
||
impl Navigator { | ||
pub fn set_progress(&mut self, goal: NavigatorGoal) { | ||
self.current_goal = Some(goal); | ||
} | ||
|
||
pub fn cancel(&mut self) { | ||
self.current_goal = None; | ||
} | ||
|
||
pub async fn tick(&mut self, entity: &LivingEntity) { | ||
if let Some(goal) = &mut self.current_goal { | ||
// first lets check if we reached destination | ||
if goal.current_progress == goal.destination { | ||
// if yes, we are done here | ||
self.current_goal = None; | ||
return; | ||
} | ||
|
||
// A star algorithm | ||
let mut best_move = Vector3::new(0.0, 0.0, 0.0); | ||
let mut lowest_cost = f64::MAX; | ||
|
||
for x in -1..=1 { | ||
for z in -1..=1 { | ||
let x = f64::from(x); | ||
let z = f64::from(z); | ||
let potential_pos = Vector3::new( | ||
goal.current_progress.x + x, | ||
goal.current_progress.y, | ||
goal.current_progress.z + z, | ||
); | ||
let node = Node::new(potential_pos); | ||
let cost = node.get_expense(goal.destination); | ||
|
||
if cost < lowest_cost { | ||
lowest_cost = cost; | ||
best_move = Vector3::new(x, 0.0, z); | ||
} | ||
} | ||
} | ||
|
||
// this is important, first this saves us many packets when we don't actually move, and secound this prevents division using zero | ||
// when normalize | ||
if best_move.x == 0.0 && best_move.z == 0.0 { | ||
return; | ||
} | ||
// Update current progress based on the best move | ||
goal.current_progress += best_move.normalize() * goal.speed; | ||
|
||
// now lets move | ||
entity.set_pos(goal.current_progress); | ||
let pos = entity.entity.pos.load(); | ||
let last_pos = entity.last_pos.load(); | ||
|
||
entity | ||
.entity | ||
.world | ||
.broadcast_packet_all(&CUpdateEntityPos::new( | ||
entity.entity.entity_id.into(), | ||
Vector3::new( | ||
pos.x.mul_add(4096.0, -(last_pos.x * 4096.0)) as i16, | ||
pos.y.mul_add(4096.0, -(last_pos.y * 4096.0)) as i16, | ||
pos.z.mul_add(4096.0, -(last_pos.z * 4096.0)) as i16, | ||
), | ||
entity | ||
.entity | ||
.on_ground | ||
.load(std::sync::atomic::Ordering::Relaxed), | ||
)) | ||
.await; | ||
} | ||
} | ||
} | ||
|
||
pub struct Node { | ||
pub location: Vector3<f64>, | ||
} | ||
|
||
impl Node { | ||
#[must_use] | ||
pub fn new(location: Vector3<f64>) -> Self { | ||
Self { location } | ||
} | ||
/// How expensive is it to go to a location | ||
/// | ||
/// Returns a f64, Higher = More Expensive | ||
#[must_use] | ||
pub fn get_expense(&self, end: Vector3<f64>) -> f64 { | ||
self.location.squared_distance_to_vec(end).sqrt() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters