Implement avatar costume change
This commit is contained in:
parent
005f4413af
commit
4fb5d000fd
25 changed files with 622 additions and 154 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1855,6 +1855,7 @@ dependencies = [
|
|||
"common",
|
||||
"sakura-data",
|
||||
"sakura-message",
|
||||
"sakura-persistence",
|
||||
"sakura-proto",
|
||||
"tracing",
|
||||
]
|
||||
|
|
BIN
assets/ExcelBinOutput/AvatarCostumeExcelConfigData
Normal file
BIN
assets/ExcelBinOutput/AvatarCostumeExcelConfigData
Normal file
Binary file not shown.
|
@ -1,5 +1,6 @@
|
|||
use sakura_message::output::ClientOutput;
|
||||
use sakura_persistence::player_information::PlayerInformation;
|
||||
use sakura_proto::PacketHead;
|
||||
|
||||
pub enum LogicCommand {
|
||||
CreateWorld {
|
||||
|
@ -7,7 +8,7 @@ pub enum LogicCommand {
|
|||
output: ClientOutput,
|
||||
},
|
||||
ClientInput {
|
||||
uid: u32,
|
||||
head: PacketHead,
|
||||
cmd_id: u16,
|
||||
data: Box<[u8]>,
|
||||
immediate_mode: bool,
|
||||
|
|
|
@ -161,6 +161,12 @@ pub fn sync_avatar_data(players: Res<Players>, out: Res<MessageOutput>) {
|
|||
.iter()
|
||||
.copied()
|
||||
.collect(),
|
||||
owned_costume_list: player_info
|
||||
.avatar_module
|
||||
.owned_costume_set
|
||||
.iter()
|
||||
.copied()
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
|
|
@ -15,7 +15,7 @@ use sakura_message::{
|
|||
};
|
||||
use sakura_pathfinding::PathfindingPlugin;
|
||||
use sakura_persistence::{player_information::PlayerInformation, Players};
|
||||
use sakura_proto::PlayerLoginRsp;
|
||||
use sakura_proto::{PacketHead, PlayerLoginRsp};
|
||||
use sakura_scene::{common::WorldOwnerUID, ScenePlugin};
|
||||
use sakura_time::TimePlugin;
|
||||
use tracing::debug;
|
||||
|
@ -64,16 +64,20 @@ impl PlayerWorld {
|
|||
app.cleanup();
|
||||
app.update();
|
||||
|
||||
output.push(PlayerLoginRsp::default());
|
||||
output.push(
|
||||
sakura_proto::PacketHead::default(),
|
||||
PlayerLoginRsp::default(),
|
||||
);
|
||||
|
||||
debug!("created world for player: {uid}");
|
||||
|
||||
Self(app)
|
||||
}
|
||||
|
||||
pub fn add_packet(&mut self, player_uid: u32, cmd_id: u16, data: Box<[u8]>) {
|
||||
pub fn add_packet(&mut self, head: PacketHead, cmd_id: u16, data: Box<[u8]>) {
|
||||
self.0
|
||||
.world_mut()
|
||||
.send_event(ClientMessageEvent::new(player_uid, cmd_id, data));
|
||||
.send_event(ClientMessageEvent::new(head, cmd_id, data));
|
||||
}
|
||||
|
||||
pub fn update(&mut self) {
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::{command::LogicCommand, player_world::PlayerWorld};
|
|||
use common::time_util;
|
||||
use sakura_message::output::ClientOutput;
|
||||
use sakura_persistence::player_information::PlayerInformation;
|
||||
use sakura_proto::PacketHead;
|
||||
use std::sync::mpsc;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -28,14 +29,14 @@ impl LogicSimulator {
|
|||
|
||||
pub fn add_client_packet(
|
||||
&self,
|
||||
player_uid: u32,
|
||||
head: PacketHead,
|
||||
cmd_id: u16,
|
||||
data: Box<[u8]>,
|
||||
immediate_mode: bool,
|
||||
) {
|
||||
self.0
|
||||
.send(LogicCommand::ClientInput {
|
||||
uid: player_uid,
|
||||
head,
|
||||
cmd_id,
|
||||
data,
|
||||
immediate_mode,
|
||||
|
@ -72,14 +73,15 @@ fn simulation_loop(
|
|||
);
|
||||
}
|
||||
ClientInput {
|
||||
uid,
|
||||
head,
|
||||
cmd_id,
|
||||
data,
|
||||
immediate_mode,
|
||||
} => {
|
||||
let uid = head.user_id;
|
||||
if let Some(world_owner_uid) = player_uid_map.get(&uid) {
|
||||
if let Some(world) = player_world_map.get_mut(world_owner_uid) {
|
||||
world.add_packet(uid, cmd_id, data);
|
||||
world.add_packet(head, cmd_id, data);
|
||||
if immediate_mode {
|
||||
world.update();
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ pub async fn on_message(state: &'static AppState, data: Box<[u8]>) {
|
|||
);
|
||||
|
||||
state.logic_simulator.add_client_packet(
|
||||
packet.head.user_id,
|
||||
packet.head.clone(),
|
||||
sub_cmd.message_id as u16,
|
||||
sub_cmd.body.into(),
|
||||
false,
|
||||
|
@ -67,7 +67,7 @@ pub async fn on_message(state: &'static AppState, data: Box<[u8]>) {
|
|||
cmd_id => {
|
||||
debug!("received packet with cmd_id: {cmd_id}");
|
||||
state.logic_simulator.add_client_packet(
|
||||
packet.head().user_id,
|
||||
packet.head(),
|
||||
cmd_id,
|
||||
packet.body().into(),
|
||||
true,
|
||||
|
@ -99,9 +99,9 @@ async fn packet_sink(
|
|||
state: &'static AppState,
|
||||
user_id: u32,
|
||||
user_session_id: u32,
|
||||
mut rx: mpsc::Receiver<(u16, Box<[u8]>)>,
|
||||
mut rx: mpsc::Receiver<(u16, PacketHead, Box<[u8]>)>,
|
||||
) {
|
||||
while let Some((cmd_id, body)) = rx.recv().await {
|
||||
while let Some((cmd_id, head, body)) = rx.recv().await {
|
||||
state
|
||||
.gate_server_socket
|
||||
.send(make_raw_packet(
|
||||
|
@ -109,7 +109,7 @@ async fn packet_sink(
|
|||
PacketHead {
|
||||
user_id,
|
||||
user_session_id,
|
||||
..Default::default()
|
||||
..head
|
||||
},
|
||||
&body,
|
||||
))
|
||||
|
|
|
@ -2,9 +2,9 @@ use std::collections::HashMap;
|
|||
|
||||
use common::time_util;
|
||||
use sakura_data::excel::{
|
||||
avatar_excel_config_collection, avatar_flycloak_excel_config_collection,
|
||||
avatar_skill_depot_excel_config_collection, weapon_excel_config_collection, AvatarExcelConfig,
|
||||
AvatarUseType,
|
||||
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,
|
||||
};
|
||||
|
||||
use sakura_persistence::player_information::*;
|
||||
|
@ -28,6 +28,10 @@ pub fn create_default_player_information(uid: u32, nick_name: String) -> PlayerI
|
|||
owned_flycloak_set: avatar_flycloak_excel_config_collection::iter()
|
||||
.map(|c| c.flycloak_id)
|
||||
.collect(),
|
||||
owned_costume_set: avatar_costume_excel_config_collection::iter()
|
||||
.filter(|c| !c.is_default)
|
||||
.map(|c| c.skin_id)
|
||||
.collect(),
|
||||
},
|
||||
item_map: HashMap::new(),
|
||||
world_position: PlayerPositionInformation {
|
||||
|
@ -129,6 +133,7 @@ fn add_avatar_and_weapon(player: &mut PlayerInformation, avatar: &AvatarExcelCon
|
|||
skill_level_map,
|
||||
inherent_proud_skill_list,
|
||||
wearing_flycloak_id: DEFAULT_FLYCLOAK_ID,
|
||||
costume_id: 0,
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
@ -96,6 +96,7 @@ async fn handle_packet(
|
|||
debug!("received packet: {}", hex::encode(&data));
|
||||
|
||||
let packet = RawPacket::new(&data)?;
|
||||
let head = packet.head();
|
||||
let (cmd_id, body) = packet::client_to_normal(packet.cmd_id(), packet.body())?;
|
||||
|
||||
match cmd_id {
|
||||
|
@ -161,7 +162,7 @@ async fn handle_packet(
|
|||
PacketHead {
|
||||
user_session_id: session.connection.conv,
|
||||
user_id: session.player_uid.get().copied().unwrap_or_default(),
|
||||
..Default::default()
|
||||
..head
|
||||
},
|
||||
&body,
|
||||
))
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use sakura_proto::{
|
||||
packet::normal_to_client,
|
||||
raw_packet::{make_raw_packet, RawPacket},
|
||||
PacketHead,
|
||||
};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
|
@ -14,12 +13,13 @@ pub async fn on_message(state: &'static AppState, data: Box<[u8]>) {
|
|||
return;
|
||||
};
|
||||
|
||||
let session_id = packet.head().user_session_id;
|
||||
let head = packet.head();
|
||||
let session_id = head.user_session_id;
|
||||
|
||||
if let Some(session) = state.sessions.get(&session_id) {
|
||||
match normal_to_client(packet.cmd_id(), packet.body()) {
|
||||
Ok((cmd_id, data)) => {
|
||||
let mut data = make_raw_packet(cmd_id, PacketHead::default(), &data);
|
||||
let mut data = make_raw_packet(cmd_id, head, &data);
|
||||
util::xor_packet(
|
||||
session.xorpad.get(),
|
||||
state.initial_xorpad.as_ref(),
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
use bevy_ecs::prelude::*;
|
||||
use sakura_data::excel::avatar_costume_excel_config_collection;
|
||||
use sakura_entity::avatar::AvatarCostumeChangeEvent;
|
||||
use sakura_message::{event::ClientMessageEvent, output::MessageOutput};
|
||||
use sakura_persistence::Players;
|
||||
use sakura_persistence::{player_information::PlayerInformation, Players};
|
||||
use sakura_proto::{
|
||||
AvatarFlycloakChangeNotify, AvatarWearFlycloakReq, AvatarWearFlycloakRsp, Retcode,
|
||||
AvatarChangeCostumeReq, AvatarChangeCostumeRsp, AvatarFlycloakChangeNotify,
|
||||
AvatarWearFlycloakReq, AvatarWearFlycloakRsp, Retcode,
|
||||
};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
|
@ -11,45 +14,135 @@ pub fn handle_appearance_change_request(
|
|||
mut events: EventReader<ClientMessageEvent>,
|
||||
mut players: ResMut<Players>,
|
||||
message_output: Res<MessageOutput>,
|
||||
mut costume_change_events: EventWriter<AvatarCostumeChangeEvent>,
|
||||
) {
|
||||
for message in events.read() {
|
||||
if let Some(request) = message.decode::<AvatarWearFlycloakReq>() {
|
||||
let player = players.get_mut(message.sender_uid());
|
||||
|
||||
let mut rsp = AvatarWearFlycloakRsp::default();
|
||||
if player
|
||||
.avatar_module
|
||||
.owned_flycloak_set
|
||||
.contains(&request.flycloak_id)
|
||||
{
|
||||
if let Some(avatar) = player
|
||||
.avatar_module
|
||||
.avatar_map
|
||||
.get_mut(&request.avatar_guid)
|
||||
{
|
||||
rsp.avatar_guid = request.avatar_guid;
|
||||
rsp.flycloak_id = request.flycloak_id;
|
||||
|
||||
avatar.wearing_flycloak_id = request.flycloak_id;
|
||||
debug!(
|
||||
"wear flycloak_id: {}, avatar_guid: {}",
|
||||
request.flycloak_id, request.avatar_guid
|
||||
);
|
||||
if let Some(notify) = wear_flycloak(player, request, &mut rsp) {
|
||||
message_output.send_to_all(notify);
|
||||
}
|
||||
|
||||
message_output.send_to_all(AvatarFlycloakChangeNotify {
|
||||
avatar_guid: request.avatar_guid,
|
||||
flycloak_id: request.flycloak_id,
|
||||
});
|
||||
} else {
|
||||
debug!("avatar with guid {} not found", request.avatar_guid);
|
||||
rsp.retcode = Retcode::RetCanNotFindAvatar.into();
|
||||
}
|
||||
} else {
|
||||
debug!("flycloak id {} is not owned", request.flycloak_id);
|
||||
rsp.retcode = Retcode::RetNotHasFlycloak.into();
|
||||
message_output.send(message.sender_uid(), rsp);
|
||||
} else if let Some(request) = message.decode::<AvatarChangeCostumeReq>() {
|
||||
let player = players.get_mut(message.sender_uid());
|
||||
let mut rsp = AvatarChangeCostumeRsp::default();
|
||||
|
||||
if let Some(change_event) = change_costume(player, request, &mut rsp) {
|
||||
costume_change_events.send(change_event);
|
||||
}
|
||||
|
||||
message_output.send(message.sender_uid(), rsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(player, response))]
|
||||
fn wear_flycloak(
|
||||
player: &mut PlayerInformation,
|
||||
request: AvatarWearFlycloakReq,
|
||||
response: &mut AvatarWearFlycloakRsp,
|
||||
) -> Option<AvatarFlycloakChangeNotify> {
|
||||
if !player
|
||||
.avatar_module
|
||||
.owned_flycloak_set
|
||||
.contains(&request.flycloak_id)
|
||||
{
|
||||
debug!("flycloak id {} is not owned", request.flycloak_id);
|
||||
response.retcode = Retcode::RetNotHasFlycloak.into();
|
||||
return None;
|
||||
}
|
||||
|
||||
let Some(avatar) = player
|
||||
.avatar_module
|
||||
.avatar_map
|
||||
.get_mut(&request.avatar_guid)
|
||||
else {
|
||||
debug!("avatar with guid {} not found", request.avatar_guid);
|
||||
response.retcode = Retcode::RetCanNotFindAvatar.into();
|
||||
return None;
|
||||
};
|
||||
|
||||
response.avatar_guid = request.avatar_guid;
|
||||
response.flycloak_id = request.flycloak_id;
|
||||
|
||||
avatar.wearing_flycloak_id = request.flycloak_id;
|
||||
debug!(
|
||||
"wear flycloak_id: {}, avatar_guid: {}",
|
||||
request.flycloak_id, request.avatar_guid
|
||||
);
|
||||
|
||||
Some(AvatarFlycloakChangeNotify {
|
||||
avatar_guid: request.avatar_guid,
|
||||
flycloak_id: request.flycloak_id,
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(skip(player, response))]
|
||||
fn change_costume(
|
||||
player: &mut PlayerInformation,
|
||||
request: AvatarChangeCostumeReq,
|
||||
response: &mut AvatarChangeCostumeRsp,
|
||||
) -> Option<AvatarCostumeChangeEvent> {
|
||||
response.retcode = Retcode::RetFail.into();
|
||||
|
||||
let config = (request.costume_id != 0)
|
||||
.then(|| {
|
||||
avatar_costume_excel_config_collection::iter().find(|c| c.skin_id == request.costume_id)
|
||||
})
|
||||
.flatten();
|
||||
|
||||
if request.costume_id != 0 && config.is_none() {
|
||||
debug!("costume_id {} config doesn't exist", request.costume_id);
|
||||
return None;
|
||||
};
|
||||
|
||||
if !player
|
||||
.avatar_module
|
||||
.owned_costume_set
|
||||
.contains(&request.costume_id)
|
||||
&& config.is_some()
|
||||
{
|
||||
debug!("costume is not unlocked, id: {}", request.costume_id);
|
||||
response.retcode = Retcode::RetNotHasCostume.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.character_id != avatar.avatar_id {
|
||||
debug!(
|
||||
"avatar costume mismatch, config: {}, requested: {}",
|
||||
config.character_id, avatar.avatar_id
|
||||
);
|
||||
response.retcode = Retcode::RetCostumeAvatarError.into();
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
response.avatar_guid = request.avatar_guid;
|
||||
response.costume_id = request.costume_id;
|
||||
response.retcode = Retcode::RetSucc.into();
|
||||
avatar.costume_id = request.costume_id;
|
||||
|
||||
debug!(
|
||||
"change costume for avatar {} to {}",
|
||||
avatar.avatar_id, request.costume_id
|
||||
);
|
||||
|
||||
Some(AvatarCostumeChangeEvent(
|
||||
player.uid,
|
||||
request.avatar_guid,
|
||||
request.costume_id,
|
||||
))
|
||||
}
|
||||
|
|
31
crates/sakura-data/src/excel/avatar_costume_excel_config.rs
Normal file
31
crates/sakura-data/src/excel/avatar_costume_excel_config.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
use sakura_data_derive::FromBinary;
|
||||
|
||||
#[derive(Debug, FromBinary)]
|
||||
pub struct AvatarCostumeExcelConfig {
|
||||
pub skin_id: u32,
|
||||
pub index_id: u32,
|
||||
pub name: u32,
|
||||
pub desc: u32,
|
||||
pub item_id: u32,
|
||||
pub character_id: u32,
|
||||
pub json_name: String,
|
||||
pub prefab_path_hash: u64,
|
||||
pub prefab_remote_path_hash: u64,
|
||||
pub prefab_npc_path_hash: u64,
|
||||
pub animator_config_path_hash: u64,
|
||||
pub prefab_manekin_path_hash: u64,
|
||||
pub unk_1: u64,
|
||||
pub controller_path_hash: u64,
|
||||
pub controller_remote_path_hash: u64,
|
||||
pub is_default: bool,
|
||||
pub is_default_unlock: bool,
|
||||
pub quality: u32,
|
||||
pub hide: bool,
|
||||
pub front_icon_name: String,
|
||||
pub side_icon_name: String,
|
||||
pub image_name_hash: u64,
|
||||
pub domestic_hide_in_art_preview: bool,
|
||||
pub oversea_hide_in_art_preview: bool,
|
||||
pub unk_2: u64,
|
||||
pub unk_3: u64,
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
mod avatar_costume_excel_config;
|
||||
mod avatar_curve_excel_config;
|
||||
mod avatar_excel_config;
|
||||
mod avatar_flycloak_excel_config;
|
||||
|
@ -11,6 +12,7 @@ mod weapon_curve_excel_config;
|
|||
mod weapon_excel_config;
|
||||
|
||||
pub mod common;
|
||||
pub use avatar_costume_excel_config::*;
|
||||
pub use avatar_curve_excel_config::*;
|
||||
pub use avatar_excel_config::*;
|
||||
pub use avatar_flycloak_excel_config::*;
|
||||
|
@ -65,6 +67,7 @@ macro_rules! excel_loader {
|
|||
|
||||
excel_loader! {
|
||||
AvatarExcelConfig;
|
||||
AvatarCostumeExcelConfig;
|
||||
AvatarFlycloakExcelConfig;
|
||||
AvatarSkillDepotExcelConfig;
|
||||
AvatarCurveExcelConfig;
|
||||
|
|
|
@ -79,6 +79,7 @@ mod tests {
|
|||
|
||||
excel_test!(
|
||||
AvatarExcelConfig,
|
||||
AvatarCostumeExcelConfig,
|
||||
AvatarFlycloakExcelConfig,
|
||||
AvatarSkillDepotExcelConfig,
|
||||
AvatarPromoteExcelConfig,
|
||||
|
|
|
@ -11,5 +11,6 @@ tracing.workspace = true
|
|||
|
||||
common.workspace = true
|
||||
sakura-data.workspace = true
|
||||
sakura-persistence.workspace = true
|
||||
sakura-message.workspace = true
|
||||
sakura-proto.workspace = true
|
||||
|
|
|
@ -2,8 +2,17 @@ use std::collections::HashMap;
|
|||
|
||||
use bevy_ecs::{prelude::*, query::QueryData};
|
||||
use sakura_message::output::MessageOutput;
|
||||
use sakura_persistence::{
|
||||
player_information::{AvatarInformation, ItemInformation},
|
||||
Players,
|
||||
};
|
||||
use sakura_proto::{AvatarChangeCostumeNotify, SceneEntityInfo};
|
||||
|
||||
use crate::{int_prop_pair, transform::Transform, weapon::WeaponQueryReadOnly};
|
||||
use crate::{
|
||||
int_prop_pair,
|
||||
transform::Transform,
|
||||
weapon::{WeaponQueryReadOnly, WeaponQueryReadOnlyItem},
|
||||
};
|
||||
|
||||
use super::{ability::Ability, common::*};
|
||||
|
||||
|
@ -25,6 +34,9 @@ pub struct AvatarEquipChangeEvent {
|
|||
pub weapon_guid: u64,
|
||||
}
|
||||
|
||||
#[derive(Event)]
|
||||
pub struct AvatarCostumeChangeEvent(pub u32, pub u64, pub u32);
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct AvatarID(pub u32);
|
||||
|
||||
|
@ -93,6 +105,52 @@ pub struct AvatarQueryReadOnly {
|
|||
pub inherent_proud_skill_list: &'static InherentProudSkillList,
|
||||
}
|
||||
|
||||
pub fn update_avatar_appearance(
|
||||
mut events: EventReader<AvatarCostumeChangeEvent>,
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn notify_avatar_costume_change(
|
||||
mut events: EventReader<AvatarCostumeChangeEvent>,
|
||||
avatars: Query<AvatarQueryReadOnly>,
|
||||
weapons: Query<WeaponQueryReadOnly>,
|
||||
message_output: Res<MessageOutput>,
|
||||
players: Res<Players>,
|
||||
) {
|
||||
for AvatarCostumeChangeEvent(player_uid, guid, _) in events.read() {
|
||||
if let Some(avatar_data) = avatars
|
||||
.iter()
|
||||
.find(|avatar_data| avatar_data.guid.0 == *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)),
|
||||
});
|
||||
}
|
||||
// that's disgusting, this packet required even if avatar is not on scene
|
||||
// even though it contains SceneEntityInfo
|
||||
else {
|
||||
let player = players.get(*player_uid);
|
||||
|
||||
let avatar = player.avatar_module.avatar_map.get(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)),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn notify_appear_avatar_entities(
|
||||
appear_avatars: Query<AvatarQueryReadOnly, (Added<Visible>, Without<ToBeRemovedMarker>)>,
|
||||
weapons: Query<WeaponQueryReadOnly>,
|
||||
|
@ -107,83 +165,7 @@ pub fn notify_appear_avatar_entities(
|
|||
.iter()
|
||||
.map(|avatar_data| {
|
||||
let weapon_data = weapons.get(avatar_data.equipment.weapon).unwrap();
|
||||
|
||||
SceneEntityInfo {
|
||||
entity_type: ProtEntityType::Avatar.into(),
|
||||
entity_id: avatar_data.entity_id.0,
|
||||
name: String::new(),
|
||||
motion_info: Some(MotionInfo {
|
||||
pos: Some(avatar_data.transform.position.into()),
|
||||
rot: Some(avatar_data.transform.rotation.into()),
|
||||
speed: Some(Vector::default()),
|
||||
..Default::default()
|
||||
}),
|
||||
prop_list: vec![
|
||||
int_prop_pair!(PROP_LEVEL, avatar_data.level.0),
|
||||
int_prop_pair!(PROP_BREAK_LEVEL, avatar_data.break_level.0),
|
||||
],
|
||||
fight_prop_list: avatar_data
|
||||
.fight_properties
|
||||
.0
|
||||
.iter()
|
||||
.map(|(k, v)| FightPropPair {
|
||||
prop_type: *k as u32,
|
||||
prop_value: *v,
|
||||
})
|
||||
.collect(),
|
||||
life_state: *avatar_data.life_state as u32,
|
||||
animator_para_list: vec![AnimatorParameterValueInfoPair {
|
||||
name_id: 0,
|
||||
animator_para: Some(AnimatorParameterValueInfo::default()),
|
||||
}],
|
||||
last_move_scene_time_ms: 0,
|
||||
last_move_reliable_seq: 0,
|
||||
entity_client_data: Some(EntityClientData::default()),
|
||||
entity_environment_info_list: Vec::with_capacity(0),
|
||||
entity_authority_info: Some(EntityAuthorityInfo {
|
||||
ability_info: Some(AbilitySyncStateInfo::default()),
|
||||
born_pos: Some(Vector::default()),
|
||||
client_extra_info: Some(EntityClientExtraInfo {
|
||||
skill_anchor_position: Some(Vector::default()),
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
tag_list: Vec::with_capacity(0),
|
||||
server_buff_list: Vec::with_capacity(0),
|
||||
entity: Some(scene_entity_info::Entity::Avatar(SceneAvatarInfo {
|
||||
uid: avatar_data.owner_player_uid.0,
|
||||
avatar_id: avatar_data.avatar_id.0,
|
||||
guid: avatar_data.guid.0,
|
||||
peer_id: avatar_data.control_peer.0,
|
||||
equip_id_list: vec![weapon_data.weapon_id.0],
|
||||
skill_depot_id: avatar_data.skill_depot.0,
|
||||
talent_id_list: vec![],
|
||||
weapon: Some(SceneWeaponInfo {
|
||||
guid: weapon_data.guid.0,
|
||||
entity_id: weapon_data.entity_id.0,
|
||||
gadget_id: weapon_data.gadget_id.0,
|
||||
item_id: weapon_data.weapon_id.0,
|
||||
level: weapon_data.level.0,
|
||||
promote_level: weapon_data.promote_level.0,
|
||||
affix_map: weapon_data.affix_map.0.clone(),
|
||||
ability_info: Some(AbilitySyncStateInfo::default()),
|
||||
renderer_changed_info: Some(EntityRendererChangedInfo::default()),
|
||||
}),
|
||||
reliquary_list: Vec::with_capacity(0),
|
||||
core_proud_skill_level: 0,
|
||||
inherent_proud_skill_list: avatar_data.inherent_proud_skill_list.0.clone(),
|
||||
skill_level_map: avatar_data.skill_level_map.0.clone(),
|
||||
proud_skill_extra_level_map: HashMap::with_capacity(0),
|
||||
server_buff_list: Vec::with_capacity(0),
|
||||
team_resonance_list: Vec::with_capacity(0),
|
||||
wearing_flycloak_id: avatar_data.appearance.flycloak_id,
|
||||
born_time: avatar_data.born_time.0,
|
||||
costume_id: avatar_data.appearance.costume_id,
|
||||
cur_vehicle_info: None,
|
||||
excel_info: Some(AvatarExcelInfo::default()),
|
||||
anim_hash: 0,
|
||||
})),
|
||||
}
|
||||
build_avatar_entity_info(&avatar_data, &weapon_data)
|
||||
})
|
||||
.collect(),
|
||||
});
|
||||
|
@ -194,3 +176,138 @@ pub fn run_if_avatar_entities_appeared(
|
|||
) -> bool {
|
||||
!appear_avatars.is_empty()
|
||||
}
|
||||
|
||||
fn build_fake_avatar_entity_info(
|
||||
avatar: &AvatarInformation,
|
||||
weapon: &ItemInformation,
|
||||
) -> SceneEntityInfo {
|
||||
use sakura_proto::*;
|
||||
|
||||
let ItemInformation::Weapon {
|
||||
weapon_id,
|
||||
level,
|
||||
promote_level,
|
||||
affix_map,
|
||||
..
|
||||
} = weapon;
|
||||
|
||||
SceneEntityInfo {
|
||||
entity_type: ProtEntityType::Avatar.into(),
|
||||
entity_id: 0,
|
||||
entity: Some(scene_entity_info::Entity::Avatar(SceneAvatarInfo {
|
||||
uid: (avatar.guid >> 32) as u32,
|
||||
avatar_id: avatar.avatar_id,
|
||||
guid: avatar.guid,
|
||||
equip_id_list: vec![*weapon_id],
|
||||
skill_depot_id: avatar.skill_depot_id,
|
||||
talent_id_list: vec![],
|
||||
weapon: Some(SceneWeaponInfo {
|
||||
guid: avatar.weapon_guid,
|
||||
item_id: *weapon_id,
|
||||
level: *level,
|
||||
promote_level: *promote_level,
|
||||
affix_map: affix_map.clone(),
|
||||
..Default::default()
|
||||
}),
|
||||
reliquary_list: Vec::with_capacity(0),
|
||||
core_proud_skill_level: 0,
|
||||
inherent_proud_skill_list: avatar.inherent_proud_skill_list.clone(),
|
||||
skill_level_map: avatar.skill_level_map.clone(),
|
||||
proud_skill_extra_level_map: HashMap::with_capacity(0),
|
||||
server_buff_list: Vec::with_capacity(0),
|
||||
team_resonance_list: Vec::with_capacity(0),
|
||||
wearing_flycloak_id: avatar.wearing_flycloak_id,
|
||||
born_time: avatar.born_time,
|
||||
costume_id: avatar.costume_id,
|
||||
cur_vehicle_info: None,
|
||||
excel_info: Some(AvatarExcelInfo::default()),
|
||||
anim_hash: 0,
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn build_avatar_entity_info(
|
||||
avatar_data: &AvatarQueryReadOnlyItem,
|
||||
weapon_data: &WeaponQueryReadOnlyItem,
|
||||
) -> SceneEntityInfo {
|
||||
use sakura_proto::*;
|
||||
|
||||
SceneEntityInfo {
|
||||
entity_type: ProtEntityType::Avatar.into(),
|
||||
entity_id: avatar_data.entity_id.0,
|
||||
name: String::new(),
|
||||
motion_info: Some(MotionInfo {
|
||||
pos: Some(avatar_data.transform.position.into()),
|
||||
rot: Some(avatar_data.transform.rotation.into()),
|
||||
speed: Some(Vector::default()),
|
||||
..Default::default()
|
||||
}),
|
||||
prop_list: vec![
|
||||
int_prop_pair!(PROP_LEVEL, avatar_data.level.0),
|
||||
int_prop_pair!(PROP_BREAK_LEVEL, avatar_data.break_level.0),
|
||||
],
|
||||
fight_prop_list: avatar_data
|
||||
.fight_properties
|
||||
.0
|
||||
.iter()
|
||||
.map(|(k, v)| FightPropPair {
|
||||
prop_type: *k as u32,
|
||||
prop_value: *v,
|
||||
})
|
||||
.collect(),
|
||||
life_state: *avatar_data.life_state as u32,
|
||||
animator_para_list: vec![AnimatorParameterValueInfoPair {
|
||||
name_id: 0,
|
||||
animator_para: Some(AnimatorParameterValueInfo::default()),
|
||||
}],
|
||||
last_move_scene_time_ms: 0,
|
||||
last_move_reliable_seq: 0,
|
||||
entity_client_data: Some(EntityClientData::default()),
|
||||
entity_environment_info_list: Vec::with_capacity(0),
|
||||
entity_authority_info: Some(EntityAuthorityInfo {
|
||||
ability_info: Some(AbilitySyncStateInfo::default()),
|
||||
born_pos: Some(Vector::default()),
|
||||
client_extra_info: Some(EntityClientExtraInfo {
|
||||
skill_anchor_position: Some(Vector::default()),
|
||||
}),
|
||||
..Default::default()
|
||||
}),
|
||||
tag_list: Vec::with_capacity(0),
|
||||
server_buff_list: Vec::with_capacity(0),
|
||||
entity: Some(scene_entity_info::Entity::Avatar(SceneAvatarInfo {
|
||||
uid: avatar_data.owner_player_uid.0,
|
||||
avatar_id: avatar_data.avatar_id.0,
|
||||
guid: avatar_data.guid.0,
|
||||
peer_id: avatar_data.control_peer.0,
|
||||
equip_id_list: vec![weapon_data.weapon_id.0],
|
||||
skill_depot_id: avatar_data.skill_depot.0,
|
||||
talent_id_list: vec![],
|
||||
weapon: Some(SceneWeaponInfo {
|
||||
guid: weapon_data.guid.0,
|
||||
entity_id: weapon_data.entity_id.0,
|
||||
gadget_id: weapon_data.gadget_id.0,
|
||||
item_id: weapon_data.weapon_id.0,
|
||||
level: weapon_data.level.0,
|
||||
promote_level: weapon_data.promote_level.0,
|
||||
affix_map: weapon_data.affix_map.0.clone(),
|
||||
ability_info: Some(AbilitySyncStateInfo::default()),
|
||||
renderer_changed_info: Some(EntityRendererChangedInfo::default()),
|
||||
}),
|
||||
reliquary_list: Vec::with_capacity(0),
|
||||
core_proud_skill_level: 0,
|
||||
inherent_proud_skill_list: avatar_data.inherent_proud_skill_list.0.clone(),
|
||||
skill_level_map: avatar_data.skill_level_map.0.clone(),
|
||||
proud_skill_extra_level_map: HashMap::with_capacity(0),
|
||||
server_buff_list: Vec::with_capacity(0),
|
||||
team_resonance_list: Vec::with_capacity(0),
|
||||
wearing_flycloak_id: avatar_data.appearance.flycloak_id,
|
||||
born_time: avatar_data.born_time.0,
|
||||
costume_id: avatar_data.appearance.costume_id,
|
||||
cur_vehicle_info: None,
|
||||
excel_info: Some(AvatarExcelInfo::default()),
|
||||
anim_hash: 0,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use avatar::AvatarEquipChangeEvent;
|
||||
use avatar::{AvatarCostumeChangeEvent, AvatarEquipChangeEvent};
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_ecs::prelude::*;
|
||||
use common::{EntityCounter, FightProperties, LifeState, ProtocolEntityID, ToBeRemovedMarker};
|
||||
|
@ -25,7 +25,9 @@ impl Plugin for EntityPlugin {
|
|||
fn build(&self, app: &mut App) {
|
||||
app.insert_resource(EntityCounter::default())
|
||||
.add_event::<AvatarEquipChangeEvent>()
|
||||
.add_event::<AvatarCostumeChangeEvent>()
|
||||
.add_event::<EntityDisappearEvent>()
|
||||
.add_systems(Update, avatar::update_avatar_appearance)
|
||||
.add_systems(
|
||||
Last,
|
||||
(
|
||||
|
@ -33,6 +35,7 @@ impl Plugin for EntityPlugin {
|
|||
notify_life_state_change,
|
||||
notify_disappear_entities,
|
||||
remove_marked_entities,
|
||||
avatar::notify_avatar_costume_change,
|
||||
avatar::notify_appear_avatar_entities
|
||||
.run_if(avatar::run_if_avatar_entities_appeared),
|
||||
monster::notify_appear_monster_entities
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
use bevy_ecs::prelude::*;
|
||||
use sakura_proto::YSMessage;
|
||||
use sakura_proto::{PacketHead, YSMessage};
|
||||
|
||||
#[derive(Event)]
|
||||
pub struct ClientMessageEvent(u32, u16, Box<[u8]>);
|
||||
pub struct ClientMessageEvent(PacketHead, u16, Box<[u8]>);
|
||||
|
||||
impl ClientMessageEvent {
|
||||
pub fn new(uid: u32, cmd_id: u16, data: Box<[u8]>) -> Self {
|
||||
Self(uid, cmd_id, data)
|
||||
pub fn new(head: PacketHead, cmd_id: u16, data: Box<[u8]>) -> Self {
|
||||
Self(head, cmd_id, data)
|
||||
}
|
||||
|
||||
pub const fn sender_uid(&self) -> u32 {
|
||||
self.0
|
||||
self.0.user_id
|
||||
}
|
||||
|
||||
pub const fn head(&self) -> &PacketHead {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub const fn cmd_id(&self) -> u16 {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use bevy_ecs::system::Resource;
|
||||
use sakura_proto::YSMessage;
|
||||
use sakura_proto::{PacketHead, YSMessage};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ClientOutput(mpsc::Sender<(u16, Box<[u8]>)>);
|
||||
pub struct ClientOutput(mpsc::Sender<(u16, PacketHead, Box<[u8]>)>);
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct MessageOutput(HashMap<u32, ClientOutput>);
|
||||
|
@ -17,26 +17,27 @@ impl MessageOutput {
|
|||
|
||||
pub fn send(&self, player_uid: u32, message: impl YSMessage) {
|
||||
if let Some(out) = self.0.get(&player_uid) {
|
||||
out.push(message);
|
||||
out.push(PacketHead::default(), message);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_to_all(&self, message: impl YSMessage + Clone) {
|
||||
for out in self.0.values() {
|
||||
out.push(message.clone());
|
||||
out.push(PacketHead::default(), message.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientOutput {
|
||||
pub fn new(tx: mpsc::Sender<(u16, Box<[u8]>)>) -> Self {
|
||||
pub fn new(tx: mpsc::Sender<(u16, PacketHead, Box<[u8]>)>) -> Self {
|
||||
Self(tx)
|
||||
}
|
||||
|
||||
pub fn push(&self, message: impl YSMessage) {
|
||||
pub fn push(&self, head: PacketHead, message: impl YSMessage) {
|
||||
self.0
|
||||
.blocking_send((
|
||||
message.get_cmd_id(),
|
||||
head,
|
||||
message.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
.unwrap()
|
||||
|
|
|
@ -34,6 +34,7 @@ pub struct AvatarModuleInformation {
|
|||
pub avatar_map: HashMap<u64, AvatarInformation>,
|
||||
pub team_map: HashMap<u32, AvatarTeamInformation>,
|
||||
pub owned_flycloak_set: HashSet<u32>,
|
||||
pub owned_costume_set: HashSet<u32>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
@ -55,6 +56,7 @@ pub struct AvatarInformation {
|
|||
pub skill_level_map: HashMap<u32, u32>,
|
||||
pub inherent_proud_skill_list: Vec<u32>,
|
||||
pub wearing_flycloak_id: u32,
|
||||
pub costume_id: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
|
|
@ -4128,11 +4128,11 @@ pub struct ForceUpdateInfo {
|
|||
#[derive(sakura_proto_derive::CmdID)]
|
||||
#[cmdid(22470)]
|
||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
||||
pub struct Flbhgdcpebg {
|
||||
pub struct ClientLoadingCostumeVerificationNotify {
|
||||
#[prost(uint32, tag = "6")]
|
||||
pub costume_id: u32,
|
||||
#[prost(uint64, tag = "3")]
|
||||
pub dljodpnohgd: u64,
|
||||
pub prefab_hash: u64,
|
||||
#[prost(uint64, tag = "5")]
|
||||
pub guid: u64,
|
||||
}
|
||||
|
@ -7044,11 +7044,11 @@ pub struct AvatarDataNotify {
|
|||
#[prost(uint32, repeated, tag = "2")]
|
||||
pub backup_avatar_team_order_list: ::prost::alloc::vec::Vec<u32>,
|
||||
#[prost(uint32, repeated, tag = "3")]
|
||||
pub ophdokofiho: ::prost::alloc::vec::Vec<u32>,
|
||||
pub owned_costume_list: ::prost::alloc::vec::Vec<u32>,
|
||||
#[prost(uint64, tag = "4")]
|
||||
pub choose_avatar_guid: u64,
|
||||
#[prost(uint32, repeated, tag = "5")]
|
||||
pub cpeajkcgpio: ::prost::alloc::vec::Vec<u32>,
|
||||
pub owned_trace_effect_list: ::prost::alloc::vec::Vec<u32>,
|
||||
#[prost(map = "uint32, message", tag = "6")]
|
||||
pub avatar_team_map: ::std::collections::HashMap<u32, AvatarTeam>,
|
||||
#[prost(message, repeated, tag = "9")]
|
||||
|
@ -20156,9 +20156,9 @@ pub mod gadget_play_info {
|
|||
#[derive(sakura_proto_derive::CmdID)]
|
||||
#[cmdid(24457)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Coocgbbbiio {
|
||||
pub struct AvatarChangeCostumeNotify {
|
||||
#[prost(message, optional, tag = "11")]
|
||||
pub ekdkeobgnmm: ::core::option::Option<SceneEntityInfo>,
|
||||
pub entity_info: ::core::option::Option<SceneEntityInfo>,
|
||||
}
|
||||
#[derive(sakura_proto_derive::CmdID)]
|
||||
#[cmdid(3411)]
|
||||
|
@ -25399,7 +25399,7 @@ pub struct SceneForceUnlockNotify {
|
|||
#[derive(sakura_proto_derive::CmdID)]
|
||||
#[cmdid(5695)]
|
||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
||||
pub struct Pbmdicgahkn {
|
||||
pub struct HomeAvatarCostumeChangeNotify {
|
||||
#[prost(uint32, tag = "5")]
|
||||
pub costume_id: u32,
|
||||
#[prost(uint32, tag = "14")]
|
||||
|
@ -27272,9 +27272,9 @@ pub struct Abmcjlmomkg {
|
|||
#[derive(sakura_proto_derive::CmdID)]
|
||||
#[cmdid(27168)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Ehiogclpann {
|
||||
pub struct AvatarChangeTraceEffectNotify {
|
||||
#[prost(message, optional, tag = "4")]
|
||||
pub ekdkeobgnmm: ::core::option::Option<SceneEntityInfo>,
|
||||
pub entity_info: ::core::option::Option<SceneEntityInfo>,
|
||||
}
|
||||
#[derive(sakura_proto_derive::CmdID)]
|
||||
#[cmdid(25876)]
|
||||
|
@ -41994,7 +41994,7 @@ pub struct Ieokmefncfg {
|
|||
#[derive(sakura_proto_derive::CmdID)]
|
||||
#[cmdid(20708)]
|
||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
||||
pub struct Anagafpkcki {
|
||||
pub struct AvatarChangeCostumeReq {
|
||||
#[prost(uint32, tag = "13")]
|
||||
pub costume_id: u32,
|
||||
#[prost(uint64, tag = "10")]
|
||||
|
@ -50336,7 +50336,7 @@ pub struct Ffajmhiamje {
|
|||
#[derive(sakura_proto_derive::CmdID)]
|
||||
#[cmdid(25161)]
|
||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
||||
pub struct Beggfkckgif {
|
||||
pub struct AvatarChangeCostumeRsp {
|
||||
#[prost(uint32, tag = "3")]
|
||||
pub costume_id: u32,
|
||||
#[prost(uint64, tag = "14")]
|
||||
|
|
|
@ -289,6 +289,17 @@ impl From<crate::client::ForceUpdateInfo> for ForceUpdateInfo {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::client::ClientLoadingCostumeVerificationNotify>
|
||||
for ClientLoadingCostumeVerificationNotify {
|
||||
fn from(value: crate::client::ClientLoadingCostumeVerificationNotify) -> Self {
|
||||
Self {
|
||||
costume_id: value.costume_id.into(),
|
||||
prefab_hash: value.prefab_hash.into(),
|
||||
guid: value.guid.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::client::AvatarTeam> for AvatarTeam {
|
||||
fn from(value: crate::client::AvatarTeam) -> Self {
|
||||
Self {
|
||||
|
@ -419,6 +430,11 @@ impl From<crate::client::AvatarDataNotify> for AvatarDataNotify {
|
|||
.into_iter()
|
||||
.map(|v| v.into())
|
||||
.collect(),
|
||||
owned_costume_list: value
|
||||
.owned_costume_list
|
||||
.into_iter()
|
||||
.map(|v| v.into())
|
||||
.collect(),
|
||||
choose_avatar_guid: value.choose_avatar_guid.into(),
|
||||
avatar_team_map: value
|
||||
.avatar_team_map
|
||||
|
@ -1250,6 +1266,14 @@ impl From<crate::client::GadgetPlayInfo> for GadgetPlayInfo {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::client::AvatarChangeCostumeNotify> for AvatarChangeCostumeNotify {
|
||||
fn from(value: crate::client::AvatarChangeCostumeNotify) -> Self {
|
||||
Self {
|
||||
entity_info: value.entity_info.map(|v| v.into()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::client::Material> for Material {
|
||||
fn from(value: crate::client::Material) -> Self {
|
||||
Self {
|
||||
|
@ -1567,6 +1591,16 @@ impl From<crate::client::SceneForceUnlockNotify> for SceneForceUnlockNotify {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::client::HomeAvatarCostumeChangeNotify>
|
||||
for HomeAvatarCostumeChangeNotify {
|
||||
fn from(value: crate::client::HomeAvatarCostumeChangeNotify) -> Self {
|
||||
Self {
|
||||
costume_id: value.costume_id.into(),
|
||||
avatar_id: value.avatar_id.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::client::AiSyncInfo> for AiSyncInfo {
|
||||
fn from(value: crate::client::AiSyncInfo) -> Self {
|
||||
Self {
|
||||
|
@ -2410,6 +2444,15 @@ impl From<crate::client::MassivePropSyncInfo> for MassivePropSyncInfo {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::client::AvatarChangeCostumeReq> for AvatarChangeCostumeReq {
|
||||
fn from(value: crate::client::AvatarChangeCostumeReq) -> Self {
|
||||
Self {
|
||||
costume_id: value.costume_id.into(),
|
||||
avatar_guid: value.avatar_guid.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::client::BreakoutVector2> for BreakoutVector2 {
|
||||
fn from(value: crate::client::BreakoutVector2) -> Self {
|
||||
Self {
|
||||
|
@ -2649,3 +2692,13 @@ impl From<crate::client::SetUpAvatarTeamRsp> for SetUpAvatarTeamRsp {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::client::AvatarChangeCostumeRsp> for AvatarChangeCostumeRsp {
|
||||
fn from(value: crate::client::AvatarChangeCostumeRsp) -> Self {
|
||||
Self {
|
||||
costume_id: value.costume_id.into(),
|
||||
avatar_guid: value.avatar_guid.into(),
|
||||
retcode: value.retcode.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,6 +94,17 @@ pub fn client_to_normal(
|
|||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::client::ClientLoadingCostumeVerificationNotify::CMD_ID => {
|
||||
let proto = crate::client::ClientLoadingCostumeVerificationNotify::decode(
|
||||
body,
|
||||
)?;
|
||||
let proto: crate::normal::ClientLoadingCostumeVerificationNotify = proto
|
||||
.into();
|
||||
Ok((
|
||||
crate::normal::ClientLoadingCostumeVerificationNotify::CMD_ID,
|
||||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::client::AvatarWearFlycloakRsp::CMD_ID => {
|
||||
let proto = crate::client::AvatarWearFlycloakRsp::decode(body)?;
|
||||
let proto: crate::normal::AvatarWearFlycloakRsp = proto.into();
|
||||
|
@ -302,6 +313,14 @@ pub fn client_to_normal(
|
|||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::client::AvatarChangeCostumeNotify::CMD_ID => {
|
||||
let proto = crate::client::AvatarChangeCostumeNotify::decode(body)?;
|
||||
let proto: crate::normal::AvatarChangeCostumeNotify = proto.into();
|
||||
Ok((
|
||||
crate::normal::AvatarChangeCostumeNotify::CMD_ID,
|
||||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::client::EvtAvatarLockChairRsp::CMD_ID => {
|
||||
let proto = crate::client::EvtAvatarLockChairRsp::decode(body)?;
|
||||
let proto: crate::normal::EvtAvatarLockChairRsp = proto.into();
|
||||
|
@ -366,6 +385,14 @@ pub fn client_to_normal(
|
|||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::client::HomeAvatarCostumeChangeNotify::CMD_ID => {
|
||||
let proto = crate::client::HomeAvatarCostumeChangeNotify::decode(body)?;
|
||||
let proto: crate::normal::HomeAvatarCostumeChangeNotify = proto.into();
|
||||
Ok((
|
||||
crate::normal::HomeAvatarCostumeChangeNotify::CMD_ID,
|
||||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::client::ScenePointUnlockNotify::CMD_ID => {
|
||||
let proto = crate::client::ScenePointUnlockNotify::decode(body)?;
|
||||
let proto: crate::normal::ScenePointUnlockNotify = proto.into();
|
||||
|
@ -502,6 +529,14 @@ pub fn client_to_normal(
|
|||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::client::AvatarChangeCostumeReq::CMD_ID => {
|
||||
let proto = crate::client::AvatarChangeCostumeReq::decode(body)?;
|
||||
let proto: crate::normal::AvatarChangeCostumeReq = proto.into();
|
||||
Ok((
|
||||
crate::normal::AvatarChangeCostumeReq::CMD_ID,
|
||||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::client::PlayerEnterSceneNotify::CMD_ID => {
|
||||
let proto = crate::client::PlayerEnterSceneNotify::decode(body)?;
|
||||
let proto: crate::normal::PlayerEnterSceneNotify = proto.into();
|
||||
|
@ -566,6 +601,14 @@ pub fn client_to_normal(
|
|||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::client::AvatarChangeCostumeRsp::CMD_ID => {
|
||||
let proto = crate::client::AvatarChangeCostumeRsp::decode(body)?;
|
||||
let proto: crate::normal::AvatarChangeCostumeRsp = proto.into();
|
||||
Ok((
|
||||
crate::normal::AvatarChangeCostumeRsp::CMD_ID,
|
||||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
not_found => Err(ProtocolConversionError::NotFound(not_found)),
|
||||
}
|
||||
}
|
||||
|
@ -665,6 +708,17 @@ pub fn normal_to_client(
|
|||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::normal::ClientLoadingCostumeVerificationNotify::CMD_ID => {
|
||||
let proto = crate::normal::ClientLoadingCostumeVerificationNotify::decode(
|
||||
body,
|
||||
)?;
|
||||
let proto: crate::client::ClientLoadingCostumeVerificationNotify = proto
|
||||
.into();
|
||||
Ok((
|
||||
crate::client::ClientLoadingCostumeVerificationNotify::CMD_ID,
|
||||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::normal::AvatarWearFlycloakRsp::CMD_ID => {
|
||||
let proto = crate::normal::AvatarWearFlycloakRsp::decode(body)?;
|
||||
let proto: crate::client::AvatarWearFlycloakRsp = proto.into();
|
||||
|
@ -873,6 +927,14 @@ pub fn normal_to_client(
|
|||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::normal::AvatarChangeCostumeNotify::CMD_ID => {
|
||||
let proto = crate::normal::AvatarChangeCostumeNotify::decode(body)?;
|
||||
let proto: crate::client::AvatarChangeCostumeNotify = proto.into();
|
||||
Ok((
|
||||
crate::client::AvatarChangeCostumeNotify::CMD_ID,
|
||||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::normal::EvtAvatarLockChairRsp::CMD_ID => {
|
||||
let proto = crate::normal::EvtAvatarLockChairRsp::decode(body)?;
|
||||
let proto: crate::client::EvtAvatarLockChairRsp = proto.into();
|
||||
|
@ -937,6 +999,14 @@ pub fn normal_to_client(
|
|||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::normal::HomeAvatarCostumeChangeNotify::CMD_ID => {
|
||||
let proto = crate::normal::HomeAvatarCostumeChangeNotify::decode(body)?;
|
||||
let proto: crate::client::HomeAvatarCostumeChangeNotify = proto.into();
|
||||
Ok((
|
||||
crate::client::HomeAvatarCostumeChangeNotify::CMD_ID,
|
||||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::normal::ScenePointUnlockNotify::CMD_ID => {
|
||||
let proto = crate::normal::ScenePointUnlockNotify::decode(body)?;
|
||||
let proto: crate::client::ScenePointUnlockNotify = proto.into();
|
||||
|
@ -1073,6 +1143,14 @@ pub fn normal_to_client(
|
|||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::normal::AvatarChangeCostumeReq::CMD_ID => {
|
||||
let proto = crate::normal::AvatarChangeCostumeReq::decode(body)?;
|
||||
let proto: crate::client::AvatarChangeCostumeReq = proto.into();
|
||||
Ok((
|
||||
crate::client::AvatarChangeCostumeReq::CMD_ID,
|
||||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::normal::PlayerEnterSceneNotify::CMD_ID => {
|
||||
let proto = crate::normal::PlayerEnterSceneNotify::decode(body)?;
|
||||
let proto: crate::client::PlayerEnterSceneNotify = proto.into();
|
||||
|
@ -1137,6 +1215,14 @@ pub fn normal_to_client(
|
|||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
crate::normal::AvatarChangeCostumeRsp::CMD_ID => {
|
||||
let proto = crate::normal::AvatarChangeCostumeRsp::decode(body)?;
|
||||
let proto: crate::client::AvatarChangeCostumeRsp = proto.into();
|
||||
Ok((
|
||||
crate::client::AvatarChangeCostumeRsp::CMD_ID,
|
||||
proto.encode_to_vec().into_boxed_slice(),
|
||||
))
|
||||
}
|
||||
not_found => Err(ProtocolConversionError::NotFound(not_found)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -289,6 +289,17 @@ impl From<crate::normal::ForceUpdateInfo> for ForceUpdateInfo {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::normal::ClientLoadingCostumeVerificationNotify>
|
||||
for ClientLoadingCostumeVerificationNotify {
|
||||
fn from(value: crate::normal::ClientLoadingCostumeVerificationNotify) -> Self {
|
||||
Self {
|
||||
costume_id: value.costume_id.into(),
|
||||
prefab_hash: value.prefab_hash.into(),
|
||||
guid: value.guid.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::normal::AvatarTeam> for AvatarTeam {
|
||||
fn from(value: crate::normal::AvatarTeam) -> Self {
|
||||
Self {
|
||||
|
@ -419,6 +430,11 @@ impl From<crate::normal::AvatarDataNotify> for AvatarDataNotify {
|
|||
.into_iter()
|
||||
.map(|v| v.into())
|
||||
.collect(),
|
||||
owned_costume_list: value
|
||||
.owned_costume_list
|
||||
.into_iter()
|
||||
.map(|v| v.into())
|
||||
.collect(),
|
||||
choose_avatar_guid: value.choose_avatar_guid.into(),
|
||||
avatar_team_map: value
|
||||
.avatar_team_map
|
||||
|
@ -1250,6 +1266,14 @@ impl From<crate::normal::GadgetPlayInfo> for GadgetPlayInfo {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::normal::AvatarChangeCostumeNotify> for AvatarChangeCostumeNotify {
|
||||
fn from(value: crate::normal::AvatarChangeCostumeNotify) -> Self {
|
||||
Self {
|
||||
entity_info: value.entity_info.map(|v| v.into()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::normal::Material> for Material {
|
||||
fn from(value: crate::normal::Material) -> Self {
|
||||
Self {
|
||||
|
@ -1567,6 +1591,16 @@ impl From<crate::normal::SceneForceUnlockNotify> for SceneForceUnlockNotify {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::normal::HomeAvatarCostumeChangeNotify>
|
||||
for HomeAvatarCostumeChangeNotify {
|
||||
fn from(value: crate::normal::HomeAvatarCostumeChangeNotify) -> Self {
|
||||
Self {
|
||||
costume_id: value.costume_id.into(),
|
||||
avatar_id: value.avatar_id.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::normal::AiSyncInfo> for AiSyncInfo {
|
||||
fn from(value: crate::normal::AiSyncInfo) -> Self {
|
||||
Self {
|
||||
|
@ -2410,6 +2444,15 @@ impl From<crate::normal::MassivePropSyncInfo> for MassivePropSyncInfo {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::normal::AvatarChangeCostumeReq> for AvatarChangeCostumeReq {
|
||||
fn from(value: crate::normal::AvatarChangeCostumeReq) -> Self {
|
||||
Self {
|
||||
costume_id: value.costume_id.into(),
|
||||
avatar_guid: value.avatar_guid.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::normal::BreakoutVector2> for BreakoutVector2 {
|
||||
fn from(value: crate::normal::BreakoutVector2) -> Self {
|
||||
Self {
|
||||
|
@ -2649,3 +2692,13 @@ impl From<crate::normal::SetUpAvatarTeamRsp> for SetUpAvatarTeamRsp {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::normal::AvatarChangeCostumeRsp> for AvatarChangeCostumeRsp {
|
||||
fn from(value: crate::normal::AvatarChangeCostumeRsp) -> Self {
|
||||
Self {
|
||||
costume_id: value.costume_id.into(),
|
||||
avatar_guid: value.avatar_guid.into(),
|
||||
retcode: value.retcode.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ pub fn player_join_team(
|
|||
},
|
||||
appearance: AvatarAppearance {
|
||||
flycloak_id: to_spawn.wearing_flycloak_id,
|
||||
costume_id: 0, // TODO!
|
||||
costume_id: to_spawn.costume_id,
|
||||
},
|
||||
transform: Transform {
|
||||
position: player_info.world_position.position.into(),
|
||||
|
|
Loading…
Reference in a new issue