From 8dde0c870522480e6f2cbce2b3638f9c871e989d Mon Sep 17 00:00:00 2001 From: xeon Date: Mon, 4 Nov 2024 01:04:18 +0300 Subject: [PATCH] Implement avatar trace effect change (Echo) --- .../AvatarTraceEffectExcelConfigData | 1 + .../game-server-core/src/player_data_sync.rs | 8 ++ crates/game-server/src/player_info_util.rs | 7 +- crates/sakura-avatar/src/appearance.rs | 110 ++++++++++++++++-- .../excel/avatar_trace_effect_excel_config.rs | 12 ++ crates/sakura-data/src/excel/mod.rs | 3 + crates/sakura-data/src/lib.rs | 1 + crates/sakura-entity/src/avatar.rs | 80 +++++++++---- crates/sakura-entity/src/lib.rs | 6 +- .../src/player_information.rs | 2 + crates/sakura-proto/gen/client.rs | 14 +-- crates/sakura-proto/gen/client_to_normal.rs | 35 ++++++ crates/sakura-proto/gen/conversion.rs | 48 ++++++++ crates/sakura-proto/gen/normal.rs | 33 ++++++ crates/sakura-proto/gen/normal_to_client.rs | 35 ++++++ crates/sakura-scene/src/player_join_team.rs | 1 + crates/sakura-scene/src/scene_team_update.rs | 1 + 17 files changed, 352 insertions(+), 45 deletions(-) create mode 100644 assets/ExcelBinOutput/AvatarTraceEffectExcelConfigData create mode 100644 crates/sakura-data/src/excel/avatar_trace_effect_excel_config.rs diff --git a/assets/ExcelBinOutput/AvatarTraceEffectExcelConfigData b/assets/ExcelBinOutput/AvatarTraceEffectExcelConfigData new file mode 100644 index 0000000..19680fb --- /dev/null +++ b/assets/ExcelBinOutput/AvatarTraceEffectExcelConfigData @@ -0,0 +1 @@ +ُ ُ ,Eff_Avatar_Lady_Sword_Qin_CharMaster_00_Blow-Eff_Avatar_Lady_Sword_Qin_CharMaster_00_Worldڏ ڏ -Eff_Avatar_Loli_Sword_Qiqi_CharMaster_00_Blow.Eff_Avatar_Loli_Sword_Qiqi_CharMaster_00_Worldȹ ۏ ۏ 5Eff_Avatar_Lady_Catalyst_Ningguang_CharMaster_00_Blow6Eff_Avatar_Lady_Catalyst_Ningguang_CharMaster_00_WorldęͶ ܏ ܏ /Eff_Avatar_Girl_Sword_Momoka_CharMaster_00_Blow0Eff_Avatar_Girl_Sword_Momoka_CharMaster_00_Worldڹݏ ݏ 1Eff_Avatar_Male_Claymore_Diluc_CharMaster_00_Blow2Eff_Avatar_Male_Claymore_Diluc_CharMaster_00_World ޏ ޏ /Eff_Avatar_Male_Pole_Zhongli_CharMaster_00_Blow0Eff_Avatar_Male_Pole_Zhongli_CharMaster_00_World ߏ ߏ /Eff_Avatar_Girl_Sword_Keqing_CharMaster_00_Blow0Eff_Avatar_Girl_Sword_Keqing_CharMaster_00_WorldÅ \ No newline at end of file diff --git a/crates/game-server-core/src/player_data_sync.rs b/crates/game-server-core/src/player_data_sync.rs index 834a8a2..3f4d749 100644 --- a/crates/game-server-core/src/player_data_sync.rs +++ b/crates/game-server-core/src/player_data_sync.rs @@ -117,6 +117,8 @@ pub fn sync_avatar_data(players: Res, out: Res) { as u32, avatar_type: 1, // TODO! wearing_flycloak_id: a.wearing_flycloak_id, + costume_id: a.costume_id, + trace_effect_id: a.trace_effect_id, fetter_info: Some(AvatarFetterInfo::default()), skill_level_map: a.skill_level_map.clone(), inherent_proud_skill_list: a.inherent_proud_skill_list.clone(), @@ -167,6 +169,12 @@ pub fn sync_avatar_data(players: Res, out: Res) { .iter() .copied() .collect(), + owned_trace_effect_list: player_info + .avatar_module + .owned_trace_effect_set + .iter() + .copied() + .collect(), ..Default::default() }, ); diff --git a/crates/game-server/src/player_info_util.rs b/crates/game-server/src/player_info_util.rs index d23c01d..c0a711c 100644 --- a/crates/game-server/src/player_info_util.rs +++ b/crates/game-server/src/player_info_util.rs @@ -4,7 +4,8 @@ use common::time_util; use sakura_data::excel::{ avatar_costume_excel_config_collection, avatar_excel_config_collection, avatar_flycloak_excel_config_collection, avatar_skill_depot_excel_config_collection, - weapon_excel_config_collection, AvatarExcelConfig, AvatarUseType, + avatar_trace_effect_excel_config_collection, weapon_excel_config_collection, AvatarExcelConfig, + AvatarUseType, }; use sakura_persistence::player_information::*; @@ -32,6 +33,9 @@ pub fn create_default_player_information(uid: u32, nick_name: String) -> PlayerI .filter(|c| !c.is_default) .map(|c| c.skin_id) .collect(), + owned_trace_effect_set: avatar_trace_effect_excel_config_collection::iter() + .map(|c| c.trace_effect_id) + .collect(), }, item_map: HashMap::new(), world_position: PlayerPositionInformation { @@ -134,6 +138,7 @@ fn add_avatar_and_weapon(player: &mut PlayerInformation, avatar: &AvatarExcelCon inherent_proud_skill_list, wearing_flycloak_id: DEFAULT_FLYCLOAK_ID, costume_id: 0, + trace_effect_id: 0, }, ); diff --git a/crates/sakura-avatar/src/appearance.rs b/crates/sakura-avatar/src/appearance.rs index 4c8b121..f238c84 100644 --- a/crates/sakura-avatar/src/appearance.rs +++ b/crates/sakura-avatar/src/appearance.rs @@ -1,11 +1,14 @@ use bevy_ecs::prelude::*; -use sakura_data::excel::avatar_costume_excel_config_collection; -use sakura_entity::avatar::AvatarCostumeChangeEvent; +use sakura_data::excel::{ + avatar_costume_excel_config_collection, avatar_trace_effect_excel_config_collection, +}; +use sakura_entity::avatar::{AvatarAppearanceChange, AvatarAppearanceChangeEvent}; use sakura_message::{event::ClientMessageEvent, output::MessageOutput}; use sakura_persistence::{player_information::PlayerInformation, Players}; use sakura_proto::{ - AvatarChangeCostumeReq, AvatarChangeCostumeRsp, AvatarFlycloakChangeNotify, - AvatarWearFlycloakReq, AvatarWearFlycloakRsp, Retcode, + AvatarChangeCostumeReq, AvatarChangeCostumeRsp, AvatarChangeTraceEffectReq, + AvatarChangeTraceEffectRsp, AvatarFlycloakChangeNotify, AvatarWearFlycloakReq, + AvatarWearFlycloakRsp, Retcode, }; use tracing::{debug, instrument}; @@ -14,7 +17,7 @@ pub fn handle_appearance_change_request( mut events: EventReader, mut players: ResMut, message_output: Res, - mut costume_change_events: EventWriter, + mut change_events: EventWriter, ) { for message in events.read() { if let Some(request) = message.decode::() { @@ -31,7 +34,16 @@ pub fn handle_appearance_change_request( let mut rsp = AvatarChangeCostumeRsp::default(); if let Some(change_event) = change_costume(player, request, &mut rsp) { - costume_change_events.send(change_event); + change_events.send(change_event); + } + + message_output.send(message.sender_uid(), rsp); + } else if let Some(request) = message.decode::() { + let player = players.get_mut(message.sender_uid()); + let mut rsp = AvatarChangeTraceEffectRsp::default(); + + if let Some(change_event) = change_trace_effect(player, request, &mut rsp) { + change_events.send(change_event); } message_output.send(message.sender_uid(), rsp); @@ -85,7 +97,7 @@ fn change_costume( player: &mut PlayerInformation, request: AvatarChangeCostumeReq, response: &mut AvatarChangeCostumeRsp, -) -> Option { +) -> Option { response.retcode = Retcode::RetFail.into(); let config = (request.costume_id != 0) @@ -140,9 +152,83 @@ fn change_costume( avatar.avatar_id, request.costume_id ); - Some(AvatarCostumeChangeEvent( - player.uid, - request.avatar_guid, - request.costume_id, - )) + Some(AvatarAppearanceChangeEvent { + player_uid: player.uid, + avatar_guid: request.avatar_guid, + change: AvatarAppearanceChange::Costume(request.costume_id), + }) +} + +#[instrument(skip(player, response))] +fn change_trace_effect( + player: &mut PlayerInformation, + request: AvatarChangeTraceEffectReq, + response: &mut AvatarChangeTraceEffectRsp, +) -> Option { + response.retcode = Retcode::RetFail.into(); + + let config = (request.trace_effect_id != 0) + .then(|| { + avatar_trace_effect_excel_config_collection::iter() + .find(|c| c.trace_effect_id == request.trace_effect_id) + }) + .flatten(); + + if request.trace_effect_id != 0 && config.is_none() { + debug!( + "trace_effect_id {} config doesn't exist", + request.trace_effect_id + ); + return None; + }; + + if !player + .avatar_module + .owned_trace_effect_set + .contains(&request.trace_effect_id) + && config.is_some() + { + debug!( + "trace effect is not unlocked, id: {}", + request.trace_effect_id + ); + response.retcode = Retcode::RetNotHasTraceEffect.into(); + return None; + } + + let Some(avatar) = player + .avatar_module + .avatar_map + .get_mut(&request.avatar_guid) + else { + debug!("avatar guid {} doesn't exist", request.avatar_guid); + return None; + }; + + if let Some(config) = config { + if config.avatar_id != avatar.avatar_id { + debug!( + "avatar trace effect mismatch, config: {}, requested: {}", + config.avatar_id, avatar.avatar_id + ); + response.retcode = Retcode::RetTraceEffectAvatarError.into(); + return None; + } + } + + response.avatar_guid = request.avatar_guid; + response.trace_effect_id = request.trace_effect_id; + response.retcode = Retcode::RetSucc.into(); + avatar.trace_effect_id = request.trace_effect_id; + + debug!( + "change trace effect for avatar {} to {}", + avatar.avatar_id, request.trace_effect_id + ); + + Some(AvatarAppearanceChangeEvent { + player_uid: player.uid, + avatar_guid: request.avatar_guid, + change: AvatarAppearanceChange::TraceEffect(request.trace_effect_id), + }) } diff --git a/crates/sakura-data/src/excel/avatar_trace_effect_excel_config.rs b/crates/sakura-data/src/excel/avatar_trace_effect_excel_config.rs new file mode 100644 index 0000000..9b0a66b --- /dev/null +++ b/crates/sakura-data/src/excel/avatar_trace_effect_excel_config.rs @@ -0,0 +1,12 @@ +use sakura_data_derive::FromBinary; + +#[derive(Debug, FromBinary)] +pub struct AvatarTraceEffectExcelConfig { + pub trace_effect_id: u32, + pub avatar_id: u32, + pub item_id: u32, + pub unk_1: String, + pub unk_2: Vec, + pub name_text_map_hash: u32, + pub desc_text_map_hash: u32, +} diff --git a/crates/sakura-data/src/excel/mod.rs b/crates/sakura-data/src/excel/mod.rs index 5d1815a..61db2a1 100644 --- a/crates/sakura-data/src/excel/mod.rs +++ b/crates/sakura-data/src/excel/mod.rs @@ -4,6 +4,7 @@ mod avatar_excel_config; mod avatar_flycloak_excel_config; mod avatar_promote_excel_config; mod avatar_skill_depot_excel_config; +mod avatar_trace_effect_excel_config; mod map_area_config; mod monster_curve_excel_config; mod monster_excel_config; @@ -18,6 +19,7 @@ pub use avatar_excel_config::*; pub use avatar_flycloak_excel_config::*; pub use avatar_promote_excel_config::*; pub use avatar_skill_depot_excel_config::*; +pub use avatar_trace_effect_excel_config::*; pub use map_area_config::*; pub use monster_curve_excel_config::*; pub use monster_excel_config::*; @@ -68,6 +70,7 @@ macro_rules! excel_loader { excel_loader! { AvatarExcelConfig; AvatarCostumeExcelConfig; + AvatarTraceEffectExcelConfig; AvatarFlycloakExcelConfig; AvatarSkillDepotExcelConfig; AvatarCurveExcelConfig; diff --git a/crates/sakura-data/src/lib.rs b/crates/sakura-data/src/lib.rs index 685fff7..85ea1d7 100644 --- a/crates/sakura-data/src/lib.rs +++ b/crates/sakura-data/src/lib.rs @@ -79,6 +79,7 @@ mod tests { excel_test!( AvatarExcelConfig, + AvatarTraceEffectExcelConfig, AvatarCostumeExcelConfig, AvatarFlycloakExcelConfig, AvatarSkillDepotExcelConfig, diff --git a/crates/sakura-entity/src/avatar.rs b/crates/sakura-entity/src/avatar.rs index 172f70a..0be588b 100644 --- a/crates/sakura-entity/src/avatar.rs +++ b/crates/sakura-entity/src/avatar.rs @@ -6,7 +6,7 @@ use sakura_persistence::{ player_information::{AvatarInformation, ItemInformation}, Players, }; -use sakura_proto::{AvatarChangeCostumeNotify, SceneEntityInfo}; +use sakura_proto::{AvatarChangeCostumeNotify, AvatarChangeTraceEffectNotify, SceneEntityInfo}; use crate::{ int_prop_pair, @@ -25,6 +25,7 @@ pub struct Equipment { pub struct AvatarAppearance { pub flycloak_id: u32, pub costume_id: u32, + pub trace_effect_id: u32, } #[derive(Event)] @@ -34,8 +35,17 @@ pub struct AvatarEquipChangeEvent { pub weapon_guid: u64, } +pub enum AvatarAppearanceChange { + Costume(u32), + TraceEffect(u32), +} + #[derive(Event)] -pub struct AvatarCostumeChangeEvent(pub u32, pub u64, pub u32); +pub struct AvatarAppearanceChangeEvent { + pub player_uid: u32, + pub avatar_guid: u64, + pub change: AvatarAppearanceChange, +} #[derive(Component)] pub struct AvatarID(pub u32); @@ -106,47 +116,71 @@ pub struct AvatarQueryReadOnly { } pub fn update_avatar_appearance( - mut events: EventReader, + mut events: EventReader, mut avatars: Query<(&Guid, &mut AvatarAppearance)>, ) { - for AvatarCostumeChangeEvent(_, guid, costume_id) in events.read() { - if let Some((_, mut appearance)) = avatars.iter_mut().find(|(g, _)| g.0 == *guid) { - appearance.costume_id = *costume_id; + for event in events.read() { + if let Some((_, mut appearance)) = + avatars.iter_mut().find(|(g, _)| g.0 == event.avatar_guid) + { + match event.change { + AvatarAppearanceChange::Costume(costume_id) => { + appearance.costume_id = costume_id; + } + AvatarAppearanceChange::TraceEffect(trace_effect_id) => { + appearance.trace_effect_id = trace_effect_id; + } + } } } } -pub fn notify_avatar_costume_change( - mut events: EventReader, +pub fn notify_avatar_appearance_change( + mut events: EventReader, avatars: Query, weapons: Query, message_output: Res, players: Res, ) { - for AvatarCostumeChangeEvent(player_uid, guid, _) in events.read() { + for event in events.read() { if let Some(avatar_data) = avatars .iter() - .find(|avatar_data| avatar_data.guid.0 == *guid) + .find(|avatar_data| avatar_data.guid.0 == event.avatar_guid) { let weapon_data = weapons.get(avatar_data.equipment.weapon).unwrap(); - message_output.send_to_all(AvatarChangeCostumeNotify { - entity_info: Some(build_avatar_entity_info(&avatar_data, &weapon_data)), - }); + let entity_info = Some(build_avatar_entity_info(&avatar_data, &weapon_data)); + + match event.change { + AvatarAppearanceChange::Costume(_) => { + message_output.send_to_all(AvatarChangeCostumeNotify { entity_info }) + } + AvatarAppearanceChange::TraceEffect(_) => { + message_output.send_to_all(AvatarChangeTraceEffectNotify { entity_info }) + } + } } - // that's disgusting, this packet required even if avatar is not on scene + // that's disgusting, notify required even if avatar is not on scene // even though it contains SceneEntityInfo else { - let player = players.get(*player_uid); + let player = players.get(event.player_uid); - let avatar = player.avatar_module.avatar_map.get(guid).unwrap(); + let avatar = player + .avatar_module + .avatar_map + .get(&event.avatar_guid) + .unwrap(); let weapon = player.item_map.get(&avatar.weapon_guid).unwrap(); - message_output.send( - *player_uid, - AvatarChangeCostumeNotify { - entity_info: Some(build_fake_avatar_entity_info(avatar, weapon)), - }, - ); + let entity_info = Some(build_fake_avatar_entity_info(avatar, weapon)); + match event.change { + AvatarAppearanceChange::Costume(_) => { + message_output.send(event.player_uid, AvatarChangeCostumeNotify { entity_info }) + } + AvatarAppearanceChange::TraceEffect(_) => message_output.send( + event.player_uid, + AvatarChangeTraceEffectNotify { entity_info }, + ), + } } } } @@ -219,6 +253,7 @@ fn build_fake_avatar_entity_info( wearing_flycloak_id: avatar.wearing_flycloak_id, born_time: avatar.born_time, costume_id: avatar.costume_id, + trace_effect_id: avatar.trace_effect_id, cur_vehicle_info: None, excel_info: Some(AvatarExcelInfo::default()), anim_hash: 0, @@ -305,6 +340,7 @@ fn build_avatar_entity_info( wearing_flycloak_id: avatar_data.appearance.flycloak_id, born_time: avatar_data.born_time.0, costume_id: avatar_data.appearance.costume_id, + trace_effect_id: avatar_data.appearance.trace_effect_id, cur_vehicle_info: None, excel_info: Some(AvatarExcelInfo::default()), anim_hash: 0, diff --git a/crates/sakura-entity/src/lib.rs b/crates/sakura-entity/src/lib.rs index 9d29872..b77edea 100644 --- a/crates/sakura-entity/src/lib.rs +++ b/crates/sakura-entity/src/lib.rs @@ -1,4 +1,4 @@ -use avatar::{AvatarCostumeChangeEvent, AvatarEquipChangeEvent}; +use avatar::{AvatarAppearanceChangeEvent, AvatarEquipChangeEvent}; use bevy_app::prelude::*; use bevy_ecs::prelude::*; use common::{EntityCounter, FightProperties, LifeState, ProtocolEntityID, ToBeRemovedMarker}; @@ -25,7 +25,7 @@ impl Plugin for EntityPlugin { fn build(&self, app: &mut App) { app.insert_resource(EntityCounter::default()) .add_event::() - .add_event::() + .add_event::() .add_event::() .add_systems(Update, avatar::update_avatar_appearance) .add_systems( @@ -35,7 +35,7 @@ impl Plugin for EntityPlugin { notify_life_state_change, notify_disappear_entities, remove_marked_entities, - avatar::notify_avatar_costume_change, + avatar::notify_avatar_appearance_change, avatar::notify_appear_avatar_entities .run_if(avatar::run_if_avatar_entities_appeared), monster::notify_appear_monster_entities diff --git a/crates/sakura-persistence/src/player_information.rs b/crates/sakura-persistence/src/player_information.rs index b41fe81..3a4d686 100644 --- a/crates/sakura-persistence/src/player_information.rs +++ b/crates/sakura-persistence/src/player_information.rs @@ -35,6 +35,7 @@ pub struct AvatarModuleInformation { pub team_map: HashMap, pub owned_flycloak_set: HashSet, pub owned_costume_set: HashSet, + pub owned_trace_effect_set: HashSet, } #[derive(Serialize, Deserialize)] @@ -57,6 +58,7 @@ pub struct AvatarInformation { pub inherent_proud_skill_list: Vec, pub wearing_flycloak_id: u32, pub costume_id: u32, + pub trace_effect_id: u32, } #[derive(Serialize, Deserialize)] diff --git a/crates/sakura-proto/gen/client.rs b/crates/sakura-proto/gen/client.rs index 27fd068..ab6d3e7 100644 --- a/crates/sakura-proto/gen/client.rs +++ b/crates/sakura-proto/gen/client.rs @@ -9248,11 +9248,11 @@ pub struct Mkbmdcgmieo { #[derive(sakura_proto_derive::CmdID)] #[cmdid(689)] #[derive(Clone, Copy, PartialEq, ::prost::Message)] -pub struct Nolndpmeomc { +pub struct AvatarChangeTraceEffectReq { #[prost(uint64, tag = "9")] pub avatar_guid: u64, #[prost(uint32, tag = "5")] - pub dpmaabplgdp: u32, + pub trace_effect_id: u32, } #[derive(sakura_proto_derive::CmdID)] #[cmdid(2773)] @@ -18167,7 +18167,7 @@ pub struct AvatarInfo { #[prost(uint32, tag = "30")] pub mfmiphlgdfl: u32, #[prost(uint32, tag = "31")] - pub dpmaabplgdp: u32, + pub trace_effect_id: u32, } #[derive(sakura_proto_derive::CmdID)] #[cmdid(26048)] @@ -18559,9 +18559,9 @@ pub struct Cgoihcdffej { #[derive(sakura_proto_derive::CmdID)] #[cmdid(25986)] #[derive(Clone, Copy, PartialEq, ::prost::Message)] -pub struct Opcpmjolife { +pub struct AvatarChangeTraceEffectRsp { #[prost(uint32, tag = "1")] - pub dpmaabplgdp: u32, + pub trace_effect_id: u32, #[prost(int32, tag = "12")] pub retcode: i32, #[prost(uint64, tag = "15")] @@ -20049,7 +20049,7 @@ pub struct Lmfbfgjedkn { #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct Glinbnfejlc { #[prost(uint32, tag = "15")] - pub dpmaabplgdp: u32, + pub trace_effect_id: u32, } #[derive(sakura_proto_derive::CmdID)] #[cmdid(9144)] @@ -37400,7 +37400,7 @@ pub struct SceneAvatarInfo { #[prost(uint32, tag = "22")] pub anim_hash: u32, #[prost(uint32, tag = "23")] - pub dpmaabplgdp: u32, + pub trace_effect_id: u32, } #[derive(sakura_proto_derive::CmdID)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/crates/sakura-proto/gen/client_to_normal.rs b/crates/sakura-proto/gen/client_to_normal.rs index b99eaf9..9c47c06 100644 --- a/crates/sakura-proto/gen/client_to_normal.rs +++ b/crates/sakura-proto/gen/client_to_normal.rs @@ -436,6 +436,11 @@ impl From for AvatarDataNotify { .map(|v| v.into()) .collect(), choose_avatar_guid: value.choose_avatar_guid.into(), + owned_trace_effect_list: value + .owned_trace_effect_list + .into_iter() + .map(|v| v.into()) + .collect(), avatar_team_map: value .avatar_team_map .into_iter() @@ -579,6 +584,15 @@ for query_curr_region_http_rsp::Detail { } } } +impl From for AvatarChangeTraceEffectReq { + fn from(value: crate::client::AvatarChangeTraceEffectReq) -> Self { + Self { + avatar_guid: value.avatar_guid.into(), + trace_effect_id: value.trace_effect_id.into(), + ..Default::default() + } + } +} impl From for QueryPathReq { fn from(value: crate::client::QueryPathReq) -> Self { Self { @@ -1085,6 +1099,7 @@ impl From for AvatarInfo { excel_info: value.excel_info.map(|v| v.into()), anim_hash: value.anim_hash.into(), mirror_avatar_info: value.mirror_avatar_info.map(|v| v.into()), + trace_effect_id: value.trace_effect_id.into(), ..Default::default() } } @@ -1141,6 +1156,16 @@ impl From for scene_entity_info::Entit } } } +impl From for AvatarChangeTraceEffectRsp { + fn from(value: crate::client::AvatarChangeTraceEffectRsp) -> Self { + Self { + trace_effect_id: value.trace_effect_id.into(), + retcode: value.retcode.into(), + avatar_guid: value.avatar_guid.into(), + ..Default::default() + } + } +} impl From for EnterScenePeerNotify { fn from(value: crate::client::EnterScenePeerNotify) -> Self { Self { @@ -1733,6 +1758,15 @@ impl From for UnlockTransPointReq { } } } +impl From +for AvatarChangeTraceEffectNotify { + fn from(value: crate::client::AvatarChangeTraceEffectNotify) -> Self { + Self { + entity_info: value.entity_info.map(|v| v.into()), + ..Default::default() + } + } +} impl From for AvatarFightPropUpdateNotify { fn from(value: crate::client::AvatarFightPropUpdateNotify) -> Self { Self { @@ -2273,6 +2307,7 @@ impl From for SceneAvatarInfo { cur_vehicle_info: value.cur_vehicle_info.map(|v| v.into()), excel_info: value.excel_info.map(|v| v.into()), anim_hash: value.anim_hash.into(), + trace_effect_id: value.trace_effect_id.into(), ..Default::default() } } diff --git a/crates/sakura-proto/gen/conversion.rs b/crates/sakura-proto/gen/conversion.rs index 8997642..f9f8dec 100644 --- a/crates/sakura-proto/gen/conversion.rs +++ b/crates/sakura-proto/gen/conversion.rs @@ -185,6 +185,14 @@ pub fn client_to_normal( proto.encode_to_vec().into_boxed_slice(), )) } + crate::client::AvatarChangeTraceEffectReq::CMD_ID => { + let proto = crate::client::AvatarChangeTraceEffectReq::decode(body)?; + let proto: crate::normal::AvatarChangeTraceEffectReq = proto.into(); + Ok(( + crate::normal::AvatarChangeTraceEffectReq::CMD_ID, + proto.encode_to_vec().into_boxed_slice(), + )) + } crate::client::QueryPathReq::CMD_ID => { let proto = crate::client::QueryPathReq::decode(body)?; let proto: crate::normal::QueryPathReq = proto.into(); @@ -289,6 +297,14 @@ pub fn client_to_normal( proto.encode_to_vec().into_boxed_slice(), )) } + crate::client::AvatarChangeTraceEffectRsp::CMD_ID => { + let proto = crate::client::AvatarChangeTraceEffectRsp::decode(body)?; + let proto: crate::normal::AvatarChangeTraceEffectRsp = proto.into(); + Ok(( + crate::normal::AvatarChangeTraceEffectRsp::CMD_ID, + proto.encode_to_vec().into_boxed_slice(), + )) + } crate::client::EnterScenePeerNotify::CMD_ID => { let proto = crate::client::EnterScenePeerNotify::decode(body)?; let proto: crate::normal::EnterScenePeerNotify = proto.into(); @@ -417,6 +433,14 @@ pub fn client_to_normal( proto.encode_to_vec().into_boxed_slice(), )) } + crate::client::AvatarChangeTraceEffectNotify::CMD_ID => { + let proto = crate::client::AvatarChangeTraceEffectNotify::decode(body)?; + let proto: crate::normal::AvatarChangeTraceEffectNotify = proto.into(); + Ok(( + crate::normal::AvatarChangeTraceEffectNotify::CMD_ID, + proto.encode_to_vec().into_boxed_slice(), + )) + } crate::client::AvatarFightPropUpdateNotify::CMD_ID => { let proto = crate::client::AvatarFightPropUpdateNotify::decode(body)?; let proto: crate::normal::AvatarFightPropUpdateNotify = proto.into(); @@ -799,6 +823,14 @@ pub fn normal_to_client( proto.encode_to_vec().into_boxed_slice(), )) } + crate::normal::AvatarChangeTraceEffectReq::CMD_ID => { + let proto = crate::normal::AvatarChangeTraceEffectReq::decode(body)?; + let proto: crate::client::AvatarChangeTraceEffectReq = proto.into(); + Ok(( + crate::client::AvatarChangeTraceEffectReq::CMD_ID, + proto.encode_to_vec().into_boxed_slice(), + )) + } crate::normal::QueryPathReq::CMD_ID => { let proto = crate::normal::QueryPathReq::decode(body)?; let proto: crate::client::QueryPathReq = proto.into(); @@ -903,6 +935,14 @@ pub fn normal_to_client( proto.encode_to_vec().into_boxed_slice(), )) } + crate::normal::AvatarChangeTraceEffectRsp::CMD_ID => { + let proto = crate::normal::AvatarChangeTraceEffectRsp::decode(body)?; + let proto: crate::client::AvatarChangeTraceEffectRsp = proto.into(); + Ok(( + crate::client::AvatarChangeTraceEffectRsp::CMD_ID, + proto.encode_to_vec().into_boxed_slice(), + )) + } crate::normal::EnterScenePeerNotify::CMD_ID => { let proto = crate::normal::EnterScenePeerNotify::decode(body)?; let proto: crate::client::EnterScenePeerNotify = proto.into(); @@ -1031,6 +1071,14 @@ pub fn normal_to_client( proto.encode_to_vec().into_boxed_slice(), )) } + crate::normal::AvatarChangeTraceEffectNotify::CMD_ID => { + let proto = crate::normal::AvatarChangeTraceEffectNotify::decode(body)?; + let proto: crate::client::AvatarChangeTraceEffectNotify = proto.into(); + Ok(( + crate::client::AvatarChangeTraceEffectNotify::CMD_ID, + proto.encode_to_vec().into_boxed_slice(), + )) + } crate::normal::AvatarFightPropUpdateNotify::CMD_ID => { let proto = crate::normal::AvatarFightPropUpdateNotify::decode(body)?; let proto: crate::client::AvatarFightPropUpdateNotify = proto.into(); diff --git a/crates/sakura-proto/gen/normal.rs b/crates/sakura-proto/gen/normal.rs index 9b752dd..e4cc2e8 100644 --- a/crates/sakura-proto/gen/normal.rs +++ b/crates/sakura-proto/gen/normal.rs @@ -11367,6 +11367,8 @@ pub struct AvatarDataNotify { pub cur_avatar_team_id: u32, #[prost(uint64, tag = "9")] pub choose_avatar_guid: u64, + #[prost(uint32, repeated, tag = "10")] + pub owned_trace_effect_list: ::prost::alloc::vec::Vec, } #[derive(sakura_proto_derive::CmdID)] #[cmdid(1608)] @@ -11936,6 +11938,33 @@ pub struct MirrorAvatarDataUpdateNotify { pub avatar_list: ::prost::alloc::vec::Vec, } #[derive(sakura_proto_derive::CmdID)] +#[cmdid(1733)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AvatarChangeTraceEffectNotify { + #[prost(message, optional, tag = "1")] + pub entity_info: ::core::option::Option, +} +#[derive(sakura_proto_derive::CmdID)] +#[cmdid(1734)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct AvatarChangeTraceEffectReq { + #[prost(uint64, tag = "1")] + pub avatar_guid: u64, + #[prost(uint32, tag = "2")] + pub trace_effect_id: u32, +} +#[derive(sakura_proto_derive::CmdID)] +#[cmdid(1735)] +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct AvatarChangeTraceEffectRsp { + #[prost(int32, tag = "1")] + pub retcode: i32, + #[prost(uint64, tag = "2")] + pub avatar_guid: u64, + #[prost(uint32, tag = "3")] + pub trace_effect_id: u32, +} +#[derive(sakura_proto_derive::CmdID)] #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct BattlePassCycle { #[prost(uint32, tag = "1")] @@ -35809,6 +35838,8 @@ pub struct SceneAvatarInfo { pub excel_info: ::core::option::Option, #[prost(uint32, tag = "21")] pub anim_hash: u32, + #[prost(uint32, tag = "22")] + pub trace_effect_id: u32, } #[derive(sakura_proto_derive::CmdID)] #[derive(Clone, Copy, PartialEq, ::prost::Message)] @@ -36784,6 +36815,8 @@ pub struct AvatarInfo { pub anim_hash: u32, #[prost(message, optional, tag = "27")] pub mirror_avatar_info: ::core::option::Option, + #[prost(uint32, tag = "31")] + pub trace_effect_id: u32, } #[derive(sakura_proto_derive::CmdID)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/crates/sakura-proto/gen/normal_to_client.rs b/crates/sakura-proto/gen/normal_to_client.rs index 260d27d..94b5865 100644 --- a/crates/sakura-proto/gen/normal_to_client.rs +++ b/crates/sakura-proto/gen/normal_to_client.rs @@ -436,6 +436,11 @@ impl From for AvatarDataNotify { .map(|v| v.into()) .collect(), choose_avatar_guid: value.choose_avatar_guid.into(), + owned_trace_effect_list: value + .owned_trace_effect_list + .into_iter() + .map(|v| v.into()) + .collect(), avatar_team_map: value .avatar_team_map .into_iter() @@ -579,6 +584,15 @@ for query_curr_region_http_rsp::Detail { } } } +impl From for AvatarChangeTraceEffectReq { + fn from(value: crate::normal::AvatarChangeTraceEffectReq) -> Self { + Self { + avatar_guid: value.avatar_guid.into(), + trace_effect_id: value.trace_effect_id.into(), + ..Default::default() + } + } +} impl From for QueryPathReq { fn from(value: crate::normal::QueryPathReq) -> Self { Self { @@ -1085,6 +1099,7 @@ impl From for AvatarInfo { excel_info: value.excel_info.map(|v| v.into()), anim_hash: value.anim_hash.into(), mirror_avatar_info: value.mirror_avatar_info.map(|v| v.into()), + trace_effect_id: value.trace_effect_id.into(), ..Default::default() } } @@ -1141,6 +1156,16 @@ impl From for scene_entity_info::Entit } } } +impl From for AvatarChangeTraceEffectRsp { + fn from(value: crate::normal::AvatarChangeTraceEffectRsp) -> Self { + Self { + trace_effect_id: value.trace_effect_id.into(), + retcode: value.retcode.into(), + avatar_guid: value.avatar_guid.into(), + ..Default::default() + } + } +} impl From for EnterScenePeerNotify { fn from(value: crate::normal::EnterScenePeerNotify) -> Self { Self { @@ -1733,6 +1758,15 @@ impl From for UnlockTransPointReq { } } } +impl From +for AvatarChangeTraceEffectNotify { + fn from(value: crate::normal::AvatarChangeTraceEffectNotify) -> Self { + Self { + entity_info: value.entity_info.map(|v| v.into()), + ..Default::default() + } + } +} impl From for AvatarFightPropUpdateNotify { fn from(value: crate::normal::AvatarFightPropUpdateNotify) -> Self { Self { @@ -2273,6 +2307,7 @@ impl From for SceneAvatarInfo { cur_vehicle_info: value.cur_vehicle_info.map(|v| v.into()), excel_info: value.excel_info.map(|v| v.into()), anim_hash: value.anim_hash.into(), + trace_effect_id: value.trace_effect_id.into(), ..Default::default() } } diff --git a/crates/sakura-scene/src/player_join_team.rs b/crates/sakura-scene/src/player_join_team.rs index 63fd331..6cb9cf1 100644 --- a/crates/sakura-scene/src/player_join_team.rs +++ b/crates/sakura-scene/src/player_join_team.rs @@ -95,6 +95,7 @@ pub fn player_join_team( appearance: AvatarAppearance { flycloak_id: to_spawn.wearing_flycloak_id, costume_id: to_spawn.costume_id, + trace_effect_id: to_spawn.trace_effect_id, }, transform: Transform { position: player_info.world_position.position.into(), diff --git a/crates/sakura-scene/src/scene_team_update.rs b/crates/sakura-scene/src/scene_team_update.rs index 3e71e3b..dab1b55 100644 --- a/crates/sakura-scene/src/scene_team_update.rs +++ b/crates/sakura-scene/src/scene_team_update.rs @@ -134,6 +134,7 @@ pub fn notify_scene_team_update( wearing_flycloak_id: avatar_data.appearance.flycloak_id, born_time: avatar_data.born_time.0, costume_id: avatar_data.appearance.costume_id, + trace_effect_id: avatar_data.appearance.trace_effect_id, cur_vehicle_info: None, excel_info: Some(AvatarExcelInfo::default()), anim_hash: 0,