diff --git a/Cargo.toml b/Cargo.toml index 51ca599..b2efcc2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,8 +23,8 @@ serde_json = "1.0" pretty_env_logger = "0.4" num-traits = "0.2" num-derive = "0.3" - pretty-hex = "0.2" +sea-orm = { version = "0.3", features = [ "sqlx-all", "runtime-async-std-native-tls" ] } [target.'cfg(windows)'.dependencies] openssl = { version = "0.10", features = ["vendored"] } diff --git a/packet-processor-macro/src/lib.rs b/packet-processor-macro/src/lib.rs index 1bcc775..ee3b898 100644 --- a/packet-processor-macro/src/lib.rs +++ b/packet-processor-macro/src/lib.rs @@ -86,6 +86,10 @@ pub fn packet_processor(args: TokenStream, input: TokenStream) -> TokenStream { return self.packet_callbacks.keys().cloned().collect(); } + fn is_supported(&self, packet_id: &proto::PacketId) -> bool { + return self.packet_callbacks.contains_key(&packet_id); + } + fn process(&mut self, user_id: u32, packet_id: proto::PacketId, metadata: Vec, data: Vec) { let callback = self.packet_callbacks.get(&packet_id); let metadata = proto::PacketHead::decode(&mut std::io::Cursor::new(metadata)).unwrap(); diff --git a/packet-processor/src/lib.rs b/packet-processor/src/lib.rs index 9117a47..6475d73 100644 --- a/packet-processor/src/lib.rs +++ b/packet-processor/src/lib.rs @@ -1,6 +1,7 @@ pub trait PacketProcessor { fn register(&mut self); fn supported(&self) -> Vec; + fn is_supported(&self, packet_id: &proto::PacketId) -> bool; fn process(&mut self, user_id: u32, packet_id: proto::PacketId, metadata: Vec, data: Vec); } @@ -30,3 +31,23 @@ macro_rules! register_callback { }; } +#[macro_export] +macro_rules! build_and_send { + ($self:ident, $user_id: ident, $metadata:ident, $id:ident { $($i:ident : $e:expr,)* }) => {{ + $self.packets_to_send_tx.send( + IpcMessage::new_from_proto( + $user_id, + proto::PacketId::$id, + $metadata, + &proto::$id { $($i: $e,)* ..proto::$id::default() } + ) + ).unwrap(); + }}; +} + +#[macro_export] +macro_rules! build { + ($id:ident { $($i:ident : $e:expr,)* }) => {{ + proto::$id { $($i: $e,)* ..proto::$id::default() } + }}; +} diff --git a/src/dbmanager/avatar_info.rs b/src/dbmanager/avatar_info.rs new file mode 100644 index 0000000..fee1bdd --- /dev/null +++ b/src/dbmanager/avatar_info.rs @@ -0,0 +1,28 @@ +// Database Manager + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "avatar_info")] +pub struct Model { + #[sea_orm(primary_key)] + pub uid: u32, + pub character_id: u32, + pub avatar_type: u8, + pub guid: u64, + pub born_time: u32, +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + _ => panic!("Unknown relation type!"), + } + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/dbmanager/avatar_team_info.rs b/src/dbmanager/avatar_team_info.rs new file mode 100644 index 0000000..3cb4140 --- /dev/null +++ b/src/dbmanager/avatar_team_info.rs @@ -0,0 +1,26 @@ +// Database Manager + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "avatar_team_info")] +pub struct Model { + #[sea_orm(primary_key)] + pub uid: u32, + pub team_id: u8, + pub guid: u64, +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + _ => panic!("Unknown relation type!"), + } + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/dbmanager/database_manager.rs b/src/dbmanager/database_manager.rs new file mode 100644 index 0000000..71cef16 --- /dev/null +++ b/src/dbmanager/database_manager.rs @@ -0,0 +1,336 @@ +// Database Manager +use std::collections::HashMap; + +use sea_orm::{entity::*, error::*, query::*, DbConn, FromQueryResult, Database}; +use sea_orm::entity::prelude::*; + +pub use super::player_info::Model as PlayerInfo; +use super::player_info::Entity as PlayerInfoEntity; + +pub use super::avatar_info::Model as AvatarInfo; +use super::avatar_info::Entity as AvatarInfoEntity; + +pub use super::scene_info::Model as SceneInfo; +use super::scene_info::Entity as SceneInfoEntity; + +pub use super::team_info::Model as TeamInfo; +use super::team_info::Entity as TeamInfoEntity; + +pub use super::avatar_team_info::Model as AvatarTeamInfo; +use super::avatar_team_info::Entity as AvatarTeamInfoEntity; + +pub use super::team_selection_info::Model as TeamSelectionInfo; +use super::team_selection_info::Entity as TeamSelectionInfoEntity; + +macro_rules! collection { + // map-like + ($($k:expr => $v:expr),* $(,)?) => {{ + use std::iter::{Iterator, IntoIterator}; + Iterator::collect(IntoIterator::into_iter([$(($k, $v),)*])) + }}; + // set-like + ($($v:expr),* $(,)?) => {{ + use std::iter::{Iterator, IntoIterator}; + Iterator::collect(IntoIterator::into_iter([$($v,)*])) + }}; +} + +trait Block { + fn wait(self) -> ::Output + where Self: Sized, Self: futures::Future + { + futures::executor::block_on(self) + } +} + +impl Block for F + where F: futures::Future +{} + +pub struct DatabaseManager { + db: DbConn, +} + +impl DatabaseManager { + pub fn new(conn_string: &str) -> Self { + return DatabaseManager { + db: Database::connect(conn_string).wait().unwrap(), + }; + } + + pub fn _get_player_info(&self, uid: u32) -> Option { + match PlayerInfoEntity::find_by_id(uid).one(&self.db).wait() { + Err(_) => { println!("DB ERROR!"); None }, + Ok(p_info) => p_info, + } + } + + pub fn get_player_info(&self, uid: u32) -> Option { + Some(PlayerInfo { + uid: uid, + nick_name: "Fapper".into(), + level: 56, + signature: "Hello world!".into(), + birthday: 0, + world_level: 8, + namecard_id: 210051, + finish_achievement_num: 42, + tower_floor_index: 1, + tower_level_index: 1, + avatar_id: 10000007, + }) + } + + pub fn get_player_props(&self, uid: u32) -> Option> { + Some(collection! { + proto::PropType::PropIsSpringAutoUse as u32 => 1, + proto::PropType::PropIsFlyable as u32 => 1, + proto::PropType::PropIsTransferable as u32 => 1, + proto::PropType::PropPlayerLevel as u32 => 56, + proto::PropType::PropPlayerExp as u32 => 1337, + proto::PropType::PropPlayerHcoin as u32 => 9001, + proto::PropType::PropPlayerScoin as u32 => 9002, + proto::PropType::PropPlayerWorldLevel as u32 => 8, + proto::PropType::PropPlayerResin as u32 => 159, + proto::PropType::PropPlayerMcoin as u32 => 9003, + proto::PropType::PropMaxStamina as u32 => 120, + proto::PropType::PropCurPersistStamina as u32 => 120, + }) + } + + pub fn get_avatar_props(&self, guid: u64) -> Option> { + let map = collection! { + proto::PropType::PropExp as u32 => 0, + proto::PropType::PropLevel as u32 => 80, + proto::PropType::PropBreakLevel as u32 => 5, + proto::PropType::PropSatiationVal as u32 => 0, + proto::PropType::PropSatiationPenaltyTime as u32 => 0, + }; + + return Some(map); + } + + pub fn get_avatar_equip(&self, guid: u64) -> Option> { + let equip = vec![Self::SPOOFED_WEAPON_GUID]; + + return Some(equip); + } + + pub fn get_skill_levels(&self, guid: u64) -> Option> { + let map = collection! { + 10068 => 3, + 100553 => 3, + 10067 => 3, + }; + + return Some(map); + } + + pub fn get_avatar_fight_props(&self, guid: u64) -> Option> { + let map = collection! { + proto::FightPropType::FightPropBaseHp as u32 => 9000.0, + proto::FightPropType::FightPropHp as u32 => 3000.0, + proto::FightPropType::FightPropHpPercent as u32 => 0.0746000, + + proto::FightPropType::FightPropBaseAttack as u32 => 600.0, + proto::FightPropType::FightPropAttack as u32 => 50.0, + proto::FightPropType::FightPropAttackPercent as u32 => 0.40, + + proto::FightPropType::FightPropBaseDefense as u32 => 600.0, + proto::FightPropType::FightPropDefense as u32 => 40.0, + proto::FightPropType::FightPropDefensePercent as u32 => 0.04, + + proto::FightPropType::FightPropCritical as u32 => 0.99, + proto::FightPropType::FightPropAntiCritical as u32 => 0.00000, + proto::FightPropType::FightPropCriticalHurt as u32 => 0.99, + proto::FightPropType::FightPropChargeEfficiency as u32 => 1.337, + + proto::FightPropType::FightPropHealAdd as u32 => 0.00000, + proto::FightPropType::FightPropHealedAdd as u32 => 0.00000, + proto::FightPropType::FightPropElementMastery as u32 => 42.0, + + proto::FightPropType::FightPropPhysicalSubHurt as u32 => 0.00000, + proto::FightPropType::FightPropPhysicalAddHurt as u32 => 0.271828, + + proto::FightPropType::FightPropFireAddHurt as u32 => 0.00000, + proto::FightPropType::FightPropElecAddHurt as u32 => 0.00000, + proto::FightPropType::FightPropWaterAddHurt as u32 => 0.00000, + proto::FightPropType::FightPropGrassAddHurt as u32 => 0.00000, + proto::FightPropType::FightPropWindAddHurt as u32 => 0.00000, + proto::FightPropType::FightPropRockAddHurt as u32 => 0.00000, + proto::FightPropType::FightPropIceAddHurt as u32 => 0.00000, + + proto::FightPropType::FightPropFireSubHurt as u32 => 0.00000, + proto::FightPropType::FightPropElecSubHurt as u32 => 0.00000, + proto::FightPropType::FightPropWaterSubHurt as u32 => 0.00000, + proto::FightPropType::FightPropGrassSubHurt as u32 => 0.00000, + proto::FightPropType::FightPropWindSubHurt as u32 => 0.00000, + proto::FightPropType::FightPropRockSubHurt as u32 => 0.00000, + proto::FightPropType::FightPropIceSubHurt as u32 => 0.00000, + + proto::FightPropType::FightPropMaxWindEnergy as u32 => 60.0000, + + proto::FightPropType::FightPropCurWindEnergy as u32 => 60.0000, + + proto::FightPropType::FightPropCurHp as u32 => 10000.0, + + proto::FightPropType::FightPropMaxHp as u32 => 12000.0, + proto::FightPropType::FightPropCurAttack as u32 => 900.0, + proto::FightPropType::FightPropCurDefense as u32 => 700.0, + proto::FightPropType::FightPropCurSpeed as u32 => 10.00000, + }; + + return Some(map); + } + + pub fn get_open_state(&self, uid: u32) -> Option> { + Some(collection! { + proto::OpenStateType::OpenStatePaimon as u32 => 1, + + proto::OpenStateType::OpenStatePlayerLvupGuide as u32 => 1, + + proto::OpenStateType::OpenStateGacha as u32 => 1, + proto::OpenStateType::OpenStateGuideGacha as u32 => 1, + + proto::OpenStateType::OpenStateGuideTeam as u32 => 1, + + proto::OpenStateType::OpenStateGuideBag as u32 => 1, + + proto::OpenStateType::OpenStateLimitRegionFreshmeat as u32 => 1, + proto::OpenStateType::OpenStateLimitRegionGlobal as u32 => 1, + proto::OpenStateType::OpenStateMultiplayer as u32 => 0, + + proto::OpenStateType::OpenStateAvatarFashion as u32 => 1, + + proto::OpenStateType::OpenStateGuideAppearance as u32 => 1, + + proto::OpenStateType::OpenStateShopTypeMall as u32 => 1, // 900 + proto::OpenStateType::OpenStateShopTypeRecommanded as u32 => 1, // 901 + proto::OpenStateType::OpenStateShopTypeGenesiscrystal as u32 => 1, // 902 + proto::OpenStateType::OpenStateShopTypeGiftpackage as u32 => 1, // 903 + + proto::OpenStateType::OpenAdventureManual as u32 => 1, // 1100 + proto::OpenStateType::OpenAdventureManualMonster as u32 => 1, // 1103 + proto::OpenStateType::OpenAdventureManualBossDungeon as u32 => 1, // 1104 + + proto::OpenStateType::OpenStateMengdeInfusedcrystal as u32 => 1, + proto::OpenStateType::OpenStateLiyueInfusedcrystal as u32 => 1, + proto::OpenStateType::OpenStateInazumaMainquestFinished as u32 => 1, + }) + } + + pub fn get_inventory(&self, uid: u32) -> Option> { + let mut weapon = proto::Weapon::default(); + weapon.level = 70; + weapon.promote_level = 4; + weapon.affix_map = collection!{111406 => 0}; + + let mut equip = proto::Equip::default(); + equip.is_locked = true; + equip.detail = Some(proto::equip::Detail::Weapon(weapon)); + + let mut item = proto::Item::default(); + item.item_id = 11406; + item.guid = Self::SPOOFED_WEAPON_GUID; + item.detail = Some(proto::item::Detail::Equip(equip)); + + return Some(vec![item]); + } + + pub fn get_avatars(&self, uid: u32) -> Option> { + let ai = AvatarInfo { + uid: uid, + character_id: 7, + avatar_type: 1, + guid: Self::SPOOFED_AVATAR_GUID, + born_time: 1633790000, + }; + + return Some(vec![ai]); + } + + pub fn get_player_scene_info(&self, uid: u32) -> Option { + let si = SceneInfo { + uid: uid, + scene_id: Self::SPOOFED_SCENE_ID, + scene_token: Self::SPOOFED_SCENE_TOKEN, + pos_x: -3400.0, + pos_y: 233.0, + pos_z: 3427.6, + }; + + return Some(si); + } + + pub fn get_player_teams(&self, uid: u32) -> Option> { + let t1 = TeamInfo { + uid: uid.clone(), + id: 1, + name: "Team 1".to_string(), + }; + + let t2 = TeamInfo { + uid: uid.clone(), + id: 2, + name: "Team 2".to_string(), + }; + + let t3 = TeamInfo { + uid: uid.clone(), + id: 3, + name: "Team 3".to_string(), + }; + + let t4 = TeamInfo { + uid: uid.clone(), + id: 4, + name: "Team 4".to_string(), + }; + + return Some(vec![t1, t2, t3, t4]); + } + + pub fn get_player_teams_avatars(&self, uid: u32) -> Option> { + let a1 = AvatarTeamInfo { + uid: uid.clone(), + team_id: 1, + guid: Self::SPOOFED_AVATAR_GUID, + }; + + let a2 = AvatarTeamInfo { + uid: uid.clone(), + team_id: 2, + guid: Self::SPOOFED_AVATAR_GUID, + }; + + let a3 = AvatarTeamInfo { + uid: uid.clone(), + team_id: 3, + guid: Self::SPOOFED_AVATAR_GUID, + }; + + let a4 = AvatarTeamInfo { + uid: uid.clone(), + team_id: 4, + guid: Self::SPOOFED_AVATAR_GUID, + }; + + return Some(vec![a1, a2, a3, a4]); + } + + pub fn get_player_team_selection(&self, uid: u32) -> Option { + let tsi = TeamSelectionInfo { + uid: uid.clone(), + avatar: Self::SPOOFED_AVATAR_GUID, + team: 1, + }; + + return Some(tsi); + } + + const BASE_GUID: u64 = 0x2400000000000000; + const SPOOFED_AVATAR_GUID: u64 = Self::BASE_GUID + 1; + const SPOOFED_WEAPON_GUID: u64 = Self::BASE_GUID + 2; + const SPOOFED_SCENE_ID: u32 = 3; + const SPOOFED_SCENE_TOKEN: u32 = 0x1234; +} diff --git a/src/dbmanager/mod.rs b/src/dbmanager/mod.rs new file mode 100644 index 0000000..49769aa --- /dev/null +++ b/src/dbmanager/mod.rs @@ -0,0 +1,10 @@ +pub mod database_manager; + +pub use self::database_manager::DatabaseManager; + +mod player_info; +mod avatar_info; +mod scene_info; +mod avatar_team_info; +mod team_info; +mod team_selection_info; diff --git a/src/dbmanager/player_info.rs b/src/dbmanager/player_info.rs new file mode 100644 index 0000000..7610a8e --- /dev/null +++ b/src/dbmanager/player_info.rs @@ -0,0 +1,34 @@ +// Database Manager + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "player_info")] +pub struct Model { + #[sea_orm(primary_key)] + pub uid: u32, + pub nick_name: String, + pub level: u8, + pub signature: String, + pub birthday: u32, + pub world_level: u8, + pub namecard_id: u32, + pub finish_achievement_num: u32, + pub tower_floor_index: u8, + pub tower_level_index: u8, + pub avatar_id: u32, +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + _ => panic!("Unknown relation type!"), + } + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/dbmanager/scene_info.rs b/src/dbmanager/scene_info.rs new file mode 100644 index 0000000..3c07ec0 --- /dev/null +++ b/src/dbmanager/scene_info.rs @@ -0,0 +1,29 @@ +// Database Manager + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "scene_info")] +pub struct Model { + #[sea_orm(primary_key)] + pub uid: u32, + pub scene_id: u32, + pub scene_token: u32, + pub pos_x: f32, + pub pos_y: f32, + pub pos_z: f32, +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + _ => panic!("Unknown relation type!"), + } + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/dbmanager/team_info.rs b/src/dbmanager/team_info.rs new file mode 100644 index 0000000..5fc4f84 --- /dev/null +++ b/src/dbmanager/team_info.rs @@ -0,0 +1,26 @@ +// Database Manager + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "team_info")] +pub struct Model { + #[sea_orm(primary_key)] + pub uid: u32, + pub id: u8, + pub name: String, +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + _ => panic!("Unknown relation type!"), + } + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/dbmanager/team_selection_info.rs b/src/dbmanager/team_selection_info.rs new file mode 100644 index 0000000..a3e5035 --- /dev/null +++ b/src/dbmanager/team_selection_info.rs @@ -0,0 +1,26 @@ +// Database Manager + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] +#[sea_orm(table_name = "team_selection_info")] +pub struct Model { + #[sea_orm(primary_key)] + pub uid: u32, + pub avatar: u64, + pub team: u8, +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + _ => panic!("Unknown relation type!"), + } + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/jsonmanager/avatar_skill_depot.rs b/src/jsonmanager/avatar_skill_depot.rs new file mode 100644 index 0000000..e73b2ff --- /dev/null +++ b/src/jsonmanager/avatar_skill_depot.rs @@ -0,0 +1,24 @@ +use serde::{Serialize, Deserialize}; + +#[serde(rename_all="PascalCase")] +#[derive(Serialize,Deserialize, Clone)] +pub struct ProudSkillOpenConfig { + pub proud_skill_group_id: Option, + pub need_avatar_promote_level: Option, +} + +#[serde(rename_all="PascalCase")] +#[derive(Serialize, Deserialize, Clone)] +pub struct AvatarSkillDepot { + pub id: u32, + pub energy_skill: Option, + pub skills: Vec, + pub sub_skills: Vec, + pub extra_abilities: Vec, + pub talents: Vec, + pub talent_star_name: String, + pub inherent_proud_skill_opens: Vec, + pub skill_depot_ability_group: String, + pub leader_talent: Option, + pub attack_mode_skill: Option, +} diff --git a/src/jsonmanager/json_manager.rs b/src/jsonmanager/json_manager.rs new file mode 100644 index 0000000..211a1fc --- /dev/null +++ b/src/jsonmanager/json_manager.rs @@ -0,0 +1,49 @@ +use std::fs::read_to_string; // use instead of std::fs::File +use std::path::Path; +use std::collections::HashMap; + +use serde::Deserialize; +use serde::de::DeserializeOwned; + +use super::avatar_skill_depot::AvatarSkillDepot; + +struct JsonReader { + base_path: String, +} + +pub struct JsonManager { + reader: JsonReader, + pub avatar_skill_depot: HashMap, +} + +impl JsonManager { + pub fn new(directory: &str) -> JsonManager { + let reader = JsonReader::new(directory); + + let asd: Vec = reader.read_json_list("AvatarSkillDepot"); + + return JsonManager { + reader: reader, + avatar_skill_depot: asd.into_iter().map(|a| (a.id, a)).collect(), + }; + } +} + +impl JsonReader { + pub fn new(directory: &str) -> JsonReader { + return JsonReader { + base_path: directory.to_owned(), + }; + } + + fn read_json_list(&self, name: &str) -> Vec + where T: DeserializeOwned + { + let path = format!("{}/{}ExcelConfigData.json", self.base_path, name); + + let json_file_path = Path::new(&path); + let json_file_str = read_to_string(json_file_path).unwrap_or_else(|_| panic!("File {} not found", path)); + let data: Vec = serde_json::from_str(&json_file_str).expect("Error while reading json"); + return data; + } +} diff --git a/src/jsonmanager/mod.rs b/src/jsonmanager/mod.rs new file mode 100644 index 0000000..4266719 --- /dev/null +++ b/src/jsonmanager/mod.rs @@ -0,0 +1,5 @@ +mod json_manager; + +pub use self::json_manager::JsonManager; + +mod avatar_skill_depot; diff --git a/src/main.rs b/src/main.rs index 04ad366..c895db2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,9 +7,13 @@ use std::thread; mod server; mod utils; +mod dbmanager; +mod jsonmanager; use server::NetworkServer; use server::DispatchServer; +use dbmanager::DatabaseManager; +use jsonmanager::JsonManager; fn main() { pretty_env_logger::init(); diff --git a/src/server/client_connection.rs b/src/server/client_connection.rs index 1f0f053..4c45830 100644 --- a/src/server/client_connection.rs +++ b/src/server/client_connection.rs @@ -7,6 +7,8 @@ use std::io::Write; use std::time::SystemTime; use std::convert::TryInto; +use crate::utils::TimeManager; + extern crate kcp; extern crate mhycrypt; @@ -106,7 +108,7 @@ impl ClientConnection { } fn elapsed_time_millis(&self) -> u32 { - return SystemTime::now().duration_since(self.established_time).unwrap().as_millis().try_into().unwrap(); + return TimeManager::duration_since(self.established_time).try_into().unwrap(); } pub fn send_udp_packet(&mut self, data: &[u8]) { diff --git a/src/server/game_server.rs b/src/server/game_server.rs index c531845..4b2ef61 100644 --- a/src/server/game_server.rs +++ b/src/server/game_server.rs @@ -7,18 +7,29 @@ use crate::server::GameWorld; use packet_processor::PacketProcessor; use crate::server::IpcMessage; +use crate::DatabaseManager; +use crate::JsonManager; +use crate::server::LoginManager; +use std::sync::Arc; + pub struct GameServer { packets_to_process_rx: mpsc::Receiver, packets_to_send_tx: mpsc::Sender, worlds: HashMap, + login_manager: LoginManager, } impl GameServer { pub fn new(packets_to_process_rx: mpsc::Receiver, packets_to_send_tx: mpsc::Sender) -> GameServer { + let db = DatabaseManager::new("sqlite://./database.db3"); + let jm = JsonManager::new("./json"); + let lm = LoginManager::new(Arc::new(db), Arc::new(jm), packets_to_send_tx.clone()); + let gs = GameServer { packets_to_process_rx: packets_to_process_rx, packets_to_send_tx: packets_to_send_tx, worlds: HashMap::new(), + login_manager: lm, }; return gs; @@ -34,17 +45,21 @@ impl GameServer { loop { let IpcMessage(user_id, packet_id, metadata, data) = self.packets_to_process_rx.recv().unwrap(); - - // TODO: each user_id will have a distinct world! - let world = match self.worlds.entry(user_id) { - Occupied(world) => world.into_mut(), - Vacant(entry) => { - let mut world = GameWorld::new(self.packets_to_send_tx.clone()); - entry.insert(world) - }, - }; - world.process(user_id, packet_id, metadata, data); + if (self.login_manager.is_supported(&packet_id)) { + self.login_manager.process(user_id, packet_id, metadata, data); + } else { + // TODO: each user_id will have a distinct world! + let world = match self.worlds.entry(user_id) { + Occupied(world) => world.into_mut(), + Vacant(entry) => { + let mut world = GameWorld::new(self.packets_to_send_tx.clone()); + entry.insert(world) + }, + }; + + world.process(user_id, packet_id, metadata, data); + } } } } diff --git a/src/server/game_world.rs b/src/server/game_world.rs index 1059ed4..cb28692 100644 --- a/src/server/game_world.rs +++ b/src/server/game_world.rs @@ -24,28 +24,8 @@ macro_rules! collection { }}; } -macro_rules! build_and_send { - ($id:ident, $self:ident, $user_id: ident, $metadata:ident, { $($i:ident : $e:expr,)* }) => {{ - $self.packets_to_send_tx.send( - IpcMessage::new_from_proto( - $user_id, - proto::PacketId::$id, - $metadata, - &proto::$id { $($i: $e,)* ..proto::$id::default() } - ) - ).unwrap(); - }}; -} - -macro_rules! build { - ($id:ident, { $($i:ident : $e:expr,)* }) => {{ - proto::$id { $($i: $e,)* ..proto::$id::default() } - }}; -} - #[packet_processor( PingReq, - PlayerLoginReq, GetPlayerSocialDetailReq, EnterSceneReadyReq, SceneInitFinishReq, @@ -63,7 +43,7 @@ impl GameWorld { const SPOOFED_AVATAR_GUID: u64 = GameWorld::BASE_GUID + 1; const SPOOFED_WEAPON_EID: u32 = 0x6000000 + 146; const SPOOFED_WEAPON_GUID: u64 = GameWorld::BASE_GUID + 2; - const SPOOFED_SCENE_TOKEN: u32 = 1234; + const SPOOFED_SCENE_TOKEN: u32 = 0x1234; const SPOOFED_SCENE_ID: u32 = 3; pub fn new(packets_to_send_tx: mpsc::Sender) -> GameWorld { @@ -81,82 +61,31 @@ impl GameWorld { rsp.client_time = req.client_time; } - fn process_player_login(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::PlayerLoginReq, rsp: &mut proto::PlayerLoginRsp) { - build_and_send! ( PlayerDataNotify, self, user_id, metadata, - { nick_name: "Fapper".into(), server_time: self.timestamp(), prop_map: self.spoof_player_props(), } - ); - - build_and_send! ( OpenStateUpdateNotify, self, user_id, metadata, - { open_state_map: self.spoof_world_props(), } - ); - - build_and_send! (StoreWeightLimitNotify, self, user_id, metadata, - { - store_type: proto::StoreType::StorePack as i32, - weight_limit: 30000, - material_count_limit: 2000, - weapon_count_limit: 2000, - reliquary_count_limit: 1000, - furniture_count_limit: 2000, - } - ); - - build_and_send! (PlayerStoreNotify, self, user_id, metadata, - {store_type: proto::StoreType::StorePack as i32, weight_limit: 30000, item_list: self.spoof_inventory(),} - ); - - build_and_send! (AvatarDataNotify, self, user_id, metadata, - { - avatar_list: vec![self.spoof_default_avatar2()], - avatar_team_map: self.spoof_team_map(), - cur_avatar_team_id: 2, - choose_avatar_guid: GameWorld::SPOOFED_AVATAR_GUID, - } - ); - - build_and_send! (PlayerEnterSceneNotify, self, user_id, metadata, - { - scene_id: GameWorld::SPOOFED_SCENE_ID, - r#type: proto::EnterType::EnterSelf as i32, - scene_begin_time: self.timestamp(), - pos: Some(proto::Vector {x: -3400.0, y: 203.0, z: -3427.60}), - target_uid: user_id, - world_level: 8, - enter_scene_token: GameWorld::SPOOFED_SCENE_TOKEN, - //enter_reason: 1, - } - ); - } - fn process_get_player_social_detail(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::GetPlayerSocialDetailReq, rsp: &mut proto::GetPlayerSocialDetailRsp) { - let avatar_info = build!(SocialShowAvatarInfo, - { - avatar_id: 10000007, - level: 80, - } - ); + let avatar_info = build!(SocialShowAvatarInfo { + avatar_id: 10000007, + level: 80, + }); - let details = build!(SocialDetail, - { - uid: user_id, - nickname: "Fukker".to_string(), - level: 56, - avatar_id: 10000007, - signature: "Fuck you".to_string(), - birthday: Some(proto::Birthday {month: 2, day: 11}), - world_level: 8, - online_state: proto::FriendOnlineState::FriendOnline as i32, - is_friend: true, - is_mp_mode_available: true, - name_card_id: 210051, - finish_achievement_num: 42, - tower_floor_index: 1, - tower_level_index: 1, - show_avatar_info_list: vec![avatar_info], // TODO - show_name_card_id_list: vec![210051], - // Field 25! - } - ); + let details = build!(SocialDetail { + uid: user_id, + nickname: "Fukker".to_string(), + level: 56, + avatar_id: 10000007, + signature: "Fuck you".to_string(), + birthday: Some(proto::Birthday {month: 2, day: 11}), + world_level: 8, + online_state: proto::FriendOnlineState::FriendOnline as i32, + is_friend: true, + is_mp_mode_available: true, + name_card_id: 210051, + finish_achievement_num: 42, + tower_floor_index: 1, + tower_level_index: 1, + show_avatar_info_list: vec![avatar_info], // TODO + show_name_card_id_list: vec![210051], + // Field 25! + }); rsp.detail_data = Some(details); } @@ -164,107 +93,91 @@ impl GameWorld { fn process_enter_scene_ready(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::EnterSceneReadyReq, rsp: &mut proto::EnterSceneReadyRsp) { rsp.enter_scene_token = req.enter_scene_token; - build_and_send!(EnterScenePeerNotify, self, user_id, metadata, - { - dest_scene_id: GameWorld::SPOOFED_SCENE_ID, - peer_id: 1, - host_peer_id: 1, - enter_scene_token: GameWorld::SPOOFED_SCENE_TOKEN, - } - ); + build_and_send!(self, user_id, metadata, EnterScenePeerNotify { + dest_scene_id: GameWorld::SPOOFED_SCENE_ID, + peer_id: 1, + host_peer_id: 1, + enter_scene_token: GameWorld::SPOOFED_SCENE_TOKEN, + }); } fn process_scene_init_finish(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::SceneInitFinishReq, rsp: &mut proto::SceneInitFinishRsp) { rsp.enter_scene_token = GameWorld::SPOOFED_SCENE_TOKEN; - build_and_send!(WorldDataNotify, self, user_id, metadata, - { world_prop_map: self.remap(&collection!{1 => 8, 2 => 0}), } - ); + build_and_send!(self, user_id, metadata, WorldDataNotify { + world_prop_map: self.remap(&collection!{1 => 8, 2 => 0}), + }); - let online_player_info = build!(OnlinePlayerInfo, - { - uid: user_id, - nickname: "Fukker".to_string(), - player_level: 56, - avatar_id: 10000007, - mp_setting_type: proto::MpSettingType::MpSettingEnterAfterApply as i32, - cur_player_num_in_world: 1, - world_level: 8, - name_card_id: 210051, - signature: "Fuck you!".to_string(), - // TODO: Field 12! - } - ); + let online_player_info = build!(OnlinePlayerInfo { + uid: user_id, + nickname: "Fukker".to_string(), + player_level: 56, + avatar_id: 10000007, + mp_setting_type: proto::MpSettingType::MpSettingEnterAfterApply as i32, + cur_player_num_in_world: 1, + world_level: 8, + name_card_id: 210051, + signature: "Fuck you!".to_string(), + // TODO: Field 12! + }); - build_and_send!(WorldPlayerInfoNotify, self, user_id, metadata, - { - player_info_list: vec![online_player_info.clone()], - player_uid_list: vec![user_id], - } - ); + build_and_send!(self, user_id, metadata, WorldPlayerInfoNotify { + player_info_list: vec![online_player_info.clone()], + player_uid_list: vec![user_id], + }); - let scene_player_info_e = build!(ScenePlayerInfo, - { - uid: user_id, - peer_id: 1, - name: "Fukker".to_string(), - scene_id: GameWorld::SPOOFED_SCENE_ID, - online_player_info: Some(online_player_info), - } - ); + let scene_player_info_e = build!(ScenePlayerInfo { + uid: user_id, + peer_id: 1, + name: "Fukker".to_string(), + scene_id: GameWorld::SPOOFED_SCENE_ID, + online_player_info: Some(online_player_info), + }); - build_and_send!(ScenePlayerInfoNotify, self, user_id, metadata, - { - player_info_list: vec![scene_player_info_e], - } - ); + build_and_send!(self, user_id, metadata, ScenePlayerInfoNotify { + player_info_list: vec![scene_player_info_e], + }); - let avatar_enter_info = build!(AvatarEnterSceneInfo, - { - avatar_guid: GameWorld::SPOOFED_AVATAR_GUID, - avatar_entity_id: GameWorld::SPOOFED_AVATAR_EID, - weapon_guid: GameWorld::SPOOFED_WEAPON_GUID, - weapon_entity_id: GameWorld::SPOOFED_WEAPON_EID, - } - ); - let mp_level_info = build!(MpLevelEntityInfo, - { - entity_id: 0xb000000 + 146, - authority_peer_id: 1, - } - ); - let team_enter_info = build!(TeamEnterSceneInfo, { team_entity_id: 0x9000000 + 1, }); + let avatar_enter_info = build!(AvatarEnterSceneInfo { + avatar_guid: GameWorld::SPOOFED_AVATAR_GUID, + avatar_entity_id: GameWorld::SPOOFED_AVATAR_EID, + weapon_guid: GameWorld::SPOOFED_WEAPON_GUID, + weapon_entity_id: GameWorld::SPOOFED_WEAPON_EID, + }); + let mp_level_info = build!(MpLevelEntityInfo { + entity_id: 0xb000000 + 146, + authority_peer_id: 1, + }); + let team_enter_info = build!(TeamEnterSceneInfo { team_entity_id: 0x9000000 + 1, }); - build_and_send!(PlayerEnterSceneInfoNotify, self, user_id, metadata, - { - enter_scene_token: GameWorld::SPOOFED_SCENE_TOKEN, - avatar_enter_info: vec![avatar_enter_info], - cur_avatar_entity_id: GameWorld::SPOOFED_AVATAR_EID, - mp_level_entity_info: Some(mp_level_info), - team_enter_info: Some(team_enter_info), - } - ); + build_and_send!(self, user_id, metadata, PlayerEnterSceneInfoNotify { + enter_scene_token: GameWorld::SPOOFED_SCENE_TOKEN, + avatar_enter_info: vec![avatar_enter_info], + cur_avatar_entity_id: GameWorld::SPOOFED_AVATAR_EID, + mp_level_entity_info: Some(mp_level_info), + team_enter_info: Some(team_enter_info), + }); - build_and_send!(PlayerGameTimeNotify, self, user_id, metadata, { + build_and_send!(self, user_id, metadata, PlayerGameTimeNotify { game_time: 5*60*60, uid: user_id, }); - build_and_send!(SceneTimeNotify, self, user_id, metadata, { + build_and_send!(self, user_id, metadata, SceneTimeNotify { scene_id: GameWorld::SPOOFED_SCENE_ID, scene_time: 9000, }); - build_and_send!(SceneDataNotify, self, user_id, metadata, { + build_and_send!(self, user_id, metadata, SceneDataNotify { level_config_name_list: vec!["Level_BigWorld".to_string()], }); - build_and_send!(HostPlayerNotify, self, user_id, metadata, { + build_and_send!(self, user_id, metadata, HostPlayerNotify { host_uid: user_id, host_peer_id: 1, }); - let scene_team_avatar = build!(SceneTeamAvatar, { + let scene_team_avatar = build!(SceneTeamAvatar { scene_id: GameWorld::SPOOFED_SCENE_ID, player_uid: user_id, avatar_guid: GameWorld::SPOOFED_AVATAR_GUID, @@ -275,7 +188,7 @@ impl GameWorld { scene_entity_info: Some(self.spoof_scene_default_avatar(user_id)), ability_control_block: Some(self.spoof_default_abilities()), }); - build_and_send!(SceneTeamUpdateNotify, self, user_id, metadata, { + build_and_send!(self, user_id, metadata, SceneTeamUpdateNotify { scene_team_avatar_list: vec![scene_team_avatar], }); } @@ -283,7 +196,7 @@ impl GameWorld { fn process_enter_scene_done(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::EnterSceneDoneReq, rsp: &mut proto::EnterSceneDoneRsp) { rsp.enter_scene_token = req.enter_scene_token; - build_and_send!(SceneEntityAppearNotify, self, user_id, metadata, { + build_and_send!(self, user_id, metadata, SceneEntityAppearNotify { entity_list: vec![self.spoof_scene_default_avatar(user_id)], appear_type: proto::VisionType::VisionBorn as i32, }); @@ -299,13 +212,13 @@ impl GameWorld { } fn spoof_scene_default_avatar(&self, user_id: u32) -> proto::SceneEntityInfo { - let motion_info = build!(MotionInfo, { - pos: Some(proto::Vector {x: -3400.0, y: 203.0, z: -3427.0}), + let motion_info = build!(MotionInfo { + pos: Some(proto::Vector {x: -3400.0, y: 233.0, z: -3427.0}), rot: Some(proto::Vector::default()), speed: Some(proto::Vector::default()), }); - let weapon = build!(SceneWeaponInfo, { + let weapon = build!(SceneWeaponInfo { entity_id: GameWorld::SPOOFED_WEAPON_EID, gadget_id: 50011406, // TODO! item_id: 11406, @@ -315,7 +228,7 @@ impl GameWorld { affix_map: collection! { 111406 => 0 }, }); - let scene_avatar_info = build!(SceneAvatarInfo, { + let scene_avatar_info = build!(SceneAvatarInfo { uid: user_id, avatar_id: 10000007, guid: GameWorld::SPOOFED_AVATAR_GUID, @@ -330,13 +243,13 @@ impl GameWorld { weapon: Some(weapon), }); - let scene_ai_info = build!(SceneEntityAiInfo, { + let scene_ai_info = build!(SceneEntityAiInfo { is_ai_open: true, born_pos: Some(proto::Vector::default()), }); - let authority_info = build!(EntityAuthorityInfo, { ai_info: Some(scene_ai_info), }); + let authority_info = build!(EntityAuthorityInfo { ai_info: Some(scene_ai_info), }); - let scene_entity_info = build!(SceneEntityInfo, { + let scene_entity_info = build!(SceneEntityInfo { entity_type: proto::ProtEntityType::ProtEntityAvatar as i32, entity_id: GameWorld::SPOOFED_AVATAR_EID, life_state: 1, @@ -350,99 +263,6 @@ impl GameWorld { return scene_entity_info; } - fn spoof_default_avatar2(&self) -> proto::AvatarInfo { - let mut avatar_info = build!(AvatarInfo, { - avatar_id: 10000007, - avatar_type: 1, - guid: GameWorld::SPOOFED_AVATAR_GUID, - skill_depot_id: 704, - born_time: 1633790000, - talent_id_list: vec![71, 72, 73, 74, 75, 76], - prop_map: self.spoof_avatar_props(), - fight_prop_map: self.spoof_avatar_fight_props(), - fetter_info: Some(self.spoof_fetter_info()), - equip_guid_list: vec![GameWorld::SPOOFED_WEAPON_GUID], - inherent_proud_skill_list: vec![72101, 72201], - skill_level_map: collection!{100553 => 3, 10067 => 3, 10068 => 3}, - proud_skill_extra_level_map: collection!{739 => 3, 732 => 3}, - }); - - return avatar_info; - } - - fn spoof_team_map(&self) -> HashMap { - let at = build!(AvatarTeam, { - team_name: "Fuck yea".to_string(), - avatar_guid_list: vec![GameWorld::SPOOFED_AVATAR_GUID], - }); - - return collection! { - 1 => at.clone(), - 2 => at.clone(), - 3 => at.clone(), - 4 => at.clone(), - }; - } - - fn spoof_player_props(&self) -> HashMap { - // TODO: fill! - let map = collection! { - proto::PropType::PropIsSpringAutoUse as u32 => 1, - proto::PropType::PropIsFlyable as u32 => 1, - proto::PropType::PropIsTransferable as u32 => 1, - proto::PropType::PropPlayerLevel as u32 => 56, - proto::PropType::PropPlayerExp as u32 => 1337, - proto::PropType::PropPlayerHcoin as u32 => 9001, - proto::PropType::PropPlayerScoin as u32 => 9002, - proto::PropType::PropPlayerWorldLevel as u32 => 8, - proto::PropType::PropPlayerResin as u32 => 159, - proto::PropType::PropPlayerMcoin as u32 => 9003, - proto::PropType::PropMaxStamina as u32 => 120, - proto::PropType::PropCurPersistStamina as u32 => 120, - }; - - return self.remap(&map); - } - - fn spoof_world_props(&self) -> HashMap { - // TODO: fill! - let map = collection! { - proto::OpenStateType::OpenStatePaimon as u32 => 1, - - proto::OpenStateType::OpenStatePlayerLvupGuide as u32 => 1, - - proto::OpenStateType::OpenStateGacha as u32 => 1, - proto::OpenStateType::OpenStateGuideGacha as u32 => 1, - - proto::OpenStateType::OpenStateGuideTeam as u32 => 1, - - proto::OpenStateType::OpenStateGuideBag as u32 => 1, - - proto::OpenStateType::OpenStateLimitRegionFreshmeat as u32 => 1, - proto::OpenStateType::OpenStateLimitRegionGlobal as u32 => 1, - proto::OpenStateType::OpenStateMultiplayer as u32 => 0, - - proto::OpenStateType::OpenStateAvatarFashion as u32 => 1, - - proto::OpenStateType::OpenStateGuideAppearance as u32 => 1, - - proto::OpenStateType::OpenStateShopTypeMall as u32 => 1, // 900 - proto::OpenStateType::OpenStateShopTypeRecommanded as u32 => 1, // 901 - proto::OpenStateType::OpenStateShopTypeGenesiscrystal as u32 => 1, // 902 - proto::OpenStateType::OpenStateShopTypeGiftpackage as u32 => 1, // 903 - - proto::OpenStateType::OpenAdventureManual as u32 => 1, // 1100 - proto::OpenStateType::OpenAdventureManualMonster as u32 => 1, // 1103 - proto::OpenStateType::OpenAdventureManualBossDungeon as u32 => 1, // 1104 - - proto::OpenStateType::OpenStateMengdeInfusedcrystal as u32 => 1, - proto::OpenStateType::OpenStateLiyueInfusedcrystal as u32 => 1, - proto::OpenStateType::OpenStateInazumaMainquestFinished as u32 => 1, - }; - - return map; - } - fn spoof_avatar_props_raw(&self) -> HashMap { // TODO: fill! let map = collection! { @@ -456,13 +276,6 @@ impl GameWorld { return map; } - fn spoof_avatar_props(&self) -> HashMap { - // TODO: fill! - let map = self.spoof_avatar_props_raw(); - - return self.remap(&map); - } - fn spoof_avatar_fight_props(&self) -> HashMap { // TODO: fill! let map = collection! { @@ -612,24 +425,6 @@ impl GameWorld { return afi; } - fn spoof_inventory(&self) -> Vec { - let mut weapon = proto::Weapon::default(); - weapon.level = 70; - weapon.promote_level = 4; - weapon.affix_map = collection!{111406 => 0}; - - let mut equip = proto::Equip::default(); - equip.is_locked = true; - equip.detail = Some(proto::equip::Detail::Weapon(weapon)); - - let mut item = proto::Item::default(); - item.item_id = 11406; - item.guid = GameWorld::SPOOFED_WEAPON_GUID; - item.detail = Some(proto::item::Detail::Equip(equip)); - - return vec![item]; - } - fn remap(&self, map: &HashMap) -> HashMap { let mut hashmap = HashMap::::new(); @@ -673,8 +468,4 @@ impl GameWorld { return ret; } - - fn timestamp(&self) -> u64 { - return SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_millis() as u64; - } } diff --git a/src/server/login_manager.rs b/src/server/login_manager.rs new file mode 100644 index 0000000..d550e35 --- /dev/null +++ b/src/server/login_manager.rs @@ -0,0 +1,231 @@ +use std::sync::{mpsc, Arc}; +use std::collections::HashMap; + +use prost::Message; + +use crate::server::IpcMessage; + +use packet_processor_macro::*; +#[macro_use] +use packet_processor::*; + +use crate::DatabaseManager; +use crate::JsonManager; + +use crate::utils::IdManager; +use crate::utils::TimeManager; + +use crate::dbmanager::database_manager::AvatarInfo as DbAvatarInfo; + +#[packet_processor(PlayerLoginReq)] +pub struct LoginManager { + packets_to_send_tx: mpsc::Sender, + db: Arc, + jm: Arc, +} + +impl LoginManager { + pub fn new(db: Arc, jm: Arc, packets_to_send_tx: mpsc::Sender) -> LoginManager { + let mut lm = LoginManager { + packet_callbacks: HashMap::new(), + packets_to_send_tx: packets_to_send_tx, + db: db.clone(), + jm: jm.clone(), + }; + + lm.register(); + + return lm; + } + + fn process_player_login(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::PlayerLoginReq, rsp: &mut proto::PlayerLoginRsp) { + let user = match self.db.get_player_info(user_id) { + Some(user) => user, + None => panic!("User {} not found!", user_id), + }; + + let player_props = match self.db.get_player_props(user_id) { + Some(props) => Self::remap(&props), + None => panic!("Props for user {} not found!", user_id), + }; + + let open_state = match self.db.get_open_state(user_id) { + Some(state) => state, + None => panic!("Open state for user {} not found!", user_id), + }; + + let inventory = match self.db.get_inventory(user_id) { + Some(inventory) => inventory, + None => panic!("Inventory for user {} not found!", user_id), + }; + + let avatar_list = match self.db.get_avatars(user_id) { + Some(avatars) => avatars + .into_iter() + .map(|a| self.build_avatar_info(&a)) + .collect(), + None => panic!("Avatars for user {} not found!", user_id), + }; + + let team_map = self.retrieve_team_info(user_id); + + let (current_avatar, current_team) = match self.db.get_player_team_selection(user_id) { + Some(team_selection) => (team_selection.avatar, team_selection.team), + None => panic!("Team selection info for user {} not found!", user_id), + }; + + let scene_info = match self.db.get_player_scene_info(user_id) { + Some(scene_info) => scene_info, + None => panic!("Scene info for user {} not found!", user_id), + }; + + build_and_send! ( self, user_id, metadata, PlayerDataNotify { + nick_name: user.nick_name, server_time: TimeManager::timestamp(), prop_map: player_props, + }); + + build_and_send! ( self, user_id, metadata, OpenStateUpdateNotify { + open_state_map: open_state, + }); + + // TODO: hardcoded limits! + build_and_send! (self, user_id, metadata, StoreWeightLimitNotify { + store_type: proto::StoreType::StorePack as i32, + weight_limit: 30000, + material_count_limit: 2000, + weapon_count_limit: 2000, + reliquary_count_limit: 1000, + furniture_count_limit: 2000, + }); + + // TODO: hardcoded limit! + build_and_send! (self, user_id, metadata, PlayerStoreNotify { + store_type: proto::StoreType::StorePack as i32, weight_limit: 30000, item_list: inventory, + }); + + build_and_send! (self, user_id, metadata, AvatarDataNotify { + avatar_list: avatar_list, + avatar_team_map: team_map, + cur_avatar_team_id: current_team.into(), + choose_avatar_guid: current_avatar, + }); + + build_and_send! (self, user_id, metadata, PlayerEnterSceneNotify { + scene_id: scene_info.scene_id, + r#type: proto::EnterType::EnterSelf as i32, + scene_begin_time: TimeManager::timestamp(), + pos: Some(proto::Vector {x: scene_info.pos_x, y: scene_info.pos_y, z: scene_info.pos_z}), + target_uid: user_id, + world_level: user.world_level as u32, + enter_scene_token: scene_info.scene_token, + //enter_reason: 1, + }); + } + + fn retrieve_team_info(&self, user_id: u32) -> HashMap { + let player_teams = match self.db.get_player_teams(user_id) { + Some(teams) => teams, + None => panic!("Teams for user {} not found!", user_id), + }; + + let player_teams_avatars = match self.db.get_player_teams_avatars(user_id) { + Some(team_avatars) => team_avatars, + None => panic!("Team avatars for user {} not found!", user_id), + }; + + let mut team_map = HashMap::::new(); + + for team in player_teams { + let at = build! ( AvatarTeam { + team_name: team.name.clone(), + avatar_guid_list: player_teams_avatars.clone().into_iter().filter(|a| a.team_id == team.id).map(|a| a.guid).collect(), + }); + + team_map.insert(team.id.into(), at); + }; + + return team_map; + } + + fn build_avatar_info(&self, a: &DbAvatarInfo) -> proto::AvatarInfo { + let di = IdManager::get_depot_id_by_char_id(a.character_id); + + let asd = &self.jm.avatar_skill_depot[&di]; + + let asl = self.db.get_skill_levels(a.guid).unwrap_or_else(|| panic!("No skill levels for avatar {}!", a.guid)); + + let mut slm = HashMap::new(); + + match asd.energy_skill { + Some(es) => { + if (asl.contains_key(&es)) { + slm.insert(es, asl[&es]); + } + }, + None => {}, + }; + + for s in &asd.skills { + if (*s != 0) { + if (asl.contains_key(s)) { + slm.insert(*s, asl[s]); + } + } + } + + let ap = self.db.get_avatar_props(a.guid).unwrap_or_else(|| panic!("Props not found for avatar {}!", a.guid)); + let afp = self.db.get_avatar_fight_props(a.guid).unwrap_or_else(|| panic!("Fight props not found for avatar {}!", a.guid)); + + let pli = proto::PropType::PropBreakLevel as u32; + + let promote_level = if ap.contains_key(&pli) { ap[&pli] as u32 } else { 0 }; + + let ips = asd.inherent_proud_skill_opens + .clone() + .into_iter() + .filter(|s| s.proud_skill_group_id != None) + .filter(|s| s.need_avatar_promote_level == None || s.need_avatar_promote_level.unwrap() <= promote_level) + .map(|s| s.proud_skill_group_id.unwrap()) + .map(|s| s * 100 + 1) // TODO: ugly hack! Fix it by reading ProudSkillExcelConfigData! + .collect(); + + // TODO: properly fill! + let afi = build!(AvatarFetterInfo { + exp_level: 1, + // TODO: fill fetter list! + }); + + let egi = self.db.get_avatar_equip(a.guid).unwrap_or_else(|| panic!("Equip not found for avatar {}!", a.guid)); + + // TODO: ugly ugly hack! + let mut fuck = HashMap::new(); + fuck.insert(732, 3); + fuck.insert(739, 3); + + let ai = build!(AvatarInfo { + avatar_id: IdManager::get_avatar_id_by_char_id(a.character_id), + avatar_type: a.avatar_type.into(), + guid: a.guid, + born_time: a.born_time, + skill_depot_id: asd.id, + talent_id_list: asd.talents.clone(), + prop_map: Self::remap(&ap), + fight_prop_map: afp, + fetter_info: Some(afi), + equip_guid_list: egi, + inherent_proud_skill_list: ips, //vec![72101, 72201], + skill_level_map: slm, + proud_skill_extra_level_map: fuck, //collection!{739 => 3, 732 => 3}, + }); + return ai; + } + + fn remap(map: &HashMap) -> HashMap { + let mut hashmap = HashMap::::new(); + + for (key, value) in map { + hashmap.insert(*key, build!(PropValue { r#type: *key, val: *value, value: Some(proto::prop_value::Value::Ival(*value)), })); + } + + return hashmap; + } +} diff --git a/src/server/mod.rs b/src/server/mod.rs index 4d73c51..94972ae 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -2,6 +2,7 @@ mod network_server; mod game_server; mod game_world; mod auth_manager; +mod login_manager; mod client_connection; mod ipc_message; mod dispatch_server; @@ -10,6 +11,7 @@ pub use self::network_server::NetworkServer; pub use self::game_server::GameServer; pub use self::game_world::GameWorld; pub use self::auth_manager::AuthManager; +pub use self::login_manager::LoginManager; pub use self::client_connection::ClientConnection; pub use self::ipc_message::IpcMessage; pub use self::dispatch_server::DispatchServer; diff --git a/src/utils/id_manager.rs b/src/utils/id_manager.rs new file mode 100644 index 0000000..1b342f6 --- /dev/null +++ b/src/utils/id_manager.rs @@ -0,0 +1,35 @@ +pub struct IdManager { +} + +impl IdManager { + const AVATAR_ID_OFFSET: u32 = 10_000_000; + + const DEPOT_ID_MULT: u32 = 100; + const DEPOT_ID_OFFSET: u32 = 1; + + const PROUD_SKILL_MULT: u32 = 100; + const PROUD_SKILL_OFFSET: u32 = 1; + + pub fn get_avatar_id_by_char_id(character_id: u32) -> u32 { + if (character_id > 100) { + panic!("Invalid character ID: {}", character_id); + } + + return character_id + Self::AVATAR_ID_OFFSET; + } + + pub fn get_depot_id_by_char_id(character_id: u32) -> u32 { + if (character_id > 100) { + panic!("Invalid character ID: {}", character_id); + } + + let mut offset = Self::DEPOT_ID_OFFSET; + + println!("HACK: main hero is fixed to Wind!"); + if (character_id == 5 || character_id == 7) { + offset = 4; + } + + return character_id * Self::DEPOT_ID_MULT + offset; + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 06533b3..d55c126 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,5 +1,9 @@ mod handshake_packet; mod data_packet; +mod id_manager; +mod time_manager; pub use self::handshake_packet::HandshakePacket; pub use self::data_packet::DataPacket; +pub use self::id_manager::IdManager; +pub use self::time_manager::TimeManager; diff --git a/src/utils/time_manager.rs b/src/utils/time_manager.rs new file mode 100644 index 0000000..a6b2c5b --- /dev/null +++ b/src/utils/time_manager.rs @@ -0,0 +1,15 @@ +use std::time::SystemTime; +use std::convert::TryInto; + +pub struct TimeManager { +} + +impl TimeManager { + pub fn duration_since(time_point: SystemTime) -> u64 { + SystemTime::now().duration_since(time_point).unwrap().as_millis().try_into().unwrap() + } + + pub fn timestamp() -> u64 { + return Self::duration_since(SystemTime::UNIX_EPOCH); + } +}