use core::any::TypeId;
use bevy::{ecs::entity::MapEntities, prelude::*, ptr::PtrMut};
use log::debug;
use serde::{Serialize, de::DeserializeOwned};
use super::{
client_message,
ctx::{ClientSendCtx, ServerReceiveCtx},
message_fns::{DeserializeFn, MessageFns, SerializeFn},
registry::RemoteMessageRegistry,
shared_message::SharedMessage,
};
use crate::prelude::*;
pub trait SharedEventAppExt {
fn add_shared_event<E: Event + Serialize + DeserializeOwned>(
&mut self,
channel: Channel,
) -> &mut Self {
self.add_shared_event_with(
channel,
client_message::default_serialize::<E>,
client_message::default_deserialize::<E>,
)
}
fn add_mapped_shared_event<E: Event + Serialize + DeserializeOwned + MapEntities + Clone>(
&mut self,
channel: Channel,
) -> &mut Self {
self.add_shared_event_with(
channel,
client_message::default_serialize_mapped::<E>,
client_message::default_deserialize::<E>,
)
}
fn add_shared_event_with<E: Event>(
&mut self,
channel: Channel,
serialize: SerializeFn<ClientSendCtx, E>,
deserialize: DeserializeFn<ServerReceiveCtx, E>,
) -> &mut Self;
}
impl SharedEventAppExt for App {
fn add_shared_event_with<E: Event>(
&mut self,
channel: Channel,
serialize: SerializeFn<ClientSendCtx, E>,
deserialize: DeserializeFn<ServerReceiveCtx, E>,
) -> &mut Self {
self.world_mut()
.resource_mut::<ProtocolHasher>()
.add_shared_event::<E>();
let fns = MessageFns::new(serialize, deserialize).with_convert::<SharedEventMessage<E>>();
let event = SharedEvent::new(self, channel, fns);
let mut registry = self.world_mut().resource_mut::<RemoteMessageRegistry>();
registry.register_shared_event(event);
self
}
}
pub(crate) struct SharedEvent {
type_id: TypeId,
message: SharedMessage,
trigger: TriggerFn,
}
impl SharedEvent {
fn new<E: Event>(
app: &mut App,
channel: Channel,
fns: MessageFns<ClientSendCtx, ServerReceiveCtx, SharedEventMessage<E>, E>,
) -> Self {
Self {
type_id: TypeId::of::<E>(),
message: SharedMessage::new(app, channel, fns),
trigger: Self::trigger_typed::<E>,
}
}
pub(crate) unsafe fn trigger(&self, commands: &mut Commands, shared_messages: PtrMut) {
unsafe { (self.trigger)(commands, shared_messages) }
}
unsafe fn trigger_typed<E: Event>(commands: &mut Commands, shared_messages: PtrMut) {
let shared_messages: &mut Messages<LocalOrRemote<SharedEventMessage<E>>> =
unsafe { shared_messages.deref_mut() };
for LocalOrRemote { sender, message } in shared_messages.drain() {
debug!(
"triggering `{}` from `{sender:?}`",
ShortName::of::<LocalOrRemote<E>>()
);
commands.trigger(LocalOrRemote {
sender,
message: message.event,
});
}
}
pub(super) fn type_id(&self) -> TypeId {
self.type_id
}
pub(crate) fn message(&self) -> &SharedMessage {
&self.message
}
}
type TriggerFn = unsafe fn(&mut Commands, PtrMut);
pub trait SharedTriggerExt {
fn shared_trigger(&mut self, event: impl Event);
}
impl SharedTriggerExt for Commands<'_, '_> {
fn shared_trigger(&mut self, event: impl Event) {
self.write_message(SharedEventMessage { event });
}
}
impl SharedTriggerExt for World {
fn shared_trigger(&mut self, event: impl Event) {
self.write_message(SharedEventMessage { event });
}
}
#[derive(Message)]
struct SharedEventMessage<E> {
event: E,
}
impl<E> From<E> for SharedEventMessage<E> {
fn from(event: E) -> Self {
Self { event }
}
}
impl<E> AsRef<E> for SharedEventMessage<E> {
fn as_ref(&self) -> &E {
&self.event
}
}