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
+3 -1
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.
+7580 -509
View File
File diff suppressed because it is too large Load Diff
+1
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
+1
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;
+18 -34
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(), nickname: String::from("RobinSR"),
stamina: 240, level: 70,
basic_info: Some(PlayerBasicInfo { world_level: 6,
nickname: String::from("RobinSR"), stamina: 240,
level: 70, ..Default::default()
world_level: 6, });
stamina: 240,
..Default::default()
}),
..Default::default()
},
)
.await
} }
+36 -43
View File
@@ -2,55 +2,48 @@ 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, .iter()
GetAvatarDataScRsp { .map(|id| {
retcode: 0, json.avatars
is_get_all: body.is_get_all, .get(id)
avatar_list: UNLOCKED_AVATARS .map(|v| {
.iter() v.to_avatar_proto(
.map(|id| { json.lightcones.iter().find(|v| v.equip_avatar == *id),
json.avatars json.relics
.get(id) .iter()
.map(|v| { .filter(|v| v.equip_avatar == *id)
v.to_avatar_proto( .collect(),
json.lightcones.iter().find(|v| v.equip_avatar == *id), )
json.relics })
.iter() .unwrap_or(Avatar {
.filter(|v| v.equip_avatar == *id) base_avatar_id: *id,
.collect(), level: 80,
) promotion: 6,
}) rank: 6,
.unwrap_or(Avatar { skilltree_list: (1..=4)
base_avatar_id: *id, .map(|m| AvatarSkillTree {
level: 80, point_id: (*id) * 1000 + m,
promotion: 6, level: 1,
rank: 6, })
skilltree_list: (1..=4) .collect(),
.map(|m| AvatarSkillTree { first_met_timestamp: 1712924677,
point_id: (*id) * 1000 + m, ..Default::default()
level: 1, })
}) })
.collect(), .collect();
..Default::default()
})
})
.collect(),
..Default::default()
},
)
.await
} }
+72 -38
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
} }
+165 -212
View File
@@ -8,118 +8,91 @@ 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, friend_name: String::from("RobinSR"),
GetFriendListInfoScRsp { simple_info: Some(SimpleInfo {
friend_list: vec![FriendListInfo { uid: SERVER_UID,
friend_name: String::from("RobinSR"), platform_type: PlatformType::Pc.into(),
simple_info: Some(SimpleInfo { online_status: FriendOnlineStatus::Online.into(),
uid: 727, head_icon: SERVER_HEAD_ICON,
platform_type: 3, chat_bubble_id: SERVER_CHAT_BUBBLE_ID,
online_status: 1, level: 70,
head_icon: 201008, nickname: String::from("Server"),
chat_bubble_id: 220005, signature: String::from("omg"),
level: 70, ..Default::default()
nickname: String::from("Server"), }),
signature: String::from("omg"), is_marked: true,
..Default::default() sent_time: 0,
}), ..Default::default()
is_marked: true, }];
sent_time: 0,
..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_time,
sent_time: cur_timestamp_ms(), text: String::from(*text),
text: "'sync'".to_string(), sender_uid: SERVER_UID,
sender_uid: 727, ..Default::default()
..Default::default() })
}, .collect();
Chat { res.to_uid = req.to_uid;
msg_type: MsgType::CustomText.into(), res.from_uid = SERVER_UID;
sent_time: cur_timestamp_ms(),
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, msg_type: body.msg_type,
RevcMsgScNotify { text: String::from("Inventory Synced"),
msg_type: body.msg_type, emote: body.emote,
text: String::from("Inventory Synced"), from_uid: SERVER_UID, // from
emote: body.emote, to_uid: 25, // to
from_uid: 727, // from chat_type: body.chat_type,
to_uid: 25, // to ..Default::default()
chat_type: body.chat_type, })
}, .await
) .unwrap();
.await?;
} }
"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, base_avatar_id: 8001,
AvatarPathChangedNotify { cur_multi_path_avatar_type: mc as i32,
base_avatar_id: 8001, })
cur_multi_path_avatar_type: mc as i32, .await
}, .unwrap();
)
.await?;
session session
.send( .send(RevcMsgScNotify {
CMD_REVC_MSG_SC_NOTIFY, msg_type: body.msg_type,
RevcMsgScNotify { text: format!("Success change mc to {:#?}", mc),
msg_type: body.msg_type, emote: body.emote,
text: format!("Success change mc to {:#?}", mc), from_uid: SERVER_UID, // from
emote: body.emote, to_uid: 25, // to
from_uid: 727, // from chat_type: body.chat_type,
to_uid: 25, // to ..Default::default()
chat_type: body.chat_type, })
}, .await
) .unwrap();
.await?;
} }
"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, base_avatar_id: 1001,
AvatarPathChangedNotify { cur_multi_path_avatar_type: march_type as i32,
base_avatar_id: 1001, })
cur_multi_path_avatar_type: march_type as i32, .await
}, .unwrap();
)
.await?;
session session
.send( .send(RevcMsgScNotify {
CMD_REVC_MSG_SC_NOTIFY, msg_type: body.msg_type,
RevcMsgScNotify { text: format!("Success change march to {:#?}", march_type),
msg_type: body.msg_type, emote: body.emote,
text: format!("Success change march to {:#?}", march_type), from_uid: SERVER_UID, // from
emote: body.emote, to_uid: 25, // to
from_uid: 727, // from chat_type: body.chat_type,
to_uid: 25, // to ..Default::default()
chat_type: body.chat_type, })
}, .await
) .unwrap();
.await?;
} }
_ => {} _ => {}
} }
} }
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,72 +173,68 @@ 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, del_equipment_list: (2000..3500).collect(),
PlayerSyncScNotify { del_relic_list: (1..2000).collect(),
del_equipment_list: (2000..3500).collect(), ..Default::default()
del_relic_list: (1..2000).collect(), })
..Default::default()
},
)
.await?;
session
.send(
CMD_PLAYER_SYNC_SC_NOTIFY,
PlayerSyncScNotify {
avatar_sync: Some(AvatarSync {
avatar_list: json
.avatars
.values()
.map(|avatar| avatar.to_avatar_proto(Option::None, vec![]))
.collect::<Vec<_>>(),
}),
..Default::default()
},
)
.await?;
session
.send(
CMD_PLAYER_SYNC_SC_NOTIFY,
PlayerSyncScNotify {
relic_list: json.relics.iter().map(|v| v.to_relic_proto()).collect(),
equipment_list: json
.lightcones
.iter()
.map(|v| v.to_equipment_proto())
.collect(),
..Default::default()
},
)
.await?;
session
.send(
CMD_PLAYER_SYNC_SC_NOTIFY,
PlayerSyncScNotify {
avatar_sync: Some(AvatarSync {
avatar_list: json
.avatars
.values()
.map(|avatar| {
avatar.to_avatar_proto(
json.lightcones
.iter()
.find(|v| v.equip_avatar == avatar.avatar_id),
json.relics
.iter()
.filter(|v| v.equip_avatar == avatar.avatar_id)
.collect(),
)
})
.collect(),
}),
..Default::default()
},
)
.await .await
.unwrap();
// Sync avatars
session
.send(PlayerSyncScNotify {
avatar_sync: Some(AvatarSync {
avatar_list: json
.avatars
.values()
.map(|avatar| avatar.to_avatar_proto(Option::None, vec![]))
.collect::<Vec<_>>(),
}),
..Default::default()
})
.await
.unwrap();
// Sync new relics
session
.send(PlayerSyncScNotify {
relic_list: json.relics.iter().map(|v| v.to_relic_proto()).collect(),
equipment_list: json
.lightcones
.iter()
.map(|v| v.to_equipment_proto())
.collect(),
..Default::default()
})
.await
.unwrap();
// Sync new lightcones
session
.send(PlayerSyncScNotify {
avatar_sync: Some(AvatarSync {
avatar_list: json
.avatars
.values()
.map(|avatar| {
avatar.to_avatar_proto(
json.lightcones
.iter()
.find(|v| v.equip_avatar == avatar.avatar_id),
json.relics
.iter()
.filter(|v| v.equip_avatar == avatar.avatar_id)
.collect(),
)
})
.collect(),
}),
..Default::default()
})
.await
.unwrap()
} }
+28 -43
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,47 +18,31 @@ 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, .map(|v| GachaItem {
gacha_num: req.gacha_num, is_new: false,
gacha_item_list: (0..req.gacha_num) gacha_item: Some(Item {
.map(|v| GachaItem { item_id: if v % 2 == 0 { 1310 } else { 1314 },
is_new: false,
gacha_item: Some(Item {
item_id: if v % 2 == 0 { 1310 } else { 1314 },
..Default::default()
}),
token_item: Some(ItemList {
item_list: vec![Item {
item_id: 251,
num: 100,
..Default::default()
}],
}),
transfer_item_list: Some(ItemList { item_list: vec![] }),
})
.collect(),
..Default::default() ..Default::default()
}, }),
) token_item: Some(ItemList {
.await item_list: vec![Item {
} item_id: 251,
num: 100,
..Default::default()
}],
}),
transfer_item_list: Some(ItemList { item_list: vec![] }),
})
.collect();
}
+43 -73
View File
@@ -1,96 +1,66 @@
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( .lightcones
CMD_GET_BAG_SC_RSP, .iter()
GetBagScRsp { .map(|v| v.to_equipment_proto())
equipment_list: player .collect();
.lightcones res.relic_list = player.relics.iter().map(|v| v.to_relic_proto()).collect();
.iter() res.material_list = vec![
.map(|v| v.to_equipment_proto()) Material {
.collect(), tid: 101, // Normal Pass
relic_list: player.relics.iter().map(|v| v.to_relic_proto()).collect(), num: 999999,
material_list: vec![ ..Default::default()
Material { },
tid: 101, // Normal Pass Material {
num: 999999, tid: 102, // Special Pass
..Default::default() num: 999999,
}, ..Default::default()
Material { },
tid: 102, // Special Pass ];
num: 999999,
..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
} }
+58 -107
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,95 +38,63 @@ 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 lineups = &mut player.lineups;
let mut player = tools::FreesrData::load().await; lineups.insert(
let lineups = &mut player.lineups; body.slot,
lineups.insert( if body.base_avatar_id == 8001 {
body.slot, player.main_character as u32
if body.base_avatar_id == 8001 { } else if body.base_avatar_id == 1001 {
player.main_character as u32 player.march_type as u32
} else if body.base_avatar_id == 1001 { } else {
player.march_type as u32 body.base_avatar_id
} else { },
body.base_avatar_id );
}, player.save_lineup().await;
); refresh_lineup(session, &player).await;
player.save_lineup().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;
for (slot, avatar_id) in &mut *lineups { for (slot, avatar_id) in &mut *lineups {
if let Some(lineup) = req.slots.get(*slot as usize) { if let Some(lineup) = req.slots.get(*slot as usize) {
*avatar_id = if lineup.id == 8001 { *avatar_id = if lineup.id == 8001 {
player.main_character as u32 player.main_character as u32
} else if lineup.id == 1001 { } else if lineup.id == 1001 {
player.march_type as u32 player.march_type as u32
} else {
lineup.id
};
} else { } else {
*avatar_id = 0; lineup.id
} };
} else {
*avatar_id = 0;
} }
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
} }
+27 -35
View File
@@ -1,37 +1,29 @@
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!"),
id: 1, id: 1,
is_read: false, is_read: false,
time: 1716041089, time: 1716041089,
expire_time: 1718633089, expire_time: 1718633089,
para_list: vec![], para_list: vec![],
attachment: Some(ItemList { attachment: Some(ItemList {
item_list: vec![Item { item_list: vec![Item {
item_id: 1310, item_id: 1310,
level: 80, level: 80,
num: 1, num: 1,
..Default::default() ..Default::default()
}], }],
}), }),
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
}
+14 -19
View File
@@ -1,23 +1,18 @@
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 { id: *id,
id: *id, 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
}
-2
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::{
+90 -134
View File
@@ -1,157 +1,113 @@
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, version: 51,
client_time_ms: body.client_time_ms, time: res.server_time_ms as i64,
server_time_ms: util::cur_timestamp_ms(), data: rbase64::decode("bG9jYWwgZnVuY3Rpb24gYmV0YV90ZXh0KG9iaikKICAgIGxvY2FsIGdhbWVPYmplY3QgPSBDUy5Vbml0eUVuZ2luZS5HYW1lT2JqZWN0LkZpbmQoIlVJUm9vdC9BYm92ZURpYWxvZy9CZXRhSGludERpYWxvZyhDbG9uZSkiKQoKICAgIGlmIGdhbWVPYmplY3QgdGhlbgogICAgICAgIGxvY2FsIHRleHRDb21wb25lbnQgPSBnYW1lT2JqZWN0OkdldENvbXBvbmVudEluQ2hpbGRyZW4odHlwZW9mKENTLlJQRy5DbGllbnQuTG9jYWxpemVkVGV4dCkpCgogICAgICAgIGlmIHRleHRDb21wb25lbnQgdGhlbgogICAgICAgICAgICB0ZXh0Q29tcG9uZW50LnRleHQgPSAiUm9iaW5TUiBpcyBhIGZyZWUgYW5kIG9wZW4gc291cmNlIHNvZnR3YXJlLiBkaXNjb3JkLmdnL3JldmVyc2Vkcm9vbXMiCiAgICAgICAgZW5kCiAgICBlbHNlCiAgICBlbmQKZW5kCgpiZXRhX3RleHQoKQ==").unwrap()
download_data: Some(ClientDownloadData { });
version: 51,
time: util::cur_timestamp_ms() as i64,
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?; data: Some(PackageData {
info_list: vec![
session 200001, 200002, 200003, 200004, 150017, 150015, 150021, 150018, 130011, 130012,
.send( 130013,
CMD_CONTENT_PACKAGE_SYNC_DATA_SC_NOTIFY, ]
ContentPackageSyncDataScNotify { .iter()
data: Some(PackageData { .map(|v| ContentInfo {
info_list: vec![ status: ContentPackageStatus::Finished.into(),
ContentInfo { content_id: *v,
status: ContentPackageStatus::Finished.into(), })
content_id: 200001, .collect(),
}, ..Default::default()
ContentInfo { }),
status: ContentPackageStatus::Finished.into(), })
content_id: 200002, .await
},
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()
}),
},
)
.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,
equip_relic_list: json equip_relic_list: json
.relics .relics
.iter() .iter()
.filter(|v| v.equip_avatar == json.main_character as u32) .filter(|v| v.equip_avatar == json.main_character as u32)
.map(|v| v.to_equipment_relic_proto()) .map(|v| v.to_equipment_relic_proto())
.collect(), .collect(),
skilltree_list: (1..=4) skilltree_list: (1..=4)
.map(|v| AvatarSkillTree { .map(|v| AvatarSkillTree {
level: 1, level: 1,
point_id: (json.main_character as u32) * 1000 + v, point_id: (json.main_character as u32) * 1000 + v,
}) })
.collect(), .collect(),
path_equipment_id: json path_equipment_id: json
.lightcones .lightcones
.iter() .iter()
.find(|v| v.equip_avatar == json.main_character as u32) .find(|v| v.equip_avatar == json.main_character as u32)
.map(|v| v.internal_uid) .map(|v| v.internal_uid)
.unwrap_or_default(), .unwrap_or_default(),
}, },
MultiPathAvatarTypeInfo { MultiPathAvatarTypeInfo {
avatar_id: json.march_type as i32, avatar_id: json.march_type as i32,
rank: 6, rank: 6,
equip_relic_list: json equip_relic_list: json
.relics .relics
.iter() .iter()
.filter(|v| v.equip_avatar == json.march_type as u32) .filter(|v| v.equip_avatar == json.march_type as u32)
.map(|v| v.to_equipment_relic_proto()) .map(|v| v.to_equipment_relic_proto())
.collect(), .collect(),
skilltree_list: (1..=4) skilltree_list: (1..=4)
.map(|v| AvatarSkillTree { .map(|v| AvatarSkillTree {
level: 1, level: 1,
point_id: (json.march_type as u32) * 1000 + v, point_id: (json.march_type as u32) * 1000 + v,
}) })
.collect(), .collect(),
path_equipment_id: json path_equipment_id: json
.lightcones .lightcones
.iter() .iter()
.find(|v| v.equip_avatar == json.march_type as u32) .find(|v| v.equip_avatar == json.march_type as u32)
.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
} }
+160 -227
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, Some(scene)
scene: if let Ok(scene) = scene { } else {
Some(scene) Some(SceneInfo {
} else { game_mode_type: 3,
Some(SceneInfo { entry_id: player.scene.entry_id,
game_mode_type: 1, plane_id: player.scene.plane_id,
entry_id: player.scene.entry_id, floor_id: player.scene.floor_id,
plane_id: player.scene.plane_id, ..Default::default()
floor_id: player.scene.floor_id, })
..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(|(_, v)| EnteredSceneInfo { .map(|(k, _)| {
floor_id: v.floor_id, let split: Vec<_> = k.split("_").collect();
plane_id: v.plane_id, 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(),
}
})
.collect::<Vec<_>>()
}) })
.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,37 +257,30 @@ 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()
})), })),
entity_id: prop_entity_id, entity_id: prop_entity_id,
@@ -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, scene: Some(scene_info.clone()),
EnterSceneByServerScNotify { lineup: Some(lineup_info),
scene: Some(scene_info.clone()), ..Default::default()
lineup: Some(lineup_info), })
..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;
} }
-117
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
// }
-2
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;
+69 -46
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;
} }
+3 -2
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,
} }
+34 -12
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);
-345
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();
}
+1
View File
@@ -0,0 +1 @@
pub mod resources;
+145
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()
});
+12 -12
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"
} }
+1
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
+37
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})]"))
}
+50967 -11845
View File
File diff suppressed because it is too large Load Diff
+12
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
+27
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
+11 -3
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
}
}
View File
+662361
View File
File diff suppressed because it is too large Load Diff
-1
View File
File diff suppressed because one or more lines are too long
+2 -9
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 {
+11 -11
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": ""
} }
} }
+11 -5
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": ""
} }
} }