use core::any::TypeId;
use bevy::{ecs::entity::MapEntities, prelude::*, ptr::PtrMut};
use log::debug;
use serde::{Serialize, de::DeserializeOwned};
use super::{
client_message::{self, ClientMessage},
ctx::{ClientSendCtx, ServerReceiveCtx},
message_fns::{DeserializeFn, MessageFns, SerializeFn},
registry::RemoteMessageRegistry,
};
use crate::prelude::*;
pub trait ClientEventAppExt {
fn add_client_event<E: Event + Serialize + DeserializeOwned>(
&mut self,
channel: Channel,
) -> &mut Self {
self.add_client_event_with(
channel,
client_message::default_serialize::<E>,
client_message::default_deserialize::<E>,
)
}
fn add_mapped_client_event<E: Event + Serialize + DeserializeOwned + MapEntities + Clone>(
&mut self,
channel: Channel,
) -> &mut Self {
self.add_client_event_with(
channel,
client_message::default_serialize_mapped::<E>,
client_message::default_deserialize::<E>,
)
}
fn add_client_event_with<E: Event>(
&mut self,
channel: Channel,
serialize: SerializeFn<ClientSendCtx, E>,
deserialize: DeserializeFn<ServerReceiveCtx, E>,
) -> &mut Self;
}
impl ClientEventAppExt for App {
fn add_client_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_client_event::<E>();
let fns = MessageFns::new(serialize, deserialize).with_convert::<ClientMessageEvent<E>>();
let event = ClientEvent::new(self, channel, fns);
let mut registry = self.world_mut().resource_mut::<RemoteMessageRegistry>();
registry.register_client_event(event);
self
}
}
pub(crate) struct ClientEvent {
type_id: TypeId,
message: ClientMessage,
trigger: TriggerFn,
}
impl ClientEvent {
fn new<E: Event>(
app: &mut App,
channel: Channel,
fns: MessageFns<ClientSendCtx, ServerReceiveCtx, ClientMessageEvent<E>, E>,
) -> Self {
Self {
type_id: TypeId::of::<E>(),
message: ClientMessage::new(app, channel, fns),
trigger: Self::trigger_typed::<E>,
}
}
pub(crate) unsafe fn trigger(&self, commands: &mut Commands, from_messages: PtrMut) {
unsafe { (self.trigger)(commands, from_messages) }
}
unsafe fn trigger_typed<E: Event>(commands: &mut Commands, from_messages: PtrMut) {
let from_messages: &mut Messages<FromClient<ClientMessageEvent<E>>> =
unsafe { from_messages.deref_mut() };
for FromClient { client_id, message } in from_messages.drain() {
debug!(
"triggering `{}` from `{client_id}`",
ShortName::of::<FromClient<E>>()
);
commands.trigger(FromClient {
client_id,
message: message.event,
});
}
}
pub(super) fn type_id(&self) -> TypeId {
self.type_id
}
pub(crate) fn message(&self) -> &ClientMessage {
&self.message
}
}
type TriggerFn = unsafe fn(&mut Commands, PtrMut);
pub trait ClientTriggerExt {
fn client_trigger(&mut self, event: impl Event);
}
impl ClientTriggerExt for Commands<'_, '_> {
fn client_trigger(&mut self, event: impl Event) {
self.write_message(ClientMessageEvent { event });
}
}
impl ClientTriggerExt for World {
fn client_trigger(&mut self, event: impl Event) {
self.write_message(ClientMessageEvent { event });
}
}
#[derive(Message)]
struct ClientMessageEvent<E> {
event: E,
}
impl<E> From<E> for ClientMessageEvent<E> {
fn from(event: E) -> Self {
Self { event }
}
}
impl<E> AsRef<E> for ClientMessageEvent<E> {
fn as_ref(&self) -> &E {
&self.event
}
}