1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-07-09 15:37:45 +00:00

Refactor lua.rs: (#109)

-The match has been moved into src/ipc/zone/event_scene.rs and slimmed down
-EventScene now provides a function to decide the opcode based on how many params it has
-The tests for EventScene were updated to acommodate the new changes
This commit is contained in:
thedax 2025-07-08 21:18:30 +00:00 committed by GitHub
parent 0cf359e8c9
commit 22dc1dbaaa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 142 additions and 147 deletions

View file

@ -1,11 +1,14 @@
use binrw::binrw;
use crate::common::ObjectTypeId;
use crate::ipc::zone::{ServerZoneIpcData, ServerZoneIpcType};
#[derive(Debug, Clone)]
#[binrw]
#[brw(little)]
#[derive(Debug, Clone)]
pub struct EventScene<const MAX_PARAMS: usize> {
#[brw(import{max_params: usize})]
#[brw(assert(params.len() <= max_params, "Too many params! {} > {}", params.len(), max_params))]
pub struct EventScene {
pub actor_id: ObjectTypeId,
pub event_id: u32,
pub scene: u16,
@ -15,10 +18,12 @@ pub struct EventScene<const MAX_PARAMS: usize> {
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; MAX_PARAMS],
#[br(count = max_params)]
#[bw(pad_size_to = 4 * max_params)]
pub params: Vec<u32>,
}
impl<const MAX_PARAMS: usize> Default for EventScene<{ MAX_PARAMS }> {
impl Default for EventScene {
fn default() -> Self {
Self {
actor_id: ObjectTypeId::default(),
@ -27,11 +32,58 @@ impl<const MAX_PARAMS: usize> Default for EventScene<{ MAX_PARAMS }> {
scene_flags: 0,
unk1: 0,
params_count: 0,
params: [0u32; MAX_PARAMS],
params: Vec::<u32>::new(),
}
}
}
impl EventScene {
pub fn package_scene(&self) -> Option<(ServerZoneIpcType, ServerZoneIpcData)> {
let op_code;
let data;
match self.params.len() {
// TODO: it would be nice to avoid cloning if possible
0..=2 => {
op_code = ServerZoneIpcType::EventScene;
data = ServerZoneIpcData::EventScene { data: self.clone() };
}
3..=4 => {
op_code = ServerZoneIpcType::EventScene4;
data = ServerZoneIpcData::EventScene4 { data: self.clone() };
}
5..=8 => {
op_code = ServerZoneIpcType::EventScene8;
data = ServerZoneIpcData::EventScene8 { data: self.clone() };
}
9..=16 => {
op_code = ServerZoneIpcType::EventScene16;
data = ServerZoneIpcData::EventScene16 { data: self.clone() };
}
17..=32 => {
op_code = ServerZoneIpcType::EventScene32;
data = ServerZoneIpcData::EventScene32 { data: self.clone() };
}
33..=64 => {
op_code = ServerZoneIpcType::EventScene64;
data = ServerZoneIpcData::EventScene64 { data: self.clone() };
}
65..=128 => {
op_code = ServerZoneIpcType::EventScene128;
data = ServerZoneIpcData::EventScene128 { data: self.clone() };
}
129..255 => {
op_code = ServerZoneIpcType::EventScene255;
data = ServerZoneIpcData::EventScene255 { data: self.clone() };
}
_ => {
return None;
}
}
Some((op_code, data))
}
}
#[cfg(test)]
mod tests {
use std::{fs::read, io::Cursor, path::PathBuf};
@ -50,7 +102,8 @@ mod tests {
let buffer = read(d).unwrap();
let mut buffer = Cursor::new(&buffer);
let event_play = EventScene::<2>::read_le(&mut buffer).unwrap();
let event_play =
EventScene::read_le_args(&mut buffer, EventSceneBinReadArgs { max_params: 2 }).unwrap();
assert_eq!(
event_play.actor_id,
ObjectTypeId {

View file

@ -252,21 +252,53 @@ pub enum ServerZoneIpcData {
ContainerInfo(ContainerInfo),
/// Sent to tell the client to play a scene
#[br(pre_assert(*magic == ServerZoneIpcType::EventScene))]
EventScene(EventScene<2>),
#[brw(little)]
EventScene {
#[brw(args { max_params: 2 } )]
data: EventScene,
},
#[br(pre_assert(*magic == ServerZoneIpcType::EventScene4))]
EventScene4(EventScene<4>),
#[brw(little)]
EventScene4 {
#[brw(args { max_params: 4 } )]
data: EventScene,
},
#[br(pre_assert(*magic == ServerZoneIpcType::EventScene8))]
EventScene8(EventScene<8>),
#[brw(little)]
EventScene8 {
#[brw(args { max_params: 8 } )]
data: EventScene,
},
#[br(pre_assert(*magic == ServerZoneIpcType::EventScene16))]
EventScene16(EventScene<16>),
#[brw(little)]
EventScene16 {
#[brw(args { max_params: 16 } )]
data: EventScene,
},
#[br(pre_assert(*magic == ServerZoneIpcType::EventScene32))]
EventScene32(EventScene<32>),
#[brw(little)]
EventScene32 {
#[brw(args { max_params: 32 } )]
data: EventScene,
},
#[br(pre_assert(*magic == ServerZoneIpcType::EventScene64))]
EventScene64(EventScene<64>),
#[brw(little)]
EventScene64 {
#[brw(args { max_params: 64 } )]
data: EventScene,
},
#[br(pre_assert(*magic == ServerZoneIpcType::EventScene128))]
EventScene128(EventScene<128>),
#[brw(little)]
EventScene128 {
#[brw(args { max_params: 128 } )]
data: EventScene,
},
#[br(pre_assert(*magic == ServerZoneIpcType::EventScene255))]
EventScene255(EventScene<255>),
#[brw(little)]
EventScene255 {
#[brw(args { max_params: 255 } )]
data: EventScene,
},
/// Sent to tell the client to load a scene, but not play it
#[br(pre_assert(*magic == ServerZoneIpcType::EventStart))]
EventStart(EventStart),
@ -651,35 +683,51 @@ mod tests {
),
(
ServerZoneIpcType::EventScene,
ServerZoneIpcData::EventScene(EventScene::default()),
ServerZoneIpcData::EventScene {
data: EventScene::default(),
},
),
(
ServerZoneIpcType::EventScene4,
ServerZoneIpcData::EventScene4(EventScene::<4>::default()),
ServerZoneIpcData::EventScene4 {
data: EventScene::default(),
},
),
(
ServerZoneIpcType::EventScene8,
ServerZoneIpcData::EventScene8(EventScene::<8>::default()),
ServerZoneIpcData::EventScene8 {
data: EventScene::default(),
},
),
(
ServerZoneIpcType::EventScene16,
ServerZoneIpcData::EventScene16(EventScene::<16>::default()),
ServerZoneIpcData::EventScene16 {
data: EventScene::default(),
},
),
(
ServerZoneIpcType::EventScene32,
ServerZoneIpcData::EventScene32(EventScene::<32>::default()),
ServerZoneIpcData::EventScene32 {
data: EventScene::default(),
},
),
(
ServerZoneIpcType::EventScene64,
ServerZoneIpcData::EventScene64(EventScene::<64>::default()),
ServerZoneIpcData::EventScene64 {
data: EventScene::default(),
},
),
(
ServerZoneIpcType::EventScene128,
ServerZoneIpcData::EventScene128(EventScene::<128>::default()),
ServerZoneIpcData::EventScene128 {
data: EventScene::default(),
},
),
(
ServerZoneIpcType::EventScene255,
ServerZoneIpcData::EventScene255(EventScene::<255>::default()),
ServerZoneIpcData::EventScene255 {
data: EventScene::default(),
},
),
(
ServerZoneIpcType::EventStart,

View file

@ -125,131 +125,26 @@ impl LuaPlayer {
event_id: u32,
scene: u16,
scene_flags: u32,
params: &[u32],
params: Vec<u32>,
) {
let op_code;
let data;
match params.len() {
// TODO: it would be nice to de-duplicate these
0..=2 => {
let mut scene = EventScene {
actor_id: target,
event_id,
scene,
scene_flags,
params_count: params.len() as u8,
..Default::default()
};
scene.params[..params.len()].copy_from_slice(&params[0..params.len()]);
let scene = EventScene {
actor_id: target,
event_id,
scene,
scene_flags,
params_count: params.len() as u8,
params: params.clone(),
..Default::default()
};
op_code = ServerZoneIpcType::EventScene;
data = ServerZoneIpcData::EventScene(scene);
}
3..=4 => {
let mut scene = EventScene::<4> {
actor_id: target,
event_id,
scene,
scene_flags,
params_count: params.len() as u8,
..Default::default()
};
scene.params[..params.len()].copy_from_slice(&params[0..params.len()]);
op_code = ServerZoneIpcType::EventScene4;
data = ServerZoneIpcData::EventScene4(scene);
}
5..=8 => {
let mut scene = EventScene::<8> {
actor_id: target,
event_id,
scene,
scene_flags,
params_count: params.len() as u8,
..Default::default()
};
scene.params[..params.len()].copy_from_slice(&params[0..params.len()]);
op_code = ServerZoneIpcType::EventScene8;
data = ServerZoneIpcData::EventScene8(scene);
}
9..=16 => {
let mut scene = EventScene::<16> {
actor_id: target,
event_id,
scene,
scene_flags,
params_count: params.len() as u8,
..Default::default()
};
scene.params[..params.len()].copy_from_slice(&params[0..params.len()]);
op_code = ServerZoneIpcType::EventScene16;
data = ServerZoneIpcData::EventScene16(scene);
}
17..=32 => {
let mut scene = EventScene::<32> {
actor_id: target,
event_id,
scene,
scene_flags,
params_count: params.len() as u8,
..Default::default()
};
scene.params[..params.len()].copy_from_slice(&params[0..params.len()]);
op_code = ServerZoneIpcType::EventScene32;
data = ServerZoneIpcData::EventScene32(scene);
}
33..=64 => {
let mut scene = EventScene::<64> {
actor_id: target,
event_id,
scene,
scene_flags,
params_count: params.len() as u8,
..Default::default()
};
scene.params.copy_from_slice(&params[0..params.len()]);
op_code = ServerZoneIpcType::EventScene64;
data = ServerZoneIpcData::EventScene64(scene);
}
65..=128 => {
let mut scene = EventScene::<128> {
actor_id: target,
event_id,
scene,
scene_flags,
params_count: params.len() as u8,
..Default::default()
};
scene.params[..params.len()].copy_from_slice(&params[0..params.len()]);
op_code = ServerZoneIpcType::EventScene128;
data = ServerZoneIpcData::EventScene128(scene);
}
129..255 => {
let mut scene = EventScene::<255> {
actor_id: target,
event_id,
scene,
scene_flags,
params_count: params.len() as u8,
..Default::default()
};
scene.params[..params.len()].copy_from_slice(&params[0..params.len()]);
op_code = ServerZoneIpcType::EventScene255;
data = ServerZoneIpcData::EventScene255(scene);
}
_ => {
tracing::warn!("Unsupported amount of parameters in play_scene!");
return;
}
if let Some((op_code, data)) = scene.package_scene() {
self.create_segment_self(op_code, data);
} else {
let error_message = "Unsupported amount of parameters in play_scene! This is likely a bug in your script! Cancelling event...".to_string();
tracing::warn!(error_message);
self.send_message(&error_message, 0);
self.finish_event(event_id);
}
self.create_segment_self(op_code, data);
}
fn set_position(&mut self, position: Position, rotation: f32) {
@ -404,7 +299,7 @@ impl UserData for LuaPlayer {
u32,
Vec<u32>,
)| {
this.play_scene(target, event_id, scene, scene_flags, &params);
this.play_scene(target, event_id, scene, scene_flags, params);
Ok(())
},
);

View file

@ -324,8 +324,7 @@ pub async fn server_main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::i
}
}
if let ClientTriggerCommand::EventRelatedUnk { .. } = &trigger.trigger
{
if let ClientTriggerCommand::EventRelatedUnk { .. } = &trigger.trigger {
let msg = FromServer::ActorControlSelf(ActorControlSelf {
category: ActorControlCategory::EventRelatedUnk1 { unk1: 1 },
});