From 4b86d62d3ffc4425c9b8ddf2ad569d27bdaf5461 Mon Sep 17 00:00:00 2001 From: xeon Date: Tue, 23 Jul 2024 00:04:59 +0300 Subject: [PATCH] Networking improvement and player nickname change console command split TcpStream into read and write halves, so it's possible to recv and send concurrently implement 'player nickname' command --- nap_gameserver/src/commands/mod.rs | 1 + nap_gameserver/src/commands/player.rs | 52 +++++++++++++++++++++++++++ nap_gameserver/src/net/session.rs | 23 ++++++------ 3 files changed, 66 insertions(+), 10 deletions(-) diff --git a/nap_gameserver/src/commands/mod.rs b/nap_gameserver/src/commands/mod.rs index 452c994..3587842 100644 --- a/nap_gameserver/src/commands/mod.rs +++ b/nap_gameserver/src/commands/mod.rs @@ -79,5 +79,6 @@ impl CommandManager { commands! { player::avatar "[player_uid] [avatar_id]" "changes player avatar for main city"; + player::nickname "[player_uid] [nickname]" "changes player nickname"; } } diff --git a/nap_gameserver/src/commands/player.rs b/nap_gameserver/src/commands/player.rs index 150a0ad..0bcefc2 100644 --- a/nap_gameserver/src/commands/player.rs +++ b/nap_gameserver/src/commands/player.rs @@ -1,4 +1,5 @@ use data::tables; +use proto::PlayerSyncScNotify; use crate::ServerState; @@ -37,3 +38,54 @@ pub async fn avatar( "changed frontend_avatar_id, you have to re-enter main city now" )) } + +pub async fn nickname( + args: &[&str], + state: &ServerState, +) -> Result> { + const USAGE: &str = "Usage: player nickname [uid] [nickname]"; + + if args.len() != 2 { + return Ok(USAGE.to_string()); + } + + let uid = args[0].parse::()?; + let nickname = args[1].trim(); + + if !matches!(nickname.len(), (4..=15)) { + return Ok(String::from( + "nickname should contain at least 4 and not more than 15 characters", + )); + } + + let Some(player_lock) = state.player_mgr.get_player(uid).await else { + return Ok(String::from("player not found")); + }; + + let (session_id, basic_info) = { + let mut player = player_lock.lock().await; + player.basic_data_model.nick_name = Some(nickname.to_string()); + + ( + player.current_session_id(), + player.basic_data_model.player_basic_info(), + ) + }; + + if let Some(session_id) = session_id { + if let Some(session) = state.session_mgr.get(session_id) { + session + .notify(PlayerSyncScNotify { + basic_info: Some(basic_info), + ..Default::default() + }) + .await?; + } + } else { + state.player_mgr.save_and_remove(uid).await; + } + + Ok(format!( + "successfully changed player {uid} nickname to {nickname}" + )) +} diff --git a/nap_gameserver/src/net/session.rs b/nap_gameserver/src/net/session.rs index a702aff..f3457f6 100644 --- a/nap_gameserver/src/net/session.rs +++ b/nap_gameserver/src/net/session.rs @@ -9,8 +9,11 @@ use common::{ use proto::{CmdID, NapMessage, PacketHead}; use tokio::{ io::AsyncWriteExt, - net::TcpStream, - sync::{Mutex, MutexGuard, OnceCell}, + net::{ + tcp::{OwnedReadHalf, OwnedWriteHalf}, + TcpStream, + }, + sync::{Mutex, OnceCell}, }; use crate::{ @@ -30,7 +33,8 @@ static SECRET_KEY: LazyLock = LazyLock::new(|| { pub struct NetSession { id: u64, - stream: Mutex, + reader: Mutex, + writer: Mutex, session_key: OnceCell, packet_id_counter: AtomicU32, state: AtomicNetSessionState, @@ -75,9 +79,12 @@ pub enum SessionError { impl NetSession { pub fn new(id: u64, stream: TcpStream) -> Self { + let (reader, writer) = stream.into_split(); + Self { id, - stream: Mutex::new(stream), + reader: Mutex::new(reader), + writer: Mutex::new(writer), session_key: OnceCell::new(), packet_id_counter: AtomicU32::new(0), state: AtomicNetSessionState::new(NetSessionState::StartEnterGameWorld), @@ -90,7 +97,7 @@ impl NetSession { let mut last_save_time = util::cur_timestamp(); let result = loop { - let packet = match NetPacket::read(&mut *self.stream().await).await { + let packet = match NetPacket::read(&mut *self.reader.lock().await).await { Ok(packet) => packet, Err(DecodeError::IoError(_)) => break Ok(()), Err(err) => break Err(SessionError::PacketDecode(err)), @@ -195,11 +202,7 @@ impl NetSession { self.xor_payload(packet.cmd_id, &mut packet.body); let buf = packet.encode(); - self.stream().await.write_all(&buf).await - } - - async fn stream(&self) -> MutexGuard<'_, TcpStream> { - self.stream.lock().await + self.writer.lock().await.write_all(&buf).await } pub fn id(&self) -> u64 {