bevy_event_chain 0.2.0

Easy trait-like behavior using observers and relations in Bevy
Documentation
# bevy_event_chain

[![crates.io](https://img.shields.io/crates/v/bevy_event_chain)](https://crates.io/crates/bevy_event_chain)

| bevy  | bevy_event_chain |
|-------|------------------|
| 0.17  | 0.1              |
| 0.18  | 0.2              |

Easy trait-like behavior using observers and relations.

Relationship targets ("parents") initiate a chain of events that go one-by-one through their relationships ("children")
before returning to the target. This is useful for acting as one mutable event, like equipment progressively
modifying stats of attacks when they happen.

# Sample

```rust
pub use bevy::prelude::*;
pub use bevy_event_chain::*;

#[derive(Component)]
#[relationship_target(relationship = TestRelationshipOf)]
pub struct TestRelationships(Vec<Entity>);

#[derive(Component)]
#[relationship(relationship_target = TestRelationships)]
pub struct TestRelationshipOf(pub Entity);

#[derive(RelatedChainEvent, Clone)]
#[related_chain_event(relationship_target = TestRelationships)]
pub struct RelatedTestEvent {
    pub value: i32,
    chain: RelatedEventChain,
}

impl RelatedTestEvent {
    pub fn new(relationship_target: Entity, relation: &ChainEventRelation<Self>) -> Self {
        Self {
            value: 0,
            chain: relation.new_chain(relationship_target),
        }
    }
}

#[derive(Event)]
pub struct DoTest;

#[derive(Resource)]
pub struct ResultResource(pub i32);


fn main() {
    let mut world = World::new();

    let root = world.spawn_empty().id();
    world.spawn(TestRelationshipOf(root)).observe(
        |mut trigger: On<RelatedTestEvent>, mut commands: Commands| {
            trigger.value += 1;
            trigger.trigger_next(&mut commands);
        },
    );
    world.spawn(TestRelationshipOf(root)).observe(
        |mut trigger: On<RelatedTestEvent>, mut commands: Commands| {
            trigger.value += 2;
            trigger.trigger_next(&mut commands);
        },
    );
    world.add_observer(
        |trigger: On<RelatedTestEvent, TestRelationships>, mut commands: Commands| {
            commands.insert_resource(ResultResource(trigger.value));
        },
    );
    world.flush();

    world.add_observer(
        move |_do: On<DoTest>,
              mut commands: Commands,
              relation: ChainEventRelation<RelatedTestEvent>| {
            RelatedTestEvent::new(root, &relation).trigger(&mut commands);
        },
    );
    world.trigger(DoTest);
    world.flush();

    let result = world.resource::<ResultResource>().0;
    assert_eq!(result, 3);
}
```

# Usage

## [`ChainEvent`]

The basic, manual version of the event chain.

Derive [`ChainEvent`] (and [`Clone`](std::clone::Clone))
on an event. It impls [`Event`](bevy::ecs::event::Event) and [`EntityEvent`](bevy::ecs::event::EntityEvent). Similarly to
[`EntityEvent`](bevy::ecs::event::EntityEvent), it needs a field of type [`EventChain`]
that is either named `chain` or has the `#[event_target]` attribute.

Also similarly to [`EntityEvent`](bevy::ecs::event::EntityEvent), it uses [`EntityTrigger`](bevy::ecs::event::EntityTrigger),
but this can be changed with `#[chain_event(trigger = ...)]`.

```rust ignore
#[derive(ChainEvent, Clone)]
pub struct TestEvent {
    pub value: i32,
    chain: EventChain,
}
```

The [`EventChain`] is constructed from a `Vec<Entity>` representing the entities in the order to send the event to,
or optionally with [`new_with_end`](EventChain::new_with_end) which just appends another entity (typically the parent or relationship target
between them) to the end of the list.

```rust ignore
impl TestEvent {
    pub fn new(targets: Vec<Entity>, root: Entity) -> Self {
        Self {
            value: 0,
            chain: EventChain::new_with_end(targets, root),
        }
    }
}
```

Spawn your entities, usually using a relationship.

```rust ignore
let parent = commands.spawn_empty().id();
let child = commands.spawn(TestRelationshipOf(parent)).id();
```

Observe the chain event on each of the entities. Each entity should trigger [`ChainEvent::next(&self) -> Self`](ChainEvent::next) to pass the event forward.

```rust ignore
commands.entity(child).observe(
	|mut trigger: On<TestEvent>, mut commands: Commands| {
		trigger.value += 1;
		commands.trigger(trigger.next());
	},
);
```

Finally, consume the event with the last entity if need be.

```rust ignore
commands.entity(root).observe(
	|trigger: On<TestEvent>, mut commands: Commands| {
		commands.insert_resource(ResultResource(trigger.value));
	},
);
```

You can now trigger events!

```rust ignore
let related = relationships
	.get(root)?
	.collection()
	.clone();
commands.trigger(TestEvent::new(related, root));
```

## [`RelatedChainEvent`]

The version of the event chain that's way easier to use, using relationships.

Start by creating your relationship as normal.

```rust ignore
#[derive(Component)]
#[relationship_target(relationship = TestRelationshipOf)]
pub struct TestRelationships(Vec<Entity>);

#[derive(Component)]
#[relationship(relationship_target = TestRelationships)]
pub struct TestRelationshipOf(pub Entity);
```

Derive [`RelatedChainEvent`] (and [`Clone`](std::clone::Clone)) on an event. It impls [`Event`](bevy::ecs::event::Event) and
[`EntityEvent`](bevy::ecs::event::EntityEvent). Similarly to [`EntityEvent`](bevy::ecs::event::EntityEvent),
it needs a field of type [`RelatedEventChain`] that is either named `chain` or has the `#[event_target]` attribute.

The relationship must be specified in the `#[related_chain_event]` attribute, using either `relationship_target = ...`
or `relationship = ...` or both. (Personally, I think `relationship_target = Children` looks better than `relationship = ChildOf`.)

The event uses [`EntityComponentTrigger`](trigger::EntityComponentTrigger)
(NOT [`EntityComponentsTrigger`](bevy::ecs::event::EntityComponentsTrigger)) and can't be changed.

```rust ignore
#[derive(RelatedChainEvent, Clone)]
#[related_chain_event(relationship_target = TestRelationships)]
pub struct RelatedTestEvent {
    pub value: i32,
    chain: RelatedEventChain,
}
```

The [`RelatedEventChain`](crate::RelatedEventChain) is constructed by requesting [`ChainEventRelation<MyEvent>`] as a `SystemParam`
and calling [`ChainEventRelation::new_chain(relationship_target: Entity)`](ChainEventRelation::new_chain).

```rust ignore
impl RelatedTestEvent {
    pub fn new(relationship_target: Entity, relation: &ChainEventRelation<Self>) -> Self {
        Self {
            value: 0,
            chain: relation.new_chain(relationship_target),
        }
    }
}
```

Spawn your entities and their relationship.

```rust ignore
let parent = commands.spawn_empty().id();
let child = commands.spawn(TestRelationshipOf(parent)).id();
```

Observe the chain event on each of the entities. Each entity should trigger [`RelatedChainEvent::next(&self) -> Self`](RelatedChainEvent::next)
and, from the `next` event, [`RelatedChainEvent::get_trigger(&self) -> EntityComponentTrigger`](RelatedChainEvent::get_trigger) to pass the event forward.
For simplicity, you can also use [`RelatedChainEvent::trigger(self, commands: &mut Commands)`](RelatedChainEvent::trigger) from the `next` event or
[`RelatedChainEvent::trigger_next(&self, commands: &mut Commands)`](RelatedChainEvent::trigger_next) (which just triggers
[`next()`](RelatedChainEvent::next) and [`next.get_trigger()`](RelatedChainEvent::get_trigger))
from the source event.

```rust ignore
commands.entity(child).observe(
	|mut trigger: On<RelatedTestEvent>, mut commands: Commands| {
		trigger.value += 1;
		trigger.trigger_next(&mut commands);
	},
);
```

Finally, consume the event with the relationship target if need be.

```rust ignore
commands.entity(root).observe(
	|trigger: On<RelatedTestEvent>, mut commands: Commands| {
		commands.insert_resource(ResultResource(trigger.value));
	},
);
```

Also for simplicity, the relationship type and its target type are passed into the event trigger
(hence the [`EntityComponentTrigger`](trigger::EntityComponentTrigger)),
so you can specify a type into the [`On`](bevy::prelude::On) to use a global observer instead. This is useful for globally consuming the final output of
an event, or for using a global observer to pass along an event that should always be passed along and shouldn't be mutated (eg. if it
only contains entity references but not their mutable components), so you don't have to worry about passing it along in each of the
entity observers.

```rust ignore
app.add_observer(
	|trigger: On<RelatedTestEvent, TestRelationships>, mut commands: Commands| {
		commands.insert_resource(ResultResource(trigger.value));
	},
);
```

You can now trigger events!

```rust ignore
fn fire_event(
	relation: ChainEventRelation<RelatedTestEvent>,
	...
) {
	...
	RelatedTestEvent::new(relationship_target, &relation).trigger(&mut commands);
}
```