From ad0d79acc1ab83242fca2b5b1ecae605914d7183 Mon Sep 17 00:00:00 2001 From: traffic95 Date: Sat, 24 May 2025 00:12:49 +0200 Subject: [PATCH] Added FirstLoginConfig --- servers/game-server/first_login.default.toml | 23 ++++++++ servers/game-server/src/config.rs | 35 +++++++++++ .../game-server/src/logic/player/avatar.rs | 58 ++++++++++++------- servers/game-server/src/logic/player/item.rs | 56 +++++++++++++----- servers/game-server/src/logic/player/mod.rs | 23 +++++--- servers/game-server/src/main.rs | 4 ++ servers/game-server/src/resources.rs | 3 +- 7 files changed, 157 insertions(+), 45 deletions(-) create mode 100644 servers/game-server/first_login.default.toml diff --git a/servers/game-server/first_login.default.toml b/servers/game-server/first_login.default.toml new file mode 100644 index 0000000..3599a35 --- /dev/null +++ b/servers/game-server/first_login.default.toml @@ -0,0 +1,23 @@ +interknot_level = 60 +control_avatar_id = 2011 +control_guise_avatar_id = 1371 +day_of_week = 5 +start_main_quest = false +default_section_id = 1 + +[avatar] +unlock_all = true +unlock_id_list = [ 1011, 1081 ] +level = 60 +rank = 6 +unlocked_talent_num = 0 +talent_switch = [ false, false, false, false, false, false ] +passive_skill_level = 7 +skill_level_map = [ 12, 12, 12, 12, 7, 7, 12 ] + +[weapon] +unlock_all = true +unlock_id_list = [ 13101 ] +level = 60 +star = 5 +refine_level = 1 \ No newline at end of file diff --git a/servers/game-server/src/config.rs b/servers/game-server/src/config.rs index 49b1955..4a3c22f 100644 --- a/servers/game-server/src/config.rs +++ b/servers/game-server/src/config.rs @@ -43,3 +43,38 @@ pub struct GachaMaterialConfig { pub id: u32, pub count: u32, } + +#[derive(Deserialize)] +pub struct FirstLoginConfig { + pub interknot_level: u32, + pub control_avatar_id: u32, + pub control_guise_avatar_id: u32, + pub day_of_week: u32, + pub start_main_quest: bool, + pub default_section_id: u32, + pub avatar: FirstLoginAvatarConfig, + pub weapon: FirstLoginWeaponConfig, +} + +#[derive(Deserialize)] +pub struct FirstLoginAvatarConfig { + pub unlock_all: bool, + #[serde(default)] + pub unlock_id_list: Vec, + pub level: u32, + pub rank: u32, + pub unlocked_talent_num: u32, + pub talent_switch: Vec, + pub passive_skill_level: u32, + pub skill_level_map: Vec, +} + +#[derive(Deserialize)] +pub struct FirstLoginWeaponConfig { + pub unlock_all: bool, + #[serde(default)] + pub unlock_id_list: Vec, + pub level: u32, + pub star: u32, + pub refine_level: u32, +} \ No newline at end of file diff --git a/servers/game-server/src/logic/player/avatar.rs b/servers/game-server/src/logic/player/avatar.rs index 85caad5..a8aa17c 100644 --- a/servers/game-server/src/logic/player/avatar.rs +++ b/servers/game-server/src/logic/player/avatar.rs @@ -10,11 +10,10 @@ use vivian_logic::{ use vivian_proto::server_only::{AvatarData, AvatarItemInfo}; use crate::{ - logic::{ + config::FirstLoginAvatarConfig, logic::{ property::{Property, PropertyHashMap}, sync::{LoginDataSyncComponent, PlayerSyncComponent, SyncType}, - }, - resources::NapResources, + }, resources::NapResources }; use super::{Model, Saveable}; @@ -28,16 +27,24 @@ pub struct AvatarModel { impl AvatarModel { pub fn on_first_login(&mut self, res: &NapResources) { - const STARTING_AVATARS: &[u32] = &[1011, 1081]; + let cfg = &res.gameplay.first_login.avatar; - STARTING_AVATARS - .iter() - .filter_map(|id| { - res.templates - .avatar_base_template_tb() - .find(|tmpl| tmpl.id() == *id) - }) - .for_each(|tmpl| self.unlock_avatar(&tmpl, None)); + if cfg.unlock_all { + res + .templates + .avatar_base_template_tb() + .for_each(|tmpl| self.unlock_avatar(&tmpl, None, Some(cfg))); + } else { + cfg + .unlock_id_list + .iter() + .filter_map(|id| { + res.templates + .avatar_base_template_tb() + .find(|tmpl| tmpl.id() == *id) + }) + .for_each(|tmpl| self.unlock_avatar(&tmpl, None, Some(cfg))); + } } pub fn send_add_avatar_notify(&self, listener: &mut dyn NotifyListener) { @@ -96,6 +103,7 @@ impl AvatarModel { &mut self, base_template: &AvatarBaseTemplate, perform_type: Option, + first_login_cfg: Option<&FirstLoginAvatarConfig>, ) { const AVATAR_BLACKLIST: &[u32] = &[]; @@ -105,20 +113,28 @@ impl AvatarModel { && !self.avatar_map.contains_key(&avatar_id) && !AVATAR_BLACKLIST.contains(&avatar_id) { + let mut skill_level_map: HashMap = (0..EAvatarSkillType::EnumCount.into()) + .map(|ty| EAvatarSkillType::try_from(ty).unwrap()) + .zip([0].into_iter().cycle()) + .collect(); + if let Some(cfg) = first_login_cfg { + skill_level_map = (0..EAvatarSkillType::EnumCount.into()) + .map(|ty| EAvatarSkillType::try_from(ty).unwrap()) + .zip(cfg.skill_level_map.clone()) + .collect(); + } + self.avatar_map.insert( avatar_id, AvatarItem { id: avatar_id, - level: 1, + level: first_login_cfg.map_or(1, |cfg| cfg.level), exp: 0, - rank: 1, - unlocked_talent_num: 0, - talent_switch: [false; 6], - passive_skill_level: 0, - skill_level_map: (0..EAvatarSkillType::EnumCount.into()) - .map(|ty| EAvatarSkillType::try_from(ty).unwrap()) - .zip([0].into_iter().cycle()) - .collect(), + rank: first_login_cfg.map_or(1, |cfg| cfg.rank), + unlocked_talent_num: first_login_cfg.map_or(0, |cfg| cfg.unlocked_talent_num), + talent_switch: first_login_cfg.map_or([false; 6], |cfg| cfg.talent_switch.as_slice().try_into().unwrap()), + passive_skill_level: first_login_cfg.map_or(0, |cfg| cfg.passive_skill_level), + skill_level_map, weapon_uid: 0, dressed_equip_map: HashMap::new(), first_get_time: time_util::unix_timestamp_seconds(), diff --git a/servers/game-server/src/logic/player/item.rs b/servers/game-server/src/logic/player/item.rs index 5e90fd1..ab5d393 100644 --- a/servers/game-server/src/logic/player/item.rs +++ b/servers/game-server/src/logic/player/item.rs @@ -37,21 +37,47 @@ impl ItemModel { .avatar_skin_base_template_tb() .for_each(|tmpl| self.item_count_map.insert(tmpl.id(), 1)); - // Unlock all weapons as well - res.templates.weapon_template_tb().for_each(|tmpl| { - let uid = self.next_uid(); - self.weapon_map.insert( - uid, - WeaponItem { - id: tmpl.item_id(), - level: 60, - exp: 0, - star: tmpl.star_limit() + 1, - refine_level: tmpl.refine_limit(), - lock: false, - }, - ); - }); + let weapon_cfg = &res.gameplay.first_login.weapon; + + if weapon_cfg.unlock_all { + res.templates.weapon_template_tb().for_each(|tmpl| { + let uid = self.next_uid(); + self.weapon_map.insert( + uid, + WeaponItem { + id: tmpl.item_id(), + level: weapon_cfg.level, + exp: 0, + star: weapon_cfg.star, + refine_level: weapon_cfg.refine_level, + lock: false, + }, + ); + }); + } else { + weapon_cfg + .unlock_id_list + .iter() + .filter_map(|id| { + res.templates + .weapon_template_tb() + .find(|tmpl| tmpl.item_id() == *id) + }) + .for_each(|tmpl| { + let uid = self.next_uid(); + self.weapon_map.insert( + uid, + WeaponItem { + id: tmpl.item_id(), + level: weapon_cfg.level, + exp: 0, + star: weapon_cfg.star, + refine_level: weapon_cfg.refine_level, + lock: false, + }, + ); + }); + } } pub fn add_weapon(&mut self, template: &WeaponTemplate) -> u32 { diff --git a/servers/game-server/src/logic/player/mod.rs b/servers/game-server/src/logic/player/mod.rs index 975facc..0c27e86 100644 --- a/servers/game-server/src/logic/player/mod.rs +++ b/servers/game-server/src/logic/player/mod.rs @@ -140,21 +140,28 @@ impl Player { // and it won't be needed to set avatar ids in basic module // (player will select them in beginner procedure) + let cfg = &self.resources.gameplay.first_login; + self.avatar_model.on_first_login(self.resources); - self.basic_model.level.set(1); - self.basic_model.avatar_id.set(2011); - self.basic_model.control_avatar_id.set(2011); - self.basic_model.control_guise_avatar_id.set(2011); + self.basic_model.level.set(cfg.interknot_level); + self.basic_model.avatar_id.set(cfg.control_avatar_id); + self.basic_model.control_avatar_id.set(cfg.control_avatar_id); + self.basic_model.control_guise_avatar_id.set(cfg.control_guise_avatar_id); - self.main_city_model.day_of_week.set(5); // Friday + self.main_city_model.day_of_week.set(cfg.day_of_week); self.item_model.on_first_login(self.resources); self.misc_model.on_first_login(self.resources); self.gacha_model.on_first_login(); + let mut main_city_quest_id = 10020001; + if !cfg.start_main_quest { + main_city_quest_id = 10020028; + } + self.quest_model - .add_main_city_quest(10020001, self.resources); + .add_main_city_quest(main_city_quest_id, self.resources); // Initialize hall scene with WorkShop section let scene_uid = self.scene_model.next_scene_uid(); @@ -163,7 +170,7 @@ impl Player { scene::SceneSnapshot { scene_id: 1, ext: scene::SceneSnapshotExt::Hall(scene::HallSceneSnapshot { - cur_section_id: 2, + cur_section_id: cfg.default_section_id, sections: HashMap::new(), main_city_objects_state: HashMap::new(), }), @@ -234,7 +241,7 @@ impl Player { AddItemSource::Mail => Some(PerformType::PerformAnimation), }; - self.avatar_model.unlock_avatar(&template, perform_type); + self.avatar_model.unlock_avatar(&template, perform_type, None); } None } diff --git a/servers/game-server/src/main.rs b/servers/game-server/src/main.rs index f6323db..1034ce1 100644 --- a/servers/game-server/src/main.rs +++ b/servers/game-server/src/main.rs @@ -47,6 +47,10 @@ async fn main() -> Result<(), StartupError> { concatcp!(CONFIG_DIR, "gacha_schedule.toml"), include_str!("../gacha_schedule.default.toml"), ), + first_login: common::config_util::load_or_create( + concatcp!(CONFIG_DIR, "first_login.toml"), + include_str!("../first_login.default.toml"), + ), }; let resources = NapResources::load(&config.resources, gameplay_cfg)?; diff --git a/servers/game-server/src/resources.rs b/servers/game-server/src/resources.rs index b97aea0..a3dd8fd 100644 --- a/servers/game-server/src/resources.rs +++ b/servers/game-server/src/resources.rs @@ -5,7 +5,7 @@ use config::{ LoadConditionsError, TemplateCollection, TemplateCollectionError, }; -use crate::config::{GachaScheduleConfig, ResourceConfig}; +use crate::config::{FirstLoginConfig, GachaScheduleConfig, ResourceConfig}; #[derive(thiserror::Error, Debug)] pub enum LoadResourcesError { @@ -40,6 +40,7 @@ pub struct NapResources { pub struct ServerGameplayConfig { pub gacha_schedule: GachaScheduleConfig, + pub first_login: FirstLoginConfig, } impl NapResources {