feat!: Refactor, Update to version 2.5.x, Add Battle Scepter

This commit is contained in:
amizing25
2024-09-16 13:10:28 +07:00
parent 88f3025333
commit 6e97b516f4
38 changed files with 722000 additions and 15463 deletions

View File

@@ -1,5 +1,5 @@
[workspace] [workspace]
members = [ "gameserver", "proto", "sdkserver"] members = ["gameserver", "proto", "sdkserver"]
resolver = "2" resolver = "2"
[workspace.package] [workspace.package]
@@ -54,6 +54,8 @@ tracing-subscriber = { version = "0.3.18", features = [
tracing-bunyan-formatter = "0.3.9" tracing-bunyan-formatter = "0.3.9"
proto = { path = "proto/" } proto = { path = "proto/" }
proto-derive = { path = "proto/proto-derive" }
[profile.release] [profile.release]
strip = true # Automatically strip symbols from the binary. strip = true # Automatically strip symbols from the binary.

File diff suppressed because it is too large Load Diff

View File

@@ -28,5 +28,6 @@ tracing-bunyan-formatter.workspace = true
prost.workspace = true prost.workspace = true
proto.workspace = true proto.workspace = true
proto-derive.workspace = true
rand.workspace = true rand.workspace = true

View File

@@ -2,6 +2,7 @@ use anyhow::Result;
mod logging; mod logging;
mod net; mod net;
mod tools;
mod util; mod util;
use logging::init_tracing; use logging::init_tracing;

View File

@@ -1,45 +1,29 @@
use anyhow::Result;
use proto::*; use proto::*;
use crate::{net::PlayerSession, util}; use crate::{net::PlayerSession, util};
pub async fn on_player_get_token_cs_req( pub async fn on_player_get_token_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
_body: &PlayerGetTokenCsReq, _body: &PlayerGetTokenCsReq,
) -> Result<()> { res: &mut PlayerGetTokenScRsp,
session ) {
.send( res.msg = String::from("OK");
CMD_PLAYER_GET_TOKEN_SC_RSP, res.uid = 25;
PlayerGetTokenScRsp {
retcode: 0,
msg: String::from("OK"),
uid: 25,
..Default::default()
},
)
.await
} }
pub async fn on_player_login_cs_req( pub async fn on_player_login_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
body: &PlayerLoginCsReq, body: &PlayerLoginCsReq,
) -> Result<()> { res: &mut PlayerLoginScRsp,
session ) {
.send( res.login_random = body.login_random;
CMD_PLAYER_LOGIN_SC_RSP, res.server_timestamp_ms = util::cur_timestamp_ms();
PlayerLoginScRsp { res.stamina = 240;
login_random: body.login_random, res.basic_info = Some(PlayerBasicInfo {
server_timestamp_ms: util::cur_timestamp_ms(),
stamina: 240,
basic_info: Some(PlayerBasicInfo {
nickname: String::from("RobinSR"), nickname: String::from("RobinSR"),
level: 70, level: 70,
world_level: 6, world_level: 6,
stamina: 240, stamina: 240,
..Default::default() ..Default::default()
}), });
..Default::default()
},
)
.await
} }

View File

@@ -2,25 +2,21 @@ use crate::net::tools::FreesrData;
use super::*; use super::*;
static UNLOCKED_AVATARS: [u32; 56] = [ static UNLOCKED_AVATARS: [u32; 57] = [
8001, 1001, 1002, 1003, 1004, 1005, 1006, 1008, 1009, 1013, 1101, 1102, 1103, 1104, 1105, 1106, 8001, 1001, 1002, 1003, 1004, 1005, 1006, 1008, 1009, 1013, 1101, 1102, 1103, 1104, 1105, 1106,
1107, 1108, 1109, 1110, 1111, 1112, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1210, 1107, 1108, 1109, 1110, 1111, 1112, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1210,
1211, 1212, 1213, 1214, 1215, 1217, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1312, 1211, 1212, 1213, 1214, 1215, 1217, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1312,
1315, 1310, 1314, 1218, 1221, 1220, 1222, 1223, 1315, 1310, 1314, 1218, 1221, 1220, 1222, 1223, 1317,
]; ];
pub async fn on_get_avatar_data_cs_req( pub async fn on_get_avatar_data_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
body: &GetAvatarDataCsReq, body: &GetAvatarDataCsReq,
) -> Result<()> { res: &mut GetAvatarDataScRsp,
) {
let json = FreesrData::load().await; let json = FreesrData::load().await;
session res.is_get_all = body.is_get_all;
.send( res.avatar_list = UNLOCKED_AVATARS
CMD_GET_AVATAR_DATA_SC_RSP,
GetAvatarDataScRsp {
retcode: 0,
is_get_all: body.is_get_all,
avatar_list: UNLOCKED_AVATARS
.iter() .iter()
.map(|id| { .map(|id| {
json.avatars json.avatars
@@ -45,12 +41,9 @@ pub async fn on_get_avatar_data_cs_req(
level: 1, level: 1,
}) })
.collect(), .collect(),
first_met_timestamp: 1712924677,
..Default::default() ..Default::default()
}) })
}) })
.collect(), .collect();
..Default::default()
},
)
.await
} }

View File

@@ -1,70 +1,53 @@
use std::collections::HashMap; use std::collections::HashMap;
use rand::Rng; use rand::Rng;
use rogue_magic_battle_unit_info::Item;
use crate::net::tools::{self, BattleType, Monster}; use crate::net::tools::{self, BattleType, Monster};
use super::*; use super::*;
pub async fn on_start_cocoon_stage_cs_req( pub async fn on_start_cocoon_stage_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
body: &StartCocoonStageCsReq, body: &StartCocoonStageCsReq,
) -> Result<()> { res: &mut StartCocoonStageScRsp,
) {
let battle_info = create_battle_info().await; let battle_info = create_battle_info().await;
let rsp = StartCocoonStageScRsp { res.prop_entity_id = body.prop_entity_id;
retcode: 0, res.cocoon_id = body.cocoon_id;
prop_entity_id: body.prop_entity_id, res.wave = body.wave;
cocoon_id: body.cocoon_id, res.battle_info = Some(battle_info);
wave: body.wave,
battle_info: Some(battle_info),
};
session.send(CMD_START_COCOON_STAGE_SC_RSP, rsp).await
} }
pub async fn on_pve_battle_result_cs_req( pub async fn on_pve_battle_result_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
body: &PveBattleResultCsReq, body: &PveBattleResultCsReq,
) -> Result<()> { res: &mut PveBattleResultScRsp,
session ) {
.send( res.end_status = body.end_status;
CMD_PVE_BATTLE_RESULT_SC_RSP, res.battle_id = body.battle_id;
PveBattleResultScRsp {
retcode: 0,
end_status: body.end_status,
battle_id: body.battle_id,
..Default::default()
},
)
.await
} }
pub async fn on_scene_cast_skill_cs_req( pub async fn on_scene_cast_skill_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
request: &SceneCastSkillCsReq, request: &SceneCastSkillCsReq,
) -> Result<()> { res: &mut SceneCastSkillScRsp,
) {
res.attacked_group_id = request.attacked_group_id;
let battle_info = create_battle_info().await; let battle_info = create_battle_info().await;
let mut resp = SceneCastSkillScRsp {
attacked_group_id: request.attacked_group_id,
retcode: 0,
..Default::default()
};
let targets = request let targets = request
.assist_monster_entity_id_list .hit_target_entity_id_list
.iter() .iter()
.filter(|id| **id > 30_000 || **id < 1_000) .filter(|id| **id > 30_000 || **id < 1_000)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if targets.is_empty() { if targets.is_empty() {
return session.send(CMD_SCENE_CAST_SKILL_SC_RSP, resp).await; return;
} }
resp.battle_info = Some(battle_info); res.battle_info = Some(battle_info);
session.send(CMD_SCENE_CAST_SKILL_SC_RSP, resp).await
} }
async fn create_battle_info() -> SceneBattleInfo { async fn create_battle_info() -> SceneBattleInfo {
@@ -237,11 +220,62 @@ async fn create_battle_info() -> SceneBattleInfo {
max_sp: 10_000, max_sp: 10_000,
}), }),
}), }),
skill_info: vec![],
}) })
} }
// monsters // monsters
battle_info.monster_wave_list = Monster::to_scene_monster_waves(&player.battle_config.monsters); battle_info.monster_wave_list = Monster::to_scene_monster_waves(&player.battle_config.monsters);
if !player.battle_config.scepters.is_empty() {
battle_info.rogue_magic_battle_info = Some(RogueMagicBattleInfo {
player_detail_info: Some(RogueMagicBattleUnitInfo {
item: Some(Item::BattleRogueMagicData(BattleRogueMagicData {
round_cnt: Some(BattleRogueMagicRoundCount {
hhfjaibgama: 3,
mmkolnbikjh: 0,
}),
battle_scepter_list: player
.battle_config
.scepters
.iter()
.map(|scepter| {
let mut battle_scepter = BattleRogueMagicScepter {
level: scepter.level,
scepter_id: scepter.id,
magic_unit_list: Vec::new(),
slot_count_map: HashMap::from([(3, 0), (4, 0), (5, 0)]),
};
let mut index = [0u32; 3];
for component in &scepter.components {
let (slot_type, locked) = match component.component_type {
tools::RogueMagicComponentType::Passive => (3u32, false),
tools::RogueMagicComponentType::Active => (4, true),
tools::RogueMagicComponentType::Attach => (5, false),
};
let slot_index = &mut index[slot_type as usize - 3];
battle_scepter.magic_unit_list.push(BattleRogueMagicUnit {
level: component.level,
unit_id: component.id,
slot_id: *slot_index,
locked,
counter_map: Default::default(),
});
*slot_index += 1;
*battle_scepter.slot_count_map.get_mut(&slot_type).unwrap() += 1;
}
battle_scepter
})
.collect(),
})),
}),
scepter: Some(Igefngnckog { ojibobnaikh: 5 }),
});
}
battle_info battle_info
} }

View File

@@ -8,37 +8,37 @@ use crate::{
use super::*; use super::*;
const SERVER_UID: u32 = 727;
const SERVER_HEAD_ICON: u32 = 201008;
const SERVER_CHAT_BUBBLE_ID: u32 = 220005;
const SERVER_CHAT_HISTORY: [&str; 4] = [
"'sync'",
"'mc {mc_id}' mc_id can be set from 8001 to 8006",
"'march {march_id}' march_id can be set 1001 or 1224",
"available command:",
];
pub async fn on_get_friend_login_info_cs_req( pub async fn on_get_friend_login_info_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
_: &GetFriendLoginInfoCsReq, _req: &GetFriendLoginInfoCsReq,
) -> Result<()> { res: &mut GetFriendLoginInfoScRsp,
session ) {
.send( res.friend_uid_list = vec![SERVER_UID];
CMD_GET_FRIEND_LOGIN_INFO_SC_RSP,
GetFriendLoginInfoScRsp {
mnacbpjeche: vec![727],
..Default::default()
},
)
.await
} }
pub async fn on_get_friend_list_info_cs_req( pub async fn on_get_friend_list_info_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
_: &GetFriendListInfoCsReq, _req: &GetFriendListInfoCsReq,
) -> Result<()> { res: &mut GetFriendListInfoScRsp,
session ) {
.send( res.friend_list = vec![FriendListInfo {
CMD_GET_FRIEND_LIST_INFO_SC_RSP,
GetFriendListInfoScRsp {
friend_list: vec![FriendListInfo {
friend_name: String::from("RobinSR"), friend_name: String::from("RobinSR"),
simple_info: Some(SimpleInfo { simple_info: Some(SimpleInfo {
uid: 727, uid: SERVER_UID,
platform_type: 3, platform_type: PlatformType::Pc.into(),
online_status: 1, online_status: FriendOnlineStatus::Online.into(),
head_icon: 201008, head_icon: SERVER_HEAD_ICON,
chat_bubble_id: 220005, chat_bubble_id: SERVER_CHAT_BUBBLE_ID,
level: 70, level: 70,
nickname: String::from("Server"), nickname: String::from("Server"),
signature: String::from("omg"), signature: String::from("omg"),
@@ -47,79 +47,52 @@ pub async fn on_get_friend_list_info_cs_req(
is_marked: true, is_marked: true,
sent_time: 0, sent_time: 0,
..Default::default() ..Default::default()
}], }];
..Default::default()
},
)
.await
} }
pub async fn on_get_private_chat_history_cs_req( pub async fn on_get_private_chat_history_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
req: &GetPrivateChatHistoryCsReq, req: &GetPrivateChatHistoryCsReq,
) -> Result<()> { res: &mut GetPrivateChatHistoryScRsp,
session ) {
.send( let cur_time = cur_timestamp_ms();
CMD_GET_PRIVATE_CHAT_HISTORY_SC_RSP, res.chat_list = SERVER_CHAT_HISTORY
GetPrivateChatHistoryScRsp { .iter()
chat_list: vec![ .map(|text| Chat {
Chat {
msg_type: MsgType::CustomText.into(), msg_type: MsgType::CustomText.into(),
sent_time: cur_timestamp_ms(), sent_time: cur_time,
text: "'sync'".to_string(), text: String::from(*text),
sender_uid: 727, sender_uid: SERVER_UID,
..Default::default() ..Default::default()
}, })
Chat { .collect();
msg_type: MsgType::CustomText.into(), res.to_uid = req.to_uid;
sent_time: cur_timestamp_ms(), res.from_uid = SERVER_UID;
text: "'mc {mc_id}' mc_id can be set from 8001 to 8006".to_string(),
sender_uid: 727,
..Default::default()
},
Chat {
msg_type: MsgType::CustomText.into(),
sent_time: cur_timestamp_ms(),
text: "'march {march_id}' march_id can be set 1001 or 1224".to_string(),
sender_uid: 727,
..Default::default()
},
Chat {
msg_type: MsgType::CustomText.into(),
sent_time: cur_timestamp_ms(),
text: "available command:".to_string(),
sender_uid: 727,
..Default::default()
},
],
sender_id: 0, // from
to_uid: req.to_uid, // to
..Default::default()
},
)
.await
} }
pub async fn on_send_msg_cs_req(session: &mut PlayerSession, body: &SendMsgCsReq) -> Result<()> { pub async fn on_send_msg_cs_req(
session: &mut PlayerSession,
body: &SendMsgCsReq,
_res: &mut SendMsgScRsp,
) {
let mut json = FreesrData::load().await; let mut json = FreesrData::load().await;
if let Some((cmd, args)) = parse_command(&body.text) { if let Some((cmd, args)) = parse_command(&body.text) {
match cmd { match cmd {
"sync" => { "sync" => {
sync_player(session, json).await?; sync_player(session, json).await;
session session
.send( .send(RevcMsgScNotify {
CMD_REVC_MSG_SC_NOTIFY,
RevcMsgScNotify {
msg_type: body.msg_type, msg_type: body.msg_type,
text: String::from("Inventory Synced"), text: String::from("Inventory Synced"),
emote: body.emote, emote: body.emote,
from_uid: 727, // from from_uid: SERVER_UID, // from
to_uid: 25, // to to_uid: 25, // to
chat_type: body.chat_type, chat_type: body.chat_type,
}, ..Default::default()
) })
.await?; .await
.unwrap();
} }
"mc" => { "mc" => {
let mc = MultiPathAvatar::from( let mc = MultiPathAvatar::from(
@@ -133,28 +106,25 @@ pub async fn on_send_msg_cs_req(session: &mut PlayerSession, body: &SendMsgCsReq
json.save().await; json.save().await;
session session
.send( .send(AvatarPathChangedNotify {
CMD_AVATAR_PATH_CHANGED_NOTIFY,
AvatarPathChangedNotify {
base_avatar_id: 8001, base_avatar_id: 8001,
cur_multi_path_avatar_type: mc as i32, cur_multi_path_avatar_type: mc as i32,
}, })
) .await
.await?; .unwrap();
session session
.send( .send(RevcMsgScNotify {
CMD_REVC_MSG_SC_NOTIFY,
RevcMsgScNotify {
msg_type: body.msg_type, msg_type: body.msg_type,
text: format!("Success change mc to {:#?}", mc), text: format!("Success change mc to {:#?}", mc),
emote: body.emote, emote: body.emote,
from_uid: 727, // from from_uid: SERVER_UID, // from
to_uid: 25, // to to_uid: 25, // to
chat_type: body.chat_type, chat_type: body.chat_type,
}, ..Default::default()
) })
.await?; .await
.unwrap();
} }
"march" => { "march" => {
let march_type = MultiPathAvatar::from( let march_type = MultiPathAvatar::from(
@@ -168,42 +138,29 @@ pub async fn on_send_msg_cs_req(session: &mut PlayerSession, body: &SendMsgCsReq
json.save().await; json.save().await;
session session
.send( .send(AvatarPathChangedNotify {
CMD_AVATAR_PATH_CHANGED_NOTIFY,
AvatarPathChangedNotify {
base_avatar_id: 1001, base_avatar_id: 1001,
cur_multi_path_avatar_type: march_type as i32, cur_multi_path_avatar_type: march_type as i32,
}, })
) .await
.await?; .unwrap();
session session
.send( .send(RevcMsgScNotify {
CMD_REVC_MSG_SC_NOTIFY,
RevcMsgScNotify {
msg_type: body.msg_type, msg_type: body.msg_type,
text: format!("Success change march to {:#?}", march_type), text: format!("Success change march to {:#?}", march_type),
emote: body.emote, emote: body.emote,
from_uid: 727, // from from_uid: SERVER_UID, // from
to_uid: 25, // to to_uid: 25, // to
chat_type: body.chat_type, chat_type: body.chat_type,
}, ..Default::default()
) })
.await?; .await
.unwrap();
} }
_ => {} _ => {}
} }
} }
session
.send(
CMD_SEND_MSG_SC_RSP,
SendMsgScRsp {
retcode: 0,
end_time: 0,
},
)
.await
} }
fn parse_command(command: &str) -> Option<(&str, Vec<&str>)> { fn parse_command(command: &str) -> Option<(&str, Vec<&str>)> {
@@ -216,22 +173,20 @@ fn parse_command(command: &str) -> Option<(&str, Vec<&str>)> {
Some((parts[0], parts[1..].to_vec())) Some((parts[0], parts[1..].to_vec()))
} }
async fn sync_player(session: &mut PlayerSession, json: FreesrData) -> Result<()> { async fn sync_player(session: &mut PlayerSession, json: FreesrData) {
// clear relics & lightcones
session session
.send( .send(PlayerSyncScNotify {
CMD_PLAYER_SYNC_SC_NOTIFY,
PlayerSyncScNotify {
del_equipment_list: (2000..3500).collect(), del_equipment_list: (2000..3500).collect(),
del_relic_list: (1..2000).collect(), del_relic_list: (1..2000).collect(),
..Default::default() ..Default::default()
}, })
) .await
.await?; .unwrap();
// Sync avatars
session session
.send( .send(PlayerSyncScNotify {
CMD_PLAYER_SYNC_SC_NOTIFY,
PlayerSyncScNotify {
avatar_sync: Some(AvatarSync { avatar_sync: Some(AvatarSync {
avatar_list: json avatar_list: json
.avatars .avatars
@@ -240,14 +195,13 @@ async fn sync_player(session: &mut PlayerSession, json: FreesrData) -> Result<()
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
}), }),
..Default::default() ..Default::default()
}, })
) .await
.await?; .unwrap();
// Sync new relics
session session
.send( .send(PlayerSyncScNotify {
CMD_PLAYER_SYNC_SC_NOTIFY,
PlayerSyncScNotify {
relic_list: json.relics.iter().map(|v| v.to_relic_proto()).collect(), relic_list: json.relics.iter().map(|v| v.to_relic_proto()).collect(),
equipment_list: json equipment_list: json
.lightcones .lightcones
@@ -255,14 +209,13 @@ async fn sync_player(session: &mut PlayerSession, json: FreesrData) -> Result<()
.map(|v| v.to_equipment_proto()) .map(|v| v.to_equipment_proto())
.collect(), .collect(),
..Default::default() ..Default::default()
}, })
) .await
.await?; .unwrap();
// Sync new lightcones
session session
.send( .send(PlayerSyncScNotify {
CMD_PLAYER_SYNC_SC_NOTIFY,
PlayerSyncScNotify {
avatar_sync: Some(AvatarSync { avatar_sync: Some(AvatarSync {
avatar_list: json avatar_list: json
.avatars .avatars
@@ -281,7 +234,7 @@ async fn sync_player(session: &mut PlayerSession, json: FreesrData) -> Result<()
.collect(), .collect(),
}), }),
..Default::default() ..Default::default()
}, })
)
.await .await
.unwrap()
} }

View File

@@ -1,10 +1,11 @@
pub use super::*; pub use super::*;
pub async fn on_get_gacha_info_cs_req( pub async fn on_get_gacha_info_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
_: &GetGachaInfoCsReq, _req: &GetGachaInfoCsReq,
) -> anyhow::Result<()> { res: &mut GetGachaInfoScRsp,
let gacha = GachaInfo { ) {
res.gacha_info_list = vec![GachaInfo {
end_time: 1924992000, end_time: 1924992000,
begin_time: 0, begin_time: 0,
gacha_ceiling: Some(GachaCeiling::default()), gacha_ceiling: Some(GachaCeiling::default()),
@@ -17,29 +18,17 @@ pub async fn on_get_gacha_info_cs_req(
], ],
gacha_id: 1001, gacha_id: 1001,
..Default::default() ..Default::default()
}; }];
session
.send(
CMD_GET_GACHA_INFO_SC_RSP,
GetGachaInfoScRsp {
gacha_info_list: vec![gacha],
..Default::default()
},
)
.await
} }
pub async fn on_do_gacha_cs_req( pub async fn on_do_gacha_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
req: &DoGachaCsReq, req: &DoGachaCsReq,
) -> anyhow::Result<()> { res: &mut DoGachaScRsp,
session ) {
.send( res.gacha_id = req.gacha_id;
CMD_DO_GACHA_SC_RSP, res.gacha_num = req.gacha_num;
DoGachaScRsp { res.gacha_item_list = (0..req.gacha_num)
gacha_id: req.gacha_id,
gacha_num: req.gacha_num,
gacha_item_list: (0..req.gacha_num)
.map(|v| GachaItem { .map(|v| GachaItem {
is_new: false, is_new: false,
gacha_item: Some(Item { gacha_item: Some(Item {
@@ -55,9 +44,5 @@ pub async fn on_do_gacha_cs_req(
}), }),
transfer_item_list: Some(ItemList { item_list: vec![] }), transfer_item_list: Some(ItemList { item_list: vec![] }),
}) })
.collect(), .collect();
..Default::default()
},
)
.await
} }

View File

@@ -1,22 +1,21 @@
use anyhow::Result;
use proto::*; use proto::*;
use crate::net::{tools::FreesrData, PlayerSession}; use crate::net::{tools::FreesrData, PlayerSession};
pub async fn on_get_bag_cs_req(session: &mut PlayerSession, _: &GetBagCsReq) -> Result<()> { pub async fn on_get_bag_cs_req(
_session: &mut PlayerSession,
_req: &GetBagCsReq,
res: &mut GetBagScRsp,
) {
let player = FreesrData::load().await; let player = FreesrData::load().await;
session res.equipment_list = player
.send(
CMD_GET_BAG_SC_RSP,
GetBagScRsp {
equipment_list: player
.lightcones .lightcones
.iter() .iter()
.map(|v| v.to_equipment_proto()) .map(|v| v.to_equipment_proto())
.collect(), .collect();
relic_list: player.relics.iter().map(|v| v.to_relic_proto()).collect(), res.relic_list = player.relics.iter().map(|v| v.to_relic_proto()).collect();
material_list: vec![ res.material_list = vec![
Material { Material {
tid: 101, // Normal Pass tid: 101, // Normal Pass
num: 999999, num: 999999,
@@ -27,70 +26,41 @@ pub async fn on_get_bag_cs_req(session: &mut PlayerSession, _: &GetBagCsReq) ->
num: 999999, num: 999999,
..Default::default() ..Default::default()
}, },
], ];
..Default::default()
},
)
.await
} }
pub async fn on_get_archive_data_cs_req( pub async fn on_get_archive_data_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
_: &GetArchiveDataCsReq, _: &GetArchiveDataCsReq,
) -> Result<()> { res: &mut GetArchiveDataScRsp,
session ) {
.send( res.archive_data = Some(ArchiveData::default());
CMD_GET_ARCHIVE_DATA_SC_RSP,
GetArchiveDataScRsp {
archive_data: Some(ArchiveData::default()),
retcode: 0,
},
)
.await
} }
pub async fn on_dress_relic_avatar_cs_req( pub async fn on_dress_relic_avatar_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
_: &DressRelicAvatarCsReq, _req: &DressRelicAvatarCsReq,
) -> Result<()> { _res: &mut DressRelicAvatarScRsp,
// ? ) {
session
.send(
CMD_DRESS_RELIC_AVATAR_SC_RSP,
DressRelicAvatarScRsp::default(),
)
.await
} }
pub async fn on_take_off_relic_cs_req( pub async fn on_take_off_relic_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
_: &TakeOffRelicCsReq, _req: &TakeOffRelicCsReq,
) -> Result<()> { _res: &mut TakeOffRelicScRsp,
// ? ) {
session
.send(CMD_TAKE_OFF_RELIC_SC_RSP, TakeOffRelicScRsp::default())
.await
} }
pub async fn on_dress_avatar_cs_req( pub async fn on_dress_avatar_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
_: &DressAvatarCsReq, _req: &DressAvatarCsReq,
) -> Result<()> { _res: &mut DressAvatarScRsp,
// ? ) {
session
.send(CMD_DRESS_AVATAR_SC_RSP, DressAvatarScRsp::default())
.await
} }
pub async fn on_take_off_equipment_cs_req( pub async fn on_take_off_equipment_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
_: &TakeOffEquipmentCsReq, _req: &TakeOffEquipmentCsReq,
) -> Result<()> { _res: &mut TakeOffEquipmentScRsp,
// ? ) {
session
.send(
CMD_TAKE_OFF_EQUIPMENT_SC_RSP,
TakeOffEquipmentScRsp::default(),
)
.await
} }

View File

@@ -6,34 +6,26 @@ use crate::net::tools::{self, AvatarJson, FreesrData};
use super::*; use super::*;
pub async fn on_get_all_lineup_data_cs_req( pub async fn on_get_all_lineup_data_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
_body: &GetAllLineupDataCsReq, _body: &GetAllLineupDataCsReq,
) -> Result<()> { res: &mut GetAllLineupDataScRsp,
) {
let player = tools::FreesrData::load().await; let player = tools::FreesrData::load().await;
let lineup = LineupInfo { res.lineup_list = vec![LineupInfo {
extra_lineup_type: ExtraLineupType::LineupNone.into(), extra_lineup_type: ExtraLineupType::LineupNone.into(),
name: "Squad 1".to_string(), name: "Squad 1".to_string(),
mp: 5, mp: 5,
max_mp: 5, max_mp: 5,
avatar_list: AvatarJson::to_lineup_avatars(&player), avatar_list: AvatarJson::to_lineup_avatars(&player),
..Default::default() ..Default::default()
}; }];
session
.send(
CMD_GET_ALL_LINEUP_DATA_SC_RSP,
GetAllLineupDataScRsp {
lineup_list: vec![lineup],
..Default::default()
},
)
.await
} }
pub async fn on_get_cur_lineup_data_cs_req( pub async fn on_get_cur_lineup_data_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
_body: &GetCurLineupDataCsReq, _body: &GetCurLineupDataCsReq,
) -> Result<()> { res: &mut GetCurLineupDataScRsp,
) {
let player = tools::FreesrData::load().await; let player = tools::FreesrData::load().await;
let lineup = LineupInfo { let lineup = LineupInfo {
extra_lineup_type: ExtraLineupType::LineupNone.into(), extra_lineup_type: ExtraLineupType::LineupNone.into(),
@@ -46,24 +38,14 @@ pub async fn on_get_cur_lineup_data_cs_req(
..Default::default() ..Default::default()
}; };
session res.lineup = Some(lineup)
.send(
CMD_GET_CUR_LINEUP_DATA_SC_RSP,
GetCurLineupDataScRsp {
lineup: Some(lineup),
..Default::default()
},
)
.await
} }
pub async fn on_join_lineup_cs_req( pub async fn on_join_lineup_cs_req(
session: &mut PlayerSession, session: &mut PlayerSession,
body: &JoinLineupCsReq, body: &JoinLineupCsReq,
) -> Result<()> { _res: &mut JoinLineupScRsp,
// update lineups ) {
// TODO: FIX THESE SHIT
{
let mut player = tools::FreesrData::load().await; let mut player = tools::FreesrData::load().await;
let lineups = &mut player.lineups; let lineups = &mut player.lineups;
lineups.insert( lineups.insert(
@@ -77,24 +59,14 @@ pub async fn on_join_lineup_cs_req(
}, },
); );
player.save_lineup().await; player.save_lineup().await;
} refresh_lineup(session, &player).await;
{
let player = tools::FreesrData::load().await;
refresh_lineup(session, &player).await?;
}
session
.send(CMD_JOIN_LINEUP_SC_RSP, JoinLineupScRsp::default())
.await
} }
pub async fn on_replace_lineup_cs_req( pub async fn on_replace_lineup_cs_req(
_session: &mut PlayerSession, _session: &mut PlayerSession,
req: &ReplaceLineupCsReq, req: &ReplaceLineupCsReq,
) -> Result<()> { _res: &mut ReplaceLineupScRsp,
{ ) {
let mut player = tools::FreesrData::load().await; let mut player = tools::FreesrData::load().await;
let lineups = &mut player.lineups; let lineups = &mut player.lineups;
@@ -112,29 +84,17 @@ pub async fn on_replace_lineup_cs_req(
} }
} }
player.save_lineup().await; player.save_lineup().await;
} refresh_lineup(_session, &player).await;
{
let player = tools::FreesrData::load().await;
refresh_lineup(_session, &player).await?;
}
_session
.send(CMD_JOIN_LINEUP_SC_RSP, JoinLineupScRsp::default())
.await
} }
pub async fn on_quit_lineup_cs_req( pub async fn on_quit_lineup_cs_req(
_session: &mut PlayerSession, _session: &mut PlayerSession,
_: &QuitLineupCsReq, _: &QuitLineupCsReq,
) -> Result<()> { _res: &mut QuitLineupScRsp,
_session ) {
.send(CMD_JOIN_LINEUP_SC_RSP, JoinLineupScRsp::default())
.await
} }
async fn refresh_lineup(sess: &mut PlayerSession, player: &FreesrData) -> Result<()> { async fn refresh_lineup(session: &mut PlayerSession, player: &FreesrData) {
let lineup = LineupInfo { let lineup = LineupInfo {
extra_lineup_type: ExtraLineupType::LineupNone.into(), extra_lineup_type: ExtraLineupType::LineupNone.into(),
name: "Squad 1".to_string(), name: "Squad 1".to_string(),
@@ -144,9 +104,8 @@ async fn refresh_lineup(sess: &mut PlayerSession, player: &FreesrData) -> Result
..Default::default() ..Default::default()
}; };
sess.send( session
CMD_SCENE_GROUP_REFRESH_SC_NOTIFY, .send(SceneGroupRefreshScNotify {
SceneGroupRefreshScNotify {
group_refresh_info: vec![SceneGroupRefreshInfo { group_refresh_info: vec![SceneGroupRefreshInfo {
group_id: 0, group_id: 0,
state: 0, state: 0,
@@ -170,31 +129,23 @@ async fn refresh_lineup(sess: &mut PlayerSession, player: &FreesrData) -> Result
}) })
.collect(), .collect(),
}], }],
}, })
) .await
.await?; .unwrap();
sess.send( session
CMD_SYNC_LINEUP_NOTIFY, .send(SyncLineupNotify {
SyncLineupNotify {
lineup: Some(lineup), lineup: Some(lineup),
reason_list: vec![], reason_list: vec![],
}, })
)
.await .await
.unwrap();
} }
pub async fn on_change_lineup_leader_cs_req( pub async fn on_change_lineup_leader_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
body: &ChangeLineupLeaderCsReq, body: &ChangeLineupLeaderCsReq,
) -> Result<()> { res: &mut ChangeLineupLeaderScRsp,
session ) {
.send( res.slot = body.slot;
CMD_CHANGE_LINEUP_LEADER_SC_RSP,
ChangeLineupLeaderScRsp {
slot: body.slot,
retcode: 0,
},
)
.await
} }

View File

@@ -1,13 +1,12 @@
use super::*; use super::*;
use anyhow::Result;
pub async fn on_get_mail_cs_req(session: &mut PlayerSession, _: &GetMailCsReq) -> Result<()> { pub async fn on_get_mail_cs_req(
session _session: &mut PlayerSession,
.send( _req: &GetMailCsReq,
CMD_GET_MAIL_SC_RSP, res: &mut GetMailScRsp,
GetMailScRsp { ) {
is_end: true, res.is_end = true;
mail_list: vec![ClientMail { res.mail_list = vec![ClientMail {
title: String::from("Welcome!"), title: String::from("Welcome!"),
sender: String::from("Server"), sender: String::from("Server"),
content: String::from("Welcome!"), content: String::from("Welcome!"),
@@ -26,12 +25,5 @@ pub async fn on_get_mail_cs_req(session: &mut PlayerSession, _: &GetMailCsReq) -
}), }),
mail_type: MailType::Normal.into(), mail_type: MailType::Normal.into(),
template_id: 0, template_id: 0,
}], }];
notice_mail_list: vec![],
start: 0,
retcode: 0,
total_num: 1,
},
)
.await
} }

View File

@@ -1,13 +1,12 @@
use super::*; use super::*;
pub async fn on_get_mission_status_cs_req( pub async fn on_get_mission_status_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
body: &GetMissionStatusCsReq, body: &GetMissionStatusCsReq,
) -> Result<()> { res: &mut GetMissionStatusScRsp,
let rsp = GetMissionStatusScRsp { ) {
retcode: 0, res.finished_main_mission_id_list = body.main_mission_id_list.clone();
finished_main_mission_id_list: body.main_mission_id_list.clone(), res.sub_mission_status_list = body
sub_mission_status_list: body
.sub_mission_id_list .sub_mission_id_list
.iter() .iter()
.map(|id| Mission { .map(|id| Mission {
@@ -15,9 +14,5 @@ pub async fn on_get_mission_status_cs_req(
progress: 1, progress: 1,
status: MissionStatus::MissionFinish.into(), status: MissionStatus::MissionFinish.into(),
}) })
.collect(), .collect();
..Default::default()
};
session.send(CMD_GET_MISSION_STATUS_SC_RSP, rsp).await
} }

View File

@@ -9,7 +9,6 @@ mod mail;
mod mission; mod mission;
mod player; mod player;
mod scene; mod scene;
mod tutorial;
use anyhow::Result; use anyhow::Result;
use paste::paste; use paste::paste;
@@ -30,7 +29,6 @@ pub use mail::*;
pub use mission::*; pub use mission::*;
pub use player::*; pub use player::*;
pub use scene::*; pub use scene::*;
// pub use tutorial::*;
#[allow(unused_imports)] #[allow(unused_imports)]
use proto::{ use proto::{

View File

@@ -1,106 +1,70 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::{net::tools::FreesrData, util}; use crate::{net::tools::FreesrData, util::cur_timestamp_ms};
use super::*; use super::*;
pub async fn on_get_basic_info_cs_req( pub async fn on_get_basic_info_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
_body: &GetBasicInfoCsReq, _body: &GetBasicInfoCsReq,
) -> Result<()> { res: &mut GetBasicInfoScRsp,
session ) {
.send( res.player_setting_info = Some(PlayerSettingInfo::default());
CMD_GET_BASIC_INFO_SC_RSP, res.gender = Gender::Woman as u32;
GetBasicInfoScRsp { res.is_gender_set = true;
retcode: 0,
player_setting_info: Some(PlayerSettingInfo::default()),
gender: Gender::Woman as u32,
is_gender_set: true,
..Default::default()
},
)
.await
} }
pub async fn on_player_heart_beat_cs_req( pub async fn on_player_heart_beat_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
body: &PlayerHeartBeatCsReq, body: &PlayerHeartBeatCsReq,
) -> Result<()> { res: &mut PlayerHeartBeatScRsp,
session ) {
.send( res.client_time_ms = body.client_time_ms;
CMD_PLAYER_HEART_BEAT_SC_RSP, res.server_time_ms = cur_timestamp_ms();
PlayerHeartBeatScRsp { res.download_data = Some(ClientDownloadData {
retcode: 0,
client_time_ms: body.client_time_ms,
server_time_ms: util::cur_timestamp_ms(),
download_data: Some(ClientDownloadData {
version: 51, version: 51,
time: util::cur_timestamp_ms() as i64, time: res.server_time_ms as i64,
data: rbase64::decode("bG9jYWwgZnVuY3Rpb24gYmV0YV90ZXh0KG9iaikKICAgIGxvY2FsIGdhbWVPYmplY3QgPSBDUy5Vbml0eUVuZ2luZS5HYW1lT2JqZWN0LkZpbmQoIlVJUm9vdC9BYm92ZURpYWxvZy9CZXRhSGludERpYWxvZyhDbG9uZSkiKQoKICAgIGlmIGdhbWVPYmplY3QgdGhlbgogICAgICAgIGxvY2FsIHRleHRDb21wb25lbnQgPSBnYW1lT2JqZWN0OkdldENvbXBvbmVudEluQ2hpbGRyZW4odHlwZW9mKENTLlJQRy5DbGllbnQuTG9jYWxpemVkVGV4dCkpCgogICAgICAgIGlmIHRleHRDb21wb25lbnQgdGhlbgogICAgICAgICAgICB0ZXh0Q29tcG9uZW50LnRleHQgPSAiUm9iaW5TUiBpcyBhIGZyZWUgYW5kIG9wZW4gc291cmNlIHNvZnR3YXJlLiBkaXNjb3JkLmdnL3JldmVyc2Vkcm9vbXMiCiAgICAgICAgZW5kCiAgICBlbHNlCiAgICBlbmQKZW5kCgpiZXRhX3RleHQoKQ==").unwrap() data: rbase64::decode("bG9jYWwgZnVuY3Rpb24gYmV0YV90ZXh0KG9iaikKICAgIGxvY2FsIGdhbWVPYmplY3QgPSBDUy5Vbml0eUVuZ2luZS5HYW1lT2JqZWN0LkZpbmQoIlVJUm9vdC9BYm92ZURpYWxvZy9CZXRhSGludERpYWxvZyhDbG9uZSkiKQoKICAgIGlmIGdhbWVPYmplY3QgdGhlbgogICAgICAgIGxvY2FsIHRleHRDb21wb25lbnQgPSBnYW1lT2JqZWN0OkdldENvbXBvbmVudEluQ2hpbGRyZW4odHlwZW9mKENTLlJQRy5DbGllbnQuTG9jYWxpemVkVGV4dCkpCgogICAgICAgIGlmIHRleHRDb21wb25lbnQgdGhlbgogICAgICAgICAgICB0ZXh0Q29tcG9uZW50LnRleHQgPSAiUm9iaW5TUiBpcyBhIGZyZWUgYW5kIG9wZW4gc291cmNlIHNvZnR3YXJlLiBkaXNjb3JkLmdnL3JldmVyc2Vkcm9vbXMiCiAgICAgICAgZW5kCiAgICBlbHNlCiAgICBlbmQKZW5kCgpiZXRhX3RleHQoKQ==").unwrap()
}), });
},
)
.await
} }
pub type PlayerLoginFinishCsReq = Dummy;
pub async fn on_player_login_finish_cs_req( pub async fn on_player_login_finish_cs_req(
session: &mut PlayerSession, session: &mut PlayerSession,
_: &PlayerLoginFinishCsReq, _req: &PlayerLoginFinishCsReq,
_res: &mut PlayerLoginFinishScRsp,
) -> Result<()> { ) -> Result<()> {
session session
.send(CMD_PLAYER_LOGIN_FINISH_SC_RSP, Dummy::default()) .send(ContentPackageSyncDataScNotify {
.await?;
session
.send(
CMD_CONTENT_PACKAGE_SYNC_DATA_SC_NOTIFY,
ContentPackageSyncDataScNotify {
data: Some(PackageData { data: Some(PackageData {
info_list: vec![ info_list: vec![
ContentInfo { 200001, 200002, 200003, 200004, 150017, 150015, 150021, 150018, 130011, 130012,
130013,
]
.iter()
.map(|v| ContentInfo {
status: ContentPackageStatus::Finished.into(), status: ContentPackageStatus::Finished.into(),
content_id: 200001, content_id: *v,
}, })
ContentInfo { .collect(),
status: ContentPackageStatus::Finished.into(),
content_id: 200002,
},
ContentInfo {
status: ContentPackageStatus::Finished.into(),
content_id: 200003,
},
ContentInfo {
status: ContentPackageStatus::Finished.into(),
content_id: 150017,
},
ContentInfo {
status: ContentPackageStatus::Finished.into(),
content_id: 150015,
},
],
..Default::default() ..Default::default()
}), }),
}, })
) .await
.await?;
Ok(())
} }
pub async fn on_get_multi_path_avatar_info_cs_req( pub async fn on_get_multi_path_avatar_info_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
_: &GetMultiPathAvatarInfoCsReq, _req: &GetMultiPathAvatarInfoCsReq,
) -> Result<()> { res: &mut GetMultiPathAvatarInfoScRsp,
) {
let json = FreesrData::load().await; let json = FreesrData::load().await;
session res.current_multi_path_avatar_id = HashMap::from([
.send( (8001, json.main_character.get_type().into()),
CMD_GET_MULTI_PATH_AVATAR_INFO_SC_RSP, (1001, json.march_type.get_type().into()),
GetMultiPathAvatarInfoScRsp { ]);
retcode: 0,
multi_path_avatar_type_info_list: vec![ res.multi_path_avatar_type_info_list = vec![
MultiPathAvatarTypeInfo { MultiPathAvatarTypeInfo {
avatar_id: json.main_character as i32, avatar_id: json.main_character as i32,
rank: 6, rank: 6,
@@ -145,13 +109,5 @@ pub async fn on_get_multi_path_avatar_info_cs_req(
.map(|v| v.internal_uid) .map(|v| v.internal_uid)
.unwrap_or_default(), .unwrap_or_default(),
}, },
], ];
current_multi_path_avatar_id: HashMap::from([
(8001, json.main_character.get_type().into()),
(1001, json.march_type.get_type().into()),
]),
..Default::default()
},
)
.await
} }

View File

@@ -1,95 +1,65 @@
use lazy_static::lazy_static; use lazy_static::lazy_static;
use prost::Message;
use scene_entity_info::Entity; use scene_entity_info::Entity;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use crate::{ use crate::{
net::{ net::tools::{AvatarJson, FreesrData, Position},
tools::{AvatarJson, FreesrData, Position}, tools::resources::GAME_RES,
tools_res::{PropState, GAME_RESOURCES},
},
util::{self}, util::{self},
}; };
use super::*; use super::*;
#[derive(Message)]
pub struct Dummy {}
pub async fn on_get_cur_scene_info_cs_req( pub async fn on_get_cur_scene_info_cs_req(
session: &mut PlayerSession, session: &mut PlayerSession,
_body: &GetCurSceneInfoCsReq, _body: &GetCurSceneInfoCsReq,
) -> Result<()> { res: &mut GetCurSceneInfoScRsp,
) {
let mut player = FreesrData::load().await; let mut player = FreesrData::load().await;
let entry = player.scene.entry_id; let entry = player.scene.entry_id;
let scene = load_scene(session, &mut player, entry, false, Option::<u32>::None).await; let scene = load_scene(session, &mut player, entry, false, Option::<u32>::None).await;
let resp = GetCurSceneInfoScRsp { res.scene = if let Ok(scene) = scene {
retcode: 0,
scene: if let Ok(scene) = scene {
Some(scene) Some(scene)
} else { } else {
Some(SceneInfo { Some(SceneInfo {
game_mode_type: 1, game_mode_type: 3,
entry_id: player.scene.entry_id, entry_id: player.scene.entry_id,
plane_id: player.scene.plane_id, plane_id: player.scene.plane_id,
floor_id: player.scene.floor_id, floor_id: player.scene.floor_id,
..Default::default() ..Default::default()
}) })
},
}; };
session.send(CMD_GET_CUR_SCENE_INFO_SC_RSP, resp).await?;
if !player.position.is_empty() {
session
.send(
CMD_SCENE_ENTITY_MOVE_SC_NOTIFY,
SceneEntityMoveScNotify {
entity_id: 0,
entry_id: player.scene.entry_id,
motion: Some(player.position.to_motion()),
..Default::default()
},
)
.await?;
};
Ok(())
} }
// enterscene
pub async fn on_enter_scene_cs_req( pub async fn on_enter_scene_cs_req(
session: &mut PlayerSession, session: &mut PlayerSession,
request: &EnterSceneCsReq, req: &EnterSceneCsReq,
) -> Result<()> { res: &mut EnterSceneScRsp,
) {
let mut player = FreesrData::load().await; let mut player = FreesrData::load().await;
// send packet first if load_scene(
session
.send(CMD_ENTER_SCENE_SC_RSP, Dummy::default())
.await?;
load_scene(
session, session,
&mut player, &mut player,
request.entry_id, req.entry_id,
true, true,
Some(request.teleport_id), Some(req.teleport_id),
) )
.await?; .await
.is_err()
Ok(()) {
res.retcode = Nbbhhpnhond::RetSceneEntryIdNotMatch as u32;
};
} }
// getscenemapinfocsreq
pub async fn on_get_scene_map_info_cs_req( pub async fn on_get_scene_map_info_cs_req(
sesison: &mut PlayerSession, _sesison: &mut PlayerSession,
request: &GetSceneMapInfoCsReq, req: &GetSceneMapInfoCsReq,
) -> Result<()> { res: &mut GetSceneMapInfoScRsp,
let mut map_infos = Vec::<MazeMapData>::new(); ) {
for entry_id in &req.entry_id_list {
for entry_id in &request.entry_id_list {
let mut map_info = MazeMapData { let mut map_info = MazeMapData {
retcode: 0, retcode: 0,
unlocked_chest_list: vec![ unlocked_chest_list: vec![
@@ -114,51 +84,37 @@ pub async fn on_get_scene_map_info_cs_req(
map_info.lighten_section_list.push(i) map_info.lighten_section_list.push(i)
} }
let group_config = GAME_RESOURCES.map_entrance.get(entry_id).and_then(|v| { let group_config = GAME_RES
GAME_RESOURCES .level_output_configs
.level_group .get(&entry_id)
.get(&format!("P{}_F{}", v.plane_id, v.floor_id)) .and_then(|v| v.iter().next());
});
if let Some(level) = group_config {
// add teleports
for teleport in &level.teleports {
map_info.unlocked_teleport_list.push(*teleport.0)
}
for (group_id, group) in &level.group_items { if let Some((_, group_config)) = group_config {
for (_, (group_id, group)) in group_config.scenes.iter().enumerate() {
map_info.maze_group_list.push(MazeGroup { map_info.maze_group_list.push(MazeGroup {
group_id: *group_id, group_id: *group_id,
..Default::default() ..Default::default()
}); });
// prop for (teleport, _) in &group.teleports {
map_info.unlocked_teleport_list.push(*teleport)
}
for prop in &group.props { for prop in &group.props {
if prop.prop_state != 8 {
continue;
}
map_info.maze_prop_list.push(MazeProp { map_info.maze_prop_list.push(MazeProp {
group_id: prop.group_id, group_id: prop.group_id,
state: if prop.prop_state_list.contains(&PropState::CheckPointEnable) { state: prop.prop_state,
PropState::CheckPointEnable as u32 config_id: prop.inst_id,
} else {
prop.state.clone() as u32
},
config_id: prop.id,
}); });
} }
} }
} }
map_infos.push(map_info) res.map_list.push(map_info)
} }
sesison
.send(
CMD_GET_SCENE_MAP_INFO_SC_RSP,
GetSceneMapInfoScRsp {
retcode: 0,
map_list: map_infos,
..Default::default()
},
)
.await
} }
lazy_static! { lazy_static! {
@@ -166,24 +122,21 @@ lazy_static! {
} }
pub async fn on_scene_entity_move_cs_req( pub async fn on_scene_entity_move_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
request: &SceneEntityMoveCsReq, req: &SceneEntityMoveCsReq,
) -> Result<()> { _res: &mut SceneEntityMoveScRsp,
) {
let mut player = FreesrData::load().await; let mut player = FreesrData::load().await;
let mut timestamp = NEXT_SCENE_SAVE.lock().await; let mut timestamp = NEXT_SCENE_SAVE.lock().await;
if util::cur_timestamp_ms() <= *timestamp { if util::cur_timestamp_ms() <= *timestamp {
session return;
.send(CMD_SCENE_ENTITY_MOVE_SC_RSP, Dummy::default())
.await?;
return Ok(());
} }
// save every 5 sec // save every 5 sec
*timestamp = util::cur_timestamp_ms() + (5 * 1000); *timestamp = util::cur_timestamp_ms() + (5 * 1000);
for entity in &request.entity_motion_list { for entity in &req.entity_motion_list {
if entity.entity_id != 0 { if entity.entity_id != 0 {
continue; continue;
} }
@@ -201,99 +154,101 @@ pub async fn on_scene_entity_move_cs_req(
} }
player.save().await; player.save().await;
session
.send(CMD_SCENE_ENTITY_MOVE_SC_RSP, Dummy::default())
.await
} }
pub async fn on_get_entered_scene_cs_req( pub async fn on_get_entered_scene_cs_req(
session: &mut PlayerSession, _session: &mut PlayerSession,
_: &GetEnteredSceneCsReq, _req: &GetEnteredSceneCsReq,
) -> Result<()> { res: &mut GetEnteredSceneScRsp,
let scenes = GAME_RESOURCES ) {
.map_entrance res.entered_scene_info = GAME_RES
.level_output_configs
.iter() .iter()
.filter(|(_, v)| { .map(|(_, v)| {
!v.finish_main_mission_list.is_empty() || !v.finish_sub_mission_list.is_empty() v.iter()
.filter(|(_, v)| v.is_entered_scene_info)
.map(|(k, _)| {
let split: Vec<_> = k.split("_").collect();
let plane_id = &split[0][1..];
let floor_id = &split[1][1..];
EnteredSceneInfo {
floor_id: floor_id.parse().unwrap(),
plane_id: plane_id.parse().unwrap(),
}
}) })
.map(|(_, v)| EnteredSceneInfo { .collect::<Vec<_>>()
floor_id: v.floor_id,
plane_id: v.plane_id,
}) })
.flatten()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
session
.send(
CMD_GET_ENTERED_SCENE_SC_RSP,
GetEnteredSceneScRsp {
entered_scene_info: scenes,
retcode: 0,
},
)
.await
} }
async fn load_scene( async fn load_scene(
session: &mut PlayerSession, session: &mut PlayerSession,
json: &mut FreesrData, json: &mut FreesrData,
entry_id: u32, entry_id: u32,
_save: bool, save_scene: bool,
teleport_id: Option<u32>, teleport_id: Option<u32>,
) -> Result<SceneInfo> { ) -> Result<SceneInfo> {
let enterance = GAME_RESOURCES let (name, scene) = GAME_RES
.map_entrance .level_output_configs
.get(&entry_id) .get(&entry_id)
.ok_or_else(|| anyhow::format_err!("Map Entrance Not Found"))?; .map(|v| v.iter().next())
.flatten()
.ok_or_else(|| {
tracing::error!("Map Entrance Not Found {}", entry_id);
anyhow::format_err!("Map Entrance Not Found {}", entry_id)
})?;
let plane = GAME_RESOURCES let split: Vec<_> = name.split("_").collect();
.maze_plane let plane_id = *&split[0][1..].parse::<u32>()?;
.get(&enterance.plane_id) let floor_id = *&split[1][1..].parse::<u32>()?;
.ok_or_else(|| anyhow::format_err!("Map Plane Not Found"))?;
let group_config = GAME_RESOURCES let mut json_pos = json.position.clone();
.level_group
.get(&format!("P{}_F{}", enterance.plane_id, enterance.floor_id))
.ok_or_else(|| anyhow::format_err!("Group Config Not Found"))?;
let mut position = json.position.clone();
if let Some(teleport_id) = teleport_id { if let Some(teleport_id) = teleport_id {
if let Some(teleport) = group_config.teleports.get(&teleport_id) { if let Some(teleport) = scene
let anchor = group_config .scenes
.group_items .iter()
.get(&teleport.anchor_group_id.unwrap_or_default()) .find_map(|(_, v)| v.teleports.get(&teleport_id))
.and_then(|v| v.anchors.get(&teleport.anchor_id.unwrap_or_default())); {
if let Some(anchor) = anchor { json_pos.x = teleport.pos.x;
position.x = (anchor.pos_x * 1000f64) as i32; json_pos.y = teleport.pos.y;
position.y = (anchor.pos_y * 1000f64) as i32; json_pos.z = teleport.pos.z;
position.z = (anchor.pos_z * 1000f64) as i32; json_pos.rot_y = teleport.rot.y;
position.rot_y = (anchor.rot_y * 1000f64) as i32; } else {
if let Some((_, teleport)) = scene
.scenes
.iter()
.find_map(|v| v.1.teleports.iter().next())
{
json_pos.x = teleport.pos.x;
json_pos.y = teleport.pos.y;
json_pos.z = teleport.pos.z;
json_pos.rot_y = teleport.rot.y;
} }
} }
} }
let mut scene_info = SceneInfo { let mut scene_info = SceneInfo {
floor_id: enterance.floor_id, floor_id,
plane_id: enterance.plane_id, plane_id,
entry_id, entry_id,
game_mode_type: plane.plane_type as u32, game_mode_type: *(&scene.plane_type) as u32,
leader_entity_id: 1, leader_entity_id: 1,
world_id: plane.world_id, world_id: scene.world_id,
..Default::default() ..Default::default()
}; };
let lineup_info = AvatarJson::to_lineup_info(&json.lineups); let lineup_info = AvatarJson::to_lineup_info(&json.lineups);
let player_pos = MotionInfo { let player_pos = MotionInfo {
// rot
rot: Some(Vector { rot: Some(Vector {
x: 0, x: 0,
y: position.rot_y, y: json_pos.rot_y,
z: 0, z: 0,
}), }),
// pos
pos: Some(Vector { pos: Some(Vector {
x: position.x, x: json_pos.x,
y: position.y, y: json_pos.y,
z: position.z, z: json_pos.z,
}), }),
}; };
@@ -302,36 +257,29 @@ async fn load_scene(
let mut npc_entity_id = 20_000; let mut npc_entity_id = 20_000;
let mut monster_entity_id = 30_000; let mut monster_entity_id = 30_000;
for (group_id, group) in &group_config.group_items { for (group_id, group) in &scene.scenes {
let mut group_info = SceneEntityGroupInfo { let mut group_info = SceneEntityGroupInfo {
state: 0,
group_id: *group_id, group_id: *group_id,
..Default::default() ..Default::default()
}; };
// Load Props // Load Props
for prop in &group.props { for prop in &group.props {
let prop_state = if prop.prop_state_list.contains(&PropState::CheckPointEnable) {
PropState::CheckPointEnable
} else {
prop.state.clone()
};
prop_entity_id += 1; prop_entity_id += 1;
let prop_position = Position { let prop_position = Position {
x: (prop.pos_x * 1000f64) as i32, x: (prop.pos.x),
y: (prop.pos_y * 1000f64) as i32, y: (prop.pos.y),
z: (prop.pos_z * 1000f64) as i32, z: (prop.pos.z),
rot_y: (prop.rot_y * 1000f64) as i32, rot_y: (prop.rot.y),
}; };
let entity_info = SceneEntityInfo { let entity_info = SceneEntityInfo {
inst_id: prop.id, inst_id: prop.inst_id,
group_id: prop.group_id, group_id: prop.group_id,
motion: Some(prop_position.to_motion()), motion: Some(prop_position.to_motion()),
entity: Some(Entity::Prop(ScenePropInfo { entity: Some(Entity::Prop(ScenePropInfo {
prop_state: prop_state as u32, prop_state: prop.prop_state,
prop_id: prop.prop_id, prop_id: prop.prop_id,
..Default::default() ..Default::default()
})), })),
@@ -343,26 +291,26 @@ async fn load_scene(
// Load NPCs // Load NPCs
for npc in &group.npcs { for npc in &group.npcs {
if loaded_npc.contains(&(npc.npcid)) || json.avatars.contains_key(&(npc.npcid)) { if loaded_npc.contains(&(npc.npc_id)) || json.avatars.contains_key(&(npc.npc_id)) {
continue; continue;
} }
npc_entity_id += 1; npc_entity_id += 1;
loaded_npc.push(npc.npcid); loaded_npc.push(npc.npc_id);
let npc_position = Position { let npc_position = Position {
x: (npc.pos_x * 1000f64) as i32, x: (npc.pos.x) as i32,
y: (npc.pos_y * 1000f64) as i32, y: (npc.pos.y) as i32,
z: (npc.pos_z * 1000f64) as i32, z: (npc.pos.z) as i32,
rot_y: (npc.rot_y * 1000f64) as i32, rot_y: (npc.rot.y) as i32,
}; };
let info = SceneEntityInfo { let info = SceneEntityInfo {
inst_id: npc.id, inst_id: npc.inst_id,
group_id: npc.group_id, group_id: npc.group_id,
entity_id: npc_entity_id, entity_id: npc_entity_id,
motion: Some(npc_position.to_motion()), motion: Some(npc_position.to_motion()),
entity: Some(Entity::Npc(SceneNpcInfo { entity: Some(Entity::Npc(SceneNpcInfo {
npc_id: npc.npcid, npc_id: npc.npc_id,
..Default::default() ..Default::default()
})), })),
}; };
@@ -374,21 +322,21 @@ async fn load_scene(
for monster in &group.monsters { for monster in &group.monsters {
monster_entity_id += 1; monster_entity_id += 1;
let monster_position = Position { let monster_position = Position {
x: (monster.pos_x * 1000f64) as i32, x: (monster.pos.x) as i32,
y: (monster.pos_y * 1000f64) as i32, y: (monster.pos.y) as i32,
z: (monster.pos_z * 1000f64) as i32, z: (monster.pos.z) as i32,
rot_y: (monster.rot_y * 1000f64) as i32, rot_y: (monster.rot.y) as i32,
}; };
let npc_monster = SceneNpcMonsterInfo { let npc_monster = SceneNpcMonsterInfo {
monster_id: monster.npcmonster_id, monster_id: monster.monster_id,
event_id: monster.event_id, event_id: monster.event_id,
world_level: 6, world_level: 6,
..Default::default() ..Default::default()
}; };
let info = SceneEntityInfo { let info = SceneEntityInfo {
inst_id: monster.id, inst_id: monster.inst_id,
group_id: monster.group_id, group_id: monster.group_id,
entity_id: monster_entity_id, entity_id: monster_entity_id,
motion: Some(monster_position.to_motion()), motion: Some(monster_position.to_motion()),
@@ -398,7 +346,20 @@ async fn load_scene(
group_info.entity_list.push(info); group_info.entity_list.push(info);
} }
// TODO: for now don't load group that have nothing in it
if group.props.is_empty() && group.npcs.is_empty() && group.monsters.is_empty() {
continue;
}
scene_info.entity_group_list.push(group_info); scene_info.entity_group_list.push(group_info);
scene_info.group_id_list.push(*group_id);
scene_info.group_state_list.push(SceneGroupState {
group_id: *group_id,
is_default: true,
state: 0,
});
} }
// load player entity // load player entity
@@ -411,20 +372,7 @@ async fn load_scene(
player_group.entity_list.push(SceneEntityInfo { player_group.entity_list.push(SceneEntityInfo {
inst_id: 0, inst_id: 0,
entity_id: (*slot) + 1, entity_id: (*slot) + 1,
motion: Some(MotionInfo { motion: Some(player_pos.clone()),
// pos
pos: Some(Vector {
x: json.position.x,
y: json.position.y,
z: json.position.z,
}),
// rot
rot: Some(Vector {
x: 0,
y: json.position.rot_y,
z: 0,
}),
}),
entity: Some(Entity::Actor(SceneActorInfo { entity: Some(Entity::Actor(SceneActorInfo {
avatar_type: AvatarType::AvatarFormalType.into(), avatar_type: AvatarType::AvatarFormalType.into(),
base_avatar_id: *avatar_id, base_avatar_id: *avatar_id,
@@ -436,37 +384,22 @@ async fn load_scene(
} }
scene_info.entity_group_list.push(player_group); scene_info.entity_group_list.push(player_group);
if _save { if save_scene {
session session
.send( .send(EnterSceneByServerScNotify {
CMD_ENTER_SCENE_BY_SERVER_SC_NOTIFY,
EnterSceneByServerScNotify {
scene: Some(scene_info.clone()), scene: Some(scene_info.clone()),
lineup: Some(lineup_info), lineup: Some(lineup_info),
..Default::default() ..Default::default()
}, })
)
.await?;
session
.send(
CMD_SCENE_ENTITY_MOVE_SC_NOTIFY,
SceneEntityMoveScNotify {
entity_id: 0,
motion: Some(player_pos),
entry_id,
..Default::default()
},
)
.await?; .await?;
json.scene.entry_id = entry_id; json.scene.entry_id = entry_id;
json.scene.floor_id = enterance.floor_id; json.scene.floor_id = floor_id;
json.scene.plane_id = enterance.plane_id; json.scene.plane_id = plane_id;
json.position.x = position.x; json.position.x = json_pos.x;
json.position.y = position.y; json.position.y = json_pos.y;
json.position.z = position.z; json.position.z = json_pos.z;
json.position.rot_y = position.rot_y; json.position.rot_y = json_pos.rot_y;
json.save().await; json.save().await;
} }

View File

@@ -1,117 +0,0 @@
// use super::*;
// static TUTORIAL_IDS: [u32; 463] = [
// 1001, 1002, 1003, 1004, 1005, 1007, 1008, 1010, 2000, 2001, 2002, 2003, 2004, 2008, 2010, 2011,
// 2012, 2013, 3001, 3002, 3003, 3004, 3005, 3006, 3008, 3009, 3010, 3011, 3012, 3202, 4002, 4003,
// 4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019,
// 4020, 4021, 4022, 4023, 4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, 4034, 4036,
// 4037, 4038, 4039, 4040, 5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012,
// 5013, 5014, 5015, 5016, 5017, 5018, 5019, 5021, 5022, 5023, 5024, 5025, 5026, 5027, 5028, 5029,
// 5030, 5031, 5032, 5033, 5034, 5035, 5036, 5038, 5039, 5041, 5044, 5045, 5046, 5047, 5048, 5049,
// 5050, 5051, 5052, 5053, 5054, 5055, 5056, 5057, 5058, 5059, 5060, 5061, 5062, 5063, 5064, 5065,
// 5070, 5071, 5072, 5073, 5074, 5075, 5077, 5078, 5079, 5081, 5082, 5083, 5084, 5085, 5086, 5087,
// 5088, 5089, 5090, 5091, 5092, 5093, 5094, 5095, 5096, 5097, 5098, 5099, 5100, 5101, 5102, 5103,
// 5104, 5105, 5106, 5107, 5108, 5109, 5110, 5111, 5112, 5113, 5114, 5115, 5116, 5130, 5131, 5132,
// 5133, 5134, 5135, 5140, 5141, 5142, 5143, 5144, 5145, 5146, 5150, 5151, 5152, 5153, 5154, 5155,
// 5156, 5157, 5158, 5159, 5160, 5161, 5162, 5172, 5173, 5174, 5175, 5176, 5177, 5178, 5179, 5180,
// 5181, 5182, 5183, 5184, 5185, 5186, 5187, 5188, 5189, 5190, 5191, 5192, 5193, 5194, 5195, 5196,
// 5197, 5198, 5199, 5200, 5201, 5202, 5301, 5302, 5303, 5304, 5305, 5306, 5308, 5309, 5310, 5322,
// 5326, 5312, 5311, 5313, 5307, 5314, 5315, 5316, 5317, 5318, 5319, 5320, 5321, 5323, 5324, 5325,
// 5350, 5387, 5352, 5388, 5355, 5360, 5361, 5356, 5357, 5358, 5359, 5351, 5365, 5366, 5367, 5368,
// 5375, 5376, 5377, 5389, 5374, 5369, 5370, 5371, 5372, 5373, 5390, 5380, 5381, 5400, 5382, 5383,
// 5392, 5378, 5384, 5393, 5408, 5394, 5395, 5391, 5385, 5397, 5398, 5399, 5386, 5401, 5402, 5403,
// 5404, 5405, 5406, 5407, 5409, 5410, 5510, 5511, 7001, 7002, 7003, 7004, 7005, 7007, 7008, 7009,
// 9001, 9002, 9003, 9004, 9005, 9006, 9007, 9008, 9009, 9010, 9011, 9012, 9013, 9014, 9015, 9016,
// 9017, 9018, 9019, 9020, 9021, 9022, 9023, 9024, 9025, 9026, 9027, 9028, 9029, 9030, 9031, 9032,
// 9033, 9034, 9035, 9036, 9037, 9038, 9039, 9040, 9041, 9042, 9043, 9044, 9045, 9046, 9047, 9048,
// 9049, 9050, 9051, 9052, 9053, 9201, 9202, 9203, 9204, 9205, 9206, 9207, 9208, 9209, 9210, 9211,
// 9212, 9213, 9214, 9301, 9302, 9303, 9304, 9305, 9306, 9307, 9308, 9309, 9310, 9311, 9313, 9314,
// 9315, 9316, 9317, 9318, 9319, 9321, 9322, 9323, 9324, 9325, 9801, 9802, 9803, 9804, 9805, 9806,
// 9807, 9808, 9809, 9810, 9811, 9812, 9813, 9814, 9816, 9817, 9818, 9819, 9815, 9820, 9901, 9903,
// 9904, 9905, 9906, 9907, 9908, 9610, 9611, 9612, 9613, 9614, 9615, 9616, 9617, 9618, 9619, 9620,
// 9621, 9622, 9623, 9624, 9625, 9626, 9627, 9628, 9629, 9630, 9631, 9701, 9702, 9703, 9704,
// ];
// static GUIDE_IDS: [u32; 326] = [
// 1101, 1102, 1103, 1104, 1105, 1108, 1109, 1116, 1117, 1118, 2006, 2007, 2008, 2105, 2106, 2107,
// 2200, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2211, 2212, 2213, 2214, 2215,
// 2216, 2217, 2218, 2219, 2220, 2221, 2222, 3007, 3105, 3106, 3107, 3108, 3109, 3201, 3202, 3203,
// 3204, 3205, 3206, 3207, 3208, 3209, 3210, 3211, 3212, 3213, 3214, 3215, 4001, 4101, 4102, 4103,
// 4104, 4105, 4106, 4107, 4109, 4110, 5101, 5102, 5103, 5104, 5105, 5106, 6001, 6002, 6003, 6004,
// 6008, 6009, 6010, 6011, 6012, 6014, 6015, 6018, 6020, 6021, 6023, 6024, 6025, 6027, 6028, 6029,
// 6030, 6031, 6032, 6033, 6034, 6035, 6036, 6037, 6038, 6039, 6040, 6041, 6042, 6043, 6044, 6045,
// 6046, 6047, 6048, 6049, 6050, 6051, 6052, 6053, 6054, 6055, 6056, 6057, 6058, 6059, 6060, 6061,
// 6062, 6063, 6064, 6065, 6066, 6067, 6068, 6069, 6070, 6071, 6072, 6073, 6074, 6075, 6076, 6077,
// 6078, 6079, 6080, 6081, 6082, 6083, 6085, 6086, 6087, 6088, 6089, 6090, 6091, 6092, 6093, 6094,
// 6095, 6096, 6097, 6098, 6099, 6100, 6101, 6102, 6103, 6104, 6105, 6106, 6107, 6108, 6109, 6110,
// 6111, 7090, 7091, 7092, 7501, 7502, 7503, 7504, 7506, 7507, 7508, 7509, 7511, 7514, 7515, 8001,
// 8002, 8003, 8004, 8006, 8007, 8008, 8010, 8011, 8012, 8013, 8014, 8015, 8016, 8017, 8018, 8019,
// 8020, 8021, 8022, 8023, 8024, 8025, 8026, 8027, 8028, 8038, 8039, 8047, 8050, 8051, 8052, 8055,
// 8056, 8057, 8058, 8059, 8061, 8062, 8063, 8064, 8065, 8066, 8067, 8069, 8070, 8072, 8073, 8074,
// 8075, 8076, 8078, 8079, 8080, 8090, 8091, 8092, 8093, 8094, 8095, 8096, 8100, 8101, 8102, 8103,
// 8104, 8105, 8106, 8107, 8108, 8109, 8110, 8111, 8112, 8113, 8122, 8123, 8124, 8140, 8141, 8142,
// 8143, 8144, 8145, 8146, 9101, 9102, 9103, 9104, 9105, 9107, 9108, 9109, 9110, 9111, 9112, 9113,
// 9114, 9115, 9116, 9117, 9118, 9119, 9120, 9201, 9202, 9203, 9204, 9205, 9206, 9207, 9208, 9209,
// 9210, 9211, 9212, 9301, 9303, 9304, 9305, 9601, 9602, 9603, 9604, 9605, 9701, 9702, 31001,
// 31102, 31103, 31105, 31106, 31109, 31204, 31206,
// ];
// pub async fn on_get_tutorial_cs_req(
// session: &mut PlayerSession,
// _body: &GetTutorialCsReq,
// ) -> Result<()> {
// session
// .send(
// CMD_GET_TUTORIAL_SC_RSP,
// GetTutorialScRsp {
// retcode: 0,
// tutorial_list: TUTORIAL_IDS
// .iter()
// .map(|id| Tutorial {
// id: *id,
// status: TutorialStatus::TutorialFinish.into(),
// })
// .collect(),
// },
// )
// .await
// }
// pub async fn on_get_tutorial_guide_cs_req(
// session: &mut PlayerSession,
// _body: &GetTutorialGuideCsReq,
// ) -> Result<()> {
// session
// .send(
// CMD_GET_TUTORIAL_GUIDE_SC_RSP,
// GetTutorialGuideScRsp {
// retcode: 0,
// tutorial_guide_list: GUIDE_IDS
// .iter()
// .map(|id| TutorialGuide {
// id: *id,
// status: TutorialStatus::TutorialFinish.into(),
// })
// .collect(),
// },
// )
// .await
// }
// pub async fn on_unlock_tutorial_guide_cs_req(
// session: &mut PlayerSession,
// body: &UnlockTutorialGuideCsReq,
// ) -> Result<()> {
// session
// .send(
// CMD_UNLOCK_TUTORIAL_GUIDE_SC_RSP,
// UnlockTutorialGuideScRsp {
// retcode: 0,
// tutorial_guide: Some(TutorialGuide {
// id: body.group_id,
// status: TutorialStatus::TutorialUnlock.into(),
// }),
// },
// )
// .await
// }

View File

@@ -4,8 +4,6 @@ mod handlers;
mod packet; mod packet;
mod session; mod session;
mod tools; mod tools;
mod tools_res;
pub use packet::NetPacket; pub use packet::NetPacket;
pub use session::PlayerSession; pub use session::PlayerSession;

View File

@@ -5,6 +5,28 @@ use tokio::net::TcpStream;
use tracing::Instrument; use tracing::Instrument;
use proto::*; use proto::*;
#[allow(unused_imports)]
use proto::{
CmdActivityType::*, CmdAdventureType::*, CmdAetherDivideType::*, CmdAlleyType::*,
CmdArchiveType::*, CmdAvatarType::*, CmdBattleCollegeType::*, CmdBattlePassType::*,
CmdBattleType::*, CmdBoxingClubType::*, CmdChallengeType::*, CmdChatType::*,
CmdChessRogueType::*, CmdClockParkType::*, CmdContentPackageType::*, CmdDailyActiveType::*,
CmdDrinkMakerType::*, CmdExpeditionType::*, CmdFantasticStoryActivityType::*,
CmdFeverTimeActivityType::*, CmdFightActivityType::*, CmdFightMathc3Type::*, CmdFightType::*,
CmdFriendType::*, CmdGachaType::*, CmdHeartdialType::*, CmdHeliobusType::*, CmdItemType::*,
CmdJukeboxType::*, CmdLineupType::*, CmdLobbyType::*, CmdMailType::*, CmdMapRotationType::*,
CmdMatchThreeModuleType::*, CmdMatchType::*, CmdMessageType::*, CmdMiscModuleType::*,
CmdMissionType::*, CmdMonopolyType::*, CmdMultiplayerType::*, CmdMultipleDropType::*,
CmdMuseumType::*, CmdOfferingType::*, CmdPamMissionType::*, CmdPhoneType::*,
CmdPlayerBoardType::*, CmdPlayerReturnType::*, CmdPlayerSync::*, CmdPlayerType::*,
CmdPlotType::*, CmdPunkLordType::*, CmdQuestType::*, CmdRaidCollectionType::*, CmdRaidType::*,
CmdRedDotType::*, CmdReplayType::*, CmdRndOptionType::*, CmdRogueCommonType::*,
CmdRogueEndless::*, CmdRogueModifierType::*, CmdRogueTournType::*, CmdRogueType::*,
CmdRollShopType::*, CmdSceneType::*, CmdServerPrefsType::*, CmdShopType::*, CmdSpaceZooType::*,
CmdStarFightType::*, CmdStoryLineType::*, CmdStrongChallengeActivityType::*,
CmdTalkRewardType::*, CmdTelevisionActivityType::*, CmdTextJoinType::*, CmdTrainVisitorType::*,
CmdTreasureDungeonType::*, CmdTutorialType::*, CmdWaypointType::*, CmdWolfBroType::*,
};
use super::handlers::*; use super::handlers::*;
use super::PlayerSession; use super::PlayerSession;
@@ -58,12 +80,16 @@ impl NetPacket {
} }
macro_rules! trait_handler { macro_rules! trait_handler {
($($name:ident $cmd_type:expr;)*) => { ($($name:tt;)*) => {
pub trait CommandHandler { pub trait CommandHandler {
$( $(
paste! { paste! {
async fn [<on_$name:snake>](session: &mut PlayerSession, body: &$name) -> Result<()> { async fn [<on_$name:snake _cs_req>](session: &mut PlayerSession, request: &[<$name CsReq>]) -> Result<()> {
[<on_$name:snake>](session, body).await let mut response = proto::[<$name ScRsp>]::default();
let _ = [<on_$name:snake _cs_req>](session, request, &mut response).await;
session.send(response).await?;
Ok(())
} }
} }
)* )*
@@ -74,12 +100,14 @@ macro_rules! trait_handler {
session.send_dummy_response(cmd_type).await?; session.send_dummy_response(cmd_type).await?;
return Ok(()); return Ok(());
} }
match cmd_type { match cmd_type {
$( $(
$cmd_type => { cmd_type if cmd_type == paste! { [<Cmd$name CsReq>] as u16 } => {
let body = $name::decode(&mut &payload[..])?; let body = paste! { proto::[<$name CsReq>]::decode(&mut &payload[..])? };
paste! { paste! {
Self::[<on_$name:snake>](session, &body) Self::[<on_$name:snake _cs_req>](session, &body)
.instrument(tracing::info_span!(stringify!([<on_$name:snake>]), cmd_type = cmd_type)) .instrument(tracing::info_span!(stringify!([<on_$name:snake>]), cmd_type = cmd_type))
.await .await
} }
@@ -96,59 +124,54 @@ macro_rules! trait_handler {
} }
trait_handler! { trait_handler! {
PlayerGetTokenCsReq 56; // PlayerGetTokenScRsp PlayerGetToken;
PlayerLoginCsReq 68; // PlayerLoginScRsp, PlayerBasicInfo PlayerLogin;
GetMissionStatusCsReq 1224; // GetMissionStatusScRsp, Mission GetMissionStatus;
GetBasicInfoCsReq 40; // GetBasicInfoScRsp, PlayerSettingInfo GetBasicInfo;
GetMultiPathAvatarInfoCsReq 27; GetMultiPathAvatarInfo;
GetAvatarDataCsReq 368; // GetAvatarDataScRsp, Avatar GetAvatarData;
GetAllLineupDataCsReq 724; // GetAllLineupDataScRsp, LineupInfo, ExtraLineupType, LineupAvatar, AmountInfo GetAllLineupData;
GetCurLineupDataCsReq 711; // GetCurLineupDataScRsp GetCurLineupData;
GetCurSceneInfoCsReq 1439; // GetCurSceneInfoScRsp, SceneInfo GetCurSceneInfo;
PlayerHeartBeatCsReq 31; // PlayerHeartBeatScRsp PlayerHeartBeat;
// // Tutorial (dummy!)
// GetTutorialGuideCsReq 1691;
// UnlockTutorialGuideCsReq 1630;
// GetTutorialCsReq 1661;
// Entity move (dummy!) // Entity move (dummy!)
SceneEntityMoveCsReq 1468; SceneEntityMove;
// Inventory (dummy!) // Inventory (dummy!)
GetBagCsReq 568; GetBag;
GetArchiveDataCsReq 2368; GetArchiveData;
DressAvatarCsReq 351; DressAvatar;
TakeOffEquipmentCsReq 399; TakeOffEquipment;
DressRelicAvatarCsReq 334; DressRelicAvatar;
TakeOffRelicCsReq 398; TakeOffRelic;
// Chat (dummy!) // Chat (dummy!)
SendMsgCsReq 3968; SendMsg;
GetPrivateChatHistoryCsReq 3956; GetPrivateChatHistory;
GetFriendListInfoCsReq 2968; GetFriendListInfo;
GetFriendLoginInfoCsReq 2969; GetFriendLoginInfo;
// In-game lineup // In-game lineup
JoinLineupCsReq 756; JoinLineup;
ChangeLineupLeaderCsReq 748; ChangeLineupLeader;
ReplaceLineupCsReq 790; ReplaceLineup;
QuitLineupCsReq 739; QuitLineup;
// Battle // Battle
StartCocoonStageCsReq 1445; StartCocoonStage;
PveBattleResultCsReq 168; PveBattleResult;
SceneCastSkillCsReq 1456; SceneCastSkill;
// Teleport // Teleport
GetEnteredSceneCsReq 1427; GetEnteredScene;
GetSceneMapInfoCsReq 1436; GetSceneMapInfo;
EnterSceneCsReq 1486; EnterScene;
// Optional // Optional
GetMailCsReq 868; GetMail;
GetGachaInfoCsReq 1968; GetGachaInfo;
DoGachaCsReq 1911; DoGacha;
// GetQuestDataCsReq 961; PlayerLoginFinish;
PlayerLoginFinishCsReq 73;
} }

View File

@@ -1,5 +1,6 @@
use anyhow::Result; use anyhow::Result;
use prost::Message; use prost::Message;
use proto::CmdID;
use tokio::{io::AsyncWriteExt, net::TcpStream}; use tokio::{io::AsyncWriteExt, net::TcpStream};
use super::{packet::CommandHandler, NetPacket}; use super::{packet::CommandHandler, NetPacket};
@@ -20,12 +21,12 @@ impl PlayerSession {
} }
} }
pub async fn send(&mut self, cmd_type: u16, body: impl Message) -> Result<()> { pub async fn send(&mut self, body: impl Message + CmdID) -> Result<()> {
let mut buf = Vec::new(); let mut buf = Vec::new();
body.encode(&mut buf)?; body.encode(&mut buf)?;
let payload: Vec<u8> = NetPacket { let payload: Vec<u8> = NetPacket {
cmd_type, cmd_type: body.get_cmd_id(),
head: Vec::new(), head: Vec::new(),
body: buf, body: buf,
} }

View File

@@ -12,7 +12,6 @@ pub struct AvatarJson {
pub data: AvatarData, pub data: AvatarData,
pub level: u32, pub level: u32,
pub promotion: u32, pub promotion: u32,
// pub rank: u32,
#[serde(alias = "use_technique")] #[serde(alias = "use_technique")]
#[serde(alias = "useTechnique")] #[serde(alias = "useTechnique")]
pub techniques: Vec<u32>, pub techniques: Vec<u32>,
@@ -32,7 +31,6 @@ impl AvatarJson {
pub fn to_avatar_proto(&self, lightcone: Option<&Lightcone>, relics: Vec<&Relic>) -> Avatar { pub fn to_avatar_proto(&self, lightcone: Option<&Lightcone>, relics: Vec<&Relic>) -> Avatar {
Avatar { Avatar {
base_avatar_id: self.avatar_id, base_avatar_id: self.avatar_id,
exp: 0,
level: self.level, level: self.level,
promotion: self.promotion, promotion: self.promotion,
rank: self.data.rank, rank: self.data.rank,
@@ -68,7 +66,7 @@ impl AvatarJson {
) -> (BattleAvatar, Vec<BattleBuff>) { ) -> (BattleAvatar, Vec<BattleBuff>) {
let battle_avatar = BattleAvatar { let battle_avatar = BattleAvatar {
index, index,
avatar_type: AvatarType::AvatarFormalType.into(), avatar_type: AvatarType::AvatarUpgradeAvailableType.into(),
id: self.avatar_id, id: self.avatar_id,
level: self.level, level: self.level,
rank: self.data.rank, rank: self.data.rank,
@@ -358,6 +356,8 @@ pub struct BattleConfig {
pub cycle_count: u32, pub cycle_count: u32,
pub path_resonance_id: u32, pub path_resonance_id: u32,
pub custom_stats: Vec<SubAffix>, pub custom_stats: Vec<SubAffix>,
#[serde(default)]
pub scepters: Vec<RogueMagicScepter>,
} }
impl Default for BattleConfig { impl Default for BattleConfig {
@@ -374,6 +374,7 @@ impl Default for BattleConfig {
cycle_count: Default::default(), cycle_count: Default::default(),
path_resonance_id: Default::default(), path_resonance_id: Default::default(),
custom_stats: Default::default(), custom_stats: Default::default(),
scepters: Default::default(),
} }
} }
} }
@@ -429,6 +430,29 @@ impl BattleBuffJson {
} }
} }
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Default)]
#[repr(u32)]
pub enum RogueMagicComponentType {
Passive = 3,
#[default]
Active = 4,
Attach = 5,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
pub struct RogueMagicScepter {
pub level: u32,
pub id: u32,
pub components: Vec<RogueMagicComponent>,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
pub struct RogueMagicComponent {
pub id: u32,
pub level: u32,
pub component_type: RogueMagicComponentType,
}
// SCENE // SCENE
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Scene { pub struct Scene {
@@ -463,13 +487,11 @@ impl Position {
pub fn to_motion(&self) -> MotionInfo { pub fn to_motion(&self) -> MotionInfo {
MotionInfo { MotionInfo {
// rot
rot: Some(Vector { rot: Some(Vector {
x: 0, x: 0,
y: self.rot_y, y: self.rot_y,
z: 0, z: 0,
}), }),
// pos
pos: Some(Vector { pos: Some(Vector {
x: self.x, x: self.x,
y: self.y, y: self.y,
@@ -488,15 +510,15 @@ pub struct FreesrData {
#[serde(default)] #[serde(default)]
pub battle_config: BattleConfig, pub battle_config: BattleConfig,
#[serde(default)] #[serde(default, skip_serializing)]
pub lineups: BTreeMap<u32, u32>, pub lineups: BTreeMap<u32, u32>,
#[serde(default)] #[serde(default, skip_serializing)]
pub position: Position, pub position: Position,
#[serde(default)] #[serde(default, skip_serializing)]
pub scene: Scene, pub scene: Scene,
#[serde(default)] #[serde(default, skip_serializing)]
pub main_character: MultiPathAvatar, pub main_character: MultiPathAvatar,
#[serde(default)] #[serde(default, skip_serializing)]
pub march_type: MultiPathAvatar, pub march_type: MultiPathAvatar,
} }
@@ -517,7 +539,7 @@ pub struct Persistent {
impl Default for Persistent { impl Default for Persistent {
fn default() -> Self { fn default() -> Self {
let mut lineups = BTreeMap::<u32, u32>::new(); let mut lineups = BTreeMap::<u32, u32>::new();
lineups.insert(0, 8006); lineups.insert(0, 8001);
lineups.insert(1, 0); lineups.insert(1, 0);
lineups.insert(2, 0); lineups.insert(2, 0);
lineups.insert(3, 0); lineups.insert(3, 0);
@@ -624,7 +646,7 @@ impl FreesrData {
async fn verify_lineup(&mut self) { async fn verify_lineup(&mut self) {
if self.lineups.is_empty() { if self.lineups.is_empty() {
self.lineups = BTreeMap::<u32, u32>::from([(0, 8006), (1, 0), (2, 0), (3, 0)]) self.lineups = BTreeMap::<u32, u32>::from([(0, 8001), (1, 0), (2, 0), (3, 0)])
} else if self.lineups.len() < 4 { } else if self.lineups.len() < 4 {
for i in self.lineups.len()..4 { for i in self.lineups.len()..4 {
self.lineups.insert(i as u32, 0); self.lineups.insert(i as u32, 0);

View File

@@ -1,345 +0,0 @@
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LevelGroup {
#[serde(rename = "GroupGUID")]
pub group_guid: String,
#[serde(default)]
#[serde(rename = "LoadSide")]
pub load_side: LoadSide,
#[serde(default)]
#[serde(rename = "LoadOnInitial")]
pub load_on_initial: bool,
#[serde(default)]
#[serde(rename = "AnchorList")]
pub anchor_list: Vec<LevelAnchor>,
#[serde(default)]
#[serde(rename = "MonsterList")]
pub monster_list: Vec<LevelMonster>,
#[serde(default)]
#[serde(rename = "PropList")]
pub prop_list: Vec<LevelProp>,
#[serde(default)]
#[serde(rename = "NPCList")]
pub npc_list: Vec<LevelNPC>,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LevelProp {
#[serde(rename = "ID")]
pub id: u32, // need
#[serde(default)]
#[serde(rename = "Category")]
pub category: String,
#[serde(default)]
#[serde(rename = "GroupName")]
pub group_name: String,
#[serde(default)]
#[serde(rename = "LoadSide")]
pub load_side: Option<LoadSide>, // need
#[serde(default)]
#[serde(rename = "PosX")]
pub pos_x: f64, // n
#[serde(default)]
#[serde(rename = "PosY")]
pub pos_y: f64, // n
#[serde(default)]
#[serde(rename = "PosZ")]
pub pos_z: f64, // n
#[serde(default)]
#[serde(rename = "RotY")]
pub rot_y: f64, // n
#[serde(rename = "PropID")]
pub prop_id: u32, // n
#[serde(rename = "AnchorID")]
pub anchor_id: Option<u32>, // n
#[serde(rename = "AnchorGroupID")]
pub anchor_group_id: Option<u32>, // n
#[serde(rename = "MappingInfoID")]
pub mapping_info_id: Option<u32>, // n
#[serde(rename = "InitLevelGraph")]
pub init_level_graph: Option<String>,
#[serde(default)]
#[serde(rename = "State")]
pub state: PropState,
#[serde(default)]
pub prop_state_list: Vec<PropState>,
#[serde(default)]
pub group_id: u32,
#[serde(rename = "IsDelete")]
#[serde(default)]
pub is_delete: bool, // n
#[serde(rename = "IsClientOnly")]
#[serde(default)]
pub client_only: bool, // n
// #[serde(default)]
// pub is_door: bool,
// #[serde(default)]
// pub is_chest: bool,
#[serde(default)]
pub __test_field: String,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LevelAnchor {
#[serde(rename = "ID")]
pub id: u32,
#[serde(default)]
#[serde(rename = "PosX")]
pub pos_x: f64,
#[serde(default)]
#[serde(rename = "PosY")]
pub pos_y: f64,
#[serde(default)]
#[serde(rename = "PosZ")]
pub pos_z: f64,
#[serde(default)]
#[serde(rename = "RotY")]
pub rot_y: f64,
#[serde(default)]
pub group_id: u32,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LevelNPC {
#[serde(rename = "ID")]
pub id: u32,
#[serde(default)]
#[serde(rename = "PosX")]
pub pos_x: f64,
#[serde(default)]
#[serde(rename = "PosY")]
pub pos_y: f64,
#[serde(default)]
#[serde(rename = "PosZ")]
pub pos_z: f64,
#[serde(rename = "Name")]
pub name: String,
#[serde(default)]
#[serde(rename = "RotY")]
pub rot_y: f64,
#[serde(rename = "NPCID")]
pub npcid: u32,
#[serde(default)]
pub group_id: u32,
#[serde(rename = "IsDelete")]
#[serde(default)]
pub is_delete: bool,
#[serde(rename = "IsClientOnly")]
#[serde(default)]
pub client_only: bool,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LevelMonster {
#[serde(rename = "ID")]
pub id: u32,
#[serde(default)]
#[serde(rename = "RotY")]
pub rot_y: f64,
#[serde(default)]
#[serde(rename = "PosX")]
pub pos_x: f64,
#[serde(default)]
#[serde(rename = "PosY")]
pub pos_y: f64,
#[serde(default)]
#[serde(rename = "PosZ")]
pub pos_z: f64,
#[serde(rename = "NPCMonsterID")]
pub npcmonster_id: u32,
#[serde(default)]
#[serde(rename = "EventID")]
pub event_id: u32,
#[serde(default)]
pub group_id: u32,
#[serde(rename = "IsDelete")]
#[serde(default)]
pub is_delete: bool,
#[serde(rename = "IsClientOnly")]
#[serde(default)]
pub client_only: bool,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Copy)]
pub enum LoadSide {
Client = 0,
Server = 1,
Unk = 2,
}
impl Default for LoadSide {
fn default() -> Self {
Self::Client
}
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LevelFloor {
pub floor_id: u32,
pub floor_name: String,
pub start_group_index: u32,
pub start_anchor_id: u32,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MapEntrance {
#[serde(rename = "ID")]
pub id: u32,
#[serde(default)]
#[serde(rename = "EntranceType")]
pub entrance_type: PlaneType,
#[serde(rename = "PlaneID")]
pub plane_id: u32,
#[serde(rename = "FloorID")]
pub floor_id: u32,
#[serde(rename = "BeginMainMissionList")]
pub begin_main_mission_list: Vec<Value>,
#[serde(rename = "FinishMainMissionList")]
pub finish_main_mission_list: Vec<Value>,
#[serde(rename = "FinishSubMissionList")]
pub finish_sub_mission_list: Vec<Value>,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MazePlane {
#[serde(rename = "PlaneID")]
pub plane_id: u32,
#[serde(rename = "PlaneType")]
pub plane_type: PlaneType,
#[serde(rename = "SubType")]
pub sub_type: u32,
#[serde(rename = "MazePoolType")]
pub maze_pool_type: u32,
#[serde(rename = "WorldID")]
pub world_id: u32,
#[serde(rename = "StartFloorID")]
pub start_floor_id: u32,
#[serde(rename = "FloorIDList")]
pub floor_idlist: Vec<u32>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Copy)]
pub enum PlaneType {
Unknown = 0,
Maze = 2,
Train = 3,
Challenge = 4,
Rogue = 5,
Raid = 6,
AetherDivide = 7,
TrialActivity = 8,
#[serde(other)]
Town = 1,
}
impl Default for PlaneType {
fn default() -> Self {
Self::Maze
}
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MazeProp {
#[serde(rename = "ID")]
pub id: u32,
#[serde(rename = "PropType")]
pub prop_type: String,
#[serde(rename = "PropStateList")]
pub prop_state_list: Vec<PropState>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub enum PropState {
#[default] Closed = 0,
Open = 1,
Locked = 2,
BridgeState1 = 3,
BridgeState2 = 4,
BridgeState3 = 5,
BridgeState4 = 6,
CheckPointDisable = 7,
CheckPointEnable = 8,
TriggerDisable = 9,
TriggerEnable = 10,
ChestLocked = 11,
ChestClosed = 12,
ChestUsed = 13,
Elevator1 = 14,
Elevator2 = 15,
Elevator3 = 16,
WaitActive = 17,
EventClose = 18,
EventOpen = 19,
Hidden = 20,
TeleportGate0 = 21,
TeleportGate1 = 22,
TeleportGate2 = 23,
TeleportGate3 = 24,
Destructed = 25,
CustomState01 = 101,
CustomState02 = 102,
CustomState03 = 103,
CustomState04 = 104,
CustomState05 = 105,
CustomState06 = 106,
CustomState07 = 107,
CustomState08 = 108,
CustomState09 = 109,
}
pub type IntMap<T> = HashMap<u32, T>;
pub type StringMap<T> = HashMap<String, T>;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SimpleLevelGroup {
pub teleports: IntMap<LevelProp>,
pub group_items: IntMap<LevelGroupItem>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct LevelGroupItem {
pub props: Vec<LevelProp>,
pub npcs: Vec<LevelNPC>,
pub monsters: Vec<LevelMonster>,
pub anchors: HashMap<u32, LevelAnchor>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct GameResources {
pub map_entrance: IntMap<MapEntrance>,
/// Key is P{PLANE_ID}_F{FLOOR_ID}
pub level_group: StringMap<SimpleLevelGroup>,
pub maze_prop: IntMap<MazeProp>,
pub maze_plane: IntMap<MazePlane>,
}
impl GameResources {
pub fn new() -> Self {
let str = std::fs::read_to_string("./resources.json")
.expect("resources.json is broken, pls redownload");
let res: Self =
serde_json::from_str(&str).expect("resources.json is broken, pls redownload");
res
}
}
lazy_static! {
pub static ref GAME_RESOURCES: GameResources = GameResources::new();
}

View File

@@ -0,0 +1 @@
pub mod resources;

View File

@@ -0,0 +1,145 @@
use serde::Deserialize;
use std::{collections::HashMap, fs, sync::LazyLock};
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Vector {
pub x: i32, // or f32 depending on your needs
pub y: i32,
pub z: i32,
}
#[derive(Deserialize, Copy, PartialEq, Clone)]
#[serde(rename_all = "camelCase")]
#[repr(u32)]
pub enum PropState {
Closed = 0,
Open = 1,
Locked = 2,
BridgeState1 = 3,
BridgeState2 = 4,
BridgeState3 = 5,
BridgeState4 = 6,
CheckPointDisable = 7,
CheckPointEnable = 8,
TriggerDisable = 9,
TriggerEnable = 10,
ChestLocked = 11,
ChestClosed = 12,
ChestUsed = 13,
Elevator1 = 14,
Elevator2 = 15,
Elevator3 = 16,
WaitActive = 17,
EventClose = 18,
EventOpen = 19,
Hidden = 20,
TeleportGate0 = 21,
TeleportGate1 = 22,
TeleportGate2 = 23,
TeleportGate3 = 24,
Destructed = 25,
CustomState01 = 101,
CustomState02 = 102,
CustomState03 = 103,
CustomState04 = 104,
CustomState05 = 105,
CustomState06 = 106,
CustomState07 = 107,
CustomState08 = 108,
CustomState09 = 109,
}
#[derive(Deserialize, Copy, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
#[repr(u32)]
pub enum PlaneType {
Unknown = 0,
Maze = 2,
Train = 3,
Challenge = 4,
Rogue = 5,
Raid = 6,
AetherDivide = 7,
TrialActivity = 8,
Town = 1,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SceneMonsterInfo {
pub pos: Vector,
pub rot: Vector,
pub group_id: u32,
pub inst_id: u32,
pub monster_id: u32,
pub event_id: u32,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SceneNpcInfo {
pub pos: Vector,
pub rot: Vector,
pub group_id: u32,
pub inst_id: u32,
pub npc_id: u32,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ScenePropInfo {
pub pos: Vector,
pub rot: Vector,
pub group_id: u32,
pub inst_id: u32,
pub prop_state: u32,
pub prop_id: u32,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TeleportInfo {
pub pos: Vector,
pub rot: Vector,
pub group_id: u32,
pub inst_id: u32,
pub anchor_id: u32,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SceneData {
pub npcs: Vec<SceneNpcInfo>,
pub props: Vec<ScenePropInfo>,
pub monsters: Vec<SceneMonsterInfo>,
pub teleports: HashMap<u32, TeleportInfo>,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LevelOutputConfig {
pub is_entered_scene_info: bool,
pub scenes: HashMap<u32, SceneData>,
pub plane_type: u32,
pub world_id: u32,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AvatarConfig {
pub weakness_buff_id: u32,
pub technique_buff_ids: Vec<u32>,
}
#[derive(Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct JsonConfig {
/// `entryid` -> `P[planeId]_F[floorId]` -> `groupId`
pub level_output_configs: HashMap<u32, HashMap<String, LevelOutputConfig>>,
pub avatar_configs: HashMap<u32, AvatarConfig>,
}
pub static GAME_RES: LazyLock<JsonConfig> = LazyLock::new(|| {
serde_json::from_str::<JsonConfig>(&fs::read_to_string("res.json").unwrap()).unwrap()
});

View File

@@ -1,21 +1,21 @@
{ {
"lineups": { "lineups": {
"0": 1222, "0": 1220,
"1": 1223, "1": 1222,
"2": 1220, "2": 1304,
"3": 1308 "3": 1309
}, },
"position": { "position": {
"x": -3722, "x": 64574,
"y": 56256, "y": 1699,
"z": -87464, "z": 258502,
"rot_y": 318488 "rot_y": 243401
}, },
"scene": { "scene": {
"plane_id": 20321, "plane_id": 20332,
"floor_id": 20321001, "floor_id": 20332001,
"entry_id": 2032101 "entry_id": 2033201
}, },
"main_character": "FemaleHarmony", "main_character": "FemaleHarmony",
"march_type": "MarchHunt" "march_type": "FemaleHarmony"
} }

View File

@@ -6,6 +6,7 @@ version.workspace = true
[dependencies] [dependencies]
prost.workspace = true prost.workspace = true
prost-types.workspace = true prost-types.workspace = true
proto-derive.workspace = true
[build-dependencies] [build-dependencies]
prost-build.workspace = true prost-build.workspace = true

View File

@@ -1,3 +1,9 @@
use std::{
fs,
io::{self, BufRead},
path::Path,
};
pub fn main() { pub fn main() {
let proto_file = "StarRail.proto"; let proto_file = "StarRail.proto";
if std::path::Path::new(proto_file).exists() { if std::path::Path::new(proto_file).exists() {
@@ -5,7 +11,38 @@ pub fn main() {
prost_build::Config::new() prost_build::Config::new()
.out_dir("out/") .out_dir("out/")
.type_attribute(".", "#[derive(proto_derive::CmdID)]")
.compile_protos(&[proto_file], &["."]) .compile_protos(&[proto_file], &["."])
.unwrap(); .unwrap();
impl_message_id(Path::new("out/_.rs")).unwrap();
} }
} }
pub fn impl_message_id(path: &Path) -> io::Result<()> {
let file = fs::File::open(path)?;
let reader = io::BufReader::new(file);
let mut output = Vec::new();
let mut attr = None;
for line in reader.lines() {
let line = line?;
if line.contains("CmdID:") {
attr = Some(make_message_id_attr(&line).unwrap());
} else {
output.push(line);
if let Some(attr) = attr.take() {
output.push(attr);
}
}
}
fs::write(path, output.join("\n").as_bytes())?;
Ok(())
}
fn make_message_id_attr(line: &str) -> Option<String> {
let id = line.trim_start().split(' ').nth(2)?.parse::<u16>().ok()?;
Some(format!("#[cmdid({id})]"))
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
[package]
name = "proto-derive"
version = "0.1.0"
edition = "2021"
[dependencies]
syn = "2.0.53"
quote = "1.0.35"
proc-macro2 = "1.0.79"
[lib]
proc-macro = true

View File

@@ -0,0 +1,27 @@
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{parse_macro_input, DeriveInput, Meta, MetaList};
#[proc_macro_derive(CmdID, attributes(cmdid))]
pub fn message_id_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let struct_name = input.ident;
let id = match input
.attrs
.iter()
.find(|attr| attr.path().is_ident("cmdid"))
{
Some(attr) => match attr.meta {
Meta::List(MetaList { ref tokens, .. }) => tokens.into_token_stream(),
_ => panic!("Invalid cmdid attribute value"),
},
_ => 0u16.into_token_stream(),
};
TokenStream::from(quote! {
impl crate::CmdID for #struct_name {
const CMD_ID: u16 = #id;
}
})
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,12 @@
mod cmd_types;
pub use cmd_types::*;
include!("../out/_.rs"); include!("../out/_.rs");
pub use prost::DecodeError as ProtobufDecodeError;
pub use prost::Message as Protobuf;
pub trait CmdID {
const CMD_ID: u16;
fn get_cmd_id(&self) -> u16 {
Self::CMD_ID
}
}

0
proto/src/message.rs Normal file
View File

662361
res.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -42,7 +42,6 @@ pub async fn query_gateway(parameters: Query<QueryGatewayParameters>) -> String
asset_bundle_url: config.asset_bundle_url.clone(), asset_bundle_url: config.asset_bundle_url.clone(),
ex_resource_url: config.ex_resource_url.clone(), ex_resource_url: config.ex_resource_url.clone(),
lua_url: config.lua_url.clone(), lua_url: config.lua_url.clone(),
// lua_version: config.lua_version.clone(),
ifix_version: String::from("0"), ifix_version: String::from("0"),
unk1: true, unk1: true,
unk2: true, unk2: true,
@@ -51,14 +50,8 @@ pub async fn query_gateway(parameters: Query<QueryGatewayParameters>) -> String
unk5: true, unk5: true,
unk6: true, unk6: true,
unk7: true, unk7: true,
mmcachlfjaa: true, jgciiljehhe: true,
ncikdciigof: true,
efknbdlnakj: true,
gpjcfcjdmol: true,
jidbdekohdh: true,
pphbpgbnoem: true,
dhppkkgjldl: true,
jipjkleanbd: true,
..Default::default() ..Default::default()
} }
} else { } else {

View File

@@ -1,14 +1,14 @@
{ {
"CNBETAWin2.2.51": { "CNBETAWin2.5.51": {
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_7037158_b67f5a6a68fb", "asset_bundle_url": "",
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_7033392_aaca9c1b456b", "ex_resource_url": "",
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_7050564_f05a0f949b10", "lua_url": "",
"lua_version": "7050564" "ifix_url": ""
}, },
"OSBETAWin2.2.51": { "CNBETAWin2.5.52": {
"asset_bundle_url": "https://autopatchos.starrails.com/asb/BetaLive/output_7037158_b67f5a6a68fb", "asset_bundle_url": "",
"ex_resource_url": "https://autopatchos.starrails.com/design_data/BetaLive/output_7033392_aaca9c1b456b", "ex_resource_url": "",
"lua_url": "https://autopatchos.starrails.com/lua/BetaLive/output_7050564_f05a0f949b10", "lua_url": "",
"lua_version": "7050564" "ifix_url": ""
} }
} }

View File

@@ -1,8 +1,14 @@
{ {
"CNBETAWin2.4.51": { "CNBETAWin2.5.51": {
"asset_bundle_url": "https://autopatchcn-ipv6.bhsr.com/asb/BetaLive/output_7663997_cd086af3f307", "asset_bundle_url": "",
"ex_resource_url": "https://autopatchcn-ipv6.bhsr.com/design_data/BetaLive/output_7689868_456662b48277", "ex_resource_url": "",
"lua_url": "https://autopatchcn-ipv6.bhsr.com/lua/BetaLive/output_7668875_0231727458ad", "lua_url": "",
"ifix_url": "https://autopatchcn-ipv6.bhsr.com/ifix/BetaLive/output_0_40d2ce0253" "ifix_url": ""
},
"CNBETAWin2.5.52": {
"asset_bundle_url": "",
"ex_resource_url": "",
"lua_url": "",
"ifix_url": ""
} }
} }