From 1cd68ee1a3a633bfc2887e4ad833a27b2550e81f Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Sun, 9 Mar 2025 11:01:06 -0400 Subject: [PATCH] Store session id, handle world join requests We have yet to implement the world server, so the client gets kicked back to the main menu immediately right now. --- src/bin/kawari-lobby.rs | 55 ++++++++++++++++++++++++++++++++++++++++- src/ipc.rs | 31 +++++++++++++++++++++++ src/packet.rs | 1 + 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/src/bin/kawari-lobby.rs b/src/bin/kawari-lobby.rs index b3e976b..7a49810 100644 --- a/src/bin/kawari-lobby.rs +++ b/src/bin/kawari-lobby.rs @@ -23,7 +23,7 @@ async fn main() { let (socket, _) = listener.accept().await.unwrap(); let (mut read, mut write) = tokio::io::split(socket); - let mut state = State { client_key: None }; + let mut state = State {client_key:None, session_id: None }; tokio::spawn(async move { let mut buf = [0; 2056]; @@ -46,6 +46,8 @@ async fn main() { "Client {session_id} ({version_info}) logging in!" ); + state.session_id = Some(session_id.clone()); + send_account_list(&mut write, &state).await; } IPCStructData::RequestCharacterList { sequence } => { @@ -69,6 +71,14 @@ async fn main() { ); } }, + IPCStructData::RequestEnterWorld { + sequence, + lookup_id, + } => { + tracing::info!("Client is joining the world..."); + + send_enter_world(&mut write, &state, *sequence, *lookup_id).await; + } _ => { panic!("The server is recieving a IPC response packet!") } @@ -371,3 +381,46 @@ async fn send_lobby_info(socket: &mut WriteHalf, state: &State, seque } } } + +async fn send_enter_world( + socket: &mut WriteHalf, + state: &State, + sequence: u64, + lookup_id: u64, +) { + let Some(session_id) = &state.session_id else { + panic!("Missing session id!"); + }; + + let timestamp: u32 = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Failed to get UNIX timestamp!") + .as_secs() + .try_into() + .unwrap(); + + let enter_world = IPCStructData::LobbyEnterWorld { + sequence, + character_id: 0, + content_id: lookup_id, // TODO: shouldn't these be named the same then? + session_id: session_id.clone(), + port: 7100, + host: "127.0.0.1".to_string(), + }; + + let ipc = IPCSegment { + unk1: 0, + unk2: 0, + op_code: IPCOpCode::LobbyEnterWorld, + server_id: 0, + timestamp, + data: enter_world, + }; + + let response_packet = PacketSegment { + source_actor: 0, + target_actor: 0, + segment_type: SegmentType::Ipc { data: ipc }, + }; + send_packet(socket, &[response_packet], state).await; +} diff --git a/src/ipc.rs b/src/ipc.rs index fd2e563..322107b 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -8,6 +8,8 @@ use crate::common::{read_string, write_string}; 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.) @@ -16,6 +18,8 @@ pub enum IPCOpCode { 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. @@ -133,6 +137,13 @@ pub enum IPCStructData { 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 { @@ -185,6 +196,24 @@ pub enum IPCStructData { #[br(count = 2)] characters: Vec, }, + 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] @@ -213,6 +242,8 @@ impl IPCSegment { IPCStructData::LobbyRetainerList { .. } => 210, IPCStructData::LobbyCharacterList { .. } => 80 + (2 * 1184), IPCStructData::LobbyCharacterAction { .. } => todo!(), + IPCStructData::LobbyEnterWorld { .. } => 160, + IPCStructData::RequestEnterWorld { .. } => todo!(), } } } diff --git a/src/packet.rs b/src/packet.rs index 60505fc..5af9586 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -176,6 +176,7 @@ pub async fn send_packet( // temporary pub struct State { pub client_key: Option<[u8; 16]>, + pub session_id: Option, } pub async fn parse_packet(data: &[u8], state: &mut State) -> Vec {