bevy_channel_trigger/
lib.rs1use bevy::{ecs::event::Event, prelude::*};
2use crossbeam_channel::{Receiver, Sender, TryRecvError};
3
4#[derive(Resource, Clone, Debug)]
6pub struct ChannelSender<T: Event>(Sender<T>);
7
8impl<T: Event> ChannelSender<T> {
9 pub fn send(&self, event: impl Into<T>) {
11 let event = event.into();
12 if let Err(err) = self.0.send(event) {
13 error!("sending failed due to receiver being dropped: {err:?}");
14 };
15 }
16}
17
18#[derive(Resource)]
19struct EventReceiver<T: Event>(Receiver<T>);
20
21pub trait ChannelTriggerApp {
23 fn add_channel_trigger<T: Event>(&mut self) -> ChannelSender<T>;
27}
28
29impl ChannelTriggerApp for App {
30 fn add_channel_trigger<T: Event>(&mut self) -> ChannelSender<T> {
31 let (sender, receiver) = crossbeam_channel::unbounded();
32 self.insert_resource(EventReceiver::<T>(receiver));
33 self.add_systems(PreUpdate, process_events::<T>);
34 ChannelSender::<T>(sender)
35 }
36}
37
38fn process_events<T: Event>(receiver: Option<Res<EventReceiver<T>>>, mut commands: Commands) {
39 if let Some(receiver) = receiver.as_ref() {
40 loop {
41 match receiver.0.try_recv() {
42 Ok(msg) => {
43 commands.trigger(msg);
44 }
45 Err(TryRecvError::Disconnected) => {
46 error!("sender dropped, removing receiver");
47 commands.remove_resource::<EventReceiver<T>>();
48 }
49 Err(TryRecvError::Empty) => {
50 break;
51 }
52 }
53 }
54 }
55}