diff --git a/resources/opcodes.json b/resources/opcodes.json index 22b02eb..ca257ef 100644 --- a/resources/opcodes.json +++ b/resources/opcodes.json @@ -308,10 +308,15 @@ "size": 16 }, { - "name": "EventHandlerReturn", + "name": "EventYieldHandler", "opcode": 840, "size": 16 }, + { + "name": "EventYieldHandler8", + "opcode": 441, + "size": 40 + }, { "name": "Config", "opcode": 534, diff --git a/src/bin/kawari-world.rs b/src/bin/kawari-world.rs index 4c3ed43..bb78fe5 100644 --- a/src/bin/kawari-world.rs +++ b/src/bin/kawari-world.rs @@ -838,14 +838,23 @@ async fn client_loop( connection.send_message(&*format!("Event {event_id} tried to start, but it doesn't have a script associated with it!")).await; } } - ClientZoneIpcData::EventHandlerReturn { handler_id, scene, error_code, num_results, params } => { - tracing::info!("Finishing this event... {handler_id} {error_code} {scene} {:?}", ¶ms[..*num_results as usize]); + ClientZoneIpcData::EventYieldHandler(handler) => { + tracing::info!("Finishing this event... {} {} {} {:?}", handler.handler_id, handler.error_code, handler.scene, &handler.params[..handler.num_results as usize]); connection .event - .as_mut() - .unwrap() - .finish(*scene, ¶ms[..*num_results as usize], &mut lua_player); + .as_mut() + .unwrap() + .finish(handler.scene, &handler.params[..handler.num_results as usize], &mut lua_player); + } + ClientZoneIpcData::EventYieldHandler8(handler) => { + tracing::info!("Finishing this event... {} {} {} {:?}", handler.handler_id, handler.error_code, handler.scene, &handler.params[..handler.num_results as usize]); + + connection + .event + .as_mut() + .unwrap() + .finish(handler.scene, &handler.params[..handler.num_results as usize], &mut lua_player); } ClientZoneIpcData::Config(config) => { connection diff --git a/src/ipc/zone/event_scene.rs b/src/ipc/zone/event_scene.rs index 41abce2..d0fc38b 100644 --- a/src/ipc/zone/event_scene.rs +++ b/src/ipc/zone/event_scene.rs @@ -4,8 +4,8 @@ use crate::common::ObjectTypeId; #[binrw] #[brw(little)] -#[derive(Debug, Clone, Default)] -pub struct EventScene { +#[derive(Debug, Clone)] +pub struct EventScene { pub actor_id: ObjectTypeId, pub event_id: u32, pub scene: u16, @@ -15,7 +15,21 @@ pub struct EventScene { pub params_count: u8, // Extra padding seems needed after or the client will seemingly softlock even with 2 params, possibly used for alignment? #[brw(pad_before = 3, pad_after = 4)] - pub params: [u32; 2], + pub params: [u32; MAX_PARAMS], +} + +impl Default for EventScene<{ MAX_PARAMS }> { + fn default() -> Self { + Self { + actor_id: ObjectTypeId::default(), + event_id: 0, + scene: 0, + scene_flags: 0, + unk1: 0, + params_count: 0, + params: [0u32; MAX_PARAMS], + } + } } #[cfg(test)] @@ -36,7 +50,7 @@ mod tests { let buffer = read(d).unwrap(); let mut buffer = Cursor::new(&buffer); - let event_play = EventScene::read_le(&mut buffer).unwrap(); + let event_play = EventScene::<2>::read_le(&mut buffer).unwrap(); assert_eq!( event_play.actor_id, ObjectTypeId { diff --git a/src/ipc/zone/event_yield_handler.rs b/src/ipc/zone/event_yield_handler.rs new file mode 100644 index 0000000..b902687 --- /dev/null +++ b/src/ipc/zone/event_yield_handler.rs @@ -0,0 +1,24 @@ +use binrw::binrw; + +#[binrw] +#[brw(little)] +#[derive(Debug, Clone)] +pub struct EventYieldHandler { + pub handler_id: u32, + pub scene: u16, + pub error_code: u8, + pub num_results: u8, + pub params: [i32; MAX_PARAMS], +} + +impl Default for EventYieldHandler<{ MAX_PARAMS }> { + fn default() -> Self { + Self { + handler_id: 0, + scene: 0, + error_code: 0, + num_results: 0, + params: [0i32; MAX_PARAMS], + } + } +} diff --git a/src/ipc/zone/mod.rs b/src/ipc/zone/mod.rs index cf3e77b..fe15806 100644 --- a/src/ipc/zone/mod.rs +++ b/src/ipc/zone/mod.rs @@ -85,6 +85,9 @@ pub use currency_info::CurrencyInfo; mod config; pub use config::Config; +mod event_yield_handler; +pub use event_yield_handler::EventYieldHandler; + use crate::common::ObjectTypeId; use crate::common::Position; use crate::common::read_string; @@ -241,7 +244,7 @@ pub enum ServerZoneIpcData { ContainerInfo(ContainerInfo), /// Sent to tell the client to play a scene #[br(pre_assert(*magic == ServerZoneIpcType::EventScene))] - EventScene(EventScene), + EventScene(EventScene<2>), /// Sent to tell the client to load a scene, but not play it #[br(pre_assert(*magic == ServerZoneIpcType::EventStart))] EventStart(EventStart), @@ -438,15 +441,10 @@ pub enum ClientZoneIpcData { #[brw(pad_after = 4)] // padding event_id: u32, }, - #[br(pre_assert(*magic == ClientZoneIpcType::EventHandlerReturn))] - EventHandlerReturn { - // TODO: This is actually EventYieldHandler - handler_id: u32, - scene: u16, - error_code: u8, - num_results: u8, - params: [i32; 2], - }, + #[br(pre_assert(*magic == ClientZoneIpcType::EventYieldHandler))] + EventYieldHandler(EventYieldHandler<2>), + #[br(pre_assert(*magic == ClientZoneIpcType::EventYieldHandler8))] + EventYieldHandler8(EventYieldHandler<8>), #[br(pre_assert(*magic == ClientZoneIpcType::Config))] Config(Config), #[br(pre_assert(*magic == ClientZoneIpcType::EventUnkRequest))] @@ -475,7 +473,7 @@ mod tests { /// Ensure that the IPC data size as reported matches up with what we write #[test] - fn world_ipc_sizes() { + fn server_zone_ipc_sizes() { let ipc_types = [ ( ServerZoneIpcType::InitResponse, @@ -605,4 +603,36 @@ mod tests { ); } } + + /// Ensure that the IPC data size as reported matches up with what we write + #[test] + fn client_zone_ipc_sizes() { + let ipc_types = [( + ClientZoneIpcType::EventYieldHandler8, + ClientZoneIpcData::EventYieldHandler8(EventYieldHandler::<8>::default()), + )]; + + 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 + ); + } + } }