diff --git a/src/bin/kawari-world.rs b/src/bin/kawari-world.rs index 507fbf6..30f7dd9 100644 --- a/src/bin/kawari-world.rs +++ b/src/bin/kawari-world.rs @@ -500,6 +500,9 @@ async fn main() { tracing::info!("Got a game master command!"); match &command { + GameMasterCommandType::ChangeWeather => { + connection.change_weather(*arg as u16).await + } GameMasterCommandType::ChangeTerritory => { connection.change_zone(*arg as u16).await } diff --git a/src/world/chat_handler.rs b/src/world/chat_handler.rs index 408d78e..5c78c3b 100644 --- a/src/world/chat_handler.rs +++ b/src/world/chat_handler.rs @@ -1,4 +1,3 @@ - use crate::{ CHAR_NAME, CUSTOMIZE_DATA, INVALID_OBJECT_ID, WORLD_ID, common::timestamp_secs, diff --git a/src/world/connection.rs b/src/world/connection.rs index 2c163c0..49c8a0c 100644 --- a/src/world/connection.rs +++ b/src/world/connection.rs @@ -12,7 +12,7 @@ use super::{ Zone, ipc::{ ActorSetPos, ClientZoneIpcSegment, InitZone, Position, ServerZoneIpcData, - ServerZoneIpcSegment, ServerZoneIpcType, UpdateClassInfo, + ServerZoneIpcSegment, ServerZoneIpcType, UpdateClassInfo, WeatherChange, }, }; @@ -137,6 +137,25 @@ impl ZoneConnection { } } + pub async fn change_weather(&mut self, new_weather_id: u16) { + let ipc = ServerZoneIpcSegment { + op_code: ServerZoneIpcType::WeatherChange, + timestamp: timestamp_secs(), + data: ServerZoneIpcData::WeatherChange(WeatherChange { + weather_id: new_weather_id, + transistion_time: 1.0, + }), + ..Default::default() + }; + + self.send_segment(PacketSegment { + source_actor: self.player_id, + target_actor: self.player_id, + segment_type: SegmentType::Ipc { data: ipc }, + }) + .await; + } + pub fn get_free_spawn_index(&mut self) -> u8 { self.spawn_index += 1; self.spawn_index diff --git a/src/world/ipc/mod.rs b/src/world/ipc/mod.rs index 13d9ece..b93afe3 100644 --- a/src/world/ipc/mod.rs +++ b/src/world/ipc/mod.rs @@ -44,6 +44,9 @@ pub use common_spawn::{CharacterMode, CommonSpawn, ObjectKind}; mod status_effect_list; pub use status_effect_list::StatusEffectList; +mod weather_change; +pub use weather_change::WeatherChange; + use crate::common::read_string; use crate::common::write_string; use crate::packet::IpcSegment; @@ -87,7 +90,6 @@ impl ReadWriteIpcSegment for ServerZoneIpcSegment { ServerZoneIpcType::Unk8 => 808, ServerZoneIpcType::LinkShellInformation => 456, ServerZoneIpcType::Unk9 => 24, - ServerZoneIpcType::Unk10 => 8, ServerZoneIpcType::Unk11 => 32, ServerZoneIpcType::Unk15 => 8, ServerZoneIpcType::Unk16 => 136, @@ -98,6 +100,7 @@ impl ReadWriteIpcSegment for ServerZoneIpcSegment { ServerZoneIpcType::PrepareZoning => 16, ServerZoneIpcType::NpcSpawn => 648, ServerZoneIpcType::StatusEffectList => 384, + ServerZoneIpcType::WeatherChange => 8, } } } @@ -130,6 +133,7 @@ pub struct ActorSetPos { #[brw(repr = u8)] #[derive(Clone, PartialEq, Debug)] pub enum GameMasterCommandType { + ChangeWeather = 0x6, ChangeTerritory = 0x58, } @@ -165,9 +169,6 @@ pub enum ServerZoneIpcType { LinkShellInformation = 0x234, // Unknown, server sends to the client before player spawn Unk9 = 0x189, - // Unknown, server sends to the client before player spawn. - // Seems to the same across two different characters? - Unk10 = 0x110, // Unknown, server sends this in response to Unk7 Unk11 = 0x156, // Sent by the server when it wants the client to... prepare to zone? @@ -188,6 +189,8 @@ pub enum ServerZoneIpcType { NpcSpawn = 0x100, // Sent by the server to update an actor's status effect list StatusEffectList = 0xBB, + // Sent by the server when it's time to change the weather + WeatherChange = 0x110, } #[binrw] @@ -273,9 +276,6 @@ pub enum ServerZoneIpcData { Unk9 { unk: [u8; 24], }, - Unk10 { - unk: u64, - }, Unk11 { timestamp: u32, #[brw(pad_after = 24)] // empty bytes @@ -302,6 +302,7 @@ pub enum ServerZoneIpcData { SocialList(SocialList), NpcSpawn(NpcSpawn), StatusEffectList(StatusEffectList), + WeatherChange(WeatherChange), } #[binrw] @@ -456,6 +457,10 @@ mod tests { ServerZoneIpcType::StatusEffectList, ServerZoneIpcData::StatusEffectList(StatusEffectList::default()), ), + ( + ServerZoneIpcType::WeatherChange, + ServerZoneIpcData::WeatherChange(WeatherChange::default()), + ), ]; for (opcode, data) in &ipc_types { diff --git a/src/world/ipc/npc_spawn.rs b/src/world/ipc/npc_spawn.rs index f6a2fc5..0d1c4c1 100644 --- a/src/world/ipc/npc_spawn.rs +++ b/src/world/ipc/npc_spawn.rs @@ -1,6 +1,5 @@ use binrw::binrw; - use super::CommonSpawn; #[binrw] diff --git a/src/world/ipc/player_spawn.rs b/src/world/ipc/player_spawn.rs index 94199cb..a10ad99 100644 --- a/src/world/ipc/player_spawn.rs +++ b/src/world/ipc/player_spawn.rs @@ -1,6 +1,5 @@ use binrw::binrw; - use super::CommonSpawn; #[binrw] diff --git a/src/world/ipc/weather_change.rs b/src/world/ipc/weather_change.rs new file mode 100644 index 0000000..f0bbec8 --- /dev/null +++ b/src/world/ipc/weather_change.rs @@ -0,0 +1,9 @@ +use binrw::binrw; + +#[binrw] +#[derive(Debug, Clone, Copy, Default)] +pub struct WeatherChange { + pub weather_id: u16, + #[brw(pad_before = 3)] + pub transistion_time: f32, +}