From 0d7bca06715297933f8502af8d9906cfe547979c Mon Sep 17 00:00:00 2001 From: Neloreck Date: Sun, 25 Feb 2024 05:59:28 +0200 Subject: [PATCH] Test helicopter and hanging lamp objects. Implement write operations. --- .../alife_object_hanging_lamp.chunk | Bin 0 -> 242 bytes .../alife_object_helicopter.chunk | Bin 0 -> 119 bytes .../data/alife/alife_object_hanging_lamp.rs | 124 +++++++++++++++++- .../src/data/alife/alife_object_helicopter.rs | 87 +++++++++++- 4 files changed, 208 insertions(+), 3 deletions(-) create mode 100644 crates/xray-db/resources/tests/chunks/alife_object_hanging_lamp/alife_object_hanging_lamp.chunk create mode 100644 crates/xray-db/resources/tests/chunks/alife_object_helicopter/alife_object_helicopter.chunk diff --git a/crates/xray-db/resources/tests/chunks/alife_object_hanging_lamp/alife_object_hanging_lamp.chunk b/crates/xray-db/resources/tests/chunks/alife_object_hanging_lamp/alife_object_hanging_lamp.chunk new file mode 100644 index 0000000000000000000000000000000000000000..78ca5e3fb3eba19ec3055383fb413882ebd3963a GIT binary patch literal 242 zcmZQzU|@I!#QY5ZCcJa~3uHC$GB79s>EzPllKfoVl*E!m25)HwhDrPk3}uh6qBY5&9l1wBxYSS|Hg|*xnw^VvD)POp?0dKCA{0j E2hg@9p8x;= literal 0 HcmV?d00001 diff --git a/crates/xray-db/src/data/alife/alife_object_hanging_lamp.rs b/crates/xray-db/src/data/alife/alife_object_hanging_lamp.rs index efa7343..cd49666 100644 --- a/crates/xray-db/src/data/alife/alife_object_hanging_lamp.rs +++ b/crates/xray-db/src/data/alife/alife_object_hanging_lamp.rs @@ -5,9 +5,10 @@ use crate::data::alife::alife_object_inherited_reader::{ }; use crate::data::alife::alife_object_skeleton::AlifeObjectSkeleton; use crate::data::alife::alife_object_visual::AlifeObjectVisual; -use byteorder::{ByteOrder, ReadBytesExt}; +use byteorder::{ByteOrder, ReadBytesExt, WriteBytesExt}; use std::io; +#[derive(Clone, Debug, PartialEq)] pub struct AlifeObjectHangingLamp { pub base: AlifeObjectVisual, pub skeleton: AlifeObjectSkeleton, @@ -35,6 +36,7 @@ pub struct AlifeObjectHangingLamp { } impl AlifeObjectInheritedReader for AlifeObjectHangingLamp { + /// Read hanging lamp data from the chunk. fn read_from_chunk(chunk: &mut Chunk) -> io::Result { let base: AlifeObjectVisual = AlifeObjectVisual::read_from_chunk::(chunk)?; let skeleton: AlifeObjectSkeleton = AlifeObjectSkeleton::read_from_chunk::(chunk)?; @@ -90,9 +92,127 @@ impl AlifeObjectInheritedReader for AlifeObjectHangingLa }) } + /// Write skeleton data into the writer. fn write(&self, writer: &mut ChunkWriter) -> io::Result<()> { - todo!("Implement write operation"); + self.base.write::(writer)?; + self.skeleton.write::(writer)?; + + writer.write_u32::(self.main_color)?; + writer.write_f32::(self.main_brightness)?; + writer.write_null_terminated_string(&self.color_animator)?; + writer.write_f32::(self.main_range)?; + writer.write_u16::(self.light_flags)?; + writer.write_null_terminated_string(&self.startup_animation)?; + writer.write_null_terminated_string(&self.fixed_bones)?; + writer.write_f32::(self.health)?; + + writer.write_f32::(self.virtual_size)?; + writer.write_f32::(self.ambient_radius)?; + writer.write_f32::(self.ambient_power)?; + writer.write_null_terminated_string(&self.ambient_texture)?; + writer.write_null_terminated_string(&self.light_texture)?; + writer.write_null_terminated_string(&self.light_bone)?; + writer.write_f32::(self.spot_cone_angle)?; + writer.write_null_terminated_string(&self.glow_texture)?; + writer.write_f32::(self.glow_radius)?; + + writer.write_null_terminated_string(&self.light_ambient_bone)?; + writer.write_f32::(self.volumetric_quality)?; + writer.write_f32::(self.volumetric_intensity)?; + writer.write_f32::(self.volumetric_distance)?; + + Ok(()) } } impl AlifeObjectGeneric for AlifeObjectHangingLamp {} + +#[cfg(test)] +mod tests { + use crate::chunk::chunk::Chunk; + use crate::chunk::writer::ChunkWriter; + use crate::data::alife::alife_object_abstract::AlifeObjectAbstract; + use crate::data::alife::alife_object_hanging_lamp::AlifeObjectHangingLamp; + use crate::data::alife::alife_object_inherited_reader::AlifeObjectInheritedReader; + use crate::data::alife::alife_object_skeleton::AlifeObjectSkeleton; + use crate::data::alife::alife_object_visual::AlifeObjectVisual; + use crate::test::utils::{ + get_test_chunk_file_sub_dir, open_test_resource_as_slice, overwrite_test_resource_as_file, + }; + use crate::types::SpawnByteOrder; + use fileslice::FileSlice; + use std::io; + + #[test] + fn test_read_write_object() -> io::Result<()> { + let mut writer: ChunkWriter = ChunkWriter::new(); + let filename: String = + get_test_chunk_file_sub_dir(file!(), &String::from("alife_object_hanging_lamp.chunk")); + + let object: AlifeObjectHangingLamp = AlifeObjectHangingLamp { + base: AlifeObjectVisual { + base: AlifeObjectAbstract { + game_vertex_id: 15, + distance: 7634.124, + direct_control: 253, + level_vertex_id: 3456, + flags: 34, + custom_data: String::from("custom-data"), + story_id: 6987, + spawn_story_id: 3986, + }, + visual_name: String::from("visual-name"), + visual_flags: 168, + }, + skeleton: AlifeObjectSkeleton { + name: String::from("skeleton-name"), + flags: 0, + source_id: 978, + }, + main_color: 52323, + main_brightness: 1.0, + color_animator: String::from("color-animator"), + main_range: 0.5, + light_flags: 425, + startup_animation: String::from("setup-animation"), + fixed_bones: String::from("fixed-bones"), + health: 1.0, + virtual_size: 0.7, + ambient_radius: 24.0, + ambient_power: 52.0, + ambient_texture: String::from("ambient-texture"), + light_texture: String::from("light-texture"), + light_bone: String::from("light-bone"), + spot_cone_angle: 5.23, + glow_texture: String::from("glow-texture"), + glow_radius: 15.43, + light_ambient_bone: String::from("light-ambient-bone"), + volumetric_quality: 1.3, + volumetric_intensity: 2.2, + volumetric_distance: 3.1, + }; + + object.write::(&mut writer)?; + + assert_eq!(writer.bytes_written(), 234); + + let bytes_written: usize = writer.flush_chunk_into_file::( + &mut overwrite_test_resource_as_file(&filename)?, + 0, + )?; + + assert_eq!(bytes_written, 234); + + let file: FileSlice = open_test_resource_as_slice(&filename)?; + + assert_eq!(file.bytes_remaining(), 234 + 8); + + let mut chunk: Chunk = Chunk::from_file(file)?.read_child_by_index(0)?; + let read_object: AlifeObjectHangingLamp = + AlifeObjectHangingLamp::read_from_chunk::(&mut chunk)?; + + assert_eq!(read_object, object); + + Ok(()) + } +} diff --git a/crates/xray-db/src/data/alife/alife_object_helicopter.rs b/crates/xray-db/src/data/alife/alife_object_helicopter.rs index c82664e..fbef378 100644 --- a/crates/xray-db/src/data/alife/alife_object_helicopter.rs +++ b/crates/xray-db/src/data/alife/alife_object_helicopter.rs @@ -9,6 +9,7 @@ use crate::data::alife::alife_object_visual::AlifeObjectVisual; use byteorder::ByteOrder; use std::io; +#[derive(Clone, Debug, PartialEq)] pub struct AlifeObjectHelicopter { pub base: AlifeObjectVisual, pub skeleton: AlifeObjectSkeleton, @@ -18,6 +19,7 @@ pub struct AlifeObjectHelicopter { } impl AlifeObjectInheritedReader for AlifeObjectHelicopter { + /// Read helicopter data from the chunk. fn read_from_chunk(chunk: &mut Chunk) -> io::Result { let base: AlifeObjectVisual = AlifeObjectVisual::read_from_chunk::(chunk)?; let motion: AlifeObjectMotion = AlifeObjectMotion::read_from_chunk::(chunk)?; @@ -35,9 +37,92 @@ impl AlifeObjectInheritedReader for AlifeObjectHelicopter }) } + /// Write helicopter data into the chunk. fn write(&self, writer: &mut ChunkWriter) -> io::Result<()> { - todo!("Implement write operation"); + self.base.write::(writer)?; + self.motion.write::(writer)?; + self.skeleton.write::(writer)?; + + writer.write_null_terminated_string(&self.startup_animation)?; + writer.write_null_terminated_string(&self.engine_sound)?; + + Ok(()) } } impl AlifeObjectGeneric for AlifeObjectHelicopter {} + +#[cfg(test)] +mod tests { + use crate::chunk::chunk::Chunk; + use crate::chunk::writer::ChunkWriter; + use crate::data::alife::alife_object_abstract::AlifeObjectAbstract; + use crate::data::alife::alife_object_helicopter::AlifeObjectHelicopter; + use crate::data::alife::alife_object_inherited_reader::AlifeObjectInheritedReader; + use crate::data::alife::alife_object_motion::AlifeObjectMotion; + use crate::data::alife::alife_object_skeleton::AlifeObjectSkeleton; + use crate::data::alife::alife_object_visual::AlifeObjectVisual; + use crate::test::utils::{ + get_test_chunk_file_sub_dir, open_test_resource_as_slice, overwrite_test_resource_as_file, + }; + use crate::types::SpawnByteOrder; + use fileslice::FileSlice; + use std::io; + + #[test] + fn test_read_write_object() -> io::Result<()> { + let mut writer: ChunkWriter = ChunkWriter::new(); + let filename: String = + get_test_chunk_file_sub_dir(file!(), &String::from("alife_object_helicopter.chunk")); + + let object: AlifeObjectHelicopter = AlifeObjectHelicopter { + base: AlifeObjectVisual { + base: AlifeObjectAbstract { + game_vertex_id: 6432, + distance: 243.53, + direct_control: 25364, + level_vertex_id: 3541, + flags: 43, + custom_data: String::from("custom-data"), + story_id: 64353, + spawn_story_id: 2533, + }, + visual_name: String::from("visual-name"), + visual_flags: 43, + }, + skeleton: AlifeObjectSkeleton { + name: String::from("skeleton-name"), + flags: 0, + source_id: 235, + }, + motion: AlifeObjectMotion { + motion_name: String::from("motion-name"), + }, + startup_animation: String::from("startup-animation"), + engine_sound: String::from("engine-sound"), + }; + + object.write::(&mut writer)?; + + assert_eq!(writer.bytes_written(), 111); + + let bytes_written: usize = writer.flush_chunk_into_file::( + &mut overwrite_test_resource_as_file(&filename)?, + 0, + )?; + + assert_eq!(bytes_written, 111); + + let file: FileSlice = open_test_resource_as_slice(&filename)?; + + assert_eq!(file.bytes_remaining(), 111 + 8); + + let mut chunk: Chunk = Chunk::from_file(file)?.read_child_by_index(0)?; + let read_object: AlifeObjectHelicopter = + AlifeObjectHelicopter::read_from_chunk::(&mut chunk)?; + + assert_eq!(read_object, object); + + Ok(()) + } +}