2025-03-16 17:43:29 -04:00
mod chat_message ;
use binrw ::binrw ;
pub use chat_message ::ChatMessage ;
mod social_list ;
pub use social_list ::PlayerEntry ;
pub use social_list ::SocialList ;
pub use social_list ::SocialListRequest ;
pub use social_list ::SocialListRequestType ;
mod player_spawn ;
pub use player_spawn ::PlayerSpawn ;
mod status_effect ;
pub use status_effect ::StatusEffect ;
mod update_class_info ;
pub use update_class_info ::UpdateClassInfo ;
mod player_setup ;
2025-05-02 23:24:31 -04:00
pub use player_setup ::PlayerStatus ;
2025-03-16 17:43:29 -04:00
mod player_stats ;
pub use player_stats ::PlayerStats ;
2025-03-18 23:30:59 -04:00
mod actor_control ;
2025-05-08 22:53:36 -04:00
pub use actor_control ::{ ActorControl , ActorControlCategory , ActorControlSelf , ActorControlTarget } ;
2025-03-16 17:43:29 -04:00
mod init_zone ;
pub use init_zone ::InitZone ;
2025-03-18 22:13:28 -04:00
mod npc_spawn ;
pub use npc_spawn ::NpcSpawn ;
mod common_spawn ;
2025-03-23 12:16:15 -04:00
pub use common_spawn ::{
2025-03-23 12:54:04 -04:00
BattleNpcSubKind , CharacterMode , CommonSpawn , DisplayFlag , GameMasterRank , ObjectKind ,
OnlineStatus , PlayerSubKind ,
2025-03-23 12:16:15 -04:00
} ;
2025-03-18 22:13:28 -04:00
2025-03-18 23:30:59 -04:00
mod status_effect_list ;
pub use status_effect_list ::StatusEffectList ;
2025-03-18 23:48:00 -04:00
mod weather_change ;
pub use weather_change ::WeatherChange ;
2025-03-19 00:28:47 -04:00
mod action_request ;
pub use action_request ::ActionRequest ;
2025-03-23 16:45:52 -04:00
mod container_info ;
2025-05-02 16:15:54 -04:00
pub use container_info ::ContainerInfo ;
2025-03-23 16:45:52 -04:00
mod item_info ;
pub use item_info ::ItemInfo ;
2025-05-02 23:24:31 -04:00
mod event_scene ;
pub use event_scene ::EventScene ;
2025-03-28 20:19:17 -04:00
mod event_start ;
pub use event_start ::EventStart ;
2025-03-29 14:14:03 -04:00
mod action_result ;
2025-04-18 13:11:29 -04:00
pub use action_result ::{
ActionEffect , ActionResult , DamageElement , DamageKind , DamageType , EffectKind ,
} ;
2025-03-29 14:14:03 -04:00
2025-05-02 23:24:31 -04:00
mod r #move ;
pub use r#move ::Move ;
2025-03-30 17:49:45 -04:00
2025-05-02 23:24:31 -04:00
mod warp ;
pub use warp ::Warp ;
2025-03-30 17:49:45 -04:00
2025-05-02 23:24:31 -04:00
mod item_operation ;
pub use item_operation ::ItemOperation ;
2025-03-31 20:05:37 -04:00
2025-03-31 21:49:12 -04:00
mod equip ;
pub use equip ::Equip ;
2025-05-08 22:53:36 -04:00
mod client_trigger ;
pub use client_trigger ::{ ClientTrigger , ClientTriggerCommand } ;
2025-06-24 19:15:25 -04:00
mod currency_info ;
pub use currency_info ::CurrencyInfo ;
2025-06-25 21:30:14 -04:00
mod config ;
pub use config ::Config ;
2025-06-28 15:57:45 -04:00
mod event_yield_handler ;
pub use event_yield_handler ::EventYieldHandler ;
2025-07-12 08:33:04 -04:00
use crate ::COMPLETED_QUEST_BITMASK_SIZE ;
2025-05-05 20:51:49 -04:00
use crate ::common ::ObjectTypeId ;
2025-03-22 22:01:32 -04:00
use crate ::common ::Position ;
2025-03-16 17:43:29 -04:00
use crate ::common ::read_string ;
use crate ::common ::write_string ;
2025-07-12 17:40:22 -04:00
use crate ::inventory ::{ ContainerType , ItemOperationKind } ;
2025-03-26 18:28:51 -04:00
use crate ::opcodes ::ClientZoneIpcType ;
use crate ::opcodes ::ServerZoneIpcType ;
2025-07-03 16:12:19 -04:00
use crate ::packet ::IPC_HEADER_SIZE ;
2025-03-16 17:43:29 -04:00
use crate ::packet ::IpcSegment ;
2025-03-17 17:12:40 -04:00
use crate ::packet ::ReadWriteIpcSegment ;
2025-03-16 17:43:29 -04:00
pub type ClientZoneIpcSegment = IpcSegment < ClientZoneIpcType , ClientZoneIpcData > ;
2025-03-25 18:15:41 -04:00
impl ReadWriteIpcSegment for ClientZoneIpcSegment {
fn calc_size ( & self ) -> u32 {
2025-07-03 16:12:19 -04:00
IPC_HEADER_SIZE + self . op_code . calc_size ( )
2025-03-25 18:15:41 -04:00
}
2025-06-26 20:59:46 -04:00
fn get_name ( & self ) -> & 'static str {
self . op_code . get_name ( )
}
2025-07-03 16:12:19 -04:00
fn get_opcode ( & self ) -> u16 {
self . op_code . get_opcode ( )
}
2025-03-25 18:15:41 -04:00
}
2025-03-16 17:43:29 -04:00
// TODO: make generic
impl Default for ClientZoneIpcSegment {
fn default ( ) -> Self {
Self {
unk1 : 0x14 ,
unk2 : 0 ,
op_code : ClientZoneIpcType ::InitRequest ,
2025-05-02 00:17:15 -04:00
option : 0 ,
2025-03-16 17:43:29 -04:00
timestamp : 0 ,
2025-03-25 18:15:41 -04:00
data : ClientZoneIpcData ::InitRequest { unk : [ 0 ; 120 ] } ,
2025-03-16 17:43:29 -04:00
}
}
}
pub type ServerZoneIpcSegment = IpcSegment < ServerZoneIpcType , ServerZoneIpcData > ;
2025-03-17 17:12:40 -04:00
impl ReadWriteIpcSegment for ServerZoneIpcSegment {
2025-03-16 17:43:29 -04:00
fn calc_size ( & self ) -> u32 {
2025-07-03 16:12:19 -04:00
IPC_HEADER_SIZE + self . op_code . calc_size ( )
2025-03-16 17:43:29 -04:00
}
2025-06-26 20:59:46 -04:00
fn get_name ( & self ) -> & 'static str {
self . op_code . get_name ( )
}
2025-07-03 16:12:19 -04:00
fn get_opcode ( & self ) -> u16 {
self . op_code . get_opcode ( )
}
2025-03-16 17:43:29 -04:00
}
// TODO: make generic
impl Default for ServerZoneIpcSegment {
fn default ( ) -> Self {
Self {
unk1 : 0x14 ,
unk2 : 0 ,
2025-05-01 23:34:06 -04:00
op_code : ServerZoneIpcType ::InitZone ,
2025-05-02 00:17:15 -04:00
option : 0 ,
2025-03-16 17:43:29 -04:00
timestamp : 0 ,
2025-05-01 23:34:06 -04:00
data : ServerZoneIpcData ::InitZone ( InitZone ::default ( ) ) ,
2025-03-16 17:43:29 -04:00
}
}
}
#[ binrw ]
2025-06-28 15:15:45 -04:00
#[ br(import(magic: &ServerZoneIpcType, size: &u32)) ]
2025-03-16 17:43:29 -04:00
#[ derive(Debug, Clone) ]
pub enum ServerZoneIpcData {
2025-03-26 18:28:51 -04:00
/// Sent by the server as response to ZoneInitRequest.
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::InitResponse)) ]
2025-03-16 17:43:29 -04:00
InitResponse {
unk1 : u64 ,
character_id : u32 ,
unk2 : u32 ,
} ,
2025-03-26 18:28:51 -04:00
/// Sent by the server that tells the client which zone to load
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::InitZone)) ]
2025-03-16 17:43:29 -04:00
InitZone ( InitZone ) ,
2025-03-26 18:28:51 -04:00
/// Sent by the server for... something
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::ActorControlSelf)) ]
2025-03-16 17:43:29 -04:00
ActorControlSelf ( ActorControlSelf ) ,
2025-03-26 18:28:51 -04:00
/// Sent by the server containing character stats
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::PlayerStats)) ]
2025-03-16 17:43:29 -04:00
PlayerStats ( PlayerStats ) ,
2025-03-26 18:28:51 -04:00
/// Sent by the server to setup the player on the client
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::PlayerStatus)) ]
2025-05-02 23:24:31 -04:00
PlayerStatus ( PlayerStatus ) ,
2025-03-26 18:28:51 -04:00
/// Sent by the server to setup class info
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::UpdateClassInfo)) ]
2025-03-16 17:43:29 -04:00
UpdateClassInfo ( UpdateClassInfo ) ,
2025-03-26 18:28:51 -04:00
/// Sent by the server to spawn the player in
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::PlayerSpawn)) ]
2025-03-16 17:43:29 -04:00
PlayerSpawn ( PlayerSpawn ) ,
2025-03-26 18:28:51 -04:00
/// Sent by the server to indicate the log out is complete
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::LogOutComplete)) ]
2025-03-16 17:43:29 -04:00
LogOutComplete {
// TODO: guessed
unk : [ u8 ; 8 ] ,
} ,
2025-03-26 18:28:51 -04:00
/// Sent by the server to modify the client's position
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::Warp)) ]
2025-05-02 23:24:31 -04:00
Warp ( Warp ) ,
2025-03-26 18:28:51 -04:00
/// Sent by the server when they send a chat message
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::ServerChatMessage)) ]
2025-03-16 17:43:29 -04:00
ServerChatMessage {
2025-06-25 10:05:34 -04:00
/*
* bits ( properties will apply when set , but a final base 10 value of zero defaults to chat log only ) :
* 76543210
* xxxxxSxC
* x = don ' t care / unused
* S = on - screen
* C = chat log
* all other bits are unused , therefore some possible examples are ( base 10 values follow ) :
* 1 = chat log only
* 4 = on - screen only
* 5 = both
* ref : https ://github.com/SapphireServer/Sapphire/blob/bf3368224a00c180cbb7ba413b52395eba58ec0b/src/common/Network/PacketDef/Zone/ServerZoneDef.h#L250
* /
param : u8 ,
2025-07-12 15:01:12 -04:00
#[ brw(pad_size_to = 775) ]
#[ br(count = 775) ]
2025-03-16 17:43:29 -04:00
#[ br(map = read_string) ]
#[ bw(map = write_string) ]
message : String ,
} ,
2025-03-26 18:28:51 -04:00
/// Unknown, but seems to contain information on cross-world linkshells
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::LinkShellInformation)) ]
2025-06-28 15:15:45 -04:00
LinkShellInformation { unk : [ u8 ; 456 ] } ,
2025-03-26 18:28:51 -04:00
/// Sent by the server when it wants the client to... prepare to zone?
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::PrepareZoning)) ]
2025-06-28 15:15:45 -04:00
PrepareZoning { unk : [ u32 ; 4 ] } ,
2025-03-26 18:28:51 -04:00
/// Sent by the server
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::ActorControl)) ]
2025-03-18 23:30:59 -04:00
ActorControl ( ActorControl ) ,
2025-03-26 18:28:51 -04:00
/// Sent by the server
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::Move)) ]
2025-05-02 23:24:31 -04:00
Move ( Move ) ,
2025-03-26 18:28:51 -04:00
/// Sent by the server in response to SocialListRequest
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::SocialList)) ]
2025-03-16 17:43:29 -04:00
SocialList ( SocialList ) ,
2025-03-26 18:28:51 -04:00
/// Sent by the server to spawn an NPC
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::NpcSpawn)) ]
2025-03-18 22:13:28 -04:00
NpcSpawn ( NpcSpawn ) ,
2025-03-26 18:28:51 -04:00
/// Sent by the server to update an actor's status effect list
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::StatusEffectList)) ]
2025-03-18 23:30:59 -04:00
StatusEffectList ( StatusEffectList ) ,
2025-03-26 18:28:51 -04:00
/// Sent by the server when it's time to change the weather
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::WeatherId)) ]
2025-05-01 23:20:56 -04:00
WeatherId ( WeatherChange ) ,
2025-03-26 18:28:51 -04:00
/// Sent to inform the client of an inventory item
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::UpdateItem)) ]
2025-05-01 23:20:56 -04:00
UpdateItem ( ItemInfo ) ,
2025-03-26 18:28:51 -04:00
/// Sent to inform the client of container status
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::ContainerInfo)) ]
2025-03-23 17:10:47 -04:00
ContainerInfo ( ContainerInfo ) ,
2025-03-28 20:19:17 -04:00
/// Sent to tell the client to play a scene
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::EventScene)) ]
2025-07-08 21:18:30 +00:00
#[ brw(little) ]
EventScene {
#[ brw(args { max_params: 2 } ) ]
data : EventScene ,
} ,
2025-06-28 16:05:36 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::EventScene4)) ]
2025-07-08 21:18:30 +00:00
#[ brw(little) ]
EventScene4 {
#[ brw(args { max_params: 4 } ) ]
data : EventScene ,
} ,
2025-06-28 16:05:36 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::EventScene8)) ]
2025-07-08 21:18:30 +00:00
#[ brw(little) ]
EventScene8 {
#[ brw(args { max_params: 8 } ) ]
data : EventScene ,
} ,
2025-06-28 16:05:36 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::EventScene16)) ]
2025-07-08 21:18:30 +00:00
#[ brw(little) ]
EventScene16 {
#[ brw(args { max_params: 16 } ) ]
data : EventScene ,
} ,
2025-06-28 16:05:36 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::EventScene32)) ]
2025-07-08 21:18:30 +00:00
#[ brw(little) ]
EventScene32 {
#[ brw(args { max_params: 32 } ) ]
data : EventScene ,
} ,
2025-06-28 16:05:36 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::EventScene64)) ]
2025-07-08 21:18:30 +00:00
#[ brw(little) ]
EventScene64 {
#[ brw(args { max_params: 64 } ) ]
data : EventScene ,
} ,
2025-06-28 16:05:36 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::EventScene128)) ]
2025-07-08 21:18:30 +00:00
#[ brw(little) ]
EventScene128 {
#[ brw(args { max_params: 128 } ) ]
data : EventScene ,
} ,
2025-06-28 16:05:36 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::EventScene255)) ]
2025-07-08 21:18:30 +00:00
#[ brw(little) ]
EventScene255 {
#[ brw(args { max_params: 255 } ) ]
data : EventScene ,
} ,
2025-03-28 20:19:17 -04:00
/// Sent to tell the client to load a scene, but not play it
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::EventStart)) ]
2025-03-28 20:19:17 -04:00
EventStart ( EventStart ) ,
2025-03-29 12:25:22 -04:00
/// Sent to update an actor's hp & mp values
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::UpdateHpMpTp)) ]
2025-03-29 12:25:22 -04:00
UpdateHpMpTp {
hp : u32 ,
mp : u16 ,
unk : u16 , // it's filled with... something
} ,
2025-03-29 14:14:03 -04:00
/// Sent to inform the client the consequences of their actions
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::ActionResult)) ]
2025-03-29 14:14:03 -04:00
ActionResult ( ActionResult ) ,
2025-03-31 21:49:12 -04:00
/// Sent to to the client to update their appearance
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::Equip)) ]
2025-03-31 21:49:12 -04:00
Equip ( Equip ) ,
2025-04-14 16:03:57 -04:00
/// Sent to the client to free up a spawn index
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::Delete)) ]
2025-05-01 23:20:56 -04:00
Delete {
spawn_index : u8 ,
#[ brw(pad_before = 3) ] // padding
actor_id : u32 ,
} ,
2025-05-05 20:51:49 -04:00
/// Sent to the client to stop their currently playing event.
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::EventFinish)) ]
2025-05-05 20:51:49 -04:00
EventFinish {
handler_id : u32 ,
event : u8 ,
result : u8 ,
#[ brw(pad_before = 2) ] // padding
#[ brw(pad_after = 4) ] // padding
arg : u32 ,
} ,
/// Sent after EventFinish? it un-occupies the character lol
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::Unk18)) ]
2025-05-05 20:51:49 -04:00
Unk18 {
unk : [ u8 ; 16 ] , // all zero...
} ,
2025-05-08 22:53:36 -04:00
/// Used to control target information
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::ActorControlTarget)) ]
2025-05-08 22:53:36 -04:00
ActorControlTarget ( ActorControlTarget ) ,
2025-06-24 19:15:25 -04:00
/// Used to update the player's currencies
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::CurrencyCrystalInfo)) ]
2025-06-24 19:15:25 -04:00
CurrencyCrystalInfo ( CurrencyInfo ) ,
2025-06-25 21:30:14 -04:00
/// Used to update an actor's equip display flags
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::Config)) ]
2025-06-25 21:30:14 -04:00
Config ( Config ) ,
2025-06-25 23:11:49 -04:00
/// Unknown, seen in haircut event
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::EventUnkReply)) ]
2025-06-25 23:11:49 -04:00
EventUnkReply {
event_id : u32 ,
unk1 : u16 ,
unk2 : u8 ,
#[ brw(pad_after = 8) ]
unk3 : u8 ,
} ,
2025-06-30 15:21:08 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::InventoryActionAck)) ]
InventoryActionAck {
sequence : u32 ,
2025-07-04 15:48:03 -04:00
#[ brw(pad_after = 10) ]
2025-06-30 15:21:08 -04:00
action_type : u16 ,
} ,
2025-06-26 20:59:46 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::UnkCall)) ]
2025-06-25 23:11:49 -04:00
UnkCall {
unk1 : u32 ,
#[ brw(pad_after = 26) ]
unk2 : u16 ,
} ,
2025-07-01 19:49:25 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::QuestCompleteList)) ]
QuestCompleteList {
2025-07-12 08:33:04 -04:00
#[ br(count = COMPLETED_QUEST_BITMASK_SIZE) ]
#[ bw(pad_size_to = COMPLETED_QUEST_BITMASK_SIZE) ]
completed_quests : Vec < u8 > ,
// TODO: what is in ehre?
#[ br(count = 69) ]
#[ bw(pad_size_to = 69) ]
unk2 : Vec < u8 > ,
2025-07-01 19:49:25 -04:00
} ,
2025-07-04 16:18:39 -04:00
/// Unsure the true purpose of this, but it's needed for the Unending Journey to function.
#[ br(pre_assert(*magic == ServerZoneIpcType::UnkResponse2)) ]
UnkResponse2 {
#[ brw(pad_after = 7) ]
unk1 : u8 ,
} ,
2025-07-12 17:40:22 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::InventoryTransaction)) ]
InventoryTransaction {
/// This is later reused in InventoryTransactionFinish, so it might be some sort of sequence or context id, but it's not the one sent by the client
2025-07-05 19:05:43 -04:00
unk1 : u32 ,
2025-07-12 17:40:22 -04:00
/// Same as the one sent by the client, not the one that the server responds with in InventoryActionAck!
operation_type : ItemOperationKind ,
2025-07-12 14:48:21 -04:00
#[ brw(pad_before = 3) ]
2025-07-05 19:05:43 -04:00
src_actor_id : u32 ,
src_storage_id : ContainerType ,
src_container_index : u16 ,
2025-07-12 14:48:21 -04:00
#[ brw(pad_before = 2) ]
2025-07-12 17:40:22 -04:00
/// On retail, this contains very strange values that don't make sense (in regards to stack size). It's possible this field is a different size or isn't intended for stack size.
unk2 : u32 ,
/// On retail, this contains very strange values that don't make sense (in regards to catalog id). It's possible this field is a different size or isn't intended for catalog id.
unk3 : u32 ,
2025-07-05 19:05:43 -04:00
/// This is all static as far as I can tell, across two captures and a bunch of discards these never changed
2025-07-12 17:40:22 -04:00
/// seems to always be 0
2025-07-05 19:05:43 -04:00
dst_actor_id : u32 ,
2025-07-12 17:40:22 -04:00
/// seems to always be 57344/0xE000
2025-07-05 19:05:43 -04:00
dst_storage_id : u16 ,
/// seems to always be 65535/0xFFFF
dst_container_index : u16 ,
/// seems to always be 0x0000FFFF
2025-07-12 14:48:21 -04:00
#[ brw(pad_after = 10) ]
2025-07-05 19:05:43 -04:00
dst_catalog_id : u32 ,
} ,
2025-07-12 17:40:22 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::InventoryTransactionFinish)) ]
InventoryTransactionFinish {
/// Same value as unk1 in InventoryTransaction.
2025-07-05 19:05:43 -04:00
unk1 : u32 ,
2025-07-12 17:40:22 -04:00
/// Repeated unk1 value.
2025-07-05 19:05:43 -04:00
unk2 : u32 ,
2025-07-12 17:40:22 -04:00
/// Unknown, seems to always be 0x00000090.
2025-07-05 19:05:43 -04:00
unk3 : u32 ,
2025-07-12 17:40:22 -04:00
/// Unknown, seems to always be 0x00000200.
2025-07-05 19:05:43 -04:00
unk4 : u32 ,
} ,
2025-07-12 20:53:59 -04:00
#[ br(pre_assert(*magic == ServerZoneIpcType::ContentFinderFound)) ]
ContentFinderFound {
/// 0 = Nothing happens
/// 1 = Reserving server
/// 2 = again? ^
/// 3 = duty ready
/// 4 = checking member status
/// nothing appears to happen above 5
state1 : u8 ,
classjob_id : u8 ,
unk1 : [ u8 ; 38 ] ,
} ,
#[ br(pre_assert(*magic == ServerZoneIpcType::ContentFinderFound2)) ]
ContentFinderFound2 { unk1 : [ u8 ; 8 ] } ,
2025-06-28 15:15:45 -04:00
Unknown {
#[ br(count = size - 32) ]
unk : Vec < u8 > ,
} ,
2025-03-16 17:43:29 -04:00
}
#[ binrw ]
2025-06-28 08:48:59 -04:00
#[ br(import(magic: &ClientZoneIpcType, size: &u32)) ]
2025-03-16 17:43:29 -04:00
#[ derive(Debug, Clone) ]
pub enum ClientZoneIpcData {
2025-03-26 18:28:51 -04:00
/// Sent by the client when they successfully initialize with the server, and they need several bits of information (e.g. what zone to load)
2025-03-16 17:43:29 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::InitRequest)) ]
InitRequest {
// TODO: full of possibly interesting information
2025-03-25 18:15:41 -04:00
unk : [ u8 ; 120 ] ,
2025-03-16 17:43:29 -04:00
} ,
2025-03-26 18:28:51 -04:00
/// Sent by the client when they're done loading and they need to be spawned in
2025-03-16 17:43:29 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::FinishLoading)) ]
FinishLoading {
// TODO: full of possibly interesting information
unk : [ u8 ; 72 ] ,
} ,
2025-05-08 22:53:36 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::ClientTrigger)) ]
ClientTrigger ( ClientTrigger ) ,
2025-03-26 18:28:51 -04:00
/// FIXME: 16 bytes of something from the client, not sure what yet
2025-03-16 17:43:29 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::Unk2)) ]
Unk2 {
// TODO: full of possibly interesting information
2025-03-25 18:15:41 -04:00
unk : [ u8 ; 16 ] ,
2025-03-16 17:43:29 -04:00
} ,
2025-03-26 18:28:51 -04:00
/// FIXME: 8 bytes of something from the client, not sure what yet
2025-03-16 17:43:29 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::Unk3)) ]
Unk3 {
// TODO: full of possibly interesting information
unk : [ u8 ; 8 ] ,
} ,
2025-03-26 18:28:51 -04:00
/// FIXME: 8 bytes of something from the client, not sure what yet
2025-03-16 17:43:29 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::Unk4)) ]
Unk4 {
// TODO: full of possibly interesting information
unk : [ u8 ; 8 ] ,
} ,
#[ br(pre_assert(*magic == ClientZoneIpcType::SetSearchInfoHandler)) ]
SetSearchInfoHandler {
// TODO: full of possibly interesting information
unk : [ u8 ; 8 ] ,
} ,
2025-03-26 18:28:51 -04:00
/// FIXME: 8 bytes of something from the client, not sure what yet
2025-03-16 17:43:29 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::Unk5)) ]
Unk5 {
// TODO: full of possibly interesting information
unk : [ u8 ; 8 ] ,
} ,
2025-03-26 18:28:51 -04:00
/// Sent by the client when it requests the friends list and other related info
2025-03-16 17:43:29 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::SocialListRequest)) ]
SocialListRequest ( SocialListRequest ) ,
#[ br(pre_assert(*magic == ClientZoneIpcType::UpdatePositionHandler)) ]
UpdatePositionHandler {
2025-03-28 23:29:16 -04:00
/// In radians.
#[ brw(pad_after = 4) ] // empty
rotation : f32 ,
2025-03-23 10:33:49 -04:00
#[ brw(pad_after = 4) ] // empty
position : Position ,
2025-03-16 17:43:29 -04:00
} ,
2025-03-26 18:28:51 -04:00
/// Sent by the client when the user requests to log out
2025-03-16 17:43:29 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::LogOut)) ]
LogOut {
// TODO: full of possibly interesting information
unk : [ u8 ; 8 ] ,
} ,
2025-03-26 18:28:51 -04:00
/// Sent by the client when it's actually disconnecting
2025-03-16 17:43:29 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::Disconnected)) ]
Disconnected {
// TODO: full of possibly interesting information
unk : [ u8 ; 8 ] ,
} ,
2025-03-26 18:28:51 -04:00
/// Sent by the client when they send a chat message
2025-03-16 17:43:29 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::ChatMessage)) ]
ChatMessage ( ChatMessage ) ,
2025-03-26 18:28:51 -04:00
/// Sent by the client when they send a GM command. This can only be sent by the client if they are sent a GM rank.
2025-05-01 23:20:56 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::GMCommand)) ]
2025-05-02 23:24:31 -04:00
GMCommand {
2025-06-28 09:56:04 -04:00
command : u32 ,
2025-05-01 23:20:56 -04:00
arg0 : u32 ,
arg1 : u32 ,
arg2 : u32 ,
arg3 : u32 ,
2025-06-28 10:05:57 -04:00
#[ brw(pad_after = 4) ]
2025-05-01 23:20:56 -04:00
target : u64 ,
2025-03-16 17:43:29 -04:00
} ,
2025-03-26 18:28:51 -04:00
/// Sent by the client when the character walks into a zone transistion
2025-05-01 23:20:56 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::ZoneJump)) ]
ZoneJump {
exit_box : u32 ,
2025-03-16 17:43:29 -04:00
position : Position ,
2025-05-01 23:20:56 -04:00
#[ brw(pad_after = 4) ] // padding
2025-03-16 17:43:29 -04:00
landset_index : i32 ,
} ,
2025-03-26 18:28:51 -04:00
/// Sent by the client when a character performs an action
2025-03-19 00:28:47 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::ActionRequest)) ]
ActionRequest ( ActionRequest ) ,
2025-03-26 16:58:55 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::Unk16)) ]
Unk16 {
unk : [ u8 ; 8 ] , // TODO: unknown
} ,
#[ br(pre_assert(*magic == ClientZoneIpcType::Unk17)) ]
Unk17 {
2025-06-25 23:11:49 -04:00
unk1 : u32 ,
unk2 : [ u8 ; 28 ] , // TODO: unknown
2025-03-26 16:58:55 -04:00
} ,
#[ br(pre_assert(*magic == ClientZoneIpcType::Unk18)) ]
Unk18 {
unk : [ u8 ; 8 ] , // TODO: unknown
} ,
2025-03-28 20:19:17 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::EventRelatedUnk)) ]
EventRelatedUnk {
unk1 : u32 ,
2025-03-28 21:28:30 -04:00
unk2 : u16 ,
#[ brw(pad_before = 2) ]
2025-03-28 20:19:17 -04:00
unk3 : u32 ,
unk4 : u32 ,
} ,
2025-03-29 16:40:33 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::Unk19)) ]
Unk19 {
unk : [ u8 ; 16 ] , // TODO: unknown
} ,
2025-05-01 23:20:56 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::ItemOperation)) ]
2025-05-02 23:24:31 -04:00
ItemOperation ( ItemOperation ) ,
2025-05-05 20:51:49 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::StartTalkEvent)) ]
StartTalkEvent {
actor_id : ObjectTypeId ,
#[ brw(pad_after = 4) ] // padding
event_id : u32 ,
} ,
2025-06-30 15:21:08 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::GilShopTransaction)) ]
GilShopTransaction {
event_id : u32 ,
/// Seems to always be 0x300000a at gil shops
unk1 : u32 ,
/// 1 is buy, 2 is sell
buy_sell_mode : u32 ,
/// Index into the shopkeeper's or the player's inventory
item_index : u32 ,
/// Quantity of items being bought or sold
item_quantity : u32 ,
/// unk 2: Flags? These change quite a bit when dealing with stackable items, but are apparently always 0 when buying non-stackable
/// Observed values so far: 0xDDDDDDDD (when buying 99 of a stackable item), 0xFFFFFFFF, 0xFFE0FFD0, 0xfffefffe, 0x0000FF64
unk2 : u32 ,
} ,
2025-07-12 17:40:22 -04:00
/// This packet is sent by the client when they pivot left or right on standard controls.
/// It is sent once when beginning to pivot, and once when pivoting ends.
#[ br(pre_assert(*magic == ClientZoneIpcType::StandardControlsPivot)) ]
StandardControlsPivot {
/// Set to 4 when beginning to pivot.
/// Set to 0 when pivoting ends.
#[ brw(pad_after = 4) ]
is_pivoting : u32 ,
} ,
2025-06-28 15:57:45 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::EventYieldHandler)) ]
EventYieldHandler ( EventYieldHandler < 2 > ) ,
#[ br(pre_assert(*magic == ClientZoneIpcType::EventYieldHandler8)) ]
EventYieldHandler8 ( EventYieldHandler < 8 > ) ,
2025-06-25 21:30:14 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::Config)) ]
Config ( Config ) ,
2025-06-25 23:11:49 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::EventUnkRequest)) ]
EventUnkRequest {
event_id : u32 ,
unk1 : u16 ,
unk2 : u8 ,
#[ brw(pad_after = 8) ]
unk3 : u8 ,
} ,
2025-07-04 16:18:39 -04:00
/// Unsure the true purpose of this, but it's needed for the Unending Journey to function.
#[ br(pre_assert(*magic == ClientZoneIpcType::UnkCall2)) ]
UnkCall2 { unk1 : [ u8 ; 8 ] } ,
2025-07-12 20:53:59 -04:00
#[ br(pre_assert(*magic == ClientZoneIpcType::ContentFinderRegister)) ]
ContentFinderRegister { unk1 : [ u8 ; 40 ] } ,
2025-06-28 08:48:59 -04:00
Unknown {
#[ br(count = size - 32) ]
unk : Vec < u8 > ,
} ,
2025-03-16 17:43:29 -04:00
}
#[ cfg(test) ]
mod tests {
use std ::io ::Cursor ;
use binrw ::BinWrite ;
2025-03-26 18:28:51 -04:00
use crate ::opcodes ::ServerZoneIpcType ;
2025-03-16 17:43:29 -04:00
use super ::* ;
/// Ensure that the IPC data size as reported matches up with what we write
#[ test ]
2025-06-28 15:57:45 -04:00
fn server_zone_ipc_sizes ( ) {
2025-03-16 17:43:29 -04:00
let ipc_types = [
2025-03-30 19:50:31 -04:00
(
ServerZoneIpcType ::InitResponse ,
ServerZoneIpcData ::InitResponse {
unk1 : 0 ,
character_id : 0 ,
unk2 : 0 ,
} ,
) ,
(
ServerZoneIpcType ::InitZone ,
ServerZoneIpcData ::InitZone ( InitZone ::default ( ) ) ,
) ,
(
ServerZoneIpcType ::ActorControlSelf ,
ServerZoneIpcData ::ActorControlSelf ( ActorControlSelf ::default ( ) ) ,
) ,
2025-03-16 17:43:29 -04:00
(
ServerZoneIpcType ::PlayerStats ,
ServerZoneIpcData ::PlayerStats ( PlayerStats ::default ( ) ) ,
) ,
(
2025-05-01 23:34:06 -04:00
ServerZoneIpcType ::PlayerStatus ,
2025-05-02 23:24:31 -04:00
ServerZoneIpcData ::PlayerStatus ( PlayerStatus ::default ( ) ) ,
2025-03-16 17:43:29 -04:00
) ,
(
ServerZoneIpcType ::UpdateClassInfo ,
ServerZoneIpcData ::UpdateClassInfo ( UpdateClassInfo ::default ( ) ) ,
) ,
(
ServerZoneIpcType ::PlayerSpawn ,
ServerZoneIpcData ::PlayerSpawn ( PlayerSpawn ::default ( ) ) ,
) ,
2025-03-30 19:50:31 -04:00
(
ServerZoneIpcType ::LogOutComplete ,
ServerZoneIpcData ::LogOutComplete { unk : [ 0 ; 8 ] } ,
) ,
2025-03-16 17:43:29 -04:00
(
2025-05-01 23:34:06 -04:00
ServerZoneIpcType ::Warp ,
2025-05-02 23:24:31 -04:00
ServerZoneIpcData ::Warp ( Warp ::default ( ) ) ,
2025-03-16 17:43:29 -04:00
) ,
2025-03-18 22:13:28 -04:00
(
2025-03-30 19:50:31 -04:00
ServerZoneIpcType ::ServerChatMessage ,
ServerZoneIpcData ::ServerChatMessage {
2025-06-25 10:05:34 -04:00
param : 0 ,
2025-03-30 19:50:31 -04:00
message : String ::new ( ) ,
} ,
) ,
2025-07-12 14:48:21 -04:00
(
ServerZoneIpcType ::LinkShellInformation ,
ServerZoneIpcData ::LinkShellInformation { unk : [ 0 ; 456 ] } ,
) ,
2025-03-30 19:50:31 -04:00
(
ServerZoneIpcType ::PrepareZoning ,
ServerZoneIpcData ::PrepareZoning { unk : [ 0 ; 4 ] } ,
2025-03-18 22:13:28 -04:00
) ,
2025-03-18 23:30:59 -04:00
(
ServerZoneIpcType ::ActorControl ,
ServerZoneIpcData ::ActorControl ( ActorControl ::default ( ) ) ,
) ,
2025-03-30 19:50:31 -04:00
(
2025-05-01 23:20:56 -04:00
ServerZoneIpcType ::Move ,
2025-05-02 23:24:31 -04:00
ServerZoneIpcData ::Move ( Move ::default ( ) ) ,
2025-03-30 19:50:31 -04:00
) ,
2025-07-12 14:48:21 -04:00
(
ServerZoneIpcType ::SocialList ,
ServerZoneIpcData ::SocialList ( SocialList ::default ( ) ) ,
) ,
2025-03-30 19:50:31 -04:00
(
ServerZoneIpcType ::NpcSpawn ,
ServerZoneIpcData ::NpcSpawn ( NpcSpawn ::default ( ) ) ,
) ,
2025-03-18 23:30:59 -04:00
(
ServerZoneIpcType ::StatusEffectList ,
ServerZoneIpcData ::StatusEffectList ( StatusEffectList ::default ( ) ) ,
) ,
2025-03-18 23:48:00 -04:00
(
2025-05-01 23:34:06 -04:00
ServerZoneIpcType ::WeatherId ,
ServerZoneIpcData ::WeatherId ( WeatherChange ::default ( ) ) ,
2025-03-18 23:48:00 -04:00
) ,
2025-03-23 17:10:47 -04:00
(
2025-05-01 23:34:06 -04:00
ServerZoneIpcType ::UpdateItem ,
ServerZoneIpcData ::UpdateItem ( ItemInfo ::default ( ) ) ,
2025-03-23 17:10:47 -04:00
) ,
(
ServerZoneIpcType ::ContainerInfo ,
ServerZoneIpcData ::ContainerInfo ( ContainerInfo ::default ( ) ) ,
) ,
2025-03-28 20:19:17 -04:00
(
2025-05-01 23:34:06 -04:00
ServerZoneIpcType ::EventScene ,
2025-07-08 21:18:30 +00:00
ServerZoneIpcData ::EventScene {
data : EventScene ::default ( ) ,
} ,
2025-03-28 20:19:17 -04:00
) ,
2025-06-28 16:05:36 -04:00
(
ServerZoneIpcType ::EventScene4 ,
2025-07-08 21:18:30 +00:00
ServerZoneIpcData ::EventScene4 {
data : EventScene ::default ( ) ,
} ,
2025-06-28 16:05:36 -04:00
) ,
(
ServerZoneIpcType ::EventScene8 ,
2025-07-08 21:18:30 +00:00
ServerZoneIpcData ::EventScene8 {
data : EventScene ::default ( ) ,
} ,
2025-06-28 16:05:36 -04:00
) ,
(
ServerZoneIpcType ::EventScene16 ,
2025-07-08 21:18:30 +00:00
ServerZoneIpcData ::EventScene16 {
data : EventScene ::default ( ) ,
} ,
2025-06-28 16:05:36 -04:00
) ,
(
ServerZoneIpcType ::EventScene32 ,
2025-07-08 21:18:30 +00:00
ServerZoneIpcData ::EventScene32 {
data : EventScene ::default ( ) ,
} ,
2025-06-28 16:05:36 -04:00
) ,
(
ServerZoneIpcType ::EventScene64 ,
2025-07-08 21:18:30 +00:00
ServerZoneIpcData ::EventScene64 {
data : EventScene ::default ( ) ,
} ,
2025-06-28 16:05:36 -04:00
) ,
(
ServerZoneIpcType ::EventScene128 ,
2025-07-08 21:18:30 +00:00
ServerZoneIpcData ::EventScene128 {
data : EventScene ::default ( ) ,
} ,
2025-06-28 16:05:36 -04:00
) ,
(
ServerZoneIpcType ::EventScene255 ,
2025-07-08 21:18:30 +00:00
ServerZoneIpcData ::EventScene255 {
data : EventScene ::default ( ) ,
} ,
2025-06-28 16:05:36 -04:00
) ,
2025-03-28 20:19:17 -04:00
(
ServerZoneIpcType ::EventStart ,
ServerZoneIpcData ::EventStart ( EventStart ::default ( ) ) ,
) ,
2025-03-29 14:14:03 -04:00
(
2025-03-30 19:50:31 -04:00
ServerZoneIpcType ::UpdateHpMpTp ,
ServerZoneIpcData ::UpdateHpMpTp {
hp : 0 ,
mp : 0 ,
unk : 0 ,
} ,
2025-03-29 14:14:03 -04:00
) ,
2025-07-12 14:48:21 -04:00
(
ServerZoneIpcType ::Equip ,
ServerZoneIpcData ::Equip ( Equip ::default ( ) ) ,
) ,
2025-03-30 17:49:45 -04:00
(
2025-03-30 19:50:31 -04:00
ServerZoneIpcType ::ActionResult ,
ServerZoneIpcData ::ActionResult ( ActionResult ::default ( ) ) ,
2025-03-30 17:49:45 -04:00
) ,
2025-03-31 21:49:12 -04:00
(
2025-07-12 14:48:21 -04:00
ServerZoneIpcType ::Delete ,
ServerZoneIpcData ::Delete {
spawn_index : 0 ,
actor_id : 0 ,
} ,
) ,
(
ServerZoneIpcType ::EventFinish ,
ServerZoneIpcData ::EventFinish {
handler_id : 0 ,
event : 0 ,
result : 0 ,
arg : 0 ,
} ,
) ,
(
ServerZoneIpcType ::Unk18 ,
ServerZoneIpcData ::Unk18 { unk : [ 0 ; 16 ] } ,
) ,
(
ServerZoneIpcType ::ActorControlTarget ,
ServerZoneIpcData ::ActorControlTarget ( ActorControlTarget ::default ( ) ) ,
) ,
(
ServerZoneIpcType ::CurrencyCrystalInfo ,
ServerZoneIpcData ::CurrencyCrystalInfo ( CurrencyInfo ::default ( ) ) ,
) ,
(
ServerZoneIpcType ::EventUnkReply ,
ServerZoneIpcData ::EventUnkReply {
event_id : 0 ,
unk1 : 0 ,
unk2 : 0 ,
unk3 : 0 ,
} ,
) ,
(
ServerZoneIpcType ::InventoryActionAck ,
ServerZoneIpcData ::InventoryActionAck {
sequence : 0 ,
action_type : 0 ,
} ,
) ,
(
ServerZoneIpcType ::UnkCall ,
ServerZoneIpcData ::UnkCall { unk1 : 0 , unk2 : 0 } ,
) ,
(
ServerZoneIpcType ::QuestCompleteList ,
ServerZoneIpcData ::QuestCompleteList {
completed_quests : Vec ::default ( ) ,
unk2 : Vec ::default ( ) ,
} ,
) ,
(
ServerZoneIpcType ::UnkResponse2 ,
ServerZoneIpcData ::UnkResponse2 { unk1 : 0 } ,
) ,
(
2025-07-12 17:40:22 -04:00
ServerZoneIpcType ::InventoryTransaction ,
ServerZoneIpcData ::InventoryTransaction {
2025-07-12 14:48:21 -04:00
unk1 : 0 ,
2025-07-12 17:40:22 -04:00
operation_type : ItemOperationKind ::Move ,
2025-07-12 14:48:21 -04:00
src_actor_id : 0 ,
src_storage_id : ContainerType ::Inventory0 ,
src_container_index : 0 ,
2025-07-12 17:40:22 -04:00
unk2 : 0 ,
unk3 : 0 ,
2025-07-12 14:48:21 -04:00
dst_actor_id : 0 ,
dst_storage_id : 0 ,
dst_container_index : 0 ,
dst_catalog_id : 0 ,
} ,
) ,
(
2025-07-12 17:40:22 -04:00
ServerZoneIpcType ::InventoryTransactionFinish ,
ServerZoneIpcData ::InventoryTransactionFinish {
2025-07-12 14:48:21 -04:00
unk1 : 0 ,
unk2 : 0 ,
unk3 : 0 ,
unk4 : 0 ,
} ,
2025-03-31 21:49:12 -04:00
) ,
2025-03-16 17:43:29 -04:00
] ;
for ( opcode , data ) in & ipc_types {
let mut cursor = Cursor ::new ( Vec ::new ( ) ) ;
let ipc_segment = ServerZoneIpcSegment {
unk1 : 0 ,
unk2 : 0 ,
op_code : opcode . clone ( ) , // doesn't matter for this test
2025-05-02 00:17:15 -04:00
option : 0 ,
2025-03-16 17:43:29 -04:00
timestamp : 0 ,
data : data . clone ( ) ,
} ;
ipc_segment . write_le ( & mut cursor ) . unwrap ( ) ;
let buffer = cursor . into_inner ( ) ;
assert_eq! (
buffer . len ( ) ,
ipc_segment . calc_size ( ) as usize ,
" {:#?} did not match size! " ,
opcode
) ;
}
}
2025-06-28 15:57:45 -04:00
/// Ensure that the IPC data size as reported matches up with what we write
#[ test ]
fn client_zone_ipc_sizes ( ) {
2025-07-12 14:48:21 -04:00
let ipc_types = [
(
ClientZoneIpcType ::InitRequest ,
ClientZoneIpcData ::InitRequest { unk : [ 0 ; 120 ] } ,
) ,
(
ClientZoneIpcType ::FinishLoading ,
ClientZoneIpcData ::FinishLoading { unk : [ 0 ; 72 ] } ,
) ,
(
ClientZoneIpcType ::ClientTrigger ,
ClientZoneIpcData ::ClientTrigger ( ClientTrigger ::default ( ) ) ,
) ,
(
ClientZoneIpcType ::Unk2 ,
ClientZoneIpcData ::Unk2 { unk : [ 0 ; 16 ] } ,
) ,
(
ClientZoneIpcType ::Unk3 ,
ClientZoneIpcData ::Unk3 { unk : [ 0 ; 8 ] } ,
) ,
(
ClientZoneIpcType ::Unk4 ,
ClientZoneIpcData ::Unk4 { unk : [ 0 ; 8 ] } ,
) ,
(
ClientZoneIpcType ::SetSearchInfoHandler ,
ClientZoneIpcData ::SetSearchInfoHandler { unk : [ 0 ; 8 ] } ,
) ,
(
ClientZoneIpcType ::Unk5 ,
ClientZoneIpcData ::Unk5 { unk : [ 0 ; 8 ] } ,
) ,
(
ClientZoneIpcType ::SocialListRequest ,
ClientZoneIpcData ::SocialListRequest ( SocialListRequest ::default ( ) ) ,
) ,
(
ClientZoneIpcType ::UpdatePositionHandler ,
ClientZoneIpcData ::UpdatePositionHandler {
rotation : 0.0 ,
position : Position ::default ( ) ,
} ,
) ,
(
ClientZoneIpcType ::LogOut ,
ClientZoneIpcData ::LogOut { unk : [ 0 ; 8 ] } ,
) ,
(
ClientZoneIpcType ::Disconnected ,
ClientZoneIpcData ::Disconnected { unk : [ 0 ; 8 ] } ,
) ,
(
ClientZoneIpcType ::ChatMessage ,
ClientZoneIpcData ::ChatMessage ( ChatMessage ::default ( ) ) ,
) ,
(
ClientZoneIpcType ::GMCommand ,
ClientZoneIpcData ::GMCommand {
command : 0 ,
arg0 : 0 ,
arg1 : 0 ,
arg2 : 0 ,
arg3 : 0 ,
target : 0 ,
} ,
) ,
(
ClientZoneIpcType ::ZoneJump ,
ClientZoneIpcData ::ZoneJump {
exit_box : 0 ,
position : Position ::default ( ) ,
landset_index : 0 ,
} ,
) ,
(
ClientZoneIpcType ::ActionRequest ,
ClientZoneIpcData ::ActionRequest ( ActionRequest ::default ( ) ) ,
) ,
(
ClientZoneIpcType ::Unk16 ,
ClientZoneIpcData ::Unk16 { unk : [ 0 ; 8 ] } ,
) ,
(
ClientZoneIpcType ::Unk17 ,
ClientZoneIpcData ::Unk17 {
unk1 : 0 ,
unk2 : [ 0 ; 28 ] ,
} ,
) ,
(
ClientZoneIpcType ::Unk18 ,
ClientZoneIpcData ::Unk18 { unk : [ 0 ; 8 ] } ,
) ,
(
ClientZoneIpcType ::EventRelatedUnk ,
ClientZoneIpcData ::EventRelatedUnk {
unk1 : 0 ,
unk2 : 0 ,
unk3 : 0 ,
unk4 : 0 ,
} ,
) ,
(
ClientZoneIpcType ::Unk19 ,
ClientZoneIpcData ::Unk19 { unk : [ 0 ; 16 ] } ,
) ,
(
ClientZoneIpcType ::ItemOperation ,
ClientZoneIpcData ::ItemOperation ( ItemOperation ::default ( ) ) ,
) ,
(
ClientZoneIpcType ::StartTalkEvent ,
ClientZoneIpcData ::StartTalkEvent {
actor_id : ObjectTypeId ::default ( ) ,
event_id : 0 ,
} ,
) ,
(
ClientZoneIpcType ::GilShopTransaction ,
ClientZoneIpcData ::GilShopTransaction {
event_id : 0 ,
unk1 : 0 ,
buy_sell_mode : 0 ,
item_index : 0 ,
item_quantity : 0 ,
unk2 : 0 ,
} ,
) ,
(
ClientZoneIpcType ::EventYieldHandler ,
ClientZoneIpcData ::EventYieldHandler ( EventYieldHandler ::< 2 > ::default ( ) ) ,
) ,
(
ClientZoneIpcType ::EventYieldHandler8 ,
ClientZoneIpcData ::EventYieldHandler8 ( EventYieldHandler ::< 8 > ::default ( ) ) ,
) ,
(
ClientZoneIpcType ::EventUnkRequest ,
ClientZoneIpcData ::EventUnkRequest {
event_id : 0 ,
unk1 : 0 ,
unk2 : 0 ,
unk3 : 0 ,
} ,
) ,
(
ClientZoneIpcType ::UnkCall2 ,
ClientZoneIpcData ::UnkCall2 { unk1 : [ 0 ; 8 ] } ,
) ,
] ;
2025-06-28 15:57:45 -04:00
for ( opcode , data ) in & ipc_types {
let mut cursor = Cursor ::new ( Vec ::new ( ) ) ;
let ipc_segment = ClientZoneIpcSegment {
unk1 : 0 ,
unk2 : 0 ,
op_code : opcode . clone ( ) , // doesn't matter for this test
option : 0 ,
timestamp : 0 ,
data : data . clone ( ) ,
} ;
ipc_segment . write_le ( & mut cursor ) . unwrap ( ) ;
let buffer = cursor . into_inner ( ) ;
assert_eq! (
buffer . len ( ) ,
ipc_segment . calc_size ( ) as usize ,
" {:#?} did not match size! " ,
opcode
) ;
}
}
2025-03-16 17:43:29 -04:00
}