mirror of
https://github.com/redstrate/Kawari.git
synced 2025-04-24 08:07:45 +00:00
Begin sending lobby information
This now puts the client onto the real lobby screen, not sure how much actually works yet.
This commit is contained in:
parent
00c5f4a10e
commit
1f43318add
2 changed files with 273 additions and 3 deletions
110
src/ipc.rs
110
src/ipc.rs
|
@ -6,10 +6,18 @@ use crate::common::{read_string, write_string};
|
|||
#[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 after exchanging encryption information with the lobby server.
|
||||
ClientVersionInfo = 0x5,
|
||||
/// Sent by the server to inform the client of service accounts.
|
||||
/// 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 inform the client of their servers.
|
||||
LobbyServerList = 0x15,
|
||||
/// Sent by the server to inform the client of their retainers.
|
||||
LobbyRetainerList = 0x17,
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
|
@ -25,6 +33,57 @@ pub struct ServiceAccount {
|
|||
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,
|
||||
// TODO: lol? why is there server_id1?
|
||||
pub server_id: u16,
|
||||
pub server_id1: u16,
|
||||
pub unk1: [u8; 16],
|
||||
#[bw(pad_size_to = 16)]
|
||||
#[br(count = 16)]
|
||||
#[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 character_server_name: String,
|
||||
#[bw(pad_size_to = 32)]
|
||||
#[br(count = 32)]
|
||||
#[br(map = read_string)]
|
||||
#[bw(map = write_string)]
|
||||
pub character_server_name1: 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]
|
||||
#[br(import(magic: &IPCOpCode))]
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -45,6 +104,12 @@ pub enum IPCStructData {
|
|||
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?
|
||||
},
|
||||
|
||||
// Server->Client IPC
|
||||
LobbyServiceAccountList {
|
||||
|
@ -57,6 +122,45 @@ pub enum IPCStructData {
|
|||
#[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,
|
||||
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,
|
||||
max_characters_on_world: u32,
|
||||
unk8: u16,
|
||||
#[brw(pad_after = 12)]
|
||||
entitled_expansion: u32,
|
||||
#[br(count = 2)]
|
||||
characters: Vec<CharacterDetails>,
|
||||
},
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
|
@ -80,6 +184,10 @@ impl IPCSegment {
|
|||
+ match self.data {
|
||||
IPCStructData::ClientVersionInfo { .. } => todo!(),
|
||||
IPCStructData::LobbyServiceAccountList { .. } => 24 + (8 * 80),
|
||||
IPCStructData::RequestCharacterList { .. } => todo!(),
|
||||
IPCStructData::LobbyServerList { .. } => 24 + (6 * 84),
|
||||
IPCStructData::LobbyRetainerList { .. } => 210,
|
||||
IPCStructData::LobbyCharacterList { .. } => 82 + (2 * 1168),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
166
src/packet.rs
166
src/packet.rs
|
@ -1,4 +1,5 @@
|
|||
use std::{
|
||||
cmp::{max, min},
|
||||
fs::write,
|
||||
io::Cursor,
|
||||
time::{SystemTime, UNIX_EPOCH},
|
||||
|
@ -13,7 +14,7 @@ use tokio::{
|
|||
use crate::{
|
||||
common::{read_bool_from, read_string, write_bool_as},
|
||||
encryption::{blowfish_encode, decrypt, encrypt, generate_encryption_key},
|
||||
ipc::{IPCOpCode, IPCSegment, IPCStructData, ServiceAccount},
|
||||
ipc::{CharacterDetails, IPCOpCode, IPCSegment, IPCStructData, Server, ServiceAccount},
|
||||
};
|
||||
|
||||
#[binrw]
|
||||
|
@ -236,7 +237,8 @@ pub async fn parse_packet(socket: &mut WriteHalf<TcpStream>, data: &[u8], state:
|
|||
unk1: 0,
|
||||
index: 0,
|
||||
name: "FINAL FANTASY XIV".to_string(),
|
||||
}].to_vec();
|
||||
}]
|
||||
.to_vec();
|
||||
// add any empty boys
|
||||
service_accounts.resize(8, ServiceAccount::default());
|
||||
|
||||
|
@ -264,6 +266,166 @@ pub async fn parse_packet(socket: &mut WriteHalf<TcpStream>, data: &[u8], state:
|
|||
};
|
||||
send_packet(socket, &[response_packet], state).await;
|
||||
}
|
||||
IPCStructData::RequestCharacterList { sequence } => {
|
||||
tracing::info!("Client is requesting character list...");
|
||||
|
||||
let timestamp: u32 = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Failed to get UNIX timestamp!")
|
||||
.as_secs()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let mut packets = Vec::new();
|
||||
// send them the character list
|
||||
{
|
||||
let mut servers = [Server {
|
||||
id: 21,
|
||||
index: 0,
|
||||
flags: 0,
|
||||
icon: 0,
|
||||
name: "KAWARI".to_string(),
|
||||
}]
|
||||
.to_vec();
|
||||
// add any empty boys
|
||||
servers.resize(6, Server::default());
|
||||
|
||||
let lobby_server_list = IPCStructData::LobbyServerList {
|
||||
sequence: 0,
|
||||
unk1: 1,
|
||||
offset: 0,
|
||||
num_servers: 1,
|
||||
servers,
|
||||
};
|
||||
|
||||
let ipc = IPCSegment {
|
||||
unk1: 0,
|
||||
unk2: 0,
|
||||
op_code: IPCOpCode::LobbyServerList,
|
||||
server_id: 0,
|
||||
timestamp,
|
||||
data: lobby_server_list,
|
||||
};
|
||||
|
||||
let response_packet = PacketSegment {
|
||||
source_actor: 0,
|
||||
target_actor: 0,
|
||||
segment_type: SegmentType::IPC { data: ipc },
|
||||
};
|
||||
packets.push(response_packet);
|
||||
}
|
||||
|
||||
// send them the retainer list
|
||||
{
|
||||
let lobby_retainer_list =
|
||||
IPCStructData::LobbyRetainerList { unk1: 1 };
|
||||
|
||||
let ipc = IPCSegment {
|
||||
unk1: 0,
|
||||
unk2: 0,
|
||||
op_code: IPCOpCode::LobbyRetainerList,
|
||||
server_id: 0,
|
||||
timestamp,
|
||||
data: lobby_retainer_list,
|
||||
};
|
||||
|
||||
let response_packet = PacketSegment {
|
||||
source_actor: 0,
|
||||
target_actor: 0,
|
||||
segment_type: SegmentType::IPC { data: ipc },
|
||||
};
|
||||
packets.push(response_packet);
|
||||
}
|
||||
|
||||
send_packet(socket, &packets, state).await;
|
||||
|
||||
// now send them the character list
|
||||
{
|
||||
let mut characters = vec![CharacterDetails {
|
||||
id: 0,
|
||||
content_id: 11111111111111111,
|
||||
index: 0,
|
||||
server_id: 21,
|
||||
server_id1: 21,
|
||||
unk1: [0; 16],
|
||||
character_name: "test".to_string(),
|
||||
character_server_name: "test".to_string(),
|
||||
character_server_name1: "test".to_string(),
|
||||
character_detail_json: "test".to_string(),
|
||||
unk2: [0; 20],
|
||||
}];
|
||||
// add any empty boys
|
||||
characters.resize(2, CharacterDetails::default());
|
||||
|
||||
for i in 0..4 {
|
||||
let mut characters_in_packet = Vec::new();
|
||||
for _ in 0..min(characters.len(), 2) {
|
||||
characters_in_packet.push(characters.swap_remove(0));
|
||||
}
|
||||
|
||||
let lobby_character_list = if i == 3 {
|
||||
// On the last packet, add the account-wide information
|
||||
IPCStructData::LobbyCharacterList {
|
||||
sequence: *sequence,
|
||||
counter: (i * 4) + 1, // TODO: why the + 1 here?
|
||||
num_in_packet: characters_in_packet.len() as u8,
|
||||
unk1: 0,
|
||||
unk2: 0,
|
||||
unk3: 0,
|
||||
unk4: 128,
|
||||
unk5: [0; 7],
|
||||
unk6: 0,
|
||||
veteran_rank: 0,
|
||||
unk7: 0,
|
||||
days_subscribed: 0,
|
||||
remaining_days: 0,
|
||||
days_to_next_rank: 0,
|
||||
max_characters_on_world: 20,
|
||||
unk8: 8,
|
||||
entitled_expansion: 4,
|
||||
characters: characters_in_packet,
|
||||
}
|
||||
} else {
|
||||
IPCStructData::LobbyCharacterList {
|
||||
sequence: *sequence,
|
||||
counter: i * 4,
|
||||
num_in_packet: characters_in_packet.len() as u8,
|
||||
unk1: 0,
|
||||
unk2: 0,
|
||||
unk3: 0,
|
||||
unk4: 0,
|
||||
unk5: [0; 7],
|
||||
unk6: 0,
|
||||
veteran_rank: 0,
|
||||
unk7: 0,
|
||||
days_subscribed: 0,
|
||||
remaining_days: 0,
|
||||
days_to_next_rank: 0,
|
||||
max_characters_on_world: 0,
|
||||
unk8: 0,
|
||||
entitled_expansion: 0,
|
||||
characters: characters_in_packet,
|
||||
}
|
||||
};
|
||||
|
||||
let ipc = IPCSegment {
|
||||
unk1: 0,
|
||||
unk2: 0,
|
||||
op_code: IPCOpCode::LobbyCharacterList,
|
||||
server_id: 0,
|
||||
timestamp,
|
||||
data: lobby_character_list,
|
||||
};
|
||||
|
||||
let response_packet = PacketSegment {
|
||||
source_actor: 0,
|
||||
target_actor: 0,
|
||||
segment_type: SegmentType::IPC { data: ipc },
|
||||
};
|
||||
send_packet(socket, &[response_packet], state).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
panic!("The server is recieving a IPC response packet!")
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue