mirror of
https://git.neonteam.dev/amizing/robinsr.git
synced 2025-03-12 03:28:30 -04:00
feat!: Refactor, Update to version 2.5.x, Add Battle Scepter
This commit is contained in:
parent
88f3025333
commit
6e97b516f4
@ -1,5 +1,5 @@
|
||||
[workspace]
|
||||
members = [ "gameserver", "proto", "sdkserver"]
|
||||
members = ["gameserver", "proto", "sdkserver"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
@ -54,6 +54,8 @@ tracing-subscriber = { version = "0.3.18", features = [
|
||||
tracing-bunyan-formatter = "0.3.9"
|
||||
|
||||
proto = { path = "proto/" }
|
||||
proto-derive = { path = "proto/proto-derive" }
|
||||
|
||||
|
||||
[profile.release]
|
||||
strip = true # Automatically strip symbols from the binary.
|
||||
|
||||
8089
freesr-data.json
8089
freesr-data.json
File diff suppressed because it is too large
Load Diff
@ -28,5 +28,6 @@ tracing-bunyan-formatter.workspace = true
|
||||
|
||||
prost.workspace = true
|
||||
proto.workspace = true
|
||||
proto-derive.workspace = true
|
||||
|
||||
rand.workspace = true
|
||||
|
||||
@ -2,6 +2,7 @@ use anyhow::Result;
|
||||
|
||||
mod logging;
|
||||
mod net;
|
||||
mod tools;
|
||||
mod util;
|
||||
|
||||
use logging::init_tracing;
|
||||
|
||||
@ -1,45 +1,29 @@
|
||||
use anyhow::Result;
|
||||
use proto::*;
|
||||
|
||||
use crate::{net::PlayerSession, util};
|
||||
|
||||
pub async fn on_player_get_token_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_session: &mut PlayerSession,
|
||||
_body: &PlayerGetTokenCsReq,
|
||||
) -> Result<()> {
|
||||
session
|
||||
.send(
|
||||
CMD_PLAYER_GET_TOKEN_SC_RSP,
|
||||
PlayerGetTokenScRsp {
|
||||
retcode: 0,
|
||||
msg: String::from("OK"),
|
||||
uid: 25,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await
|
||||
res: &mut PlayerGetTokenScRsp,
|
||||
) {
|
||||
res.msg = String::from("OK");
|
||||
res.uid = 25;
|
||||
}
|
||||
|
||||
pub async fn on_player_login_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_session: &mut PlayerSession,
|
||||
body: &PlayerLoginCsReq,
|
||||
) -> Result<()> {
|
||||
session
|
||||
.send(
|
||||
CMD_PLAYER_LOGIN_SC_RSP,
|
||||
PlayerLoginScRsp {
|
||||
login_random: body.login_random,
|
||||
server_timestamp_ms: util::cur_timestamp_ms(),
|
||||
stamina: 240,
|
||||
basic_info: Some(PlayerBasicInfo {
|
||||
nickname: String::from("RobinSR"),
|
||||
level: 70,
|
||||
world_level: 6,
|
||||
stamina: 240,
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await
|
||||
res: &mut PlayerLoginScRsp,
|
||||
) {
|
||||
res.login_random = body.login_random;
|
||||
res.server_timestamp_ms = util::cur_timestamp_ms();
|
||||
res.stamina = 240;
|
||||
res.basic_info = Some(PlayerBasicInfo {
|
||||
nickname: String::from("RobinSR"),
|
||||
level: 70,
|
||||
world_level: 6,
|
||||
stamina: 240,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
@ -2,55 +2,48 @@ use crate::net::tools::FreesrData;
|
||||
|
||||
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,
|
||||
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,
|
||||
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(
|
||||
session: &mut PlayerSession,
|
||||
_session: &mut PlayerSession,
|
||||
body: &GetAvatarDataCsReq,
|
||||
) -> Result<()> {
|
||||
res: &mut GetAvatarDataScRsp,
|
||||
) {
|
||||
let json = FreesrData::load().await;
|
||||
session
|
||||
.send(
|
||||
CMD_GET_AVATAR_DATA_SC_RSP,
|
||||
GetAvatarDataScRsp {
|
||||
retcode: 0,
|
||||
is_get_all: body.is_get_all,
|
||||
avatar_list: UNLOCKED_AVATARS
|
||||
.iter()
|
||||
.map(|id| {
|
||||
json.avatars
|
||||
.get(id)
|
||||
.map(|v| {
|
||||
v.to_avatar_proto(
|
||||
json.lightcones.iter().find(|v| v.equip_avatar == *id),
|
||||
json.relics
|
||||
.iter()
|
||||
.filter(|v| v.equip_avatar == *id)
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
.unwrap_or(Avatar {
|
||||
base_avatar_id: *id,
|
||||
level: 80,
|
||||
promotion: 6,
|
||||
rank: 6,
|
||||
skilltree_list: (1..=4)
|
||||
.map(|m| AvatarSkillTree {
|
||||
point_id: (*id) * 1000 + m,
|
||||
level: 1,
|
||||
})
|
||||
.collect(),
|
||||
..Default::default()
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await
|
||||
res.is_get_all = body.is_get_all;
|
||||
res.avatar_list = UNLOCKED_AVATARS
|
||||
.iter()
|
||||
.map(|id| {
|
||||
json.avatars
|
||||
.get(id)
|
||||
.map(|v| {
|
||||
v.to_avatar_proto(
|
||||
json.lightcones.iter().find(|v| v.equip_avatar == *id),
|
||||
json.relics
|
||||
.iter()
|
||||
.filter(|v| v.equip_avatar == *id)
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
.unwrap_or(Avatar {
|
||||
base_avatar_id: *id,
|
||||
level: 80,
|
||||
promotion: 6,
|
||||
rank: 6,
|
||||
skilltree_list: (1..=4)
|
||||
.map(|m| AvatarSkillTree {
|
||||
point_id: (*id) * 1000 + m,
|
||||
level: 1,
|
||||
})
|
||||
.collect(),
|
||||
first_met_timestamp: 1712924677,
|
||||
..Default::default()
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
|
||||
@ -1,70 +1,53 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use rand::Rng;
|
||||
use rogue_magic_battle_unit_info::Item;
|
||||
|
||||
use crate::net::tools::{self, BattleType, Monster};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub async fn on_start_cocoon_stage_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_session: &mut PlayerSession,
|
||||
body: &StartCocoonStageCsReq,
|
||||
) -> Result<()> {
|
||||
res: &mut StartCocoonStageScRsp,
|
||||
) {
|
||||
let battle_info = create_battle_info().await;
|
||||
|
||||
let rsp = StartCocoonStageScRsp {
|
||||
retcode: 0,
|
||||
prop_entity_id: body.prop_entity_id,
|
||||
cocoon_id: body.cocoon_id,
|
||||
wave: body.wave,
|
||||
battle_info: Some(battle_info),
|
||||
};
|
||||
|
||||
session.send(CMD_START_COCOON_STAGE_SC_RSP, rsp).await
|
||||
res.prop_entity_id = body.prop_entity_id;
|
||||
res.cocoon_id = body.cocoon_id;
|
||||
res.wave = body.wave;
|
||||
res.battle_info = Some(battle_info);
|
||||
}
|
||||
|
||||
pub async fn on_pve_battle_result_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_session: &mut PlayerSession,
|
||||
body: &PveBattleResultCsReq,
|
||||
) -> Result<()> {
|
||||
session
|
||||
.send(
|
||||
CMD_PVE_BATTLE_RESULT_SC_RSP,
|
||||
PveBattleResultScRsp {
|
||||
retcode: 0,
|
||||
end_status: body.end_status,
|
||||
battle_id: body.battle_id,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await
|
||||
res: &mut PveBattleResultScRsp,
|
||||
) {
|
||||
res.end_status = body.end_status;
|
||||
res.battle_id = body.battle_id;
|
||||
}
|
||||
|
||||
pub async fn on_scene_cast_skill_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_session: &mut PlayerSession,
|
||||
request: &SceneCastSkillCsReq,
|
||||
) -> Result<()> {
|
||||
res: &mut SceneCastSkillScRsp,
|
||||
) {
|
||||
res.attacked_group_id = request.attacked_group_id;
|
||||
|
||||
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
|
||||
.assist_monster_entity_id_list
|
||||
.hit_target_entity_id_list
|
||||
.iter()
|
||||
.filter(|id| **id > 30_000 || **id < 1_000)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if targets.is_empty() {
|
||||
return session.send(CMD_SCENE_CAST_SKILL_SC_RSP, resp).await;
|
||||
return;
|
||||
}
|
||||
|
||||
resp.battle_info = Some(battle_info);
|
||||
|
||||
session.send(CMD_SCENE_CAST_SKILL_SC_RSP, resp).await
|
||||
res.battle_info = Some(battle_info);
|
||||
}
|
||||
|
||||
async fn create_battle_info() -> SceneBattleInfo {
|
||||
@ -237,11 +220,62 @@ async fn create_battle_info() -> SceneBattleInfo {
|
||||
max_sp: 10_000,
|
||||
}),
|
||||
}),
|
||||
skill_info: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@ -8,118 +8,91 @@ use crate::{
|
||||
|
||||
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(
|
||||
session: &mut PlayerSession,
|
||||
_: &GetFriendLoginInfoCsReq,
|
||||
) -> Result<()> {
|
||||
session
|
||||
.send(
|
||||
CMD_GET_FRIEND_LOGIN_INFO_SC_RSP,
|
||||
GetFriendLoginInfoScRsp {
|
||||
mnacbpjeche: vec![727],
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await
|
||||
_session: &mut PlayerSession,
|
||||
_req: &GetFriendLoginInfoCsReq,
|
||||
res: &mut GetFriendLoginInfoScRsp,
|
||||
) {
|
||||
res.friend_uid_list = vec![SERVER_UID];
|
||||
}
|
||||
|
||||
pub async fn on_get_friend_list_info_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_: &GetFriendListInfoCsReq,
|
||||
) -> Result<()> {
|
||||
session
|
||||
.send(
|
||||
CMD_GET_FRIEND_LIST_INFO_SC_RSP,
|
||||
GetFriendListInfoScRsp {
|
||||
friend_list: vec![FriendListInfo {
|
||||
friend_name: String::from("RobinSR"),
|
||||
simple_info: Some(SimpleInfo {
|
||||
uid: 727,
|
||||
platform_type: 3,
|
||||
online_status: 1,
|
||||
head_icon: 201008,
|
||||
chat_bubble_id: 220005,
|
||||
level: 70,
|
||||
nickname: String::from("Server"),
|
||||
signature: String::from("omg"),
|
||||
..Default::default()
|
||||
}),
|
||||
is_marked: true,
|
||||
sent_time: 0,
|
||||
..Default::default()
|
||||
}],
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await
|
||||
_session: &mut PlayerSession,
|
||||
_req: &GetFriendListInfoCsReq,
|
||||
res: &mut GetFriendListInfoScRsp,
|
||||
) {
|
||||
res.friend_list = vec![FriendListInfo {
|
||||
friend_name: String::from("RobinSR"),
|
||||
simple_info: Some(SimpleInfo {
|
||||
uid: SERVER_UID,
|
||||
platform_type: PlatformType::Pc.into(),
|
||||
online_status: FriendOnlineStatus::Online.into(),
|
||||
head_icon: SERVER_HEAD_ICON,
|
||||
chat_bubble_id: SERVER_CHAT_BUBBLE_ID,
|
||||
level: 70,
|
||||
nickname: String::from("Server"),
|
||||
signature: String::from("omg"),
|
||||
..Default::default()
|
||||
}),
|
||||
is_marked: true,
|
||||
sent_time: 0,
|
||||
..Default::default()
|
||||
}];
|
||||
}
|
||||
|
||||
pub async fn on_get_private_chat_history_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_session: &mut PlayerSession,
|
||||
req: &GetPrivateChatHistoryCsReq,
|
||||
) -> Result<()> {
|
||||
session
|
||||
.send(
|
||||
CMD_GET_PRIVATE_CHAT_HISTORY_SC_RSP,
|
||||
GetPrivateChatHistoryScRsp {
|
||||
chat_list: vec![
|
||||
Chat {
|
||||
msg_type: MsgType::CustomText.into(),
|
||||
sent_time: cur_timestamp_ms(),
|
||||
text: "'sync'".to_string(),
|
||||
sender_uid: 727,
|
||||
..Default::default()
|
||||
},
|
||||
Chat {
|
||||
msg_type: MsgType::CustomText.into(),
|
||||
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
|
||||
res: &mut GetPrivateChatHistoryScRsp,
|
||||
) {
|
||||
let cur_time = cur_timestamp_ms();
|
||||
res.chat_list = SERVER_CHAT_HISTORY
|
||||
.iter()
|
||||
.map(|text| Chat {
|
||||
msg_type: MsgType::CustomText.into(),
|
||||
sent_time: cur_time,
|
||||
text: String::from(*text),
|
||||
sender_uid: SERVER_UID,
|
||||
..Default::default()
|
||||
})
|
||||
.collect();
|
||||
res.to_uid = req.to_uid;
|
||||
res.from_uid = SERVER_UID;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if let Some((cmd, args)) = parse_command(&body.text) {
|
||||
match cmd {
|
||||
"sync" => {
|
||||
sync_player(session, json).await?;
|
||||
sync_player(session, json).await;
|
||||
session
|
||||
.send(
|
||||
CMD_REVC_MSG_SC_NOTIFY,
|
||||
RevcMsgScNotify {
|
||||
msg_type: body.msg_type,
|
||||
text: String::from("Inventory Synced"),
|
||||
emote: body.emote,
|
||||
from_uid: 727, // from
|
||||
to_uid: 25, // to
|
||||
chat_type: body.chat_type,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
.send(RevcMsgScNotify {
|
||||
msg_type: body.msg_type,
|
||||
text: String::from("Inventory Synced"),
|
||||
emote: body.emote,
|
||||
from_uid: SERVER_UID, // from
|
||||
to_uid: 25, // to
|
||||
chat_type: body.chat_type,
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
"mc" => {
|
||||
let mc = MultiPathAvatar::from(
|
||||
@ -133,28 +106,25 @@ pub async fn on_send_msg_cs_req(session: &mut PlayerSession, body: &SendMsgCsReq
|
||||
json.save().await;
|
||||
|
||||
session
|
||||
.send(
|
||||
CMD_AVATAR_PATH_CHANGED_NOTIFY,
|
||||
AvatarPathChangedNotify {
|
||||
base_avatar_id: 8001,
|
||||
cur_multi_path_avatar_type: mc as i32,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
.send(AvatarPathChangedNotify {
|
||||
base_avatar_id: 8001,
|
||||
cur_multi_path_avatar_type: mc as i32,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
session
|
||||
.send(
|
||||
CMD_REVC_MSG_SC_NOTIFY,
|
||||
RevcMsgScNotify {
|
||||
msg_type: body.msg_type,
|
||||
text: format!("Success change mc to {:#?}", mc),
|
||||
emote: body.emote,
|
||||
from_uid: 727, // from
|
||||
to_uid: 25, // to
|
||||
chat_type: body.chat_type,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
.send(RevcMsgScNotify {
|
||||
msg_type: body.msg_type,
|
||||
text: format!("Success change mc to {:#?}", mc),
|
||||
emote: body.emote,
|
||||
from_uid: SERVER_UID, // from
|
||||
to_uid: 25, // to
|
||||
chat_type: body.chat_type,
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
"march" => {
|
||||
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;
|
||||
|
||||
session
|
||||
.send(
|
||||
CMD_AVATAR_PATH_CHANGED_NOTIFY,
|
||||
AvatarPathChangedNotify {
|
||||
base_avatar_id: 1001,
|
||||
cur_multi_path_avatar_type: march_type as i32,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
.send(AvatarPathChangedNotify {
|
||||
base_avatar_id: 1001,
|
||||
cur_multi_path_avatar_type: march_type as i32,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
session
|
||||
.send(
|
||||
CMD_REVC_MSG_SC_NOTIFY,
|
||||
RevcMsgScNotify {
|
||||
msg_type: body.msg_type,
|
||||
text: format!("Success change march to {:#?}", march_type),
|
||||
emote: body.emote,
|
||||
from_uid: 727, // from
|
||||
to_uid: 25, // to
|
||||
chat_type: body.chat_type,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
.send(RevcMsgScNotify {
|
||||
msg_type: body.msg_type,
|
||||
text: format!("Success change march to {:#?}", march_type),
|
||||
emote: body.emote,
|
||||
from_uid: SERVER_UID, // from
|
||||
to_uid: 25, // to
|
||||
chat_type: body.chat_type,
|
||||
..Default::default()
|
||||
})
|
||||
.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>)> {
|
||||
@ -216,72 +173,68 @@ fn parse_command(command: &str) -> Option<(&str, Vec<&str>)> {
|
||||
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
|
||||
.send(
|
||||
CMD_PLAYER_SYNC_SC_NOTIFY,
|
||||
PlayerSyncScNotify {
|
||||
del_equipment_list: (2000..3500).collect(),
|
||||
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()
|
||||
},
|
||||
)
|
||||
.send(PlayerSyncScNotify {
|
||||
del_equipment_list: (2000..3500).collect(),
|
||||
del_relic_list: (1..2000).collect(),
|
||||
..Default::default()
|
||||
})
|
||||
.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()
|
||||
}
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
pub use super::*;
|
||||
|
||||
pub async fn on_get_gacha_info_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_: &GetGachaInfoCsReq,
|
||||
) -> anyhow::Result<()> {
|
||||
let gacha = GachaInfo {
|
||||
_session: &mut PlayerSession,
|
||||
_req: &GetGachaInfoCsReq,
|
||||
res: &mut GetGachaInfoScRsp,
|
||||
) {
|
||||
res.gacha_info_list = vec![GachaInfo {
|
||||
end_time: 1924992000,
|
||||
begin_time: 0,
|
||||
gacha_ceiling: Some(GachaCeiling::default()),
|
||||
@ -17,47 +18,31 @@ pub async fn on_get_gacha_info_cs_req(
|
||||
],
|
||||
gacha_id: 1001,
|
||||
..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(
|
||||
session: &mut PlayerSession,
|
||||
_session: &mut PlayerSession,
|
||||
req: &DoGachaCsReq,
|
||||
) -> anyhow::Result<()> {
|
||||
session
|
||||
.send(
|
||||
CMD_DO_GACHA_SC_RSP,
|
||||
DoGachaScRsp {
|
||||
gacha_id: req.gacha_id,
|
||||
gacha_num: req.gacha_num,
|
||||
gacha_item_list: (0..req.gacha_num)
|
||||
.map(|v| GachaItem {
|
||||
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(),
|
||||
res: &mut DoGachaScRsp,
|
||||
) {
|
||||
res.gacha_id = req.gacha_id;
|
||||
res.gacha_num = req.gacha_num;
|
||||
res.gacha_item_list = (0..req.gacha_num)
|
||||
.map(|v| GachaItem {
|
||||
is_new: false,
|
||||
gacha_item: Some(Item {
|
||||
item_id: if v % 2 == 0 { 1310 } else { 1314 },
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
}),
|
||||
token_item: Some(ItemList {
|
||||
item_list: vec![Item {
|
||||
item_id: 251,
|
||||
num: 100,
|
||||
..Default::default()
|
||||
}],
|
||||
}),
|
||||
transfer_item_list: Some(ItemList { item_list: vec![] }),
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
|
||||
@ -1,96 +1,66 @@
|
||||
use anyhow::Result;
|
||||
use proto::*;
|
||||
|
||||
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;
|
||||
|
||||
session
|
||||
.send(
|
||||
CMD_GET_BAG_SC_RSP,
|
||||
GetBagScRsp {
|
||||
equipment_list: player
|
||||
.lightcones
|
||||
.iter()
|
||||
.map(|v| v.to_equipment_proto())
|
||||
.collect(),
|
||||
relic_list: player.relics.iter().map(|v| v.to_relic_proto()).collect(),
|
||||
material_list: vec![
|
||||
Material {
|
||||
tid: 101, // Normal Pass
|
||||
num: 999999,
|
||||
..Default::default()
|
||||
},
|
||||
Material {
|
||||
tid: 102, // Special Pass
|
||||
num: 999999,
|
||||
..Default::default()
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await
|
||||
res.equipment_list = player
|
||||
.lightcones
|
||||
.iter()
|
||||
.map(|v| v.to_equipment_proto())
|
||||
.collect();
|
||||
res.relic_list = player.relics.iter().map(|v| v.to_relic_proto()).collect();
|
||||
res.material_list = vec![
|
||||
Material {
|
||||
tid: 101, // Normal Pass
|
||||
num: 999999,
|
||||
..Default::default()
|
||||
},
|
||||
Material {
|
||||
tid: 102, // Special Pass
|
||||
num: 999999,
|
||||
..Default::default()
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
pub async fn on_get_archive_data_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_session: &mut PlayerSession,
|
||||
_: &GetArchiveDataCsReq,
|
||||
) -> Result<()> {
|
||||
session
|
||||
.send(
|
||||
CMD_GET_ARCHIVE_DATA_SC_RSP,
|
||||
GetArchiveDataScRsp {
|
||||
archive_data: Some(ArchiveData::default()),
|
||||
retcode: 0,
|
||||
},
|
||||
)
|
||||
.await
|
||||
res: &mut GetArchiveDataScRsp,
|
||||
) {
|
||||
res.archive_data = Some(ArchiveData::default());
|
||||
}
|
||||
|
||||
pub async fn on_dress_relic_avatar_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_: &DressRelicAvatarCsReq,
|
||||
) -> Result<()> {
|
||||
// ?
|
||||
session
|
||||
.send(
|
||||
CMD_DRESS_RELIC_AVATAR_SC_RSP,
|
||||
DressRelicAvatarScRsp::default(),
|
||||
)
|
||||
.await
|
||||
_session: &mut PlayerSession,
|
||||
_req: &DressRelicAvatarCsReq,
|
||||
_res: &mut DressRelicAvatarScRsp,
|
||||
) {
|
||||
}
|
||||
|
||||
pub async fn on_take_off_relic_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_: &TakeOffRelicCsReq,
|
||||
) -> Result<()> {
|
||||
// ?
|
||||
session
|
||||
.send(CMD_TAKE_OFF_RELIC_SC_RSP, TakeOffRelicScRsp::default())
|
||||
.await
|
||||
_session: &mut PlayerSession,
|
||||
_req: &TakeOffRelicCsReq,
|
||||
_res: &mut TakeOffRelicScRsp,
|
||||
) {
|
||||
}
|
||||
|
||||
pub async fn on_dress_avatar_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_: &DressAvatarCsReq,
|
||||
) -> Result<()> {
|
||||
// ?
|
||||
session
|
||||
.send(CMD_DRESS_AVATAR_SC_RSP, DressAvatarScRsp::default())
|
||||
.await
|
||||
_session: &mut PlayerSession,
|
||||
_req: &DressAvatarCsReq,
|
||||
_res: &mut DressAvatarScRsp,
|
||||
) {
|
||||
}
|
||||
|
||||
pub async fn on_take_off_equipment_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_: &TakeOffEquipmentCsReq,
|
||||
) -> Result<()> {
|
||||
// ?
|
||||
session
|
||||
.send(
|
||||
CMD_TAKE_OFF_EQUIPMENT_SC_RSP,
|
||||
TakeOffEquipmentScRsp::default(),
|
||||
)
|
||||
.await
|
||||
_session: &mut PlayerSession,
|
||||
_req: &TakeOffEquipmentCsReq,
|
||||
_res: &mut TakeOffEquipmentScRsp,
|
||||
) {
|
||||
}
|
||||
|
||||
@ -6,34 +6,26 @@ use crate::net::tools::{self, AvatarJson, FreesrData};
|
||||
use super::*;
|
||||
|
||||
pub async fn on_get_all_lineup_data_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_session: &mut PlayerSession,
|
||||
_body: &GetAllLineupDataCsReq,
|
||||
) -> Result<()> {
|
||||
res: &mut GetAllLineupDataScRsp,
|
||||
) {
|
||||
let player = tools::FreesrData::load().await;
|
||||
let lineup = LineupInfo {
|
||||
res.lineup_list = vec![LineupInfo {
|
||||
extra_lineup_type: ExtraLineupType::LineupNone.into(),
|
||||
name: "Squad 1".to_string(),
|
||||
mp: 5,
|
||||
max_mp: 5,
|
||||
avatar_list: AvatarJson::to_lineup_avatars(&player),
|
||||
..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(
|
||||
session: &mut PlayerSession,
|
||||
_session: &mut PlayerSession,
|
||||
_body: &GetCurLineupDataCsReq,
|
||||
) -> Result<()> {
|
||||
res: &mut GetCurLineupDataScRsp,
|
||||
) {
|
||||
let player = tools::FreesrData::load().await;
|
||||
let lineup = LineupInfo {
|
||||
extra_lineup_type: ExtraLineupType::LineupNone.into(),
|
||||
@ -46,95 +38,63 @@ pub async fn on_get_cur_lineup_data_cs_req(
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
session
|
||||
.send(
|
||||
CMD_GET_CUR_LINEUP_DATA_SC_RSP,
|
||||
GetCurLineupDataScRsp {
|
||||
lineup: Some(lineup),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await
|
||||
res.lineup = Some(lineup)
|
||||
}
|
||||
|
||||
pub async fn on_join_lineup_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
body: &JoinLineupCsReq,
|
||||
) -> Result<()> {
|
||||
// update lineups
|
||||
// TODO: FIX THESE SHIT
|
||||
{
|
||||
let mut player = tools::FreesrData::load().await;
|
||||
let lineups = &mut player.lineups;
|
||||
lineups.insert(
|
||||
body.slot,
|
||||
if body.base_avatar_id == 8001 {
|
||||
player.main_character as u32
|
||||
} else if body.base_avatar_id == 1001 {
|
||||
player.march_type as u32
|
||||
} else {
|
||||
body.base_avatar_id
|
||||
},
|
||||
);
|
||||
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
|
||||
_res: &mut JoinLineupScRsp,
|
||||
) {
|
||||
let mut player = tools::FreesrData::load().await;
|
||||
let lineups = &mut player.lineups;
|
||||
lineups.insert(
|
||||
body.slot,
|
||||
if body.base_avatar_id == 8001 {
|
||||
player.main_character as u32
|
||||
} else if body.base_avatar_id == 1001 {
|
||||
player.march_type as u32
|
||||
} else {
|
||||
body.base_avatar_id
|
||||
},
|
||||
);
|
||||
player.save_lineup().await;
|
||||
refresh_lineup(session, &player).await;
|
||||
}
|
||||
|
||||
pub async fn on_replace_lineup_cs_req(
|
||||
_session: &mut PlayerSession,
|
||||
req: &ReplaceLineupCsReq,
|
||||
) -> Result<()> {
|
||||
{
|
||||
let mut player = tools::FreesrData::load().await;
|
||||
_res: &mut ReplaceLineupScRsp,
|
||||
) {
|
||||
let mut player = tools::FreesrData::load().await;
|
||||
|
||||
let lineups = &mut player.lineups;
|
||||
for (slot, avatar_id) in &mut *lineups {
|
||||
if let Some(lineup) = req.slots.get(*slot as usize) {
|
||||
*avatar_id = if lineup.id == 8001 {
|
||||
player.main_character as u32
|
||||
} else if lineup.id == 1001 {
|
||||
player.march_type as u32
|
||||
} else {
|
||||
lineup.id
|
||||
};
|
||||
let lineups = &mut player.lineups;
|
||||
for (slot, avatar_id) in &mut *lineups {
|
||||
if let Some(lineup) = req.slots.get(*slot as usize) {
|
||||
*avatar_id = if lineup.id == 8001 {
|
||||
player.main_character as u32
|
||||
} else if lineup.id == 1001 {
|
||||
player.march_type as u32
|
||||
} else {
|
||||
*avatar_id = 0;
|
||||
}
|
||||
lineup.id
|
||||
};
|
||||
} else {
|
||||
*avatar_id = 0;
|
||||
}
|
||||
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
|
||||
player.save_lineup().await;
|
||||
refresh_lineup(_session, &player).await;
|
||||
}
|
||||
|
||||
pub async fn on_quit_lineup_cs_req(
|
||||
_session: &mut PlayerSession,
|
||||
_: &QuitLineupCsReq,
|
||||
) -> Result<()> {
|
||||
_session
|
||||
.send(CMD_JOIN_LINEUP_SC_RSP, JoinLineupScRsp::default())
|
||||
.await
|
||||
_res: &mut QuitLineupScRsp,
|
||||
) {
|
||||
}
|
||||
|
||||
async fn refresh_lineup(sess: &mut PlayerSession, player: &FreesrData) -> Result<()> {
|
||||
async fn refresh_lineup(session: &mut PlayerSession, player: &FreesrData) {
|
||||
let lineup = LineupInfo {
|
||||
extra_lineup_type: ExtraLineupType::LineupNone.into(),
|
||||
name: "Squad 1".to_string(),
|
||||
@ -144,9 +104,8 @@ async fn refresh_lineup(sess: &mut PlayerSession, player: &FreesrData) -> Result
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
sess.send(
|
||||
CMD_SCENE_GROUP_REFRESH_SC_NOTIFY,
|
||||
SceneGroupRefreshScNotify {
|
||||
session
|
||||
.send(SceneGroupRefreshScNotify {
|
||||
group_refresh_info: vec![SceneGroupRefreshInfo {
|
||||
group_id: 0,
|
||||
state: 0,
|
||||
@ -170,31 +129,23 @@ async fn refresh_lineup(sess: &mut PlayerSession, player: &FreesrData) -> Result
|
||||
})
|
||||
.collect(),
|
||||
}],
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
sess.send(
|
||||
CMD_SYNC_LINEUP_NOTIFY,
|
||||
SyncLineupNotify {
|
||||
session
|
||||
.send(SyncLineupNotify {
|
||||
lineup: Some(lineup),
|
||||
reason_list: vec![],
|
||||
},
|
||||
)
|
||||
.await
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub async fn on_change_lineup_leader_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_session: &mut PlayerSession,
|
||||
body: &ChangeLineupLeaderCsReq,
|
||||
) -> Result<()> {
|
||||
session
|
||||
.send(
|
||||
CMD_CHANGE_LINEUP_LEADER_SC_RSP,
|
||||
ChangeLineupLeaderScRsp {
|
||||
slot: body.slot,
|
||||
retcode: 0,
|
||||
},
|
||||
)
|
||||
.await
|
||||
res: &mut ChangeLineupLeaderScRsp,
|
||||
) {
|
||||
res.slot = body.slot;
|
||||
}
|
||||
|
||||
@ -1,37 +1,29 @@
|
||||
use super::*;
|
||||
use anyhow::Result;
|
||||
|
||||
pub async fn on_get_mail_cs_req(session: &mut PlayerSession, _: &GetMailCsReq) -> Result<()> {
|
||||
session
|
||||
.send(
|
||||
CMD_GET_MAIL_SC_RSP,
|
||||
GetMailScRsp {
|
||||
is_end: true,
|
||||
mail_list: vec![ClientMail {
|
||||
title: String::from("Welcome!"),
|
||||
sender: String::from("Server"),
|
||||
content: String::from("Welcome!"),
|
||||
id: 1,
|
||||
is_read: false,
|
||||
time: 1716041089,
|
||||
expire_time: 1718633089,
|
||||
para_list: vec![],
|
||||
attachment: Some(ItemList {
|
||||
item_list: vec![Item {
|
||||
item_id: 1310,
|
||||
level: 80,
|
||||
num: 1,
|
||||
..Default::default()
|
||||
}],
|
||||
}),
|
||||
mail_type: MailType::Normal.into(),
|
||||
template_id: 0,
|
||||
}],
|
||||
notice_mail_list: vec![],
|
||||
start: 0,
|
||||
retcode: 0,
|
||||
total_num: 1,
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
pub async fn on_get_mail_cs_req(
|
||||
_session: &mut PlayerSession,
|
||||
_req: &GetMailCsReq,
|
||||
res: &mut GetMailScRsp,
|
||||
) {
|
||||
res.is_end = true;
|
||||
res.mail_list = vec![ClientMail {
|
||||
title: String::from("Welcome!"),
|
||||
sender: String::from("Server"),
|
||||
content: String::from("Welcome!"),
|
||||
id: 1,
|
||||
is_read: false,
|
||||
time: 1716041089,
|
||||
expire_time: 1718633089,
|
||||
para_list: vec![],
|
||||
attachment: Some(ItemList {
|
||||
item_list: vec![Item {
|
||||
item_id: 1310,
|
||||
level: 80,
|
||||
num: 1,
|
||||
..Default::default()
|
||||
}],
|
||||
}),
|
||||
mail_type: MailType::Normal.into(),
|
||||
template_id: 0,
|
||||
}];
|
||||
}
|
||||
|
||||
@ -1,23 +1,18 @@
|
||||
use super::*;
|
||||
|
||||
pub async fn on_get_mission_status_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_session: &mut PlayerSession,
|
||||
body: &GetMissionStatusCsReq,
|
||||
) -> Result<()> {
|
||||
let rsp = GetMissionStatusScRsp {
|
||||
retcode: 0,
|
||||
finished_main_mission_id_list: body.main_mission_id_list.clone(),
|
||||
sub_mission_status_list: body
|
||||
.sub_mission_id_list
|
||||
.iter()
|
||||
.map(|id| Mission {
|
||||
id: *id,
|
||||
progress: 1,
|
||||
status: MissionStatus::MissionFinish.into(),
|
||||
})
|
||||
.collect(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
session.send(CMD_GET_MISSION_STATUS_SC_RSP, rsp).await
|
||||
}
|
||||
res: &mut GetMissionStatusScRsp,
|
||||
) {
|
||||
res.finished_main_mission_id_list = body.main_mission_id_list.clone();
|
||||
res.sub_mission_status_list = body
|
||||
.sub_mission_id_list
|
||||
.iter()
|
||||
.map(|id| Mission {
|
||||
id: *id,
|
||||
progress: 1,
|
||||
status: MissionStatus::MissionFinish.into(),
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
|
||||
@ -9,7 +9,6 @@ mod mail;
|
||||
mod mission;
|
||||
mod player;
|
||||
mod scene;
|
||||
mod tutorial;
|
||||
|
||||
use anyhow::Result;
|
||||
use paste::paste;
|
||||
@ -30,7 +29,6 @@ pub use mail::*;
|
||||
pub use mission::*;
|
||||
pub use player::*;
|
||||
pub use scene::*;
|
||||
// pub use tutorial::*;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use proto::{
|
||||
|
||||
@ -1,157 +1,113 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{net::tools::FreesrData, util};
|
||||
use crate::{net::tools::FreesrData, util::cur_timestamp_ms};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub async fn on_get_basic_info_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_session: &mut PlayerSession,
|
||||
_body: &GetBasicInfoCsReq,
|
||||
) -> Result<()> {
|
||||
session
|
||||
.send(
|
||||
CMD_GET_BASIC_INFO_SC_RSP,
|
||||
GetBasicInfoScRsp {
|
||||
retcode: 0,
|
||||
player_setting_info: Some(PlayerSettingInfo::default()),
|
||||
gender: Gender::Woman as u32,
|
||||
is_gender_set: true,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await
|
||||
res: &mut GetBasicInfoScRsp,
|
||||
) {
|
||||
res.player_setting_info = Some(PlayerSettingInfo::default());
|
||||
res.gender = Gender::Woman as u32;
|
||||
res.is_gender_set = true;
|
||||
}
|
||||
|
||||
pub async fn on_player_heart_beat_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_session: &mut PlayerSession,
|
||||
body: &PlayerHeartBeatCsReq,
|
||||
) -> Result<()> {
|
||||
session
|
||||
.send(
|
||||
CMD_PLAYER_HEART_BEAT_SC_RSP,
|
||||
PlayerHeartBeatScRsp {
|
||||
retcode: 0,
|
||||
client_time_ms: body.client_time_ms,
|
||||
server_time_ms: util::cur_timestamp_ms(),
|
||||
download_data: Some(ClientDownloadData {
|
||||
version: 51,
|
||||
time: util::cur_timestamp_ms() as i64,
|
||||
data: rbase64::decode("bG9jYWwgZnVuY3Rpb24gYmV0YV90ZXh0KG9iaikKICAgIGxvY2FsIGdhbWVPYmplY3QgPSBDUy5Vbml0eUVuZ2luZS5HYW1lT2JqZWN0LkZpbmQoIlVJUm9vdC9BYm92ZURpYWxvZy9CZXRhSGludERpYWxvZyhDbG9uZSkiKQoKICAgIGlmIGdhbWVPYmplY3QgdGhlbgogICAgICAgIGxvY2FsIHRleHRDb21wb25lbnQgPSBnYW1lT2JqZWN0OkdldENvbXBvbmVudEluQ2hpbGRyZW4odHlwZW9mKENTLlJQRy5DbGllbnQuTG9jYWxpemVkVGV4dCkpCgogICAgICAgIGlmIHRleHRDb21wb25lbnQgdGhlbgogICAgICAgICAgICB0ZXh0Q29tcG9uZW50LnRleHQgPSAiUm9iaW5TUiBpcyBhIGZyZWUgYW5kIG9wZW4gc291cmNlIHNvZnR3YXJlLiBkaXNjb3JkLmdnL3JldmVyc2Vkcm9vbXMiCiAgICAgICAgZW5kCiAgICBlbHNlCiAgICBlbmQKZW5kCgpiZXRhX3RleHQoKQ==").unwrap()
|
||||
}),
|
||||
},
|
||||
)
|
||||
.await
|
||||
res: &mut PlayerHeartBeatScRsp,
|
||||
) {
|
||||
res.client_time_ms = body.client_time_ms;
|
||||
res.server_time_ms = cur_timestamp_ms();
|
||||
res.download_data = Some(ClientDownloadData {
|
||||
version: 51,
|
||||
time: res.server_time_ms as i64,
|
||||
data: rbase64::decode("bG9jYWwgZnVuY3Rpb24gYmV0YV90ZXh0KG9iaikKICAgIGxvY2FsIGdhbWVPYmplY3QgPSBDUy5Vbml0eUVuZ2luZS5HYW1lT2JqZWN0LkZpbmQoIlVJUm9vdC9BYm92ZURpYWxvZy9CZXRhSGludERpYWxvZyhDbG9uZSkiKQoKICAgIGlmIGdhbWVPYmplY3QgdGhlbgogICAgICAgIGxvY2FsIHRleHRDb21wb25lbnQgPSBnYW1lT2JqZWN0OkdldENvbXBvbmVudEluQ2hpbGRyZW4odHlwZW9mKENTLlJQRy5DbGllbnQuTG9jYWxpemVkVGV4dCkpCgogICAgICAgIGlmIHRleHRDb21wb25lbnQgdGhlbgogICAgICAgICAgICB0ZXh0Q29tcG9uZW50LnRleHQgPSAiUm9iaW5TUiBpcyBhIGZyZWUgYW5kIG9wZW4gc291cmNlIHNvZnR3YXJlLiBkaXNjb3JkLmdnL3JldmVyc2Vkcm9vbXMiCiAgICAgICAgZW5kCiAgICBlbHNlCiAgICBlbmQKZW5kCgpiZXRhX3RleHQoKQ==").unwrap()
|
||||
});
|
||||
}
|
||||
|
||||
pub type PlayerLoginFinishCsReq = Dummy;
|
||||
|
||||
pub async fn on_player_login_finish_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_: &PlayerLoginFinishCsReq,
|
||||
_req: &PlayerLoginFinishCsReq,
|
||||
_res: &mut PlayerLoginFinishScRsp,
|
||||
) -> Result<()> {
|
||||
session
|
||||
.send(CMD_PLAYER_LOGIN_FINISH_SC_RSP, Dummy::default())
|
||||
.await?;
|
||||
|
||||
session
|
||||
.send(
|
||||
CMD_CONTENT_PACKAGE_SYNC_DATA_SC_NOTIFY,
|
||||
ContentPackageSyncDataScNotify {
|
||||
data: Some(PackageData {
|
||||
info_list: vec![
|
||||
ContentInfo {
|
||||
status: ContentPackageStatus::Finished.into(),
|
||||
content_id: 200001,
|
||||
},
|
||||
ContentInfo {
|
||||
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()
|
||||
}),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
.send(ContentPackageSyncDataScNotify {
|
||||
data: Some(PackageData {
|
||||
info_list: vec![
|
||||
200001, 200002, 200003, 200004, 150017, 150015, 150021, 150018, 130011, 130012,
|
||||
130013,
|
||||
]
|
||||
.iter()
|
||||
.map(|v| ContentInfo {
|
||||
status: ContentPackageStatus::Finished.into(),
|
||||
content_id: *v,
|
||||
})
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn on_get_multi_path_avatar_info_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_: &GetMultiPathAvatarInfoCsReq,
|
||||
) -> Result<()> {
|
||||
_session: &mut PlayerSession,
|
||||
_req: &GetMultiPathAvatarInfoCsReq,
|
||||
res: &mut GetMultiPathAvatarInfoScRsp,
|
||||
) {
|
||||
let json = FreesrData::load().await;
|
||||
|
||||
session
|
||||
.send(
|
||||
CMD_GET_MULTI_PATH_AVATAR_INFO_SC_RSP,
|
||||
GetMultiPathAvatarInfoScRsp {
|
||||
retcode: 0,
|
||||
multi_path_avatar_type_info_list: vec![
|
||||
MultiPathAvatarTypeInfo {
|
||||
avatar_id: json.main_character as i32,
|
||||
rank: 6,
|
||||
equip_relic_list: json
|
||||
.relics
|
||||
.iter()
|
||||
.filter(|v| v.equip_avatar == json.main_character as u32)
|
||||
.map(|v| v.to_equipment_relic_proto())
|
||||
.collect(),
|
||||
skilltree_list: (1..=4)
|
||||
.map(|v| AvatarSkillTree {
|
||||
level: 1,
|
||||
point_id: (json.main_character as u32) * 1000 + v,
|
||||
})
|
||||
.collect(),
|
||||
path_equipment_id: json
|
||||
.lightcones
|
||||
.iter()
|
||||
.find(|v| v.equip_avatar == json.main_character as u32)
|
||||
.map(|v| v.internal_uid)
|
||||
.unwrap_or_default(),
|
||||
},
|
||||
MultiPathAvatarTypeInfo {
|
||||
avatar_id: json.march_type as i32,
|
||||
rank: 6,
|
||||
equip_relic_list: json
|
||||
.relics
|
||||
.iter()
|
||||
.filter(|v| v.equip_avatar == json.march_type as u32)
|
||||
.map(|v| v.to_equipment_relic_proto())
|
||||
.collect(),
|
||||
skilltree_list: (1..=4)
|
||||
.map(|v| AvatarSkillTree {
|
||||
level: 1,
|
||||
point_id: (json.march_type as u32) * 1000 + v,
|
||||
})
|
||||
.collect(),
|
||||
path_equipment_id: json
|
||||
.lightcones
|
||||
.iter()
|
||||
.find(|v| v.equip_avatar == json.march_type as u32)
|
||||
.map(|v| v.internal_uid)
|
||||
.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
|
||||
res.current_multi_path_avatar_id = HashMap::from([
|
||||
(8001, json.main_character.get_type().into()),
|
||||
(1001, json.march_type.get_type().into()),
|
||||
]);
|
||||
|
||||
res.multi_path_avatar_type_info_list = vec![
|
||||
MultiPathAvatarTypeInfo {
|
||||
avatar_id: json.main_character as i32,
|
||||
rank: 6,
|
||||
equip_relic_list: json
|
||||
.relics
|
||||
.iter()
|
||||
.filter(|v| v.equip_avatar == json.main_character as u32)
|
||||
.map(|v| v.to_equipment_relic_proto())
|
||||
.collect(),
|
||||
skilltree_list: (1..=4)
|
||||
.map(|v| AvatarSkillTree {
|
||||
level: 1,
|
||||
point_id: (json.main_character as u32) * 1000 + v,
|
||||
})
|
||||
.collect(),
|
||||
path_equipment_id: json
|
||||
.lightcones
|
||||
.iter()
|
||||
.find(|v| v.equip_avatar == json.main_character as u32)
|
||||
.map(|v| v.internal_uid)
|
||||
.unwrap_or_default(),
|
||||
},
|
||||
MultiPathAvatarTypeInfo {
|
||||
avatar_id: json.march_type as i32,
|
||||
rank: 6,
|
||||
equip_relic_list: json
|
||||
.relics
|
||||
.iter()
|
||||
.filter(|v| v.equip_avatar == json.march_type as u32)
|
||||
.map(|v| v.to_equipment_relic_proto())
|
||||
.collect(),
|
||||
skilltree_list: (1..=4)
|
||||
.map(|v| AvatarSkillTree {
|
||||
level: 1,
|
||||
point_id: (json.march_type as u32) * 1000 + v,
|
||||
})
|
||||
.collect(),
|
||||
path_equipment_id: json
|
||||
.lightcones
|
||||
.iter()
|
||||
.find(|v| v.equip_avatar == json.march_type as u32)
|
||||
.map(|v| v.internal_uid)
|
||||
.unwrap_or_default(),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@ -1,95 +1,65 @@
|
||||
use lazy_static::lazy_static;
|
||||
use prost::Message;
|
||||
use scene_entity_info::Entity;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::{
|
||||
net::{
|
||||
tools::{AvatarJson, FreesrData, Position},
|
||||
tools_res::{PropState, GAME_RESOURCES},
|
||||
},
|
||||
net::tools::{AvatarJson, FreesrData, Position},
|
||||
tools::resources::GAME_RES,
|
||||
util::{self},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Message)]
|
||||
pub struct Dummy {}
|
||||
|
||||
pub async fn on_get_cur_scene_info_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_body: &GetCurSceneInfoCsReq,
|
||||
) -> Result<()> {
|
||||
res: &mut GetCurSceneInfoScRsp,
|
||||
) {
|
||||
let mut player = FreesrData::load().await;
|
||||
let entry = player.scene.entry_id;
|
||||
|
||||
let scene = load_scene(session, &mut player, entry, false, Option::<u32>::None).await;
|
||||
|
||||
let resp = GetCurSceneInfoScRsp {
|
||||
retcode: 0,
|
||||
scene: if let Ok(scene) = scene {
|
||||
Some(scene)
|
||||
} else {
|
||||
Some(SceneInfo {
|
||||
game_mode_type: 1,
|
||||
entry_id: player.scene.entry_id,
|
||||
plane_id: player.scene.plane_id,
|
||||
floor_id: player.scene.floor_id,
|
||||
..Default::default()
|
||||
})
|
||||
},
|
||||
res.scene = if let Ok(scene) = scene {
|
||||
Some(scene)
|
||||
} else {
|
||||
Some(SceneInfo {
|
||||
game_mode_type: 3,
|
||||
entry_id: player.scene.entry_id,
|
||||
plane_id: player.scene.plane_id,
|
||||
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(
|
||||
session: &mut PlayerSession,
|
||||
request: &EnterSceneCsReq,
|
||||
) -> Result<()> {
|
||||
req: &EnterSceneCsReq,
|
||||
res: &mut EnterSceneScRsp,
|
||||
) {
|
||||
let mut player = FreesrData::load().await;
|
||||
|
||||
// send packet first
|
||||
session
|
||||
.send(CMD_ENTER_SCENE_SC_RSP, Dummy::default())
|
||||
.await?;
|
||||
|
||||
load_scene(
|
||||
if load_scene(
|
||||
session,
|
||||
&mut player,
|
||||
request.entry_id,
|
||||
req.entry_id,
|
||||
true,
|
||||
Some(request.teleport_id),
|
||||
Some(req.teleport_id),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
res.retcode = Nbbhhpnhond::RetSceneEntryIdNotMatch as u32;
|
||||
};
|
||||
}
|
||||
|
||||
// getscenemapinfocsreq
|
||||
pub async fn on_get_scene_map_info_cs_req(
|
||||
sesison: &mut PlayerSession,
|
||||
request: &GetSceneMapInfoCsReq,
|
||||
) -> Result<()> {
|
||||
let mut map_infos = Vec::<MazeMapData>::new();
|
||||
|
||||
for entry_id in &request.entry_id_list {
|
||||
_sesison: &mut PlayerSession,
|
||||
req: &GetSceneMapInfoCsReq,
|
||||
res: &mut GetSceneMapInfoScRsp,
|
||||
) {
|
||||
for entry_id in &req.entry_id_list {
|
||||
let mut map_info = MazeMapData {
|
||||
retcode: 0,
|
||||
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)
|
||||
}
|
||||
|
||||
let group_config = GAME_RESOURCES.map_entrance.get(entry_id).and_then(|v| {
|
||||
GAME_RESOURCES
|
||||
.level_group
|
||||
.get(&format!("P{}_F{}", v.plane_id, v.floor_id))
|
||||
});
|
||||
if let Some(level) = group_config {
|
||||
// add teleports
|
||||
for teleport in &level.teleports {
|
||||
map_info.unlocked_teleport_list.push(*teleport.0)
|
||||
}
|
||||
let group_config = GAME_RES
|
||||
.level_output_configs
|
||||
.get(&entry_id)
|
||||
.and_then(|v| v.iter().next());
|
||||
|
||||
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 {
|
||||
group_id: *group_id,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
// prop
|
||||
for (teleport, _) in &group.teleports {
|
||||
map_info.unlocked_teleport_list.push(*teleport)
|
||||
}
|
||||
|
||||
for prop in &group.props {
|
||||
if prop.prop_state != 8 {
|
||||
continue;
|
||||
}
|
||||
map_info.maze_prop_list.push(MazeProp {
|
||||
group_id: prop.group_id,
|
||||
state: if prop.prop_state_list.contains(&PropState::CheckPointEnable) {
|
||||
PropState::CheckPointEnable as u32
|
||||
} else {
|
||||
prop.state.clone() as u32
|
||||
},
|
||||
config_id: prop.id,
|
||||
state: prop.prop_state,
|
||||
config_id: prop.inst_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! {
|
||||
@ -166,24 +122,21 @@ lazy_static! {
|
||||
}
|
||||
|
||||
pub async fn on_scene_entity_move_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
request: &SceneEntityMoveCsReq,
|
||||
) -> Result<()> {
|
||||
_session: &mut PlayerSession,
|
||||
req: &SceneEntityMoveCsReq,
|
||||
_res: &mut SceneEntityMoveScRsp,
|
||||
) {
|
||||
let mut player = FreesrData::load().await;
|
||||
let mut timestamp = NEXT_SCENE_SAVE.lock().await;
|
||||
|
||||
if util::cur_timestamp_ms() <= *timestamp {
|
||||
session
|
||||
.send(CMD_SCENE_ENTITY_MOVE_SC_RSP, Dummy::default())
|
||||
.await?;
|
||||
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
|
||||
// save every 5 sec
|
||||
*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 {
|
||||
continue;
|
||||
}
|
||||
@ -201,99 +154,101 @@ pub async fn on_scene_entity_move_cs_req(
|
||||
}
|
||||
|
||||
player.save().await;
|
||||
session
|
||||
.send(CMD_SCENE_ENTITY_MOVE_SC_RSP, Dummy::default())
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn on_get_entered_scene_cs_req(
|
||||
session: &mut PlayerSession,
|
||||
_: &GetEnteredSceneCsReq,
|
||||
) -> Result<()> {
|
||||
let scenes = GAME_RESOURCES
|
||||
.map_entrance
|
||||
_session: &mut PlayerSession,
|
||||
_req: &GetEnteredSceneCsReq,
|
||||
res: &mut GetEnteredSceneScRsp,
|
||||
) {
|
||||
res.entered_scene_info = GAME_RES
|
||||
.level_output_configs
|
||||
.iter()
|
||||
.filter(|(_, v)| {
|
||||
!v.finish_main_mission_list.is_empty() || !v.finish_sub_mission_list.is_empty()
|
||||
})
|
||||
.map(|(_, v)| EnteredSceneInfo {
|
||||
floor_id: v.floor_id,
|
||||
plane_id: v.plane_id,
|
||||
.map(|(_, v)| {
|
||||
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(),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
session
|
||||
.send(
|
||||
CMD_GET_ENTERED_SCENE_SC_RSP,
|
||||
GetEnteredSceneScRsp {
|
||||
entered_scene_info: scenes,
|
||||
retcode: 0,
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn load_scene(
|
||||
session: &mut PlayerSession,
|
||||
json: &mut FreesrData,
|
||||
entry_id: u32,
|
||||
_save: bool,
|
||||
save_scene: bool,
|
||||
teleport_id: Option<u32>,
|
||||
) -> Result<SceneInfo> {
|
||||
let enterance = GAME_RESOURCES
|
||||
.map_entrance
|
||||
let (name, scene) = GAME_RES
|
||||
.level_output_configs
|
||||
.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
|
||||
.maze_plane
|
||||
.get(&enterance.plane_id)
|
||||
.ok_or_else(|| anyhow::format_err!("Map Plane Not Found"))?;
|
||||
let split: Vec<_> = name.split("_").collect();
|
||||
let plane_id = *&split[0][1..].parse::<u32>()?;
|
||||
let floor_id = *&split[1][1..].parse::<u32>()?;
|
||||
|
||||
let group_config = GAME_RESOURCES
|
||||
.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();
|
||||
let mut json_pos = json.position.clone();
|
||||
if let Some(teleport_id) = teleport_id {
|
||||
if let Some(teleport) = group_config.teleports.get(&teleport_id) {
|
||||
let anchor = group_config
|
||||
.group_items
|
||||
.get(&teleport.anchor_group_id.unwrap_or_default())
|
||||
.and_then(|v| v.anchors.get(&teleport.anchor_id.unwrap_or_default()));
|
||||
if let Some(anchor) = anchor {
|
||||
position.x = (anchor.pos_x * 1000f64) as i32;
|
||||
position.y = (anchor.pos_y * 1000f64) as i32;
|
||||
position.z = (anchor.pos_z * 1000f64) as i32;
|
||||
position.rot_y = (anchor.rot_y * 1000f64) as i32;
|
||||
if let Some(teleport) = scene
|
||||
.scenes
|
||||
.iter()
|
||||
.find_map(|(_, v)| v.teleports.get(&teleport_id))
|
||||
{
|
||||
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;
|
||||
} 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 {
|
||||
floor_id: enterance.floor_id,
|
||||
plane_id: enterance.plane_id,
|
||||
floor_id,
|
||||
plane_id,
|
||||
entry_id,
|
||||
game_mode_type: plane.plane_type as u32,
|
||||
game_mode_type: *(&scene.plane_type) as u32,
|
||||
leader_entity_id: 1,
|
||||
world_id: plane.world_id,
|
||||
world_id: scene.world_id,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let lineup_info = AvatarJson::to_lineup_info(&json.lineups);
|
||||
let player_pos = MotionInfo {
|
||||
// rot
|
||||
rot: Some(Vector {
|
||||
x: 0,
|
||||
y: position.rot_y,
|
||||
y: json_pos.rot_y,
|
||||
z: 0,
|
||||
}),
|
||||
// pos
|
||||
pos: Some(Vector {
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
z: position.z,
|
||||
x: json_pos.x,
|
||||
y: json_pos.y,
|
||||
z: json_pos.z,
|
||||
}),
|
||||
};
|
||||
|
||||
@ -302,37 +257,30 @@ async fn load_scene(
|
||||
let mut npc_entity_id = 20_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 {
|
||||
state: 0,
|
||||
group_id: *group_id,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// Load 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;
|
||||
|
||||
let prop_position = Position {
|
||||
x: (prop.pos_x * 1000f64) as i32,
|
||||
y: (prop.pos_y * 1000f64) as i32,
|
||||
z: (prop.pos_z * 1000f64) as i32,
|
||||
rot_y: (prop.rot_y * 1000f64) as i32,
|
||||
x: (prop.pos.x),
|
||||
y: (prop.pos.y),
|
||||
z: (prop.pos.z),
|
||||
rot_y: (prop.rot.y),
|
||||
};
|
||||
|
||||
let entity_info = SceneEntityInfo {
|
||||
inst_id: prop.id,
|
||||
inst_id: prop.inst_id,
|
||||
group_id: prop.group_id,
|
||||
motion: Some(prop_position.to_motion()),
|
||||
entity: Some(Entity::Prop(ScenePropInfo {
|
||||
prop_state: prop_state as u32,
|
||||
prop_id: prop.prop_id,
|
||||
prop_state: prop.prop_state,
|
||||
prop_id: prop.prop_id,
|
||||
..Default::default()
|
||||
})),
|
||||
entity_id: prop_entity_id,
|
||||
@ -343,26 +291,26 @@ async fn load_scene(
|
||||
|
||||
// Load 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;
|
||||
}
|
||||
npc_entity_id += 1;
|
||||
loaded_npc.push(npc.npcid);
|
||||
loaded_npc.push(npc.npc_id);
|
||||
|
||||
let npc_position = Position {
|
||||
x: (npc.pos_x * 1000f64) as i32,
|
||||
y: (npc.pos_y * 1000f64) as i32,
|
||||
z: (npc.pos_z * 1000f64) as i32,
|
||||
rot_y: (npc.rot_y * 1000f64) as i32,
|
||||
x: (npc.pos.x) as i32,
|
||||
y: (npc.pos.y) as i32,
|
||||
z: (npc.pos.z) as i32,
|
||||
rot_y: (npc.rot.y) as i32,
|
||||
};
|
||||
|
||||
let info = SceneEntityInfo {
|
||||
inst_id: npc.id,
|
||||
inst_id: npc.inst_id,
|
||||
group_id: npc.group_id,
|
||||
entity_id: npc_entity_id,
|
||||
motion: Some(npc_position.to_motion()),
|
||||
entity: Some(Entity::Npc(SceneNpcInfo {
|
||||
npc_id: npc.npcid,
|
||||
npc_id: npc.npc_id,
|
||||
..Default::default()
|
||||
})),
|
||||
};
|
||||
@ -374,21 +322,21 @@ async fn load_scene(
|
||||
for monster in &group.monsters {
|
||||
monster_entity_id += 1;
|
||||
let monster_position = Position {
|
||||
x: (monster.pos_x * 1000f64) as i32,
|
||||
y: (monster.pos_y * 1000f64) as i32,
|
||||
z: (monster.pos_z * 1000f64) as i32,
|
||||
rot_y: (monster.rot_y * 1000f64) as i32,
|
||||
x: (monster.pos.x) as i32,
|
||||
y: (monster.pos.y) as i32,
|
||||
z: (monster.pos.z) as i32,
|
||||
rot_y: (monster.rot.y) as i32,
|
||||
};
|
||||
|
||||
let npc_monster = SceneNpcMonsterInfo {
|
||||
monster_id: monster.npcmonster_id,
|
||||
monster_id: monster.monster_id,
|
||||
event_id: monster.event_id,
|
||||
world_level: 6,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let info = SceneEntityInfo {
|
||||
inst_id: monster.id,
|
||||
inst_id: monster.inst_id,
|
||||
group_id: monster.group_id,
|
||||
entity_id: monster_entity_id,
|
||||
motion: Some(monster_position.to_motion()),
|
||||
@ -398,7 +346,20 @@ async fn load_scene(
|
||||
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.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
|
||||
@ -411,20 +372,7 @@ async fn load_scene(
|
||||
player_group.entity_list.push(SceneEntityInfo {
|
||||
inst_id: 0,
|
||||
entity_id: (*slot) + 1,
|
||||
motion: Some(MotionInfo {
|
||||
// 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,
|
||||
}),
|
||||
}),
|
||||
motion: Some(player_pos.clone()),
|
||||
entity: Some(Entity::Actor(SceneActorInfo {
|
||||
avatar_type: AvatarType::AvatarFormalType.into(),
|
||||
base_avatar_id: *avatar_id,
|
||||
@ -436,37 +384,22 @@ async fn load_scene(
|
||||
}
|
||||
scene_info.entity_group_list.push(player_group);
|
||||
|
||||
if _save {
|
||||
if save_scene {
|
||||
session
|
||||
.send(
|
||||
CMD_ENTER_SCENE_BY_SERVER_SC_NOTIFY,
|
||||
EnterSceneByServerScNotify {
|
||||
scene: Some(scene_info.clone()),
|
||||
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()
|
||||
},
|
||||
)
|
||||
.send(EnterSceneByServerScNotify {
|
||||
scene: Some(scene_info.clone()),
|
||||
lineup: Some(lineup_info),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
|
||||
json.scene.entry_id = entry_id;
|
||||
json.scene.floor_id = enterance.floor_id;
|
||||
json.scene.plane_id = enterance.plane_id;
|
||||
json.position.x = position.x;
|
||||
json.position.y = position.y;
|
||||
json.position.z = position.z;
|
||||
json.position.rot_y = position.rot_y;
|
||||
json.scene.floor_id = floor_id;
|
||||
json.scene.plane_id = plane_id;
|
||||
json.position.x = json_pos.x;
|
||||
json.position.y = json_pos.y;
|
||||
json.position.z = json_pos.z;
|
||||
json.position.rot_y = json_pos.rot_y;
|
||||
json.save().await;
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
// }
|
||||
@ -4,8 +4,6 @@ mod handlers;
|
||||
mod packet;
|
||||
mod session;
|
||||
mod tools;
|
||||
mod tools_res;
|
||||
|
||||
|
||||
pub use packet::NetPacket;
|
||||
pub use session::PlayerSession;
|
||||
|
||||
@ -5,6 +5,28 @@ use tokio::net::TcpStream;
|
||||
use tracing::Instrument;
|
||||
|
||||
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::PlayerSession;
|
||||
@ -58,12 +80,16 @@ impl NetPacket {
|
||||
}
|
||||
|
||||
macro_rules! trait_handler {
|
||||
($($name:ident $cmd_type:expr;)*) => {
|
||||
($($name:tt;)*) => {
|
||||
pub trait CommandHandler {
|
||||
$(
|
||||
paste! {
|
||||
async fn [<on_$name:snake>](session: &mut PlayerSession, body: &$name) -> Result<()> {
|
||||
[<on_$name:snake>](session, body).await
|
||||
async fn [<on_$name:snake _cs_req>](session: &mut PlayerSession, request: &[<$name CsReq>]) -> Result<()> {
|
||||
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?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
||||
match cmd_type {
|
||||
$(
|
||||
$cmd_type => {
|
||||
let body = $name::decode(&mut &payload[..])?;
|
||||
cmd_type if cmd_type == paste! { [<Cmd$name CsReq>] as u16 } => {
|
||||
let body = paste! { proto::[<$name CsReq>]::decode(&mut &payload[..])? };
|
||||
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))
|
||||
.await
|
||||
}
|
||||
@ -96,59 +124,54 @@ macro_rules! trait_handler {
|
||||
}
|
||||
|
||||
trait_handler! {
|
||||
PlayerGetTokenCsReq 56; // PlayerGetTokenScRsp
|
||||
PlayerLoginCsReq 68; // PlayerLoginScRsp, PlayerBasicInfo
|
||||
GetMissionStatusCsReq 1224; // GetMissionStatusScRsp, Mission
|
||||
GetBasicInfoCsReq 40; // GetBasicInfoScRsp, PlayerSettingInfo
|
||||
GetMultiPathAvatarInfoCsReq 27;
|
||||
GetAvatarDataCsReq 368; // GetAvatarDataScRsp, Avatar
|
||||
GetAllLineupDataCsReq 724; // GetAllLineupDataScRsp, LineupInfo, ExtraLineupType, LineupAvatar, AmountInfo
|
||||
GetCurLineupDataCsReq 711; // GetCurLineupDataScRsp
|
||||
GetCurSceneInfoCsReq 1439; // GetCurSceneInfoScRsp, SceneInfo
|
||||
PlayerHeartBeatCsReq 31; // PlayerHeartBeatScRsp
|
||||
PlayerGetToken;
|
||||
PlayerLogin;
|
||||
GetMissionStatus;
|
||||
GetBasicInfo;
|
||||
GetMultiPathAvatarInfo;
|
||||
GetAvatarData;
|
||||
GetAllLineupData;
|
||||
GetCurLineupData;
|
||||
GetCurSceneInfo;
|
||||
PlayerHeartBeat;
|
||||
|
||||
// // Tutorial (dummy!)
|
||||
// GetTutorialGuideCsReq 1691;
|
||||
// UnlockTutorialGuideCsReq 1630;
|
||||
// GetTutorialCsReq 1661;
|
||||
|
||||
// Entity move (dummy!)
|
||||
SceneEntityMoveCsReq 1468;
|
||||
SceneEntityMove;
|
||||
|
||||
// Inventory (dummy!)
|
||||
GetBagCsReq 568;
|
||||
GetArchiveDataCsReq 2368;
|
||||
DressAvatarCsReq 351;
|
||||
TakeOffEquipmentCsReq 399;
|
||||
DressRelicAvatarCsReq 334;
|
||||
TakeOffRelicCsReq 398;
|
||||
GetBag;
|
||||
GetArchiveData;
|
||||
DressAvatar;
|
||||
TakeOffEquipment;
|
||||
DressRelicAvatar;
|
||||
TakeOffRelic;
|
||||
|
||||
// Chat (dummy!)
|
||||
SendMsgCsReq 3968;
|
||||
GetPrivateChatHistoryCsReq 3956;
|
||||
GetFriendListInfoCsReq 2968;
|
||||
GetFriendLoginInfoCsReq 2969;
|
||||
SendMsg;
|
||||
GetPrivateChatHistory;
|
||||
GetFriendListInfo;
|
||||
GetFriendLoginInfo;
|
||||
|
||||
// In-game lineup
|
||||
JoinLineupCsReq 756;
|
||||
ChangeLineupLeaderCsReq 748;
|
||||
ReplaceLineupCsReq 790;
|
||||
QuitLineupCsReq 739;
|
||||
JoinLineup;
|
||||
ChangeLineupLeader;
|
||||
ReplaceLineup;
|
||||
QuitLineup;
|
||||
|
||||
// Battle
|
||||
StartCocoonStageCsReq 1445;
|
||||
PveBattleResultCsReq 168;
|
||||
SceneCastSkillCsReq 1456;
|
||||
StartCocoonStage;
|
||||
PveBattleResult;
|
||||
SceneCastSkill;
|
||||
|
||||
// Teleport
|
||||
GetEnteredSceneCsReq 1427;
|
||||
GetSceneMapInfoCsReq 1436;
|
||||
EnterSceneCsReq 1486;
|
||||
GetEnteredScene;
|
||||
GetSceneMapInfo;
|
||||
EnterScene;
|
||||
|
||||
// Optional
|
||||
GetMailCsReq 868;
|
||||
GetGachaInfoCsReq 1968;
|
||||
DoGachaCsReq 1911;
|
||||
// GetQuestDataCsReq 961;
|
||||
PlayerLoginFinishCsReq 73;
|
||||
GetMail;
|
||||
GetGachaInfo;
|
||||
DoGacha;
|
||||
PlayerLoginFinish;
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use anyhow::Result;
|
||||
use prost::Message;
|
||||
use proto::CmdID;
|
||||
use tokio::{io::AsyncWriteExt, net::TcpStream};
|
||||
|
||||
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();
|
||||
body.encode(&mut buf)?;
|
||||
|
||||
let payload: Vec<u8> = NetPacket {
|
||||
cmd_type,
|
||||
cmd_type: body.get_cmd_id(),
|
||||
head: Vec::new(),
|
||||
body: buf,
|
||||
}
|
||||
|
||||
@ -12,7 +12,6 @@ pub struct AvatarJson {
|
||||
pub data: AvatarData,
|
||||
pub level: u32,
|
||||
pub promotion: u32,
|
||||
// pub rank: u32,
|
||||
#[serde(alias = "use_technique")]
|
||||
#[serde(alias = "useTechnique")]
|
||||
pub techniques: Vec<u32>,
|
||||
@ -32,7 +31,6 @@ impl AvatarJson {
|
||||
pub fn to_avatar_proto(&self, lightcone: Option<&Lightcone>, relics: Vec<&Relic>) -> Avatar {
|
||||
Avatar {
|
||||
base_avatar_id: self.avatar_id,
|
||||
exp: 0,
|
||||
level: self.level,
|
||||
promotion: self.promotion,
|
||||
rank: self.data.rank,
|
||||
@ -68,7 +66,7 @@ impl AvatarJson {
|
||||
) -> (BattleAvatar, Vec<BattleBuff>) {
|
||||
let battle_avatar = BattleAvatar {
|
||||
index,
|
||||
avatar_type: AvatarType::AvatarFormalType.into(),
|
||||
avatar_type: AvatarType::AvatarUpgradeAvailableType.into(),
|
||||
id: self.avatar_id,
|
||||
level: self.level,
|
||||
rank: self.data.rank,
|
||||
@ -358,6 +356,8 @@ pub struct BattleConfig {
|
||||
pub cycle_count: u32,
|
||||
pub path_resonance_id: u32,
|
||||
pub custom_stats: Vec<SubAffix>,
|
||||
#[serde(default)]
|
||||
pub scepters: Vec<RogueMagicScepter>,
|
||||
}
|
||||
|
||||
impl Default for BattleConfig {
|
||||
@ -374,6 +374,7 @@ impl Default for BattleConfig {
|
||||
cycle_count: Default::default(),
|
||||
path_resonance_id: 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
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Scene {
|
||||
@ -463,13 +487,11 @@ impl Position {
|
||||
|
||||
pub fn to_motion(&self) -> MotionInfo {
|
||||
MotionInfo {
|
||||
// rot
|
||||
rot: Some(Vector {
|
||||
x: 0,
|
||||
y: self.rot_y,
|
||||
z: 0,
|
||||
}),
|
||||
// pos
|
||||
pos: Some(Vector {
|
||||
x: self.x,
|
||||
y: self.y,
|
||||
@ -488,15 +510,15 @@ pub struct FreesrData {
|
||||
#[serde(default)]
|
||||
pub battle_config: BattleConfig,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing)]
|
||||
pub lineups: BTreeMap<u32, u32>,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing)]
|
||||
pub position: Position,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing)]
|
||||
pub scene: Scene,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing)]
|
||||
pub main_character: MultiPathAvatar,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing)]
|
||||
pub march_type: MultiPathAvatar,
|
||||
}
|
||||
|
||||
@ -517,7 +539,7 @@ pub struct Persistent {
|
||||
impl Default for Persistent {
|
||||
fn default() -> Self {
|
||||
let mut lineups = BTreeMap::<u32, u32>::new();
|
||||
lineups.insert(0, 8006);
|
||||
lineups.insert(0, 8001);
|
||||
lineups.insert(1, 0);
|
||||
lineups.insert(2, 0);
|
||||
lineups.insert(3, 0);
|
||||
@ -624,7 +646,7 @@ impl FreesrData {
|
||||
|
||||
async fn verify_lineup(&mut self) {
|
||||
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 {
|
||||
for i in self.lineups.len()..4 {
|
||||
self.lineups.insert(i as u32, 0);
|
||||
|
||||
@ -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
gameserver/src/tools/mod.rs
Normal file
1
gameserver/src/tools/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod resources;
|
||||
145
gameserver/src/tools/resources.rs
Normal file
145
gameserver/src/tools/resources.rs
Normal 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()
|
||||
});
|
||||
24
persistent
24
persistent
@ -1,21 +1,21 @@
|
||||
{
|
||||
"lineups": {
|
||||
"0": 1222,
|
||||
"1": 1223,
|
||||
"2": 1220,
|
||||
"3": 1308
|
||||
"0": 1220,
|
||||
"1": 1222,
|
||||
"2": 1304,
|
||||
"3": 1309
|
||||
},
|
||||
"position": {
|
||||
"x": -3722,
|
||||
"y": 56256,
|
||||
"z": -87464,
|
||||
"rot_y": 318488
|
||||
"x": 64574,
|
||||
"y": 1699,
|
||||
"z": 258502,
|
||||
"rot_y": 243401
|
||||
},
|
||||
"scene": {
|
||||
"plane_id": 20321,
|
||||
"floor_id": 20321001,
|
||||
"entry_id": 2032101
|
||||
"plane_id": 20332,
|
||||
"floor_id": 20332001,
|
||||
"entry_id": 2033201
|
||||
},
|
||||
"main_character": "FemaleHarmony",
|
||||
"march_type": "MarchHunt"
|
||||
"march_type": "FemaleHarmony"
|
||||
}
|
||||
@ -6,6 +6,7 @@ version.workspace = true
|
||||
[dependencies]
|
||||
prost.workspace = true
|
||||
prost-types.workspace = true
|
||||
proto-derive.workspace = true
|
||||
|
||||
[build-dependencies]
|
||||
prost-build.workspace = true
|
||||
|
||||
@ -1,3 +1,9 @@
|
||||
use std::{
|
||||
fs,
|
||||
io::{self, BufRead},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
pub fn main() {
|
||||
let proto_file = "StarRail.proto";
|
||||
if std::path::Path::new(proto_file).exists() {
|
||||
@ -5,7 +11,38 @@ pub fn main() {
|
||||
|
||||
prost_build::Config::new()
|
||||
.out_dir("out/")
|
||||
.type_attribute(".", "#[derive(proto_derive::CmdID)]")
|
||||
.compile_protos(&[proto_file], &["."])
|
||||
.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})]"))
|
||||
}
|
||||
|
||||
62812
proto/out/_.rs
62812
proto/out/_.rs
File diff suppressed because it is too large
Load Diff
12
proto/proto-derive/Cargo.toml
Normal file
12
proto/proto-derive/Cargo.toml
Normal 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
proto/proto-derive/src/lib.rs
Normal file
27
proto/proto-derive/src/lib.rs
Normal 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
@ -1,4 +1,12 @@
|
||||
mod cmd_types;
|
||||
pub use cmd_types::*;
|
||||
|
||||
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
0
proto/src/message.rs
Normal file
File diff suppressed because one or more lines are too long
@ -42,7 +42,6 @@ pub async fn query_gateway(parameters: Query<QueryGatewayParameters>) -> String
|
||||
asset_bundle_url: config.asset_bundle_url.clone(),
|
||||
ex_resource_url: config.ex_resource_url.clone(),
|
||||
lua_url: config.lua_url.clone(),
|
||||
// lua_version: config.lua_version.clone(),
|
||||
ifix_version: String::from("0"),
|
||||
unk1: true,
|
||||
unk2: true,
|
||||
@ -51,14 +50,8 @@ pub async fn query_gateway(parameters: Query<QueryGatewayParameters>) -> String
|
||||
unk5: true,
|
||||
unk6: true,
|
||||
unk7: true,
|
||||
mmcachlfjaa: true,
|
||||
ncikdciigof: true,
|
||||
efknbdlnakj: true,
|
||||
gpjcfcjdmol: true,
|
||||
jidbdekohdh: true,
|
||||
pphbpgbnoem: true,
|
||||
dhppkkgjldl: true,
|
||||
jipjkleanbd: true,
|
||||
jgciiljehhe: true,
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
{
|
||||
"CNBETAWin2.2.51": {
|
||||
"asset_bundle_url": "https://autopatchcn.bhsr.com/asb/BetaLive/output_7037158_b67f5a6a68fb",
|
||||
"ex_resource_url": "https://autopatchcn.bhsr.com/design_data/BetaLive/output_7033392_aaca9c1b456b",
|
||||
"lua_url": "https://autopatchcn.bhsr.com/lua/BetaLive/output_7050564_f05a0f949b10",
|
||||
"lua_version": "7050564"
|
||||
"CNBETAWin2.5.51": {
|
||||
"asset_bundle_url": "",
|
||||
"ex_resource_url": "",
|
||||
"lua_url": "",
|
||||
"ifix_url": ""
|
||||
},
|
||||
"OSBETAWin2.2.51": {
|
||||
"asset_bundle_url": "https://autopatchos.starrails.com/asb/BetaLive/output_7037158_b67f5a6a68fb",
|
||||
"ex_resource_url": "https://autopatchos.starrails.com/design_data/BetaLive/output_7033392_aaca9c1b456b",
|
||||
"lua_url": "https://autopatchos.starrails.com/lua/BetaLive/output_7050564_f05a0f949b10",
|
||||
"lua_version": "7050564"
|
||||
"CNBETAWin2.5.52": {
|
||||
"asset_bundle_url": "",
|
||||
"ex_resource_url": "",
|
||||
"lua_url": "",
|
||||
"ifix_url": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
{
|
||||
"CNBETAWin2.4.51": {
|
||||
"asset_bundle_url": "https://autopatchcn-ipv6.bhsr.com/asb/BetaLive/output_7663997_cd086af3f307",
|
||||
"ex_resource_url": "https://autopatchcn-ipv6.bhsr.com/design_data/BetaLive/output_7689868_456662b48277",
|
||||
"lua_url": "https://autopatchcn-ipv6.bhsr.com/lua/BetaLive/output_7668875_0231727458ad",
|
||||
"ifix_url": "https://autopatchcn-ipv6.bhsr.com/ifix/BetaLive/output_0_40d2ce0253"
|
||||
"CNBETAWin2.5.51": {
|
||||
"asset_bundle_url": "",
|
||||
"ex_resource_url": "",
|
||||
"lua_url": "",
|
||||
"ifix_url": ""
|
||||
},
|
||||
"CNBETAWin2.5.52": {
|
||||
"asset_bundle_url": "",
|
||||
"ex_resource_url": "",
|
||||
"lua_url": "",
|
||||
"ifix_url": ""
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user