Implement avatar trace effect change (Echo)

This commit is contained in:
xeon 2024-11-04 01:04:18 +03:00
parent 4fb5d000fd
commit 8dde0c8705
17 changed files with 352 additions and 45 deletions

View file

@ -0,0 +1 @@
Ù<7F> ƒ­âÙ<> ,Eff_Avatar_Lady_Sword_Qin_CharMaster_00_Blow-Eff_Avatar_Lady_Sword_Qin_CharMaster_00_WorldøœÖÞîøœÅÚ<7F> £­âÚ<> -Eff_Avatar_Loli_Sword_Qiqi_CharMaster_00_Blow.Eff_Avatar_Loli_Sword_Qiqi_CharMaster_00_World€Îȹ<>ò™ Û<7F> ›­âÛ<> 5Eff_Avatar_Lady_Catalyst_Ningguang_CharMaster_00_Blow6Eff_Avatar_Lady_Catalyst_Ningguang_CharMaster_00_World˜Ä™«ÖÞͶ Ü<7F> ½­âÜ<> /Eff_Avatar_Girl_Sword_Momoka_CharMaster_00_Blow0Eff_Avatar_Girl_Sword_Momoka_CharMaster_00_WorldÐÚ¹·ŽøƒÄÝ<7F> <0A>­âÝ<> 1Eff_Avatar_Male_Claymore_Diluc_CharMaster_00_Blow2Eff_Avatar_Male_Claymore_Diluc_CharMaster_00_WorldÐÆÈÆ Þè²ÔÞ<7F> ž­âÞ<> /Eff_Avatar_Male_Pole_Zhongli_CharMaster_00_Blow0Eff_Avatar_Male_Pole_Zhongli_CharMaster_00_World¨åø¼öèÎË ß<7F> ª­âß<> /Eff_Avatar_Girl_Sword_Keqing_CharMaster_00_Blow0Eff_Avatar_Girl_Sword_Keqing_CharMaster_00_Worldˆ´Ã…¦ÚÑó

View file

@ -117,6 +117,8 @@ pub fn sync_avatar_data(players: Res<Players>, out: Res<MessageOutput>) {
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<Players>, out: Res<MessageOutput>) {
.iter()
.copied()
.collect(),
owned_trace_effect_list: player_info
.avatar_module
.owned_trace_effect_set
.iter()
.copied()
.collect(),
..Default::default()
},
);

View file

@ -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,
},
);

View file

@ -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<ClientMessageEvent>,
mut players: ResMut<Players>,
message_output: Res<MessageOutput>,
mut costume_change_events: EventWriter<AvatarCostumeChangeEvent>,
mut change_events: EventWriter<AvatarAppearanceChangeEvent>,
) {
for message in events.read() {
if let Some(request) = message.decode::<AvatarWearFlycloakReq>() {
@ -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::<AvatarChangeTraceEffectReq>() {
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<AvatarCostumeChangeEvent> {
) -> Option<AvatarAppearanceChangeEvent> {
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<AvatarAppearanceChangeEvent> {
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),
})
}

View file

@ -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<String>,
pub name_text_map_hash: u32,
pub desc_text_map_hash: u32,
}

View file

@ -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;

View file

@ -79,6 +79,7 @@ mod tests {
excel_test!(
AvatarExcelConfig,
AvatarTraceEffectExcelConfig,
AvatarCostumeExcelConfig,
AvatarFlycloakExcelConfig,
AvatarSkillDepotExcelConfig,

View file

@ -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<AvatarCostumeChangeEvent>,
mut events: EventReader<AvatarAppearanceChangeEvent>,
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<AvatarCostumeChangeEvent>,
pub fn notify_avatar_appearance_change(
mut events: EventReader<AvatarAppearanceChangeEvent>,
avatars: Query<AvatarQueryReadOnly>,
weapons: Query<WeaponQueryReadOnly>,
message_output: Res<MessageOutput>,
players: Res<Players>,
) {
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,

View file

@ -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::<AvatarEquipChangeEvent>()
.add_event::<AvatarCostumeChangeEvent>()
.add_event::<AvatarAppearanceChangeEvent>()
.add_event::<EntityDisappearEvent>()
.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

View file

@ -35,6 +35,7 @@ pub struct AvatarModuleInformation {
pub team_map: HashMap<u32, AvatarTeamInformation>,
pub owned_flycloak_set: HashSet<u32>,
pub owned_costume_set: HashSet<u32>,
pub owned_trace_effect_set: HashSet<u32>,
}
#[derive(Serialize, Deserialize)]
@ -57,6 +58,7 @@ pub struct AvatarInformation {
pub inherent_proud_skill_list: Vec<u32>,
pub wearing_flycloak_id: u32,
pub costume_id: u32,
pub trace_effect_id: u32,
}
#[derive(Serialize, Deserialize)]

View file

@ -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)]

View file

@ -436,6 +436,11 @@ impl From<crate::client::AvatarDataNotify> 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<crate::client::AvatarChangeTraceEffectReq> 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<crate::client::QueryPathReq> for QueryPathReq {
fn from(value: crate::client::QueryPathReq) -> Self {
Self {
@ -1085,6 +1099,7 @@ impl From<crate::client::AvatarInfo> 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<crate::client::scene_entity_info::Entity> for scene_entity_info::Entit
}
}
}
impl From<crate::client::AvatarChangeTraceEffectRsp> 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<crate::client::EnterScenePeerNotify> for EnterScenePeerNotify {
fn from(value: crate::client::EnterScenePeerNotify) -> Self {
Self {
@ -1733,6 +1758,15 @@ impl From<crate::client::UnlockTransPointReq> for UnlockTransPointReq {
}
}
}
impl From<crate::client::AvatarChangeTraceEffectNotify>
for AvatarChangeTraceEffectNotify {
fn from(value: crate::client::AvatarChangeTraceEffectNotify) -> Self {
Self {
entity_info: value.entity_info.map(|v| v.into()),
..Default::default()
}
}
}
impl From<crate::client::AvatarFightPropUpdateNotify> for AvatarFightPropUpdateNotify {
fn from(value: crate::client::AvatarFightPropUpdateNotify) -> Self {
Self {
@ -2273,6 +2307,7 @@ impl From<crate::client::SceneAvatarInfo> 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()
}
}

View file

@ -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();

View file

@ -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<u32>,
}
#[derive(sakura_proto_derive::CmdID)]
#[cmdid(1608)]
@ -11936,6 +11938,33 @@ pub struct MirrorAvatarDataUpdateNotify {
pub avatar_list: ::prost::alloc::vec::Vec<AvatarInfo>,
}
#[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<SceneEntityInfo>,
}
#[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<AvatarExcelInfo>,
#[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<MirrorAvatarInfo>,
#[prost(uint32, tag = "31")]
pub trace_effect_id: u32,
}
#[derive(sakura_proto_derive::CmdID)]
#[derive(Clone, PartialEq, ::prost::Message)]

View file

@ -436,6 +436,11 @@ impl From<crate::normal::AvatarDataNotify> 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<crate::normal::AvatarChangeTraceEffectReq> 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<crate::normal::QueryPathReq> for QueryPathReq {
fn from(value: crate::normal::QueryPathReq) -> Self {
Self {
@ -1085,6 +1099,7 @@ impl From<crate::normal::AvatarInfo> 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<crate::normal::scene_entity_info::Entity> for scene_entity_info::Entit
}
}
}
impl From<crate::normal::AvatarChangeTraceEffectRsp> 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<crate::normal::EnterScenePeerNotify> for EnterScenePeerNotify {
fn from(value: crate::normal::EnterScenePeerNotify) -> Self {
Self {
@ -1733,6 +1758,15 @@ impl From<crate::normal::UnlockTransPointReq> for UnlockTransPointReq {
}
}
}
impl From<crate::normal::AvatarChangeTraceEffectNotify>
for AvatarChangeTraceEffectNotify {
fn from(value: crate::normal::AvatarChangeTraceEffectNotify) -> Self {
Self {
entity_info: value.entity_info.map(|v| v.into()),
..Default::default()
}
}
}
impl From<crate::normal::AvatarFightPropUpdateNotify> for AvatarFightPropUpdateNotify {
fn from(value: crate::normal::AvatarFightPropUpdateNotify) -> Self {
Self {
@ -2273,6 +2307,7 @@ impl From<crate::normal::SceneAvatarInfo> 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()
}
}

View file

@ -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(),

View file

@ -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,