diff --git a/src/bin/kawari-world.rs b/src/bin/kawari-world.rs index 6aa2b8c..e372f80 100644 --- a/src/bin/kawari-world.rs +++ b/src/bin/kawari-world.rs @@ -11,9 +11,10 @@ use kawari::packet::{ send_packet, }; use kawari::world::ipc::{ - ClientZoneIpcData, CommonSpawn, DisplayFlag, GameMasterCommandType, GameMasterRank, ObjectKind, - OnlineStatus, PlayerSubKind, ServerZoneIpcData, ServerZoneIpcSegment, ServerZoneIpcType, - SocialListRequestType, StatusEffect, + ClientZoneIpcData, CommonSpawn, ContainerInfo, ContainerType, DisplayFlag, + GameMasterCommandType, GameMasterRank, ItemInfo, ObjectKind, OnlineStatus, PlayerSubKind, + ServerZoneIpcData, ServerZoneIpcSegment, ServerZoneIpcType, SocialListRequestType, + StatusEffect, }; use kawari::world::{ ChatHandler, Zone, ZoneConnection, @@ -188,6 +189,76 @@ async fn main() { .await; } + let item_ids = [ + (12, 0x00003b1d), + (11, 0x0000114a), + (10, 0x00003b1c), + (9, 0x00003b1a), + (8, 0x00003b1b), + (7, 0x00000ea7), + (6, 0x00000ce1), + (4, 0x00000dc1), + (3, 0x00000ba8), + (0, 0x00000641), + ]; + + // send inventory + { + for (slot, id) in &item_ids { + let ipc = ServerZoneIpcSegment { + op_code: ServerZoneIpcType::ItemInfo, + timestamp: timestamp_secs(), + data: ServerZoneIpcData::ItemInfo(ItemInfo { + container: ContainerType::Equipped, + slot: *slot, + quantity: 1, + catalog_id: *id, + condition: 30000, + ..Default::default() + }), + ..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; + } + } + + // inform the client they have 10 items equipped + { + let ipc = ServerZoneIpcSegment { + op_code: ServerZoneIpcType::ContainerInfo, + timestamp: timestamp_secs(), + data: ServerZoneIpcData::ContainerInfo( + ContainerInfo { + container: ContainerType::Equipped, + num_items: item_ids.len() as u32, + ..Default::default() + }, + ), + ..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; + } + // Control Data { let ipc = ServerZoneIpcSegment { diff --git a/src/world/ipc/mod.rs b/src/world/ipc/mod.rs index 05d7535..92e3dfe 100644 --- a/src/world/ipc/mod.rs +++ b/src/world/ipc/mod.rs @@ -108,6 +108,8 @@ impl ReadWriteIpcSegment for ServerZoneIpcSegment { ServerZoneIpcType::NpcSpawn => 648, ServerZoneIpcType::StatusEffectList => 384, ServerZoneIpcType::WeatherChange => 8, + ServerZoneIpcType::ItemInfo => 64, + ServerZoneIpcType::ContainerInfo => 16, } } } @@ -199,6 +201,10 @@ pub enum ServerZoneIpcType { StatusEffectList = 0xBB, // Sent by the server when it's time to change the weather WeatherChange = 0x110, + // Sent to inform the client of an inventory item + ItemInfo = 0x3AA, + // Sent to inform the client of container status + ContainerInfo = 0x2EA, } #[binrw] @@ -315,6 +321,8 @@ pub enum ServerZoneIpcData { NpcSpawn(NpcSpawn), StatusEffectList(StatusEffectList), WeatherChange(WeatherChange), + ItemInfo(ItemInfo), + ContainerInfo(ContainerInfo), } #[binrw] @@ -483,6 +491,14 @@ mod tests { ServerZoneIpcType::ActorControl, ServerZoneIpcData::ActorControl(ActorControl::default()), ), + ( + ServerZoneIpcType::ItemInfo, + ServerZoneIpcData::ItemInfo(ItemInfo::default()), + ), + ( + ServerZoneIpcType::ContainerInfo, + ServerZoneIpcData::ContainerInfo(ContainerInfo::default()), + ), ]; for (opcode, data) in &ipc_types {