use std::marker::PhantomData;
use bevy::prelude::*;
use crate::Message;
use super::{ClientId, RecvError, ServerEvent, ServerTransport, SessionError};
#[derive(Debug, derivative::Derivative)]
#[derivative(Default)]
pub struct ServerTransportPlugin<C2S, S2C, T> {
_phantom_c2s: PhantomData<C2S>,
_phantom_s2c: PhantomData<S2C>,
_phantom_t: PhantomData<T>,
}
impl<C2S, S2C, T> Plugin for ServerTransportPlugin<C2S, S2C, T>
where
C2S: Message,
S2C: Message + Clone,
T: ServerTransport<C2S, S2C> + Resource,
{
fn build(&self, app: &mut App) {
app.add_event::<RemoteClientConnecting>()
.add_event::<RemoteClientConnected>()
.add_event::<FromClient<C2S>>()
.add_event::<RemoteClientDisconnected>()
.add_event::<ToClient<S2C>>()
.add_event::<DisconnectClient>()
.configure_set(
PreUpdate,
ServerTransportSet::Recv.run_if(resource_exists::<T>()),
)
.configure_set(
PostUpdate,
ServerTransportSet::Send.run_if(resource_exists::<T>()),
)
.add_systems(
PreUpdate,
recv::<C2S, S2C, T>.in_set(ServerTransportSet::Recv),
)
.add_systems(
PostUpdate,
send::<C2S, S2C, T>.in_set(ServerTransportSet::Send),
);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, SystemSet)]
pub enum ServerTransportSet {
Recv,
Send,
}
#[derive(Debug, Clone, Event)]
pub struct RemoteClientConnecting {
pub client: ClientId,
}
#[derive(Debug, Clone, Event)]
pub struct RemoteClientConnected {
pub client: ClientId,
}
#[derive(Debug, Clone, Event)]
pub struct FromClient<C2S> {
pub client: ClientId,
pub msg: C2S,
}
#[derive(Debug, Event)]
pub struct RemoteClientDisconnected {
pub client: ClientId,
pub reason: SessionError,
}
#[derive(Debug, Event)]
pub struct ToClient<S2C> {
pub client: ClientId,
pub msg: S2C,
}
#[derive(Debug, Clone, Event)]
pub struct DisconnectClient {
pub client: ClientId,
}
fn recv<C2S, S2C, T>(
mut commands: Commands,
mut server: ResMut<T>,
mut connecting: EventWriter<RemoteClientConnecting>,
mut connected: EventWriter<RemoteClientConnected>,
mut from_client: EventWriter<FromClient<C2S>>,
mut disconnected: EventWriter<RemoteClientDisconnected>,
) where
C2S: Message,
S2C: Message,
T: ServerTransport<C2S, S2C> + Resource,
{
loop {
match server.recv() {
Ok(ServerEvent::Connecting { client }) => {
connecting.send(RemoteClientConnecting { client });
}
Ok(ServerEvent::Connected { client }) => {
connected.send(RemoteClientConnected { client });
}
Ok(ServerEvent::Recv { client, msg }) => {
from_client.send(FromClient { client, msg });
}
Ok(ServerEvent::Disconnected { client, reason }) => {
disconnected.send(RemoteClientDisconnected { client, reason });
}
Err(RecvError::Empty) => break,
Err(RecvError::Closed) => {
commands.remove_resource::<T>();
break;
}
}
}
}
fn send<C2S, S2C, T>(
mut server: ResMut<T>,
mut to_client: EventReader<ToClient<S2C>>,
mut disconnect: EventReader<DisconnectClient>,
) where
C2S: Message,
S2C: Message + Clone,
T: ServerTransport<C2S, S2C> + Resource,
{
for ToClient { client, msg } in to_client.iter() {
server.send(*client, msg.clone());
}
for DisconnectClient { client } in disconnect.iter() {
server.disconnect(*client);
}
}