An experimental, status effects-as-entities system for Bevy.
1use bevy_ecs::prelude::*;
2use std::any::TypeId;
3use std::collections::HashMap;
4
5/// A function used to merge effects with [`EffectMode::Merge`](crate::EffectMode::Merge),
6/// which must be registered in the [registry](EffectMergeRegistry).
7///
8/// The component the function is registered for is guaranteed to exist on both provided entities.
9/// Note that the incoming entity exists in a **separate world**.
10///
11/// # Example
12/// ```rust
13/// # use bevy_ecs::prelude::*;
14/// # use bevy_alchemy::EffectMergeRegistry;
15/// #[derive(Component, Clone)]
16/// struct MyEffect(f32);
17///
18/// fn merge_my_effect(mut existing: EntityWorldMut, incoming: EntityRef) {
19/// let mut existing = existing.get_mut::<MyEffect>().unwrap();
20/// let incoming = incoming.get::<MyEffect>().unwrap();
21/// existing.0 += incoming.0;
22/// }
23/// ```
24pub type EffectMergeFn = fn(existing: EntityWorldMut, incoming: EntityRef);
25
26/// Stores the effect merge logic for each registered component.
27/// New components can be registered by providing a [`EffectMergeFn`] to the [`register`](EffectMergeRegistry::register) method.
28/// This function will be run whenever an effect is applied twice to the same entity with [`EffectMode::Merge`](crate::EffectMode::Merge).
29///
30/// # Example
31/// ```rust
32/// # use bevy_ecs::prelude::*;
33/// # use bevy_alchemy::EffectMergeRegistry;
34/// #[derive(Component, Clone)]
35/// struct MyEffect(f32);
36///
37/// fn main() {
38/// let mut world = World::new();
39///
40/// world.get_resource_or_init::<EffectMergeRegistry>()
41/// .register::<MyEffect>(merge_my_effect);
42/// }
43///
44/// fn merge_my_effect(mut existing: EntityWorldMut, incoming: EntityRef) {
45/// let mut existing = existing.get_mut::<MyEffect>().unwrap();
46/// let incoming = incoming.get::<MyEffect>().unwrap();
47/// existing.0 += incoming.0;
48/// }
49/// ```
50#[derive(Resource, Default)]
51pub struct EffectMergeRegistry {
52 pub(crate) merges: HashMap<TypeId, EffectMergeFn>,
53}
54
55impl EffectMergeRegistry {
56 /// Registers a [`EffectMergeFn`] to be run whenever two `T` status effect components are merged.
57 pub fn register<T: Component + Clone>(&mut self, f: EffectMergeFn) -> &mut Self {
58 self.merges.insert(TypeId::of::<T>(), f);
59 self
60 }
61}