azalea/pathfinder/
goto_event.rs

1use std::{sync::Arc, time::Duration};
2
3use bevy_ecs::{entity::Entity, event::Event};
4
5use crate::pathfinder::{
6    astar::PathfinderTimeout,
7    goals::Goal,
8    moves::{self, SuccessorsFn},
9};
10
11/// Send this event to start pathfinding to the given goal.
12///
13/// Also see [`PathfinderClientExt::goto`].
14///
15/// This event is read by [`goto_listener`]
16///
17/// [`goto_listener`]: crate::pathfinder::goto_listener
18/// [`PathfinderClientExt::goto`]: crate::pathfinder::PathfinderClientExt::goto
19#[derive(Event)]
20#[non_exhaustive]
21pub struct GotoEvent {
22    /// The local bot entity that will do the pathfinding and execute the path.
23    pub entity: Entity,
24    pub goal: Arc<dyn Goal>,
25    pub opts: PathfinderOpts,
26}
27
28impl GotoEvent {
29    pub fn new(entity: Entity, goal: impl Goal + 'static, opts: PathfinderOpts) -> Self {
30        Self {
31            entity,
32            goal: Arc::new(goal),
33            opts,
34        }
35    }
36}
37
38/// Configuration options that the pathfinder will use when calculating and
39/// executing a path.
40///
41/// This can be passed into [`Client::goto_with_opts`] or
42/// [`Client::start_goto_with_opts`].
43///
44/// ```
45/// # use azalea::pathfinder::{moves, PathfinderOpts};
46/// // example config to disallow mining blocks and to not do parkour
47/// let opts = PathfinderOpts::new()
48///     .allow_mining(false)
49///     .successors_fn(moves::basic::basic_move);
50/// ```
51///
52/// [`Client::goto_with_opts`]: super::PathfinderClientExt::goto_with_opts
53/// [`Client::start_goto_with_opts`]: super::PathfinderClientExt::start_goto_with_opts
54#[derive(Clone, Debug)]
55#[non_exhaustive]
56pub struct PathfinderOpts {
57    pub(crate) successors_fn: SuccessorsFn,
58    pub(crate) allow_mining: bool,
59    pub(crate) retry_on_no_path: bool,
60    pub(crate) min_timeout: PathfinderTimeout,
61    pub(crate) max_timeout: PathfinderTimeout,
62}
63
64impl PathfinderOpts {
65    pub const fn new() -> Self {
66        Self {
67            successors_fn: moves::default_move,
68            allow_mining: true,
69            retry_on_no_path: true,
70            min_timeout: PathfinderTimeout::Time(Duration::from_secs(1)),
71            max_timeout: PathfinderTimeout::Time(Duration::from_secs(5)),
72        }
73    }
74    /// Set the function that's used for checking what moves are possible.
75    ///
76    /// Defaults to [`moves::default_move`].
77    pub fn successors_fn(mut self, successors_fn: SuccessorsFn) -> Self {
78        self.successors_fn = successors_fn;
79        self
80    }
81    /// Set whether the bot is allowed to break blocks while pathfinding.
82    ///
83    /// Defaults to `true`.
84    pub fn allow_mining(mut self, allow_mining: bool) -> Self {
85        self.allow_mining = allow_mining;
86        self
87    }
88    /// Whether we should recalculate the path when the pathfinder timed out and
89    /// there's no partial path to try.
90    ///
91    /// Defaults to `true`.
92    pub fn retry_on_no_path(mut self, retry_on_no_path: bool) -> Self {
93        self.retry_on_no_path = retry_on_no_path;
94        self
95    }
96    /// The minimum amount of time that should pass before the A* pathfinder
97    /// function can return a timeout if it finds a path that seems good enough.
98    /// It may take up to [`Self::max_timeout`] if it can't immediately find
99    /// a usable path.
100    ///
101    /// Defaults to `PathfinderTimeout::Time(Duration::from_secs(1))`.
102    ///
103    /// Also see [`PathfinderTimeout::Nodes`]
104    pub fn min_timeout(mut self, min_timeout: PathfinderTimeout) -> Self {
105        self.min_timeout = min_timeout;
106        self
107    }
108    /// The absolute maximum amount of time that the pathfinder function can
109    /// take to find a path. If it takes this long, it means no usable path was
110    /// found (so it might be impossible).
111    ///
112    /// Defaults to `PathfinderTimeout::Time(Duration::from_secs(5))`.
113    pub fn max_timeout(mut self, max_timeout: PathfinderTimeout) -> Self {
114        self.max_timeout = max_timeout;
115        self
116    }
117}
118impl Default for PathfinderOpts {
119    fn default() -> Self {
120        Self::new()
121    }
122}