azalea/pathfinder/
custom_state.rs

1use std::{
2    any::{Any, TypeId},
3    sync::Arc,
4};
5
6use bevy_ecs::component::Component;
7use parking_lot::RwLock;
8use rustc_hash::FxHashMap;
9
10/// The component that holds the custom pathfinder state for one of our bots.
11///
12/// See [`CustomPathfinderStateRef`] for more information about the inner type.
13///
14/// Azalea won't automatically insert this component, so if you're trying to use
15/// it then you should also have logic to insert the component if it's not
16/// present.
17///
18/// Be aware that a read lock is held on the `RwLock` while a path is being
19/// calculated, which may take up to several seconds. For this reason, it may be
20/// favorable to use [`RwLock::try_write`] instead of [`RwLock::write`] when
21/// updating it to avoid blocking the current thread.
22#[derive(Clone, Component, Default)]
23pub struct CustomPathfinderState(pub Arc<RwLock<CustomPathfinderStateRef>>);
24
25/// Arbitrary state that's passed to the pathfinder, intended to be used for
26/// custom moves that need to access things that are usually inaccessible.
27///
28/// This is included in [`PathfinderCtx`].
29///
30/// [`PathfinderCtx`]: crate::pathfinder::PathfinderCtx
31#[derive(Debug, Default)]
32pub struct CustomPathfinderStateRef {
33    map: FxHashMap<TypeId, Box<dyn Any + Send + Sync>>,
34}
35
36impl CustomPathfinderStateRef {
37    pub fn insert<T: 'static + Send + Sync>(&mut self, t: T) {
38        self.map.insert(TypeId::of::<T>(), Box::new(t));
39    }
40
41    pub fn get<T: 'static + Send + Sync>(&self) -> Option<&T> {
42        self.map
43            .get(&TypeId::of::<T>())
44            .map(|value| value.downcast_ref().unwrap())
45    }
46}