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:
parent
7b0c41a478
commit
68d87c3a42
2 changed files with 300 additions and 20 deletions
|
@ -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(
|
||||||
.await;
|
&mut write,
|
||||||
}*/
|
&[response_packet],
|
||||||
|
&mut state,
|
||||||
|
CompressionType::Oodle,
|
||||||
|
)
|
||||||
|
.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!"
|
||||||
|
|
170
src/ipc.rs
170
src/ipc.rs
|
@ -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!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue