diff --git a/bevy_renet/Cargo.toml b/bevy_renet/Cargo.toml index 667badd7..0285610f 100644 --- a/bevy_renet/Cargo.toml +++ b/bevy_renet/Cargo.toml @@ -13,10 +13,12 @@ version = "0.0.9" [features] default = ["transport"] transport = ["renet/transport"] +steam = ["renet_steam"] [dependencies] bevy = {version = "0.11", default-features = false} renet = {path = "../renet", version = "0.0.13", features = ["bevy"]} +renet_steam = { path = "../renet_steam", version = "0.0.1", features = [ "bevy" ], optional = true } [dev-dependencies] bevy = {version = "0.11", default-features = false, features = ["bevy_core_pipeline", "bevy_render", "bevy_asset", "bevy_pbr", "x11", "tonemapping_luts", "ktx2", "zstd"]} diff --git a/bevy_renet/examples/simple.rs b/bevy_renet/examples/simple.rs index 2b314c34..08859933 100644 --- a/bevy_renet/examples/simple.rs +++ b/bevy_renet/examples/simple.rs @@ -44,7 +44,6 @@ enum ServerMessages { fn new_renet_client() -> (RenetClient, NetcodeClientTransport) { let client = RenetClient::new(ConnectionConfig::default()); - let server_addr = "127.0.0.1:5000".parse().unwrap(); let socket = UdpSocket::bind("127.0.0.1:0").unwrap(); let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); diff --git a/bevy_renet/src/lib.rs b/bevy_renet/src/lib.rs index 992fd858..3fe2831b 100644 --- a/bevy_renet/src/lib.rs +++ b/bevy_renet/src/lib.rs @@ -6,6 +6,10 @@ use renet::{RenetClient, RenetServer, ServerEvent}; #[cfg(feature = "transport")] pub mod transport; + +#[cfg(feature = "steam")] +pub mod steam; + pub struct RenetServerPlugin; pub struct RenetClientPlugin; diff --git a/bevy_renet/src/steam.rs b/bevy_renet/src/steam.rs new file mode 100644 index 00000000..04da1720 --- /dev/null +++ b/bevy_renet/src/steam.rs @@ -0,0 +1,138 @@ +use bevy::{app::AppExit, prelude::*}; +use renet::{RenetClient, RenetServer}; +use renet_steam::steamworks::SteamError; + +use crate::{RenetClientPlugin, RenetServerPlugin}; + +pub use renet_steam::{SteamClientTransport, SteamServerTransport}; + +pub struct SteamServerPlugin; + +pub struct SteamClientPlugin; + +#[derive(Debug, Event)] +pub struct SteamNetError(pub SteamError); + +impl Plugin for SteamServerPlugin { + fn build(&self, app: &mut App) { + app.add_systems( + PreUpdate, + Self::update_system + .run_if(resource_exists::()) + .run_if(resource_exists::()) + .after(RenetServerPlugin::update_system), + ); + + app.add_systems( + PostUpdate, + (Self::send_packets, Self::disconnect_on_exit) + .run_if(resource_exists::()) + .run_if(resource_exists::()), + ); + } +} + +impl SteamServerPlugin { + pub fn update_system(mut transport: ResMut, mut server: ResMut) { + transport.update(&mut server); + } + + pub fn send_packets(mut transport: ResMut, mut server: ResMut) { + transport.send_packets(&mut server); + } + + pub fn disconnect_on_exit(exit: EventReader, mut transport: ResMut, mut server: ResMut) { + if !exit.is_empty() { + transport.disconnect_all(&mut server, false); + } + } +} + +impl Plugin for SteamClientPlugin { + fn build(&self, app: &mut App) { + app.add_event::(); + + app.add_systems( + PreUpdate, + Self::update_system + .run_if(resource_exists::()) + .run_if(resource_exists::()) + .after(RenetClientPlugin::update_system), + ); + app.add_systems( + PostUpdate, + (Self::send_packets, Self::disconnect_on_exit) + .run_if(resource_exists::()) + .run_if(resource_exists::()), + ); + } +} + +impl SteamClientPlugin { + pub fn update_system(mut transport: ResMut, mut client: ResMut) { + transport.update(&mut client); + } + + pub fn send_packets( + mut transport: ResMut, + mut client: ResMut, + mut transport_errors: EventWriter, + ) { + if let Err(e) = transport.send_packets(&mut client) { + transport_errors.send(SteamNetError(e)); + } + } + + fn disconnect_on_exit(exit: EventReader, mut transport: ResMut) { + if !exit.is_empty() && !transport.is_disconnected() { + transport.disconnect(false); + } + } +} + +pub fn client_connected() -> impl FnMut(Option>) -> bool { + |transport| match transport { + Some(transport) => transport.is_connected(), + None => false, + } +} + +pub fn client_diconnected() -> impl FnMut(Option>) -> bool { + |transport| match transport { + Some(transport) => transport.is_disconnected(), + None => true, + } +} + +pub fn client_connecting() -> impl FnMut(Option>) -> bool { + |transport| match transport { + Some(transport) => transport.is_connecting(), + None => false, + } +} + +pub fn client_just_connected() -> impl FnMut(Local, Option>) -> bool { + |mut last_connected: Local, transport| { + let Some(transport) = transport else { + return false; + }; + + let connected = transport.is_connected(); + let just_connected = !*last_connected && connected; + *last_connected = connected; + just_connected + } +} + +pub fn client_just_diconnected() -> impl FnMut(Local, Option>) -> bool { + |mut last_disconnected: Local, transport| { + let Some(transport) = transport else { + return true; + }; + + let disconnected = transport.is_disconnected(); + let just_disconnected = !*last_disconnected && disconnected; + *last_disconnected = disconnected; + just_disconnected + } +} diff --git a/renet_steam/examples/echo.rs b/renet_steam/examples/echo.rs index b7c928e9..74bafbac 100644 --- a/renet_steam/examples/echo.rs +++ b/renet_steam/examples/echo.rs @@ -95,7 +95,7 @@ fn run_client(steam_client: Client, single: SingleClient, server_ last_updated = now; client.update(duration); - transport.update(duration, &mut client); + transport.update(&mut client); if transport.is_connected() { match stdin_channel.try_recv() { diff --git a/renet_steam/src/client.rs b/renet_steam/src/client.rs index ba2caefe..445cf82d 100644 --- a/renet_steam/src/client.rs +++ b/renet_steam/src/client.rs @@ -1,5 +1,3 @@ -use std::time::Duration; - use super::MAX_MESSAGE_BATCH_SIZE; use renet::RenetClient; use steamworks::{ @@ -11,7 +9,7 @@ use steamworks::{ #[cfg_attr(feature = "bevy", derive(bevy_ecs::system::Resource))] pub struct SteamClientTransport { networking_sockets: NetworkingSockets, - connection: NetConnection, + connection: Option>, } impl SteamClientTransport { @@ -24,7 +22,7 @@ impl SteamClientTransport { .connect_p2p(NetworkingIdentity::new_steam_id(*steam_id), 0, options)?; Ok(Self { networking_sockets, - connection, + connection: Some(connection), }) } @@ -47,17 +45,26 @@ impl SteamClientTransport { } pub fn connection_state(&self) -> NetworkingConnectionState { - if let Ok(info) = self.networking_sockets.get_connection_info(&self.connection) { - if let Ok(state) = info.state() { - return state; - } - } + let Some(connection) = &self.connection else { + return NetworkingConnectionState::ClosedByPeer; + }; + + let Ok(info) = self.networking_sockets.get_connection_info(connection) else { + return NetworkingConnectionState::None; + }; - NetworkingConnectionState::None + match info.state() { + Ok(state) => state, + Err(_) => NetworkingConnectionState::None, + } } pub fn disconnect_reason(&self) -> Option { - if let Ok(info) = self.networking_sockets.get_connection_info(&self.connection) { + let Some(connection) = &self.connection else { + return Some(NetConnectionEnd::AppGeneric); + }; + + if let Ok(info) = self.networking_sockets.get_connection_info(connection) { return info.end_reason(); } @@ -68,20 +75,22 @@ impl SteamClientTransport { steam_client.user().steam_id().raw() } - pub fn disconnect(self, send_last_packets: bool) { - self.connection.close( - steamworks::networking_types::NetConnectionEnd::AppGeneric, - Some("Disconnecting from server"), - send_last_packets, - ); + pub fn disconnect(&mut self, send_last_packets: bool) { + if let Some(connection) = self.connection.take() { + connection.close(NetConnectionEnd::AppGeneric, Some("Disconnecting from server"), send_last_packets); + } } - pub fn update(&mut self, _duration: Duration, client: &mut RenetClient) { - if !self.is_connected() { + pub fn update(&mut self, client: &mut RenetClient) { + if self.is_disconnected() { + if self.connection.is_some() { + self.disconnect(false); + } return; }; - let messages = self.connection.receive_messages(MAX_MESSAGE_BATCH_SIZE); + let connection = self.connection.as_mut().unwrap(); + let messages = connection.receive_messages(MAX_MESSAGE_BATCH_SIZE); messages.iter().for_each(|message| { client.process_packet(message.data()); }); @@ -96,11 +105,12 @@ impl SteamClientTransport { return Ok(()); } + let connection = self.connection.as_mut().unwrap(); let packets = client.get_packets_to_send(); for packet in packets { - self.connection.send_message(&packet, SendFlags::UNRELIABLE)?; + connection.send_message(&packet, SendFlags::UNRELIABLE)?; } - self.connection.flush_messages() + connection.flush_messages() } } diff --git a/renet_steam/src/lib.rs b/renet_steam/src/lib.rs index bdf2d01c..1aa34701 100644 --- a/renet_steam/src/lib.rs +++ b/renet_steam/src/lib.rs @@ -5,3 +5,6 @@ mod server; pub use client::SteamClientTransport; pub use server::SteamServerTransport; + +#[doc(hidden)] +pub use steamworks; \ No newline at end of file