diff --git a/resources/opcodes.json b/resources/opcodes.json index 464b138..07c34b9 100644 --- a/resources/opcodes.json +++ b/resources/opcodes.json @@ -174,6 +174,11 @@ "name": "CurrencyCrystalInfo", "opcode": 548, "size": 24 + }, + { + "name": "Config", + "opcode": 153, + "size": 8 } ], "ClientZoneIpcType": [ @@ -296,6 +301,11 @@ "name": "EventHandlerReturn", "opcode": 840, "size": 16 + }, + { + "name": "Config", + "opcode": 534, + "size": 8 } ], "ServerLobbyIpcType": [ diff --git a/src/bin/kawari-world.rs b/src/bin/kawari-world.rs index 840346d..ca64a1a 100644 --- a/src/bin/kawari-world.rs +++ b/src/bin/kawari-world.rs @@ -864,6 +864,16 @@ async fn client_loop( .unwrap() .finish(*scene, ¶ms[..*num_results as usize], &mut lua_player); } + ClientZoneIpcData::Config(config) => { + connection + .handle + .send(ToServer::Config( + connection.id, + connection.player_data.actor_id, + config.clone(), + )) + .await; + } } } SegmentData::KeepAliveRequest { id, timestamp } => { @@ -918,6 +928,7 @@ async fn client_loop( FromServer::ActorControlSelf(actor_control) => connection.actor_control_self(actor_control).await, FromServer::ActionComplete(request) => connection.execute_action(request, &mut lua_player).await, FromServer::ActionCancelled() => connection.cancel_action().await, + FromServer::UpdateConfig(actor_id, config) => connection.update_config(actor_id, config).await, }, None => break, } diff --git a/src/ipc/zone/config.rs b/src/ipc/zone/config.rs new file mode 100644 index 0000000..4faa956 --- /dev/null +++ b/src/ipc/zone/config.rs @@ -0,0 +1,11 @@ +use binrw::binrw; + +use super::DisplayFlag; + +#[binrw] +#[brw(little)] +#[derive(Debug, Clone, Default)] +pub struct Config { + #[brw(pad_after = 4)] + pub display_flag: DisplayFlag, +} diff --git a/src/ipc/zone/mod.rs b/src/ipc/zone/mod.rs index ec389cd..091b908 100644 --- a/src/ipc/zone/mod.rs +++ b/src/ipc/zone/mod.rs @@ -82,6 +82,9 @@ pub use client_trigger::{ClientTrigger, ClientTriggerCommand}; mod currency_info; pub use currency_info::CurrencyInfo; +mod config; +pub use config::Config; + use crate::common::ObjectTypeId; use crate::common::Position; use crate::common::read_string; @@ -263,6 +266,8 @@ pub enum ServerZoneIpcData { ActorControlTarget(ActorControlTarget), /// Used to update the player's currencies CurrencyCrystalInfo(CurrencyInfo), + /// Used to update an actor's equip display flags + Config(Config), } #[binrw] @@ -401,6 +406,8 @@ pub enum ClientZoneIpcData { num_results: u8, params: [u32; 2], }, + #[br(pre_assert(*magic == ClientZoneIpcType::Config))] + Config(Config), } #[cfg(test)] diff --git a/src/world/common.rs b/src/world/common.rs index 791cbbc..9d1a128 100644 --- a/src/world/common.rs +++ b/src/world/common.rs @@ -12,7 +12,7 @@ use crate::{ common::Position, ipc::zone::{ ActionRequest, ActorControl, ActorControlSelf, ActorControlTarget, ClientTrigger, - CommonSpawn, NpcSpawn, + CommonSpawn, Config, NpcSpawn, }, }; @@ -40,6 +40,8 @@ pub enum FromServer { ActionComplete(ActionRequest), /// Action has been cancelled ActionCancelled(), + /// Update an actor's equip display flags. + UpdateConfig(u32, Config), } #[derive(Debug, Clone)] @@ -99,6 +101,8 @@ pub enum ToServer { DebugSpawnClone(ClientId, u32), /// Request to perform an action ActionRequest(ClientId, u32, ActionRequest), + /// We want to update our own equip display flags. + Config(ClientId, u32, Config), } #[derive(Clone, Debug)] diff --git a/src/world/connection.rs b/src/world/connection.rs index ae3cb9c..5a9e255 100644 --- a/src/world/connection.rs +++ b/src/world/connection.rs @@ -17,9 +17,9 @@ use crate::{ chat::ServerChatIpcSegment, zone::{ ActionEffect, ActionRequest, ActionResult, ActorControl, ActorControlCategory, - ActorControlSelf, ActorControlTarget, ClientZoneIpcSegment, CommonSpawn, ContainerInfo, - CurrencyInfo, DisplayFlag, EffectKind, Equip, GameMasterRank, InitZone, ItemInfo, Move, - NpcSpawn, ObjectKind, PlayerStats, PlayerSubKind, ServerZoneIpcData, + ActorControlSelf, ActorControlTarget, ClientZoneIpcSegment, CommonSpawn, Config, + ContainerInfo, CurrencyInfo, DisplayFlag, EffectKind, Equip, GameMasterRank, InitZone, + ItemInfo, Move, NpcSpawn, ObjectKind, PlayerStats, PlayerSubKind, ServerZoneIpcData, ServerZoneIpcSegment, StatusEffect, StatusEffectList, UpdateClassInfo, Warp, WeatherChange, }, @@ -871,6 +871,23 @@ impl ZoneConnection { .await; } + pub async fn update_config(&mut self, actor_id: u32, config: Config) { + let ipc = ServerZoneIpcSegment { + op_code: ServerZoneIpcType::Config, + timestamp: timestamp_secs(), + data: ServerZoneIpcData::Config(config), + ..Default::default() + }; + + self.send_segment(PacketSegment { + source_actor: actor_id, + target_actor: self.player_data.actor_id, + segment_type: SegmentType::Ipc, + data: SegmentData::Ipc { data: ipc }, + }) + .await; + } + pub fn get_player_common_spawn( &self, exit_position: Option, diff --git a/src/world/server.rs b/src/world/server.rs index 54b7540..994356a 100644 --- a/src/world/server.rs +++ b/src/world/server.rs @@ -589,6 +589,18 @@ pub async fn server_main_loop(mut recv: Receiver) -> Result<(), std::i }); } } + ToServer::Config(_from_id, from_actor_id, config) => { + let mut data = data.lock().unwrap(); + for (id, (handle, _)) in &mut data.clients { + let id = *id; + + let msg = FromServer::UpdateConfig(from_actor_id, config.clone()); + + if handle.send(msg).is_err() { + to_remove.push(id); + } + } + } ToServer::Disconnected(from_id) => { let mut data = data.lock().unwrap();