From 8a9492b4af9d111c672c654badbc9872e4c05fde Mon Sep 17 00:00:00 2001 From: Max Whitehead <35712032+MaxCWhitehead@users.noreply.github.com> Date: Sat, 8 Jun 2024 09:48:16 -0700 Subject: [PATCH] feat(networking): Add 'DisconnectedPlayers' resource to net session runner (#409) Each frame `DisconnectedPlayers` resource is updated in net session, can be used by game to determine which players may not be connected. If rollback before a disconnect - player is still listed in resource, because dc'd players are persisted on runner directly + copied to resource. --- .../bones_framework/src/networking.rs | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/framework_crates/bones_framework/src/networking.rs b/framework_crates/bones_framework/src/networking.rs index c92522763..8aaa1c6cb 100644 --- a/framework_crates/bones_framework/src/networking.rs +++ b/framework_crates/bones_framework/src/networking.rs @@ -51,7 +51,9 @@ impl From for NetworkInputStatus { /// Module prelude. pub mod prelude { - pub use super::{debug::prelude::*, input, lan, online, proto, NetworkInfo, RUNTIME}; + pub use super::{ + debug::prelude::*, input, lan, online, proto, DisconnectedPlayers, NetworkInfo, RUNTIME, + }; } /// Muliplier for framerate that will be used when playing an online match. @@ -192,6 +194,16 @@ pub struct NetworkInfo { pub socket: Socket, } +/// Resource tracking which players have been disconnected. +/// May not be in world if no disconnects. +/// +/// If rollback to frame before disconnect, player handle is still included here. +#[derive(HasSchema, Clone, Default)] +pub struct DisconnectedPlayers { + /// Handles of players that have been disconnected. + pub disconnected_players: Vec, +} + /// [`SessionRunner`] implementation that uses [`ggrs`] for network play. /// /// This is where the whole `ggrs` integration is implemented. @@ -223,6 +235,9 @@ pub struct GgrsSessionRunner<'a, InputTypes: NetworkInputConfig<'a>> { /// Session runner's input collector. pub input_collector: InputTypes::InputCollector, + /// Players who have been reported disconnected by ggrs + disconnected_players: Vec, + /// Store copy of socket to be able to restart session runner with existing socket. socket: Socket, @@ -334,6 +349,7 @@ where last_run: None, network_fps: network_fps as f64, original_fps: simulation_fps as f64, + disconnected_players: default(), input_collector: InputTypes::InputCollector::default(), socket: info.socket.clone(), local_input_delay, @@ -398,8 +414,10 @@ where ggrs::GgrsEvent::Synchronized { addr } => { info!(player=%addr, "Syncrhonized network client"); } - // TODO - ggrs::GgrsEvent::Disconnected { .. } => {} //return Err(SessionError::Disconnected)}, + ggrs::GgrsEvent::Disconnected { addr } => { + warn!(player=%addr, "Player Disconnected"); + self.disconnected_players.push(addr); + } //return Err(SessionError::Disconnected)}, ggrs::GgrsEvent::NetworkInterrupted { addr, .. } => { info!(player=%addr, "Network player interrupted"); } @@ -491,6 +509,12 @@ where socket: self.socket.clone(), }); + // Disconnected players persisted on session runner, and updated each frame. + // This avoids a rollback from changing resource state. + world.insert_resource(DisconnectedPlayers { + disconnected_players: self.disconnected_players.clone(), + }); + { world .resource_mut::