From 84cde7b14c00a1cb82f656b488ac88c24f00e1b8 Mon Sep 17 00:00:00 2001 From: koe Date: Sat, 3 Feb 2024 17:40:19 -0600 Subject: [PATCH] remove steam transport --- Cargo.toml | 1 - bevy_renet/Cargo.toml | 2 - bevy_renet/src/lib.rs | 3 - bevy_renet/src/steam.rs | 107 -------------------- demo_bevy/Cargo.toml | 3 - demo_bevy/README.md | 6 -- demo_bevy/src/bin/client.rs | 44 -------- demo_bevy/src/bin/server.rs | 31 ------ deny.toml | 5 - renet_steam/Cargo.toml | 24 ----- renet_steam/README.md | 3 - renet_steam/examples/echo.rs | 188 ----------------------------------- renet_steam/src/client.rs | 157 ----------------------------- renet_steam/src/lib.rs | 10 -- renet_steam/src/server.rs | 174 -------------------------------- 15 files changed, 758 deletions(-) delete mode 100644 bevy_renet/src/steam.rs delete mode 100644 renet_steam/Cargo.toml delete mode 100644 renet_steam/README.md delete mode 100644 renet_steam/examples/echo.rs delete mode 100644 renet_steam/src/client.rs delete mode 100644 renet_steam/src/lib.rs delete mode 100644 renet_steam/src/server.rs diff --git a/Cargo.toml b/Cargo.toml index 4ac46c75..a01bc2b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,5 @@ members = [ "renetcode", "bevy_renet", "renet_visualizer", - "renet_steam", ] resolver = "2" diff --git a/bevy_renet/Cargo.toml b/bevy_renet/Cargo.toml index 9fc703cc..be11d518 100644 --- a/bevy_renet/Cargo.toml +++ b/bevy_renet/Cargo.toml @@ -14,7 +14,6 @@ version = "0.0.10" default = ["transport"] serde = ["renet/serde"] transport = ["renet/transport"] -steam = ["renet_steam"] [[example]] name = "simple" @@ -23,7 +22,6 @@ required-features = ["serde", "transport"] [dependencies] bevy = {version = "0.12", default-features = false} renet = {path = "../renet", version = "0.0.14", default-features=false, features = ["bevy"]} -renet_steam = { path = "../renet_steam", version = "0.0.1", features = [ "bevy" ], optional = true } [dev-dependencies] bevy = {version = "0.12", default-features = false, features = ["bevy_core_pipeline", "bevy_render", "bevy_asset", "bevy_pbr", "x11", "tonemapping_luts", "ktx2", "zstd"]} diff --git a/bevy_renet/src/lib.rs b/bevy_renet/src/lib.rs index d76b1103..f854b4a1 100644 --- a/bevy_renet/src/lib.rs +++ b/bevy_renet/src/lib.rs @@ -7,9 +7,6 @@ use renet::{RenetClient, RenetServer, ServerEvent}; #[cfg(feature = "transport")] pub mod transport; -#[cfg(feature = "steam")] -pub mod steam; - /// This system set is where all transports receive messages /// /// If you want to ensure data has arrived in the [`RenetClient`] or [`RenetServer`], then schedule your diff --git a/bevy_renet/src/steam.rs b/bevy_renet/src/steam.rs deleted file mode 100644 index d9b08efa..00000000 --- a/bevy_renet/src/steam.rs +++ /dev/null @@ -1,107 +0,0 @@ -use bevy::{app::AppExit, prelude::*}; -use renet::{RenetClient, RenetServer}; -use renet_steam::steamworks::SteamError; - -use crate::{RenetClientPlugin, RenetReceive, RenetSend, RenetServerPlugin}; - -pub use renet_steam::{AccessPermission, SteamClientTransport, SteamServerConfig, SteamServerTransport}; - -pub struct SteamServerPlugin; - -pub struct SteamClientPlugin; - -#[derive(Debug, Event)] -pub struct SteamTransportError(pub SteamError); - -impl std::fmt::Display for SteamTransportError { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(fmt, "{}", self.0) - } -} - -impl Plugin for SteamServerPlugin { - fn build(&self, app: &mut App) { - app.add_systems( - PreUpdate, - Self::update_system - .in_set(RenetReceive) - .run_if(resource_exists::()) - .after(RenetServerPlugin::update_system) - .before(RenetServerPlugin::emit_server_events_system), - ); - - app.add_systems( - PostUpdate, - (Self::send_packets.in_set(RenetSend), Self::disconnect_on_exit).run_if(resource_exists::()), - ); - } -} - -impl SteamServerPlugin { - fn update_system(mut transport: Option>, mut server: ResMut) { - if let Some(transport) = transport.as_mut() { - transport.update(&mut server); - } - } - - fn send_packets(mut transport: Option>, mut server: ResMut) { - if let Some(transport) = transport.as_mut() { - transport.send_packets(&mut server); - } - } - - pub fn disconnect_on_exit( - exit: EventReader, - mut transport: Option>, - mut server: ResMut, - ) { - if let Some(transport) = transport.as_mut() { - 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 - .in_set(RenetReceive) - .run_if(resource_exists::()) - .run_if(resource_exists::()) - .after(RenetClientPlugin::update_system), - ); - app.add_systems( - PostUpdate, - (Self::send_packets.in_set(RenetSend), Self::disconnect_on_exit) - .run_if(resource_exists::()) - .run_if(resource_exists::()), - ); - } -} - -impl SteamClientPlugin { - fn update_system(mut transport: ResMut, mut client: ResMut) { - transport.update(&mut client); - } - - 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(SteamTransportError(e)); - } - } - - fn disconnect_on_exit(exit: EventReader, mut transport: ResMut) { - if !exit.is_empty() { - transport.disconnect(); - } - } -} diff --git a/demo_bevy/Cargo.toml b/demo_bevy/Cargo.toml index 224f6a6c..6ce09562 100644 --- a/demo_bevy/Cargo.toml +++ b/demo_bevy/Cargo.toml @@ -12,7 +12,6 @@ path = "src/bin/server.rs" [features] transport = ["bevy_renet/transport"] -steam = ["bevy_renet/steam", "steamworks"] [dependencies] bevy = {version = "0.12", default-features = false, features = ["bevy_core_pipeline", "bevy_render", "bevy_asset", "bevy_pbr", "x11", "tonemapping_luts", "ktx2", "zstd"]} @@ -23,5 +22,3 @@ bevy_egui = "0.23.0" renet_visualizer = { path = "../renet_visualizer", features = ["bevy"] } smooth-bevy-cameras = "0.10" fastrand = "2.0.0" - -steamworks = { git = "https://github.com/Noxime/steamworks-rs", rev = "a4dfe2a", optional = true } diff --git a/demo_bevy/README.md b/demo_bevy/README.md index d8cc7fa1..d5a3e26c 100644 --- a/demo_bevy/README.md +++ b/demo_bevy/README.md @@ -9,10 +9,4 @@ Running using the netcode transport: - server: `cargo run --bin server --features transport` - client: `cargo run --bin client --features transport` -Running using the steam transport: - -- server: `cargo run --bin server --features steam` -- client: `cargo run --bin client --features steam -- [HOST_STEAM_ID]` - - The `HOST_STEAM_ID` is printed in the console when the server is started - You can toogle [renet_visualizer](https://github.com/lucaspoffo/renet/tree/master/renet_visualizer) with `F1` in the client. diff --git a/demo_bevy/src/bin/client.rs b/demo_bevy/src/bin/client.rs index c742929e..f976a4e4 100644 --- a/demo_bevy/src/bin/client.rs +++ b/demo_bevy/src/bin/client.rs @@ -80,47 +80,6 @@ fn add_netcode_network(app: &mut App) { app.add_systems(Update, panic_on_error_system); } -#[cfg(feature = "steam")] -fn add_steam_network(app: &mut App) { - use bevy_renet::steam::{SteamClientPlugin, SteamClientTransport, SteamTransportError}; - use steamworks::{SingleClient, SteamId}; - - let (steam_client, single) = steamworks::Client::init_app(480).unwrap(); - - steam_client.networking_utils().init_relay_network_access(); - - let args: Vec = std::env::args().collect(); - let server_steam_id: u64 = args[1].parse().unwrap(); - let server_steam_id = SteamId::from_raw(server_steam_id); - - let client = RenetClient::new(connection_config()); - let transport = SteamClientTransport::new(&steam_client, &server_steam_id).unwrap(); - - app.add_plugins(SteamClientPlugin); - app.insert_resource(client); - app.insert_resource(transport); - app.insert_resource(CurrentClientId(steam_client.user().steam_id().raw())); - - app.configure_sets(Update, Connected.run_if(client_connected())); - - app.insert_non_send_resource(single); - fn steam_callbacks(client: NonSend) { - client.run_callbacks(); - } - - app.add_systems(PreUpdate, steam_callbacks); - - // If any error is found we just panic - #[allow(clippy::never_loop)] - fn panic_on_error_system(mut renet_error: EventReader) { - for e in renet_error.read() { - panic!("{}", e); - } - } - - app.add_systems(Update, panic_on_error_system); -} - fn main() { let mut app = App::new(); app.add_plugins(DefaultPlugins); @@ -133,9 +92,6 @@ fn main() { #[cfg(feature = "transport")] add_netcode_network(&mut app); - #[cfg(feature = "steam")] - add_steam_network(&mut app); - app.add_event::(); app.insert_resource(ClientLobby::default()); diff --git a/demo_bevy/src/bin/server.rs b/demo_bevy/src/bin/server.rs index c59ed34f..cab49dad 100644 --- a/demo_bevy/src/bin/server.rs +++ b/demo_bevy/src/bin/server.rs @@ -57,34 +57,6 @@ fn add_netcode_network(app: &mut App) { app.insert_resource(transport); } -#[cfg(feature = "steam")] -fn add_steam_network(app: &mut App) { - use bevy_renet::steam::{AccessPermission, SteamServerConfig, SteamServerPlugin, SteamServerTransport}; - use demo_bevy::connection_config; - use steamworks::SingleClient; - - let (steam_client, single) = steamworks::Client::init_app(480).unwrap(); - - let server: RenetServer = RenetServer::new(connection_config()); - - let steam_transport_config = SteamServerConfig { - max_clients: 10, - access_permission: AccessPermission::Public, - }; - let transport = SteamServerTransport::new(&steam_client, steam_transport_config).unwrap(); - - app.add_plugins(SteamServerPlugin); - app.insert_resource(server); - app.insert_non_send_resource(transport); - app.insert_non_send_resource(single); - - fn steam_callbacks(client: NonSend) { - client.run_callbacks(); - } - - app.add_systems(PreUpdate, steam_callbacks); -} - fn main() { let mut app = App::new(); app.add_plugins(DefaultPlugins); @@ -102,9 +74,6 @@ fn main() { #[cfg(feature = "transport")] add_netcode_network(&mut app); - #[cfg(feature = "steam")] - add_steam_network(&mut app); - app.add_systems( Update, ( diff --git a/deny.toml b/deny.toml index 3ca9278c..2a9272de 100644 --- a/deny.toml +++ b/deny.toml @@ -30,8 +30,3 @@ wildcards = "allow" [sources] unknown-registry = "deny" unknown-git = "deny" - -allow-git = [ - # Unreleased version for steamworks, need release with PR https://github.com/Noxime/steamworks-rs/pull/134 - "https://github.com/Noxime/steamworks-rs" -] diff --git a/renet_steam/Cargo.toml b/renet_steam/Cargo.toml deleted file mode 100644 index 9627dbfc..00000000 --- a/renet_steam/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "renet_steam" -version = "0.0.1" -keywords = ["gamedev", "networking", "transport"] -description = "steam transport for the renet crate: Server/Client network library for multiplayer games" -repository = "https://github.com/lucaspoffo/renet" -license = "MIT OR Apache-2.0" -readme = "README.md" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[features] -bevy = ["dep:bevy_ecs"] - -[dependencies] -renet = { path = "../renet" } -# its version 0.10 but we need to use the rev because of a missing feature -steamworks = { git = "https://github.com/Noxime/steamworks-rs", rev = "a4dfe2a" } -log = "0.4.19" -bevy_ecs = { version = "0.12", optional = true } - -[dev-dependencies] -env_logger = "0.10.0" diff --git a/renet_steam/README.md b/renet_steam/README.md deleted file mode 100644 index 894f8a45..00000000 --- a/renet_steam/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Renet Steam - -Transport layer for renet using the steamworks. \ No newline at end of file diff --git a/renet_steam/examples/echo.rs b/renet_steam/examples/echo.rs deleted file mode 100644 index be7f81ac..00000000 --- a/renet_steam/examples/echo.rs +++ /dev/null @@ -1,188 +0,0 @@ -use std::{ - sync::mpsc::{self, Receiver, TryRecvError}, - thread, - time::{Duration, Instant}, -}; - -use renet::{ConnectionConfig, DefaultChannel, RenetClient, RenetServer, ServerEvent}; -use renet_steam::{AccessPermission, SteamClientTransport, SteamServerConfig, SteamServerTransport}; -use steamworks::{Client, ClientManager, LobbyId, LobbyType, SingleClient, SteamId}; - -fn main() { - env_logger::init(); - let (steam_client, single) = Client::init_app(480).unwrap(); - steam_client.networking_utils().init_relay_network_access(); - - println!("Usage:"); - println!("\tclient [SERVER_STEAM_ID] [LOBBY_ID?]"); - println!("\tserver [lobby?]"); - - let args: Vec = std::env::args().collect(); - - let exec_type = &args[1]; - match exec_type.as_str() { - "client" => { - let server_steam_id: u64 = args[2].parse().unwrap(); - let mut lobby_id: Option = None; - if let Some(lobby) = args.get(3) { - let id: u64 = lobby.parse().unwrap(); - lobby_id = Some(LobbyId::from_raw(id)); - } - run_client(steam_client, single, SteamId::from_raw(server_steam_id), lobby_id); - } - "server" => { - let mut with_lobby = false; - if let Some(lobby) = args.get(2) { - with_lobby = lobby.as_str() == "lobby"; - } - run_server(steam_client, single, with_lobby); - } - _ => { - println!("Invalid argument, first one must be \"client\" or \"server\"."); - } - } -} - -fn run_server(steam_client: Client, single: SingleClient, with_lobby: bool) { - // Create lobby if necessary - let access_permission = if with_lobby { - let (sender_create_lobby, receiver_create_lobby) = mpsc::channel(); - steam_client.matchmaking().create_lobby(LobbyType::Public, 10, move |lobby| { - match lobby { - Ok(lobby) => { - sender_create_lobby.send(lobby).unwrap(); - } - Err(e) => panic!("Failed to create lobby: {e}"), - }; - }); - - loop { - single.run_callbacks(); - if let Ok(lobby) = receiver_create_lobby.try_recv() { - println!("Created lobby with id: {}", lobby.raw()); - break AccessPermission::InLobby(lobby); - } - thread::sleep(Duration::from_millis(20)); - } - } else { - AccessPermission::Public - }; - - let connection_config = ConnectionConfig::default(); - let mut server: RenetServer = RenetServer::new(connection_config); - let steam_transport_config = SteamServerConfig { - max_clients: 10, - access_permission, - }; - let mut transport = SteamServerTransport::new(&steam_client, steam_transport_config).unwrap(); - - let mut received_messages = vec![]; - let mut last_updated = Instant::now(); - - loop { - single.run_callbacks(); - let now = Instant::now(); - let duration = now - last_updated; - last_updated = now; - - server.update(duration); - transport.update(&mut server); - - received_messages.clear(); - - while let Some(event) = server.get_event() { - match event { - ServerEvent::ClientConnected { client_id } => { - println!("Client {} connected.", client_id) - } - ServerEvent::ClientDisconnected { client_id, reason } => { - println!("Client {} disconnected: {}", client_id, reason); - } - } - } - - for client_id in server.clients_id() { - while let Some(message) = server.receive_message(client_id, DefaultChannel::ReliableOrdered) { - let text = String::from_utf8(message.into()).unwrap(); - println!("Client {} sent text: {}", client_id, text); - let text = format!("{}: {}", client_id, text); - received_messages.push(text); - } - } - - for text in received_messages.iter() { - server.broadcast_message(DefaultChannel::ReliableOrdered, text.as_bytes().to_vec()); - } - - transport.send_packets(&mut server); - thread::sleep(Duration::from_millis(20)); - } -} - -fn run_client(steam_client: Client, single: SingleClient, server_steam_id: SteamId, lobby_id: Option) { - // Connect to lobby - if let Some(lobby_id) = lobby_id { - let (sender_join_lobby, receiver_join_lobby) = mpsc::channel(); - steam_client.matchmaking().join_lobby(lobby_id, move |lobby| { - match lobby { - Ok(lobby) => { - sender_join_lobby.send(lobby).unwrap(); - } - Err(e) => panic!("Failed to join lobby: {e:?}"), - }; - }); - - loop { - single.run_callbacks(); - if let Ok(lobby) = receiver_join_lobby.try_recv() { - println!("Joined lobby with id: {}", lobby.raw()); - break; - } - thread::sleep(Duration::from_millis(20)); - } - } - let connection_config = ConnectionConfig::default(); - let mut client = RenetClient::new(connection_config); - - let mut transport = SteamClientTransport::new(&steam_client, &server_steam_id).unwrap(); - let stdin_channel: Receiver = spawn_stdin_channel(); - - let mut last_updated = Instant::now(); - loop { - single.run_callbacks(); - let now = Instant::now(); - let duration = now - last_updated; - last_updated = now; - - client.update(duration); - transport.update(&mut client); - - if client.is_connected() { - match stdin_channel.try_recv() { - Ok(text) => { - client.send_message(DefaultChannel::ReliableOrdered, text.as_bytes().to_vec()); - } - Err(TryRecvError::Empty) => {} - Err(TryRecvError::Disconnected) => panic!("Channel disconnected"), - } - - while let Some(text) = client.receive_message(DefaultChannel::ReliableOrdered) { - let text = String::from_utf8(text.into()).unwrap(); - println!("{}", text); - } - } - - transport.send_packets(&mut client).unwrap(); - thread::sleep(Duration::from_millis(20)); - } -} - -fn spawn_stdin_channel() -> Receiver { - let (tx, rx) = mpsc::channel::(); - thread::spawn(move || loop { - let mut buffer = String::new(); - std::io::stdin().read_line(&mut buffer).unwrap(); - tx.send(buffer.trim_end().to_string()).unwrap(); - }); - rx -} diff --git a/renet_steam/src/client.rs b/renet_steam/src/client.rs deleted file mode 100644 index 2e9f58ec..00000000 --- a/renet_steam/src/client.rs +++ /dev/null @@ -1,157 +0,0 @@ -use super::MAX_MESSAGE_BATCH_SIZE; -use renet::RenetClient; -use steamworks::{ - networking_sockets::{InvalidHandle, NetConnection, NetworkingSockets}, - networking_types::{NetConnectionEnd, NetworkingConnectionState, NetworkingIdentity, SendFlags}, - ClientManager, SteamError, SteamId, -}; - -enum ConnectionState { - Connected { connection: NetConnection }, - Disconnected { end_reason: NetConnectionEnd }, -} - -#[cfg_attr(feature = "bevy", derive(bevy_ecs::system::Resource))] -pub struct SteamClientTransport { - networking_sockets: NetworkingSockets, - state: ConnectionState, -} - -impl SteamClientTransport { - pub fn new(client: &steamworks::Client, steam_id: &SteamId) -> Result { - let networking_sockets = client.networking_sockets(); - - let options = Vec::new(); - let connection = client - .networking_sockets() - .connect_p2p(NetworkingIdentity::new_steam_id(*steam_id), 0, options)?; - Ok(Self { - networking_sockets, - state: ConnectionState::Connected { connection }, - }) - } - - fn is_connected(&self) -> bool { - let status = self.connection_state(); - - status == NetworkingConnectionState::Connected - } - - fn is_disconnected(&self) -> bool { - let status = self.connection_state(); - status == NetworkingConnectionState::ClosedByPeer - || status == NetworkingConnectionState::ProblemDetectedLocally - || status == NetworkingConnectionState::None - } - - fn is_connecting(&self) -> bool { - let status = self.connection_state(); - status == NetworkingConnectionState::Connecting || status == NetworkingConnectionState::FindingRoute - } - - fn connection_state(&self) -> NetworkingConnectionState { - let connection = match &self.state { - ConnectionState::Connected { connection } => connection, - ConnectionState::Disconnected { .. } => { - return NetworkingConnectionState::None; - } - }; - - let Ok(info) = self.networking_sockets.get_connection_info(connection) else { - return NetworkingConnectionState::None; - }; - - match info.state() { - Ok(state) => state, - Err(_) => NetworkingConnectionState::None, - } - } - - pub fn disconnect_reason(&self) -> Option { - let connection = match &self.state { - ConnectionState::Connected { connection } => connection, - ConnectionState::Disconnected { end_reason, .. } => { - return Some(*end_reason); - } - }; - - if let Ok(info) = self.networking_sockets.get_connection_info(connection) { - return info.end_reason(); - } - - None - } - - pub fn client_id(&self, steam_client: &steamworks::Client) -> u64 { - steam_client.user().steam_id().raw() - } - - pub fn disconnect(&mut self) { - if matches!(self.state, ConnectionState::Disconnected { .. }) { - return; - } - - let disconnect_state = ConnectionState::Disconnected { - end_reason: NetConnectionEnd::AppGeneric, - }; - let old_state = std::mem::replace(&mut self.state, disconnect_state); - if let ConnectionState::Connected { connection } = old_state { - connection.close(NetConnectionEnd::AppGeneric, Some("Client disconnected"), false); - } - } - - pub fn update(&mut self, client: &mut RenetClient) { - if self.is_disconnected() { - // Mark the client as disconnected if an error occured in the transport layer - client.disconnect_due_to_transport(); - - if let ConnectionState::Connected { connection } = &self.state { - let end_reason = self - .networking_sockets - .get_connection_info(connection) - .map(|info| info.end_reason()) - .unwrap_or_default() - .unwrap_or(NetConnectionEnd::AppGeneric); - - self.state = ConnectionState::Disconnected { end_reason }; - } - - return; - }; - - if self.is_connected() { - client.set_connected(); - } else if self.is_connecting() { - client.set_connecting(); - } - - let ConnectionState::Connected { connection } = &mut self.state else { - unreachable!() - }; - - let messages = connection.receive_messages(MAX_MESSAGE_BATCH_SIZE); - messages.iter().for_each(|message| { - client.process_packet(message.data()); - }); - } - - pub fn send_packets(&mut self, client: &mut RenetClient) -> Result<(), SteamError> { - if self.is_disconnected() { - return Err(SteamError::NoConnection); - } - - if self.is_connecting() { - return Ok(()); - } - - let ConnectionState::Connected { connection } = &mut self.state else { - unreachable!() - }; - let packets = client.get_packets_to_send(); - for packet in packets { - connection.send_message(&packet, SendFlags::UNRELIABLE)?; - } - - connection.flush_messages() - } -} diff --git a/renet_steam/src/lib.rs b/renet_steam/src/lib.rs deleted file mode 100644 index 2c8b2387..00000000 --- a/renet_steam/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -const MAX_MESSAGE_BATCH_SIZE: usize = 512; - -mod client; -mod server; - -pub use client::SteamClientTransport; -pub use server::{AccessPermission, SteamServerConfig, SteamServerTransport}; - -#[doc(hidden)] -pub use steamworks; diff --git a/renet_steam/src/server.rs b/renet_steam/src/server.rs deleted file mode 100644 index bc73fd83..00000000 --- a/renet_steam/src/server.rs +++ /dev/null @@ -1,174 +0,0 @@ -use std::collections::{HashMap, HashSet}; - -use renet::{ClientId, RenetServer}; -use steamworks::{ - networking_sockets::{InvalidHandle, ListenSocket, NetConnection}, - networking_types::{ListenSocketEvent, NetConnectionEnd, NetworkingConfigEntry, SendFlags}, - Client, ClientManager, FriendFlags, Friends, LobbyId, Manager, Matchmaking, SteamId, -}; - -use super::MAX_MESSAGE_BATCH_SIZE; - -pub enum AccessPermission { - /// Everyone can connect - Public, - /// No one can connect - Private, - /// Only friends from the host can connect - FriendsOnly, - /// Only user from this list can connect - InList(HashSet), - /// Users that are in the lobby can connect - InLobby(LobbyId), -} - -pub struct SteamServerConfig { - pub max_clients: usize, - pub access_permission: AccessPermission, -} - -#[cfg_attr(feature = "bevy", derive(bevy_ecs::system::Resource))] -pub struct SteamServerTransport { - listen_socket: ListenSocket, - matchmaking: Matchmaking, - friends: Friends, - max_clients: usize, - access_permission: AccessPermission, - connections: HashMap>, -} - -impl SteamServerTransport { - pub fn new(client: &Client, config: SteamServerConfig) -> Result { - let options: Vec = Vec::new(); - let listen_socket = client.networking_sockets().create_listen_socket_p2p(0, options)?; - let matchmaking = client.matchmaking(); - let friends = client.friends(); - - Ok(Self { - listen_socket, - matchmaking, - friends, - max_clients: config.max_clients, - access_permission: config.access_permission, - connections: HashMap::new(), - }) - } - - pub fn max_clients(&self) -> usize { - self.max_clients - } - - /// Update the access permission to the server, - /// this change only applies to new connections. - pub fn set_access_permissions(&mut self, access_permission: AccessPermission) { - self.access_permission = access_permission; - } - - /// Disconnects a client from the server. - pub fn disconnect_client(&mut self, client_id: ClientId, server: &mut RenetServer, flush_last_packets: bool) { - if let Some((_key, value)) = self.connections.remove_entry(&client_id) { - let _ = value.close(NetConnectionEnd::AppGeneric, Some("Client was kicked"), flush_last_packets); - } - server.remove_connection(client_id); - } - - /// Disconnects all active clients including the host client from the server. - pub fn disconnect_all(&mut self, server: &mut RenetServer, flush_last_packets: bool) { - let keys = self.connections.keys().cloned().collect::>(); - for client_id in keys { - let _ = self.connections.remove_entry(&client_id).unwrap().1.close( - NetConnectionEnd::AppGeneric, - Some("Client was kicked"), - flush_last_packets, - ); - server.remove_connection(client_id); - } - } - - /// Update server connections, and receive packets from the network. - pub fn update(&mut self, server: &mut RenetServer) { - while let Some(event) = self.listen_socket.try_receive_event() { - match event { - ListenSocketEvent::Connected(event) => { - if let Some(steam_id) = event.remote().steam_id() { - let client_id = ClientId::from_raw(steam_id.raw()); - server.add_connection(client_id); - self.connections.insert(client_id, event.take_connection()); - } - } - ListenSocketEvent::Disconnected(event) => { - if let Some(steam_id) = event.remote().steam_id() { - let client_id = ClientId::from_raw(steam_id.raw()); - server.remove_connection(client_id); - self.connections.remove(&client_id); - } - } - ListenSocketEvent::Connecting(event) => { - if server.connected_clients() >= self.max_clients { - event.reject(NetConnectionEnd::AppGeneric, Some("Too many clients")); - continue; - } - - let Some(steam_id) = event.remote().steam_id() else { - event.reject(NetConnectionEnd::AppGeneric, Some("Invalid steam id")); - continue; - }; - - let permitted = match &self.access_permission { - AccessPermission::Public => true, - AccessPermission::Private => false, - AccessPermission::FriendsOnly => { - let friend = self.friends.get_friend(steam_id); - friend.has_friend(FriendFlags::IMMEDIATE) - } - AccessPermission::InList(list) => list.contains(&steam_id), - AccessPermission::InLobby(lobby) => { - let users_in_lobby = self.matchmaking.lobby_members(*lobby); - users_in_lobby.contains(&steam_id) - } - }; - - if permitted { - if let Err(e) = event.accept() { - log::error!("Failed to accept connection from {steam_id:?}: {e}"); - } - } else { - event.reject(NetConnectionEnd::AppGeneric, Some("Not allowed")); - } - } - } - } - - for (client_id, connection) in self.connections.iter_mut() { - // TODO this allocates on the side of steamworks.rs and should be avoided, PR needed - let messages = connection.receive_messages(MAX_MESSAGE_BATCH_SIZE); - messages.iter().for_each(|message| { - if let Err(e) = server.process_packet_from(message.data(), *client_id) { - log::error!("Error while processing payload for {}: {}", client_id, e); - }; - }); - } - } - - /// Send packets to connected clients. - pub fn send_packets(&mut self, server: &mut RenetServer) { - 'clients: for client_id in server.clients_id() { - let Some(connection) = self.connections.get(&client_id) else { - log::error!("Error while sending packet: connection not found"); - continue; - }; - let packets = server.get_packets_to_send(client_id).unwrap(); - // TODO: while this works fine we should probaly use the send_messages function from the listen_socket - for packet in packets { - if let Err(e) = connection.send_message(&packet, SendFlags::UNRELIABLE) { - log::error!("Failed to send packet to client {client_id}: {e}"); - continue 'clients; - } - } - - if let Err(e) = connection.flush_messages() { - log::error!("Failed flush messages for {client_id}: {e}"); - } - } - } -}