generated from tipragot/rust
This commit is contained in:
parent
9f9ac40a13
commit
fb2850deef
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -403,8 +403,10 @@ dependencies = [
|
|||
"aes-gcm",
|
||||
"base64 0.21.7",
|
||||
"bevy",
|
||||
"bincode",
|
||||
"igd",
|
||||
"local-ip-address",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1159,6 +1161,15 @@ dependencies = [
|
|||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.69.4"
|
||||
|
|
|
@ -17,3 +17,5 @@ aes-gcm = "0.10.3"
|
|||
base64 = "0.21.7"
|
||||
igd = "0.12.1"
|
||||
bevy = "0.12.1"
|
||||
serde = "1.0.196"
|
||||
bincode = "1.3.3"
|
||||
|
|
|
@ -50,11 +50,15 @@ use std::sync::Mutex;
|
|||
use aes_gcm::aead::{Aead, AeadCore, KeyInit, OsRng};
|
||||
use aes_gcm::{Aes128Gcm, Key, Nonce};
|
||||
use base64::prelude::*;
|
||||
use bevy::ecs::schedule::SystemConfigs;
|
||||
use bevy::prelude::*;
|
||||
use igd::{Gateway, PortMappingProtocol};
|
||||
use local_ip_address::local_ip;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
|
||||
/// A non-blocking tcp connection.
|
||||
#[derive(Component, Resource)]
|
||||
pub struct Connection {
|
||||
/// The underlying [TcpStream] used for the connection.
|
||||
stream: TcpStream,
|
||||
|
@ -231,7 +235,7 @@ impl Connection {
|
|||
}
|
||||
|
||||
// Returning success.
|
||||
Ok(self.send_buffers.is_empty())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Receives a byte block from the connection.
|
||||
|
@ -375,6 +379,7 @@ impl Connection {
|
|||
}
|
||||
|
||||
/// A non-blocking tcp listener.
|
||||
#[derive(Resource)]
|
||||
pub struct Listener(TcpListener, Gateway, SocketAddrV4, Key<Aes128Gcm>);
|
||||
|
||||
impl Listener {
|
||||
|
@ -441,5 +446,242 @@ impl Drop for Listener {
|
|||
#[derive(Resource, Default)]
|
||||
struct LastEventId(u16);
|
||||
|
||||
/// An extension trait for the bevy [App] to allow registering network events.
|
||||
pub trait NetworkAppExt {}
|
||||
/// An utility function that sends an [Event] to a [Connection].
|
||||
fn send_event<T: Event + Serialize + DeserializeOwned>(
|
||||
connection: &Connection,
|
||||
event_id: u16,
|
||||
event: &T,
|
||||
) {
|
||||
// Serializing the event.
|
||||
let message = match bincode::serialize(event) {
|
||||
Ok(message) => message,
|
||||
Err(e) => {
|
||||
error!("failed to serialize event: {e}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// Sending the event.
|
||||
if let Err(e) = connection.send(&message, event_id) {
|
||||
info!("failed to send event: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
/// An [Event] received from the server on the client.
|
||||
#[derive(Event)]
|
||||
pub struct ServerEvent<T: Event + Serialize + DeserializeOwned>(pub T);
|
||||
|
||||
impl<T: Event + Serialize + DeserializeOwned> ServerEvent<T> {
|
||||
/// Returns a system that receives the events from the server.
|
||||
pub fn receive(event_id: u16) -> SystemConfigs {
|
||||
(move |connection: Res<Connection>, mut events: EventWriter<Self>| {
|
||||
// Get all received messages.
|
||||
let messages = match connection.receive(event_id) {
|
||||
Ok(messages) => messages,
|
||||
Err(e) => {
|
||||
error!("failed to receive event: {e}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// Send the events in the world.
|
||||
for message in messages {
|
||||
// Deserializing the message.
|
||||
let event: T = match bincode::deserialize(&message) {
|
||||
Ok(event) => event,
|
||||
Err(e) => {
|
||||
error!("failed to deserialize event: {e}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// Sending the event.
|
||||
events.send(Self(event));
|
||||
}
|
||||
})
|
||||
.run_if(resource_exists::<Connection>())
|
||||
}
|
||||
}
|
||||
|
||||
/// An [Event] received from a specific client on the server.
|
||||
#[derive(Event)]
|
||||
pub struct ClientEvent<T: Event + Serialize + DeserializeOwned>(pub Entity, pub T);
|
||||
|
||||
impl<T: Event + Serialize + DeserializeOwned> ClientEvent<T> {
|
||||
/// Returns a system that receives the events from the clients on the
|
||||
/// server.
|
||||
pub fn receive(event_id: u16) -> impl Fn(Query<(Entity, &Connection)>, EventWriter<Self>) {
|
||||
move |connections: Query<(Entity, &Connection)>, mut events: EventWriter<Self>| {
|
||||
for (entity, connection) in connections.iter() {
|
||||
// Get all received messages.
|
||||
let messages = match connection.receive(event_id) {
|
||||
Ok(messages) => messages,
|
||||
Err(e) => {
|
||||
error!("failed to receive event: {e}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// Send the events in the world.
|
||||
for message in messages {
|
||||
// Deserializing the message.
|
||||
let event: T = match bincode::deserialize(&message) {
|
||||
Ok(event) => event,
|
||||
Err(e) => {
|
||||
error!("failed to deserialize event: {e}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// Sending the event.
|
||||
events.send(Self(entity, event));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An [Event] used to send a network event to all the connected clients on the
|
||||
/// server.
|
||||
#[derive(Event)]
|
||||
pub struct SendAll<T: Event + Serialize + DeserializeOwned>(pub T);
|
||||
|
||||
impl<T: Event + Serialize + DeserializeOwned> SendAll<T> {
|
||||
/// Returns a system that sends the events to all the connected clients on
|
||||
/// the server.
|
||||
pub fn send(event_id: u16) -> impl Fn(EventReader<Self>, Query<&Connection>) {
|
||||
move |mut events: EventReader<Self>, connections: Query<&Connection>| {
|
||||
for event in events.read() {
|
||||
for connection in connections.iter() {
|
||||
send_event(connection, event_id, &event.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An [Event] used to send a network event to a specific client on the server.
|
||||
#[derive(Event)]
|
||||
pub struct SendTo<T: Event + Serialize + DeserializeOwned>(pub Entity, pub T);
|
||||
|
||||
impl<T: Event + Serialize + DeserializeOwned> SendTo<T> {
|
||||
/// Returns a system that sends the events to a specific client on the
|
||||
/// server.
|
||||
pub fn send(event_id: u16) -> impl Fn(EventReader<Self>, Query<&Connection>) {
|
||||
move |mut events: EventReader<Self>, connections: Query<&Connection>| {
|
||||
for event in events.read() {
|
||||
match connections.get(event.0) {
|
||||
Ok(connection) => send_event(connection, event_id, &event.1),
|
||||
Err(e) => error!("tried to send event to non-existent connection: {e}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An [Event] used to send an [Event] from a client to the server.
|
||||
#[derive(Event)]
|
||||
pub struct SendToServer<T: Event + Serialize + DeserializeOwned>(pub T);
|
||||
|
||||
impl<T: Event + Serialize + DeserializeOwned> SendToServer<T> {
|
||||
/// Returns a system that sends the events from a client to the server.
|
||||
pub fn send(event_id: u16) -> SystemConfigs {
|
||||
(move |mut events: EventReader<Self>, connection: Option<Res<Connection>>| {
|
||||
for event in events.read() {
|
||||
if let Some(connection) = connection.as_ref() {
|
||||
send_event(connection, event_id, &event.0);
|
||||
} else {
|
||||
error!("tried to send event to non-existent connection");
|
||||
}
|
||||
}
|
||||
})
|
||||
.run_if(resource_exists::<Connection>())
|
||||
}
|
||||
}
|
||||
|
||||
/// A plugin that manages network [Connection]s.
|
||||
pub struct NetworkPlugin;
|
||||
|
||||
impl NetworkPlugin {
|
||||
/// A system that update the client [Connection]s on the server.
|
||||
fn update_client_connections(
|
||||
mut commands: Commands,
|
||||
mut connections: Query<(Entity, &mut Connection)>,
|
||||
) {
|
||||
for (entity, mut connection) in &mut connections {
|
||||
if let Err(e) = connection.update() {
|
||||
info!("closing client connection: {e}");
|
||||
commands.entity(entity).remove::<Connection>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A system that update the server [Connection] on the client.
|
||||
fn update_server_connection(mut commands: Commands, mut connection: ResMut<Connection>) {
|
||||
if let Err(e) = connection.update() {
|
||||
info!("closing server connection: {e}");
|
||||
commands.remove_resource::<Connection>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Plugin for NetworkPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_systems(
|
||||
Last,
|
||||
(
|
||||
Self::update_client_connections,
|
||||
Self::update_server_connection.run_if(resource_exists::<Connection>()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// An extension trait for a bevy [App] that adds network related features.
|
||||
pub trait NetworkAppExt {
|
||||
/// Setup the application to manage network events of type `T`.
|
||||
///
|
||||
/// This will automatically define multiple events:
|
||||
/// - [ServerEvent]: an [Event] received from the server on the client.
|
||||
/// - [ClientEvent]: an [Event] received from a specific client on the
|
||||
/// server.
|
||||
/// - [SendAll]: used to send a network event to all the connected clients
|
||||
/// on the server.
|
||||
/// - [SendTo]: used to send a network event to a specific client on the
|
||||
/// server.
|
||||
/// - [SendToServer]: used to send an [Event] from a client to the server.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bevnet::NetworkAppExt;
|
||||
/// use bevy::prelude::*;
|
||||
/// use serde::{Deserialize, Serialize};
|
||||
///
|
||||
/// #[derive(Event, Deserialize, Serialize)]
|
||||
/// struct MyEvent;
|
||||
///
|
||||
/// let mut app = App::new();
|
||||
/// app.add_network_event::<MyEvent>();
|
||||
/// ```
|
||||
fn add_network_event<T: Event + DeserializeOwned + Serialize>(&mut self) -> &mut Self;
|
||||
}
|
||||
|
||||
impl NetworkAppExt for App {
|
||||
fn add_network_event<T: Event + DeserializeOwned + Serialize>(&mut self) -> &mut Self {
|
||||
let mut event_id = self.world.get_resource_or_insert_with(LastEventId::default);
|
||||
event_id.0 += 1;
|
||||
let event_id = event_id.0;
|
||||
|
||||
self.add_event::<ServerEvent<T>>()
|
||||
.add_systems(PostUpdate, ServerEvent::<T>::receive(event_id))
|
||||
.add_event::<ClientEvent<T>>()
|
||||
.add_systems(PostUpdate, ClientEvent::<T>::receive(event_id))
|
||||
.add_event::<SendAll<T>>()
|
||||
.add_systems(PreUpdate, SendAll::<T>::send(event_id))
|
||||
.add_event::<SendTo<T>>()
|
||||
.add_systems(PreUpdate, SendTo::<T>::send(event_id))
|
||||
.add_event::<SendToServer<T>>()
|
||||
.add_systems(PreUpdate, SendToServer::<T>::send(event_id))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue