Implement #[property_accessors] proc macro to reduce boilerplate for accessing optional properties

This commit is contained in:
xeon 2024-12-12 21:53:27 +03:00
parent ec9ddd4ef7
commit a266b2e12b
13 changed files with 182 additions and 230 deletions

View file

@ -75,7 +75,7 @@ impl DbContext {
} }
pub async fn save_player_data(&self, last_uid: u32, player_info: &PlayerInfo) -> Result<()> { pub async fn save_player_data(&self, last_uid: u32, player_info: &PlayerInfo) -> Result<()> {
let player_uid = player_info.uid.unwrap(); let player_uid = *player_info.uid();
let _: PlayerData = self let _: PlayerData = self
.0 .0

View file

@ -73,8 +73,8 @@ pub fn execute_action(
match action { match action {
ActionCreateNpcCfg { id, tag_id } => { ActionCreateNpcCfg { id, tag_id } => {
let uid = session.uid_counter.next(); let uid = session.uid_counter.next();
let sdg = session.player_info.single_dungeon_group.as_mut().unwrap(); let sdg = session.player_info.single_dungeon_group_mut();
sdg.npcs.as_mut().unwrap().insert( sdg.npcs_mut().insert(
scene_uid, scene_uid,
uid, uid,
NpcInfo { NpcInfo {
@ -100,10 +100,8 @@ pub fn execute_action(
section_listen_events, section_listen_events,
.. ..
} => { } => {
let sdg = session.player_info.single_dungeon_group.as_mut().unwrap(); let sdg = session.player_info.single_dungeon_group_mut();
sdg.npcs sdg.npcs()
.as_ref()
.unwrap()
.iter() .iter()
.filter(|(s_uid, _, _)| **s_uid == scene_uid) .filter(|(s_uid, _, _)| **s_uid == scene_uid)
.for_each(|(_, &uid, npc)| { .for_each(|(_, &uid, npc)| {
@ -133,12 +131,7 @@ pub fn execute_action(
}); });
} }
ActionSetMainCityObjectState { object_state, .. } => { ActionSetMainCityObjectState { object_state, .. } => {
let main_city_objects_state = session let main_city_objects_state = session.player_info.main_city_objects_state_mut();
.player_info
.main_city_objects_state
.as_mut()
.unwrap();
object_state object_state
.iter() .iter()
.for_each(|(&obj, &state)| main_city_objects_state.insert(obj, state)); .for_each(|(&obj, &state)| main_city_objects_state.insert(obj, state));

View file

@ -323,7 +323,7 @@ pub fn create_starting_player_info(uid: u64, nick_name: &str) -> (UidCounter, Pl
.filter(|tmpl| tmpl.camp() != 0) .filter(|tmpl| tmpl.camp() != 0)
.for_each(|tmpl| { .for_each(|tmpl| {
let uid = counter.next(); let uid = counter.next();
player_info.items.as_mut().unwrap().insert( player_info.items_mut().insert(
uid, uid,
ItemInfo::AvatarInfo { ItemInfo::AvatarInfo {
uid, uid,
@ -354,7 +354,7 @@ pub fn create_starting_player_info(uid: u64, nick_name: &str) -> (UidCounter, Pl
.iter() .iter()
.for_each(|tmpl| { .for_each(|tmpl| {
let uid = counter.next(); let uid = counter.next();
player_info.items.as_mut().unwrap().insert( player_info.items_mut().insert(
uid, uid,
ItemInfo::Weapon { ItemInfo::Weapon {
uid, uid,

View file

@ -75,9 +75,7 @@ pub async fn on_rpc_weapon_dress_arg(
) -> Result<RpcWeaponDressRet, i32> { ) -> Result<RpcWeaponDressRet, i32> {
let Some(target_avatar_uid) = session let Some(target_avatar_uid) = session
.player_info .player_info
.items .items()
.as_ref()
.unwrap()
.iter() .iter()
.find(|(_, item)| { .find(|(_, item)| {
if let ItemInfo::AvatarInfo { id, .. } = item { if let ItemInfo::AvatarInfo { id, .. } = item {
@ -94,9 +92,7 @@ pub async fn on_rpc_weapon_dress_arg(
let Some((_, ItemInfo::Weapon { avatar_uid, .. })) = session let Some((_, ItemInfo::Weapon { avatar_uid, .. })) = session
.player_info .player_info
.items .items_mut()
.as_mut()
.unwrap()
.iter_mut() .iter_mut()
.find(|(uid, _)| (*uid & 0xFFFFFFFF) as u32 == arg.weapon_uid) .find(|(uid, _)| (*uid & 0xFFFFFFFF) as u32 == arg.weapon_uid)
else { else {
@ -124,9 +120,7 @@ pub async fn on_rpc_weapon_un_dress_arg(
) -> Result<RpcWeaponUnDressRet, i32> { ) -> Result<RpcWeaponUnDressRet, i32> {
let Some(target_avatar_uid) = session let Some(target_avatar_uid) = session
.player_info .player_info
.items .items()
.as_ref()
.unwrap()
.iter() .iter()
.find(|(_, item)| { .find(|(_, item)| {
if let ItemInfo::AvatarInfo { id, .. } = item { if let ItemInfo::AvatarInfo { id, .. } = item {
@ -143,9 +137,7 @@ pub async fn on_rpc_weapon_un_dress_arg(
session session
.player_info .player_info
.items .items_mut()
.as_mut()
.unwrap()
.iter_mut() .iter_mut()
.for_each(|(_, item)| { .for_each(|(_, item)| {
if let ItemInfo::Weapon { avatar_uid, .. } = item { if let ItemInfo::Weapon { avatar_uid, .. } = item {

View file

@ -118,17 +118,13 @@ pub async fn on_rpc_mod_time_arg(
debug!("{arg:?}"); debug!("{arg:?}");
let player_info = &mut session.player_info; let player_info = &mut session.player_info;
let scene_uid = player_info.scene_uid.unwrap(); let scene_uid = *player_info.scene_uid();
let dungeon_collection = player_info.dungeon_collection.as_mut().unwrap(); let dungeon_collection = player_info.dungeon_collection_mut();
if let Some(protocol::scene_info::SceneInfo::Hall { if let Some(protocol::scene_info::SceneInfo::Hall {
main_city_time_info, main_city_time_info,
.. ..
}) = dungeon_collection }) = dungeon_collection.scenes_mut().get_mut(&scene_uid)
.scenes
.as_mut()
.unwrap()
.get_mut(&scene_uid)
{ {
let prev_time = main_city_time_info.initial_time; let prev_time = main_city_time_info.initial_time;
main_city_time_info.initial_time = match arg.time_period { main_city_time_info.initial_time = match arg.time_period {

View file

@ -99,8 +99,8 @@ pub async fn on_rpc_player_transaction_arg(
session: &mut PlayerSession, session: &mut PlayerSession,
_: RpcPlayerTransactionArg, _: RpcPlayerTransactionArg,
) -> Result<RpcPlayerTransactionRet, i32> { ) -> Result<RpcPlayerTransactionRet, i32> {
let player_uid = session.player_info.uid.unwrap_or_default(); let player_uid = session.player_info.uid();
let scene_uid = session.player_info.scene_uid.unwrap_or_default(); let scene_uid = session.player_info.scene_uid();
Ok(RpcPlayerTransactionRet { Ok(RpcPlayerTransactionRet {
retcode: 0, retcode: 0,

View file

@ -17,20 +17,18 @@ pub async fn on_rpc_get_archive_info_arg(
session: &mut PlayerSession, session: &mut PlayerSession,
_: RpcGetArchiveInfoArg, _: RpcGetArchiveInfoArg,
) -> Result<RpcGetArchiveInfoRet, i32> { ) -> Result<RpcGetArchiveInfoRet, i32> {
let archive_info = session.player_info.archive_info.as_ref().unwrap(); let archive_info = session.player_info.archive_info();
Ok(RpcGetArchiveInfoRet { Ok(RpcGetArchiveInfoRet {
retcode: 0, retcode: 0,
archive_info: ArchiveInfo { archive_info: ArchiveInfo {
hollow_archive_id_list: archive_info hollow_archive_id_list: archive_info
.hollow_archive_id .hollow_archive_id()
.as_ref() .iter()
.map(|set| set.iter().map(|id| *id as u32).collect()) .map(|id| *id as u32)
.unwrap_or_default(), .collect(),
videotaps_info: archive_info videotaps_info: archive_info
.videotaps_info .videotaps_info()
.as_ref()
.unwrap()
.iter() .iter()
.map(|(id, videotape)| VideotapeInfo { .map(|(id, videotape)| VideotapeInfo {
archive_file_id: *id as u32, archive_file_id: *id as u32,
@ -52,10 +50,10 @@ pub async fn on_rpc_get_yorozuya_info_arg(
retcode: 0, retcode: 0,
yorozuya_info: YorozuyaInfo { yorozuya_info: YorozuyaInfo {
unlock_hollow_id_list: yorozuya_info unlock_hollow_id_list: yorozuya_info
.unlock_hollow_id .unlock_hollow_id()
.as_ref() .iter()
.map(|list| list.iter().map(|id| *id as u32).collect()) .map(|id| *id as u32)
.unwrap_or_default(), .collect(),
}, },
}) })
} }

View file

@ -15,14 +15,7 @@ pub async fn on_rpc_enter_world_arg(
) -> Result<RpcEnterWorldRet, i32> { ) -> Result<RpcEnterWorldRet, i32> {
let player_info = &mut session.player_info; let player_info = &mut session.player_info;
if player_info if *player_info.dungeon_collection().default_scene_uid() == 0 {
.dungeon_collection
.as_ref()
.unwrap()
.default_scene_uid
.unwrap()
== 0
{
let dungeon_uid = session.uid_counter.next(); let dungeon_uid = session.uid_counter.next();
let scene_uid = session.uid_counter.next(); let scene_uid = session.uid_counter.next();
@ -79,38 +72,25 @@ pub async fn on_rpc_enter_world_arg(
}, },
}; };
let dungeon_collection = player_info.dungeon_collection.as_mut().unwrap(); let dungeon_collection = player_info.dungeon_collection_mut();
dungeon_collection dungeon_collection
.dungeons .dungeons_mut()
.as_mut()
.unwrap()
.insert(dungeon_uid, dungeon_info); .insert(dungeon_uid, dungeon_info);
dungeon_collection dungeon_collection
.scenes .scenes_mut()
.as_mut()
.unwrap()
.insert(scene_uid, scene_info); .insert(scene_uid, scene_info);
dungeon_collection.default_scene_uid = Some(scene_uid); *dungeon_collection.default_scene_uid_mut() = scene_uid;
} }
let scene_uid = session let scene_uid = *session.player_info.dungeon_collection().default_scene_uid();
.player_info
.dungeon_collection
.as_ref()
.unwrap()
.default_scene_uid
.unwrap();
session.player_info.scene_uid = Some(scene_uid); session.player_info.scene_uid = Some(scene_uid);
if let Some(section_id) = session if let Some(section_id) = session
.player_info .player_info
.dungeon_collection .dungeon_collection()
.as_ref() .scenes()
.unwrap()
.scenes
.as_ref()
.unwrap()
.get(&scene_uid) .get(&scene_uid)
.map(|sc| *sc.get_section_id()) .map(|sc| *sc.get_section_id())
{ {
@ -154,13 +134,11 @@ pub async fn on_rpc_save_pos_in_main_city_arg(
session: &mut PlayerSession, session: &mut PlayerSession,
arg: RpcSavePosInMainCityArg, arg: RpcSavePosInMainCityArg,
) -> Result<RpcSavePosInMainCityRet, i32> { ) -> Result<RpcSavePosInMainCityRet, i32> {
let pos_in_main_city = session.player_info.pos_in_main_city.as_mut().unwrap(); let scene_uid = *session.player_info.scene_uid();
let dungeon_collection = session.player_info.dungeon_collection();
let scene_uid = session.player_info.scene_uid.unwrap();
let dungeon_collection = session.player_info.dungeon_collection.as_ref().unwrap();
let Some(protocol::scene_info::SceneInfo::Hall { section_id, .. }) = let Some(protocol::scene_info::SceneInfo::Hall { section_id, .. }) =
dungeon_collection.scenes.as_ref().unwrap().get(&scene_uid) dungeon_collection.scenes().get(&scene_uid)
else { else {
return Err(-1); return Err(-1);
}; };
@ -170,9 +148,10 @@ pub async fn on_rpc_save_pos_in_main_city_arg(
arg.position.position.clone().try_into(), arg.position.position.clone().try_into(),
arg.position.rotation.clone().try_into(), arg.position.rotation.clone().try_into(),
) { ) {
pos_in_main_city.position = Some(position); session.player_info.pos_in_main_city_mut().position = Some(position);
pos_in_main_city.rotation = Some(rotation); session.player_info.pos_in_main_city_mut().rotation = Some(rotation);
pos_in_main_city.initial_pos_id = Some(String::with_capacity(0)); session.player_info.pos_in_main_city_mut().initial_pos_id =
Some(String::with_capacity(0));
debug!( debug!(
"player_uid: {}, pos in main city updated: {arg:?}", "player_uid: {}, pos in main city updated: {arg:?}",
@ -195,24 +174,19 @@ pub async fn on_rpc_enter_section_arg(
arg: RpcEnterSectionArg, arg: RpcEnterSectionArg,
) -> Result<RpcEnterSectionRet, i32> { ) -> Result<RpcEnterSectionRet, i32> {
let player_info = &mut session.player_info; let player_info = &mut session.player_info;
let cur_scene_uid = player_info.scene_uid.unwrap(); let cur_scene_uid = *player_info.scene_uid();
let dungeon_collection = player_info.dungeon_collection.as_mut().unwrap(); let dungeon_collection = player_info.dungeon_collection_mut();
let Some(scene_info::SceneInfo::Hall { section_id, .. }) = dungeon_collection let Some(scene_info::SceneInfo::Hall { section_id, .. }) =
.scenes dungeon_collection.scenes_mut().get_mut(&cur_scene_uid)
.as_mut()
.unwrap()
.get_mut(&cur_scene_uid)
else { else {
error!("RpcEnterSection: current scene is not Hall!"); error!("RpcEnterSection: current scene is not Hall!");
return Err(-1); return Err(-1);
}; };
*section_id = arg.section_id as i32; *section_id = arg.section_id as i32;
player_info.pos_in_main_city_mut().initial_pos_id = Some(arg.transform_id);
let player_pos_in_main_city = player_info.pos_in_main_city.as_mut().unwrap();
player_pos_in_main_city.initial_pos_id = Some(arg.transform_id);
scene_section_util::init_hall_scene_section(session, cur_scene_uid, arg.section_id as i32); scene_section_util::init_hall_scene_section(session, cur_scene_uid, arg.section_id as i32);
level::on_section_enter(session, cur_scene_uid, arg.section_id as i32); level::on_section_enter(session, cur_scene_uid, arg.section_id as i32);
@ -249,7 +223,7 @@ pub async fn on_rpc_begin_training_course_battle_arg(
let dungeon_uid = session.uid_counter.next(); let dungeon_uid = session.uid_counter.next();
let scene_uid = session.uid_counter.next(); let scene_uid = session.uid_counter.next();
let cur_scene_uid = player_info.scene_uid.unwrap(); let cur_scene_uid = *player_info.scene_uid();
let dungeon_info = protocol::dungeon_info::DungeonInfo { let dungeon_info = protocol::dungeon_info::DungeonInfo {
uid: dungeon_uid, uid: dungeon_uid,
id: 12254000, id: 12254000,
@ -327,16 +301,12 @@ pub async fn on_rpc_begin_training_course_battle_arg(
weather: WeatherType::Rain, weather: WeatherType::Rain,
}; };
let dungeon_collection = player_info.dungeon_collection.as_mut().unwrap(); let dungeon_collection = player_info.dungeon_collection_mut();
dungeon_collection dungeon_collection
.dungeons .dungeons_mut()
.as_mut()
.unwrap()
.insert(dungeon_uid, dungeon_info); .insert(dungeon_uid, dungeon_info);
dungeon_collection dungeon_collection
.scenes .scenes_mut()
.as_mut()
.unwrap()
.insert(scene_uid, scene_info); .insert(scene_uid, scene_info);
let mut scene_info = build_client_scene_info(&session.player_info, scene_uid).unwrap(); let mut scene_info = build_client_scene_info(&session.player_info, scene_uid).unwrap();
@ -371,23 +341,13 @@ pub async fn on_rpc_leave_cur_dungeon_arg(
session: &mut PlayerSession, session: &mut PlayerSession,
_: RpcLeaveCurDungeonArg, _: RpcLeaveCurDungeonArg,
) -> Result<RpcLeaveCurDungeonRet, i32> { ) -> Result<RpcLeaveCurDungeonRet, i32> {
let scene_uid = session let scene_uid = *session.player_info.dungeon_collection().default_scene_uid();
.player_info
.dungeon_collection
.as_ref()
.unwrap()
.default_scene_uid
.unwrap();
session.player_info.scene_uid = Some(scene_uid); session.player_info.scene_uid = Some(scene_uid);
if let Some(section_id) = session if let Some(section_id) = session
.player_info .player_info
.dungeon_collection .dungeon_collection()
.as_ref() .scenes()
.unwrap()
.scenes
.as_ref()
.unwrap()
.get(&scene_uid) .get(&scene_uid)
.map(|sc| *sc.get_section_id()) .map(|sc| *sc.get_section_id())
{ {

View file

@ -10,18 +10,15 @@ use qwer::{phashmap, phashset, PropertyHashMap, PropertyHashSet};
use crate::{level, PlayerSession}; use crate::{level, PlayerSession};
pub fn init_hall_scene_section(session: &mut PlayerSession, scene_uid: u64, section_id: i32) { pub fn init_hall_scene_section(session: &mut PlayerSession, scene_uid: u64, section_id: i32) {
let single_dungeon_group = session.player_info.single_dungeon_group.as_mut().unwrap(); let single_dungeon_group = session.player_info.single_dungeon_group_mut();
if single_dungeon_group if single_dungeon_group
.section .section()
.as_ref()
.unwrap()
.contains(&scene_uid, &section_id) .contains(&scene_uid, &section_id)
{ {
return; return;
} }
let section_map = single_dungeon_group.section.as_mut().unwrap(); single_dungeon_group.section_mut().insert(
section_map.insert(
scene_uid, scene_uid,
section_id, section_id,
SectionInfo { SectionInfo {
@ -67,10 +64,8 @@ fn build_scene_unit_protocol_info(
scene_uid: u64, scene_uid: u64,
section_id: u32, section_id: u32,
) -> Vec<SceneUnitProtocolInfo> { ) -> Vec<SceneUnitProtocolInfo> {
let sdg = session.player_info.single_dungeon_group.as_ref().unwrap(); let sdg = session.player_info.single_dungeon_group();
sdg.npcs sdg.npcs()
.as_ref()
.unwrap()
.iter() .iter()
.filter(|(s_uid, _, npc)| { .filter(|(s_uid, _, npc)| {
**s_uid == scene_uid && npc.scene_data.section_id == section_id as i32 **s_uid == scene_uid && npc.scene_data.section_id == section_id as i32

View file

@ -1,8 +1,16 @@
use polymorphic::implement_polymorphic; use polymorphic::implement_polymorphic;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use property_accessors::implement_property_accessors;
mod polymorphic; mod polymorphic;
mod property_accessors;
#[proc_macro] #[proc_macro]
pub fn polymorphic(input: TokenStream) -> TokenStream { pub fn polymorphic(input: TokenStream) -> TokenStream {
implement_polymorphic(input) implement_polymorphic(input)
} }
#[proc_macro_attribute]
pub fn property_accessors(_attr: TokenStream, item: TokenStream) -> TokenStream {
implement_property_accessors(item)
}

View file

@ -0,0 +1,62 @@
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{parse_macro_input, Fields, GenericArgument, ItemStruct, PathArguments, Type};
pub fn implement_property_accessors(input: TokenStream) -> TokenStream {
let input_struct = parse_macro_input!(input as ItemStruct);
let struct_name = &input_struct.ident;
let Fields::Named(fields) = &input_struct.fields else {
panic!("only structs with named fields are supported by #[property_accessors]");
};
let mut get_methods = proc_macro2::TokenStream::new();
let mut get_mut_methods = proc_macro2::TokenStream::new();
for field in fields.named.iter() {
let name = field.ident.as_ref().unwrap();
let ty = get_underlying_type(&field.ty);
get_methods.extend(quote! {
pub fn #name(&self) -> &#ty {
self.#name.as_ref().unwrap()
}
});
let mut_getter_name = format_ident!("{}_mut", name);
get_mut_methods.extend(quote! {
pub fn #mut_getter_name(&mut self) -> &mut #ty {
self.#name.as_mut().unwrap()
}
});
}
quote! {
#input_struct
impl #struct_name {
#get_methods
#get_mut_methods
}
}
.into()
}
fn get_underlying_type(ty: &Type) -> &Type {
let Type::Path(path) = ty else {
panic!("all fields of struct for #[property_accessor] should be Option<T>");
};
let last_segment = path.path.segments.last();
let last_segment = last_segment.as_ref().unwrap();
let PathArguments::AngleBracketed(args) = &last_segment.arguments else {
panic!("all fields of struct for #[property_accessor] should be Option<T>");
};
if let GenericArgument::Type(ty) = args.args.first().unwrap() {
ty
} else {
panic!("all fields of struct for #[property_accessor] should be Option<T>");
}
}

View file

@ -1,5 +1,6 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use protocol_macros::property_accessors;
use qwer::{OctData, PropertyDoubleKeyHashMap, PropertyHashMap, PropertyHashSet}; use qwer::{OctData, PropertyDoubleKeyHashMap, PropertyHashMap, PropertyHashSet};
use crate::action_info::ActionInfo; use crate::action_info::ActionInfo;
@ -86,6 +87,7 @@ pub struct EventGraphsInfo {
#[derive(OctData, Clone, Debug, Default)] #[derive(OctData, Clone, Debug, Default)]
#[property_object(u16, 0x01)] #[property_object(u16, 0x01)]
#[root] #[root]
#[property_accessors]
pub struct PlayerInfo { pub struct PlayerInfo {
#[tag = 1] #[tag = 1]
pub uid: Option<u64>, pub uid: Option<u64>,
@ -215,6 +217,7 @@ pub struct PlayerInfo {
#[derive(OctData, Clone, Debug, Default)] #[derive(OctData, Clone, Debug, Default)]
#[property_object] #[property_object]
#[property_accessors]
pub struct DungeonCollection { pub struct DungeonCollection {
#[tag = 1] #[tag = 1]
pub dungeons: Option<PropertyHashMap<u64, DungeonInfo>>, pub dungeons: Option<PropertyHashMap<u64, DungeonInfo>>,
@ -264,6 +267,7 @@ pub struct VideotapeInfo {
#[derive(OctData, Clone, Debug, Default)] #[derive(OctData, Clone, Debug, Default)]
#[property_object] #[property_object]
#[property_accessors]
pub struct ArchiveInfo { pub struct ArchiveInfo {
#[tag = 1] #[tag = 1]
pub videotaps_info: Option<PropertyHashMap<i32, VideotapeInfo>>, pub videotaps_info: Option<PropertyHashMap<i32, VideotapeInfo>>,
@ -283,6 +287,7 @@ pub struct UnlockInfo {
#[derive(OctData, Clone, Debug, Default)] #[derive(OctData, Clone, Debug, Default)]
#[property_object] #[property_object]
#[property_accessors]
pub struct YorozuyaInfo { pub struct YorozuyaInfo {
#[tag = 1] #[tag = 1]
pub last_refresh_timestamp_common: Option<u64>, pub last_refresh_timestamp_common: Option<u64>,
@ -333,6 +338,7 @@ pub struct EquipGachaInfo {
#[derive(OctData, Clone, Debug)] #[derive(OctData, Clone, Debug)]
#[property_object] #[property_object]
#[property_accessors]
pub struct BeginnerProcedureInfo { pub struct BeginnerProcedureInfo {
#[tag = 1] #[tag = 1]
pub procedure_id: Option<i32>, pub procedure_id: Option<i32>,
@ -340,6 +346,7 @@ pub struct BeginnerProcedureInfo {
#[derive(OctData, Clone, Debug, Default)] #[derive(OctData, Clone, Debug, Default)]
#[property_object] #[property_object]
#[property_accessors]
pub struct PlayerPosInMainCity { pub struct PlayerPosInMainCity {
#[tag = 1] #[tag = 1]
pub position: Option<Vector3f>, pub position: Option<Vector3f>,
@ -777,6 +784,7 @@ pub struct SectionInfo {
#[derive(OctData, Clone, Debug, Default)] #[derive(OctData, Clone, Debug, Default)]
#[property_object] #[property_object]
#[property_accessors]
pub struct SingleDungeonGroup { pub struct SingleDungeonGroup {
#[tag = 1] #[tag = 1]
pub dungeons: Option<PropertyHashMap<u64, DungeonTable>>, pub dungeons: Option<PropertyHashMap<u64, DungeonTable>>,
@ -874,6 +882,7 @@ pub struct AreasInfo {
#[derive(OctData, Clone, Debug)] #[derive(OctData, Clone, Debug)]
#[property_object] #[property_object]
#[property_accessors]
pub struct BGMInfo { pub struct BGMInfo {
#[tag = 1] #[tag = 1]
pub bgm_id: Option<u32>, pub bgm_id: Option<u32>,

View file

@ -8,18 +8,12 @@ use crate::{
pub fn build_player_basic_info(player_info: &PlayerInfo) -> PlayerBasicInfo { pub fn build_player_basic_info(player_info: &PlayerInfo) -> PlayerBasicInfo {
PlayerBasicInfo { PlayerBasicInfo {
last_enter_world_timestamp: player_info.last_enter_world_timestamp.unwrap_or_default() last_enter_world_timestamp: *player_info.last_enter_world_timestamp() as i64,
as i64, avatar_id: *player_info.avatar_id(),
avatar_id: player_info.avatar_id.unwrap_or_default(), player_avatar_id: *player_info.avatar_id(),
player_avatar_id: player_info.avatar_id.unwrap_or_default(), main_city_avatar_id: *player_info.main_city_avatar_id(),
main_city_avatar_id: player_info.main_city_avatar_id.unwrap_or_default(), nick_name: player_info.nick_name().clone(),
nick_name: player_info.nick_name.clone().unwrap_or_default(), level: *player_info.yorozuya_info().yorozuya_level(),
level: player_info
.yorozuya_info
.as_ref()
.map(|yi| yi.yorozuya_level)
.flatten()
.unwrap_or_default(),
} }
} }
@ -27,16 +21,13 @@ pub fn build_client_scene_info(
player_info: &PlayerInfo, player_info: &PlayerInfo,
scene_uid: u64, scene_uid: u64,
) -> Option<crate::SceneInfo> { ) -> Option<crate::SceneInfo> {
let dungeon_collection = player_info.dungeon_collection.as_ref().unwrap(); let dungeon_collection = player_info.dungeon_collection();
let Some(scene_info) = dungeon_collection.scenes.as_ref().unwrap().get(&scene_uid) else { let Some(scene_info) = dungeon_collection.scenes().get(&scene_uid) else {
return None; return None;
}; };
let player_pos_in_main_city = player_info.pos_in_main_city.as_ref().unwrap(); let player_pos_in_main_city = player_info.pos_in_main_city();
let initial_transform = player_pos_in_main_city let initial_transform = player_pos_in_main_city.initial_pos_id().clone();
.initial_pos_id
.clone()
.unwrap_or_default();
Some(match scene_info { Some(match scene_info {
SceneInfo::Hall { SceneInfo::Hall {
@ -49,35 +40,22 @@ pub fn build_client_scene_info(
scene_type: 1, scene_type: 1,
hall_scene_info: Some(crate::HallSceneInfo { hall_scene_info: Some(crate::HallSceneInfo {
section_id: *section_id as u32, section_id: *section_id as u32,
player_avatar_id: player_info.avatar_id.unwrap_or_default(), player_avatar_id: *player_info.avatar_id(),
main_city_avatar_id: player_info.main_city_avatar_id.unwrap_or_default(), main_city_avatar_id: *player_info.main_city_avatar_id(),
bgm_id: player_info bgm_id: *player_info.bgm_info().bgm_id(),
.bgm_info
.as_ref()
.map(|bgm| bgm.bgm_id.clone())
.flatten()
.unwrap_or_default(),
day_of_week: main_city_time_info.day_of_week as u32, day_of_week: main_city_time_info.day_of_week as u32,
time_of_day: main_city_time_info.initial_time, time_of_day: main_city_time_info.initial_time,
camera_x: *camera_x, camera_x: *camera_x,
camera_y: *camera_y, camera_y: *camera_y,
position: initial_transform.is_empty().then(|| crate::Transform { position: initial_transform.is_empty().then(|| crate::Transform {
position: player_pos_in_main_city position: player_pos_in_main_city.position().clone().into(),
.position rotation: player_pos_in_main_city.rotation().clone().into(),
.clone()
.unwrap_or_default()
.into(),
rotation: player_pos_in_main_city
.rotation
.clone()
.unwrap_or_default()
.into(),
}), }),
main_city_objects_state: player_info main_city_objects_state: player_info
.main_city_objects_state .main_city_objects_state()
.as_ref() .iter()
.map(|map| map.iter().map(|(&k, &v)| (k, v)).collect()) .map(|(&k, &v)| (k, v))
.unwrap_or_default(), .collect(),
scene_unit_list: Vec::new(), scene_unit_list: Vec::new(),
transform_id: initial_transform, transform_id: initial_transform,
}), }),
@ -86,12 +64,7 @@ pub fn build_client_scene_info(
SceneInfo::Fresh { .. } => crate::SceneInfo { SceneInfo::Fresh { .. } => crate::SceneInfo {
scene_type: 4, scene_type: 4,
fresh_scene_info: Some(crate::FreshSceneInfo { fresh_scene_info: Some(crate::FreshSceneInfo {
beginner_procedure_id: player_info beginner_procedure_id: *player_info.beginner_procedure_info().procedure_id() as u32,
.beginner_procedure_info
.as_ref()
.unwrap()
.procedure_id
.unwrap_or_default() as u32,
}), }),
..Default::default() ..Default::default()
}, },
@ -123,8 +96,8 @@ pub fn build_client_dungeon_info(
player_info: &PlayerInfo, player_info: &PlayerInfo,
scene_uid: u64, scene_uid: u64,
) -> Option<crate::DungeonInfo> { ) -> Option<crate::DungeonInfo> {
let dungeon_collection = player_info.dungeon_collection.as_ref().unwrap(); let dungeon_collection = player_info.dungeon_collection();
let Some(scene_info) = dungeon_collection.scenes.as_ref().unwrap().get(&scene_uid) else { let Some(scene_info) = dungeon_collection.scenes().get(&scene_uid) else {
return None; return None;
}; };
@ -134,9 +107,7 @@ pub fn build_client_dungeon_info(
} }
let dungeon_info = dungeon_collection let dungeon_info = dungeon_collection
.dungeons .dungeons()
.as_ref()
.unwrap()
.get(scene_info.get_dungeon_uid()) .get(scene_info.get_dungeon_uid())
.unwrap(); .unwrap();
@ -147,7 +118,7 @@ pub fn build_client_dungeon_info(
.avatars .avatars
.iter() .iter()
.map(|(_, unit)| { .map(|(_, unit)| {
let avatar_info = player_info.items.as_ref().unwrap().get(&unit.uid).unwrap(); let avatar_info = player_info.items().get(&unit.uid).unwrap();
AvatarUnitInfo { AvatarUnitInfo {
avatar_id: *avatar_info.get_id() as u32, avatar_id: *avatar_info.get_id() as u32,
} }
@ -162,13 +133,9 @@ pub fn build_hall_refresh_arg(
hall_scene_uid: u64, hall_scene_uid: u64,
refresh_immediately: bool, refresh_immediately: bool,
) -> Option<PtcHallRefreshArg> { ) -> Option<PtcHallRefreshArg> {
let dungeon_collection = player_info.dungeon_collection.as_ref().unwrap(); let dungeon_collection = player_info.dungeon_collection();
let scene_info = dungeon_collection let scene_info = dungeon_collection.scenes().get(&hall_scene_uid);
.scenes let player_pos_in_main_city = player_info.pos_in_main_city();
.as_ref()
.unwrap()
.get(&hall_scene_uid);
let player_pos_in_main_city = player_info.pos_in_main_city.as_ref().unwrap();
match scene_info { match scene_info {
Some(SceneInfo::Hall { Some(SceneInfo::Hall {
@ -180,39 +147,23 @@ pub fn build_hall_refresh_arg(
}) => Some(PtcHallRefreshArg { }) => Some(PtcHallRefreshArg {
refresh_immediately, refresh_immediately,
section_id: *section_id as u32, section_id: *section_id as u32,
player_avatar_id: player_info.avatar_id.unwrap_or_default(), player_avatar_id: *player_info.avatar_id(),
main_city_avatar_id: player_info.main_city_avatar_id.unwrap_or_default(), main_city_avatar_id: *player_info.main_city_avatar_id(),
transform_id: player_pos_in_main_city transform_id: player_pos_in_main_city.initial_pos_id().clone(),
.initial_pos_id bgm_id: *player_info.bgm_info().bgm_id(),
.clone()
.unwrap_or_default(),
bgm_id: player_info
.bgm_info
.as_ref()
.map(|bgm| bgm.bgm_id.clone())
.flatten()
.unwrap_or_default(),
day_of_week: main_city_time_info.day_of_week as u32, day_of_week: main_city_time_info.day_of_week as u32,
time_of_day: main_city_time_info.initial_time, time_of_day: main_city_time_info.initial_time,
camera_x: *camera_x, camera_x: *camera_x,
camera_y: *camera_y, camera_y: *camera_y,
position: crate::Transform { position: crate::Transform {
position: player_pos_in_main_city position: player_pos_in_main_city.position().clone().into(),
.position rotation: player_pos_in_main_city.rotation().clone().into(),
.clone()
.unwrap_or_default()
.into(),
rotation: player_pos_in_main_city
.rotation
.clone()
.unwrap_or_default()
.into(),
}, },
main_city_objects_state: player_info main_city_objects_state: player_info
.main_city_objects_state .main_city_objects_state()
.as_ref() .iter()
.map(|map| map.iter().map(|(&k, &v)| (k, v)).collect()) .map(|(&k, &v)| (k, v))
.unwrap_or_default(), .collect(),
scene_unit_list: Vec::new(), scene_unit_list: Vec::new(),
}), }),
_ => None, _ => None,
@ -221,9 +172,7 @@ pub fn build_hall_refresh_arg(
pub fn build_sync_avatar_info_list(player_info: &PlayerInfo) -> Vec<AvatarInfo> { pub fn build_sync_avatar_info_list(player_info: &PlayerInfo) -> Vec<AvatarInfo> {
player_info player_info
.items .items()
.as_ref()
.unwrap()
.iter() .iter()
.map(|(uid, item)| { .map(|(uid, item)| {
if let ItemInfo::AvatarInfo { if let ItemInfo::AvatarInfo {
@ -249,9 +198,7 @@ pub fn build_sync_avatar_info_list(player_info: &PlayerInfo) -> Vec<AvatarInfo>
first_get_time: *first_get_time as i64, first_get_time: *first_get_time as i64,
talent_switch_list: talent_switch.clone(), talent_switch_list: talent_switch.clone(),
cur_weapon_uid: player_info cur_weapon_uid: player_info
.items .items()
.as_ref()
.unwrap()
.iter() .iter()
.find(|(_, item)| { .find(|(_, item)| {
if let ItemInfo::Weapon { avatar_uid, .. } = item { if let ItemInfo::Weapon { avatar_uid, .. } = item {
@ -280,9 +227,7 @@ pub fn build_sync_avatar_info_list(player_info: &PlayerInfo) -> Vec<AvatarInfo>
pub fn build_sync_weapon_info_list(player_info: &PlayerInfo) -> Vec<WeaponInfo> { pub fn build_sync_weapon_info_list(player_info: &PlayerInfo) -> Vec<WeaponInfo> {
player_info player_info
.items .items()
.as_ref()
.unwrap()
.iter() .iter()
.map(|(_, item)| { .map(|(_, item)| {
if let ItemInfo::Weapon { if let ItemInfo::Weapon {
@ -315,9 +260,7 @@ pub fn build_sync_weapon_info_list(player_info: &PlayerInfo) -> Vec<WeaponInfo>
pub fn build_sync_equip_info_list(player_info: &PlayerInfo) -> Vec<EquipInfo> { pub fn build_sync_equip_info_list(player_info: &PlayerInfo) -> Vec<EquipInfo> {
player_info player_info
.items .items()
.as_ref()
.unwrap()
.iter() .iter()
.map(|(_, item)| { .map(|(_, item)| {
if let ItemInfo::Equip { if let ItemInfo::Equip {
@ -348,9 +291,7 @@ pub fn build_sync_equip_info_list(player_info: &PlayerInfo) -> Vec<EquipInfo> {
pub fn build_sync_resource_info_list(player_info: &PlayerInfo) -> Vec<ResourceInfo> { pub fn build_sync_resource_info_list(player_info: &PlayerInfo) -> Vec<ResourceInfo> {
player_info player_info
.items .items()
.as_ref()
.unwrap()
.iter() .iter()
.map(|(_, item)| match item { .map(|(_, item)| match item {
ItemInfo::Currency { id, count, .. } => Some(ResourceInfo { ItemInfo::Currency { id, count, .. } => Some(ResourceInfo {
@ -379,9 +320,7 @@ pub fn build_sync_auto_recovery_info(
player_info: &PlayerInfo, player_info: &PlayerInfo,
) -> HashMap<u32, crate::AutoRecoveryInfo> { ) -> HashMap<u32, crate::AutoRecoveryInfo> {
player_info player_info
.auto_recovery_info .auto_recovery_info()
.as_ref()
.unwrap()
.iter() .iter()
.map(|(id, info)| (*id as u32, info.clone())) .map(|(id, info)| (*id as u32, info.clone()))
.collect() .collect()