From 66ad49dcb24cbf37aba118a4cca6c19917c90bc2 Mon Sep 17 00:00:00 2001 From: xeon Date: Tue, 14 May 2024 15:58:06 +0300 Subject: [PATCH] New command system, some new commands (scene enter, avatar max_traces) --- gameserver/src/game/commands/avatar.rs | 61 +++++++++++++++ gameserver/src/game/commands/mod.rs | 63 +++++++++++++++ gameserver/src/game/commands/relic.rs | 42 ++++++++++ gameserver/src/game/commands/scene.rs | 25 ++++++ gameserver/src/game/context.rs | 4 +- gameserver/src/game/managers/command.rs | 100 ------------------------ gameserver/src/game/managers/mod.rs | 2 - gameserver/src/game/mod.rs | 1 + gameserver/src/net/handlers/chat.rs | 7 +- gameserver/src/net/packet.rs | 2 +- gameserver/src/net/session.rs | 4 +- 11 files changed, 198 insertions(+), 113 deletions(-) create mode 100644 gameserver/src/game/commands/avatar.rs create mode 100644 gameserver/src/game/commands/mod.rs create mode 100644 gameserver/src/game/commands/relic.rs create mode 100644 gameserver/src/game/commands/scene.rs delete mode 100644 gameserver/src/game/managers/command.rs diff --git a/gameserver/src/game/commands/avatar.rs b/gameserver/src/game/commands/avatar.rs new file mode 100644 index 0000000..c55b61d --- /dev/null +++ b/gameserver/src/game/commands/avatar.rs @@ -0,0 +1,61 @@ +use common::data::EXCEL_COLLECTION; + +use super::*; + +pub async fn max_traces(args: &[&str], session: &PlayerSession) -> Result<()> { + let Some(Ok(avatar_id)) = args.get(0).map(|s| s.parse::()) else { + return send_text(session, "Usage: /avatar max_traces [avatar_id]").await; + }; + + { + let mut player_info = session.context.player.borrow_mut(); + let avatar_comp = player_info.data.avatar_bin.as_mut().unwrap(); + + let Some(avatar) = avatar_comp + .avatar_list + .iter_mut() + .find(|a| a.avatar_id == avatar_id) + else { + return send_text(session, &format!("Avatar {avatar_id} doesn't exist")).await; + }; + + EXCEL_COLLECTION + .avatar_skill_tree_configs + .iter() + .filter(|c| c.avatar_id == avatar_id) + .map(|c| (c.point_id, c.max_level)) + .for_each(|(pt, lv)| { + if let Some(skill_tree) = avatar + .skill_tree_list + .iter_mut() + .find(|st| st.point_id == pt) + { + skill_tree.level = lv + } else { + avatar.skill_tree_list.push(AvatarSkillTreeBin { + point_id: pt, + level: lv, + }) + } + }); + } + + let avatar_mgr = session.context.avatar_mgr.borrow(); + session + .send( + CMD_PLAYER_SYNC_SC_NOTIFY, + PlayerSyncScNotify { + avatar_sync: Some(AvatarSync { + avatar_list: avatar_mgr.avatar_list_proto(), + }), + ..Default::default() + }, + ) + .await?; + + send_text( + session, + &format!("Successfully maxed out traces of avatar {avatar_id}"), + ) + .await +} diff --git a/gameserver/src/game/commands/mod.rs b/gameserver/src/game/commands/mod.rs new file mode 100644 index 0000000..b251193 --- /dev/null +++ b/gameserver/src/game/commands/mod.rs @@ -0,0 +1,63 @@ +use anyhow::Result; +use proto::*; + +use crate::{net::PlayerSession, util}; + +mod avatar; +mod relic; +mod scene; + +macro_rules! commands { + ($($category:ident $action:ident;)*) => { + pub async fn execute_command(command: &str, session: &PlayerSession) -> Result<()> { + let input = command[1..].split(" ").collect::>(); + + let (Some(category), Some(action)) = (input.get(0), input.get(1)) else { + return send_text(session, "Usage: /[category] [action] [arg1] [arg2] ...").await; + }; + + let args = &input[2..]; + if let Err(_) = match (*category, *action) { + $( + (stringify!($category), stringify!($action)) => { + $category::$action(args, session).await + } + )*, + _ => send_text(session, "Unknown command").await, + } { + return send_text( + session, + "Command execution failed. Re-check your input and try again.", + ) + .await; + } + + Ok(()) + } + }; +} + +commands! { + avatar max_traces; + relic give; + scene enter; +} + +async fn send_text(session: &PlayerSession, content: &str) -> Result<()> { + session + .send( + CMD_GET_PRIVATE_CHAT_HISTORY_SC_RSP, + GetPrivateChatHistoryScRsp { + contact_id: 13371337, + chat_message_list: vec![ChatMessageData { + sender_id: 13371337, + message_type: MsgType::CustomText.into(), + timestamp: util::cur_timestamp_seconds(), + content: content.to_string(), + ..Default::default() + }], + ..Default::default() + }, + ) + .await +} diff --git a/gameserver/src/game/commands/relic.rs b/gameserver/src/game/commands/relic.rs new file mode 100644 index 0000000..d29712a --- /dev/null +++ b/gameserver/src/game/commands/relic.rs @@ -0,0 +1,42 @@ +use super::*; + +const GIVE_RELIC_USAGE: &'static str = "Usage: /relic give [id] [level] [main_affix] [sub_affix_count] [sub_affix1_id] [sub_affix1_cnt] ..."; +pub async fn give(args: &[&str], session: &PlayerSession) -> Result<()> { + if args.len() < 4 { + return send_text(session, GIVE_RELIC_USAGE).await; + } + + let id = args[0].parse::()?; + let level = args[1].parse::()?; + let main_affix = args[2].parse::()?; + let sub_affix_count = args[3].parse::()?; + + if args.len() - 4 < (sub_affix_count * 2) as usize { + return send_text(session, GIVE_RELIC_USAGE).await; + } + + let mut sub_affix_params = Vec::with_capacity(sub_affix_count); + + let args = &args[4..]; + for i in 0..sub_affix_count { + let sub_affix_id = args[i * 2].parse::()?; + let sub_affix_cnt = args[i * 2 + 1].parse::()?; + + sub_affix_params.push((sub_affix_id, sub_affix_cnt)); + } + + let item_mgr = session.context.item_mgr.borrow(); + item_mgr.give_relic(id, level, main_affix, sub_affix_params)?; + + session + .send( + CMD_PLAYER_SYNC_SC_NOTIFY, + PlayerSyncScNotify { + relic_list: item_mgr.relic_list_proto(), + ..Default::default() + }, + ) + .await?; + + send_text(session, "Relic added successfully").await +} diff --git a/gameserver/src/game/commands/scene.rs b/gameserver/src/game/commands/scene.rs new file mode 100644 index 0000000..e11db4d --- /dev/null +++ b/gameserver/src/game/commands/scene.rs @@ -0,0 +1,25 @@ +use super::*; + +pub async fn enter(args: &[&str], session: &PlayerSession) -> Result<()> { + let Some(Ok(entry_id)) = args.get(0).map(|s| s.parse::()) else { + return send_text(session, "Usage: /scene enter [entry_id]").await; + }; + + let mut scene_mgr = session.context.scene_mgr.borrow_mut(); + let scene = match scene_mgr.enter_scene(entry_id) { + Ok(scene_info) => Some(scene_info), + Err(_) => return send_text(session, &format!("Failed to enter scene {entry_id}.")).await, + }; + + let lineup_mgr = session.context.lineup_mgr.borrow(); + session + .send( + CMD_ENTER_SCENE_BY_SERVER_SC_NOTIFY, + EnterSceneByServerScNotify { + scene, + lineup: Some(lineup_mgr.cur_lineup_proto()), + reason: EnterSceneReason::None.into(), + }, + ) + .await +} diff --git a/gameserver/src/game/context.rs b/gameserver/src/game/context.rs index 0971d8e..24bd323 100644 --- a/gameserver/src/game/context.rs +++ b/gameserver/src/game/context.rs @@ -16,7 +16,6 @@ pub struct GameContext { logged_in: OnceCell<()>, pub player: Arc>, pub avatar_mgr: Arc>, - pub command_mgr: Arc>, pub hero_basic_type_mgr: Arc>, pub item_mgr: Arc>, pub lineup_mgr: Arc>, @@ -38,8 +37,7 @@ impl GameContext { Self { logged_in: OnceCell::new(), player: player.clone(), - avatar_mgr: avatar_mgr.clone(), - command_mgr: Arc::new(AtomicRefCell::new(CommandManager::new(item_mgr.clone()))), + avatar_mgr, hero_basic_type_mgr: Arc::new(AtomicRefCell::new(HeroBasicTypeManager::new( player.clone(), ))), diff --git a/gameserver/src/game/managers/command.rs b/gameserver/src/game/managers/command.rs deleted file mode 100644 index ebddc4e..0000000 --- a/gameserver/src/game/managers/command.rs +++ /dev/null @@ -1,100 +0,0 @@ -use crate::{net::PlayerSession, util}; -use anyhow::Result; -use proto::*; - -use super::*; - -pub struct CommandManager { - item_mgr: Arc>, -} - -impl CommandManager { - pub fn new(item_mgr: Arc>) -> Self { - Self { item_mgr } - } - - pub async fn execute_command(&self, command: &str, session: &PlayerSession) -> Result<()> { - let input = command.split(" ").collect::>(); - - let (Some(category), Some(action)) = (input.get(0), input.get(1)) else { - return self - .send_text(session, "Usage: /[category] [action] [arg1] [arg2] ...") - .await; - }; - - let args = &input[2..]; - if let Err(_) = match (*category, *action) { - ("/relic", "give") => self.give_relic(args, session).await, - _ => self.send_text(session, "Unknown command").await, - } { - return self - .send_text( - session, - "Command execution failed. Re-check your input and try again.", - ) - .await; - } - - Ok(()) - } - - const GIVE_RELIC_USAGE: &'static str = "Usage: /relic give [id] [level] [main_affix] [sub_affix_count] [sub_affix1_id] [sub_affix1_cnt] ..."; - async fn give_relic(&self, args: &[&str], session: &PlayerSession) -> Result<()> { - if args.len() < 4 { - return self.send_text(session, Self::GIVE_RELIC_USAGE).await; - } - - let id = args[0].parse::()?; - let level = args[1].parse::()?; - let main_affix = args[2].parse::()?; - let sub_affix_count = args[3].parse::()?; - - if args.len() - 4 < (sub_affix_count * 2) as usize { - return self.send_text(session, Self::GIVE_RELIC_USAGE).await; - } - - let mut sub_affix_params = Vec::with_capacity(sub_affix_count); - - let args = &args[4..]; - for i in 0..sub_affix_count { - let sub_affix_id = args[i * 2].parse::()?; - let sub_affix_cnt = args[i * 2 + 1].parse::()?; - - sub_affix_params.push((sub_affix_id, sub_affix_cnt)); - } - - let item_mgr = self.item_mgr.borrow(); - item_mgr.give_relic(id, level, main_affix, sub_affix_params)?; - - session - .send( - CMD_PLAYER_SYNC_SC_NOTIFY, - PlayerSyncScNotify { - relic_list: item_mgr.relic_list_proto(), - ..Default::default() - }, - ) - .await?; - - self.send_text(session, "Relic added successfully").await - } - - async fn send_text(&self, session: &PlayerSession, content: &str) -> Result<()> { - session - .send( - CMD_GET_PRIVATE_CHAT_HISTORY_SC_RSP, - GetPrivateChatHistoryScRsp { - contact_id: 13371337, - chat_message_list: vec![ChatMessageData { - sender_id: 13371337, - message_type: MsgType::CustomText.into(), - timestamp: util::cur_timestamp_seconds(), - content: content.to_string(), - ..Default::default() - }], - ..Default::default() - }, - ) - .await - } -} diff --git a/gameserver/src/game/managers/mod.rs b/gameserver/src/game/managers/mod.rs index cd1f87b..799f6ae 100644 --- a/gameserver/src/game/managers/mod.rs +++ b/gameserver/src/game/managers/mod.rs @@ -3,7 +3,6 @@ use atomic_refcell::AtomicRefCell; use std::sync::{Arc, Weak}; mod avatar; -mod command; mod hero_basic_type; mod item; mod lineup; @@ -12,7 +11,6 @@ mod time; mod tutorial; pub use avatar::AvatarManager; -pub use command::CommandManager; pub use hero_basic_type::HeroBasicTypeManager; pub use item::ItemManager; pub use lineup::LineupManager; diff --git a/gameserver/src/game/mod.rs b/gameserver/src/game/mod.rs index 0caa9cf..12efb30 100644 --- a/gameserver/src/game/mod.rs +++ b/gameserver/src/game/mod.rs @@ -1,3 +1,4 @@ +pub mod commands; mod context; mod gameplay_config; pub mod managers; diff --git a/gameserver/src/net/handlers/chat.rs b/gameserver/src/net/handlers/chat.rs index 0731f1a..9586bba 100644 --- a/gameserver/src/net/handlers/chat.rs +++ b/gameserver/src/net/handlers/chat.rs @@ -1,13 +1,10 @@ -use crate::util; +use crate::{game::commands, util}; use super::*; pub async fn on_send_msg_cs_req(session: &PlayerSession, body: &SendMsgCsReq) -> Result<()> { - let command_mgr = session.context.command_mgr.borrow(); if body.message_text.starts_with("/") { - command_mgr - .execute_command(&body.message_text, session) - .await?; + commands::execute_command(&body.message_text, session).await?; } session diff --git a/gameserver/src/net/packet.rs b/gameserver/src/net/packet.rs index a08dfe6..29def30 100644 --- a/gameserver/src/net/packet.rs +++ b/gameserver/src/net/packet.rs @@ -59,7 +59,7 @@ impl NetPacket { macro_rules! trait_handler { ($($name:ident $cmd_type:expr;)*) => { - pub trait CommandHandler { + pub trait NetCommandHandler { $( paste! { async fn [](session: &PlayerSession, body: &$name) -> Result<()> { diff --git a/gameserver/src/net/session.rs b/gameserver/src/net/session.rs index 951bdd0..3391313 100644 --- a/gameserver/src/net/session.rs +++ b/gameserver/src/net/session.rs @@ -10,7 +10,7 @@ use tokio::{ use crate::game::{GameContext, PlayerInfo}; -use super::{packet::CommandHandler, NetPacket}; +use super::{packet::NetCommandHandler, NetPacket}; pub struct PlayerSession { client_socket: Arc>, @@ -82,4 +82,4 @@ impl PlayerSession { } // Auto implemented -impl CommandHandler for PlayerSession {} +impl NetCommandHandler for PlayerSession {}