1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-04-24 08:07:45 +00:00

Add the remaining IPC opcodes to allow you to join a world

This commit is contained in:
Joshua Goins 2025-03-12 00:32:37 -04:00
parent 7b0c41a478
commit 68d87c3a42
2 changed files with 300 additions and 20 deletions

View file

@ -1,6 +1,6 @@
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use kawari::ipc::{ActorControlType, IPCOpCode, IPCSegment, IPCStructData, Position}; use kawari::ipc::{ActorControlType, IPCOpCode, IPCSegment, IPCStructData, Position, StatusEffect};
use kawari::oodle::FFXIVOodle; use kawari::oodle::FFXIVOodle;
use kawari::packet::{ use kawari::packet::{
CompressionType, PacketSegment, SegmentType, State, parse_packet, send_keep_alive, send_packet, CompressionType, PacketSegment, SegmentType, State, parse_packet, send_keep_alive, send_packet,
@ -38,6 +38,15 @@ async fn main() {
println!("recieved {n} bytes..."); println!("recieved {n} bytes...");
let (segments, connection_type) = parse_packet(&buf[..n], &mut state).await; let (segments, connection_type) = parse_packet(&buf[..n], &mut state).await;
for segment in &segments { for segment in &segments {
let timestamp_secs = || {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Failed to get UNIX timestamp!")
.as_secs()
.try_into()
.unwrap()
};
match &segment.segment_type { match &segment.segment_type {
SegmentType::InitializeSession { player_id } => { SegmentType::InitializeSession { player_id } => {
state.player_id = Some(*player_id); state.player_id = Some(*player_id);
@ -147,15 +156,6 @@ async fn main() {
"Client is now requesting zone information. Sending!" "Client is now requesting zone information. Sending!"
); );
let timestamp_secs = || {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Failed to get UNIX timestamp!")
.as_secs()
.try_into()
.unwrap()
};
// IPC Init(?) // IPC Init(?)
{ {
let ipc = IPCSegment { let ipc = IPCSegment {
@ -502,19 +502,97 @@ async fn main() {
) )
.await; .await;
} }
}
IPCStructData::FinishLoading { .. } => {
tracing::info!(
"Client has finished loading... spawning in!"
);
// ????? // send player spawn
/*{ {
let ipc = IPCSegment { let ipc = IPCSegment {
unk1: 0, unk1: 0,
unk2: 0, unk2: 0,
op_code: IPCOpCode::InitRequest, op_code: IPCOpCode::PlayerSpawn,
server_id: 0, server_id: 0,
timestamp: timestamp_secs(), timestamp: timestamp_secs(),
data: IPCStructData::InitResponse { data: IPCStructData::PlayerSpawn {
unk1: 0, title: 0,
character_id: state.player_id.unwrap(), u1b: 0,
unk2: 0, current_world_id: 0,
home_world_id: 0,
gm_rank: 0,
u3c: 0,
u4: 0,
online_status: 0,
pose: 0,
u5a: 0,
u5b: 0,
u5c: 0,
target_id: 0,
u6: 0,
u7: 0,
main_weapon_model: 0,
sec_weapon_model: 0,
craft_tool_model: 0,
u14: 0,
u15: 0,
b_npc_base: 0,
b_npc_name: 0,
u18: 0,
u19: 0,
director_id: 0,
owner_id: 0,
u22: 0,
padding4: [0; 16],
hp_max: 0,
hp_curr: 0,
display_flags: 0,
fate_id: 0,
mp_curr: 0,
mp_max: 0,
unk: 0,
model_chara: 0,
rotation: 0,
current_mount: 0,
active_minion: 0,
u23: 0,
u24: 0,
u25: 0,
u26: 0,
spawn_index: 0,
state: 0,
persistent_emote: 0,
model_type: 0,
subtype: 0,
voice: 0,
enemy_type: 0,
unk27: 0,
level: 0,
class_job: 0,
unk28: 0,
unk29: 0,
unk30: 0,
mount_head: 0,
mount_body: 0,
mount_feet: 0,
mount_color: 0,
scale: 0,
element_data: [0; 6],
padding2: [0; 12],
effect: [StatusEffect::default(); 30],
pos: Position {
x: 0.0,
y: 0.0,
z: 0.0,
},
models: [0; 10],
unknown6_58: [0; 10],
padding3: [0; 7],
name: [0; 32],
look: [0; 26],
fc_tag: [0; 6],
padding: [0; 26],
}, },
}; };
@ -523,9 +601,41 @@ async fn main() {
target_actor: state.player_id.unwrap(), target_actor: state.player_id.unwrap(),
segment_type: SegmentType::Ipc { data: ipc }, segment_type: SegmentType::Ipc { data: ipc },
}; };
send_packet(&mut write, &[response_packet], &mut state, CompressionType::Oodle) send_packet(
&mut write,
&[response_packet],
&mut state,
CompressionType::Oodle,
)
.await; .await;
}*/ }
}
IPCStructData::Unk1 { .. } => {
tracing::info!("Recieved Unk1!");
}
IPCStructData::Unk2 { .. } => {
tracing::info!("Recieved Unk2!");
}
IPCStructData::Unk3 { .. } => {
tracing::info!("Recieved Unk3!");
}
IPCStructData::Unk4 { .. } => {
tracing::info!("Recieved Unk4!");
}
IPCStructData::SetSearchInfoHandler { .. } => {
tracing::info!("Recieved SetSearchInfoHandler!");
}
IPCStructData::Unk5 { .. } => {
tracing::info!("Recieved Unk5!");
}
IPCStructData::Unk6 { .. } => {
tracing::info!("Recieved Unk6!");
}
IPCStructData::Unk7 { .. } => {
tracing::info!("Recieved Unk7!");
}
IPCStructData::UpdatePositionHandler { .. } => {
tracing::info!("Recieved UpdatePositionHandler!");
} }
_ => panic!( _ => panic!(
"The server is recieving a IPC response or unknown packet!" "The server is recieving a IPC response or unknown packet!"

View file

@ -43,6 +43,27 @@ pub enum IPCOpCode {
PlayerSetup = 0x006B, PlayerSetup = 0x006B,
// Sent by the server to setup class info // Sent by the server to setup class info
UpdateClassInfo = 0x006A, UpdateClassInfo = 0x006A,
// Sent by the client when they're done loading and they need to be spawned in
FinishLoading = 0x397, // TODO: assumed
// Sent by the server to spawn the player in
PlayerSpawn = 0x1AB,
// FIXME: 32 bytes of something from the client, not sure what yet
Unk1 = 0x37C,
// FIXME: 16 bytes of something from the client, not sure what yet
Unk2 = 0x1A1,
// FIXME: 8 bytes of something from the client, not sure what yet
Unk3 = 0x326,
// FIXME: 8 bytes of something from the client, not sure what yet
Unk4 = 0x143,
SetSearchInfoHandler = 0x3B2, // TODO: assumed,
// FIXME: 8 bytes of something from the client, not sure what yet
Unk5 = 0x2D0,
// FIXME: 8 bytes of something from the client, not sure what yet
Unk6 = 0x2E5,
// FIXME: 32 bytes of something from the client, not sure what yet
Unk7 = 0x2B5,
UpdatePositionHandler = 0x249, // TODO: assumed
} }
#[binrw] #[binrw]
@ -141,6 +162,15 @@ pub enum ActorControlType {
SetCharaGearParamUI = 0x260, SetCharaGearParamUI = 0x260,
} }
#[binrw]
#[derive(Debug, Clone, Copy, Default)]
pub struct StatusEffect {
effect_id: u16,
param: u16,
duration: f32,
source_actor_id: u32,
}
#[binrw] #[binrw]
#[br(import(magic: &IPCOpCode))] #[br(import(magic: &IPCOpCode))]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -197,6 +227,56 @@ pub enum IPCStructData {
#[br(dbg)] #[br(dbg)]
unk: [u8; 105], unk: [u8; 105],
}, },
#[br(pre_assert(*magic == IPCOpCode::FinishLoading))]
FinishLoading {
// TODO: full of possibly interesting information
unk: [u8; 72],
},
#[br(pre_assert(*magic == IPCOpCode::Unk1))]
Unk1 {
// TODO: full of possibly interesting information
unk: [u8; 32],
},
#[br(pre_assert(*magic == IPCOpCode::Unk2))]
Unk2 {
// TODO: full of possibly interesting information
unk: [u8; 16],
},
#[br(pre_assert(*magic == IPCOpCode::Unk3))]
Unk3 {
// TODO: full of possibly interesting information
unk: [u8; 8],
},
#[br(pre_assert(*magic == IPCOpCode::Unk4))]
Unk4 {
// TODO: full of possibly interesting information
unk: [u8; 8],
},
#[br(pre_assert(*magic == IPCOpCode::SetSearchInfoHandler))]
SetSearchInfoHandler {
// TODO: full of possibly interesting information
unk: [u8; 8],
},
#[br(pre_assert(*magic == IPCOpCode::Unk5))]
Unk5 {
// TODO: full of possibly interesting information
unk: [u8; 8],
},
#[br(pre_assert(*magic == IPCOpCode::Unk6))]
Unk6 {
// TODO: full of possibly interesting information
unk: [u8; 8],
},
#[br(pre_assert(*magic == IPCOpCode::Unk7))]
Unk7 {
// TODO: full of possibly interesting information
unk: [u8; 32],
},
#[br(pre_assert(*magic == IPCOpCode::UpdatePositionHandler))]
UpdatePositionHandler {
// TODO: full of possibly interesting information
unk: [u8; 24],
},
// Server->Client IPC // Server->Client IPC
#[br(pre_assert(false))] #[br(pre_assert(false))]
@ -488,6 +568,85 @@ pub enum IPCStructData {
class_level: u16, class_level: u16,
role_actions: [u32; 10], role_actions: [u32; 10],
}, },
#[br(pre_assert(false))]
PlayerSpawn {
title: u16,
u1b: u16,
current_world_id: u16,
home_world_id: u16,
gm_rank: u8,
u3c: u8,
u4: u8,
online_status: u8,
pose: u8,
u5a: u8,
u5b: u8,
u5c: u8,
target_id: u64,
u6: u32,
u7: u32,
main_weapon_model: u64,
sec_weapon_model: u64,
craft_tool_model: u64,
u14: u32,
u15: u32,
b_npc_base: u32,
b_npc_name: u32,
u18: u32,
u19: u32,
director_id: u32,
owner_id: u32,
u22: u32,
padding4: [u8; 16],
hp_max: u32,
hp_curr: u32,
display_flags: u32,
fate_id: u16,
mp_curr: u16,
mp_max: u16,
unk: u16,
model_chara: u16,
rotation: u16,
current_mount: u16,
active_minion: u16,
u23: u8,
u24: u8,
u25: u8,
u26: u8,
spawn_index: u8,
state: u8,
persistent_emote: u8,
model_type: u8,
subtype: u8,
voice: u8,
enemy_type: u8,
unk27: u8,
level: u8,
class_job: u8,
unk28: u8,
unk29: u8,
unk30: u8,
mount_head: u8,
mount_body: u8,
mount_feet: u8,
mount_color: u8,
scale: u8,
element_data: [u8; 6],
padding2: [u8; 12],
effect: [StatusEffect; 30],
pos: Position,
models: [u32; 10],
unknown6_58: [u8; 10],
padding3: [u8; 7],
name: [u8; 32],
look: [u8; 26],
fc_tag: [u8; 6],
padding: [u8; 26],
},
} }
#[binrw] #[binrw]
@ -529,6 +688,17 @@ impl IPCSegment {
IPCStructData::PlayerStats { .. } => 228, IPCStructData::PlayerStats { .. } => 228,
IPCStructData::PlayerSetup { .. } => 2544, IPCStructData::PlayerSetup { .. } => 2544,
IPCStructData::UpdateClassInfo { .. } => 48, IPCStructData::UpdateClassInfo { .. } => 48,
IPCStructData::FinishLoading { .. } => todo!(),
IPCStructData::PlayerSpawn { .. } => 656,
IPCStructData::Unk1 { .. } => todo!(),
IPCStructData::Unk2 { .. } => todo!(),
IPCStructData::Unk3 { .. } => todo!(),
IPCStructData::Unk4 { .. } => todo!(),
IPCStructData::SetSearchInfoHandler { .. } => todo!(),
IPCStructData::Unk5 { .. } => todo!(),
IPCStructData::Unk6 { .. } => todo!(),
IPCStructData::Unk7 { .. } => todo!(),
IPCStructData::UpdatePositionHandler { .. } => todo!(),
} }
} }
} }