2.4.1 (#9)
Review this, includes: - Unlocks for weapons - All weapons unlock - Max level weapons - Max resonance weapons - Fixed unlocks for roles, now max level, breakthrought and resonance come from bindata - Unlocks for all skin types(flight, wing, role, skin) - Weapon inventory implemented - Change role skin implemented - Change weapon skin implmented - Change flight skin implemented - Change wing skin implemented - Change weapon implemented(basic, no attributes, no switch) - Created SequenceGenerator to emulate sql sequences with reusable ids Known bugs: - In prod only one projection can be equipped simulataneously, we dont care :xdskull: - Change skin will plot with invalid Rotation so a change of character is required, investigate this Reviewed-on: WutheringSlaves/wicked-waifus-rs#9 Reviewed-by: RabbyDevs <rabbydevs@gmail.com>
This commit is contained in:
parent
3552b7a431
commit
4d6b79aa29
26 changed files with 1297 additions and 114 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -276,9 +276,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.22"
|
version = "1.2.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1"
|
checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -3026,7 +3026,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wicked-waifus-protocol"
|
name = "wicked-waifus-protocol"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://git.xeondev.com/wickedwaifus/wicked-waifus-proto#6f2733c09b78a6e874f379254c9b71fbef23c3a0"
|
source = "git+https://git.xeondev.com/wickedwaifus/wicked-waifus-proto#b358a1ae29335c5c6fd0f1502471c9a90e7f1bf4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
|
@ -3044,7 +3044,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wicked-waifus-protocol-derive"
|
name = "wicked-waifus-protocol-derive"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://git.xeondev.com/wickedwaifus/wicked-waifus-proto#6f2733c09b78a6e874f379254c9b71fbef23c3a0"
|
source = "git+https://git.xeondev.com/wickedwaifus/wicked-waifus-proto#b358a1ae29335c5c6fd0f1502471c9a90e7f1bf4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
55
wicked-waifus-data/src/fly_skin_config.rs
Normal file
55
wicked-waifus-data/src/fly_skin_config.rs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
pub struct FlySkinConfigData {
|
||||||
|
pub id: i32,
|
||||||
|
pub skin_type: i32,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub model_id: i32,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub stand_anim: String,
|
||||||
|
pub quality_id: i32,
|
||||||
|
pub skin_grade: i32,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub name: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub type_description: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub attributes_description: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub bg_description: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub icon: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub icon_middle: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub icon_small: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub mesh: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub obtained_show_description: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub show_in_bag: bool,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub item_access: Vec<i32>,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub sort_index: i32,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub red_dot_disable_rule: i32,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub preview_texture_in_buy_view: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub preview_texture_in_pay_shop: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub preview_texture_in_pop: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub skin_obtain_color1: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub skin_obtain_color2: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub skin_obtain_image: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub is_special_view_after_obtain: bool,
|
||||||
|
}
|
|
@ -125,6 +125,7 @@ json_data! {
|
||||||
FavorLevel;
|
FavorLevel;
|
||||||
FavorStory;
|
FavorStory;
|
||||||
FavorWord;
|
FavorWord;
|
||||||
|
FlySkinConfig;
|
||||||
ForgeFormula;
|
ForgeFormula;
|
||||||
FunctionCondition;
|
FunctionCondition;
|
||||||
Gacha;
|
Gacha;
|
||||||
|
@ -145,7 +146,6 @@ json_data! {
|
||||||
ResonanceAmplification;
|
ResonanceAmplification;
|
||||||
ResonantChain;
|
ResonantChain;
|
||||||
RoleBreach;
|
RoleBreach;
|
||||||
RoleExpItem;
|
|
||||||
RoleInfo;
|
RoleInfo;
|
||||||
RoleLevelConsume;
|
RoleLevelConsume;
|
||||||
RolePropertyGrowth;
|
RolePropertyGrowth;
|
||||||
|
@ -159,6 +159,7 @@ json_data! {
|
||||||
WeaponLevel;
|
WeaponLevel;
|
||||||
WeaponPropertyGrowth;
|
WeaponPropertyGrowth;
|
||||||
WeaponReson;
|
WeaponReson;
|
||||||
|
WeaponSkin;
|
||||||
}
|
}
|
||||||
|
|
||||||
json_hash_table_data! {
|
json_hash_table_data! {
|
||||||
|
@ -167,6 +168,7 @@ json_hash_table_data! {
|
||||||
BlueprintConfig, blueprint_type, String;
|
BlueprintConfig, blueprint_type, String;
|
||||||
DragonPool, id, i32;
|
DragonPool, id, i32;
|
||||||
DropPackage, id, i32;
|
DropPackage, id, i32;
|
||||||
|
RoleExpItem, id, i32;
|
||||||
TemplateConfig, blueprint_type, String;
|
TemplateConfig, blueprint_type, String;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +186,10 @@ pub mod level_entity_config_data {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(map_id: i32, entity_id: i64) -> Option<&'static Data> {
|
pub fn get(map_id: i32, entity_id: i64) -> Option<&'static Data> {
|
||||||
TABLE.get().unwrap().get(&create_key_internal(map_id, entity_id))
|
TABLE
|
||||||
|
.get()
|
||||||
|
.unwrap()
|
||||||
|
.get(&create_key_internal(map_id, entity_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -207,10 +212,9 @@ fn load_json_entity_level_config_data(base_path: &str) -> Result<(), LoadDataErr
|
||||||
serde_json::from_reader::<BufReader<File>, Vec<level_entity_config_data::Data>>(reader)?
|
serde_json::from_reader::<BufReader<File>, Vec<level_entity_config_data::Data>>(reader)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|element| (level_entity_config_data::create_key(&element), element))
|
.map(|element| (level_entity_config_data::create_key(&element), element))
|
||||||
.collect::<std::collections::HashMap<_, _>>()
|
.collect::<std::collections::HashMap<_, _>>(),
|
||||||
);
|
);
|
||||||
tracing::info!("Loading data finished: {path}");
|
tracing::info!("Loading data finished: {path}");
|
||||||
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
54
wicked-waifus-data/src/weapon_skin.rs
Normal file
54
wicked-waifus-data/src/weapon_skin.rs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))]
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
pub struct WeaponSkinData {
|
||||||
|
pub id: i32,
|
||||||
|
pub weapon_skin_type: i32,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub name: String,
|
||||||
|
pub hide_in_skin_view: bool,
|
||||||
|
pub quality_id: i32,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub model_id: i32,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub transform_id: i32,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub models: Vec<i32>,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub type_description: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub attributes_description: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub bg_description: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub card_icon_path: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub icon: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub icon_middle: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub icon_small: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
#[serde(rename = "MaxCapcity")] // kuro!
|
||||||
|
pub max_capacity: i32,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub item_access: Vec<i32>,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub obtained_show: i32,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub obtained_show_description: String,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub num_limit: i32,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub show_in_bag: bool,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub sort_index: i32,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub hidden_time: i32,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub destructible: bool,
|
||||||
|
#[cfg(feature = "strict_json_fields")]
|
||||||
|
pub red_dot_disable_rule: i32,
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ load_textmaps = true
|
||||||
quadrant_size = 1000000
|
quadrant_size = 1000000
|
||||||
|
|
||||||
[asset_config]
|
[asset_config]
|
||||||
asset_url = "https://git.xeondev.com/wickedwaifus/wicked-waifus-data/releases/download/pioneer_2.4.1/bundle.zip"
|
asset_url = "https://git.xeondev.com/wickedwaifus/wicked-waifus-data/releases/download/pioneer_2.4.4/bundle.zip"
|
||||||
buffer_size = 268435456
|
buffer_size = 268435456
|
||||||
|
|
||||||
[default_unlocks]
|
[default_unlocks]
|
||||||
|
@ -28,8 +28,15 @@ unlock_all_roles_max_level = false
|
||||||
unlock_all_roles_all_sequences = false
|
unlock_all_roles_all_sequences = false
|
||||||
unlock_all_mc_elements = true
|
unlock_all_mc_elements = true
|
||||||
unlock_all_weapons = false
|
unlock_all_weapons = false
|
||||||
|
unlock_all_weapons_max_level = false
|
||||||
|
unlock_all_weapons_all_reson = false
|
||||||
unlock_all_adventures = false
|
unlock_all_adventures = false
|
||||||
unlock_all_functions = true
|
unlock_all_functions = true
|
||||||
unlock_all_guides = false
|
unlock_all_guides = false
|
||||||
unlock_all_tutorials = false
|
unlock_all_tutorials = false
|
||||||
unlock_all_teleporter = false
|
unlock_all_teleporter = false
|
||||||
|
unlock_all_role_skins = false
|
||||||
|
# TODO: Set this to the same value as unlock_all_role_skins, without it, it fails(maybe jinshi weapon skin problem??)
|
||||||
|
unlock_all_weapon_skins = false
|
||||||
|
unlock_all_fly_skins = false
|
||||||
|
unlock_all_wing_skins = false
|
|
@ -37,12 +37,18 @@ pub struct DefaultUnlocks {
|
||||||
pub unlock_all_roles_max_level: bool,
|
pub unlock_all_roles_max_level: bool,
|
||||||
pub unlock_all_roles_all_sequences: bool,
|
pub unlock_all_roles_all_sequences: bool,
|
||||||
pub unlock_all_mc_elements: bool,
|
pub unlock_all_mc_elements: bool,
|
||||||
pub unlock_all_weapons: bool, // TODO:
|
pub unlock_all_weapons: bool,
|
||||||
|
pub unlock_all_weapons_max_level: bool,
|
||||||
|
pub unlock_all_weapons_all_reson: bool,
|
||||||
pub unlock_all_adventures: bool,
|
pub unlock_all_adventures: bool,
|
||||||
pub unlock_all_functions: bool,
|
pub unlock_all_functions: bool,
|
||||||
pub unlock_all_guides: bool,
|
pub unlock_all_guides: bool,
|
||||||
pub unlock_all_tutorials: bool,
|
pub unlock_all_tutorials: bool,
|
||||||
pub unlock_all_teleporter: bool,
|
pub unlock_all_teleporter: bool,
|
||||||
|
pub unlock_all_role_skins: bool,
|
||||||
|
pub unlock_all_weapon_skins: bool,
|
||||||
|
pub unlock_all_fly_skins: bool,
|
||||||
|
pub unlock_all_wing_skins: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TomlConfig for ServiceConfig {
|
impl TomlConfig for ServiceConfig {
|
||||||
|
|
|
@ -19,6 +19,7 @@ mod summoner;
|
||||||
mod tag;
|
mod tag;
|
||||||
mod visibility;
|
mod visibility;
|
||||||
mod vision_skill;
|
mod vision_skill;
|
||||||
|
mod weapon_skin;
|
||||||
|
|
||||||
pub use attribute::Attribute;
|
pub use attribute::Attribute;
|
||||||
pub use autonomous::Autonomous;
|
pub use autonomous::Autonomous;
|
||||||
|
@ -41,3 +42,4 @@ pub use summoner::Summoner;
|
||||||
pub use tag::Tag;
|
pub use tag::Tag;
|
||||||
pub use visibility::Visibility;
|
pub use visibility::Visibility;
|
||||||
pub use vision_skill::VisionSkill;
|
pub use vision_skill::VisionSkill;
|
||||||
|
pub use weapon_skin::WeaponSkin;
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
use wicked_waifus_protocol::entity_component_pb::ComponentPb;
|
||||||
|
use wicked_waifus_protocol::{EntityComponentPb, WeaponSkinComponentPb};
|
||||||
|
use crate::logic::ecs::component::Component;
|
||||||
|
|
||||||
|
pub struct WeaponSkin {
|
||||||
|
pub skin_id: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for WeaponSkin {
|
||||||
|
fn set_pb_data(&self, pb: &mut wicked_waifus_protocol::EntityPb) {
|
||||||
|
pb.component_pbs.push(EntityComponentPb {
|
||||||
|
component_pb: Some(ComponentPb::WeaponSkinComponentPb(WeaponSkinComponentPb {
|
||||||
|
weapon_skin_id: self.skin_id,
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,6 +44,7 @@ impl_component_container! {
|
||||||
Summoner;
|
Summoner;
|
||||||
SoarWingSkin;
|
SoarWingSkin;
|
||||||
ParaglidingSkin;
|
ParaglidingSkin;
|
||||||
|
WeaponSkin;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Component {
|
pub trait Component {
|
||||||
|
|
|
@ -113,7 +113,13 @@ impl GachaPool {
|
||||||
match player.role_list.get(&item_id) {
|
match player.role_list.get(&item_id) {
|
||||||
None => {
|
None => {
|
||||||
if required_role_ids.contains(&item_id) {
|
if required_role_ids.contains(&item_id) {
|
||||||
player.role_list.insert(item_id, Role::new(item_id));
|
let role = Role::new(item_id);
|
||||||
|
let role_id = role.role_id;
|
||||||
|
let weapon_id = role.equip_weapon;
|
||||||
|
player.role_list.insert(item_id, role);
|
||||||
|
// TODO notifies player update
|
||||||
|
player.inventory.add_weapon(role_id, 0, 1, 0, 0, 0, weapon_id).unwrap();
|
||||||
|
// TODO notifies weapon update
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(role) => {
|
Some(role) => {
|
||||||
|
|
|
@ -33,7 +33,6 @@ dummy_handler! {
|
||||||
ExchangeReward;
|
ExchangeReward;
|
||||||
Liveness;
|
Liveness;
|
||||||
PhotoMemory;
|
PhotoMemory;
|
||||||
WeaponSkin;
|
|
||||||
VisionEquipGroupInfo;
|
VisionEquipGroupInfo;
|
||||||
UpdatePlayStationBlockAccount;
|
UpdatePlayStationBlockAccount;
|
||||||
AdventureManual;
|
AdventureManual;
|
||||||
|
|
|
@ -12,12 +12,11 @@ pub fn on_normal_item_request(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_weapon_item_request(
|
pub fn on_weapon_item_request(
|
||||||
_player: &mut Player,
|
player: &mut Player,
|
||||||
_: WeaponItemRequest,
|
_: WeaponItemRequest,
|
||||||
_response: &mut WeaponItemResponse,
|
response: &mut WeaponItemResponse,
|
||||||
) {
|
) {
|
||||||
// TODO: Implement this
|
response.weapon_item_list = player.inventory.to_weapon_item_list();
|
||||||
tracing::warn!("Unhandled WeaponItemRequest");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_phantom_item_request(
|
pub fn on_phantom_item_request(
|
||||||
|
|
|
@ -19,6 +19,7 @@ use wicked_waifus_protocol::message::Message;
|
||||||
pub use skill::*;
|
pub use skill::*;
|
||||||
pub use teleport::*;
|
pub use teleport::*;
|
||||||
pub use tutorial::*;
|
pub use tutorial::*;
|
||||||
|
pub use weapon::*;
|
||||||
|
|
||||||
mod advice;
|
mod advice;
|
||||||
mod animal;
|
mod animal;
|
||||||
|
@ -40,6 +41,7 @@ mod scene;
|
||||||
mod skill;
|
mod skill;
|
||||||
mod teleport;
|
mod teleport;
|
||||||
mod tutorial;
|
mod tutorial;
|
||||||
|
mod weapon;
|
||||||
|
|
||||||
macro_rules! handle_request {
|
macro_rules! handle_request {
|
||||||
($($name:ident $(, $inner_package:ident)?;)*) => {
|
($($name:ident $(, $inner_package:ident)?;)*) => {
|
||||||
|
@ -200,13 +202,19 @@ handle_request! {
|
||||||
RoleFavorList;
|
RoleFavorList;
|
||||||
FormationAttr;
|
FormationAttr;
|
||||||
UpdateFormation;
|
UpdateFormation;
|
||||||
|
UnlockRoleSkinList;
|
||||||
|
RoleSkinChange;
|
||||||
|
FlySkinWear;
|
||||||
|
FlySkinWearAllRole;
|
||||||
|
RoleLevelUpView;
|
||||||
|
PbUpLevelRole;
|
||||||
|
RoleBreakThroughView;
|
||||||
|
|
||||||
// Scene (TODO: Review this on_..., port some from go)
|
// Scene (TODO: Review this on_..., port some from go)
|
||||||
SceneTrace;
|
SceneTrace;
|
||||||
SceneLoadingFinish;
|
SceneLoadingFinish;
|
||||||
UpdateSceneDate;
|
UpdateSceneDate;
|
||||||
AccessPathTimeServerConfig;
|
AccessPathTimeServerConfig;
|
||||||
UnlockRoleSkinList;
|
|
||||||
PlayerHeadData;
|
PlayerHeadData;
|
||||||
|
|
||||||
// Shop (TODO: Review this on_..., port some from go)
|
// Shop (TODO: Review this on_..., port some from go)
|
||||||
|
@ -237,6 +245,12 @@ handle_request! {
|
||||||
TutorialReceive;
|
TutorialReceive;
|
||||||
TutorialUnlock;
|
TutorialUnlock;
|
||||||
|
|
||||||
|
// Weapon
|
||||||
|
WeaponSkin;
|
||||||
|
EquipWeaponSkin;
|
||||||
|
SendEquipSkin;
|
||||||
|
EquipTakeOn;
|
||||||
|
|
||||||
// TODO: Implement all this properly, workaround for game enter
|
// TODO: Implement all this properly, workaround for game enter
|
||||||
EntityPatrolStop;
|
EntityPatrolStop;
|
||||||
InitRange;
|
InitRange;
|
||||||
|
@ -264,7 +278,6 @@ handle_request! {
|
||||||
Liveness;
|
Liveness;
|
||||||
WebSign;
|
WebSign;
|
||||||
PhotoMemory;
|
PhotoMemory;
|
||||||
WeaponSkin;
|
|
||||||
VisionEquipGroupInfo;
|
VisionEquipGroupInfo;
|
||||||
UpdatePlayStationBlockAccount;
|
UpdatePlayStationBlockAccount;
|
||||||
AdventureManual;
|
AdventureManual;
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use wicked_waifus_protocol::{
|
use crate::logic::components::{ParaglidingSkin, RoleSkin, SoarWingSkin, WeaponSkin};
|
||||||
ClientCurrentRoleReportRequest, ClientCurrentRoleReportResponse, ERemoveEntityType, ErrorCode,
|
use crate::logic::ecs::component::ComponentContainer;
|
||||||
FormationAttrRequest, FormationAttrResponse, PlayerMotionRequest, PlayerMotionResponse,
|
use crate::logic::player::{ItemUsage, Player};
|
||||||
RoleFavorListRequest, RoleFavorListResponse, RoleShowListUpdateRequest,
|
|
||||||
RoleShowListUpdateResponse, UpdateFormationRequest, UpdateFormationResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::logic::player::Player;
|
|
||||||
use crate::logic::role::{Role, RoleFormation};
|
use crate::logic::role::{Role, RoleFormation};
|
||||||
|
use crate::modify_component;
|
||||||
|
use wicked_waifus_protocol::{ArrayIntInt, ClientCurrentRoleReportRequest, ClientCurrentRoleReportResponse, ERemoveEntityType, EntityAddNotify, EntityEquipSkinChangeNotify, EntityFlySkinChangeData, EntityPb, EntityRemoveInfo, EntityRemoveNotify, EquipFlySkinData, ErrorCode, FlySkinConfigData, FlySkinWearAllRoleRequest, FlySkinWearAllRoleResponse, FlySkinWearRequest, FlySkinWearResponse, FormationAttrRequest, FormationAttrResponse, PbUpLevelRoleRequest, PbUpLevelRoleResponse, PlayerMotionRequest, PlayerMotionResponse, RoleBreakThroughViewRequest, RoleBreakThroughViewResponse, RoleFavorListRequest, RoleFavorListResponse, RoleFlyEquipChangeNotify, RoleLevelUpViewRequest, RoleLevelUpViewResponse, RoleShowListUpdateRequest, RoleShowListUpdateResponse, RoleSkinChangeRequest, RoleSkinChangeResponse, SoarWingOrParaglidingSkinChangeNotify, UnlockRoleSkinListRequest, UnlockRoleSkinListResponse, UpdateFormationRequest, UpdateFormationResponse, WeaponSkinComponentPb};
|
||||||
|
|
||||||
pub fn on_role_show_list_update_request(
|
pub fn on_role_show_list_update_request(
|
||||||
player: &mut Player,
|
player: &mut Player,
|
||||||
|
@ -152,3 +149,421 @@ pub fn on_player_motion_request(
|
||||||
Some(_) => response.error_id = ErrorCode::Success.into(),
|
Some(_) => response.error_id = ErrorCode::Success.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn on_unlock_role_skin_list_request(
|
||||||
|
player: &Player,
|
||||||
|
_request: UnlockRoleSkinListRequest,
|
||||||
|
response: &mut UnlockRoleSkinListResponse,
|
||||||
|
) {
|
||||||
|
response.role_skin_list = player.unlocked_skins.role_skins.iter().cloned().collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_role_skin_change_request(
|
||||||
|
player: &mut Player,
|
||||||
|
request: RoleSkinChangeRequest,
|
||||||
|
response: &mut RoleSkinChangeResponse,
|
||||||
|
) {
|
||||||
|
// TODO: Should we verify role id first against bindata?
|
||||||
|
let role = player.role_list.get_mut(&request.role_id);
|
||||||
|
let Some(role) = role else {
|
||||||
|
response.error_code = ErrorCode::NotValidRole.into();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verify Id exist in bindata
|
||||||
|
let Some(skin_data) =
|
||||||
|
wicked_waifus_data::role_skin_data::iter().find(|data| data.id == request.skin_id)
|
||||||
|
else {
|
||||||
|
response.error_code = ErrorCode::ErrRoleSkinConfig.into();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verify Skin is unlocked
|
||||||
|
if !player.unlocked_skins.role_skins.contains(&skin_data.id) {
|
||||||
|
response.error_code = ErrorCode::ErrRoleSkinLocked.into();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that role has this skin
|
||||||
|
if skin_data.role_id != role.role_id {
|
||||||
|
response.error_code = ErrorCode::ErrRoleSkinNotMatch.into();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
role.skin_id = request.skin_id;
|
||||||
|
if request.is_wear_weapon_skin {
|
||||||
|
if skin_data.suit_weapon_skin_id == 0 {
|
||||||
|
response.error_code = ErrorCode::ErrRoleSkinWeaponNotSuit.into();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
role.weapon_skin_id = skin_data.suit_weapon_skin_id;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let world_ref = player.world.borrow();
|
||||||
|
let world = world_ref.get_world_entity();
|
||||||
|
let entity_id = world.get_entity_id(request.role_id);
|
||||||
|
modify_component!(
|
||||||
|
world.get_entity_components(entity_id as i32),
|
||||||
|
RoleSkin,
|
||||||
|
|skin_component: &mut RoleSkin| {
|
||||||
|
skin_component.skin_id = role.skin_id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if request.is_wear_weapon_skin {
|
||||||
|
// Check for suit_weapon_skin_id == 0 has already been done
|
||||||
|
modify_component!(
|
||||||
|
world.get_entity_components(entity_id as i32),
|
||||||
|
WeaponSkin,
|
||||||
|
|skin_component: &mut WeaponSkin| {
|
||||||
|
skin_component.skin_id = skin_data.suit_weapon_skin_id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// Since the whole entity is recreated this shouldn't be needed but meh, whatever
|
||||||
|
player.notify(EntityEquipSkinChangeNotify {
|
||||||
|
entity_id,
|
||||||
|
weapon_skin_component_pb: Some(WeaponSkinComponentPb {
|
||||||
|
weapon_skin_id:skin_data.suit_weapon_skin_id,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
player.notify(EntityRemoveNotify {
|
||||||
|
remove_infos: vec![EntityRemoveInfo {
|
||||||
|
entity_id,
|
||||||
|
r#type: 0,
|
||||||
|
}],
|
||||||
|
is_remove: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut pb = EntityPb {
|
||||||
|
id: entity_id,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
world
|
||||||
|
.get_entity_components(entity_id as i32)
|
||||||
|
.into_iter()
|
||||||
|
.for_each(|comp| comp.set_pb_data(&mut pb));
|
||||||
|
|
||||||
|
player.notify(EntityAddNotify {
|
||||||
|
entity_pbs: vec![pb],
|
||||||
|
remove_tag_ids: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
player.notify(player.build_update_formation_notify());
|
||||||
|
response.error_code = ErrorCode::Success.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_fly_skin_wear_request(
|
||||||
|
player: &mut Player,
|
||||||
|
request: FlySkinWearRequest,
|
||||||
|
response: &mut FlySkinWearResponse,
|
||||||
|
) {
|
||||||
|
let role = player.role_list.get_mut(&request.role_id);
|
||||||
|
let Some(role) = role else {
|
||||||
|
response.error_code = ErrorCode::NotValidRole.into();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verify Id exist in bindata
|
||||||
|
let skin =
|
||||||
|
wicked_waifus_data::fly_skin_config_data::iter().find(|&skin| skin.id == request.skin_id);
|
||||||
|
let Some(skin) = skin else {
|
||||||
|
response.error_code = ErrorCode::NoFlySkinItem.into();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
match skin.skin_type {
|
||||||
|
0 => {
|
||||||
|
// Verify Skin is unlocked
|
||||||
|
if !player.unlocked_skins.fly_skins.contains(&skin.id) {
|
||||||
|
response.error_code = ErrorCode::ErrRoleSkinLocked.into();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
role.fly_skin_id = request.skin_id
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
if !player.unlocked_skins.wing_skins.contains(&skin.id) {
|
||||||
|
response.error_code = ErrorCode::ErrRoleSkinLocked.into();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
role.wing_skin_id = request.skin_id
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
response.error_code = ErrorCode::FlySkinTypeErr.into();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let world_ref = player.world.borrow();
|
||||||
|
let world = world_ref.get_world_entity();
|
||||||
|
let entity_id = world.get_entity_id(request.role_id);
|
||||||
|
match skin.skin_type {
|
||||||
|
0 => {
|
||||||
|
modify_component!(
|
||||||
|
world.get_entity_components(entity_id as i32),
|
||||||
|
SoarWingSkin,
|
||||||
|
|skin_component: &mut SoarWingSkin| {
|
||||||
|
skin_component.skin_id = role.skin_id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
modify_component!(
|
||||||
|
world.get_entity_components(entity_id as i32),
|
||||||
|
ParaglidingSkin,
|
||||||
|
|skin_component: &mut ParaglidingSkin| {
|
||||||
|
skin_component.skin_id = role.skin_id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => unreachable!("Already tested above"),
|
||||||
|
}
|
||||||
|
player.notify(SoarWingOrParaglidingSkinChangeNotify {
|
||||||
|
fly_skin_data: vec![EntityFlySkinChangeData {
|
||||||
|
entity_id,
|
||||||
|
fly_skin_config_data: vec![FlySkinConfigData {
|
||||||
|
skin_id: request.skin_id,
|
||||||
|
fly_skin_id: skin.skin_type,
|
||||||
|
}],
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
player.notify(RoleFlyEquipChangeNotify {
|
||||||
|
fly_skin_data: vec![EquipFlySkinData {
|
||||||
|
role_id: request.role_id,
|
||||||
|
skin_id: request.skin_id,
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
response.error_code = ErrorCode::Success.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_fly_skin_wear_all_role_request(
|
||||||
|
player: &mut Player,
|
||||||
|
request: FlySkinWearAllRoleRequest,
|
||||||
|
response: &mut FlySkinWearAllRoleResponse,
|
||||||
|
) {
|
||||||
|
let skin =
|
||||||
|
wicked_waifus_data::fly_skin_config_data::iter().find(|&skin| skin.id == request.skin_id);
|
||||||
|
let Some(skin) = skin else {
|
||||||
|
response.error_code = ErrorCode::NoFlySkinItem.into();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
match skin.skin_type {
|
||||||
|
0 => {
|
||||||
|
// Verify Skin is unlocked
|
||||||
|
if !player.unlocked_skins.fly_skins.contains(&skin.id) {
|
||||||
|
response.error_code = ErrorCode::ErrRoleSkinLocked.into();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for role in player.role_list.values_mut() {
|
||||||
|
role.fly_skin_id = request.skin_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
if !player.unlocked_skins.wing_skins.contains(&skin.id) {
|
||||||
|
response.error_code = ErrorCode::ErrRoleSkinLocked.into();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for role in player.role_list.values_mut() {
|
||||||
|
role.wing_skin_id = request.skin_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
response.error_code = ErrorCode::FlySkinTypeErr.into();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
player.notify(RoleFlyEquipChangeNotify {
|
||||||
|
fly_skin_data: player
|
||||||
|
.role_list
|
||||||
|
.values()
|
||||||
|
.map(|r| EquipFlySkinData {
|
||||||
|
role_id: r.role_id,
|
||||||
|
skin_id: request.skin_id,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
});
|
||||||
|
{
|
||||||
|
let world_ref = player.world.borrow();
|
||||||
|
let world = world_ref.get_world_entity();
|
||||||
|
let data = player
|
||||||
|
.role_list
|
||||||
|
.values()
|
||||||
|
.filter_map(|role| {
|
||||||
|
let entity_id = world.get_entity_id(role.role_id);
|
||||||
|
if entity_id == -1 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
match skin.skin_type {
|
||||||
|
0 => {
|
||||||
|
modify_component!(
|
||||||
|
world.get_entity_components(entity_id as i32),
|
||||||
|
SoarWingSkin,
|
||||||
|
|skin_component: &mut SoarWingSkin| {
|
||||||
|
skin_component.skin_id = role.skin_id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
modify_component!(
|
||||||
|
world.get_entity_components(entity_id as i32),
|
||||||
|
ParaglidingSkin,
|
||||||
|
|skin_component: &mut ParaglidingSkin| {
|
||||||
|
skin_component.skin_id = role.skin_id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => unreachable!("Already tested above"),
|
||||||
|
}
|
||||||
|
Some(EntityFlySkinChangeData {
|
||||||
|
entity_id,
|
||||||
|
fly_skin_config_data: vec![FlySkinConfigData {
|
||||||
|
skin_id: request.skin_id,
|
||||||
|
fly_skin_id: skin.skin_type,
|
||||||
|
}],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
player.notify(SoarWingOrParaglidingSkinChangeNotify {
|
||||||
|
fly_skin_data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
response.error_code = ErrorCode::Success.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_role_level_up_view_request(
|
||||||
|
player: &mut Player,
|
||||||
|
request: RoleLevelUpViewRequest,
|
||||||
|
response: &mut RoleLevelUpViewResponse,
|
||||||
|
) {
|
||||||
|
let role = player.role_list.get(&request.role_id);
|
||||||
|
let Some(role) = role else {
|
||||||
|
response.error_code = ErrorCode::NotValidRole.into();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
response.level = role.level;
|
||||||
|
// TODO: shall we get from data? seems client can do it by himself
|
||||||
|
response.level_exp_info = vec![ArrayIntInt { key: 1, value: 200 }];
|
||||||
|
response.exp = role.exp;
|
||||||
|
// it seems add_exp, final_prop, cost_list amd overflow_list are handled by client, so skip
|
||||||
|
|
||||||
|
let items = wicked_waifus_data::role_exp_item_data::iter()
|
||||||
|
.map(|(&id, _)| id)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
response.item_list = player.inventory.to_array_int_int_filtered(&items);
|
||||||
|
response.error_code = ErrorCode::Success.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_pb_up_level_role_request(
|
||||||
|
player: &mut Player,
|
||||||
|
request: PbUpLevelRoleRequest,
|
||||||
|
response: &mut PbUpLevelRoleResponse,
|
||||||
|
) {
|
||||||
|
response.role_id = request.role_id;
|
||||||
|
let role = player.role_list.get(&request.role_id);
|
||||||
|
let Some(role) = role else {
|
||||||
|
response.error_code = ErrorCode::NotValidRole.into();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: no shell_credit??? :turtle_skull:
|
||||||
|
let items = player.inventory.consume_items(
|
||||||
|
&request
|
||||||
|
.item_list
|
||||||
|
.iter()
|
||||||
|
.map(|item| ItemUsage {
|
||||||
|
id: item.key,
|
||||||
|
quantity: -item.value,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
);
|
||||||
|
let Ok(_items) = items else {
|
||||||
|
response.error_code = ErrorCode::ErrConsumeNotEnough.into();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut total_exp = request
|
||||||
|
.item_list
|
||||||
|
.iter()
|
||||||
|
.filter_map(|item| {
|
||||||
|
wicked_waifus_data::role_exp_item_data::get(&item.key)
|
||||||
|
.map(|exp| exp.basic_exp * item.value)
|
||||||
|
})
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
let role_level_consume_id = wicked_waifus_data::role_info_data::iter()
|
||||||
|
.find(|role| role.id == request.role_id)
|
||||||
|
.map(|role| role.level_consume_id)
|
||||||
|
.unwrap_or(10001);
|
||||||
|
|
||||||
|
let mut levels_consume = wicked_waifus_data::role_level_consume_data::iter()
|
||||||
|
.filter(|consume| {
|
||||||
|
consume.consume_group_id == role_level_consume_id && consume.level > role.level
|
||||||
|
}) // TODO: add upper bound too(till breakthrough)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
levels_consume.sort_by_key(|item| item.level);
|
||||||
|
|
||||||
|
let mut level = role.level;
|
||||||
|
for level_consume in levels_consume {
|
||||||
|
if level_consume.exp_count > total_exp {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
total_exp -= level_consume.exp_count;
|
||||||
|
level = level_consume.level;
|
||||||
|
}
|
||||||
|
response.level = level;
|
||||||
|
response.exp = total_exp;
|
||||||
|
|
||||||
|
// TODO is item_map the overflowing items or all items used? also should we sent more notifies?
|
||||||
|
response.error_code = ErrorCode::Success.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
// on_role_break_through_view_request
|
||||||
|
|
||||||
|
pub fn on_role_break_through_view_request(
|
||||||
|
player: &mut Player,
|
||||||
|
request: RoleBreakThroughViewRequest,
|
||||||
|
response: &mut RoleBreakThroughViewResponse,
|
||||||
|
) {
|
||||||
|
let role = player.role_list.get(&request.role_id);
|
||||||
|
let Some(role) = role else {
|
||||||
|
response.error_code = ErrorCode::NotValidRole.into();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// if !condition {
|
||||||
|
// response.error_code = ErrorCode::ErrRoleConditionNotFind.into();
|
||||||
|
// response.is_condition_finish = false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
let role_breach_id = wicked_waifus_data::role_info_data::iter()
|
||||||
|
.find(|role| role.id == request.role_id)
|
||||||
|
.map(|role| role.breach_id)
|
||||||
|
.unwrap_or(request.role_id);
|
||||||
|
|
||||||
|
let condition = wicked_waifus_data::role_breach_data::iter()
|
||||||
|
.find(|role_breach_data| {
|
||||||
|
role_breach_data.breach_group_id == role_breach_id
|
||||||
|
&& role_breach_data.breach_level == role.breakthrough
|
||||||
|
})
|
||||||
|
.unwrap(); // TODO: handling
|
||||||
|
|
||||||
|
response.error_code = ErrorCode::Success.into();
|
||||||
|
response.level_limit = condition.max_level;
|
||||||
|
|
||||||
|
response.cost_list = condition
|
||||||
|
.breach_consume
|
||||||
|
.iter()
|
||||||
|
.map(|(&id, &count)| ArrayIntInt {
|
||||||
|
key: id,
|
||||||
|
value: count,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
// TODO: un_lock_skill_id, reward_list, final_prop
|
||||||
|
response.is_condition_finish = true; // is this last??
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
use wicked_waifus_protocol::{ErrorCode, SceneLoadingFinishRequest, SceneLoadingFinishResponse, SceneTraceRequest, SceneTraceResponse, UpdateSceneDateRequest, UpdateSceneDateResponse, AccessPathTimeServerConfigRequest, AccessPathTimeServerConfigResponse, PlayerHeadDataRequest, PlayerHeadDataResponse, UnlockRoleSkinListRequest, UnlockRoleSkinListResponse, JsPatchNotify};
|
use wicked_waifus_protocol::{
|
||||||
|
AccessPathTimeServerConfigRequest, AccessPathTimeServerConfigResponse, ErrorCode,
|
||||||
|
JsPatchNotify, PlayerHeadDataRequest, PlayerHeadDataResponse, SceneLoadingFinishRequest,
|
||||||
|
SceneLoadingFinishResponse, SceneTraceRequest, SceneTraceResponse, UpdateSceneDateRequest,
|
||||||
|
UpdateSceneDateResponse,
|
||||||
|
};
|
||||||
|
|
||||||
const WATER_MASK: &str = include_str!("../../../scripts/watermask-disable.js");
|
const WATER_MASK: &str = include_str!("../../../scripts/watermask-disable.js");
|
||||||
const UID_FIX: &str = include_str!("../../../scripts/uidfix.js");
|
const UID_FIX: &str = include_str!("../../../scripts/uidfix.js");
|
||||||
|
@ -65,14 +70,3 @@ pub fn on_player_head_data_request(
|
||||||
// TODO: port this from golang
|
// TODO: port this from golang
|
||||||
response.pi = vec![];
|
response.pi = vec![];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_unlock_role_skin_list_request(
|
|
||||||
_player: &Player,
|
|
||||||
_request: UnlockRoleSkinListRequest,
|
|
||||||
response: &mut UnlockRoleSkinListResponse,
|
|
||||||
) {
|
|
||||||
// TODO: port this from golang
|
|
||||||
response.role_skin_list = wicked_waifus_data::role_skin_data::iter()
|
|
||||||
.map(|data| data.id)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
}
|
|
175
wicked-waifus-game-server/src/logic/handler/weapon.rs
Normal file
175
wicked-waifus-game-server/src/logic/handler/weapon.rs
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
use crate::logic::components::{Equip, WeaponSkin};
|
||||||
|
use crate::logic::ecs::component::ComponentContainer;
|
||||||
|
use crate::logic::player::Player;
|
||||||
|
use crate::modify_component;
|
||||||
|
use wicked_waifus_protocol::{EntityEquipChangeNotify, EntityEquipSkinChangeNotify, EquipComponentPb, EquipTakeOnNotify, EquipTakeOnRequest, EquipTakeOnResponse, EquipWeaponSkinRequest, EquipWeaponSkinResponse, ErrorCode, LoadEquipData, SendEquipSkinRequest, SendEquipSkinResponse, WeaponSkinComponentPb, WeaponSkinDeleteNotify, WeaponSkinRequest, WeaponSkinResponse};
|
||||||
|
|
||||||
|
pub fn on_weapon_skin_request(
|
||||||
|
player: &Player,
|
||||||
|
_request: WeaponSkinRequest,
|
||||||
|
response: &mut WeaponSkinResponse,
|
||||||
|
) {
|
||||||
|
response.equip_list = player
|
||||||
|
.role_list
|
||||||
|
.values()
|
||||||
|
.filter(|role| role.weapon_skin_id != 0)
|
||||||
|
.map(|role| LoadEquipData {
|
||||||
|
role_id: role.role_id,
|
||||||
|
skin_id: role.weapon_skin_id,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
response.error_code = ErrorCode::Success.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_equip_weapon_skin_request(
|
||||||
|
player: &mut Player,
|
||||||
|
request: EquipWeaponSkinRequest,
|
||||||
|
response: &mut EquipWeaponSkinResponse,
|
||||||
|
) {
|
||||||
|
let Some(equip_data) = request.data else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let role = player.role_list.get_mut(&equip_data.role_id);
|
||||||
|
let Some(role) = role else {
|
||||||
|
response.error_code = ErrorCode::NotValidRole.into();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verify Id exist in bindata
|
||||||
|
let Some(skin_data) =
|
||||||
|
wicked_waifus_data::weapon_skin_data::iter().find(|data| data.id == equip_data.skin_id)
|
||||||
|
else {
|
||||||
|
response.error_code = ErrorCode::WeaponSkinDataErr.into();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verify Skin is unlocked
|
||||||
|
if !player.unlocked_skins.weapon_skins.contains(&skin_data.id) {
|
||||||
|
response.error_code = ErrorCode::WeaponSkinUnLockErr.into();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
role.weapon_skin_id = equip_data.skin_id;
|
||||||
|
{
|
||||||
|
let world_ref = player.world.borrow();
|
||||||
|
let world = world_ref.get_world_entity();
|
||||||
|
let entity_id = world.get_entity_id(equip_data.role_id);
|
||||||
|
modify_component!(
|
||||||
|
world.get_entity_components(entity_id as i32),
|
||||||
|
WeaponSkin,
|
||||||
|
|skin_component: &mut WeaponSkin| {
|
||||||
|
skin_component.skin_id = equip_data.skin_id;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
player.notify(EntityEquipSkinChangeNotify {
|
||||||
|
entity_id,
|
||||||
|
weapon_skin_component_pb: Some(WeaponSkinComponentPb {
|
||||||
|
weapon_skin_id: equip_data.skin_id,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the all list needed or only the new one??
|
||||||
|
response.data_list = player
|
||||||
|
.role_list
|
||||||
|
.values()
|
||||||
|
.filter(|role| role.weapon_skin_id != 0)
|
||||||
|
.map(|role| LoadEquipData {
|
||||||
|
role_id: role.role_id,
|
||||||
|
skin_id: role.weapon_skin_id,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
response.error_code = ErrorCode::Success.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_send_equip_skin_request(
|
||||||
|
player: &mut Player,
|
||||||
|
request: SendEquipSkinRequest,
|
||||||
|
response: &mut SendEquipSkinResponse,
|
||||||
|
) {
|
||||||
|
let role = player.role_list.get_mut(&request.role_id);
|
||||||
|
let Some(role) = role else {
|
||||||
|
response.error_code = ErrorCode::NotValidRole.into();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let old_skin_id = role.weapon_skin_id;
|
||||||
|
role.weapon_skin_id = 0;
|
||||||
|
{
|
||||||
|
let world_ref = player.world.borrow();
|
||||||
|
let world = world_ref.get_world_entity();
|
||||||
|
let entity_id = world.get_entity_id(request.role_id);
|
||||||
|
modify_component!(
|
||||||
|
world.get_entity_components(entity_id as i32),
|
||||||
|
WeaponSkin,
|
||||||
|
|skin_component: &mut WeaponSkin| {
|
||||||
|
skin_component.skin_id = 0;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
player.notify(EntityEquipSkinChangeNotify {
|
||||||
|
entity_id,
|
||||||
|
weapon_skin_component_pb: Some(WeaponSkinComponentPb {
|
||||||
|
weapon_skin_id: 0,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
player.notify(WeaponSkinDeleteNotify {
|
||||||
|
role_id: request.role_id,
|
||||||
|
skin_id: old_skin_id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
response.error_code = ErrorCode::Success.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_equip_take_on_request(
|
||||||
|
player: &mut Player,
|
||||||
|
request: EquipTakeOnRequest,
|
||||||
|
response: &mut EquipTakeOnResponse,
|
||||||
|
) {
|
||||||
|
let Some(equip_data) = request.data else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Add sanity checks(add from another role, a.k.a.: switch from roles)
|
||||||
|
player.notify(EquipTakeOnNotify { data_list: vec![equip_data] });
|
||||||
|
|
||||||
|
let role = player.role_list.get_mut(&equip_data.role_id);
|
||||||
|
let Some(role) = role else {
|
||||||
|
response.error_code = ErrorCode::NotValidRole.into();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some((id, breach)) = player.inventory.get_weapon_equip_info(equip_data.equip_inc_id) else {
|
||||||
|
response.error_code = ErrorCode::ErrItemNotFound.into();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
role.equip_weapon = id;
|
||||||
|
|
||||||
|
// TODO: Change attributes based on weapon (PbRolePropsNotify + buffs + CombatNotifyAttributeChangedNotify)
|
||||||
|
|
||||||
|
{
|
||||||
|
// TODO: remove from old one if in scene in case of weapon switch
|
||||||
|
let world_ref = player.world.borrow();
|
||||||
|
let world = world_ref.get_world_entity();
|
||||||
|
let entity_id = world.get_entity_id(equip_data.role_id);
|
||||||
|
modify_component!(
|
||||||
|
world.get_entity_components(entity_id as i32),
|
||||||
|
Equip,
|
||||||
|
|equip_component: &mut Equip| {
|
||||||
|
equip_component.weapon_id = id;
|
||||||
|
equip_component.weapon_breach_level = breach;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
player.notify(EntityEquipChangeNotify {
|
||||||
|
entity_id,
|
||||||
|
equip_component: Some(EquipComponentPb {
|
||||||
|
weapon_id: id,
|
||||||
|
weapon_breach_level: breach,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// TODO: Should we return all of them??
|
||||||
|
response.data_list = vec![equip_data];
|
||||||
|
response.error_code = ErrorCode::Success.into();
|
||||||
|
}
|
|
@ -11,16 +11,16 @@ use wicked_waifus_protocol::{
|
||||||
AdventreTask, AdventureManualData, AdventureUpdateNotify, AdviceSettingNotify, BuffItemNotify,
|
AdventreTask, AdventureManualData, AdventureUpdateNotify, AdviceSettingNotify, BuffItemNotify,
|
||||||
ControlInfoNotify, EEntityType, ERemoveEntityType, EnergyInfo, EnergyUpdateNotify,
|
ControlInfoNotify, EEntityType, ERemoveEntityType, EnergyInfo, EnergyUpdateNotify,
|
||||||
EntityAddNotify, EntityConfigType, EntityPb, EntityRemoveInfo, EntityRemoveNotify, EntityState,
|
EntityAddNotify, EntityConfigType, EntityPb, EntityRemoveInfo, EntityRemoveNotify, EntityState,
|
||||||
FavorItem, FightFormationNotifyInfo, FightRoleInfo, FightRoleInfos, FormationRoleInfo,
|
FavorItem, FightFormationNotifyInfo, FightRoleInfo, FightRoleInfos, FlyEquipAddNotify,
|
||||||
GroupFormation, HostTeleportUnlockNotify, InstDataNotify, ItemPkgOpenNotify,
|
FlySkinEquipData, GroupFormation, HostTeleportUnlockNotify, InstDataNotify, ItemPkgOpenNotify,
|
||||||
LevelPlayInfoNotify, LivingStatus, MailInfosNotify, MapUnlockFieldNotify,
|
LevelPlayInfoNotify, LivingStatus, MailInfosNotify, MonthCardDailyRewardNotify,
|
||||||
MonthCardDailyRewardNotify, MoonChasingTargetGetCountNotify,
|
MoonChasingTargetGetCountNotify, MoonChasingTrackMoonHandbookRewardNotify,
|
||||||
MoonChasingTrackMoonHandbookRewardNotify, NormalItemUpdateNotify, PassiveSkillNotify,
|
NormalItemUpdateNotify, PassiveSkillNotify, PbGetRoleListNotify, PlayerAttr, PlayerAttrKey,
|
||||||
PbGetRoleListNotify, PlayerAttr, PlayerAttrKey, PlayerAttrNotify, PlayerAttrType,
|
PlayerAttrNotify, PlayerAttrType, PlayerFightFormations, PlayerVarNotify, ProtocolUnit,
|
||||||
PlayerFightFormations, PlayerVarNotify, ProtocolUnit, PushContextIdNotify,
|
PushContextIdNotify, PushDataCompleteNotify, RoguelikeCurrencyNotify, RoleChangeUnlockNotify,
|
||||||
PushDataCompleteNotify, RoguelikeCurrencyNotify, RoleChangeUnlockNotify, RoleFavor,
|
RoleFavor, RoleFavorListNotify, RoleFlyEquipNotify, RoleMotion, RoleMotionListNotify,
|
||||||
RoleFavorListNotify, RoleMotion, RoleMotionListNotify, SettingNotify, TeleportUpdateNotify,
|
SettingNotify, TeleportUpdateNotify, UnlockSkinDataNotify, UpdateFormationNotify,
|
||||||
UpdateFormationNotify, UpdateGroupFormationNotify,
|
UpdateGroupFormationNotify,
|
||||||
};
|
};
|
||||||
use wicked_waifus_protocol_internal::{PlayerBasicData, PlayerRoleData, PlayerSaveData};
|
use wicked_waifus_protocol_internal::{PlayerBasicData, PlayerRoleData, PlayerSaveData};
|
||||||
|
|
||||||
|
@ -46,16 +46,17 @@ use crate::logic::player::player_mc_element::PlayerMcElement;
|
||||||
use crate::logic::player::player_month_card::PlayerMonthCard;
|
use crate::logic::player::player_month_card::PlayerMonthCard;
|
||||||
use crate::logic::player::player_teleports::{PlayerTeleport, PlayerTeleports};
|
use crate::logic::player::player_teleports::{PlayerTeleport, PlayerTeleports};
|
||||||
use crate::logic::player::player_tutorials::{PlayerTutorial, PlayerTutorials};
|
use crate::logic::player::player_tutorials::{PlayerTutorial, PlayerTutorials};
|
||||||
|
use crate::logic::player::Element::Spectro;
|
||||||
use crate::logic::{
|
use crate::logic::{
|
||||||
components::{
|
components::{
|
||||||
Attribute, EntityConfig, Equip, FightBuff, Movement, OwnerPlayer, PlayerOwnedEntityMarker,
|
Attribute, EntityConfig, Equip, FightBuff, Movement, OwnerPlayer, ParaglidingSkin,
|
||||||
Position, Visibility, VisionSkill, SoarWingSkin
|
PlayerOwnedEntityMarker, Position, SoarWingSkin, Visibility, VisionSkill, WeaponSkin,
|
||||||
},
|
},
|
||||||
ecs::component::ComponentContainer,
|
ecs::component::ComponentContainer,
|
||||||
};
|
};
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
use crate::{config, create_player_entity_pb, query_components};
|
use crate::{config, create_player_entity_pb};
|
||||||
use crate::logic::player::Element::Spectro;
|
use crate::logic::player::player_unlocked_skins::PlayerUnlockedSkins;
|
||||||
|
|
||||||
mod basic_info;
|
mod basic_info;
|
||||||
mod explore_tools;
|
mod explore_tools;
|
||||||
|
@ -72,6 +73,7 @@ mod player_mc_element;
|
||||||
mod player_month_card;
|
mod player_month_card;
|
||||||
mod player_teleports;
|
mod player_teleports;
|
||||||
mod player_tutorials;
|
mod player_tutorials;
|
||||||
|
mod player_unlocked_skins;
|
||||||
|
|
||||||
pub struct Player {
|
pub struct Player {
|
||||||
session: Option<Arc<Session>>,
|
session: Option<Arc<Session>>,
|
||||||
|
@ -93,6 +95,7 @@ pub struct Player {
|
||||||
pub map_trace: PlayerMapTrace,
|
pub map_trace: PlayerMapTrace,
|
||||||
pub month_card: PlayerMonthCard,
|
pub month_card: PlayerMonthCard,
|
||||||
pub mc_element: PlayerMcElement,
|
pub mc_element: PlayerMcElement,
|
||||||
|
pub unlocked_skins: PlayerUnlockedSkins,
|
||||||
// Runtime
|
// Runtime
|
||||||
pub world: Rc<RefCell<World>>,
|
pub world: Rc<RefCell<World>>,
|
||||||
pub last_save_time: u64,
|
pub last_save_time: u64,
|
||||||
|
@ -123,6 +126,10 @@ impl Player {
|
||||||
self.notify(self.explore_tools.build_roulette_update_notify());
|
self.notify(self.explore_tools.build_roulette_update_notify());
|
||||||
self.notify(self.build_role_favor_list_notify());
|
self.notify(self.build_role_favor_list_notify());
|
||||||
self.notify(self.func.build_func_open_notify());
|
self.notify(self.func.build_func_open_notify());
|
||||||
|
self.notify(self.build_weapon_skin_notify());
|
||||||
|
self.notify(self.build_fly_equip_notify());
|
||||||
|
self.notify(self.build_role_fly_equip_notify());
|
||||||
|
|
||||||
self.notify(InstDataNotify {
|
self.notify(InstDataNotify {
|
||||||
enter_infos: vec![], // TODO: No effect in normal world, to implement for dungeon::logic()
|
enter_infos: vec![], // TODO: No effect in normal world, to implement for dungeon::logic()
|
||||||
});
|
});
|
||||||
|
@ -211,6 +218,11 @@ impl Player {
|
||||||
self.role_list.insert(role_id, Role::new(role_id));
|
self.role_list.insert(role_id, Role::new(role_id));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
for role in self.role_list.values() {
|
||||||
|
self.inventory
|
||||||
|
.add_weapon(role.equip_weapon, 0, 1, 0, 0, 0, role.role_id)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
self.formation_list.insert(1, RoleFormation::default());
|
self.formation_list.insert(1, RoleFormation::default());
|
||||||
self.cur_formation_id = 1;
|
self.cur_formation_id = 1;
|
||||||
|
@ -305,8 +317,8 @@ impl Player {
|
||||||
RoleFavorListNotify {
|
RoleFavorListNotify {
|
||||||
favor_list: self
|
favor_list: self
|
||||||
.role_list
|
.role_list
|
||||||
.iter()
|
.values()
|
||||||
.map(|(_, role)| RoleFavor {
|
.map(|role| RoleFavor {
|
||||||
role_id: role.role_id,
|
role_id: role.role_id,
|
||||||
level: role.favor_level,
|
level: role.favor_level,
|
||||||
exp: role.favor_exp,
|
exp: role.favor_exp,
|
||||||
|
@ -338,12 +350,73 @@ impl Player {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn build_weapon_skin_notify(&self) -> UnlockSkinDataNotify {
|
||||||
|
UnlockSkinDataNotify {
|
||||||
|
phantom_skin_list: self.unlocked_skins.weapon_skins.iter().cloned().collect(),
|
||||||
|
is_login: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_fly_equip_notify(&self) -> FlyEquipAddNotify {
|
||||||
|
FlyEquipAddNotify {
|
||||||
|
unlock_fly_skin_ids: self
|
||||||
|
.unlocked_skins
|
||||||
|
.fly_skins
|
||||||
|
.iter()
|
||||||
|
.chain(&self.unlocked_skins.wing_skins)
|
||||||
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_role_fly_equip_notify(&self) -> RoleFlyEquipNotify {
|
||||||
|
let merged: Vec<_> = self
|
||||||
|
.unlocked_skins
|
||||||
|
.fly_skins
|
||||||
|
.iter()
|
||||||
|
.chain(&self.unlocked_skins.wing_skins)
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut equipped_skins: HashMap<i32, Vec<i32>> = HashMap::new();
|
||||||
|
for role in self.role_list.values() {
|
||||||
|
if role.fly_skin_id != 0 {
|
||||||
|
equipped_skins
|
||||||
|
.entry(role.fly_skin_id)
|
||||||
|
.or_default()
|
||||||
|
.push(role.role_id);
|
||||||
|
}
|
||||||
|
if role.wing_skin_id != 0 {
|
||||||
|
equipped_skins
|
||||||
|
.entry(role.wing_skin_id)
|
||||||
|
.or_default()
|
||||||
|
.push(role.role_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RoleFlyEquipNotify {
|
||||||
|
fly_skin_equip_data: merged
|
||||||
|
.iter()
|
||||||
|
.map(|&skin| match equipped_skins.get(&skin) {
|
||||||
|
Some(role_list) => FlySkinEquipData {
|
||||||
|
role_ids: role_list.to_vec(),
|
||||||
|
skin_id: skin,
|
||||||
|
},
|
||||||
|
None => FlySkinEquipData {
|
||||||
|
role_ids: vec![],
|
||||||
|
skin_id: skin,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build_motion_list_notify(&self) -> RoleMotionListNotify {
|
pub fn build_motion_list_notify(&self) -> RoleMotionListNotify {
|
||||||
RoleMotionListNotify {
|
RoleMotionListNotify {
|
||||||
motion_list: self
|
motion_list: self
|
||||||
.role_list
|
.role_list
|
||||||
.iter()
|
.values()
|
||||||
.map(|(_, role)| {
|
.map(|role| {
|
||||||
RoleMotion {
|
RoleMotion {
|
||||||
role_id: role.role_id,
|
role_id: role.role_id,
|
||||||
motion_ids: motion_data::iter()
|
motion_ids: motion_data::iter()
|
||||||
|
@ -404,15 +477,10 @@ impl Player {
|
||||||
fight_role_infos: cur_formation
|
fight_role_infos: cur_formation
|
||||||
.role_ids
|
.role_ids
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&role_id| {
|
.map(|&role_id| FightRoleInfo {
|
||||||
let entity_id = world.get_entity_id(role_id);
|
role_id,
|
||||||
let role_skin =
|
entity_id: world.get_entity_id(role_id),
|
||||||
query_components!(world, entity_id, RoleSkin).0.unwrap();
|
on_stage_without_control: false,
|
||||||
FightRoleInfo {
|
|
||||||
role_id,
|
|
||||||
entity_id: world.get_entity_id(role_id),
|
|
||||||
on_stage_without_control: false,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
cur_role: cur_formation.cur_role,
|
cur_role: cur_formation.cur_role,
|
||||||
|
@ -449,14 +517,7 @@ impl Player {
|
||||||
tracing::warn!("Role {} not found in use role list", role_id);
|
tracing::warn!("Role {} not found in use role list", role_id);
|
||||||
return Default::default();
|
return Default::default();
|
||||||
}
|
}
|
||||||
let role = *role_map.get(&role_id).unwrap();
|
role_map.get(role_id).unwrap().to_formation_protobuf()
|
||||||
FormationRoleInfo {
|
|
||||||
role_id: role.role_id,
|
|
||||||
max_hp: 0,
|
|
||||||
cur_hp: 0,
|
|
||||||
level: role.level,
|
|
||||||
role_skin_id: role.skin_id,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
is_current: formation.is_current,
|
is_current: formation.is_current,
|
||||||
|
@ -514,7 +575,7 @@ impl Player {
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
self.notify(NormalItemUpdateNotify {
|
self.notify(NormalItemUpdateNotify {
|
||||||
normal_item_list: self.inventory.to_normal_item_list_filtered(vec![3]),
|
normal_item_list: self.inventory.to_normal_item_list_filtered(&[3]),
|
||||||
no_tips: false,
|
no_tips: false,
|
||||||
});
|
});
|
||||||
self.notify(MonthCardDailyRewardNotify {
|
self.notify(MonthCardDailyRewardNotify {
|
||||||
|
@ -596,6 +657,10 @@ impl Player {
|
||||||
.mc_element
|
.mc_element
|
||||||
.map(PlayerMcElement::load_from_save)
|
.map(PlayerMcElement::load_from_save)
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
|
unlocked_skins: save_data
|
||||||
|
.unlocked_skins
|
||||||
|
.map(PlayerUnlockedSkins::load_from_save)
|
||||||
|
.unwrap_or_default(),
|
||||||
world: Rc::new(RefCell::new(World::new())),
|
world: Rc::new(RefCell::new(World::new())),
|
||||||
last_save_time: time_util::unix_timestamp(),
|
last_save_time: time_util::unix_timestamp(),
|
||||||
quadrant_id: 0,
|
quadrant_id: 0,
|
||||||
|
@ -631,6 +696,7 @@ impl Player {
|
||||||
map_trace: Some(self.map_trace.build_save_data()),
|
map_trace: Some(self.map_trace.build_save_data()),
|
||||||
month_card: Some(self.month_card.build_save_data()),
|
month_card: Some(self.month_card.build_save_data()),
|
||||||
mc_element: Some(self.mc_element.build_save_data()),
|
mc_element: Some(self.mc_element.build_save_data()),
|
||||||
|
unlocked_skins: Some(self.unlocked_skins.build_save_data()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,12 +705,11 @@ impl Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_role_list_notify(&self) -> PbGetRoleListNotify {
|
pub fn build_role_list_notify(&self) -> PbGetRoleListNotify {
|
||||||
// TODO: There is a bug we are investigating with several resonators, this is a workaround
|
|
||||||
PbGetRoleListNotify {
|
PbGetRoleListNotify {
|
||||||
role_list: self
|
role_list: self
|
||||||
.role_list
|
.role_list
|
||||||
.iter()
|
.values()
|
||||||
.map(|(_, role)| role.to_protobuf())
|
.map(|role| role.to_protobuf())
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::sync::atomic::AtomicI32;
|
||||||
|
use wicked_waifus_protocol::{ArrayIntInt, NormalItem, WeaponItem};
|
||||||
|
|
||||||
use wicked_waifus_protocol::NormalItem;
|
use crate::config;
|
||||||
|
use crate::logic::utils::seq_utils::{SequenceGenerator, Sequencer};
|
||||||
use wicked_waifus_protocol_internal::PlayerInventoryData;
|
use wicked_waifus_protocol_internal::{PlayerInventoryData, PlayerInventoryWeaponData};
|
||||||
|
|
||||||
pub struct PlayerInventory {
|
pub struct PlayerInventory {
|
||||||
items: HashMap<i32, i32>,
|
items: HashMap<i32, i32>,
|
||||||
|
weapons_seq: SequenceGenerator<i32, AtomicI32>,
|
||||||
|
weapons: HashMap<i32, PlayerInventoryWeaponData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ItemUsage {
|
pub struct ItemUsage {
|
||||||
|
@ -33,13 +37,16 @@ impl PlayerInventory {
|
||||||
|
|
||||||
pub fn load_from_save(data: PlayerInventoryData) -> Self {
|
pub fn load_from_save(data: PlayerInventoryData) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
weapons_seq: SequenceGenerator::from_data(&data.weapons),
|
||||||
items: data.items.clone(),
|
items: data.items.clone(),
|
||||||
|
weapons: data.weapons.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_save_data(&self) -> PlayerInventoryData {
|
pub fn build_save_data(&self) -> PlayerInventoryData {
|
||||||
PlayerInventoryData {
|
PlayerInventoryData {
|
||||||
items: self.items.clone(),
|
items: self.items.clone(),
|
||||||
|
weapons: self.weapons.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,10 +59,19 @@ impl PlayerInventory {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn consume_item(&mut self, id: i32, quantity: i32) -> Result<i32, InventoryError> {
|
pub fn consume_item(&mut self, id: i32, quantity: i32) -> Result<i32, InventoryError> {
|
||||||
Ok(*self.consume_items(&[ItemUsage { id, quantity: -quantity }])?.get(&id).unwrap())
|
Ok(*self
|
||||||
|
.consume_items(&[ItemUsage {
|
||||||
|
id,
|
||||||
|
quantity: -quantity,
|
||||||
|
}])?
|
||||||
|
.get(&id)
|
||||||
|
.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn consume_items(&mut self, usages: &[ItemUsage]) -> Result<HashMap<i32, i32>, InventoryError> {
|
pub fn consume_items(
|
||||||
|
&mut self,
|
||||||
|
usages: &[ItemUsage],
|
||||||
|
) -> Result<HashMap<i32, i32>, InventoryError> {
|
||||||
if !self.has_enough_items(usages) {
|
if !self.has_enough_items(usages) {
|
||||||
return Err(InventoryError::ItemsNotEnough());
|
return Err(InventoryError::ItemsNotEnough());
|
||||||
}
|
}
|
||||||
|
@ -68,6 +84,11 @@ impl PlayerInventory {
|
||||||
self.items.get(&Self::UNION_EXP_ID).copied().unwrap_or(0)
|
self.items.get(&Self::UNION_EXP_ID).copied().unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn add_shell_credits(&mut self, count: i32) -> i32 {
|
||||||
|
self.add_internal(Self::SHELL_CREDIT_ID, count)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn get_shell_credits(&self) -> i32 {
|
pub fn get_shell_credits(&self) -> i32 {
|
||||||
self.items.get(&Self::SHELL_CREDIT_ID).copied().unwrap_or(0)
|
self.items.get(&Self::SHELL_CREDIT_ID).copied().unwrap_or(0)
|
||||||
|
@ -97,35 +118,113 @@ impl PlayerInventory {
|
||||||
// TODO: Check if this is item or not
|
// TODO: Check if this is item or not
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn get_waveplate_crystal(&self) -> i32 {
|
pub fn get_waveplate_crystal(&self) -> i32 {
|
||||||
self.items.get(&Self::WAVEPLATE_CRYSTAL_ID).copied().unwrap_or(0)
|
self.items
|
||||||
|
.get(&Self::WAVEPLATE_CRYSTAL_ID)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_normal_item_list(&self) -> Vec<NormalItem> {
|
pub fn to_normal_item_list(&self) -> Vec<NormalItem> {
|
||||||
self.items.iter()
|
self.items
|
||||||
|
.iter()
|
||||||
.filter(|(&id, _)| Self::WAVEPLATE_ID != id && Self::WAVEPLATE_CRYSTAL_ID != id)
|
.filter(|(&id, _)| Self::WAVEPLATE_ID != id && Self::WAVEPLATE_CRYSTAL_ID != id)
|
||||||
// TODO: Implement expiration
|
// TODO: Implement expiration
|
||||||
.map(|(&id, &count)| NormalItem { id, count, expire_time: 0 })
|
.map(|(&id, &count)| NormalItem {
|
||||||
|
id,
|
||||||
|
count,
|
||||||
|
expire_time: 0,
|
||||||
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_normal_item_list_filtered(&self, ids: Vec<i32>) -> Vec<NormalItem> {
|
pub fn to_normal_item_list_filtered(&self, ids: &[i32]) -> Vec<NormalItem> {
|
||||||
self.items.iter()
|
self.items
|
||||||
|
.iter()
|
||||||
.filter(|(&id, _)| ids.contains(&id))
|
.filter(|(&id, _)| ids.contains(&id))
|
||||||
// TODO: Implement expiration
|
// TODO: Implement expiration
|
||||||
.map(|(&id, &count)| NormalItem { id, count, expire_time: 0 })
|
.map(|(&id, &count)| NormalItem {
|
||||||
|
id,
|
||||||
|
count,
|
||||||
|
expire_time: 0,
|
||||||
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_array_int_int_filtered(&self, ids: &[i32]) -> Vec<ArrayIntInt> {
|
||||||
|
ids.iter()
|
||||||
|
.map(|id| ArrayIntInt {
|
||||||
|
key: *id,
|
||||||
|
value: self.items.get(id).copied().unwrap_or(0),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_weapon(
|
||||||
|
&mut self,
|
||||||
|
id: i32,
|
||||||
|
func: i32,
|
||||||
|
level: i32,
|
||||||
|
exp: i32,
|
||||||
|
breach: i32,
|
||||||
|
reson: i32,
|
||||||
|
role: i32,
|
||||||
|
) -> Result<i32, InventoryError> {
|
||||||
|
let inc_id = self.weapons_seq.take_id();
|
||||||
|
self.weapons.insert(
|
||||||
|
inc_id,
|
||||||
|
PlayerInventoryWeaponData {
|
||||||
|
id,
|
||||||
|
func_value: func,
|
||||||
|
level,
|
||||||
|
exp,
|
||||||
|
breach,
|
||||||
|
reson_level: reson,
|
||||||
|
role_id: role,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
Ok(inc_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_weapon(&mut self, id: i32) {
|
||||||
|
self.weapons.remove(&id);
|
||||||
|
self.weapons_seq.give_id(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_weapon_item_list(&self) -> Vec<WeaponItem> {
|
||||||
|
self.weapons
|
||||||
|
.iter()
|
||||||
|
.map(|(&inc_id, data)| WeaponItem {
|
||||||
|
id: data.id,
|
||||||
|
incr_id: inc_id,
|
||||||
|
func_value: data.func_value,
|
||||||
|
weapon_level: data.level,
|
||||||
|
weapon_exp: data.exp,
|
||||||
|
weapon_breach: data.breach,
|
||||||
|
weapon_reson_level: data.reson_level,
|
||||||
|
role_id: data.role_id,
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_weapon_equip_info(&self, inc_id: i32) -> Option<(i32, i32)> {
|
||||||
|
self.weapons
|
||||||
|
.get(&inc_id)
|
||||||
|
.map(|weapon_data| (weapon_data.id, weapon_data.breach))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn add_internal(&mut self, id: i32, quantity: i32) -> i32 {
|
fn add_internal(&mut self, id: i32, quantity: i32) -> i32 {
|
||||||
*self.items.entry(id)
|
*self
|
||||||
|
.items
|
||||||
|
.entry(id)
|
||||||
.and_modify(|count| *count += quantity)
|
.and_modify(|count| *count += quantity)
|
||||||
.or_insert(quantity)
|
.or_insert(quantity)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn add_many_internal(&mut self, usages: &[ItemUsage]) -> HashMap<i32, i32> {
|
fn add_many_internal(&mut self, usages: &[ItemUsage]) -> HashMap<i32, i32> {
|
||||||
usages.iter()
|
usages
|
||||||
|
.iter()
|
||||||
.filter(|usage| usage.quantity != 0)
|
.filter(|usage| usage.quantity != 0)
|
||||||
.map(|delta| (delta.id, self.add_internal(delta.id, delta.quantity)))
|
.map(|delta| (delta.id, self.add_internal(delta.id, delta.quantity)))
|
||||||
.collect::<HashMap<_, _>>()
|
.collect::<HashMap<_, _>>()
|
||||||
|
@ -138,17 +237,80 @@ impl PlayerInventory {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn has_enough_items(&self, items_delta: &[ItemUsage]) -> bool {
|
fn has_enough_items(&self, items_delta: &[ItemUsage]) -> bool {
|
||||||
items_delta.iter()
|
items_delta
|
||||||
.fold(true, |is_enough, delta| {
|
.iter()
|
||||||
is_enough && self.has_enough_item(delta.id, -delta.quantity)
|
.all(|delta| self.has_enough_item(delta.id, -delta.quantity))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PlayerInventory {
|
impl Default for PlayerInventory {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
let mut weapons_seq = SequenceGenerator::new();
|
||||||
|
let default_unlocks = &config::get_config().default_unlocks;
|
||||||
|
let weapons: HashMap<i32, PlayerInventoryWeaponData> =
|
||||||
|
match default_unlocks.unlock_all_weapons {
|
||||||
|
true => wicked_waifus_data::weapon_conf_data::iter()
|
||||||
|
.map(|data| {
|
||||||
|
let (level, breach) = if default_unlocks.unlock_all_weapons_max_level {
|
||||||
|
(
|
||||||
|
wicked_waifus_data::weapon_level_data::iter()
|
||||||
|
.filter(|level_data| level_data.level_id == data.level_id)
|
||||||
|
.map(|level_data| level_data.level)
|
||||||
|
.max()
|
||||||
|
.unwrap_or(1),
|
||||||
|
wicked_waifus_data::weapon_breach_data::iter()
|
||||||
|
.filter(|level_data| level_data.breach_id == data.breach_id)
|
||||||
|
.map(|level_data| level_data.level)
|
||||||
|
.max()
|
||||||
|
.unwrap_or(0),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
wicked_waifus_data::weapon_level_data::iter()
|
||||||
|
.filter(|level_data| level_data.level_id == data.level_id)
|
||||||
|
.map(|level_data| level_data.level)
|
||||||
|
.min()
|
||||||
|
.unwrap_or(1),
|
||||||
|
wicked_waifus_data::weapon_breach_data::iter()
|
||||||
|
.filter(|level_data| level_data.breach_id == data.breach_id)
|
||||||
|
.map(|level_data| level_data.level)
|
||||||
|
.min()
|
||||||
|
.unwrap_or(0),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let reson_level = if default_unlocks.unlock_all_weapons_all_reson {
|
||||||
|
wicked_waifus_data::weapon_reson_data::iter()
|
||||||
|
.filter(|level_data| level_data.reson_id == data.reson_id)
|
||||||
|
.map(|level_data| level_data.level)
|
||||||
|
.max()
|
||||||
|
.unwrap_or(0)
|
||||||
|
} else {
|
||||||
|
wicked_waifus_data::weapon_reson_data::iter()
|
||||||
|
.filter(|level_data| level_data.reson_id == data.reson_id)
|
||||||
|
.map(|level_data| level_data.level)
|
||||||
|
.min()
|
||||||
|
.unwrap_or(0)
|
||||||
|
};
|
||||||
|
(
|
||||||
|
weapons_seq.take_id(),
|
||||||
|
PlayerInventoryWeaponData {
|
||||||
|
id: data.item_id,
|
||||||
|
func_value: 0,
|
||||||
|
level,
|
||||||
|
exp: 0,
|
||||||
|
breach,
|
||||||
|
reson_level,
|
||||||
|
role_id: 0,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<HashMap<_, _>>(),
|
||||||
|
false => Default::default(),
|
||||||
|
};
|
||||||
Self {
|
Self {
|
||||||
items: HashMap::new(),
|
items: HashMap::new(),
|
||||||
|
weapons_seq,
|
||||||
|
weapons,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
use crate::config;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use wicked_waifus_protocol_internal::PlayerUnlockedSkinsData;
|
||||||
|
|
||||||
|
pub struct PlayerUnlockedSkins {
|
||||||
|
pub role_skins: HashSet<i32>,
|
||||||
|
pub weapon_skins: HashSet<i32>,
|
||||||
|
pub fly_skins: HashSet<i32>,
|
||||||
|
pub wing_skins: HashSet<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlayerUnlockedSkins {
|
||||||
|
pub fn load_from_save(data: PlayerUnlockedSkinsData) -> Self {
|
||||||
|
Self {
|
||||||
|
role_skins: data.role_skins.iter().cloned().collect(),
|
||||||
|
weapon_skins: data.weapon_skins.iter().cloned().collect(),
|
||||||
|
fly_skins: data.fly_skins.iter().cloned().collect(),
|
||||||
|
wing_skins: data.wing_skins.iter().cloned().collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_save_data(&self) -> PlayerUnlockedSkinsData {
|
||||||
|
PlayerUnlockedSkinsData {
|
||||||
|
role_skins: self.role_skins.iter().cloned().collect(),
|
||||||
|
weapon_skins: self.weapon_skins.iter().cloned().collect(),
|
||||||
|
fly_skins: self.fly_skins.iter().cloned().collect(),
|
||||||
|
wing_skins: self.wing_skins.iter().cloned().collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PlayerUnlockedSkins {
|
||||||
|
fn default() -> Self {
|
||||||
|
let unlocks = &config::get_config().default_unlocks;
|
||||||
|
|
||||||
|
Self {
|
||||||
|
role_skins: if unlocks.unlock_all_role_skins {
|
||||||
|
wicked_waifus_data::role_skin_data::iter()
|
||||||
|
.map(|skin| skin.id)
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
HashSet::new()
|
||||||
|
},
|
||||||
|
|
||||||
|
weapon_skins: if unlocks.unlock_all_weapon_skins {
|
||||||
|
wicked_waifus_data::weapon_skin_data::iter()
|
||||||
|
.map(|skin| skin.id)
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
HashSet::new()
|
||||||
|
},
|
||||||
|
|
||||||
|
fly_skins: if unlocks.unlock_all_fly_skins {
|
||||||
|
wicked_waifus_data::fly_skin_config_data::iter()
|
||||||
|
.filter(|skin| skin.skin_type == 0)
|
||||||
|
.map(|skin| skin.id)
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
HashSet::new()
|
||||||
|
},
|
||||||
|
|
||||||
|
wing_skins: if unlocks.unlock_all_wing_skins {
|
||||||
|
wicked_waifus_data::fly_skin_config_data::iter()
|
||||||
|
.filter(|skin| skin.skin_type == 1)
|
||||||
|
.map(|skin| skin.id)
|
||||||
|
.collect()
|
||||||
|
} else {
|
||||||
|
HashSet::new()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use wicked_waifus_protocol::{ArrayIntInt, RoleInfo};
|
use wicked_waifus_protocol::{ArrayIntInt, FormationRoleInfo, RoleInfo};
|
||||||
|
|
||||||
use crate::config;
|
use crate::config;
|
||||||
use crate::logic::utils::growth_utils::get_role_props_by_level;
|
use crate::logic::utils::growth_utils::get_role_props_by_level;
|
||||||
|
@ -50,6 +50,9 @@ pub struct Role {
|
||||||
pub element_energy: i32,
|
pub element_energy: i32,
|
||||||
pub favor_level: i32,
|
pub favor_level: i32,
|
||||||
pub favor_exp: i32,
|
pub favor_exp: i32,
|
||||||
|
pub wing_skin_id: i32,
|
||||||
|
pub fly_skin_id: i32,
|
||||||
|
pub weapon_skin_id: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Role {
|
impl Role {
|
||||||
|
@ -119,21 +122,44 @@ impl Role {
|
||||||
|
|
||||||
let default_unlocks = &config::get_config().default_unlocks;
|
let default_unlocks = &config::get_config().default_unlocks;
|
||||||
let (level, breakthrough) = if default_unlocks.unlock_all_roles_max_level {
|
let (level, breakthrough) = if default_unlocks.unlock_all_roles_max_level {
|
||||||
(data.max_level, 6)
|
(
|
||||||
|
data.max_level,
|
||||||
|
wicked_waifus_data::role_breach_data::iter()
|
||||||
|
.filter(|level_data| level_data.breach_group_id == data.breach_id)
|
||||||
|
.map(|level_data| level_data.breach_level)
|
||||||
|
.max()
|
||||||
|
.unwrap_or(0),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
(1, 0)
|
(
|
||||||
|
1,
|
||||||
|
wicked_waifus_data::role_breach_data::iter()
|
||||||
|
.filter(|level_data| level_data.breach_group_id == data.breach_id)
|
||||||
|
.map(|level_data| level_data.breach_level)
|
||||||
|
.min()
|
||||||
|
.unwrap_or(0),
|
||||||
|
)
|
||||||
};
|
};
|
||||||
let resonant_chain_group_index = if default_unlocks.unlock_all_roles_all_sequences {
|
let resonant_chain_group_index = if default_unlocks.unlock_all_roles_all_sequences {
|
||||||
6
|
wicked_waifus_data::resonant_chain_data::iter()
|
||||||
|
.filter(|level_data| level_data.group_id == data.resonant_chain_group_id)
|
||||||
|
.map(|level_data| level_data.group_index)
|
||||||
|
.max()
|
||||||
|
.unwrap_or(0)
|
||||||
} else {
|
} else {
|
||||||
0
|
wicked_waifus_data::resonant_chain_data::iter()
|
||||||
|
.filter(|level_data| level_data.group_id == data.resonant_chain_group_id)
|
||||||
|
.map(|level_data| level_data.group_index)
|
||||||
|
.min()
|
||||||
|
.unwrap_or(0)
|
||||||
};
|
};
|
||||||
|
// TODO: add weapon and echo stats
|
||||||
let base_stats = &get_role_props_by_level(role_id, level, breakthrough);
|
let base_stats = &get_role_props_by_level(role_id, level, breakthrough);
|
||||||
Self {
|
Self {
|
||||||
role_id,
|
role_id,
|
||||||
name: String::with_capacity(0),
|
name: String::with_capacity(0),
|
||||||
level,
|
level,
|
||||||
exp: 0, // TODO: Compute based on level??
|
exp: 0,
|
||||||
breakthrough,
|
breakthrough,
|
||||||
skill_map: HashMap::new(), // TODO!
|
skill_map: HashMap::new(), // TODO!
|
||||||
star: 0,
|
star: 0,
|
||||||
|
@ -151,12 +177,16 @@ impl Role {
|
||||||
element_energy: base_stats.element_energy,
|
element_energy: base_stats.element_energy,
|
||||||
favor_level: 0,
|
favor_level: 0,
|
||||||
favor_exp: 0,
|
favor_exp: 0,
|
||||||
|
wing_skin_id: 0,
|
||||||
|
fly_skin_id: 0,
|
||||||
|
weapon_skin_id: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_base_properties(&self) -> BasePropertyData {
|
pub fn get_base_properties(&self) -> BasePropertyData {
|
||||||
// Overwrite dynamic attributes with stores values
|
// Overwrite dynamic attributes with stores values
|
||||||
let mut base_stats = get_role_props_by_level(self.role_id, self.level, self.breakthrough);
|
let mut base_stats = get_role_props_by_level(self.role_id, self.level, self.breakthrough);
|
||||||
|
// TODO: add weapon and echo stats
|
||||||
// TODO: Integrity check, value has to be between 0 and max
|
// TODO: Integrity check, value has to be between 0 and max
|
||||||
base_stats.life = self.hp;
|
base_stats.life = self.hp;
|
||||||
base_stats.energy = self.energy;
|
base_stats.energy = self.energy;
|
||||||
|
@ -169,6 +199,7 @@ impl Role {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_protobuf(&self) -> RoleInfo {
|
pub fn to_protobuf(&self) -> RoleInfo {
|
||||||
|
// TODO: add weapon and echo stats
|
||||||
let base_prop: HashMap<i32, i32> = load_key_value(&self.get_base_properties());
|
let base_prop: HashMap<i32, i32> = load_key_value(&self.get_base_properties());
|
||||||
RoleInfo {
|
RoleInfo {
|
||||||
role_id: self.role_id,
|
role_id: self.role_id,
|
||||||
|
@ -192,6 +223,17 @@ impl Role {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_formation_protobuf(&self) -> FormationRoleInfo {
|
||||||
|
let base_stats = get_role_props_by_level(self.role_id, self.level, self.breakthrough);
|
||||||
|
FormationRoleInfo {
|
||||||
|
role_id: self.role_id,
|
||||||
|
max_hp: base_stats.life_max,
|
||||||
|
cur_hp: base_stats.life,
|
||||||
|
level: self.level,
|
||||||
|
role_skin_id: self.skin_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_from_save(data: RoleData) -> (i32, Self) {
|
pub fn load_from_save(data: RoleData) -> (i32, Self) {
|
||||||
(
|
(
|
||||||
data.role_id,
|
data.role_id,
|
||||||
|
@ -217,6 +259,9 @@ impl Role {
|
||||||
element_energy: data.stats.unwrap().element_energy,
|
element_energy: data.stats.unwrap().element_energy,
|
||||||
favor_level: data.favor_level,
|
favor_level: data.favor_level,
|
||||||
favor_exp: data.favor_exp,
|
favor_exp: data.favor_exp,
|
||||||
|
wing_skin_id: data.wing_skin_id,
|
||||||
|
fly_skin_id: data.fly_skin_id,
|
||||||
|
weapon_skin_id: data.weapon_skin_id,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -250,6 +295,9 @@ impl Role {
|
||||||
}),
|
}),
|
||||||
favor_level: self.favor_level,
|
favor_level: self.favor_level,
|
||||||
favor_exp: self.favor_exp,
|
favor_exp: self.favor_exp,
|
||||||
|
wing_skin_id: self.wing_skin_id,
|
||||||
|
fly_skin_id: self.fly_skin_id,
|
||||||
|
weapon_skin_id: self.weapon_skin_id,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,7 +229,7 @@ fn collect_action(player: &mut Player,
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let updated_items = player.inventory.add_items(&usages);
|
let updated_items = player.inventory.add_items(&usages);
|
||||||
let normal_item_list = player.inventory.to_normal_item_list_filtered(
|
let normal_item_list = player.inventory.to_normal_item_list_filtered(
|
||||||
updated_items.keys().cloned().collect::<Vec<i32>>()
|
&updated_items.keys().cloned().collect::<Vec<i32>>()
|
||||||
);
|
);
|
||||||
player.notify(NormalItemUpdateNotify { normal_item_list, no_tips: false });
|
player.notify(NormalItemUpdateNotify { normal_item_list, no_tips: false });
|
||||||
// UpdateHandBookActiveStateMapNotify
|
// UpdateHandBookActiveStateMapNotify
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
pub mod action_utils;
|
pub mod action_utils;
|
||||||
pub mod condition_utils;
|
pub mod condition_utils;
|
||||||
pub mod entity_serializer;
|
pub mod entity_serializer;
|
||||||
pub mod load_role_info;
|
|
||||||
pub mod world_util;
|
|
||||||
pub mod quadrant_util;
|
|
||||||
pub mod growth_utils;
|
pub mod growth_utils;
|
||||||
|
pub mod load_role_info;
|
||||||
|
pub mod quadrant_util;
|
||||||
|
pub mod seq_utils;
|
||||||
pub mod tag_utils;
|
pub mod tag_utils;
|
||||||
|
pub mod world_util;
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::sync::OnceLock;
|
||||||
|
|
||||||
use wicked_waifus_data::LevelEntityConfigData;
|
use wicked_waifus_data::LevelEntityConfigData;
|
||||||
|
|
||||||
struct StaticConfig {
|
pub(crate) struct StaticConfig {
|
||||||
edge_size: f32,
|
edge_size: f32,
|
||||||
edge_check: f32,
|
edge_check: f32,
|
||||||
}
|
}
|
||||||
|
|
55
wicked-waifus-game-server/src/logic/utils/seq_utils.rs
Normal file
55
wicked-waifus-game-server/src/logic/utils/seq_utils.rs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
|
||||||
|
pub trait Sequencer<T> {
|
||||||
|
fn new() -> Self;
|
||||||
|
fn from_data<V>(data: &HashMap<T, V>) -> Self;
|
||||||
|
fn take_id(&mut self) -> T;
|
||||||
|
fn give_id(&mut self, id: T);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SequenceGenerator<T, A> {
|
||||||
|
recycled_ids: VecDeque<T>,
|
||||||
|
next_id: A,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! sequence_trait_impl {
|
||||||
|
($t:ty, $a:ty) => (
|
||||||
|
impl Sequencer<$t> for SequenceGenerator<$t, $a> {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
recycled_ids: Default::default(),
|
||||||
|
next_id: <$a>::new(1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_data<V>(data: &HashMap<$t, V>) -> Self {
|
||||||
|
let max_id = data.keys().max().copied().unwrap_or(1);
|
||||||
|
let next_id = <$a>::new(max_id);
|
||||||
|
|
||||||
|
let mut recycled_ids = VecDeque::new();
|
||||||
|
for i in 1..max_id {
|
||||||
|
if !data.contains_key(&i) {
|
||||||
|
recycled_ids.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
recycled_ids,
|
||||||
|
next_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_id(&mut self) -> $t {
|
||||||
|
self.recycled_ids
|
||||||
|
.pop_front()
|
||||||
|
.unwrap_or_else(|| self.next_id.fetch_add(1, std::sync::atomic::Ordering::Relaxed))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn give_id(&mut self, id: $t) {
|
||||||
|
self.recycled_ids.push_back(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
sequence_trait_impl!(i32, std::sync::atomic::AtomicI32);
|
||||||
|
sequence_trait_impl!(i64, std::sync::atomic::AtomicI64);
|
|
@ -9,7 +9,7 @@ use wicked_waifus_data::{
|
||||||
blueprint_config_data, template_config_data, EntityLogic, EntityType, LevelEntityConfigData,
|
blueprint_config_data, template_config_data, EntityLogic, EntityType, LevelEntityConfigData,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::logic::components::{Autonomous, Fsm, Interact, MonsterAi, SoarWingSkin, StateTag, Tag};
|
use crate::logic::components::{Autonomous, Fsm, Interact, MonsterAi, ParaglidingSkin, SoarWingSkin, StateTag, Tag, WeaponSkin};
|
||||||
use crate::logic::ecs::entity::EntityBuilder;
|
use crate::logic::ecs::entity::EntityBuilder;
|
||||||
use crate::logic::ecs::world::World;
|
use crate::logic::ecs::world::World;
|
||||||
use crate::logic::math::Transform;
|
use crate::logic::math::Transform;
|
||||||
|
@ -87,7 +87,13 @@ macro_rules! create_player_entity_pb {
|
||||||
skin_id: role.skin_id,
|
skin_id: role.skin_id,
|
||||||
}))
|
}))
|
||||||
.with(ComponentContainer::SoarWingSkin(SoarWingSkin {
|
.with(ComponentContainer::SoarWingSkin(SoarWingSkin {
|
||||||
skin_id: 84000001,
|
skin_id: role.fly_skin_id,
|
||||||
|
}))
|
||||||
|
.with(ComponentContainer::ParaglidingSkin(ParaglidingSkin {
|
||||||
|
skin_id: role.wing_skin_id,
|
||||||
|
}))
|
||||||
|
.with(ComponentContainer::WeaponSkin(WeaponSkin {
|
||||||
|
skin_id: role.weapon_skin_id,
|
||||||
}))
|
}))
|
||||||
.with(ComponentContainer::FightBuff(buf_manager))
|
.with(ComponentContainer::FightBuff(buf_manager))
|
||||||
.build();
|
.build();
|
||||||
|
@ -181,7 +187,13 @@ pub fn add_player_entities(player: &Player) {
|
||||||
skin_id: role.skin_id,
|
skin_id: role.skin_id,
|
||||||
}))
|
}))
|
||||||
.with(ComponentContainer::SoarWingSkin(SoarWingSkin {
|
.with(ComponentContainer::SoarWingSkin(SoarWingSkin {
|
||||||
skin_id: 84000001,
|
skin_id: role.fly_skin_id,
|
||||||
|
}))
|
||||||
|
.with(ComponentContainer::ParaglidingSkin(ParaglidingSkin {
|
||||||
|
skin_id: role.wing_skin_id,
|
||||||
|
}))
|
||||||
|
.with(ComponentContainer::WeaponSkin(WeaponSkin {
|
||||||
|
skin_id: role.weapon_skin_id, // TODO: Is this kept on weapon change
|
||||||
}))
|
}))
|
||||||
.with(ComponentContainer::FightBuff(buf_manager))
|
.with(ComponentContainer::FightBuff(buf_manager))
|
||||||
.build();
|
.build();
|
||||||
|
@ -243,11 +255,10 @@ fn build_player_info_list(world: &World) -> Vec<ScenePlayerInformation> {
|
||||||
world.get_world_entity(),
|
world.get_world_entity(),
|
||||||
PlayerOwnedEntityMarker,
|
PlayerOwnedEntityMarker,
|
||||||
OwnerPlayer,
|
OwnerPlayer,
|
||||||
EntityConfig,
|
EntityConfig
|
||||||
RoleSkin
|
|
||||||
)
|
)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(_, _, owner, _, _)| owner.0 == sp.player_id);
|
.filter(|(_, _, owner, _)| owner.0 == sp.player_id);
|
||||||
|
|
||||||
ScenePlayerInformation {
|
ScenePlayerInformation {
|
||||||
cur_role: cur_role_id,
|
cur_role: cur_role_id,
|
||||||
|
@ -264,7 +275,7 @@ fn build_player_info_list(world: &World) -> Vec<ScenePlayerInformation> {
|
||||||
cur_role: cur_role_id,
|
cur_role: cur_role_id,
|
||||||
// is_retain: true,
|
// is_retain: true,
|
||||||
fight_role_infos: active_characters
|
fight_role_infos: active_characters
|
||||||
.map(|(id, _, _, conf, role_skin)| FightRoleInfo {
|
.map(|(id, _, _, conf)| FightRoleInfo {
|
||||||
entity_id: id.into(),
|
entity_id: id.into(),
|
||||||
role_id: conf.config_id,
|
role_id: conf.config_id,
|
||||||
on_stage_without_control: false,
|
on_stage_without_control: false,
|
||||||
|
|
|
@ -60,6 +60,9 @@ message RoleData {
|
||||||
RoleStats stats = 17;
|
RoleStats stats = 17;
|
||||||
int32 favor_level = 18;
|
int32 favor_level = 18;
|
||||||
int32 favor_exp = 19;
|
int32 favor_exp = 19;
|
||||||
|
int32 wing_skin_id = 20;
|
||||||
|
int32 fly_skin_id = 21;
|
||||||
|
int32 weapon_skin_id = 22;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RoleFormationData {
|
message RoleFormationData {
|
||||||
|
@ -135,8 +138,19 @@ message PlayerAdventureStatusData {
|
||||||
repeated PlayerAdventureGlobalStatusData status = 1;
|
repeated PlayerAdventureGlobalStatusData status = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message PlayerInventoryWeaponData {
|
||||||
|
int32 id = 1;
|
||||||
|
int32 func_value = 2;
|
||||||
|
int32 level = 3;
|
||||||
|
int32 exp = 4;
|
||||||
|
int32 breach = 5;
|
||||||
|
int32 reson_level = 6;
|
||||||
|
int32 role_id = 7;
|
||||||
|
}
|
||||||
|
|
||||||
message PlayerInventoryData {
|
message PlayerInventoryData {
|
||||||
map<int32, int32> items = 1;
|
map<int32, int32> items = 1;
|
||||||
|
map<int32, PlayerInventoryWeaponData> weapons = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PlayerTeleportData {
|
message PlayerTeleportData {
|
||||||
|
@ -182,6 +196,13 @@ message PlayerMcElementData {
|
||||||
PlayerMcElementType current_element = 2;
|
PlayerMcElementType current_element = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message PlayerUnlockedSkinsData {
|
||||||
|
repeated int32 role_skins = 1;
|
||||||
|
repeated int32 weapon_skins = 2;
|
||||||
|
repeated int32 fly_skins = 3;
|
||||||
|
repeated int32 wing_skins = 4;
|
||||||
|
}
|
||||||
|
|
||||||
message PlayerSaveData {
|
message PlayerSaveData {
|
||||||
PlayerBasicData basic_data = 1;
|
PlayerBasicData basic_data = 1;
|
||||||
PlayerRoleData role_data = 2;
|
PlayerRoleData role_data = 2;
|
||||||
|
@ -198,4 +219,5 @@ message PlayerSaveData {
|
||||||
PlayerMapTraceData map_trace = 13;
|
PlayerMapTraceData map_trace = 13;
|
||||||
PlayerMonthCardData month_card = 14;
|
PlayerMonthCardData month_card = 14;
|
||||||
PlayerMcElementData mc_element = 15;
|
PlayerMcElementData mc_element = 15;
|
||||||
|
PlayerUnlockedSkinsData unlocked_skins = 16;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue