1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-06-08 17:37:46 +00:00

Add world server, fix reading compression type

This doesn't work yet as we don't implement Oodle decompression, but we at least
start recieving the packets.
This commit is contained in:
Joshua Goins 2025-03-09 11:07:01 -04:00
parent 1cd68ee1a3
commit e5d143d2c6
5 changed files with 68 additions and 10 deletions

1
run.sh
View file

@ -8,4 +8,5 @@ cargo run -q --package kawari --bin kawari-login &
cargo run -q --package kawari --bin kawari-patch & cargo run -q --package kawari --bin kawari-patch &
cargo run -q --package kawari --bin kawari-web & cargo run -q --package kawari --bin kawari-web &
cargo run -q --package kawari --bin kawari-lobby & cargo run -q --package kawari --bin kawari-lobby &
cargo run -q --package kawari --bin kawari-world &
wait wait

View file

@ -1,5 +1,4 @@
use std::cmp::min; use std::cmp::min;
use std::fs::read;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use kawari::client_select_data::{ClientCustomizeData, ClientSelectData}; use kawari::client_select_data::{ClientCustomizeData, ClientSelectData};
@ -23,7 +22,10 @@ async fn main() {
let (socket, _) = listener.accept().await.unwrap(); let (socket, _) = listener.accept().await.unwrap();
let (mut read, mut write) = tokio::io::split(socket); let (mut read, mut write) = tokio::io::split(socket);
let mut state = State {client_key:None, session_id: None }; let mut state = State {
client_key: None,
session_id: None,
};
tokio::spawn(async move { tokio::spawn(async move {
let mut buf = [0; 2056]; let mut buf = [0; 2056];
@ -77,7 +79,8 @@ async fn main() {
} => { } => {
tracing::info!("Client is joining the world..."); tracing::info!("Client is joining the world...");
send_enter_world(&mut write, &state, *sequence, *lookup_id).await; send_enter_world(&mut write, &state, *sequence, *lookup_id)
.await;
} }
_ => { _ => {
panic!("The server is recieving a IPC response packet!") panic!("The server is recieving a IPC response packet!")
@ -131,7 +134,7 @@ async fn send_account_list(socket: &mut WriteHalf<TcpStream>, state: &State) {
.unwrap(); .unwrap();
// send the client the service account list // send the client the service account list
let mut service_accounts = [ServiceAccount { let service_accounts = [ServiceAccount {
id: 0x002E4A2B, id: 0x002E4A2B,
unk1: 0, unk1: 0,
index: 0, index: 0,

46
src/bin/kawari-world.rs Normal file
View file

@ -0,0 +1,46 @@
use kawari::packet::{SegmentType, State, parse_packet, send_keep_alive};
use tokio::io::AsyncReadExt;
use tokio::net::TcpListener;
#[tokio::main]
async fn main() {
tracing_subscriber::fmt::init();
let listener = TcpListener::bind("127.0.0.1:7100").await.unwrap();
tracing::info!("World server started on 7100");
loop {
let (socket, _) = listener.accept().await.unwrap();
let (mut read, mut write) = tokio::io::split(socket);
let mut state = State {
client_key: None,
session_id: None,
};
tokio::spawn(async move {
let mut buf = [0; 2056];
loop {
let n = read.read(&mut buf).await.expect("Failed to read data!");
if n != 0 {
let segments = parse_packet(&buf[..n], &mut state).await;
for segment in &segments {
match &segment.segment_type {
SegmentType::Ipc { data } => {
panic!("The server is recieving a IPC response or unknown packet!")
}
SegmentType::KeepAlive { id, timestamp } => {
send_keep_alive(&mut write, &state, *id, *timestamp).await
}
_ => {
panic!("The server is recieving a response or unknown packet!")
}
}
}
}
}
});
}
}

View file

@ -49,7 +49,7 @@ where
let decryption_result = blowfish_decode(encryption_key.as_ptr(), 16, data.as_ptr(), size); let decryption_result = blowfish_decode(encryption_key.as_ptr(), 16, data.as_ptr(), size);
let decrypted_data = slice::from_raw_parts(decryption_result, size as usize); let decrypted_data = slice::from_raw_parts(decryption_result, size as usize);
write("decrypted.bin", &decrypted_data).unwrap(); write("decrypted.bin", decrypted_data).unwrap();
let mut cursor = Cursor::new(&decrypted_data); let mut cursor = Cursor::new(&decrypted_data);
T::read_options(&mut cursor, endian, ()) T::read_options(&mut cursor, endian, ())

View file

@ -11,7 +11,7 @@ use tokio::{
}; };
use crate::{ use crate::{
common::{read_bool_from, read_string, write_bool_as}, common::read_string,
encryption::{decrypt, encrypt}, encryption::{decrypt, encrypt},
ipc::IPCSegment, ipc::IPCSegment,
}; };
@ -61,6 +61,15 @@ pub enum SegmentType {
KeepAliveResponse { id: u32, timestamp: u32 }, KeepAliveResponse { id: u32, timestamp: u32 },
} }
#[binrw]
#[brw(repr = u8)]
#[derive(Debug)]
enum CompressionType {
Uncompressed = 0,
ZLib = 1,
Oodle = 2,
}
#[binrw] #[binrw]
#[derive(Debug)] #[derive(Debug)]
struct PacketHeader { struct PacketHeader {
@ -71,9 +80,7 @@ struct PacketHeader {
connection_type: ConnectionType, connection_type: ConnectionType,
segment_count: u16, segment_count: u16,
unk3: u8, unk3: u8,
#[br(map = read_bool_from::<u8>)] compressed: CompressionType,
#[bw(map = write_bool_as::<u8>)]
compressed: bool,
unk4: u16, unk4: u16,
unk5: u32, // iolite says the size after oodle decompression unk5: u32, // iolite says the size after oodle decompression
} }
@ -108,6 +115,7 @@ impl PacketSegment {
#[brw(import(encryption_key: Option<&[u8]>))] #[brw(import(encryption_key: Option<&[u8]>))]
#[derive(Debug)] #[derive(Debug)]
struct Packet { struct Packet {
#[br(dbg)]
header: PacketHeader, header: PacketHeader,
#[br(count = header.segment_count, args { inner: (encryption_key,) })] #[br(count = header.segment_count, args { inner: (encryption_key,) })]
#[bw(args(encryption_key))] #[bw(args(encryption_key))]
@ -144,7 +152,7 @@ pub async fn send_packet(
connection_type: ConnectionType::Lobby, connection_type: ConnectionType::Lobby,
segment_count: segments.len() as u16, segment_count: segments.len() as u16,
unk3: 0, unk3: 0,
compressed: false, compressed: CompressionType::Uncompressed,
unk4: 0, unk4: 0,
unk5: 0, unk5: 0,
}; };