#![deny(
missing_docs,
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces,
unused_qualifications,
clippy::unwrap_used
)]
#![allow(clippy::type_complexity)]
mod client;
mod error;
mod network_message;
mod server;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use bevy::{prelude::*, utils::Uuid};
pub use client::{AppNetworkClientMessage, NetworkClient};
use crossbeam_channel::{unbounded, Receiver, Sender};
use derive_more::{Deref, Display};
use error::NetworkError;
pub use network_message::{ClientMessage, NetworkMessage, ServerMessage};
use serde::{Deserialize, Serialize};
pub use server::{AppNetworkServerMessage, NetworkServer};
struct SyncChannel<T> {
pub(crate) sender: Sender<T>,
pub(crate) receiver: Receiver<T>,
}
impl<T> SyncChannel<T> {
fn new() -> Self {
let (sender, receiver) = unbounded();
SyncChannel { sender, receiver }
}
}
#[derive(Hash, PartialEq, Eq, Clone, Copy, Display, Debug)]
#[display(fmt = "Connection from {} with ID={}", addr, uuid)]
pub struct ConnectionId {
uuid: Uuid,
addr: SocketAddr,
}
impl ConnectionId {
pub fn address(&self) -> SocketAddr {
self.addr
}
pub(crate) fn server(addr: Option<SocketAddr>) -> ConnectionId {
ConnectionId {
uuid: Uuid::nil(),
addr: addr.unwrap_or_else(|| SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)),
}
}
pub fn is_server(&self) -> bool {
self.uuid == Uuid::nil()
}
}
#[derive(Serialize, Deserialize)]
struct NetworkPacket {
kind: String,
data: Box<dyn NetworkMessage>,
}
impl std::fmt::Debug for NetworkPacket {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("NetworkPacket")
.field("kind", &self.kind)
.finish()
}
}
#[derive(Debug)]
pub enum ServerNetworkEvent {
Connected(ConnectionId),
Disconnected(ConnectionId),
Error(NetworkError),
}
#[derive(Debug)]
pub enum ClientNetworkEvent {
Connected,
Disconnected,
Error(NetworkError),
}
#[derive(Debug, Deref)]
pub struct NetworkData<T> {
source: ConnectionId,
#[deref]
inner: T,
}
impl<T> NetworkData<T> {
pub(crate) fn new(source: ConnectionId, inner: T) -> Self {
Self { source, inner }
}
pub fn source(&self) -> ConnectionId {
self.source
}
pub fn into_inner(self) -> T {
self.inner
}
}
#[derive(Clone, Debug)]
#[allow(missing_copy_implementations)]
pub struct NetworkSettings {
pub max_packet_length: usize,
}
impl Default for NetworkSettings {
fn default() -> Self {
NetworkSettings {
max_packet_length: 10 * 1024 * 1024,
}
}
}
#[derive(Default, Copy, Clone, Debug)]
pub struct ServerPlugin;
impl Plugin for ServerPlugin {
fn build(&self, app: &mut AppBuilder) {
app.insert_resource(server::NetworkServer::new());
app.add_event::<ServerNetworkEvent>();
app.init_resource::<NetworkSettings>();
app.add_system_to_stage(
CoreStage::PreUpdate,
server::handle_new_incoming_connections.system(),
);
}
}
#[derive(Default, Copy, Clone, Debug)]
pub struct ClientPlugin;
impl Plugin for ClientPlugin {
fn build(&self, app: &mut AppBuilder) {
app.insert_resource(client::NetworkClient::new());
app.add_event::<ClientNetworkEvent>();
app.init_resource::<NetworkSettings>();
app.add_system_to_stage(
CoreStage::PreUpdate,
client::send_client_network_events.system(),
);
app.add_system_to_stage(
CoreStage::PreUpdate,
client::handle_connection_event.system(),
);
}
}