1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-04-19 22:36:49 +00:00

Add packets related to playing events and scenes

This commit is contained in:
Joshua Goins 2025-03-28 20:19:17 -04:00
parent cb740a2a93
commit bcbe62af06
12 changed files with 257 additions and 5 deletions

View file

@ -129,6 +129,16 @@
"name": "ContainerInfo",
"opcode": 566,
"size": 16
},
{
"name": "EventPlay",
"opcode": 991,
"size": 40
},
{
"name": "EventStart",
"opcode": 955,
"size": 24
}
],
"ClientZoneIpcType": [
@ -231,6 +241,11 @@
"name": "Unk18",
"opcode": 221,
"size": 8
},
{
"name": "EventRelatedUnk",
"opcode": 861,
"size": 16
}
],
"ServerLobbyIpcType": [

Binary file not shown.

Binary file not shown.

View file

@ -745,6 +745,16 @@ async fn main() {
ClientZoneIpcData::Unk18 { .. } => {
tracing::info!("Recieved Unk18!");
}
ClientZoneIpcData::EventRelatedUnk {
unk1,
unk2,
unk3,
unk4,
} => {
tracing::info!(
"Recieved EventRelatedUnk! {unk1} {unk2} {unk3} {unk4}"
);
}
}
}
SegmentType::KeepAlive { id, timestamp } => {

View file

@ -20,7 +20,7 @@ pub use position::Position;
#[binrw]
#[brw(little)]
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ObjectId(pub u32);
impl Default for ObjectId {
@ -32,7 +32,7 @@ impl Default for ObjectId {
// See https://github.com/aers/FFXIVClientStructs/blob/main/FFXIVClientStructs/FFXIV/Client/Game/Object/GameObject.cs#L158
#[binrw]
#[brw(little)]
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ObjectTypeId {
pub object_id: ObjectId,
#[brw(pad_after = 3)]

View file

@ -46,6 +46,8 @@ pub(crate) fn decompress<T: ReadWriteIpcSegment>(
let mut cursor = Cursor::new(&data);
std::fs::write("decompressed.bin", &data).unwrap();
for _ in 0..header.segment_count {
let current_position = cursor.position();
segments.push(PacketSegment::read_options(

View file

@ -4,8 +4,9 @@ use crate::{
opcodes::ServerZoneIpcType,
packet::{PacketSegment, SegmentType},
world::ipc::{
ActorControl, ActorControlCategory, BattleNpcSubKind, CommonSpawn, DisplayFlag, NpcSpawn,
ObjectKind, PlayerSpawn, PlayerSubKind, ServerZoneIpcData, ServerZoneIpcSegment,
ActorControl, ActorControlCategory, BattleNpcSubKind, CommonSpawn, DisplayFlag, EventPlay,
EventStart, NpcSpawn, ObjectKind, OnlineStatus, PlayerSpawn, PlayerSubKind,
ServerZoneIpcData, ServerZoneIpcSegment,
},
};
@ -265,6 +266,91 @@ impl ChatHandler {
.await;
}
}
"!playscene" => {
// only works in ul'dah opening
// Load the game script for this event on the client
{
let ipc = ServerZoneIpcSegment {
unk1: 20,
unk2: 0,
op_code: ServerZoneIpcType::EventStart,
server_id: 0,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::EventStart(EventStart {
target_id: ObjectTypeId {
object_id: ObjectId(connection.player_data.actor_id),
object_type: 0,
},
event_type: 15,
event_id: 0x130003,
flags: 0,
event_arg: 182,
}),
};
connection
.send_segment(PacketSegment {
source_actor: connection.player_data.actor_id,
target_actor: connection.player_data.actor_id,
segment_type: SegmentType::Ipc { data: ipc },
})
.await;
}
// set our status icon to viewing cutscene
{
let ipc = ServerZoneIpcSegment {
unk1: 20,
unk2: 0,
op_code: ServerZoneIpcType::ActorControl,
server_id: 0,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::ActorControl(ActorControl {
category: ActorControlCategory::SetStatusIcon {
icon: OnlineStatus::ViewingCutscene,
},
}),
};
connection
.send_segment(PacketSegment {
source_actor: connection.player_data.actor_id,
target_actor: connection.player_data.actor_id,
segment_type: SegmentType::Ipc { data: ipc },
})
.await;
}
// play the scene, bart
{
let ipc = ServerZoneIpcSegment {
unk1: 20,
unk2: 0,
op_code: ServerZoneIpcType::EventPlay,
server_id: 0,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::EventPlay(EventPlay {
actor_id: ObjectTypeId {
object_id: ObjectId(connection.player_data.actor_id),
object_type: 0,
},
event_id: 0x130003,
scene: 1,
scene_flags: 4959237,
..Default::default()
}),
};
connection
.send_segment(PacketSegment {
source_actor: connection.player_data.actor_id,
target_actor: connection.player_data.actor_id,
segment_type: SegmentType::Ipc { data: ipc },
})
.await;
}
}
_ => tracing::info!("Unrecognized debug command!"),
}
}

View file

@ -1,5 +1,7 @@
use binrw::binrw;
use super::OnlineStatus;
// See https://github.com/awgil/ffxiv_reverse/blob/f35b6226c1478234ca2b7149f82d251cffca2f56/vnetlog/vnetlog/ServerIPC.cs#L266 for a REALLY useful list of known values
#[binrw]
#[derive(Debug, Eq, PartialEq, Clone)]
@ -21,6 +23,11 @@ pub enum ActorControlCategory {
unk1: u32,
unk2: u32,
},
#[brw(magic = 0x01F8u16)]
SetStatusIcon {
#[brw(pad_before = 2)]
icon: OnlineStatus,
},
}
#[binrw]

View file

@ -86,7 +86,7 @@ pub enum CharacterMode {
#[binrw]
#[brw(little)]
#[brw(repr = u8)]
#[derive(Debug, Clone, Default, PartialEq)]
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub enum OnlineStatus {
Offline = 0x0,
GameQA = 1,
@ -94,6 +94,7 @@ pub enum OnlineStatus {
GameMasterBlue = 3,
EventParticipant = 4,
NewAdventurer = 32, // TODO: This is actually a flag!
ViewingCutscene = 15,
#[default]
Online = 47,
}

View file

@ -0,0 +1,57 @@
use binrw::binrw;
use crate::common::ObjectTypeId;
#[binrw]
#[brw(little)]
#[derive(Debug, Clone, Default)]
pub struct EventPlay {
pub actor_id: ObjectTypeId,
pub event_id: u32,
pub scene: u16,
#[brw(pad_before = 2)] // FIXME: um, i don't think this is empty!!
pub scene_flags: u32,
pub unk1: u32,
pub unk2: u8,
#[brw(pad_before = 3)]
pub unk3: u32,
pub unk4: u32,
pub unk5: u32,
}
#[cfg(test)]
mod tests {
use std::{fs::read, io::Cursor, path::PathBuf};
use binrw::BinRead;
use crate::common::ObjectId;
use super::*;
#[test]
fn read_intro_event_start() {
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
d.push("resources/tests/event_play.bin");
let buffer = read(d).unwrap();
let mut buffer = Cursor::new(&buffer);
let event_play = EventPlay::read_le(&mut buffer).unwrap();
assert_eq!(
event_play.actor_id,
ObjectTypeId {
object_id: ObjectId(277124129),
object_type: 0
}
);
assert_eq!(event_play.event_id, 0x130003); // aether intro
assert_eq!(event_play.scene, 0);
assert_eq!(event_play.scene_flags, 4959237);
assert_eq!(event_play.unk1, 0);
assert_eq!(event_play.unk2, 1);
assert_eq!(event_play.unk3, 0);
assert_eq!(event_play.unk4, 0);
assert_eq!(event_play.unk5, 0);
}
}

View file

@ -0,0 +1,49 @@
use binrw::binrw;
use crate::common::ObjectTypeId;
#[binrw]
#[brw(little)]
#[derive(Debug, Clone, Default)]
pub struct EventStart {
pub target_id: ObjectTypeId,
pub event_id: u32,
pub event_type: u8,
pub flags: u8,
#[brw(pad_before = 2)]
#[brw(pad_after = 4)]
pub event_arg: u32,
}
#[cfg(test)]
mod tests {
use std::{fs::read, io::Cursor, path::PathBuf};
use binrw::BinRead;
use crate::common::ObjectId;
use super::*;
#[test]
fn read_intro_event_start() {
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
d.push("resources/tests/event_start.bin");
let buffer = read(d).unwrap();
let mut buffer = Cursor::new(&buffer);
let event_start = EventStart::read_le(&mut buffer).unwrap();
assert_eq!(
event_start.target_id,
ObjectTypeId {
object_id: ObjectId(277124129),
object_type: 0
}
);
assert_eq!(event_start.event_id, 0x130003); // aether intro
assert_eq!(event_start.event_type, 15);
assert_eq!(event_start.flags, 0);
assert_eq!(event_start.event_arg, 182);
}
}

View file

@ -53,6 +53,12 @@ pub use container_info::{ContainerInfo, ContainerType};
mod item_info;
pub use item_info::ItemInfo;
mod event_play;
pub use event_play::EventPlay;
mod event_start;
pub use event_start::EventStart;
use crate::common::Position;
use crate::common::read_string;
use crate::common::write_string;
@ -205,6 +211,10 @@ pub enum ServerZoneIpcData {
ItemInfo(ItemInfo),
/// Sent to inform the client of container status
ContainerInfo(ContainerInfo),
/// Sent to tell the client to play a scene
EventPlay(EventPlay),
/// Sent to tell the client to load a scene, but not play it
EventStart(EventStart),
}
#[binrw]
@ -324,6 +334,13 @@ pub enum ClientZoneIpcData {
Unk18 {
unk: [u8; 8], // TODO: unknown
},
#[br(pre_assert(*magic == ClientZoneIpcType::EventRelatedUnk))]
EventRelatedUnk {
unk1: u32,
unk2: u32,
unk3: u32,
unk4: u32,
},
}
#[cfg(test)]
@ -396,6 +413,14 @@ mod tests {
ServerZoneIpcType::ContainerInfo,
ServerZoneIpcData::ContainerInfo(ContainerInfo::default()),
),
(
ServerZoneIpcType::EventPlay,
ServerZoneIpcData::EventPlay(EventPlay::default()),
),
(
ServerZoneIpcType::EventStart,
ServerZoneIpcData::EventStart(EventStart::default()),
),
];
for (opcode, data) in &ipc_types {