mirror of
https://github.com/redstrate/Kawari.git
synced 2025-04-20 06:37:45 +00:00
Add packets related to playing events and scenes
This commit is contained in:
parent
cb740a2a93
commit
bcbe62af06
12 changed files with 257 additions and 5 deletions
|
@ -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": [
|
||||
|
|
BIN
resources/tests/event_play.bin
Normal file
BIN
resources/tests/event_play.bin
Normal file
Binary file not shown.
BIN
resources/tests/event_start.bin
Normal file
BIN
resources/tests/event_start.bin
Normal file
Binary file not shown.
|
@ -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 } => {
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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!"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
57
src/world/ipc/event_play.rs
Normal file
57
src/world/ipc/event_play.rs
Normal 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);
|
||||
}
|
||||
}
|
49
src/world/ipc/event_start.rs
Normal file
49
src/world/ipc/event_start.rs
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue