1
0
mirror of https://git.ngram.ca/OpenJam/rc-servers synced 2026-08-23 23:08:52 +00:00

Add network-layer multiplayer disconnect handling

This commit is contained in:
NG (Graham)
2026-01-07 21:09:38 -05:00
parent 1d0831d307
commit ac9e2a9fcd
10 changed files with 64 additions and 18 deletions

View File

@@ -21,10 +21,10 @@ atomic_float = "1.1"
num-quaternion.workspace = true
rand.workspace = true
#literustlib_server = { version = "0.3", path = "../../LiteRustLib/server" }
#literustlib = { version = "0.3", path = "../../LiteRustLib" }
literustlib_server = { version = "0.3" }
literustlib = { version = "0.3" }
literustlib_server = { version = "0.4", path = "../../LiteRustLib/server" }
literustlib = { version = "0.4", path = "../../LiteRustLib" }
#literustlib_server = { version = "0.4" }
#literustlib = { version = "0.4" }
rlnl = { version = "0.1", path = "../../rlnl" }
oj_serdes.workspace = true

View File

@@ -0,0 +1,29 @@
pub struct ClientDisconnecter {
msg_router: tokio::sync::mpsc::Sender<crate::matches::GameMessage>,
}
pub(super) fn handler(init_ctx: &crate::InitConfig) -> ClientDisconnecter {
ClientDisconnecter::new(init_ctx)
}
impl ClientDisconnecter {
fn new(init_ctx: &crate::InitConfig) -> Self {
Self {
msg_router: init_ctx.matches_chann.clone(),
}
}
}
#[async_trait::async_trait]
impl crate::DisconnectHandler for ClientDisconnecter {
async fn handle(&self, _peer: &std::sync::Arc<literustlib_server::Connection<crate::PacketData>>, user: &crate::UserData) {
if let Some(user_info) = user.user().await {
crate::events::log_channel_send_failure(self.msg_router.send(crate::matches::GameMessage::EndConnection {
user_id: user_info.user_id(),
is_unregister: false,
}).await);
} else {
log::error!("Failed to handle disconnect for unknown user");
}
}
}

View File

@@ -22,6 +22,7 @@ impl crate::handlers::DatalessEventCodeHandler for ClientUnregisterer {
if let Some(user_info) = user.user().await {
super::log_channel_send_failure(self.msg_router.send(crate::matches::GameMessage::EndConnection {
user_id: user_info.user_id(),
is_unregister: true,
}).await);
} else {
log::error!("Failed to handle sync loading request for unknown user");

View File

@@ -19,7 +19,11 @@ mod player_leave;
mod heal_assist_bonus;
pub async fn handler(init_ctx: &crate::InitConfig) -> crate::handler::LnlEventHandler {
crate::handler::LnlEventHandler::new(init_ctx.users.clone(), crate::vehicle_motion::handler(init_ctx))
crate::handler::LnlEventHandler::new(
init_ctx.users.clone(),
crate::vehicle_motion::handler(init_ctx),
crate::disconnect::handler(init_ctx),
)
.add(validate_game_guid::handler(init_ctx))
.add(loading_progress::handler(init_ctx))
.add(all_loading_progress::handler(init_ctx))

View File

@@ -1,14 +1,16 @@
pub struct LnlEventHandler {
event_handlers: std::collections::HashMap<i16, Box<dyn super::EventCodeHandler>>,
motion_handler: Box<dyn super::RobotMotionHandler>,
disconnect_handler: Box<dyn super::DisconnectHandler>,
user_provider: std::sync::Arc<oj_rc_core::persist::user::UserImpl>
}
impl LnlEventHandler {
pub fn new<M: super::RobotMotionHandler + 'static>(user_provider: std::sync::Arc<oj_rc_core::persist::user::UserImpl>, motion_handler: M) -> Self {
pub fn new<M: super::RobotMotionHandler + 'static, D: super::DisconnectHandler + 'static>(user_provider: std::sync::Arc<oj_rc_core::persist::user::UserImpl>, motion_handler: M, disconnect_handler: D) -> Self {
Self {
event_handlers: std::collections::HashMap::new(),
motion_handler: Box::new(motion_handler),
disconnect_handler: Box::new(disconnect_handler),
user_provider,
}
}
@@ -75,12 +77,12 @@ impl literustlib_server::EventHandler for LnlEventHandler {
}
async fn on_disconnect(&self, peer: &std::sync::Arc<literustlib_server::Connection<Self::PacketData>>, user: &Self::UserData) {
self.disconnect_handler.handle(peer, user).await;
if let Some(user_info) = user.user().await {
log::info!("Disconnect from user {} ({})", user_info.user_id(), peer.id());
} else {
log::debug!("Disconnect from connection {}", peer.id());
}
}
}

View File

@@ -1,13 +1,14 @@
mod cli;
mod handler;
mod traits;
pub use traits::{EventCodeHandler, UserData, PacketData, EventCode, RobotMotionHandler, Broadcastable};
pub use traits::{EventCodeHandler, UserData, PacketData, EventCode, RobotMotionHandler, DisconnectHandler, Broadcastable};
mod data;
mod events;
mod handlers;
mod user;
mod matches;
mod vehicle_motion;
mod disconnect;
pub struct InitConfig {
pub config: oj_rc_core::persist::config::ConfigImpl,

View File

@@ -427,8 +427,8 @@ impl <L: super::CustomGameLogic> GenericGamemodeEngine<L> {
super::GameMessage::NewConnection { user, game_guid, connection, response, sender } => {
self.on_new_connection(user, game_guid, connection, response, sender).await;
},
super::GameMessage::EndConnection { user_id } => {
is_engaged = self.on_end_connection(user_id).await;
super::GameMessage::EndConnection { user_id, is_unregister } => {
is_engaged = self.on_end_connection(user_id, is_unregister).await;
},
super::GameMessage::RequestLeave { user_id } => {
self.on_request_leave(user_id).await;
@@ -569,7 +569,7 @@ impl <L: super::CustomGameLogic> GenericGamemodeEngine<L> {
}
}
async fn on_end_connection(&self, user_id: i32) -> bool {
async fn on_end_connection(&self, user_id: i32, _is_unregister: bool) -> bool {
if let Some(player_id) = self.user_key_by_user_id(user_id) {
let conn_opt = self.users.write().await.remove(&player_id);
if let Some(conn) = conn_opt {
@@ -642,7 +642,14 @@ impl <L: super::CustomGameLogic> GenericGamemodeEngine<L> {
}
}
}
true
for user in self.descriptors.values() {
if user.descriptor.user_id.is_none() { continue; } // skip non-players
let mode = ConnectionMode::from_u8(user.state.mode.load(std::sync::atomic::Ordering::Relaxed));
if !matches!(mode, ConnectionMode::Disconnected) {
return true;
}
}
false
}
async fn on_request_leave(&self, user_id: i32) {

View File

@@ -8,6 +8,7 @@ pub enum GameMessage {
},
EndConnection {
user_id: i32,
is_unregister: bool,
},
RequestLeave {
user_id: i32,

View File

@@ -15,4 +15,9 @@ pub trait RobotMotionHandler: Send + Sync {
async fn handle(&self, data: &bytes::Bytes, user: &UserData);
}
#[async_trait::async_trait]
pub trait DisconnectHandler: Send + Sync {
async fn handle(&self, peer: &std::sync::Arc<literustlib_server::Connection<PacketData>>, user: &UserData);
}
pub trait Broadcastable: byteserde::ser_heap::ByteSerializeHeap + core::any::Any + Send + Sync + 'static {}