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}