From a856f719f0c860fad9fc54e6841d2be742a75ed1 Mon Sep 17 00:00:00 2001 From: xeon Date: Fri, 29 Mar 2024 23:39:42 +0300 Subject: [PATCH] Refactor PlayerSession, in-game lineup editing --- gameserver/src/game/mod.rs | 3 + gameserver/src/game/player_info.rs | 57 +++++++ gameserver/src/net/handlers/authentication.rs | 4 +- gameserver/src/net/handlers/avatar.rs | 2 +- gameserver/src/net/handlers/battle.rs | 16 +- gameserver/src/net/handlers/lineup.rs | 161 ++++++++++++------ gameserver/src/net/handlers/mission.rs | 2 +- gameserver/src/net/handlers/mod.rs | 4 +- gameserver/src/net/handlers/player.rs | 6 +- gameserver/src/net/handlers/scene.rs | 2 +- gameserver/src/net/handlers/tutorial.rs | 6 +- gameserver/src/net/packet.rs | 10 +- gameserver/src/net/session.rs | 38 ++++- proto/out/_.rs | 6 +- 14 files changed, 231 insertions(+), 86 deletions(-) create mode 100644 gameserver/src/game/player_info.rs diff --git a/gameserver/src/game/mod.rs b/gameserver/src/game/mod.rs index 685bf55..b2c2f80 100644 --- a/gameserver/src/game/mod.rs +++ b/gameserver/src/game/mod.rs @@ -1,2 +1,5 @@ mod global_config; +mod player_info; + pub use global_config::INSTANCE as globals; +pub use player_info::PlayerInfo; diff --git a/gameserver/src/game/player_info.rs b/gameserver/src/game/player_info.rs new file mode 100644 index 0000000..a9a5051 --- /dev/null +++ b/gameserver/src/game/player_info.rs @@ -0,0 +1,57 @@ +use crate::net::PlayerSession; + +use super::globals; +use anyhow::Result; +use proto::*; + +pub struct PlayerInfo { + pub lineup: LineupInfo, +} + +impl PlayerInfo { + pub fn new() -> Self { + Self { + lineup: default_lineup(), + } + } + + pub async fn sync_lineup(&self, session: &PlayerSession) -> Result<()> { + session + .send( + CMD_SYNC_LINEUP_NOTIFY, + SyncLineupNotify { + lineup: Some(self.lineup.clone()), + ..Default::default() + }, + ) + .await + } +} + +fn default_lineup() -> LineupInfo { + LineupInfo { + plane_id: 10001, + name: String::from("Lineup 1"), + index: 0, + leader_slot: 0, + mp: 5, + mp_max: 5, + avatar_list: globals + .lineup + .iter() + .enumerate() + .map(|(idx, id)| LineupAvatar { + id: *id, + slot: idx as u32, + hp: 10000, + sp: Some(AmountInfo { + cur_amount: 10000, + max_amount: 10000, + }), + satiety: 100, + avatar_type: 3, + }) + .collect(), + ..Default::default() + } +} diff --git a/gameserver/src/net/handlers/authentication.rs b/gameserver/src/net/handlers/authentication.rs index 7862146..af50496 100644 --- a/gameserver/src/net/handlers/authentication.rs +++ b/gameserver/src/net/handlers/authentication.rs @@ -4,7 +4,7 @@ use proto::*; use crate::{net::PlayerSession, util}; pub async fn on_player_get_token_cs_req( - session: &mut PlayerSession, + session: &PlayerSession, _body: &PlayerGetTokenCsReq, ) -> Result<()> { session @@ -21,7 +21,7 @@ pub async fn on_player_get_token_cs_req( } pub async fn on_player_login_cs_req( - session: &mut PlayerSession, + session: &PlayerSession, body: &PlayerLoginCsReq, ) -> Result<()> { session diff --git a/gameserver/src/net/handlers/avatar.rs b/gameserver/src/net/handlers/avatar.rs index 7a2ee5d..8e865ce 100644 --- a/gameserver/src/net/handlers/avatar.rs +++ b/gameserver/src/net/handlers/avatar.rs @@ -8,7 +8,7 @@ static UNLOCKED_AVATARS: [u32; 49] = [ ]; pub async fn on_get_avatar_data_cs_req( - session: &mut PlayerSession, + session: &PlayerSession, body: &GetAvatarDataCsReq, ) -> Result<()> { session diff --git a/gameserver/src/net/handlers/battle.rs b/gameserver/src/net/handlers/battle.rs index 06e5768..30fe89c 100644 --- a/gameserver/src/net/handlers/battle.rs +++ b/gameserver/src/net/handlers/battle.rs @@ -2,9 +2,11 @@ use super::*; use crate::game::globals; pub async fn on_start_cocoon_stage_cs_req( - session: &mut PlayerSession, + session: &PlayerSession, body: &StartCocoonStageCsReq, ) -> Result<()> { + let player_info = session.player_info(); + let rsp = StartCocoonStageScRsp { retcode: 0, prop_entity_id: body.prop_entity_id, @@ -14,13 +16,13 @@ pub async fn on_start_cocoon_stage_cs_req( stage_id: 201012311, logic_random_seed: 4444, battle_id: 1, - battle_avatar_list: globals + battle_avatar_list: player_info .lineup + .avatar_list .iter() - .enumerate() - .map(|(idx, id)| BattleAvatar { - index: idx as u32, - id: *id, + .map(|avatar| BattleAvatar { + index: avatar.slot, + id: avatar.id, level: 80, promotion: 6, rank: 6, @@ -55,7 +57,7 @@ pub async fn on_start_cocoon_stage_cs_req( } pub async fn on_pve_battle_result_cs_req( - session: &mut PlayerSession, + session: &PlayerSession, body: &PveBattleResultCsReq, ) -> Result<()> { session diff --git a/gameserver/src/net/handlers/lineup.rs b/gameserver/src/net/handlers/lineup.rs index c397089..d9c3255 100644 --- a/gameserver/src/net/handlers/lineup.rs +++ b/gameserver/src/net/handlers/lineup.rs @@ -1,86 +1,47 @@ use super::*; -use crate::game::globals; pub async fn on_get_all_lineup_data_cs_req( - session: &mut PlayerSession, + session: &PlayerSession, _body: &GetAllLineupDataCsReq, ) -> Result<()> { + let player_info = session.player_info(); + session .send( CMD_GET_ALL_LINEUP_DATA_SC_RSP, GetAllLineupDataScRsp { retcode: 0, cur_index: 0, - lineup_list: vec![LineupInfo { - plane_id: 10001, - name: String::from("Lineup 1"), - index: 0, - avatar_list: globals - .lineup - .iter() - .enumerate() - .map(|(idx, id)| LineupAvatar { - id: *id, - slot: idx as u32, - hp: 10000, - sp: Some(AmountInfo { - cur_amount: 10000, - max_amount: 10000, - }), - satiety: 100, - avatar_type: 3, - }) - .collect(), - ..Default::default() - }], + lineup_list: vec![player_info.lineup.clone()], }, ) .await } pub async fn on_get_cur_lineup_data_cs_req( - session: &mut PlayerSession, + session: &PlayerSession, _body: &GetCurLineupDataCsReq, ) -> Result<()> { + let player_info = session.player_info(); + session .send( CMD_GET_CUR_LINEUP_DATA_SC_RSP, GetCurLineupDataScRsp { retcode: 0, - lineup: Some(LineupInfo { - plane_id: 10001, - name: String::from("Lineup 1"), - index: 0, - leader_slot: 0, - mp: 5, - mp_max: 5, - avatar_list: globals - .lineup - .iter() - .enumerate() - .map(|(idx, id)| LineupAvatar { - id: *id, - slot: idx as u32, - hp: 10000, - sp: Some(AmountInfo { - cur_amount: 10000, - max_amount: 10000, - }), - satiety: 100, - avatar_type: 3, - }) - .collect(), - ..Default::default() - }), + lineup: Some(player_info.lineup.clone()), }, ) .await } pub async fn on_change_lineup_leader_cs_req( - session: &mut PlayerSession, + session: &PlayerSession, body: &ChangeLineupLeaderCsReq, ) -> Result<()> { + let mut player_info = session.player_info_mut(); + player_info.lineup.leader_slot = body.slot; + session .send( CMD_CHANGE_LINEUP_LEADER_SC_RSP, @@ -91,3 +52,101 @@ pub async fn on_change_lineup_leader_cs_req( ) .await } + +pub async fn on_join_lineup_cs_req(session: &PlayerSession, body: &JoinLineupCsReq) -> Result<()> { + let mut player_info = session.player_info_mut(); + + if !(0..4).contains(&body.slot) { + return session + .send( + CMD_JOIN_LINEUP_CS_REQ, + JoinLineupScRsp { + retcode: Retcode::RetLineupInvalidMemberPos as u32, + }, + ) + .await; + } + + if player_info + .lineup + .avatar_list + .iter() + .any(|avatar| avatar.slot == body.slot) + { + return session + .send( + CMD_JOIN_LINEUP_CS_REQ, + JoinLineupScRsp { + retcode: Retcode::RetLineupAvatarAlreadyInit as u32, + }, + ) + .await; + } + + player_info + .lineup + .avatar_list + .push(lineup_avatar(body.base_avatar_id, body.slot)); + + player_info.sync_lineup(session).await?; + session + .send(CMD_JOIN_LINEUP_SC_RSP, JoinLineupScRsp::default()) + .await +} + +pub async fn on_replace_lineup_cs_req( + session: &PlayerSession, + body: &ReplaceLineupCsReq, +) -> Result<()> { + let mut player_info = session.player_info_mut(); + + player_info.lineup.avatar_list.clear(); + for slot_info in &body.lineup_slots { + player_info + .lineup + .avatar_list + .push(lineup_avatar(slot_info.id, slot_info.slot)); + } + player_info.lineup.leader_slot = body.leader_slot; + + player_info.sync_lineup(session).await?; + session + .send(CMD_REPLACE_LINEUP_SC_RSP, ReplaceLineupScRsp::default()) + .await +} + +pub async fn on_quit_lineup_cs_req(session: &PlayerSession, body: &QuitLineupCsReq) -> Result<()> { + let mut player_info = session.player_info_mut(); + player_info + .lineup + .avatar_list + .retain(|avatar| avatar.id != body.base_avatar_id); + + player_info.sync_lineup(session).await?; + session + .send( + CMD_QUIT_LINEUP_SC_RSP, + QuitLineupScRsp { + plane_id: body.plane_id, + is_mainline: !body.is_virtual, + is_virtual: body.is_virtual, + base_avatar_id: body.base_avatar_id, + retcode: 0, + }, + ) + .await +} + +fn lineup_avatar(id: u32, slot: u32) -> LineupAvatar { + LineupAvatar { + id, + slot, + hp: 10000, + sp: Some(AmountInfo { + cur_amount: 10000, + max_amount: 10000, + }), + satiety: 100, + avatar_type: 3, + } +} diff --git a/gameserver/src/net/handlers/mission.rs b/gameserver/src/net/handlers/mission.rs index 70e864a..83717ba 100644 --- a/gameserver/src/net/handlers/mission.rs +++ b/gameserver/src/net/handlers/mission.rs @@ -41,7 +41,7 @@ static FINISHED_MAIN_MISSIONS: [u32; 365] = [ ]; pub async fn on_get_mission_status_cs_req( - session: &mut PlayerSession, + session: &PlayerSession, body: &GetMissionStatusCsReq, ) -> Result<()> { let rsp = GetMissionStatusScRsp { diff --git a/gameserver/src/net/handlers/mod.rs b/gameserver/src/net/handlers/mod.rs index 6b84f5b..fec82d2 100644 --- a/gameserver/src/net/handlers/mod.rs +++ b/gameserver/src/net/handlers/mod.rs @@ -46,7 +46,7 @@ macro_rules! dummy { } } - pub async fn send_dummy_response(&mut self, req_id: u16) -> Result<()> { + pub async fn send_dummy_response(&self, req_id: u16) -> Result<()> { let cmd_type = match req_id { $( x if x == [] as u16 => [] as u16, @@ -61,7 +61,7 @@ macro_rules! dummy { } .into(); - self.client_socket.write_all(&payload).await?; + self.client_socket().await.write_all(&payload).await?; Ok(()) } diff --git a/gameserver/src/net/handlers/player.rs b/gameserver/src/net/handlers/player.rs index c4a94ce..a01f83f 100644 --- a/gameserver/src/net/handlers/player.rs +++ b/gameserver/src/net/handlers/player.rs @@ -3,7 +3,7 @@ use crate::util; use super::*; pub async fn on_get_basic_info_cs_req( - session: &mut PlayerSession, + session: &PlayerSession, _body: &GetBasicInfoCsReq, ) -> Result<()> { session @@ -19,7 +19,7 @@ pub async fn on_get_basic_info_cs_req( } pub async fn on_get_hero_basic_type_info_cs_req( - session: &mut PlayerSession, + session: &PlayerSession, _body: &GetHeroBasicTypeInfoCsReq, ) -> Result<()> { session @@ -40,7 +40,7 @@ pub async fn on_get_hero_basic_type_info_cs_req( } pub async fn on_player_heart_beat_cs_req( - session: &mut PlayerSession, + session: &PlayerSession, body: &PlayerHeartBeatCsReq, ) -> Result<()> { session diff --git a/gameserver/src/net/handlers/scene.rs b/gameserver/src/net/handlers/scene.rs index 0e82079..1bdf321 100644 --- a/gameserver/src/net/handlers/scene.rs +++ b/gameserver/src/net/handlers/scene.rs @@ -1,7 +1,7 @@ use super::*; pub async fn on_get_cur_scene_info_cs_req( - session: &mut PlayerSession, + session: &PlayerSession, _body: &GetCurSceneInfoCsReq, ) -> Result<()> { session diff --git a/gameserver/src/net/handlers/tutorial.rs b/gameserver/src/net/handlers/tutorial.rs index a770f66..4e3b58f 100644 --- a/gameserver/src/net/handlers/tutorial.rs +++ b/gameserver/src/net/handlers/tutorial.rs @@ -8,7 +8,7 @@ static TUTORIAL_IDS: [u32; 55] = [ ]; pub async fn on_get_tutorial_cs_req( - session: &mut PlayerSession, + session: &PlayerSession, _body: &GetTutorialCsReq, ) -> Result<()> { session @@ -29,7 +29,7 @@ pub async fn on_get_tutorial_cs_req( } pub async fn on_get_tutorial_guide_cs_req( - session: &mut PlayerSession, + session: &PlayerSession, _body: &GetTutorialGuideCsReq, ) -> Result<()> { session @@ -44,7 +44,7 @@ pub async fn on_get_tutorial_guide_cs_req( } pub async fn on_unlock_tutorial_guide_cs_req( - session: &mut PlayerSession, + session: &PlayerSession, body: &UnlockTutorialGuideCsReq, ) -> Result<()> { session diff --git a/gameserver/src/net/packet.rs b/gameserver/src/net/packet.rs index d1a4577..b51b94a 100644 --- a/gameserver/src/net/packet.rs +++ b/gameserver/src/net/packet.rs @@ -62,13 +62,13 @@ macro_rules! trait_handler { pub trait CommandHandler { $( paste! { - async fn [](session: &mut PlayerSession, body: &$name) -> Result<()> { + async fn [](session: &PlayerSession, body: &$name) -> Result<()> { [](session, body).await } } )* - async fn on_message(session: &mut PlayerSession, cmd_type: u16, payload: Vec) -> Result<()> { + async fn on_message(session: &PlayerSession, cmd_type: u16, payload: Vec) -> Result<()> { use ::prost::Message; if PlayerSession::should_send_dummy_rsp(cmd_type) { session.send_dummy_response(cmd_type).await?; @@ -641,18 +641,18 @@ trait_handler! { // ExtraLineupDestroyNotify 763; // GetLineupAvatarDataCsReq 768; // SwitchLineupIndexScRsp 795; - // JoinLineupCsReq 702; + JoinLineupCsReq 702; // GetAllLineupDataScRsp 716; // SetLineupNameCsReq 742; // ChangeLineupLeaderScRsp 733; ChangeLineupLeaderCsReq 706; - // ReplaceLineupCsReq 785; + ReplaceLineupCsReq 785; // SwapLineupCsReq 786; // QuitLineupScRsp 743; // GetLineupAvatarDataScRsp 796; // ReplaceLineupScRsp 756; // GetStageLineupCsReq 734; - // QuitLineupCsReq 719; + QuitLineupCsReq 719; // SetLineupNameScRsp 737; // SwitchLineupIndexCsReq 759; GetCurLineupDataCsReq 762; diff --git a/gameserver/src/net/session.rs b/gameserver/src/net/session.rs index 8001809..c726787 100644 --- a/gameserver/src/net/session.rs +++ b/gameserver/src/net/session.rs @@ -1,26 +1,38 @@ use anyhow::Result; +use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use prost::Message; -use tokio::{io::AsyncWriteExt, net::TcpStream}; +use std::sync::Arc; +use tokio::{ + io::AsyncWriteExt, + net::TcpStream, + sync::{Mutex, MutexGuard}, +}; + +use crate::game::PlayerInfo; use super::{packet::CommandHandler, NetPacket}; pub struct PlayerSession { - pub(crate) client_socket: TcpStream, + client_socket: Arc>, + player_info: Arc>, } impl PlayerSession { - pub const fn new(client_socket: TcpStream) -> Self { - Self { client_socket } + pub fn new(client_socket: TcpStream) -> Self { + Self { + client_socket: Arc::new(Mutex::new(client_socket)), + player_info: Arc::new(AtomicRefCell::new(PlayerInfo::new())), + } } pub async fn run(&mut self) -> Result<()> { loop { - let net_packet = NetPacket::read(&mut self.client_socket).await?; + let net_packet = NetPacket::read(&mut *self.client_socket().await).await?; Self::on_message(self, net_packet.cmd_type, net_packet.body).await?; } } - pub async fn send(&mut self, cmd_type: u16, body: impl Message) -> Result<()> { + pub async fn send(&self, cmd_type: u16, body: impl Message) -> Result<()> { let mut buf = Vec::new(); body.encode(&mut buf)?; @@ -31,9 +43,21 @@ impl PlayerSession { } .into(); - self.client_socket.write_all(&payload).await?; + self.client_socket().await.write_all(&payload).await?; Ok(()) } + + pub async fn client_socket(&self) -> MutexGuard<'_, TcpStream> { + self.client_socket.lock().await + } + + pub fn player_info(&self) -> AtomicRef { + self.player_info.borrow() + } + + pub fn player_info_mut(&self) -> AtomicRefMut { + self.player_info.borrow_mut() + } } // Auto implemented diff --git a/proto/out/_.rs b/proto/out/_.rs index 2b3282f..aff2c8c 100644 --- a/proto/out/_.rs +++ b/proto/out/_.rs @@ -9165,7 +9165,7 @@ pub struct VirtualLineupDestroyNotify { #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Kcllnhmojig { +pub struct LineupSlotInfo { #[prost(uint32, tag = "11")] pub slot: u32, #[prost(enumeration = "AvatarType", tag = "14")] @@ -9182,13 +9182,13 @@ pub struct ReplaceLineupCsReq { #[prost(uint32, tag = "6")] pub djdbkfnekpf: u32, #[prost(uint32, tag = "12")] - pub hpammbapokf: u32, + pub leader_slot: u32, #[prost(bool, tag = "10")] pub is_virtual: bool, #[prost(uint32, tag = "2")] pub plane_id: u32, #[prost(message, repeated, tag = "5")] - pub jkifflmenfn: ::prost::alloc::vec::Vec, + pub lineup_slots: ::prost::alloc::vec::Vec, #[prost(enumeration = "ExtraLineupType", tag = "9")] pub extra_lineup_type: i32, }