Rework message handler system, fix scene time

This commit is contained in:
xeon 2024-05-25 17:04:04 +03:00
parent 0e0a78abaa
commit cf855ef4b6
16 changed files with 462 additions and 405 deletions

View file

@ -1,15 +1,13 @@
use super::*;
pub async fn on_rpc_battle_report_arg(
session: &NetworkSession,
pub async fn on_rpc_battle_report(
_session: &NetworkSession,
arg: &RpcBattleReportArg,
) -> Result<()> {
) -> Result<RpcBattleReportRet> {
let need_index = arg
.battle_reports
.last()
.map_or(0, |report| report.index + 1);
session
.send_rpc_ret(RpcBattleReportRet::new(need_index))
.await
Ok(RpcBattleReportRet::new(need_index))
}

View file

@ -4,10 +4,10 @@ use super::*;
const START_PROC_ID: i32 = 1;
pub async fn on_rpc_advance_beginner_procedure_arg(
pub async fn on_rpc_advance_beginner_procedure(
session: &NetworkSession,
arg: &RpcAdvanceBeginnerProcedureArg,
) -> Result<()> {
) -> Result<RpcAdvanceBeginnerProcedureRet> {
let next_procedure_id = if arg.procedure_id == 0 {
START_PROC_ID
} else {
@ -19,29 +19,25 @@ pub async fn on_rpc_advance_beginner_procedure_arg(
Box::pin(world::enter_main_city(session)).await?;
}
session
.send_rpc_ret(RpcAdvanceBeginnerProcedureRet::new(next_procedure_id))
.await
Ok(RpcAdvanceBeginnerProcedureRet::new(next_procedure_id))
}
pub async fn on_rpc_beginnerbattle_begin_arg(
session: &NetworkSession,
pub async fn on_rpc_beginnerbattle_begin(
_session: &NetworkSession,
arg: &RpcBeginnerbattleBeginArg,
) -> Result<()> {
session
.send_rpc_ret(RpcBeginnerbattleBeginRet::new(format!(
) -> Result<RpcBeginnerbattleBeginRet> {
Ok(RpcBeginnerbattleBeginRet::new(format!(
"{}-{}",
arg.battle_id,
util::cur_timestamp_seconds()
)))
.await
}
pub async fn on_rpc_beginnerbattle_end_arg(
session: &NetworkSession,
pub async fn on_rpc_beginnerbattle_end(
_session: &NetworkSession,
arg: &RpcBeginnerbattleEndArg,
) -> Result<()> {
) -> Result<RpcBeginnerbattleEndRet> {
tracing::info!("Battle statistics: {:?}", arg.battle_statistics);
session.send_rpc_ret(RpcBeginnerbattleEndRet::new()).await
Ok(RpcBeginnerbattleEndRet::new())
}

View file

@ -6,10 +6,10 @@ use crate::data;
use super::*;
pub async fn on_rpc_hollow_move_arg(
pub async fn on_rpc_hollow_move(
session: &mut NetworkSession,
arg: &RpcHollowMoveArg,
) -> Result<()> {
) -> Result<RpcHollowMoveRet> {
tracing::info!("Hollow movement {:?}", &arg);
let destination_pos = *arg.positions.last().unwrap();
@ -19,9 +19,13 @@ pub async fn on_rpc_hollow_move_arg(
let (ptc_hollow_grid, ptc_sync_hollow_event) =
hollow_grid_manager.move_to(destination_pos, scene_uid);
session.send_rpc_arg(114, &ptc_hollow_grid).await?;
session
.send_rpc_arg(PTC_HOLLOW_GRID_ID, &ptc_hollow_grid)
.await?;
if let Some(ptc_sync_hollow_event) = ptc_sync_hollow_event {
session.send_rpc_arg(210, &ptc_sync_hollow_event).await?;
session
.send_rpc_arg(PTC_SYNC_HOLLOW_EVENT_INFO_ID, &ptc_sync_hollow_event)
.await?;
}
let pos = PtcPositionInHollowChangedArg {
@ -30,17 +34,20 @@ pub async fn on_rpc_hollow_move_arg(
position: destination_pos,
};
session.send_rpc_arg(141, &pos).await?;
session
.send_rpc_ret(RpcHollowMoveRet::new(
.send_rpc_arg(PTC_POSITION_IN_HOLLOW_CHANGED_ID, &pos)
.await?;
Ok(RpcHollowMoveRet::new(
arg.hollow_level,
*arg.positions.last().unwrap(),
))
.await
}
pub async fn on_rpc_end_battle_arg(session: &NetworkSession, arg: &RpcEndBattleArg) -> Result<()> {
pub async fn on_rpc_end_battle(
session: &NetworkSession,
arg: &RpcEndBattleArg,
) -> Result<RpcEndBattleRet> {
tracing::info!("RpcEndBattle: {:?}", &arg);
let player_uid = session.get_player_uid();
@ -49,7 +56,9 @@ pub async fn on_rpc_end_battle_arg(session: &NetworkSession, arg: &RpcEndBattleA
let (sync_event, hollow_finished) = hollow_grid_manager.battle_finished();
if !hollow_finished {
session.send_rpc_arg(210, &sync_event).await?;
session
.send_rpc_arg(PTC_SYNC_HOLLOW_EVENT_INFO_ID, &sync_event)
.await?;
} else {
let dungeon_manager = session.context.dungeon_manager.borrow();
let _ = *dungeon_manager
@ -66,7 +75,7 @@ pub async fn on_rpc_end_battle_arg(session: &NetworkSession, arg: &RpcEndBattleA
};
session
.send_rpc_arg(148, &ptc_dungeon_quest_finished)
.send_rpc_arg(PTC_DUNGEON_QUEST_FINISHED_ID, &ptc_dungeon_quest_finished)
.await?;
}
@ -80,7 +89,7 @@ pub async fn on_rpc_end_battle_arg(session: &NetworkSession, arg: &RpcEndBattleA
session
.send_rpc_arg(
124,
PTC_SYNC_HOLLOW_GRID_MAPS_ID,
&hollow_grid_manager.sync_hollow_maps(player_uid, dungeon_manager.get_cur_scene_uid()),
)
.await?;
@ -92,23 +101,26 @@ pub async fn on_rpc_end_battle_arg(session: &NetworkSession, arg: &RpcEndBattleA
};
session
.send_rpc_arg(141, &ptc_position_in_hollow_changed)
.send_rpc_arg(
PTC_POSITION_IN_HOLLOW_CHANGED_ID,
&ptc_position_in_hollow_changed,
)
.await?;
session.send_rpc_arg(118, &ptc_enter_scene).await?;
session
.send_rpc_ret(RpcEndBattleRet::new(
.send_rpc_arg(PTC_ENTER_SCENE_ID, &ptc_enter_scene)
.await?;
Ok(RpcEndBattleRet::new(
hollow_grid_manager.get_cur_event_template_id(),
HashMap::new(),
))
.await
}
pub async fn on_rpc_run_hollow_event_graph_arg(
pub async fn on_rpc_run_hollow_event_graph(
session: &mut NetworkSession,
arg: &RpcRunHollowEventGraphArg,
) -> Result<()> {
) -> Result<RpcRunHollowEventGraphRet> {
tracing::info!("Run hollow event graph {:?}", arg);
let scene_uid = session.get_player().scene_uid.unwrap();
@ -132,14 +144,20 @@ pub async fn on_rpc_run_hollow_event_graph_arg(
},
specials: phashmap![],
};
session.send_rpc_arg(210, &finish_perform).await?;
session
.send_rpc_arg(PTC_SYNC_HOLLOW_EVENT_INFO_ID, &finish_perform)
.await?;
let hollow_grid_manager = session.context.hollow_grid_manager.borrow();
let (ptc_hollow_grid, ptc_sync_hollow_event) = hollow_grid_manager.move_to(22, scene_uid);
session.send_rpc_arg(114, &ptc_hollow_grid).await?;
session
.send_rpc_arg(PTC_HOLLOW_GRID_ID, &ptc_hollow_grid)
.await?;
if let Some(ptc_sync_hollow_event) = ptc_sync_hollow_event {
session.send_rpc_arg(210, &ptc_sync_hollow_event).await?;
session
.send_rpc_arg(PTC_SYNC_HOLLOW_EVENT_INFO_ID, &ptc_sync_hollow_event)
.await?;
}
} else {
let hollow_grid_manager = session.context.hollow_grid_manager.borrow();
@ -151,9 +169,13 @@ pub async fn on_rpc_run_hollow_event_graph_arg(
);
if !hollow_finished {
session.send_rpc_arg(210, &sync_hollow_event).await?;
session
.send_rpc_arg(PTC_SYNC_HOLLOW_EVENT_INFO_ID, &sync_hollow_event)
.await?;
}
session.send_rpc_arg(114, &hollow_grid).await?;
session
.send_rpc_arg(PTC_HOLLOW_GRID_ID, &hollow_grid)
.await?;
if hollow_finished {
let dungeon_manager = session.context.dungeon_manager.borrow();
@ -171,7 +193,7 @@ pub async fn on_rpc_run_hollow_event_graph_arg(
};
session
.send_rpc_arg(148, &ptc_dungeon_quest_finished)
.send_rpc_arg(PTC_DUNGEON_QUEST_FINISHED_ID, &ptc_dungeon_quest_finished)
.await?;
}
@ -190,12 +212,15 @@ pub async fn on_rpc_run_hollow_event_graph_arg(
};
session
.send_rpc_arg(141, &ptc_position_in_hollow_changed)
.send_rpc_arg(
PTC_POSITION_IN_HOLLOW_CHANGED_ID,
&ptc_position_in_hollow_changed,
)
.await?;
session
.send_rpc_arg(
118,
PTC_ENTER_SCENE_ID,
dungeon_manager
.enter_battle(battle_scene_uid)
.send_changes(session)
@ -205,13 +230,13 @@ pub async fn on_rpc_run_hollow_event_graph_arg(
}
}
session.send_rpc_ret(RpcRunHollowEventGraphRet::new()).await
Ok(RpcRunHollowEventGraphRet::new())
}
pub async fn on_rpc_start_hollow_quest_arg(
pub async fn on_rpc_start_hollow_quest(
session: &NetworkSession,
arg: &RpcStartHollowQuestArg,
) -> Result<()> {
) -> Result<RpcStartHollowQuestRet> {
tracing::info!("start hollow quest: {arg:?}");
// Set avatar HP properties
@ -223,12 +248,10 @@ pub async fn on_rpc_start_hollow_quest_arg(
.find(|(uid, _)| **uid == *avatar_uid)
.map(|(_, item)| item)
else {
return session
.send_rpc_ret(RpcStartHollowQuestRet::error(
return Ok(RpcStartHollowQuestRet::error(
ErrorCode::ObjectNotExist,
Vec::new(),
))
.await;
));
};
let avatar_config = data::iter_avatar_config_collection()
@ -241,7 +264,9 @@ pub async fn on_rpc_start_hollow_quest_arg(
changed_properties: phashmap![(1, avatar_config.hp), (111, avatar_config.hp)],
};
session.send_rpc_arg(129, &update_properties).await?;
session
.send_rpc_arg(PTC_PROPERTY_CHANGED_ID, &update_properties)
.await?;
}
let dungeon_manager = session.context.dungeon_manager.borrow();
@ -287,7 +312,7 @@ pub async fn on_rpc_start_hollow_quest_arg(
session
.send_rpc_arg(
124,
PTC_SYNC_HOLLOW_GRID_MAPS_ID,
&hollow_grid_manager.sync_hollow_maps(session.get_player_uid(), scene_uid),
)
.await?;
@ -299,7 +324,10 @@ pub async fn on_rpc_start_hollow_quest_arg(
};
session
.send_rpc_arg(141, &ptc_position_in_hollow_changed)
.send_rpc_arg(
PTC_POSITION_IN_HOLLOW_CHANGED_ID,
&ptc_position_in_hollow_changed,
)
.await?;
let ptc_sync_hollow_event_info = PtcSyncHollowEventInfoArg {
@ -321,9 +349,11 @@ pub async fn on_rpc_start_hollow_quest_arg(
};
session
.send_rpc_arg(210, &ptc_sync_hollow_event_info)
.send_rpc_arg(PTC_SYNC_HOLLOW_EVENT_INFO_ID, &ptc_sync_hollow_event_info)
.await?;
session.send_rpc_arg(118, &ptc_enter_scene).await?;
session.send_rpc_ret(RpcStartHollowQuestRet::new()).await
session
.send_rpc_arg(PTC_ENTER_SCENE_ID, &ptc_enter_scene)
.await?;
Ok(RpcStartHollowQuestRet::new())
}

View file

@ -5,32 +5,31 @@ use crate::game::util;
const DEFAULT_ACCOUNT_ID: u64 = 1337;
pub async fn on_rpc_login_arg(session: &NetworkSession, arg: &RpcLoginArg) -> Result<()> {
pub async fn on_rpc_login(session: &NetworkSession, arg: &RpcLoginArg) -> Result<RpcLoginRet> {
tracing::info!("Received rpc login arg: {}", arg.account_name);
*session.get_account_mut() = util::create_default_account(DEFAULT_ACCOUNT_ID);
session
.send_rpc_ret(RpcLoginRet::new(
Ok(RpcLoginRet::new(
session.ns_prop_mgr.serialize_account_info(),
))
.await
}
pub async fn on_ptc_get_server_timestamp_arg(
session: &NetworkSession,
pub async fn on_ptc_get_server_timestamp(
_session: &NetworkSession,
_arg: &PtcGetServerTimestampArg,
) -> Result<()> {
session
.send_rpc_ret(PtcGetServerTimestampRet::new(
) -> Result<PtcGetServerTimestampRet> {
Ok(PtcGetServerTimestampRet::new(
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis() as u64,
0,
))
.await
}
pub async fn on_rpc_keep_alive_arg(session: &NetworkSession, _arg: &RpcKeepAliveArg) -> Result<()> {
session.send_rpc_ret(RpcKeepAliveRet::new()).await
pub async fn on_rpc_keep_alive(
_session: &NetworkSession,
_arg: &RpcKeepAliveArg,
) -> Result<RpcKeepAliveRet> {
Ok(RpcKeepAliveRet::new())
}

View file

@ -1,8 +1,8 @@
use super::*;
pub async fn on_rpc_get_player_mails_arg(
session: &NetworkSession,
pub async fn on_rpc_get_player_mails(
_session: &NetworkSession,
_arg: &RpcGetPlayerMailsArg,
) -> Result<()> {
session.send_rpc_ret(RpcGetPlayerMailsRet::new(0)).await
) -> Result<RpcGetPlayerMailsRet> {
Ok(RpcGetPlayerMailsRet::new(0))
}

View file

@ -9,10 +9,6 @@ mod role;
mod world;
mod yorozuya;
use super::NetworkSession;
use anyhow::Result;
use protocol::*;
pub use battle::*;
pub use beginner_procedure::*;
pub use hollow::*;
@ -23,3 +19,68 @@ pub use progression::*;
pub use role::*;
pub use world::*;
pub use yorozuya::*;
use super::NetworkSession;
use anyhow::Result;
use paste::paste;
use protocol::*;
macro_rules! protocol_handlers {
($($name:ident;)*) => {
pub trait ProtocolHandler {
async fn on_message(session: &mut NetworkSession, protocol_id: u16, payload: Vec<u8>) -> Result<()> {
use ::qwer::OctData;
use ::tracing::Instrument;
paste! {
match protocol_id {
$(::protocol::[<$name:snake:upper _ID>] => {
let arg = ::protocol::[<$name Arg>]::unmarshal_from(&mut &payload[..], 0)?;
let ret = [<on_$name:snake>](session, &arg)
.instrument(tracing::info_span!(stringify!([<on_$name:snake>]), protocol_id = protocol_id))
.await?;
session.send_rpc_ret(ret).await
}
)*
_ => {
tracing::warn!("Message with protocol id {protocol_id} wasn't handled!");
Ok(())
},
}
}
}
async fn send_rpc_ret(&self, data: impl ::qwer::OctData) -> Result<()>;
}
};
}
protocol_handlers! {
RpcLogin;
PtcGetServerTimestamp;
PtcPlayerOperation;
RpcAdvanceBeginnerProcedure;
RpcBattleReport;
RpcBeginnerbattleBegin;
RpcBeginnerbattleEnd;
RpcCheckYorozuyaInfoRefresh;
RpcCloseLevelChgTips;
RpcDelNewMap;
RpcEndBattle;
RpcEnterWorld;
RpcFinishActPerformShow;
RpcFinishEventGraphPerformShow;
RpcGetPlayerMails;
RpcHollowMove;
RpcInteractWithUnit;
RpcKeepAlive;
RpcLeaveCurDungeon;
RpcModNickName;
RpcPerformEnd;
RpcPerformJump;
RpcPerformTrigger;
RpcRunEventGraph;
RpcRunHollowEventGraph;
RpcSavePosInMainCity;
RpcStartHollowQuest;
}

View file

@ -1,36 +1,32 @@
use super::*;
pub async fn on_rpc_perform_trigger_arg(
session: &NetworkSession,
pub async fn on_rpc_perform_trigger(
_session: &NetworkSession,
arg: &RpcPerformTriggerArg,
) -> Result<()> {
session
.send_rpc_ret(RpcPerformTriggerRet::new(format!(
) -> Result<RpcPerformTriggerRet> {
Ok(RpcPerformTriggerRet::new(format!(
"{}-{}",
arg.perform_id, arg.perform_type
)))
.await
}
pub async fn on_rpc_perform_end_arg(
session: &NetworkSession,
pub async fn on_rpc_perform_end(
_session: &NetworkSession,
_arg: &RpcPerformEndArg,
) -> Result<()> {
session.send_rpc_ret(RpcPerformEndRet::new()).await
) -> Result<RpcPerformEndRet> {
Ok(RpcPerformEndRet::new())
}
pub async fn on_rpc_finish_a_c_t_perform_show_arg(
session: &NetworkSession,
_arg: &RpcFinishACTPerformShowArg,
) -> Result<()> {
session
.send_rpc_ret(RpcFinishACTPerformShowRet::new())
.await
pub async fn on_rpc_finish_act_perform_show(
_session: &NetworkSession,
_arg: &RpcFinishActPerformShowArg,
) -> Result<RpcFinishActPerformShowRet> {
Ok(RpcFinishActPerformShowRet::new())
}
pub async fn on_rpc_perform_jump_arg(
session: &NetworkSession,
pub async fn on_rpc_perform_jump(
_session: &NetworkSession,
_arg: &RpcPerformJumpArg,
) -> Result<()> {
session.send_rpc_ret(RpcPerformJumpRet::new()).await
) -> Result<RpcPerformJumpRet> {
Ok(RpcPerformJumpRet::new())
}

View file

@ -1,15 +1,15 @@
use super::*;
pub async fn on_rpc_close_level_chg_tips_arg(
session: &NetworkSession,
pub async fn on_rpc_close_level_chg_tips(
_session: &NetworkSession,
_arg: &RpcCloseLevelChgTipsArg,
) -> Result<()> {
session.send_rpc_ret(RpcCloseLevelChgTipsRet::new()).await
) -> Result<RpcCloseLevelChgTipsRet> {
Ok(RpcCloseLevelChgTipsRet::new())
}
pub async fn on_rpc_del_new_map_arg(
session: &NetworkSession,
pub async fn on_rpc_del_new_map(
_session: &NetworkSession,
_arg: &RpcDelNewMapArg,
) -> Result<()> {
session.send_rpc_ret(RpcDelNewMapRet::new()).await
) -> Result<RpcDelNewMapRet> {
Ok(RpcDelNewMapRet::new())
}

View file

@ -1,9 +1,9 @@
use super::*;
pub async fn on_rpc_mod_nick_name_arg(
pub async fn on_rpc_mod_nick_name(
session: &NetworkSession,
arg: &RpcModNickNameArg,
) -> Result<()> {
) -> Result<RpcModNickNameRet> {
tracing::info!("creating character");
let mut player = session.get_player_mut();
@ -19,6 +19,8 @@ pub async fn on_rpc_mod_nick_name_arg(
},
};
session.send_rpc_arg(101, &player_info_changed).await?;
session.send_rpc_ret(RpcModNickNameRet::new()).await
session
.send_rpc_arg(PTC_PLAYER_INFO_CHANGED_ID, &player_info_changed)
.await?;
Ok(RpcModNickNameRet::new())
}

View file

@ -8,10 +8,10 @@ use crate::game::util;
use super::*;
pub async fn on_rpc_run_event_graph_arg(
pub async fn on_rpc_run_event_graph(
session: &NetworkSession,
arg: &RpcRunEventGraphArg,
) -> Result<()> {
) -> Result<RpcRunEventGraphRet> {
tracing::info!("RunEventGraph requested");
let scene_unit_mgr = session.context.scene_unit_manager.borrow();
@ -42,14 +42,17 @@ pub async fn on_rpc_run_event_graph_arg(
},
);
session.send_rpc_arg(177, &ptc_sync_event_info).await?;
session.send_rpc_ret(RpcRunEventGraphRet::new()).await
session
.send_rpc_arg(PTC_SYNC_EVENT_INFO_ID, &ptc_sync_event_info)
.await?;
Ok(RpcRunEventGraphRet::new())
}
pub async fn on_rpc_finish_event_graph_perform_show_arg(
pub async fn on_rpc_finish_event_graph_perform_show(
session: &NetworkSession,
arg: &RpcFinishEventGraphPerformShowArg,
) -> Result<()> {
) -> Result<RpcFinishEventGraphPerformShowRet> {
tracing::info!("FinishEventGraphPerformShow");
let mut ptc_sync_event_info = PtcSyncEventInfoArg {
@ -74,16 +77,17 @@ pub async fn on_rpc_finish_event_graph_perform_show_arg(
},
);
session.send_rpc_arg(177, &ptc_sync_event_info).await?;
session
.send_rpc_ret(RpcFinishEventGraphPerformShowRet::new())
.await
.send_rpc_arg(PTC_SYNC_EVENT_INFO_ID, &ptc_sync_event_info)
.await?;
Ok(RpcFinishEventGraphPerformShowRet::new())
}
pub async fn on_rpc_interact_with_unit_arg(
pub async fn on_rpc_interact_with_unit(
session: &NetworkSession,
arg: &RpcInteractWithUnitArg,
) -> Result<()> {
) -> Result<RpcInteractWithUnitRet> {
tracing::info!("InteractWithUnit");
let scene_unit_mgr = session.context.scene_unit_manager.borrow();
@ -114,32 +118,34 @@ pub async fn on_rpc_interact_with_unit_arg(
},
);
session.send_rpc_arg(177, &ptc_sync_event_info).await?;
session.send_rpc_ret(RpcInteractWithUnitRet::new()).await
session
.send_rpc_arg(PTC_SYNC_EVENT_INFO_ID, &ptc_sync_event_info)
.await?;
Ok(RpcInteractWithUnitRet::new())
}
pub async fn on_rpc_leave_cur_dungeon_arg(
pub async fn on_rpc_leave_cur_dungeon(
session: &NetworkSession,
_arg: &RpcLeaveCurDungeonArg,
) -> Result<()> {
) -> Result<RpcLeaveCurDungeonRet> {
Box::pin(enter_main_city(session)).await?;
session.send_rpc_ret(RpcLeaveCurDungeonRet::new()).await
Ok(RpcLeaveCurDungeonRet::new())
}
pub async fn on_ptc_player_operation_arg(
session: &NetworkSession,
pub async fn on_ptc_player_operation(
_session: &NetworkSession,
_arg: &PtcPlayerOperationArg,
) -> Result<()> {
session.send_rpc_ret(PtcPlayerOperationRet::new()).await
) -> Result<PtcPlayerOperationRet> {
Ok(PtcPlayerOperationRet::new())
}
pub async fn on_rpc_save_pos_in_main_city_arg(
session: &NetworkSession,
pub async fn on_rpc_save_pos_in_main_city(
_session: &NetworkSession,
_arg: &RpcSavePosInMainCityArg,
) -> Result<()> {
) -> Result<RpcSavePosInMainCityRet> {
tracing::info!("MainCity pos updated");
session.send_rpc_ret(RpcSavePosInMainCityRet::new()).await
Ok(RpcSavePosInMainCityRet::new())
}
fn create_player(id: u64) -> PlayerInfo {
@ -171,7 +177,7 @@ pub async fn enter_main_city(session: &NetworkSession) -> Result<()> {
session
.send_rpc_arg(
243,
PTC_ENTER_SECTION_ID,
dungeon_manager
.enter_scene_section(hall_scene_uid, 2)
.unwrap(),
@ -179,12 +185,15 @@ pub async fn enter_main_city(session: &NetworkSession) -> Result<()> {
.await?;
session
.send_rpc_arg(180, &scene_unit_mgr.sync(hall_scene_uid, 2))
.send_rpc_arg(
PTC_SYNC_SCENE_UNIT_ID,
&scene_unit_mgr.sync(hall_scene_uid, 2),
)
.await?;
session
.send_rpc_arg(
118,
PTC_ENTER_SCENE_ID,
dungeon_manager
.enter_main_city()?
.send_changes(session)
@ -193,10 +202,10 @@ pub async fn enter_main_city(session: &NetworkSession) -> Result<()> {
.await
}
pub async fn on_rpc_enter_world_arg(
pub async fn on_rpc_enter_world(
session: &NetworkSession,
_arg: &RpcEnterWorldArg,
) -> Result<()> {
) -> Result<RpcEnterWorldRet> {
let account = session.get_account();
let id = *account.players.as_ref().unwrap().first().unwrap(); // get first id from list
@ -209,8 +218,8 @@ pub async fn on_rpc_enter_world_arg(
item_manager.add_resource(100, 1337);
for avatar_id in data::iter_avatar_config_collection()
.filter(|c| c.camp != 0)
.map(|c| c.id)
.filter(|id| *id < 2000)
{
item_manager.unlock_avatar(avatar_id);
}
@ -264,7 +273,7 @@ pub async fn on_rpc_enter_world_arg(
let fresh_scene_uid = *dungeon_manager.create_fresh().unwrap();
session
.send_rpc_arg(
118,
PTC_ENTER_SCENE_ID,
dungeon_manager
.enter_scene(fresh_scene_uid)
.unwrap()
@ -274,8 +283,16 @@ pub async fn on_rpc_enter_world_arg(
}
session
.send_rpc_ret(RpcEnterWorldRet::new(
.send_rpc_arg(
PTC_SYNC_SCENE_TIME_ID,
&PtcSyncSceneTimeArg {
timestamp: 3600 * 8 * 1000,
last_timestamp: 0,
},
)
.await?;
Ok(RpcEnterWorldRet::new(
session.ns_prop_mgr.serialize_player_info(),
))
.await
}

View file

@ -1,10 +1,8 @@
use super::*;
pub async fn on_rpc_check_yorozuya_info_refresh_arg(
session: &NetworkSession,
pub async fn on_rpc_check_yorozuya_info_refresh(
_session: &NetworkSession,
_arg: &RpcCheckYorozuyaInfoRefreshArg,
) -> Result<()> {
session
.send_rpc_ret(RpcCheckYorozuyaInfoRefreshRet::new())
.await
) -> Result<RpcCheckYorozuyaInfoRefreshRet> {
Ok(RpcCheckYorozuyaInfoRefreshRet::new())
}

View file

@ -1,15 +1,8 @@
use anyhow::Result;
use paste::paste;
use tokio::io::AsyncReadExt;
use tokio::net::TcpStream;
use tracing::Instrument;
use protocol::*;
use qwer::ProtocolHeader;
use super::handlers::*;
use super::NetworkSession;
pub struct Packet {
#[allow(unused)]
pub to_channel: u16,
@ -83,190 +76,3 @@ impl From<ResponseBody> for Vec<u8> {
out
}
}
macro_rules! trait_handler {
($($name:ident $protocol_id:expr;)*) => {
#[allow(dead_code)]
#[allow(unused_variables)]
pub trait PacketHandler {
$(
paste! {
#[tracing::instrument(skip(session))]
async fn [<on_$name:snake>](session: &mut NetworkSession, arg: &$name) -> Result<()> {
[<on_$name:snake>](session, arg).await
}
}
)*
async fn on_message(session: &mut NetworkSession, protocol_id: u16, payload: Vec<u8>) -> Result<()> {
use ::qwer::OctData;
match protocol_id {
$(
$protocol_id => {
let arg = $name::unmarshal_from(&mut &payload[..], 0)?;
paste! {
Self::[<on_$name:snake>](session, &arg)
.instrument(tracing::info_span!(stringify!([<on_$name:snake>]), protocol_id = protocol_id))
.await
}
}
)*
_ => {
tracing::warn!("Unknown protocol id: {protocol_id}");
Ok(())
},
}
}
}
};
}
trait_handler! {
RpcLoginArg 100;
// PtcAbilityPopText 239;
// PtcAccountInfoChanged 102;
// PtcAvatarMapChanged 246;
// PtcBeforeGoToHollowLevel 145;
// PtcCardDisable 217;
// PtcChallengeQuestFinished 193;
// PtcClientCommon 110;
// PtcConfigUpdated 277;
// PtcDungeonQuestFinished 148;
// PtcDungeonQuestPrepareToFinish 136;
// PtcEnterScene 118;
// PtcEnterSceneBegin 200;
// PtcEnterSceneEnd 224;
// PtcEnterSection 243;
// PtcFairyInfoChanged 134;
// PtcFunctionSwitchMask 279;
PtcGetServerTimestampArg 204;
// PtcGoToHollowLevel 154;
// PtcHollowBlackout 268;
// PtcHollowGlobalEvent 138;
// PtcHollowGrid 114;
// PtcHollowPushBack 284;
// PtcHollowQuestUnlockedByMainCityQuest 201;
// PtcHpOrStressChanged 226;
// PtcItemChanged 117;
// PtcKickPlayer 184;
// PtcPauseMainCityTime 116;
// PtcPlayerInfoChangedArg 101;
// PtcPlayerMailsReceived 222;
// PtcPlayerMailsRemoved 225;
PtcPlayerOperationArg 203;
// PtcPopupWindow 206;
// PtcPosition 176;
// PtcPositionInHollowChanged 141;
// PtcPrepareSection 115;
// PtcPreventAddiction 270;
// PtcPropertyChanged 129;
// PtcQuestUnlocked 158;
// PtcReceivedChatMessage_Player2Client 165;
// PtcScenePropertyChanged 128;
// PtcShowCardGenreTips 276;
// PtcShowTips 207;
// PtcShowUnlockIDTips 278;
// PtcStaminaOverLevelPunish 147;
// PtcSyncEventInfo 177;
// PtcSyncHollowEventInfo 210;
// PtcSyncHollowGridMaps 124;
// PtcSyncSceneTime 249;
// PtcSyncSceneUnit 180;
// PtcTransformToHollowGrid 144;
// PtcUnlock 196;
// RpcAFKHollowQuest 241;
RpcAdvanceBeginnerProcedureArg 171;
// RpcAvatarAdvance 111;
// RpcAvatarLevelUp 107;
// RpcAvatarSkillLevelUp 197;
// RpcAvatarStarUp 108;
// RpcAvatarUnlockTalent 199;
// RpcAwardAllPlayerMail 257;
// RpcAwardPlayerMail 256;
// RpcBattleRebegin 286;
RpcBattleReportArg 125;
// RpcBeginArchiveBattleQuest 137;
RpcBeginnerbattleBeginArg 258;
RpcBeginnerbattleEndArg 285;
// RpcBeginnerbattleRebegin 250;
// RpcBuyAutoRecoveryItem 167;
// RpcBuyVHSCollection 269;
RpcCheckYorozuyaInfoRefreshArg 245;
// RpcClickHollowSystem 282;
RpcCloseLevelChgTipsArg 244;
// RpcCreatePlayer 104;
// RpcDebugPay 216;
RpcDelNewMapArg 287;
// RpcDelNewRamen 228;
// RpcDressEquipment 112;
// RpcEatRamen 283;
RpcEndBattleArg 251;
// RpcEndSlotMachine 186;
// RpcEnterSection 175;
RpcEnterWorldArg 105;
// RpcEquipDecompose 170;
// RpcEquipGacha 169;
// RpcEquipLock 172;
// RpcEquipmentLevelUp 130;
// RpcEquipmentStarUp 131;
RpcFinishACTPerformShowArg 185;
// RpcFinishBlackout 267;
RpcFinishEventGraphPerformShowArg 187;
// RpcFinishGraphInClient 146;
// RpcGMCommand 113;
// RpcGacha 173;
// RpcGetArchiveReward 166;
// RpcGetAuthKey 280;
// RpcGetChatHistory_Client2Player 159;
RpcGetPlayerMailsArg 221;
// RpcGetShopInfo 122;
// RpcGetYorozuyaInfo 182;
// RpcGiveUpDungeonQuest 142;
// RpcHollowChangeAffix 143;
RpcHollowMoveArg 248;
// RpcHollowShopping 213;
RpcInteractWithUnitArg 181;
// RpcItemConvert 281;
RpcKeepAliveArg 149;
RpcLeaveCurDungeonArg 140;
// RpcLeaveWorld 190;
// RpcLogin 100;
// RpcLogout 103;
// RpcMakeChoiceOfEvent 214;
// RpcMakeInitiativeItem 234;
RpcModNickNameArg 215;
// RpcOpenVHSStore 135;
RpcPerformEndArg 255;
RpcPerformJumpArg 254;
RpcPerformTriggerArg 253;
// RpcPrepareNextHollowEnd 252;
// RpcReadPlayerMail 263;
// RpcReceiveVHSStoreReward 227;
// RpcReenterWorld 150;
// RpcRefreshShop 237;
// RpcRefreshVHSTrending 235;
// RpcRemoveHollowCurse 229;
// RpcRemovePlayerMailsFromClient 264;
RpcRunEventGraphArg 179;
RpcRunHollowEventGraphArg 211;
RpcSavePosInMainCityArg 202;
// RpcSelectChallenge 236;
// RpcSelectVHSCollection 219;
// RpcSendChatMessage_Client2Player 163;
// RpcSetBGM 273;
// RpcSetMainCityObjectState 274;
// RpcSetPlayerMailOld 265;
// RpcShopping 230;
RpcStartHollowQuestArg 183;
// RpcSwitchHollowRank 198;
// RpcUndressEquipment 109;
// RpcUseInitiativeItem 220;
// RpcWeaponDecompose 120;
// RpcWeaponDress 132;
// RpcWeaponLevelUp 126;
// RpcWeaponLock 119;
// RpcWeaponRefine 232;
// RpcWeaponStarUp 127;
// RpcWeaponUnDress 139;
// RpcYorozuyaManualReceiveReward 168;
}

View file

@ -11,7 +11,8 @@ use tokio::sync::{Mutex, MutexGuard};
use crate::game::manager::net_stream;
use crate::game::GameContext;
use super::{packet::PacketHandler, Packet, RequestBody, ResponseBody};
use super::handlers::ProtocolHandler;
use super::{Packet, RequestBody, ResponseBody};
pub struct NetworkSession {
client_socket: Arc<Mutex<TcpStream>>,
@ -82,7 +83,35 @@ impl NetworkSession {
}
}
pub async fn send_rpc_ret(&self, data: impl OctData) -> Result<()> {
pub async fn send_rpc_arg(&self, protocol_id: u16, data: &impl OctData) -> Result<()> {
let header: Vec<u8> = ProtocolHeader::default().into();
let mut payload = Vec::new();
let mut cursor = Cursor::new(&mut payload);
data.marshal_to(&mut cursor, 0)?;
let body: Vec<u8> = RequestBody {
protocol_id,
payload,
}
.into();
let mut packet = Vec::new();
packet.extend(0_u16.to_le_bytes());
packet.extend(((body.len() + 2) as u32).to_le_bytes());
packet.extend((header.len() as u16).to_le_bytes());
packet.extend(header);
packet.extend(body);
packet.extend(0_u16.to_le_bytes()); // middleware count
self.client_socket().await.write_all(&packet).await?;
tracing::info!("Ptc with protocol id {protocol_id} sent");
Ok(())
}
}
impl ProtocolHandler for NetworkSession {
async fn send_rpc_ret(&self, data: impl OctData) -> Result<()> {
let header = ProtocolHeader {
is_rpc_ret: true,
rpc_arg_uid: self.cur_rpc_uid,
@ -111,33 +140,4 @@ impl NetworkSession {
self.client_socket().await.write_all(&packet).await?;
Ok(())
}
pub async fn send_rpc_arg(&self, protocol_id: u16, data: &impl OctData) -> Result<()> {
let header: Vec<u8> = ProtocolHeader::default().into();
let mut payload = Vec::new();
let mut cursor = Cursor::new(&mut payload);
data.marshal_to(&mut cursor, 0)?;
let body: Vec<u8> = RequestBody {
protocol_id,
payload,
}
.into();
let mut packet = Vec::new();
packet.extend(0_u16.to_le_bytes());
packet.extend(((body.len() + 2) as u32).to_le_bytes());
packet.extend((header.len() as u16).to_le_bytes());
packet.extend(header);
packet.extend(body);
packet.extend(0_u16.to_le_bytes()); // middleware count
self.client_socket().await.write_all(&packet).await?;
tracing::info!("Ptc with protocol id {protocol_id} sent");
Ok(())
}
}
// Auto implemented
impl PacketHandler for NetworkSession {}

View file

@ -4,10 +4,12 @@ use qwer::{OctData, PropertyDoubleKeyHashMap, PropertyHashMap, PropertyHashSet};
mod enums;
mod polymorphic;
mod protocol_id;
mod rpc_ptc;
mod structs;
pub use enums::*;
pub use polymorphic::*;
pub use protocol_id::*;
pub use rpc_ptc::*;
pub use structs::*;

146
protocol/src/protocol_id.rs Normal file
View file

@ -0,0 +1,146 @@
pub const RPC_LOGIN_ID: u16 = 100;
pub const PTC_PLAYER_INFO_CHANGED_ID: u16 = 101;
pub const PTC_ACCOUNT_INFO_CHANGED_ID: u16 = 102;
pub const RPC_LOGOUT_ID: u16 = 103;
pub const RPC_CREATE_PLAYER_ID: u16 = 104;
pub const RPC_ENTER_WORLD_ID: u16 = 105;
pub const RPC_AVATAR_LEVEL_UP_ID: u16 = 107;
pub const RPC_AVATAR_STAR_UP_ID: u16 = 108;
pub const RPC_UNDRESS_EQUIPMENT_ID: u16 = 109;
pub const PTC_CLIENT_COMMON_ID: u16 = 110;
pub const RPC_AVATAR_ADVANCE_ID: u16 = 111;
pub const RPC_DRESS_EQUIPMENT_ID: u16 = 112;
pub const RPC_GM_COMMAND_ID: u16 = 113;
pub const PTC_HOLLOW_GRID_ID: u16 = 114;
pub const PTC_PREPARE_SECTION_ID: u16 = 115;
pub const PTC_PAUSE_MAIN_CITY_TIME_ID: u16 = 116;
pub const PTC_ITEM_CHANGED_ID: u16 = 117;
pub const PTC_ENTER_SCENE_ID: u16 = 118;
pub const RPC_WEAPON_LOCK_ID: u16 = 119;
pub const RPC_WEAPON_DECOMPOSE_ID: u16 = 120;
pub const RPC_GET_SHOP_INFO_ID: u16 = 122;
pub const PTC_SYNC_HOLLOW_GRID_MAPS_ID: u16 = 124;
pub const RPC_BATTLE_REPORT_ID: u16 = 125;
pub const RPC_WEAPON_LEVEL_UP_ID: u16 = 126;
pub const RPC_WEAPON_STAR_UP_ID: u16 = 127;
pub const PTC_SCENE_PROPERTY_CHANGED_ID: u16 = 128;
pub const PTC_PROPERTY_CHANGED_ID: u16 = 129;
pub const RPC_EQUIPMENT_LEVEL_UP_ID: u16 = 130;
pub const RPC_EQUIPMENT_STAR_UP_ID: u16 = 131;
pub const RPC_WEAPON_DRESS_ID: u16 = 132;
pub const PTC_FAIRY_INFO_CHANGED_ID: u16 = 134;
pub const RPC_OPEN_VHS_STORE_ID: u16 = 135;
pub const PTC_DUNGEON_QUEST_PREPARE_TO_FINISH_ID: u16 = 136;
pub const RPC_BEGIN_ARCHIVE_BATTLE_QUEST_ID: u16 = 137;
pub const PTC_HOLLOW_GLOBAL_EVENT_ID: u16 = 138;
pub const RPC_WEAPON_UN_DRESS_ID: u16 = 139;
pub const RPC_LEAVE_CUR_DUNGEON_ID: u16 = 140;
pub const PTC_POSITION_IN_HOLLOW_CHANGED_ID: u16 = 141;
pub const RPC_GIVE_UP_DUNGEON_QUEST_ID: u16 = 142;
pub const RPC_HOLLOW_CHANGE_AFFIX_ID: u16 = 143;
pub const PTC_TRANSFORM_TO_HOLLOW_GRID_ID: u16 = 144;
pub const PTC_BEFORE_GO_TO_HOLLOW_LEVEL_ID: u16 = 145;
pub const RPC_FINISH_GRAPH_IN_CLIENT_ID: u16 = 146;
pub const PTC_STAMINA_OVER_LEVEL_PUNISH_ID: u16 = 147;
pub const PTC_DUNGEON_QUEST_FINISHED_ID: u16 = 148;
pub const RPC_KEEP_ALIVE_ID: u16 = 149;
pub const RPC_REENTER_WORLD_ID: u16 = 150;
pub const PTC_GO_TO_HOLLOW_LEVEL_ID: u16 = 154;
pub const PTC_QUEST_UNLOCKED_ID: u16 = 158;
pub const RPC_GET_CHAT_HISTORY_CLIENT2_PLAYER_ID: u16 = 159;
pub const RPC_SEND_CHAT_MESSAGE_CLIENT2_PLAYER_ID: u16 = 163;
pub const PTC_RECEIVED_CHAT_MESSAGE_PLAYER2_CLIENT_ID: u16 = 165;
pub const RPC_GET_ARCHIVE_REWARD_ID: u16 = 166;
pub const RPC_BUY_AUTO_RECOVERY_ITEM_ID: u16 = 167;
pub const RPC_YOROZUYA_MANUAL_RECEIVE_REWARD_ID: u16 = 168;
pub const RPC_EQUIP_GACHA_ID: u16 = 169;
pub const RPC_EQUIP_DECOMPOSE_ID: u16 = 170;
pub const RPC_ADVANCE_BEGINNER_PROCEDURE_ID: u16 = 171;
pub const RPC_EQUIP_LOCK_ID: u16 = 172;
pub const RPC_GACHA_ID: u16 = 173;
pub const RPC_ENTER_SECTION_ID: u16 = 175;
pub const PTC_POSITION_ID: u16 = 176;
pub const PTC_SYNC_EVENT_INFO_ID: u16 = 177;
pub const RPC_RUN_EVENT_GRAPH_ID: u16 = 179;
pub const PTC_SYNC_SCENE_UNIT_ID: u16 = 180;
pub const RPC_INTERACT_WITH_UNIT_ID: u16 = 181;
pub const RPC_GET_YOROZUYA_INFO_ID: u16 = 182;
pub const RPC_START_HOLLOW_QUEST_ID: u16 = 183;
pub const PTC_KICK_PLAYER_ID: u16 = 184;
pub const RPC_FINISH_ACT_PERFORM_SHOW_ID: u16 = 185;
pub const RPC_END_SLOT_MACHINE_ID: u16 = 186;
pub const RPC_FINISH_EVENT_GRAPH_PERFORM_SHOW_ID: u16 = 187;
pub const RPC_LEAVE_WORLD_ID: u16 = 190;
pub const PTC_CHALLENGE_QUEST_FINISHED_ID: u16 = 193;
pub const PTC_UNLOCK_ID: u16 = 196;
pub const RPC_AVATAR_SKILL_LEVEL_UP_ID: u16 = 197;
pub const RPC_SWITCH_HOLLOW_RANK_ID: u16 = 198;
pub const RPC_AVATAR_UNLOCK_TALENT_ID: u16 = 199;
pub const PTC_ENTER_SCENE_BEGIN_ID: u16 = 200;
pub const PTC_HOLLOW_QUEST_UNLOCKED_BY_MAIN_CITY_QUEST_ID: u16 = 201;
pub const RPC_SAVE_POS_IN_MAIN_CITY_ID: u16 = 202;
pub const PTC_PLAYER_OPERATION_ID: u16 = 203;
pub const PTC_GET_SERVER_TIMESTAMP_ID: u16 = 204;
pub const PTC_POPUP_WINDOW_ID: u16 = 206;
pub const PTC_SHOW_TIPS_ID: u16 = 207;
pub const PTC_SYNC_HOLLOW_EVENT_INFO_ID: u16 = 210;
pub const RPC_RUN_HOLLOW_EVENT_GRAPH_ID: u16 = 211;
pub const RPC_HOLLOW_SHOPPING_ID: u16 = 213;
pub const RPC_MAKE_CHOICE_OF_EVENT_ID: u16 = 214;
pub const RPC_MOD_NICK_NAME_ID: u16 = 215;
pub const RPC_DEBUG_PAY_ID: u16 = 216;
pub const PTC_CARD_DISABLE_ID: u16 = 217;
pub const RPC_SELECT_VHS_COLLECTION_ID: u16 = 219;
pub const RPC_USE_INITIATIVE_ITEM_ID: u16 = 220;
pub const RPC_GET_PLAYER_MAILS_ID: u16 = 221;
pub const PTC_PLAYER_MAILS_RECEIVED_ID: u16 = 222;
pub const PTC_ENTER_SCENE_END_ID: u16 = 224;
pub const PTC_PLAYER_MAILS_REMOVED_ID: u16 = 225;
pub const PTC_HP_OR_STRESS_CHANGED_ID: u16 = 226;
pub const RPC_RECEIVE_VHS_STORE_REWARD_ID: u16 = 227;
pub const RPC_DEL_NEW_RAMEN_ID: u16 = 228;
pub const RPC_REMOVE_HOLLOW_CURSE_ID: u16 = 229;
pub const RPC_SHOPPING_ID: u16 = 230;
pub const RPC_WEAPON_REFINE_ID: u16 = 232;
pub const RPC_MAKE_INITIATIVE_ITEM_ID: u16 = 234;
pub const RPC_REFRESH_VHS_TRENDING_ID: u16 = 235;
pub const RPC_SELECT_CHALLENGE_ID: u16 = 236;
pub const RPC_REFRESH_SHOP_ID: u16 = 237;
pub const PTC_ABILITY_POP_TEXT_ID: u16 = 239;
pub const RPC_AFK_HOLLOW_QUEST_ID: u16 = 241;
pub const PTC_ENTER_SECTION_ID: u16 = 243;
pub const RPC_CLOSE_LEVEL_CHG_TIPS_ID: u16 = 244;
pub const RPC_CHECK_YOROZUYA_INFO_REFRESH_ID: u16 = 245;
pub const PTC_AVATAR_MAP_CHANGED_ID: u16 = 246;
pub const RPC_HOLLOW_MOVE_ID: u16 = 248;
pub const PTC_SYNC_SCENE_TIME_ID: u16 = 249;
pub const RPC_BEGINNERBATTLE_REBEGIN_ID: u16 = 250;
pub const RPC_END_BATTLE_ID: u16 = 251;
pub const RPC_PREPARE_NEXT_HOLLOW_END_ID: u16 = 252;
pub const RPC_PERFORM_TRIGGER_ID: u16 = 253;
pub const RPC_PERFORM_JUMP_ID: u16 = 254;
pub const RPC_PERFORM_END_ID: u16 = 255;
pub const RPC_AWARD_PLAYER_MAIL_ID: u16 = 256;
pub const RPC_AWARD_ALL_PLAYER_MAIL_ID: u16 = 257;
pub const RPC_BEGINNERBATTLE_BEGIN_ID: u16 = 258;
pub const RPC_READ_PLAYER_MAIL_ID: u16 = 263;
pub const RPC_REMOVE_PLAYER_MAILS_FROM_CLIENT_ID: u16 = 264;
pub const RPC_SET_PLAYER_MAIL_OLD_ID: u16 = 265;
pub const RPC_FINISH_BLACKOUT_ID: u16 = 267;
pub const PTC_HOLLOW_BLACKOUT_ID: u16 = 268;
pub const RPC_BUY_VHS_COLLECTION_ID: u16 = 269;
pub const PTC_PREVENT_ADDICTION_ID: u16 = 270;
pub const RPC_SET_BGM_ID: u16 = 273;
pub const RPC_SET_MAIN_CITY_OBJECT_STATE_ID: u16 = 274;
pub const PTC_SHOW_CARD_GENRE_TIPS_ID: u16 = 276;
pub const PTC_CONFIG_UPDATED_ID: u16 = 277;
pub const PTC_SHOW_UNLOCK_ID_TIPS_ID: u16 = 278;
pub const PTC_FUNCTION_SWITCH_MASK_ID: u16 = 279;
pub const RPC_GET_AUTH_KEY_ID: u16 = 280;
pub const RPC_ITEM_CONVERT_ID: u16 = 281;
pub const RPC_CLICK_HOLLOW_SYSTEM_ID: u16 = 282;
pub const RPC_EAT_RAMEN_ID: u16 = 283;
pub const PTC_HOLLOW_PUSH_BACK_ID: u16 = 284;
pub const RPC_BEGINNERBATTLE_END_ID: u16 = 285;
pub const RPC_BATTLE_REBEGIN_ID: u16 = 286;
pub const RPC_DEL_NEW_MAP_ID: u16 = 287;

View file

@ -117,7 +117,7 @@ pub struct RpcModNickNameArg {
}
#[derive(OctData, Clone, Debug)]
pub struct RpcFinishACTPerformShowArg {
pub struct RpcFinishActPerformShowArg {
pub moment: ACTPerformShowMoment,
pub step: u8,
}
@ -337,6 +337,12 @@ pub struct PtcDungeonQuestFinishedArg {
pub statistics: PropertyHashMap<QuestStatisticsType, u64>,
}
#[derive(OctData, Debug)]
pub struct PtcSyncSceneTimeArg {
pub timestamp: u64,
pub last_timestamp: u64,
}
ret! {
struct RpcLoginRet {
account_info: PropertyBlob,
@ -369,7 +375,7 @@ ret! {
struct RpcModNickNameRet {
}
struct RpcFinishACTPerformShowRet {
struct RpcFinishActPerformShowRet {
}
struct RpcKeepAliveRet {