From 9b088aaf80a5031a01d51f0a69b4b64b8b1600e9 Mon Sep 17 00:00:00 2001 From: Nobody Date: Wed, 26 Jan 2022 21:49:54 +0500 Subject: [PATCH] Move mapper and avatar building into separate module --- src/server/game_server.rs | 12 +- src/server/game_world.rs | 332 +++++++++++++----------------------- src/server/login_manager.rs | 97 +---------- src/utils/avatar_builder.rs | 110 ++++++++++++ src/utils/mod.rs | 4 + src/utils/remapper.rs | 49 ++++++ 6 files changed, 302 insertions(+), 302 deletions(-) create mode 100644 src/utils/avatar_builder.rs create mode 100644 src/utils/remapper.rs diff --git a/src/server/game_server.rs b/src/server/game_server.rs index 4b2ef61..56dbf9a 100644 --- a/src/server/game_server.rs +++ b/src/server/game_server.rs @@ -17,19 +17,23 @@ pub struct GameServer { packets_to_send_tx: mpsc::Sender, worlds: HashMap, login_manager: LoginManager, + database_manager: Arc, + json_manager: Arc, } 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 db = Arc::new(DatabaseManager::new("sqlite://./database.db3")); + let jm = Arc::new(JsonManager::new("./json")); + let lm = LoginManager::new(db.clone(), jm.clone(), 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, + database_manager: db.clone(), + json_manager: jm.clone(), }; return gs; @@ -53,7 +57,7 @@ impl GameServer { 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()); + let mut world = GameWorld::new(self.database_manager.clone(),self.json_manager.clone(), self.packets_to_send_tx.clone()); entry.insert(world) }, }; diff --git a/src/server/game_world.rs b/src/server/game_world.rs index cb28692..adf5602 100644 --- a/src/server/game_world.rs +++ b/src/server/game_world.rs @@ -1,15 +1,21 @@ -use std::sync::mpsc; +use std::sync::{mpsc, Arc}; use std::io::Cursor; use std::collections::HashMap; use std::time::SystemTime; use prost::Message; +use chrono::Datelike; + use crate::server::IpcMessage; +use crate::utils::{AvatarBuilder, Remapper}; + use packet_processor_macro::*; #[macro_use] use packet_processor::*; +use crate::DatabaseManager; +use crate::JsonManager; macro_rules! collection { // map-like @@ -35,20 +41,21 @@ macro_rules! collection { )] pub struct GameWorld { packets_to_send_tx: mpsc::Sender, + db: Arc, + jm: Arc, } impl GameWorld { const BASE_GUID: u64 = 0x2400000000000000; const SPOOFED_AVATAR_EID: u32 = (1<<24) + 146; - 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 = 0x1234; - const SPOOFED_SCENE_ID: u32 = 3; - pub fn new(packets_to_send_tx: mpsc::Sender) -> GameWorld { + pub fn new(db: Arc, jm: Arc, packets_to_send_tx: mpsc::Sender) -> GameWorld { let mut gw = GameWorld { packets_to_send_tx: packets_to_send_tx, + db: db.clone(), + jm: jm.clone(), packet_callbacks: HashMap::new(), }; @@ -62,28 +69,38 @@ impl GameWorld { } fn process_get_player_social_detail(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::GetPlayerSocialDetailReq, rsp: &mut proto::GetPlayerSocialDetailRsp) { + let user = match self.db.get_player_info(user_id) { + Some(user) => user, + None => panic!("User {} not found!", user_id), + }; + + let props = self.db.get_player_props(user_id).unwrap_or_else(|| panic!("Failed to get properties for user {}!", user_id)); + + let user_level = props[&(proto::PropType::PropPlayerLevel as u32)] as u32; + let world_level = props[&(proto::PropType::PropPlayerWorldLevel as u32)] as u32; + let avatar_info = build!(SocialShowAvatarInfo { - avatar_id: 10000007, + avatar_id: user.avatar_id, 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, + nickname: user.nick_name.clone(), + level: user_level, + avatar_id: user.avatar_id, + signature: user.signature.clone(), + birthday: Some(proto::Birthday {month: user.birthday.month(), day: user.birthday.day()}), + world_level: world_level, + online_state: proto::FriendOnlineState::FriendOnline as i32, // TODO + is_friend: true, // TODO + is_mp_mode_available: true, // TODO + name_card_id: user.namecard_id, + finish_achievement_num: user.finish_achievement_num, // TODO + tower_floor_index: user.tower_floor_index as u32, + tower_level_index: user.tower_level_index as u32, show_avatar_info_list: vec![avatar_info], // TODO - show_name_card_id_list: vec![210051], + show_name_card_id_list: vec![user.namecard_id], // TODO: add all namecards! // Field 25! }); @@ -93,31 +110,56 @@ 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; + let current_scene_info = match self.db.get_player_scene_info(user_id) { + Some(scene_info) => scene_info, + None => panic!("Scene info not found for user {}!", user_id), + }; + 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, + dest_scene_id: current_scene_info.scene_id, + peer_id: 1, // TODO + host_peer_id: 1, // TODO + enter_scene_token: req.enter_scene_token, // TODO?? }); } 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; + let current_avatar_guid = match self.db.get_player_team_selection(user_id) { + Some(team_selection) => team_selection.avatar, + None => panic!("Team selection info not found for user {}!", user_id), + }; + + let current_scene_info = match self.db.get_player_scene_info(user_id) { + Some(scene_info) => scene_info, + None => panic!("Scene info not found for user {}!", user_id), + }; + + let user = match self.db.get_player_info(user_id) { + Some(user) => user, + None => panic!("User {} not found!", user_id), + }; + + let props = self.db.get_player_props(user_id).unwrap_or_else(|| panic!("Failed to get properties for user {}!", user_id)); + + let user_level = props[&(proto::PropType::PropPlayerLevel as u32)] as u32; + let world_level = props[&(proto::PropType::PropPlayerWorldLevel as u32)] as u32; + + rsp.enter_scene_token = current_scene_info.scene_token; build_and_send!(self, user_id, metadata, WorldDataNotify { - world_prop_map: self.remap(&collection!{1 => 8, 2 => 0}), + world_prop_map: Remapper::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(), + nickname: user.nick_name.clone(), + player_level: user_level, + avatar_id: user.avatar_id, + mp_setting_type: proto::MpSettingType::MpSettingEnterAfterApply as i32, // TODO! + cur_player_num_in_world: 1, // TODO! + world_level: world_level, + name_card_id: user.namecard_id, + signature: user.signature.clone(), // TODO: Field 12! }); @@ -128,9 +170,9 @@ impl GameWorld { let scene_player_info_e = build!(ScenePlayerInfo { uid: user_id, - peer_id: 1, - name: "Fukker".to_string(), - scene_id: GameWorld::SPOOFED_SCENE_ID, + peer_id: 1, // TODO + name: user.nick_name.clone(), + scene_id: current_scene_info.scene_id, online_player_info: Some(online_player_info), }); @@ -139,7 +181,7 @@ impl GameWorld { }); let avatar_enter_info = build!(AvatarEnterSceneInfo { - avatar_guid: GameWorld::SPOOFED_AVATAR_GUID, + avatar_guid: current_avatar_guid as u64, // FIXME avatar_entity_id: GameWorld::SPOOFED_AVATAR_EID, weapon_guid: GameWorld::SPOOFED_WEAPON_GUID, weapon_entity_id: GameWorld::SPOOFED_WEAPON_EID, @@ -151,7 +193,7 @@ impl GameWorld { let team_enter_info = build!(TeamEnterSceneInfo { team_entity_id: 0x9000000 + 1, }); build_and_send!(self, user_id, metadata, PlayerEnterSceneInfoNotify { - enter_scene_token: GameWorld::SPOOFED_SCENE_TOKEN, + enter_scene_token: current_scene_info.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), @@ -164,27 +206,28 @@ impl GameWorld { }); build_and_send!(self, user_id, metadata, SceneTimeNotify { - scene_id: GameWorld::SPOOFED_SCENE_ID, + scene_id: current_scene_info.scene_id, scene_time: 9000, }); build_and_send!(self, user_id, metadata, SceneDataNotify { - level_config_name_list: vec!["Level_BigWorld".to_string()], + level_config_name_list: vec!["Level_BigWorld".to_string()], // TODO }); build_and_send!(self, user_id, metadata, HostPlayerNotify { host_uid: user_id, - host_peer_id: 1, + host_peer_id: 1, // TODO }); + // TODO: perform for each avatar in the team! let scene_team_avatar = build!(SceneTeamAvatar { - scene_id: GameWorld::SPOOFED_SCENE_ID, + scene_id: current_scene_info.scene_id, player_uid: user_id, - avatar_guid: GameWorld::SPOOFED_AVATAR_GUID, + avatar_guid: current_avatar_guid as u64, // FIXME entity_id: GameWorld::SPOOFED_AVATAR_EID, weapon_guid: GameWorld::SPOOFED_WEAPON_GUID, weapon_entity_id: GameWorld::SPOOFED_WEAPON_EID, - is_player_cur_avatar: true, + is_player_cur_avatar: true, // TODO scene_entity_info: Some(self.spoof_scene_default_avatar(user_id)), ability_control_block: Some(self.spoof_default_abilities()), }); @@ -198,12 +241,17 @@ impl GameWorld { 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, + appear_type: proto::VisionType::VisionBorn as i32, // TODO }); } fn process_post_enter_scene(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::PostEnterSceneReq, rsp: &mut proto::PostEnterSceneRsp) { - rsp.enter_scene_token = GameWorld::SPOOFED_SCENE_TOKEN; + let current_scene_info = match self.db.get_player_scene_info(user_id) { + Some(scene_info) => scene_info, + None => panic!("Scene info not found for user {}!", user_id), + }; + + rsp.enter_scene_token = current_scene_info.scene_token; } fn process_enter_world_area(&self, user_id: u32, metadata: &proto::PacketHead, req: &proto::EnterWorldAreaReq, rsp: &mut proto::EnterWorldAreaRsp) { @@ -212,8 +260,23 @@ impl GameWorld { } fn spoof_scene_default_avatar(&self, user_id: u32) -> proto::SceneEntityInfo { + let user = self.db.get_player_scene_info(user_id).unwrap_or_else(|| panic!("User info not found for user {}!", user_id)); + + let current_avatar_guid = match self.db.get_player_team_selection(user_id) { + Some(team_selection) => team_selection.avatar, + None => panic!("Team selection info not found for user {}!", user_id), + }; + + let avatar_info = self.db.get_avatar(current_avatar_guid).unwrap_or_else(|| panic!("Avatar info for avatar {} not found!", current_avatar_guid)); + + let avatar_info = AvatarBuilder::build_avatar_info(self.jm.clone(), self.db.clone(), &avatar_info); + + let current_avatar_props = self.db.get_avatar_props(current_avatar_guid).unwrap_or_else(|| panic!("Properties not found for avatar {}!", current_avatar_guid)); + + let current_avatar_fight_props = self.db.get_avatar_fight_props(current_avatar_guid).unwrap_or_else(|| panic!("Fight props not found for avatar {}!", current_avatar_guid)); + let motion_info = build!(MotionInfo { - pos: Some(proto::Vector {x: -3400.0, y: 233.0, z: -3427.0}), + pos: Some(proto::Vector {x: user.pos_x, y: user.pos_y, z: user.pos_z}), rot: Some(proto::Vector::default()), speed: Some(proto::Vector::default()), }); @@ -230,16 +293,16 @@ impl GameWorld { let scene_avatar_info = build!(SceneAvatarInfo { uid: user_id, - avatar_id: 10000007, - guid: GameWorld::SPOOFED_AVATAR_GUID, - peer_id: 1, - skill_depot_id: 704, - born_time: 1633790000, - talent_id_list: vec![71, 72, 73, 74, 75, 76], - 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}, - equip_id_list: vec![11406], + avatar_id: avatar_info.avatar_id, + guid: current_avatar_guid as u64, // FIXME + peer_id: 1, // TODO + skill_depot_id: avatar_info.skill_depot_id, + born_time: avatar_info.born_time, + talent_id_list: avatar_info.talent_id_list, + inherent_proud_skill_list: avatar_info.inherent_proud_skill_list, + skill_level_map: avatar_info.skill_level_map, + proud_skill_extra_level_map: avatar_info.proud_skill_extra_level_map, + equip_id_list: vec![11406], // TODO weapon: Some(weapon), }); @@ -254,8 +317,8 @@ impl GameWorld { entity_id: GameWorld::SPOOFED_AVATAR_EID, life_state: 1, entity: Some(proto::scene_entity_info::Entity::Avatar(scene_avatar_info)), - prop_list: self.spoof_scene_avatar_props(), - fight_prop_list: self.spoof_scene_avatar_fight_props(), + prop_list: Remapper::remap2(¤t_avatar_props), + fight_prop_list: Remapper::remap3(¤t_avatar_fight_props), motion_info: Some(motion_info), entity_authority_info: Some(authority_info), }); @@ -263,89 +326,6 @@ impl GameWorld { return scene_entity_info; } - fn spoof_avatar_props_raw(&self) -> HashMap { - // TODO: fill! - 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 map; - } - - fn spoof_avatar_fight_props(&self) -> HashMap { - // TODO: fill! - 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 map; - } - - fn spoof_scene_avatar_props(&self) -> Vec { - let map = self.spoof_avatar_props_raw(); - - return self.remap2(&map); - } - - fn spoof_scene_avatar_fight_props(&self) -> Vec { - let map = self.spoof_avatar_fight_props(); - - return self.remap3(&map); - } - fn spoof_default_abilities(&self) -> proto::AbilityControlBlock { let map: HashMap = collection! { 1 => 0x05FF9657, @@ -402,70 +382,4 @@ impl GameWorld { return acb; } - - fn spoof_fetter_info(&self) -> proto::AvatarFetterInfo { - // Fetter info is used for character info and voicelines in "about" section of chara menu - let mut afi = proto::AvatarFetterInfo::default(); - afi.exp_level = 1; - - let map: HashMap = collection! { - }; - - let mut fl = vec![]; - - for (key, value) in map { - let mut fd = proto::FetterData::default(); - fd.fetter_id = key; - fd.fetter_state = value; - fl.push(fd); - } - - //afi.fetter_list = fl; - - return afi; - } - - fn remap(&self, map: &HashMap) -> HashMap { - let mut hashmap = HashMap::::new(); - - for (key, value) in map { - let mut prop = proto::PropValue::default(); - prop.r#type = *key; - prop.val = *value; - prop.value = Some(proto::prop_value::Value::Ival(*value)); - hashmap.insert(*key, prop); - } - - return hashmap; - } - - fn remap2(&self, map: &HashMap) -> Vec { - let mut ret = vec![]; - - for (key, value) in map { - let mut prop = proto::PropValue::default(); - prop.r#type = *key; - prop.val = *value; - prop.value = Some(proto::prop_value::Value::Ival(*value)); - let mut pair = proto::PropPair::default(); - pair.r#type = *key; - pair.prop_value = Some(prop); - ret.push(pair); - } - - return ret; - } - - fn remap3(&self, map: &HashMap) -> Vec { - let mut ret = vec![]; - - for (key, value) in map { - let mut pair = proto::FightPropPair::default(); - pair.prop_type = *key; - pair.prop_value = *value; - ret.push(pair); - } - - return ret; - } } diff --git a/src/server/login_manager.rs b/src/server/login_manager.rs index d550e35..59308e2 100644 --- a/src/server/login_manager.rs +++ b/src/server/login_manager.rs @@ -12,7 +12,7 @@ use packet_processor::*; use crate::DatabaseManager; use crate::JsonManager; -use crate::utils::IdManager; +use crate::utils::{AvatarBuilder, IdManager, Remapper}; use crate::utils::TimeManager; use crate::dbmanager::database_manager::AvatarInfo as DbAvatarInfo; @@ -45,7 +45,7 @@ impl LoginManager { }; let player_props = match self.db.get_player_props(user_id) { - Some(props) => Self::remap(&props), + Some(props) => Remapper::remap(&props), None => panic!("Props for user {} not found!", user_id), }; @@ -62,7 +62,7 @@ impl LoginManager { let avatar_list = match self.db.get_avatars(user_id) { Some(avatars) => avatars .into_iter() - .map(|a| self.build_avatar_info(&a)) + .map(|a| AvatarBuilder::build_avatar_info(self.jm.clone(), self.db.clone(), &a)) .collect(), None => panic!("Avatars for user {} not found!", user_id), }; @@ -79,6 +79,8 @@ impl LoginManager { None => panic!("Scene info for user {} not found!", user_id), }; + let world_level = player_props[&(proto::PropType::PropPlayerWorldLevel as u32)].val as u32; + build_and_send! ( self, user_id, metadata, PlayerDataNotify { nick_name: user.nick_name, server_time: TimeManager::timestamp(), prop_map: player_props, }); @@ -106,7 +108,7 @@ impl LoginManager { avatar_list: avatar_list, avatar_team_map: team_map, cur_avatar_team_id: current_team.into(), - choose_avatar_guid: current_avatar, + choose_avatar_guid: current_avatar as u64, // FIXME }); build_and_send! (self, user_id, metadata, PlayerEnterSceneNotify { @@ -115,7 +117,7 @@ impl LoginManager { 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, + world_level: world_level, enter_scene_token: scene_info.scene_token, //enter_reason: 1, }); @@ -137,7 +139,7 @@ impl LoginManager { 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(), + avatar_guid_list: player_teams_avatars.clone().into_iter().filter(|a| a.team_id == team.id).map(|a| a.guid as u64).collect(), // FIXME }); team_map.insert(team.id.into(), at); @@ -145,87 +147,4 @@ impl LoginManager { 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/utils/avatar_builder.rs b/src/utils/avatar_builder.rs new file mode 100644 index 0000000..5f1562c --- /dev/null +++ b/src/utils/avatar_builder.rs @@ -0,0 +1,110 @@ +use std::sync::Arc; +use std::collections::HashMap; + +use packet_processor_macro::*; +#[macro_use] +use packet_processor::*; + +use crate::dbmanager::database_manager::AvatarInfo as DbAvatarInfo; +use crate::{DatabaseManager, JsonManager}; +use crate::utils::{IdManager, Remapper}; + +pub struct AvatarBuilder {} + +impl AvatarBuilder { + pub fn build_avatar_info(jm: Arc, db: Arc, a: &DbAvatarInfo) -> proto::AvatarInfo { + let di = IdManager::get_depot_id_by_char_id(a.character_id); + + let asd = &jm.avatar_skill_depot[&di]; + + let asl = 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 = db.get_avatar_props(a.guid).unwrap_or_else(|| panic!("Props not found for avatar {}!", a.guid)); + let afp = 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 = db.get_avatar_equip(a.guid).unwrap_or_else(|| panic!("Equip not found for avatar {}!", a.guid)); + let egi = egi.into_iter().map(|g| g as u64).collect(); // FIXME + + // 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 as u64, // FIXME + born_time: a.born_time, + skill_depot_id: asd.id, + talent_id_list: asd.talents.clone(), + prop_map: Remapper::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 spoof_fetter_info() -> proto::AvatarFetterInfo { + // Fetter info is used for character info and voicelines in "about" section of chara menu + let mut afi = proto::AvatarFetterInfo::default(); + afi.exp_level = 1; + + /*let map: HashMap = collection! { + }; + + let mut fl = vec![]; + + for (key, value) in map { + let mut fd = proto::FetterData::default(); + fd.fetter_id = key; + fd.fetter_state = value; + fl.push(fd); + } + + //afi.fetter_list = fl;*/ + + return afi; + } +} \ No newline at end of file diff --git a/src/utils/mod.rs b/src/utils/mod.rs index d55c126..dd2bec0 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -2,8 +2,12 @@ mod handshake_packet; mod data_packet; mod id_manager; mod time_manager; +mod avatar_builder; +mod remapper; pub use self::handshake_packet::HandshakePacket; pub use self::data_packet::DataPacket; pub use self::id_manager::IdManager; pub use self::time_manager::TimeManager; +pub use self::remapper::Remapper; +pub use self::avatar_builder::AvatarBuilder; \ No newline at end of file diff --git a/src/utils/remapper.rs b/src/utils/remapper.rs new file mode 100644 index 0000000..9c2734a --- /dev/null +++ b/src/utils/remapper.rs @@ -0,0 +1,49 @@ +use std::collections::HashMap; + +pub struct Remapper {} + +impl Remapper { + pub fn remap(map: &HashMap) -> HashMap { + let mut hashmap = HashMap::::new(); + + for (key, value) in map { + let mut prop = proto::PropValue::default(); + prop.r#type = *key; + prop.val = *value; + prop.value = Some(proto::prop_value::Value::Ival(*value)); + hashmap.insert(*key, prop); + } + + return hashmap; + } + + pub fn remap2(map: &HashMap) -> Vec { + let mut ret = vec![]; + + for (key, value) in map { + let mut prop = proto::PropValue::default(); + prop.r#type = *key; + prop.val = *value; + prop.value = Some(proto::prop_value::Value::Ival(*value)); + let mut pair = proto::PropPair::default(); + pair.r#type = *key; + pair.prop_value = Some(prop); + ret.push(pair); + } + + return ret; + } + + pub fn remap3(map: &HashMap) -> Vec { + let mut ret = vec![]; + + for (key, value) in map { + let mut pair = proto::FightPropPair::default(); + pair.prop_type = *key; + pair.prop_value = *value; + ret.push(pair); + } + + return ret; + } +} \ No newline at end of file