1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-04-22 07:27:44 +00:00
kawari/src/ipc.rs

250 lines
6.8 KiB
Rust
Raw Normal View History

use binrw::binrw;
use crate::common::{read_string, write_string};
#[binrw]
#[brw(repr = u16)]
#[derive(Clone, PartialEq, Debug)]
pub enum IPCOpCode {
/// Sent by the client when it requests the character list in the lobby.
RequestCharacterList = 0x3,
/// Sent by the client when it requests to enter a world.
RequestEnterWorld = 0x4,
/// Sent by the client after exchanging encryption information with the lobby server.
ClientVersionInfo = 0x5,
/// Sent by the client when they request something about the character (e.g. deletion.)
LobbyCharacterAction = 0xB,
/// Sent by the server to inform the client of their service accounts.
LobbyServiceAccountList = 0xC,
/// Sent by the server to inform the client of their characters.
LobbyCharacterList = 0xD,
/// Sent by the server to tell the client how to connect to the world server.
LobbyEnterWorld = 0xF,
/// Sent by the server to inform the client of their servers.
LobbyServerList = 0x15,
/// Sent by the server to inform the client of their retainers.
LobbyRetainerList = 0x17,
}
#[binrw]
#[derive(Debug, Clone, Default)]
pub struct ServiceAccount {
pub id: u32,
pub unk1: u32,
pub index: u32,
#[bw(pad_size_to = 0x44)]
#[br(count = 0x44)]
#[br(map = read_string)]
#[bw(map = write_string)]
pub name: String,
}
#[binrw]
#[derive(Debug, Clone, Default)]
pub struct Server {
pub id: u16,
pub index: u16,
pub flags: u32,
#[brw(pad_before = 4)]
#[brw(pad_after = 4)]
pub icon: u32,
#[bw(pad_size_to = 0x40)]
#[br(count = 0x40)]
#[br(map = read_string)]
#[bw(map = write_string)]
pub name: String,
}
#[binrw]
#[derive(Debug, Clone, Default)]
pub struct CharacterDetails {
#[brw(pad_after = 4)]
pub id: u32,
pub content_id: u64,
#[brw(pad_after = 4)]
pub index: u32,
pub origin_server_id: u16,
pub current_server_id: u16,
pub unk1: [u8; 16],
2025-03-08 23:49:53 -05:00
#[bw(pad_size_to = 32)]
#[br(count = 32)]
#[br(map = read_string)]
#[bw(map = write_string)]
pub character_name: String,
#[bw(pad_size_to = 32)]
#[br(count = 32)]
#[br(map = read_string)]
#[bw(map = write_string)]
pub origin_server_name: String,
#[bw(pad_size_to = 32)]
#[br(count = 32)]
#[br(map = read_string)]
#[bw(map = write_string)]
pub current_server_name: String,
#[bw(pad_size_to = 1024)]
#[br(count = 1024)]
#[br(map = read_string)]
#[bw(map = write_string)]
pub character_detail_json: String,
pub unk2: [u8; 20],
}
#[binrw]
#[brw(repr = u8)]
#[derive(Clone, PartialEq, Debug)]
pub enum LobbyCharacterAction {
Delete = 0x4,
Request = 0x15,
}
#[binrw]
#[br(import(magic: &IPCOpCode))]
#[derive(Debug, Clone)]
pub enum IPCStructData {
// Client->Server IPC
#[br(pre_assert(*magic == IPCOpCode::ClientVersionInfo))]
ClientVersionInfo {
#[brw(pad_before = 18)] // full of nonsense i don't understand yet
#[br(count = 64)]
#[br(map = read_string)]
#[bw(ignore)]
session_id: String,
#[brw(pad_before = 8)] // empty
#[br(count = 128)]
#[br(map = read_string)]
#[bw(ignore)]
version_info: String,
// unknown stuff at the end, it's not completely empty'
},
#[br(pre_assert(*magic == IPCOpCode::RequestCharacterList))]
RequestCharacterList {
#[brw(pad_before = 16)]
sequence: u64,
// TODO: what is in here?
},
#[br(pre_assert(*magic == IPCOpCode::LobbyCharacterAction))]
LobbyCharacterAction {
#[brw(pad_before = 16)]
sequence: u64,
#[brw(pad_before = 1)]
action: LobbyCharacterAction,
#[brw(pad_before = 2)]
#[bw(pad_size_to = 32)]
#[br(count = 32)]
#[br(map = read_string)]
#[bw(map = write_string)]
name: String,
// TODO: what else is in here?
},
#[br(pre_assert(*magic == IPCOpCode::RequestEnterWorld))]
RequestEnterWorld {
#[brw(pad_before = 16)]
sequence: u64,
lookup_id: u64,
// TODO: what else is in here?
},
// Server->Client IPC
LobbyServiceAccountList {
sequence: u64,
#[brw(pad_before = 1)]
num_service_accounts: u8,
unk1: u8,
#[brw(pad_after = 4)]
unk2: u8,
#[br(count = 8)]
service_accounts: Vec<ServiceAccount>,
},
LobbyServerList {
sequence: u64,
unk1: u16,
offset: u16,
#[brw(pad_after = 8)]
num_servers: u32,
#[br(count = 6)]
servers: Vec<Server>,
},
LobbyRetainerList {
// TODO: what is in here?
#[brw(pad_before = 7)]
#[brw(pad_after = 202)]
unk1: u8,
},
LobbyCharacterList {
sequence: u64,
counter: u8,
#[brw(pad_after = 2)]
num_in_packet: u8,
unk1: u8,
unk2: u8,
unk3: u8,
/// Set to 128 if legacy character
unk4: u8,
unk5: [u32; 7],
unk6: u8,
veteran_rank: u8,
#[brw(pad_after = 1)]
unk7: u8,
days_subscribed: u32,
remaining_days: u32,
days_to_next_rank: u32,
2025-03-08 23:49:53 -05:00
max_characters_on_world: u16,
unk8: u16,
#[brw(pad_after = 12)]
entitled_expansion: u32,
#[br(count = 2)]
characters: Vec<CharacterDetails>,
},
LobbyEnterWorld {
sequence: u64,
character_id: u32,
#[brw(pad_before = 4)]
content_id: u64,
#[brw(pad_before = 4)]
#[bw(pad_size_to = 66)]
#[br(count = 66)]
#[br(map = read_string)]
#[bw(map = write_string)]
session_id: String,
port: u16,
#[brw(pad_after = 16)]
#[br(count = 48)]
#[br(map = read_string)]
#[bw(map = write_string)]
host: String,
},
}
#[binrw]
#[derive(Debug, Clone)]
pub struct IPCSegment {
pub unk1: u8,
pub unk2: u8,
pub op_code: IPCOpCode,
#[brw(pad_before = 2)] // empty
pub server_id: u16,
pub timestamp: u32,
#[brw(pad_before = 4)]
#[br(args(&op_code))]
pub data: IPCStructData,
}
impl IPCSegment {
pub fn calc_size(&self) -> u32 {
let header = 16;
header
+ match self.data {
IPCStructData::ClientVersionInfo { .. } => todo!(),
IPCStructData::LobbyServiceAccountList { .. } => 24 + (8 * 80),
IPCStructData::RequestCharacterList { .. } => todo!(),
IPCStructData::LobbyServerList { .. } => 24 + (6 * 84),
IPCStructData::LobbyRetainerList { .. } => 210,
2025-03-08 23:49:53 -05:00
IPCStructData::LobbyCharacterList { .. } => 80 + (2 * 1184),
IPCStructData::LobbyCharacterAction { .. } => todo!(),
IPCStructData::LobbyEnterWorld { .. } => 160,
IPCStructData::RequestEnterWorld { .. } => todo!(),
}
}
}