diff --git a/crates/xray-db/resources/tests/chunks/alife_object_inventory_box/alife_object_inventory_box.chunk b/crates/xray-db/resources/tests/chunks/alife_object_inventory_box/alife_object_inventory_box.chunk new file mode 100644 index 0000000..460cd9b Binary files /dev/null and b/crates/xray-db/resources/tests/chunks/alife_object_inventory_box/alife_object_inventory_box.chunk differ diff --git a/crates/xray-db/resources/tests/chunks/alife_object_item_weapon_magazined/alife_object_item_weapon_magazined.chunk b/crates/xray-db/resources/tests/chunks/alife_object_item_weapon_magazined/alife_object_item_weapon_magazined.chunk new file mode 100644 index 0000000..a41a32a Binary files /dev/null and b/crates/xray-db/resources/tests/chunks/alife_object_item_weapon_magazined/alife_object_item_weapon_magazined.chunk differ diff --git a/crates/xray-db/resources/tests/chunks/alife_object_item_weapon_magazined_wgl/alife_object_item_weapon_magazined_wgl.chunk b/crates/xray-db/resources/tests/chunks/alife_object_item_weapon_magazined_wgl/alife_object_item_weapon_magazined_wgl.chunk new file mode 100644 index 0000000..37903f5 Binary files /dev/null and b/crates/xray-db/resources/tests/chunks/alife_object_item_weapon_magazined_wgl/alife_object_item_weapon_magazined_wgl.chunk differ diff --git a/crates/xray-db/resources/tests/chunks/alife_object_item_weapon_shotgun/alife_object_item_weapon_shotgun.chunk b/crates/xray-db/resources/tests/chunks/alife_object_item_weapon_shotgun/alife_object_item_weapon_shotgun.chunk new file mode 100644 index 0000000..13903f3 Binary files /dev/null and b/crates/xray-db/resources/tests/chunks/alife_object_item_weapon_shotgun/alife_object_item_weapon_shotgun.chunk differ diff --git a/crates/xray-db/src/data/alife/alife_object_inventory_box.rs b/crates/xray-db/src/data/alife/alife_object_inventory_box.rs index 02ec5f6..fda947c 100644 --- a/crates/xray-db/src/data/alife/alife_object_inventory_box.rs +++ b/crates/xray-db/src/data/alife/alife_object_inventory_box.rs @@ -4,7 +4,7 @@ use crate::data::alife::alife_object_inherited_reader::{ AlifeObjectGeneric, AlifeObjectInheritedReader, }; use crate::data::alife::alife_object_visual::AlifeObjectVisual; -use byteorder::{ByteOrder, ReadBytesExt}; +use byteorder::{ByteOrder, ReadBytesExt, WriteBytesExt}; use std::io; #[derive(Clone, Debug, PartialEq)] @@ -16,6 +16,7 @@ pub struct AlifeObjectInventoryBox { } impl AlifeObjectInheritedReader for AlifeObjectInventoryBox { + /// Read inventory object data from the chunk. fn read_from_chunk(chunk: &mut Chunk) -> io::Result { let base: AlifeObjectVisual = AlifeObjectVisual::read_from_chunk::(chunk)?; @@ -31,9 +32,82 @@ impl AlifeObjectInheritedReader for AlifeObjectInventor }) } + /// Write inventory object data into the writer. fn write(&self, writer: &mut ChunkWriter) -> io::Result<()> { - todo!("Implement write operation"); + self.base.write::(writer)?; + + writer.write_u8(self.can_take)?; + writer.write_u8(self.is_closed)?; + writer.write_null_terminated_string(&self.tip)?; + + Ok(()) } } impl AlifeObjectGeneric for AlifeObjectInventoryBox {} + +#[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_inherited_reader::AlifeObjectInheritedReader; + use crate::data::alife::alife_object_inventory_box::AlifeObjectInventoryBox; + 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_inventory_box.chunk")); + + let object: AlifeObjectInventoryBox = AlifeObjectInventoryBox { + base: AlifeObjectVisual { + base: AlifeObjectAbstract { + game_vertex_id: 0, + distance: 0.0, + direct_control: 0, + level_vertex_id: 0, + flags: 0, + custom_data: "".to_string(), + story_id: 0, + spawn_story_id: 0, + }, + visual_name: "".to_string(), + visual_flags: 0, + }, + can_take: 0, + is_closed: 0, + tip: "".to_string(), + }; + + object.write::(&mut writer)?; + + assert_eq!(writer.bytes_written(), 32); + + let bytes_written: usize = writer.flush_chunk_into_file::( + &mut overwrite_test_resource_as_file(&filename)?, + 0, + )?; + + assert_eq!(bytes_written, 32); + + let file: FileSlice = open_test_resource_as_slice(&filename)?; + + assert_eq!(file.bytes_remaining(), 32 + 8); + + let mut chunk: Chunk = Chunk::from_file(file)?.read_child_by_index(0)?; + let read_object: AlifeObjectInventoryBox = + AlifeObjectInventoryBox::read_from_chunk::(&mut chunk)?; + + assert_eq!(read_object, object); + + Ok(()) + } +} diff --git a/crates/xray-db/src/data/alife/alife_object_item_weapon_magazined.rs b/crates/xray-db/src/data/alife/alife_object_item_weapon_magazined.rs index 11f5a3e..6e1b146 100644 --- a/crates/xray-db/src/data/alife/alife_object_item_weapon_magazined.rs +++ b/crates/xray-db/src/data/alife/alife_object_item_weapon_magazined.rs @@ -7,11 +7,13 @@ use crate::data::alife::alife_object_item_weapon::AlifeObjectItemWeapon; use byteorder::ByteOrder; use std::io; +#[derive(Clone, Debug, PartialEq)] pub struct AlifeObjectItemWeaponMagazined { pub base: AlifeObjectItemWeapon, } impl AlifeObjectInheritedReader for AlifeObjectItemWeaponMagazined { + /// Read magazined weapon data from the chunk. fn read_from_chunk( chunk: &mut Chunk, ) -> io::Result { @@ -20,9 +22,94 @@ impl AlifeObjectInheritedReader for AlifeObjectI Ok(AlifeObjectItemWeaponMagazined { base }) } + /// Write magazined weapon item into the writer. fn write(&self, writer: &mut ChunkWriter) -> io::Result<()> { - todo!("Implement write operation"); + self.base.write::(writer)?; + + Ok(()) } } impl AlifeObjectGeneric for AlifeObjectItemWeaponMagazined {} + +#[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_inherited_reader::AlifeObjectInheritedReader; + use crate::data::alife::alife_object_item::AlifeObjectItem; + use crate::data::alife::alife_object_item_weapon::AlifeObjectItemWeapon; + use crate::data::alife::alife_object_item_weapon_magazined::AlifeObjectItemWeaponMagazined; + use crate::data::alife::alife_object_item_weapon_magazined_wgl::AlifeObjectItemWeaponMagazinedWgl; + 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_item_weapon_magazined.chunk"), + ); + + let object: AlifeObjectItemWeaponMagazinedWgl = AlifeObjectItemWeaponMagazinedWgl { + base: AlifeObjectItemWeaponMagazined { + base: AlifeObjectItemWeapon { + base: AlifeObjectItem { + base: AlifeObjectVisual { + base: AlifeObjectAbstract { + game_vertex_id: 5232, + distance: 53.1213, + direct_control: 67, + level_vertex_id: 25313, + flags: 32, + custom_data: String::from("custom-data"), + story_id: 3486, + spawn_story_id: 37663, + }, + visual_name: String::from("visual-name"), + visual_flags: 33, + }, + condition: 1.0, + upgrades_count: 0, + }, + ammo_current: 20, + ammo_elapsed: 10, + weapon_state: 1, + addon_flags: 1, + ammo_type: 1, + elapsed_grenades: 0, + }, + }, + }; + + object.write::(&mut writer)?; + + assert_eq!(writer.bytes_written(), 67); + + let bytes_written: usize = writer.flush_chunk_into_file::( + &mut overwrite_test_resource_as_file(&filename)?, + 0, + )?; + + assert_eq!(bytes_written, 67); + + let file: FileSlice = open_test_resource_as_slice(&filename)?; + + assert_eq!(file.bytes_remaining(), 67 + 8); + + let mut chunk: Chunk = Chunk::from_file(file)?.read_child_by_index(0)?; + let read_object: AlifeObjectItemWeaponMagazinedWgl = + AlifeObjectItemWeaponMagazinedWgl::read_from_chunk::(&mut chunk)?; + + assert_eq!(read_object, object); + + Ok(()) + } +} diff --git a/crates/xray-db/src/data/alife/alife_object_item_weapon_magazined_wgl.rs b/crates/xray-db/src/data/alife/alife_object_item_weapon_magazined_wgl.rs index daa3683..82122c6 100644 --- a/crates/xray-db/src/data/alife/alife_object_item_weapon_magazined_wgl.rs +++ b/crates/xray-db/src/data/alife/alife_object_item_weapon_magazined_wgl.rs @@ -7,6 +7,7 @@ use crate::data::alife::alife_object_item_weapon_magazined::AlifeObjectItemWeapo use byteorder::ByteOrder; use std::io; +#[derive(Clone, Debug, PartialEq)] pub struct AlifeObjectItemWeaponMagazinedWgl { pub base: AlifeObjectItemWeaponMagazined, } @@ -14,6 +15,7 @@ pub struct AlifeObjectItemWeaponMagazinedWgl { impl AlifeObjectInheritedReader for AlifeObjectItemWeaponMagazinedWgl { + /// Read magazined weapon with launcher from the chunk. fn read_from_chunk( chunk: &mut Chunk, ) -> io::Result { @@ -23,9 +25,94 @@ impl AlifeObjectInheritedReader Ok(AlifeObjectItemWeaponMagazinedWgl { base }) } + /// Write magazined weapon with launcher data into the writer. fn write(&self, writer: &mut ChunkWriter) -> io::Result<()> { - todo!("Implement write operation"); + self.base.write::(writer)?; + + Ok(()) } } impl AlifeObjectGeneric for AlifeObjectItemWeaponMagazinedWgl {} + +#[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_inherited_reader::AlifeObjectInheritedReader; + use crate::data::alife::alife_object_item::AlifeObjectItem; + use crate::data::alife::alife_object_item_weapon::AlifeObjectItemWeapon; + use crate::data::alife::alife_object_item_weapon_magazined::AlifeObjectItemWeaponMagazined; + use crate::data::alife::alife_object_item_weapon_magazined_wgl::AlifeObjectItemWeaponMagazinedWgl; + 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_item_weapon_magazined_wgl.chunk"), + ); + + let object: AlifeObjectItemWeaponMagazinedWgl = AlifeObjectItemWeaponMagazinedWgl { + base: AlifeObjectItemWeaponMagazined { + base: AlifeObjectItemWeapon { + base: AlifeObjectItem { + base: AlifeObjectVisual { + base: AlifeObjectAbstract { + game_vertex_id: 2413, + distance: 53.1213, + direct_control: 3643, + level_vertex_id: 25313, + flags: 32, + custom_data: String::from("custom-data"), + story_id: 3486, + spawn_story_id: 37663, + }, + visual_name: String::from("visual-name"), + visual_flags: 36, + }, + condition: 1.0, + upgrades_count: 0, + }, + ammo_current: 20, + ammo_elapsed: 10, + weapon_state: 1, + addon_flags: 1, + ammo_type: 1, + elapsed_grenades: 0, + }, + }, + }; + + object.write::(&mut writer)?; + + assert_eq!(writer.bytes_written(), 67); + + let bytes_written: usize = writer.flush_chunk_into_file::( + &mut overwrite_test_resource_as_file(&filename)?, + 0, + )?; + + assert_eq!(bytes_written, 67); + + let file: FileSlice = open_test_resource_as_slice(&filename)?; + + assert_eq!(file.bytes_remaining(), 67 + 8); + + let mut chunk: Chunk = Chunk::from_file(file)?.read_child_by_index(0)?; + let read_object: AlifeObjectItemWeaponMagazinedWgl = + AlifeObjectItemWeaponMagazinedWgl::read_from_chunk::(&mut chunk)?; + + assert_eq!(read_object, object); + + Ok(()) + } +} diff --git a/crates/xray-db/src/data/alife/alife_object_item_weapon_shotgun.rs b/crates/xray-db/src/data/alife/alife_object_item_weapon_shotgun.rs index 7ebf8f8..f1dcddf 100644 --- a/crates/xray-db/src/data/alife/alife_object_item_weapon_shotgun.rs +++ b/crates/xray-db/src/data/alife/alife_object_item_weapon_shotgun.rs @@ -7,20 +7,104 @@ use crate::data::alife::alife_object_item_weapon::AlifeObjectItemWeapon; use byteorder::ByteOrder; use std::io; +#[derive(Clone, Debug, PartialEq)] pub struct AlifeObjectItemWeaponShotgun { pub base: AlifeObjectItemWeapon, } impl AlifeObjectInheritedReader for AlifeObjectItemWeaponShotgun { + /// Read shotgun object data from the chunk. fn read_from_chunk(chunk: &mut Chunk) -> io::Result { let base: AlifeObjectItemWeapon = AlifeObjectItemWeapon::read_from_chunk::(chunk)?; Ok(AlifeObjectItemWeaponShotgun { base }) } + /// Write shotgun object data into the writer. fn write(&self, writer: &mut ChunkWriter) -> io::Result<()> { - todo!("Implement write operation"); + self.base.write::(writer)?; + + Ok(()) } } impl AlifeObjectGeneric for AlifeObjectItemWeaponShotgun {} + +#[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_inherited_reader::AlifeObjectInheritedReader; + use crate::data::alife::alife_object_item::AlifeObjectItem; + use crate::data::alife::alife_object_item_weapon::AlifeObjectItemWeapon; + use crate::data::alife::alife_object_item_weapon_shotgun::AlifeObjectItemWeaponShotgun; + 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_item_weapon_shotgun.chunk"), + ); + + let object: AlifeObjectItemWeaponShotgun = AlifeObjectItemWeaponShotgun { + base: AlifeObjectItemWeapon { + base: AlifeObjectItem { + base: AlifeObjectVisual { + base: AlifeObjectAbstract { + game_vertex_id: 36426, + distance: 54.132, + direct_control: 441, + level_vertex_id: 23513, + flags: 33, + custom_data: String::from("custom-data"), + story_id: 35426, + spawn_story_id: 267845, + }, + visual_name: String::from("visual-name"), + visual_flags: 253, + }, + condition: 1.0, + upgrades_count: 0, + }, + ammo_current: 20, + ammo_elapsed: 10, + weapon_state: 3, + addon_flags: 36, + ammo_type: 1, + elapsed_grenades: 1, + }, + }; + + object.write::(&mut writer)?; + + assert_eq!(writer.bytes_written(), 67); + + let bytes_written: usize = writer.flush_chunk_into_file::( + &mut overwrite_test_resource_as_file(&filename)?, + 0, + )?; + + assert_eq!(bytes_written, 67); + + let file: FileSlice = open_test_resource_as_slice(&filename)?; + + assert_eq!(file.bytes_remaining(), 67 + 8); + + let mut chunk: Chunk = Chunk::from_file(file)?.read_child_by_index(0)?; + let read_object: AlifeObjectItemWeaponShotgun = + AlifeObjectItemWeaponShotgun::read_from_chunk::(&mut chunk)?; + + assert_eq!(read_object, object); + + Ok(()) + } +}