forked from NewEriduPubSec/JaneDoe-ZS
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
This commit is contained in:
parent
9af61cd33f
commit
4b86d62d3f
3 changed files with 66 additions and 10 deletions
|
@ -79,5 +79,6 @@ impl CommandManager {
|
||||||
|
|
||||||
commands! {
|
commands! {
|
||||||
player::avatar "[player_uid] [avatar_id]" "changes player avatar for main city";
|
player::avatar "[player_uid] [avatar_id]" "changes player avatar for main city";
|
||||||
|
player::nickname "[player_uid] [nickname]" "changes player nickname";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use data::tables;
|
use data::tables;
|
||||||
|
use proto::PlayerSyncScNotify;
|
||||||
|
|
||||||
use crate::ServerState;
|
use crate::ServerState;
|
||||||
|
|
||||||
|
@ -37,3 +38,54 @@ pub async fn avatar(
|
||||||
"changed frontend_avatar_id, you have to re-enter main city now"
|
"changed frontend_avatar_id, you have to re-enter main city now"
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn nickname(
|
||||||
|
args: &[&str],
|
||||||
|
state: &ServerState,
|
||||||
|
) -> Result<String, Box<dyn std::error::Error>> {
|
||||||
|
const USAGE: &str = "Usage: player nickname [uid] [nickname]";
|
||||||
|
|
||||||
|
if args.len() != 2 {
|
||||||
|
return Ok(USAGE.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let uid = args[0].parse::<u32>()?;
|
||||||
|
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}"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
|
@ -9,8 +9,11 @@ use common::{
|
||||||
use proto::{CmdID, NapMessage, PacketHead};
|
use proto::{CmdID, NapMessage, PacketHead};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::AsyncWriteExt,
|
io::AsyncWriteExt,
|
||||||
net::TcpStream,
|
net::{
|
||||||
sync::{Mutex, MutexGuard, OnceCell},
|
tcp::{OwnedReadHalf, OwnedWriteHalf},
|
||||||
|
TcpStream,
|
||||||
|
},
|
||||||
|
sync::{Mutex, OnceCell},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -30,7 +33,8 @@ static SECRET_KEY: LazyLock<MhyXorpad> = LazyLock::new(|| {
|
||||||
|
|
||||||
pub struct NetSession {
|
pub struct NetSession {
|
||||||
id: u64,
|
id: u64,
|
||||||
stream: Mutex<TcpStream>,
|
reader: Mutex<OwnedReadHalf>,
|
||||||
|
writer: Mutex<OwnedWriteHalf>,
|
||||||
session_key: OnceCell<MhyXorpad>,
|
session_key: OnceCell<MhyXorpad>,
|
||||||
packet_id_counter: AtomicU32,
|
packet_id_counter: AtomicU32,
|
||||||
state: AtomicNetSessionState,
|
state: AtomicNetSessionState,
|
||||||
|
@ -75,9 +79,12 @@ pub enum SessionError {
|
||||||
|
|
||||||
impl NetSession {
|
impl NetSession {
|
||||||
pub fn new(id: u64, stream: TcpStream) -> Self {
|
pub fn new(id: u64, stream: TcpStream) -> Self {
|
||||||
|
let (reader, writer) = stream.into_split();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
stream: Mutex::new(stream),
|
reader: Mutex::new(reader),
|
||||||
|
writer: Mutex::new(writer),
|
||||||
session_key: OnceCell::new(),
|
session_key: OnceCell::new(),
|
||||||
packet_id_counter: AtomicU32::new(0),
|
packet_id_counter: AtomicU32::new(0),
|
||||||
state: AtomicNetSessionState::new(NetSessionState::StartEnterGameWorld),
|
state: AtomicNetSessionState::new(NetSessionState::StartEnterGameWorld),
|
||||||
|
@ -90,7 +97,7 @@ impl NetSession {
|
||||||
let mut last_save_time = util::cur_timestamp();
|
let mut last_save_time = util::cur_timestamp();
|
||||||
|
|
||||||
let result = loop {
|
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,
|
Ok(packet) => packet,
|
||||||
Err(DecodeError::IoError(_)) => break Ok(()),
|
Err(DecodeError::IoError(_)) => break Ok(()),
|
||||||
Err(err) => break Err(SessionError::PacketDecode(err)),
|
Err(err) => break Err(SessionError::PacketDecode(err)),
|
||||||
|
@ -195,11 +202,7 @@ impl NetSession {
|
||||||
self.xor_payload(packet.cmd_id, &mut packet.body);
|
self.xor_payload(packet.cmd_id, &mut packet.body);
|
||||||
|
|
||||||
let buf = packet.encode();
|
let buf = packet.encode();
|
||||||
self.stream().await.write_all(&buf).await
|
self.writer.lock().await.write_all(&buf).await
|
||||||
}
|
|
||||||
|
|
||||||
async fn stream(&self) -> MutexGuard<'_, TcpStream> {
|
|
||||||
self.stream.lock().await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id(&self) -> u64 {
|
pub fn id(&self) -> u64 {
|
||||||
|
|
Loading…
Reference in a new issue