diff --git a/wicked-waifus-data/src/buff.rs b/wicked-waifus-data/src/buff.rs new file mode 100644 index 0000000..e06830e --- /dev/null +++ b/wicked-waifus-data/src/buff.rs @@ -0,0 +1,12 @@ +use serde::Deserialize; + +#[derive(Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct BuffData { + pub id: i64, + pub ge_desc: String, + pub duration_policy: i32, + pub extra_effect_parameters: Option>, + pub game_attribute_i_d: i32 +} \ No newline at end of file diff --git a/wicked-waifus-data/src/lib.rs b/wicked-waifus-data/src/lib.rs index 176e29c..c92daf1 100644 --- a/wicked-waifus-data/src/lib.rs +++ b/wicked-waifus-data/src/lib.rs @@ -168,8 +168,9 @@ json_hash_table_data! { DragonPool, id, i32; DropPackage, id, i32; TemplateConfig, blueprint_type, String; + SummonCfg, blueprint_type, String; + Buff, id, i64; } - mod level_entity_config; pub mod level_entity_config_data { @@ -184,7 +185,10 @@ pub mod level_entity_config_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)] @@ -207,10 +211,9 @@ fn load_json_entity_level_config_data(base_path: &str) -> Result<(), LoadDataErr serde_json::from_reader::, Vec>(reader)? .into_iter() .map(|element| (level_entity_config_data::create_key(&element), element)) - .collect::>() + .collect::>(), ); tracing::info!("Loading data finished: {path}"); - Ok(()) -} \ No newline at end of file +} diff --git a/wicked-waifus-data/src/pb_components/mod.rs b/wicked-waifus-data/src/pb_components/mod.rs index 105daf9..b2c926a 100644 --- a/wicked-waifus-data/src/pb_components/mod.rs +++ b/wicked-waifus-data/src/pb_components/mod.rs @@ -15,6 +15,7 @@ pub mod reward; pub mod teleport; pub mod timer; pub mod var; +pub mod model; #[derive(Deserialize, Debug, Clone)] #[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] @@ -28,6 +29,7 @@ pub struct ComponentsData { pub interact_component: Option, pub entity_state_component: Option, pub reward_component: Option, + pub model_component: Option, // TODO: Implement this ones #[cfg(feature = "strict_json_fields")] pub scene_actor_ref_component: Option, @@ -70,8 +72,6 @@ pub struct ComponentsData { #[cfg(feature = "strict_json_fields")] pub photo_target_component: Option, #[cfg(feature = "strict_json_fields")] - pub model_component: Option, - #[cfg(feature = "strict_json_fields")] pub entity_group_component: Option, #[cfg(feature = "strict_json_fields")] pub scene_item_life_cycle_component: Option, @@ -230,6 +230,7 @@ impl ComponentsData { interact_component: self.interact_component.as_ref().or(template.interact_component.as_ref()).cloned(), entity_state_component: self.entity_state_component.as_ref().or(template.entity_state_component.as_ref()).cloned(), reward_component: self.reward_component.as_ref().or(template.reward_component.as_ref()).cloned(), + model_component: self.model_component.as_ref().or(template.model_component.as_ref()).cloned(), } } } \ No newline at end of file diff --git a/wicked-waifus-data/src/pb_components/model.rs b/wicked-waifus-data/src/pb_components/model.rs new file mode 100644 index 0000000..52cb255 --- /dev/null +++ b/wicked-waifus-data/src/pb_components/model.rs @@ -0,0 +1,18 @@ +use serde::Deserialize; + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ModelType { + r#type: Option, + model_id: Option +} + +#[derive(Deserialize, Debug, Clone)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct ModelComponent { + pub half_height: Option, + pub disabled: Option, + pub model_type: Option +} \ No newline at end of file diff --git a/wicked-waifus-data/src/summon_cfg.rs b/wicked-waifus-data/src/summon_cfg.rs new file mode 100644 index 0000000..ffda5bc --- /dev/null +++ b/wicked-waifus-data/src/summon_cfg.rs @@ -0,0 +1,12 @@ +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +#[cfg_attr(feature = "strict_json_fields", serde(deny_unknown_fields))] +#[serde(rename_all = "PascalCase")] +pub struct SummonCfgData { + pub id: i32, + pub blueprint_type: String, + #[cfg(feature = "strict_json_fields")] + pub name: String, + pub born_buff_id: Vec, +} \ No newline at end of file diff --git a/wicked-waifus-game-server/scripts/watermask-disable.js b/wicked-waifus-game-server/scripts/watermask-disable.js deleted file mode 100644 index ff996f2..0000000 --- a/wicked-waifus-game-server/scripts/watermask-disable.js +++ /dev/null @@ -1 +0,0 @@ -require('../Module/WaterMask/WaterMaskController').WaterMaskView.EOo(); \ No newline at end of file diff --git a/wicked-waifus-game-server/scripts/watermask-edit.js b/wicked-waifus-game-server/scripts/watermask-edit.js new file mode 100644 index 0000000..d255330 --- /dev/null +++ b/wicked-waifus-game-server/scripts/watermask-edit.js @@ -0,0 +1,41 @@ +const UE = require("ue"), + Info_1 = require("../../../Core/Common/Info"), + MathUtils_1 = require("../../../Core/Utils/MathUtils"), + EventDefine_1 = require("../../Common/Event/EventDefine"), + EventSystem_1 = require("../../Common/Event/EventSystem"), + UiControllerBase_1 = require("../../Ui/Base/UiControllerBase"), + UiLayerType_1 = require("../../Ui/Define/UiLayerType"), + UiLayer_1 = require("../../Ui/UiLayer"); + +var _a = require('../Module/WaterMask/WaterMaskController').WaterMaskView; +_a.LOo = 0.18; +_a.yOo = 700; +_a.IOo = 700; +_a.vOo = function () { + void 0 !== _a.SOo && _a.EOo(); + var e = UiLayer_1.UiLayer.GetLayerRootUiItem(UiLayerType_1.ELayerType.WaterMask), + t = (_a.SOo = UE.KuroActorManager.SpawnActor(Info_1.Info.World, UE.UIContainerActor.StaticClass(), + MathUtils_1.MathUtils.DefaultTransform, void 0), _a.SOo.RootComponent), + e = (t.SetDisplayName("WaterMaskContainer"), UE.KuroStaticLibrary.SetActorPermanent(_a.SOo, !0, !0), _a.SOo + .K2_AttachRootComponentTo(e), t.GetRootCanvas().GetOwner().RootComponent), + i = e.widget.width % _a.yOo / 2, + r = e.widget.height % _a.IOo / 2, + n = e.widget.width / 2, + _ = e.widget.height / 2, + s = Math.ceil(e.widget.width / _a.yOo), + o = Math.ceil(e.widget.height / _a.IOo), + v = " "; // EDIT ME! + for (let a = 0; a < s; a++) + for (let e = 0; e < o; e++) { + var E = UE.KuroActorManager.SpawnActor(Info_1.Info.World, UE.UITextActor.StaticClass(), MathUtils_1 + .MathUtils.DefaultTransform, void 0), + U = E.RootComponent, + U = (E.K2_AttachRootComponentTo(t), U.SetDisplayName("WaterMaskText"), E.GetComponentByClass(UE + .UIText.StaticClass())); + U.SetFontSize(_a.vFt), U.SetOverflowType(0), U.SetAlpha(_a.LOo), U.SetFont(UE.LGUIFontData + .GetDefaultFont()), U.SetText(v), U.SetUIRelativeLocation(new UE.Vector(a * _a.yOo - n + i, e * + _a.IOo - _ + r, 0)), U.SetUIRelativeRotation(new UE.Rotator(0, _a.TOo, 0)), UE.KuroStaticLibrary + .SetActorPermanent(E, !0, !0) + } +}; +_a.vOo(); \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/ecs/buf.rs b/wicked-waifus-game-server/src/logic/ecs/buf.rs index 6ae527b..98bd1df 100644 --- a/wicked-waifus-game-server/src/logic/ecs/buf.rs +++ b/wicked-waifus-game-server/src/logic/ecs/buf.rs @@ -8,17 +8,34 @@ pub struct BufManager { recycled_handles: HashMap>, } -impl BufManager { - const PERMANENT_ROLE_BUFFS: &'static [i64] = &[ - 3003, // Remove wall run prohibition - 3004, // Remove gliding prohibition - 1213, // Reduce stamina while flying - 1214, // Reduce stamina while flying in sprint - 1215, // Reduce stamina while flying up in sprint - 1216, // Reduce stamina while flying down in sprint - 640012051, // Allow flying -> tag: 1151923109 - ]; +const OVERRIDE_BUFFS: &[i64] = &[ + 3003, // Remove wall run prohibition + 3004, // Remove gliding prohibition + 1213, // Reduce stamina while flying + 1214, // Reduce stamina while flying in sprint + 1215, // Reduce stamina while flying up in sprint + 1216, // Reduce stamina while flying down in sprint + 640012051, // Allow flying -> tag: 1151923109 +]; +const ROLE_OVERRIDES: &[(i32, &[i64])] = &[ + (1407, &[ + // ciaconna's forte buffs are completely fucked to get from an algorithm and i hate kuro! + 1407900003, + 1407500040, + ]), +]; + +fn get_role_buff_overrides(role_id: i32) -> Option<&'static [i64]> { + for &(role, buff) in ROLE_OVERRIDES { + if role == role_id { + return Some(buff); + } + } + None +} + +impl BufManager { pub fn create(&mut self, buf: &mut FightBuffInformation) { let handle = self .recycled_handles @@ -35,7 +52,9 @@ impl BufManager { #[inline(always)] pub fn remove_entity_buffs(&mut self, entity_id: i64) { - let handles = self.active_buf_set.iter() + let handles = self + .active_buf_set + .iter() .filter(|(_, buff)| buff.entity_id == entity_id) .map(|(&handle, _)| handle) .collect::>(); @@ -57,13 +76,33 @@ impl BufManager { } } - pub fn create_permanent_buffs(&mut self, origin_id: i64) -> Vec { - Self::PERMANENT_ROLE_BUFFS + pub fn create_permanent_buffs(&mut self, origin_id: i64, role_id: i32) -> Vec { + let mut buffs = wicked_waifus_data::buff_data::iter().filter(|(id, buf)| { + id.to_string().starts_with(&role_id.to_string()) // must be part of char kit :) + && + ( + !id.to_string().contains("666")// KURO IS EVIL + && + buf.duration_policy == 1 + ) + // && + // !buf.ge_desc.contains("【废弃】") // remove "deprecated" buffs + }) + .map(|x| *x.0) + .collect::>(); + + buffs.extend(OVERRIDE_BUFFS.iter().copied()); + if let Some(role_buff_overrides) = get_role_buff_overrides(role_id) { + buffs.extend(role_buff_overrides.iter().copied()); + } + buffs.dedup(); + + buffs .iter() - .map(|&id| { + .map(|id| { let mut buff = FightBuffInformation { handle_id: 0, - buff_id: id, + buff_id: *id, level: 1, stack_count: 1, instigator_id: origin_id, diff --git a/wicked-waifus-game-server/src/logic/ecs/world.rs b/wicked-waifus-game-server/src/logic/ecs/world.rs index 3692c68..453ffed 100644 --- a/wicked-waifus-game-server/src/logic/ecs/world.rs +++ b/wicked-waifus-game-server/src/logic/ecs/world.rs @@ -7,6 +7,7 @@ use std::collections::hash_map::{Keys, Values}; use std::collections::HashMap; use wicked_waifus_protocol::FightBuffInformation; +#[derive(Default)] pub struct WorldEntity { components: HashMap>>, entity_manager: EntityManager, @@ -111,17 +112,7 @@ impl WorldEntity { self.entity_manager.active_entity_empty() } - pub fn generate_role_permanent_buffs(&mut self, entity_id: i64) -> Vec { - self.buff_manager.create_permanent_buffs(entity_id) - } -} - -impl Default for WorldEntity { - fn default() -> Self { - Self { - components: HashMap::new(), - entity_manager: EntityManager::default(), - buff_manager: BufManager::default(), - } + pub fn generate_role_permanent_buffs(&mut self, entity_id: i32, role_id: i32) -> Vec { + self.buff_manager.create_permanent_buffs(entity_id as i64, role_id) } } diff --git a/wicked-waifus-game-server/src/logic/handler/role.rs b/wicked-waifus-game-server/src/logic/handler/role.rs index f17cf8a..2b45f09 100644 --- a/wicked-waifus-game-server/src/logic/handler/role.rs +++ b/wicked-waifus-game-server/src/logic/handler/role.rs @@ -81,41 +81,41 @@ pub fn on_update_formation_request( } if let Some(old_formation) = player.formation_list.get(&real_formation_id) { - let removed_entities: Vec = old_formation + let removed_entities: Vec = old_formation + .role_ids + .iter() + .map(|&role_id| world.get_entity_id(role_id)) + .collect(); + removed_entities.iter().for_each(|&entity_id| { + world.remove_entity(entity_id as i32); + }); + player.notify(player.build_player_entity_remove_notify( + removed_entities, + ERemoveEntityType::RemoveTypeNormal, + )); + } + + let added_roles: Vec = formation .role_ids .iter() - .map(|&role_id| world.get_entity_id(role_id)) + .map(|&role_id| Role::new(role_id)) .collect(); - removed_entities.iter().for_each(|&entity_id| { - world.remove_entity(entity_id as i32); - }); - player.notify(player.build_player_entity_remove_notify( - removed_entities, - ERemoveEntityType::RemoveTypeNormal, + + if !added_roles.is_empty() { + // add new roles + player.notify(player.build_player_entity_add_notify(added_roles, world)); + } + + // send update group formation notify + player.notify(player.build_update_group_formation_notify( + RoleFormation { + id: formation_id, + cur_role, + role_ids: formation.role_ids.clone(), + is_current, + }, + world, )); - } - - let added_roles: Vec = formation - .role_ids - .iter() - .map(|&role_id| Role::new(role_id)) - .collect(); - - if !added_roles.is_empty() { - // add new roles - player.notify(player.build_player_entity_add_notify(added_roles)); - } - - // send update group formation notify - player.notify(player.build_update_group_formation_notify( - RoleFormation { - id: formation_id, - cur_role, - role_ids: formation.role_ids.clone(), - is_current, - }, - world, - )); response.formation = Some(formation.clone()); } diff --git a/wicked-waifus-game-server/src/logic/handler/scene.rs b/wicked-waifus-game-server/src/logic/handler/scene.rs index 5fa42e6..cca218d 100644 --- a/wicked-waifus-game-server/src/logic/handler/scene.rs +++ b/wicked-waifus-game-server/src/logic/handler/scene.rs @@ -1,6 +1,7 @@ use wicked_waifus_protocol::{ErrorCode, SceneLoadingFinishRequest, SceneLoadingFinishResponse, SceneTraceRequest, SceneTraceResponse, UpdateSceneDateRequest, UpdateSceneDateResponse, AccessPathTimeServerConfigRequest, AccessPathTimeServerConfigResponse, PlayerHeadDataRequest, PlayerHeadDataResponse, UnlockRoleSkinListRequest, UnlockRoleSkinListResponse, JsPatchNotify}; -const WATER_MASK: &str = include_str!("../../../scripts/watermask-disable.js"); +//const WATER_MASK: &str = include_str!("../../../scripts/watermask-disable.js"); +const WATER_MASK: &str = include_str!("../../../scripts/watermask-edit.js"); const UID_FIX: &str = include_str!("../../../scripts/uidfix.js"); const CENSORSHIP_FIX: &str = include_str!("../../../scripts/censorshipfix.js"); const DEBUG_DISABLE: &str = include_str!("../../../scripts/debug_disable.js"); diff --git a/wicked-waifus-game-server/src/logic/player/mod.rs b/wicked-waifus-game-server/src/logic/player/mod.rs index 02b0c0c..27164dd 100644 --- a/wicked-waifus-game-server/src/logic/player/mod.rs +++ b/wicked-waifus-game-server/src/logic/player/mod.rs @@ -263,7 +263,7 @@ impl Player { } if !rf.role_ids.contains(&rf.cur_role) { - rf.cur_role = *rf.role_ids.iter().nth(0).unwrap(); + rf.cur_role = *rf.role_ids.first().unwrap(); } } } @@ -304,9 +304,7 @@ impl Player { pub fn build_role_favor_list_notify(&self) -> RoleFavorListNotify { RoleFavorListNotify { favor_list: self - .role_list - .iter() - .map(|(_, role)| RoleFavor { + .role_list.values().map(|role| RoleFavor { role_id: role.role_id, level: role.favor_level, exp: role.favor_exp, @@ -341,9 +339,7 @@ impl Player { pub fn build_motion_list_notify(&self) -> RoleMotionListNotify { RoleMotionListNotify { motion_list: self - .role_list - .iter() - .map(|(_, role)| { + .role_list.values().map(|role| { RoleMotion { role_id: role.role_id, motion_ids: motion_data::iter() @@ -362,14 +358,15 @@ impl Player { } } - pub fn build_player_entity_add_notify(&self, role_list: Vec) -> EntityAddNotify { + pub fn build_player_entity_add_notify(&self, role_list: Vec, world: &mut WorldEntity) -> EntityAddNotify { create_player_entity_pb!( role_list, self.basic_info.cur_map_id, self, self.basic_info.id, self.location.position.clone(), - self.explore_tools + self.explore_tools, + world ) } @@ -449,13 +446,13 @@ impl Player { tracing::warn!("Role {} not found in use role list", role_id); return Default::default(); } - let role = *role_map.get(&role_id).unwrap(); + let role = *role_map.get(role_id).unwrap(); FormationRoleInfo { role_id: role.role_id, max_hp: 0, cur_hp: 0, level: role.level, - role_skin_id: role.skin_id, + ..Default::default() } }) .collect(), @@ -607,9 +604,7 @@ impl Player { basic_data: Some(self.basic_info.build_save_data()), role_data: Some(PlayerRoleData { role_list: self - .role_list - .iter() - .map(|(_, role)| role.build_save_data()) + .role_list.values().map(|role| role.build_save_data()) .collect(), role_formation_list: self .formation_list @@ -642,9 +637,7 @@ impl Player { // TODO: There is a bug we are investigating with several resonators, this is a workaround PbGetRoleListNotify { role_list: self - .role_list - .iter() - .map(|(_, role)| role.to_protobuf()) + .role_list.values().map(|role| role.to_protobuf()) .collect(), } } diff --git a/wicked-waifus-game-server/src/logic/role/formation.rs b/wicked-waifus-game-server/src/logic/role/formation.rs index 7ae91f9..30ee4c4 100644 --- a/wicked-waifus-game-server/src/logic/role/formation.rs +++ b/wicked-waifus-game-server/src/logic/role/formation.rs @@ -29,7 +29,7 @@ impl RoleFormation { RoleFormationData { formation_id: self.id, cur_role: self.cur_role, - role_id_list: self.role_ids.iter().map(|&role_id| role_id).collect(), + role_id_list: self.role_ids.to_vec(), is_current: self.is_current, } } diff --git a/wicked-waifus-game-server/src/logic/utils/mod.rs b/wicked-waifus-game-server/src/logic/utils/mod.rs index c7eec47..fd7f09b 100644 --- a/wicked-waifus-game-server/src/logic/utils/mod.rs +++ b/wicked-waifus-game-server/src/logic/utils/mod.rs @@ -5,4 +5,4 @@ pub mod load_role_info; pub mod world_util; pub mod quadrant_util; pub mod growth_utils; -pub mod tag_utils; +pub mod tag_utils; \ No newline at end of file diff --git a/wicked-waifus-game-server/src/logic/utils/world_util.rs b/wicked-waifus-game-server/src/logic/utils/world_util.rs index 4a0634e..de95786 100644 --- a/wicked-waifus-game-server/src/logic/utils/world_util.rs +++ b/wicked-waifus-game-server/src/logic/utils/world_util.rs @@ -1,58 +1,60 @@ +use wicked_waifus_protocol::summon::ESummonType; use wicked_waifus_protocol::{ - EEntityType, ERemoveEntityType, EntityAddNotify, EntityConfigType, EntityPb, EntityRemoveInfo, - EntityRemoveNotify, EntityState, FightRoleInfo, FightRoleInfos, LivingStatus, SceneInformation, - SceneMode, ScenePlayerInformation, SceneTimeInfo, + EEntityType, ERemoveEntityType, EntityAddNotify, EntityConfigType, EntityPb, EntityRemoveInfo, EntityRemoveNotify, EntityState, FightBuffInformation, FightRoleInfo, FightRoleInfos, LivingStatus, SceneInformation, SceneMode, ScenePlayerInformation, SceneTimeInfo }; use wicked_waifus_data::pb_components::ComponentsData; use wicked_waifus_data::{ - blueprint_config_data, template_config_data, EntityLogic, EntityType, LevelEntityConfigData, + base_property_data, blueprint_config_data, template_config_data, EntityLogic, EntityType, LevelEntityConfigData }; use crate::logic::components::{Autonomous, Fsm, Interact, MonsterAi, SoarWingSkin, StateTag, Tag}; -use crate::logic::ecs::entity::EntityBuilder; -use crate::logic::ecs::world::World; +use crate::logic::ecs::entity::{Entity, EntityBuilder}; +use crate::logic::ecs::world::{World, WorldEntity}; use crate::logic::math::Transform; use crate::logic::player::Player; -use crate::logic::utils::{entity_serializer, tag_utils}; use crate::logic::utils::growth_utils::get_monster_props_by_level; +use crate::logic::utils::{entity_serializer, tag_utils}; use crate::logic::{ components::{ - Attribute, EntityConfig, Equip, FightBuff, Movement, OwnerPlayer, PlayerOwnedEntityMarker, - Position, RoleSkin, Visibility, VisionSkill, + Attribute, Concomitant, EntityConfig, Equip, FightBuff, Movement, OwnerPlayer, + PlayerOwnedEntityMarker, Position, RoleSkin, Summoner, Visibility, VisionSkill, }, ecs::component::ComponentContainer, }; +//use crate::resonator_data::{ResonatorData, Concomitant, SummonerComponent}; + use crate::query_with; #[macro_export] macro_rules! create_player_entity_pb { - ($role_list:expr, $cur_map_id:expr, $player:expr, $player_id:expr, $position:expr, $explore_tools:expr) => {{ - let mut world_ref = $player.world.borrow_mut(); - let world = world_ref.get_mut_world_entity(); - - let current_formation = $player.formation_list.get(&$player.cur_formation_id).unwrap(); + ($role_list:expr, $cur_map_id:expr, $player:expr, $player_id:expr, $position:expr, $explore_tools:expr, $world:expr) => {{ + let current_formation = $player + .formation_list + .get(&$player.cur_formation_id) + .unwrap(); let cur_role_id = current_formation.cur_role; let mut pbs = Vec::new(); for role in $role_list { - let entity = world.create_entity( - role.role_id, - EEntityType::Player.into(), - $cur_map_id, - ); - // Once per character buffs are implemented, add a mut on role_buffs - let fight_buff_infos = world.generate_role_permanent_buffs(entity.entity_id as i64); - let buf_manager = FightBuff { + let role_id: i32 = role.role_id; + let entity = + $world.create_entity(role.role_id, EEntityType::Player.into(), $cur_map_id); + let fight_buff_infos = $world.generate_role_permanent_buffs(entity.entity_id, role_id); + + let buffs = FightBuff { fight_buff_infos, - list_buff_effect_cd: vec![], + ..Default::default() }; - let entity = world.create_builder(entity) - .with(ComponentContainer::PlayerOwnedEntityMarker(PlayerOwnedEntityMarker { - entity_type: EEntityType::Player, - })) + let entity = $world + .create_builder(entity) + .with(ComponentContainer::PlayerOwnedEntityMarker( + PlayerOwnedEntityMarker { + entity_type: EEntityType::Player, + }, + )) .with(ComponentContainer::EntityConfig(EntityConfig { camp: 0, config_id: role.role_id, @@ -62,23 +64,19 @@ macro_rules! create_player_entity_pb { })) .with(ComponentContainer::OwnerPlayer(OwnerPlayer($player_id))) .with(ComponentContainer::Position(Position($position))) - .with(ComponentContainer::Visibility(Visibility{ + .with(ComponentContainer::Visibility(Visibility { is_visible: role.role_id == cur_role_id, is_actor_visible: true, })) - // TODO: Check if role has hardness or rage_mode - // TODO: Support AddProp from Equipment(Echo, weapon, buffs??), weapon base state goes to base_prop too. - .with(ComponentContainer::Attribute( - Attribute::from_data( - &role.get_base_properties(), - None, - None, - ) - )) + .with(ComponentContainer::Attribute(Attribute::from_data( + &role.get_base_properties(), + None, + None, + ))) .with(ComponentContainer::Movement(Movement::default())) .with(ComponentContainer::Equip(Equip { weapon_id: role.equip_weapon, - weapon_breach_level: 90, // TODO: store this too + weapon_breach_level: 90, })) .with(ComponentContainer::VisionSkill(VisionSkill { skill_id: $explore_tools.active_explore_skill, @@ -89,7 +87,7 @@ macro_rules! create_player_entity_pb { .with(ComponentContainer::SoarWingSkin(SoarWingSkin { skin_id: 84000001, })) - .with(ComponentContainer::FightBuff(buf_manager)) + .with(ComponentContainer::FightBuff(buffs)) .build(); let mut pb = EntityPb { @@ -97,7 +95,7 @@ macro_rules! create_player_entity_pb { ..Default::default() }; - world + $world .get_entity_components(entity.entity_id) .into_iter() .for_each(|comp| comp.set_pb_data(&mut pb)); @@ -111,6 +109,85 @@ macro_rules! create_player_entity_pb { }}; } +fn summon_concomitant(player: &Player, world: &mut WorldEntity, summon_cfg: &wicked_waifus_data::SummonCfgData) -> Entity { + let mut concomitant_buffs: Vec = Vec::new(); + + for buff_id in &summon_cfg.born_buff_id { + concomitant_buffs + .push(FightBuffInformation { + handle_id: 1, + buff_id: *buff_id, + level: 1, + stack_count: 1, + instigator_id: 0, + entity_id: 0, + apply_type: 0, + duration: -1.0, + left_duration: -1.0, + context: vec![], + is_active: true, + server_id: 1, + message_id: 1, + } + ); + } + + let concomitant_id = template_config_data::get(&summon_cfg.blueprint_type).unwrap().id; + tracing::info!("Adding Concomitant with id: {}", concomitant_id); + let con_buffs = concomitant_buffs.clone(); + + let con_entity = world.create_entity( + concomitant_id, + EEntityType::Monster.into(), + player.basic_info.cur_map_id, + ); + + world + .create_builder(con_entity) + .with(ComponentContainer::PlayerOwnedEntityMarker(PlayerOwnedEntityMarker { + entity_type: EEntityType::Monster, + })) + .with(ComponentContainer::EntityConfig(EntityConfig { + camp: 0, + config_id: concomitant_id, + config_type: EntityConfigType::Template, + entity_type: EEntityType::Monster, + entity_state: EntityState::Sleep, + })) + .with(ComponentContainer::OwnerPlayer(OwnerPlayer( + player.basic_info.id, + ))) + .with(ComponentContainer::Position(Position( + player.location.position.clone(), + ))) + .with(ComponentContainer::Visibility(Visibility { + is_visible: false, + is_actor_visible: false, + })) + .with(ComponentContainer::Attribute(Attribute::from_data( + base_property_data::iter() + .find(|d| d.id == concomitant_id as i32) + .unwrap_or_else(|| { + base_property_data::iter() + .find(|d| d.id == 390070051) + .unwrap_or_else(|| { + tracing::error!("Default base property concomitant not found!"); + panic!("Critical config missing: base property concomitant") + }) + }), + None, + None, + ))) + .with(ComponentContainer::Movement(Movement::default())) + .with(ComponentContainer::FightBuff(FightBuff { fight_buff_infos: con_buffs, ..Default::default() })) + .with(ComponentContainer::Summoner(Summoner { + summon_cfg_id: summon_cfg.id, + summon_skill_id: 0, + summon_type: ESummonType::ESummonTypeConcomitantCustom.into() + })) + .build() +} + pub fn add_player_entities(player: &Player) { let mut world_ref = player.world.borrow_mut(); let world = world_ref.get_mut_world_entity(); @@ -120,22 +197,32 @@ pub fn add_player_entities(player: &Player) { let role_vec = current_formation .role_ids .iter() - .map(|role_id| player.role_list.get(&role_id).unwrap()) + .map(|role_id| player.role_list.get(role_id).unwrap()) .collect::>(); let cur_role_id = current_formation.cur_role; if world.active_entity_empty() { for role in role_vec { + let mut concomitants: Vec = vec![]; + + for (_, summon_cfg) in wicked_waifus_data::summon_cfg_data::iter().filter(|(_, cfg)| { + cfg.blueprint_type.starts_with("Player0") && cfg.born_buff_id.iter().any(|x| { + x.to_string().starts_with(&role.role_id.to_string()) + }) + }) { + let concomitant = summon_concomitant(player, world, summon_cfg); + concomitants.push(concomitant.entity_id.into()); + } + let entity = world.create_entity( role.role_id, EEntityType::Player.into(), player.basic_info.cur_map_id, ); - // Once per character buffs are implemented, add a mut on role_buffs - let fight_buff_infos = world.generate_role_permanent_buffs(entity.entity_id as i64); + let fight_buff_infos = world.generate_role_permanent_buffs(entity.entity_id, role.role_id); let buf_manager = FightBuff { fight_buff_infos, - list_buff_effect_cd: vec![], + list_buff_effect_cd: vec![] }; let entity = world .create_builder(entity) @@ -148,7 +235,7 @@ pub fn add_player_entities(player: &Player) { camp: 0, config_id: role.role_id, config_type: EntityConfigType::Character, - entity_type: EEntityType::Player.into(), + entity_type: EEntityType::Player, entity_state: EntityState::Default, })) .with(ComponentContainer::OwnerPlayer(OwnerPlayer( @@ -184,6 +271,11 @@ pub fn add_player_entities(player: &Player) { skin_id: 84000001, })) .with(ComponentContainer::FightBuff(buf_manager)) + .with(ComponentContainer::Concomitant(Concomitant { + vision_entity_id: 0, + custom_entity_ids: concomitants, + phantom_role_id: 0, + })) .build(); tracing::debug!( @@ -264,7 +356,7 @@ fn build_player_info_list(world: &World) -> Vec { cur_role: cur_role_id, // is_retain: true, fight_role_infos: active_characters - .map(|(id, _, _, conf, role_skin)| FightRoleInfo { + .map(|(id, _, _, conf, _role_skin)| FightRoleInfo { entity_id: id.into(), role_id: conf.config_id, on_stage_without_control: false, @@ -430,7 +522,13 @@ pub fn add_entities(player: &Player, entities: &[&LevelEntityConfigData], extern build_autonomous_component(&mut builder, player.basic_info.id, entity_logic); build_interact_component(&mut builder, &components); - build_tags_components(&mut builder, &components, player, blueprint_config.unwrap().entity_type, config_id as i64); + build_tags_components( + &mut builder, + &components, + player, + blueprint_config.unwrap().entity_type, + config_id as i64, + ); build_attribute_component(&mut builder, &components, player.location.instance_id); build_ai_components(&mut builder, &components); added_entities.push(builder.build()); @@ -496,7 +594,10 @@ fn build_tags_components( if let Some(entity_state_component) = &components.entity_state_component { let state = match entity_type { EntityType::Teleporter | EntityType::TemporaryTeleporter => { - let result = player.teleports.teleports_data.iter() + let result = player + .teleports + .teleports_data + .iter() .find(|teleporter| teleporter.entity_config_id == config_id); match result.is_some() { true => tag_utils::get_tag_id_by_name("关卡.Common.状态.激活"),