diff --git a/nap_gameserver/src/commands/avatar.rs b/nap_gameserver/src/commands/avatar.rs new file mode 100644 index 0000000..d137d84 --- /dev/null +++ b/nap_gameserver/src/commands/avatar.rs @@ -0,0 +1,53 @@ +use data::tables; +use proto::{AddAvatarPerformType, AddAvatarScNotify, PlayerSyncScNotify}; + +use crate::ServerState; + +pub async fn add(args: &[&str], state: &ServerState) -> Result> { + const USAGE: &str = "Usage: avatar add [player_uid] [avatar_id]"; + + if args.len() != 2 { + return Ok(USAGE.to_string()); + } + + let uid = args[0].parse::()?; + let avatar_id = args[1].parse::()?; + + let Some(player_lock) = state.player_mgr.get_player(uid).await else { + return Ok(String::from("player not found")); + }; + + if !tables::avatar_base_template_tb::iter().any(|tmpl| tmpl.id == avatar_id) { + return Ok(format!("avatar with id {avatar_id} doesn't exist")); + } + + let (session_id, avatar_sync) = { + let mut player = player_lock.lock().await; + + player.role_model.add_avatar(avatar_id); + (player.current_session_id(), player.role_model.avatar_sync()) + }; + + if let Some(session) = session_id.map(|id| state.session_mgr.get(id)).flatten() { + session + .notify(AddAvatarScNotify { + avatar_id, + perform_type: AddAvatarPerformType::Gacha.into(), + ..Default::default() + }) + .await?; + + session + .notify(PlayerSyncScNotify { + avatar: Some(avatar_sync), + ..Default::default() + }) + .await?; + } else { + state.player_mgr.save_and_remove(uid).await; + } + + Ok(format!( + "successfully added avatar {avatar_id} to player {uid}" + )) +} diff --git a/nap_gameserver/src/commands/mod.rs b/nap_gameserver/src/commands/mod.rs index 3587842..42c87f1 100644 --- a/nap_gameserver/src/commands/mod.rs +++ b/nap_gameserver/src/commands/mod.rs @@ -5,6 +5,7 @@ use rustyline_async::{Readline, ReadlineEvent, SharedWriter}; use crate::ServerState; +mod avatar; mod player; pub struct CommandManager { @@ -80,5 +81,7 @@ impl CommandManager { commands! { player::avatar "[player_uid] [avatar_id]" "changes player avatar for main city"; player::nickname "[player_uid] [nickname]" "changes player nickname"; + player::procedure "[player_uid] [procedure_id]" "changes current beginner procedure id, parameter -1 can be used for skipping it"; + avatar::add "[player_uid] [avatar_id]" "gives avatar with specified id to player"; } } diff --git a/nap_gameserver/src/commands/player.rs b/nap_gameserver/src/commands/player.rs index 0bcefc2..812a875 100644 --- a/nap_gameserver/src/commands/player.rs +++ b/nap_gameserver/src/commands/player.rs @@ -21,7 +21,7 @@ pub async fn avatar( }; if !tables::avatar_base_template_tb::iter().any(|tmpl| tmpl.id == avatar_id) { - return Ok(format!("section with id {avatar_id} doesn't exist")); + return Ok(format!("avatar with id {avatar_id} doesn't exist")); } let should_save = { @@ -72,15 +72,13 @@ pub async fn nickname( ) }; - 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?; - } + if let Some(session) = session_id.map(|id| state.session_mgr.get(id)).flatten() { + session + .notify(PlayerSyncScNotify { + basic_info: Some(basic_info), + ..Default::default() + }) + .await?; } else { state.player_mgr.save_and_remove(uid).await; } @@ -89,3 +87,43 @@ pub async fn nickname( "successfully changed player {uid} nickname to {nickname}" )) } + +pub async fn procedure( + args: &[&str], + state: &ServerState, +) -> Result> { + const USAGE: &str = "Usage: player procedure [uid] [procedure_id]"; + + if args.len() != 2 { + return Ok(USAGE.to_string()); + } + + let uid = args[0].parse::()?; + let procedure_id = args[1].parse::()?; + + if procedure_id != -1 + && !tables::procedure_config_template_tb::iter() + .any(|tmpl| tmpl.procedure_id == procedure_id) + { + return Ok(format!("procedure_id {procedure_id} doesn't exist")); + } + + let Some(player_lock) = state.player_mgr.get_player(uid).await else { + return Ok(String::from("player not found")); + }; + + let session_id = { + let mut player = player_lock.lock().await; + player.basic_data_model.beginner_procedure_id = procedure_id; + + player.current_session_id() + }; + + if session_id.is_none() { + state.player_mgr.save_and_remove(uid).await; + } + + Ok(format!( + "successfully changed procedure_id to {procedure_id}" + )) +} diff --git a/nap_gameserver/src/logic/role/role_model.rs b/nap_gameserver/src/logic/role/role_model.rs index a1d57fd..ade7182 100644 --- a/nap_gameserver/src/logic/role/role_model.rs +++ b/nap_gameserver/src/logic/role/role_model.rs @@ -1,5 +1,4 @@ -use data::tables; -use proto::RoleModelBin; +use proto::{AvatarSync, RoleModelBin}; use crate::logic::role::Avatar; @@ -10,16 +9,34 @@ pub struct RoleModel { impl Default for RoleModel { fn default() -> Self { Self { - avatar_list: tables::avatar_base_template_tb::iter() - .map(|a| a.id) - .filter(|tmpl_id| *tmpl_id < 2000) - .map(|tmpl_id| Avatar::new(tmpl_id)) + avatar_list: Self::DEFAULT_AVATARS + .iter() + .map(|tmpl_id| Avatar::new(*tmpl_id)) .collect(), } } } impl RoleModel { + const DEFAULT_AVATARS: [u32; 2] = [1011, 1081]; + + pub fn add_avatar(&mut self, template_id: u32) { + if !self + .avatar_list + .iter() + .any(|a| a.template_id == template_id) + { + self.avatar_list.push(Avatar::new(template_id)); + } + } + + pub fn avatar_sync(&self) -> AvatarSync { + AvatarSync { + avatar_list: self.avatar_list.iter().map(Avatar::to_client).collect(), + ..Default::default() + } + } + pub fn from_bin(bin: RoleModelBin) -> Self { Self { avatar_list: bin.avatar_list.into_iter().map(Avatar::from_bin).collect(), diff --git a/nap_proto/out/_.rs b/nap_proto/out/_.rs index 32f5545..9120023 100644 --- a/nap_proto/out/_.rs +++ b/nap_proto/out/_.rs @@ -2260,7 +2260,7 @@ pub struct PlayerSyncScNotify { #[prost(message, optional, tag = "7")] pub aklfkgodkde: ::core::option::Option, #[prost(message, optional, tag = "8")] - pub hpebckigilk: ::core::option::Option, + pub avatar: ::core::option::Option, #[prost(message, optional, tag = "9")] pub oalcbialjcp: ::core::option::Option, #[prost(message, optional, tag = "10")] @@ -2865,8 +2865,8 @@ pub struct Cbjppjfbabb { #[derive(proto_gen::XorFields)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Cbegnphfokb { - #[prost(enumeration = "Nnhipbjjhpn", tag = "11")] +pub struct AddAvatarScNotify { + #[prost(enumeration = "AddAvatarPerformType", tag = "11")] pub perform_type: i32, #[prost(bool, tag = "2")] pub aobemkmdkgo: bool, @@ -13667,7 +13667,7 @@ pub struct Falmoffnjhn { #[derive(proto_gen::XorFields)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Ibgbjekpnnb { +pub struct AvatarSync { #[prost(message, repeated, tag = "11")] pub avatar_list: ::prost::alloc::vec::Vec, #[prost(uint32, repeated, tag = "14")] @@ -29107,7 +29107,7 @@ pub struct Hklkphimdcd { #[prost(enumeration = "TimePeriodType", tag = "4")] pub feanogfdcjh: i32, #[prost(enumeration = "AvatarType", tag = "5")] - pub hpebckigilk: i32, + pub avatar: i32, } #[derive(proto_gen::CmdID)] #[derive(proto_gen::XorFields)] @@ -37619,7 +37619,7 @@ impl Iojdgcmbnmj { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum Fjfehdiinkj { - Dcljkmhcfdh = 0, + None = 0, Cpehddkeocl = 1, Ceemppmehlf = 2, } @@ -37630,7 +37630,7 @@ impl Fjfehdiinkj { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Fjfehdiinkj::Dcljkmhcfdh => "FJFEHDIINKJ_DCLJKMHCFDH", + Fjfehdiinkj::None => "FJFEHDIINKJ_NONE", Fjfehdiinkj::Cpehddkeocl => "FJFEHDIINKJ_CPEHDDKEOCL", Fjfehdiinkj::Ceemppmehlf => "FJFEHDIINKJ_CEEMPPMEHLF", } @@ -37638,7 +37638,7 @@ impl Fjfehdiinkj { /// Creates an enum from field names used in the ProtoBuf definition. pub fn from_str_name(value: &str) -> ::core::option::Option { match value { - "FJFEHDIINKJ_DCLJKMHCFDH" => Some(Self::Dcljkmhcfdh), + "FJFEHDIINKJ_NONE" => Some(Self::None), "FJFEHDIINKJ_CPEHDDKEOCL" => Some(Self::Cpehddkeocl), "FJFEHDIINKJ_CEEMPPMEHLF" => Some(Self::Ceemppmehlf), _ => None, @@ -37649,29 +37649,29 @@ impl Fjfehdiinkj { #[derive(proto_gen::XorFields)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] -pub enum Nnhipbjjhpn { - Dcljkmhcfdh = 0, - Dcldpjgpkag = 1, - Kcaachafbnc = 2, +pub enum AddAvatarPerformType { + None = 0, + ShowPopup = 1, + Gacha = 2, } -impl Nnhipbjjhpn { +impl AddAvatarPerformType { /// String value of the enum field names used in the ProtoBuf definition. /// /// The values are not transformed in any way and thus are considered stable /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Nnhipbjjhpn::Dcljkmhcfdh => "NNHIPBJJHPN_DCLJKMHCFDH", - Nnhipbjjhpn::Dcldpjgpkag => "NNHIPBJJHPN_DCLDPJGPKAG", - Nnhipbjjhpn::Kcaachafbnc => "NNHIPBJJHPN_KCAACHAFBNC", + AddAvatarPerformType::None => "ADD_AVATAR_PERFORM_TYPE_NONE", + AddAvatarPerformType::ShowPopup => "ADD_AVATAR_PERFORM_TYPE_SHOW_POPUP", + AddAvatarPerformType::Gacha => "ADD_AVATAR_PERFORM_TYPE_GACHA", } } /// Creates an enum from field names used in the ProtoBuf definition. pub fn from_str_name(value: &str) -> ::core::option::Option { match value { - "NNHIPBJJHPN_DCLJKMHCFDH" => Some(Self::Dcljkmhcfdh), - "NNHIPBJJHPN_DCLDPJGPKAG" => Some(Self::Dcldpjgpkag), - "NNHIPBJJHPN_KCAACHAFBNC" => Some(Self::Kcaachafbnc), + "ADD_AVATAR_PERFORM_TYPE_NONE" => Some(Self::None), + "ADD_AVATAR_PERFORM_TYPE_SHOW_POPUP" => Some(Self::ShowPopup), + "ADD_AVATAR_PERFORM_TYPE_GACHA" => Some(Self::Gacha), _ => None, } } @@ -44829,7 +44829,7 @@ impl Cmmembfifpk { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum Onmblkkmfje { - Dcljkmhcfdh = 0, + None = 0, Njkogaelffh = 2, Dbldnilkljk = 3, Lcdlmcjihee = 4, @@ -44842,7 +44842,7 @@ impl Onmblkkmfje { /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Onmblkkmfje::Dcljkmhcfdh => "ONMBLKKMFJE_DCLJKMHCFDH", + Onmblkkmfje::None => "ONMBLKKMFJE_NONE", Onmblkkmfje::Njkogaelffh => "ONMBLKKMFJE_NJKOGAELFFH", Onmblkkmfje::Dbldnilkljk => "ONMBLKKMFJE_DBLDNILKLJK", Onmblkkmfje::Lcdlmcjihee => "ONMBLKKMFJE_LCDLMCJIHEE", @@ -44852,7 +44852,7 @@ impl Onmblkkmfje { /// Creates an enum from field names used in the ProtoBuf definition. pub fn from_str_name(value: &str) -> ::core::option::Option { match value { - "ONMBLKKMFJE_DCLJKMHCFDH" => Some(Self::Dcljkmhcfdh), + "ONMBLKKMFJE_NONE" => Some(Self::None), "ONMBLKKMFJE_NJKOGAELFFH" => Some(Self::Njkogaelffh), "ONMBLKKMFJE_DBLDNILKLJK" => Some(Self::Dbldnilkljk), "ONMBLKKMFJE_LCDLMCJIHEE" => Some(Self::Lcdlmcjihee),