forked from yixuan-rs/yixuan-rs
Added FirstLoginConfig
This commit is contained in:
parent
aec5a50d3e
commit
ad0d79acc1
7 changed files with 157 additions and 45 deletions
23
servers/game-server/first_login.default.toml
Normal file
23
servers/game-server/first_login.default.toml
Normal file
|
@ -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
|
|
@ -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<u32>,
|
||||
pub level: u32,
|
||||
pub rank: u32,
|
||||
pub unlocked_talent_num: u32,
|
||||
pub talent_switch: Vec<bool>,
|
||||
pub passive_skill_level: u32,
|
||||
pub skill_level_map: Vec<u32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct FirstLoginWeaponConfig {
|
||||
pub unlock_all: bool,
|
||||
#[serde(default)]
|
||||
pub unlock_id_list: Vec<u32>,
|
||||
pub level: u32,
|
||||
pub star: u32,
|
||||
pub refine_level: u32,
|
||||
}
|
|
@ -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<vivian_proto::add_avatar_sc_notify::PerformType>,
|
||||
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<EAvatarSkillType, u32> = (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(),
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue