use crate::prelude::RemoteEvent;
use crate::registry::{MessageError, MessageKind};
use crate::send::Priority;
use crate::{MessageManager, MessageNetId};
use alloc::vec::Vec;
use bevy_ecs::change_detection::MutUntyped;
use bevy_ecs::lifecycle::HookContext;
use bevy_ecs::prelude::*;
use bevy_ecs::world::DeferredWorld;
use bevy_utils::prelude::DebugName;
use lightyear_core::id::PeerId;
use lightyear_serde::ToBytes;
use lightyear_serde::entity_map::SendEntityMap;
use lightyear_serde::registry::ErasedSerializeFns;
use lightyear_serde::writer::Writer;
use lightyear_transport::channel::{Channel, ChannelKind};
use lightyear_transport::prelude::Transport;
use tracing::trace;
#[derive(Component)]
#[require(MessageManager)]
#[component(on_add = EventSender::<M>::on_add_hook)]
pub struct EventSender<M: Event> {
send: Vec<(M, ChannelKind, Priority)>,
writer: Writer,
}
impl<M: Event> Default for EventSender<M> {
fn default() -> Self {
Self {
send: Vec::new(),
writer: Writer::default(),
}
}
}
impl<M: Event> EventSender<M> {
pub(crate) unsafe fn send_event_typed(
trigger_sender: MutUntyped,
net_id: MessageNetId,
transport: &Transport,
serialize_metadata: &ErasedSerializeFns,
entity_map: &mut SendEntityMap,
) -> Result<(), MessageError> {
let mut sender = unsafe { trigger_sender.with_type::<Self>() };
let sender = &mut *sender;
sender.send.drain(..).try_for_each(|(message, channel_kind, priority)| {
net_id.to_bytes(&mut sender.writer)?;
unsafe { serialize_metadata.serialize::<SendEntityMap, M, M>(&message, &mut sender.writer, entity_map)? };
let bytes = sender.writer.split();
trace!("Sending message of type {:?} with net_id {net_id:?} on channel {channel_kind:?}", DebugName::type_name::<M>());
transport.send_erased(channel_kind, bytes, priority)?;
Ok(())
})
}
pub(crate) unsafe fn send_local_trigger_typed(
trigger_sender: MutUntyped,
commands: &ParallelCommands,
) {
let mut sender = unsafe { trigger_sender.with_type::<Self>() };
sender
.send
.drain(..)
.for_each(|(message, channel_kind, priority)| {
let remote_trigger = RemoteEvent {
trigger: message,
from: PeerId::Local(0),
};
commands.command_scope(|mut c| {
c.trigger(remote_trigger);
});
});
}
pub fn on_add_hook(mut world: DeferredWorld, context: HookContext) {
world.commands().queue(move |world: &mut World| {
let mut entity_mut = world.entity_mut(context.entity);
let mut message_manager = entity_mut.get_mut::<MessageManager>().unwrap();
let message_kind_present = message_manager
.send_triggers
.iter()
.any(|(message_kind, _)| *message_kind == MessageKind::of::<M>());
if !message_kind_present {
message_manager
.send_triggers
.push((MessageKind::of::<M>(), context.component_id));
}
})
}
}
pub(crate) type SendTriggerFn = unsafe fn(
sender: MutUntyped,
message_net_id: MessageNetId,
transport: &Transport,
serialize_metadata: &ErasedSerializeFns,
entity_map: &mut SendEntityMap,
) -> Result<(), MessageError>;
pub(crate) type SendLocalTriggerFn = unsafe fn(sender: MutUntyped, commands: &ParallelCommands);
impl<M: Event> EventSender<M> {
pub fn trigger<C: Channel>(&mut self, trigger: M) {
self.send.push((trigger, ChannelKind::of::<C>(), 1.0));
}
}