1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-07-10 07:57:46 +00:00

Fix various size issues with lobby IPC packets

Some of these were the wrong size, and were affecting both the
server and packet analyzer alike. This should now more accurately
reflect retail.
This commit is contained in:
Joshua Goins 2025-07-04 15:01:27 -04:00
parent 7801398590
commit 24edee6548
4 changed files with 105 additions and 33 deletions

View file

@ -412,7 +412,7 @@
{ {
"name": "DistRetainerInfo", "name": "DistRetainerInfo",
"opcode": 23, "opcode": 23,
"size": 210 "size": 536
} }
], ],
"ClientLobbyIpcType": [ "ClientLobbyIpcType": [

View file

@ -216,6 +216,7 @@ async fn main() {
sequence, sequence,
session_id, session_id,
version_info, version_info,
..
} => { } => {
tracing::info!( tracing::info!(
"Client {session_id} ({version_info}) logging in!" "Client {session_id} ({version_info}) logging in!"
@ -294,6 +295,7 @@ async fn main() {
ClientLobbyIpcData::GameLogin { ClientLobbyIpcData::GameLogin {
sequence, sequence,
content_id, content_id,
..
} => { } => {
tracing::info!("Client is joining the world with {content_id}"); tracing::info!("Client is joining the world with {content_id}");

View file

@ -5,8 +5,9 @@ use crate::common::CHAR_NAME_MAX_LENGTH;
use super::{read_string, write_string}; use super::{read_string, write_string};
#[binrw] #[binrw]
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug, Default)]
pub enum LobbyCharacterActionKind { pub enum LobbyCharacterActionKind {
#[default]
#[brw(magic = 0x1u8)] #[brw(magic = 0x1u8)]
ReserveName, ReserveName,
#[brw(magic = 0x2u8)] #[brw(magic = 0x2u8)]
@ -34,11 +35,11 @@ pub enum LobbyCharacterActionKind {
} }
#[binrw] #[binrw]
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug, Default)]
pub struct CharaMake { pub struct CharaMake {
pub sequence: u64, pub sequence: u64,
pub content_id: u64, pub content_id: u64,
#[br(pad_before = 8)] #[brw(pad_before = 8)]
pub character_index: u8, pub character_index: u8,
pub action: LobbyCharacterActionKind, pub action: LobbyCharacterActionKind,
pub world_id: u16, pub world_id: u16,

View file

@ -47,6 +47,7 @@ impl Default for ClientLobbyIpcSegment {
sequence: 0, sequence: 0,
session_id: String::new(), session_id: String::new(),
version_info: String::new(), version_info: String::new(),
unk1: 0,
}, },
} }
} }
@ -105,6 +106,8 @@ pub enum ClientLobbyIpcData {
sequence: u64, sequence: u64,
content_id: u64, content_id: u64,
// TODO: what else is in here? // TODO: what else is in here?
unk1: u64,
unk2: u64,
}, },
/// Sent by the client after exchanging encryption information with the lobby server. /// Sent by the client after exchanging encryption information with the lobby server.
#[br(pre_assert(*magic == ClientLobbyIpcType::LoginEx))] #[br(pre_assert(*magic == ClientLobbyIpcType::LoginEx))]
@ -113,15 +116,19 @@ pub enum ClientLobbyIpcData {
#[brw(pad_before = 10)] // full of nonsense i don't understand yet #[brw(pad_before = 10)] // full of nonsense i don't understand yet
#[br(count = 64)] #[br(count = 64)]
#[bw(pad_size_to = 64)]
#[br(map = read_string)] #[br(map = read_string)]
#[bw(ignore)] #[bw(map = write_string)]
session_id: String, session_id: String,
#[br(count = 144)] #[br(count = 144)]
#[bw(pad_size_to = 144)]
#[br(map = read_string)] #[br(map = read_string)]
#[bw(ignore)] #[bw(map = write_string)]
version_info: String, version_info: String,
// unknown stuff at the end, it's not completely empty
#[brw(pad_before = 910)] // empty
unk1: u64,
}, },
#[br(pre_assert(*magic == ClientLobbyIpcType::ShandaLogin))] #[br(pre_assert(*magic == ClientLobbyIpcType::ShandaLogin))]
ShandaLogin { ShandaLogin {
@ -199,7 +206,7 @@ pub enum ServerLobbyIpcData {
DistRetainerInfo { DistRetainerInfo {
// TODO: what is in here? // TODO: what is in here?
#[brw(pad_before = 7)] #[brw(pad_before = 7)]
#[brw(pad_after = 202)] #[brw(pad_after = 528)]
unk1: u8, unk1: u8,
}, },
Unknown { Unknown {
@ -218,24 +225,36 @@ mod tests {
/// Ensure that the IPC data size as reported matches up with what we write /// Ensure that the IPC data size as reported matches up with what we write
#[test] #[test]
fn lobby_ipc_sizes() { fn server_lobby_ipc_sizes() {
let ipc_types = [ let ipc_types = [
(
ServerLobbyIpcType::NackReply,
ServerLobbyIpcData::NackReply {
sequence: 0,
error: 0,
value: 0,
exd_error_id: 0,
unk1: 0,
},
),
( (
ServerLobbyIpcType::LoginReply, ServerLobbyIpcType::LoginReply,
ServerLobbyIpcData::LoginReply(LoginReply::default()), ServerLobbyIpcData::LoginReply(LoginReply::default()),
), ),
(
ServerLobbyIpcType::DistWorldInfo,
ServerLobbyIpcData::DistWorldInfo(DistWorldInfo::default()),
),
(
ServerLobbyIpcType::DistRetainerInfo,
ServerLobbyIpcData::DistRetainerInfo { unk1: 0 },
),
( (
ServerLobbyIpcType::ServiceLoginReply, ServerLobbyIpcType::ServiceLoginReply,
ServerLobbyIpcData::ServiceLoginReply(ServiceLoginReply::default()), ServerLobbyIpcData::ServiceLoginReply(ServiceLoginReply::default()),
), ),
(
ServerLobbyIpcType::CharaMakeReply,
ServerLobbyIpcData::CharaMakeReply {
sequence: 0,
unk1: 0,
unk2: 0,
action: LobbyCharacterActionKind::ReserveName,
details: CharacterDetails::default(),
},
),
( (
ServerLobbyIpcType::GameLoginReply, ServerLobbyIpcType::GameLoginReply,
ServerLobbyIpcData::GameLoginReply { ServerLobbyIpcData::GameLoginReply {
@ -248,24 +267,12 @@ mod tests {
}, },
), ),
( (
ServerLobbyIpcType::NackReply, ServerLobbyIpcType::DistWorldInfo,
ServerLobbyIpcData::NackReply { ServerLobbyIpcData::DistWorldInfo(DistWorldInfo::default()),
sequence: 0,
error: 0,
value: 0,
exd_error_id: 0,
unk1: 0,
},
), ),
( (
ServerLobbyIpcType::CharaMakeReply, ServerLobbyIpcType::DistRetainerInfo,
ServerLobbyIpcData::CharaMakeReply { ServerLobbyIpcData::DistRetainerInfo { unk1: 0 },
sequence: 0,
unk1: 0,
unk2: 0,
action: LobbyCharacterActionKind::ReserveName,
details: CharacterDetails::default(),
},
), ),
]; ];
@ -292,4 +299,66 @@ mod tests {
); );
} }
} }
/// Ensure that the IPC data size as reported matches up with what we write
#[test]
fn client_lobby_ipc_sizes() {
let ipc_types = [
(
ClientLobbyIpcType::ServiceLogin,
ClientLobbyIpcData::ServiceLogin { sequence: 0 },
),
(
ClientLobbyIpcType::GameLogin,
ClientLobbyIpcData::GameLogin {
sequence: 0,
content_id: 0,
unk1: 0,
unk2: 0,
},
),
(
ClientLobbyIpcType::LoginEx,
ClientLobbyIpcData::LoginEx {
sequence: 0,
session_id: String::default(),
version_info: String::default(),
unk1: 0,
},
),
(
ClientLobbyIpcType::ShandaLogin,
ClientLobbyIpcData::ShandaLogin {
unk: Vec::default(),
},
),
(
ClientLobbyIpcType::CharaMake,
ClientLobbyIpcData::CharaMake(CharaMake::default()),
),
];
for (opcode, ipc) in &ipc_types {
let mut cursor = Cursor::new(Vec::new());
let ipc_segment = ClientLobbyIpcSegment {
unk1: 0,
unk2: 0,
op_code: opcode.clone(),
option: 0,
timestamp: 0,
data: ipc.clone(),
};
ipc_segment.write_le(&mut cursor).unwrap();
let buffer = cursor.into_inner();
assert_eq!(
buffer.len(),
ipc_segment.calc_size() as usize,
"{:#?} did not match size!",
opcode
);
}
}
} }