diff --git a/src/techblox/blocks/block_entity.rs b/src/techblox/blocks/block_entity.rs index 926400a..22efdcd 100644 --- a/src/techblox/blocks/block_entity.rs +++ b/src/techblox/blocks/block_entity.rs @@ -1,3 +1,5 @@ +use std::convert::AsRef; + use crate::techblox::{SerializedEntityDescriptor, Parsable, SerializedEntityComponent}; use crate::techblox::blocks::{DBEntityStruct, PositionEntityStruct, ScalingEntityStruct, RotationEntityStruct, SkewComponent, GridRotationStruct, SerializedGridConnectionsEntityStruct, SerializedBlockPlacementInfoStruct, @@ -75,3 +77,13 @@ impl SerializedEntityDescriptor for BlockEntity { Self::hash("StandardBlockEntityDescriptorV4") // 1357220432 } } + +impl AsRef for BlockEntity { + fn as_ref(&self) -> &Self { + self + } +} + +pub trait Block: SerializedEntityDescriptor + AsRef {} + +impl Block for BlockEntity {} diff --git a/src/techblox/blocks/common_components.rs b/src/techblox/blocks/common_components.rs index 9e87d43..15bb660 100644 --- a/src/techblox/blocks/common_components.rs +++ b/src/techblox/blocks/common_components.rs @@ -106,7 +106,7 @@ impl SerializedEntityComponent for SerializedColourParameterEntityStruct {} /// Block group component. #[derive(Copy, Clone, Parsable)] pub struct BlockGroupEntityComponent { - /// Index of colour in Techblox palette + /// Index of block in Techblox block groups (deserialized in earlier part of game save) pub current_block_group: i32, } diff --git a/src/techblox/blocks/engine.rs b/src/techblox/blocks/engine.rs index 35f6bde..06715a4 100644 --- a/src/techblox/blocks/engine.rs +++ b/src/techblox/blocks/engine.rs @@ -1,5 +1,7 @@ +use std::convert::AsRef; + use crate::techblox::{SerializedEntityDescriptor, Parsable, SerializedEntityComponent, -blocks::{BlockEntity}}; +blocks::{BlockEntity, Block}}; use libfj_parsable_macro_derive::*; /// Engine entity descriptor @@ -33,6 +35,14 @@ impl SerializedEntityDescriptor for EngineBlockEntity { } } +impl AsRef for EngineBlockEntity { + fn as_ref(&self) -> &BlockEntity { + &self.block + } +} + +impl Block for EngineBlockEntity {} + /// Engine settings entity component. #[derive(Copy, Clone, Parsable)] pub struct EngineBlockTweakableComponent { diff --git a/src/techblox/blocks/joint.rs b/src/techblox/blocks/joint.rs index 14ca192..ff221b0 100644 --- a/src/techblox/blocks/joint.rs +++ b/src/techblox/blocks/joint.rs @@ -1,5 +1,7 @@ +use std::convert::AsRef; + use crate::techblox::{SerializedEntityDescriptor, Parsable, SerializedEntityComponent, -blocks::{BlockEntity}}; +blocks::{BlockEntity, Block}}; use libfj_parsable_macro_derive::*; /// Joint block entity descriptor @@ -26,3 +28,11 @@ impl SerializedEntityDescriptor for JointBlockEntity { Self::hash("JointBlockEntityDescriptorV3") // 3586818581 } } + +impl AsRef for JointBlockEntity { + fn as_ref(&self) -> &BlockEntity { + &self.block + } +} + +impl Block for JointBlockEntity {} diff --git a/src/techblox/blocks/lookup_tables.rs b/src/techblox/blocks/lookup_tables.rs index bcb695d..b82f467 100644 --- a/src/techblox/blocks/lookup_tables.rs +++ b/src/techblox/blocks/lookup_tables.rs @@ -1,6 +1,6 @@ use std::io::Read; -use crate::techblox::{Parsable, SerializedEntityDescriptor}; +use crate::techblox::{Parsable}; use crate::techblox::blocks::*; const HASHNAMES: &[&str] = &[ @@ -70,7 +70,8 @@ const HASHNAMES: &[&str] = &[ "CharacterCameraEntityDescriptorV1", ]; -pub fn lookup_hashname(hash: u32, data: &mut dyn Read) -> std::io::Result> { +pub fn lookup_hashname(hash: u32, data: &mut dyn Read) -> + std::io::Result> { Ok(match hash { 1357220432 /*StandardBlockEntityDescriptorV4*/ => Box::new(BlockEntity::parse(data)?), 2281299333 /*PilotSeatEntityDescriptorV4*/ => Box::new(PilotSeatEntity::parse(data)?), diff --git a/src/techblox/blocks/mod.rs b/src/techblox/blocks/mod.rs index e1f926c..19ce4c6 100644 --- a/src/techblox/blocks/mod.rs +++ b/src/techblox/blocks/mod.rs @@ -12,7 +12,7 @@ mod tyre; mod wheel_rig; mod wire_entity; -pub use block_entity::{BlockEntity}; +pub use block_entity::{BlockEntity, Block}; pub use common_components::{DBEntityStruct, PositionEntityStruct, ScalingEntityStruct, RotationEntityStruct, SkewComponent, GridRotationStruct, SerializedGridConnectionsEntityStruct, SerializedBlockPlacementInfoStruct, SerializedCubeMaterialStruct, SerializedUniformBlockScaleEntityStruct, SerializedColourParameterEntityStruct, diff --git a/src/techblox/blocks/passenger_seat.rs b/src/techblox/blocks/passenger_seat.rs index 9110a15..7175b36 100644 --- a/src/techblox/blocks/passenger_seat.rs +++ b/src/techblox/blocks/passenger_seat.rs @@ -1,5 +1,7 @@ +use std::convert::AsRef; + use crate::techblox::{SerializedEntityDescriptor, Parsable, SerializedEntityComponent, -blocks::{BlockEntity, SeatFollowCamComponent}}; +blocks::{BlockEntity, SeatFollowCamComponent, Block}}; use libfj_parsable_macro_derive::*; /// Passenger seat entity descriptor (V4) @@ -32,3 +34,11 @@ impl SerializedEntityDescriptor for PassengerSeatEntity { Self::hash("PassengerSeatEntityDescriptorV4") // 1360086092 } } + +impl AsRef for PassengerSeatEntity { + fn as_ref(&self) -> &BlockEntity { + &self.block + } +} + +impl Block for PassengerSeatEntity {} diff --git a/src/techblox/blocks/pilot_seat.rs b/src/techblox/blocks/pilot_seat.rs index c454c3e..3510f83 100644 --- a/src/techblox/blocks/pilot_seat.rs +++ b/src/techblox/blocks/pilot_seat.rs @@ -1,4 +1,6 @@ -use crate::techblox::{SerializedEntityDescriptor, Parsable, SerializedEntityComponent, blocks::BlockEntity}; +use std::convert::AsRef; + +use crate::techblox::{SerializedEntityDescriptor, Parsable, SerializedEntityComponent, blocks::{BlockEntity, Block}}; use libfj_parsable_macro_derive::*; /// Pilot seat entity descriptor (V4) @@ -32,6 +34,14 @@ impl SerializedEntityDescriptor for PilotSeatEntity { } } +impl AsRef for PilotSeatEntity { + fn as_ref(&self) -> &BlockEntity { + &self.block + } +} + +impl Block for PilotSeatEntity {} + /// Seat settings entity component. #[derive(Copy, Clone, Parsable)] pub struct SeatFollowCamComponent { diff --git a/src/techblox/blocks/spring.rs b/src/techblox/blocks/spring.rs index fb888a6..ea23f3e 100644 --- a/src/techblox/blocks/spring.rs +++ b/src/techblox/blocks/spring.rs @@ -1,5 +1,7 @@ +use std::convert::AsRef; + use crate::techblox::{SerializedEntityDescriptor, Parsable, SerializedEntityComponent, -blocks::{BlockEntity}}; +blocks::{BlockEntity, Block}}; use libfj_parsable_macro_derive::*; /// Damped angular spring entity descriptor @@ -37,6 +39,14 @@ impl SerializedEntityDescriptor for DampedAngularSpringEntity { } } +impl AsRef for DampedAngularSpringEntity { + fn as_ref(&self) -> &BlockEntity { + &self.block + } +} + +impl Block for DampedAngularSpringEntity {} + /// Damped spring entity descriptor #[derive(Copy, Clone, Parsable)] pub struct DampedSpringEntity { @@ -72,6 +82,14 @@ impl SerializedEntityDescriptor for DampedSpringEntity { } } +impl AsRef for DampedSpringEntity { + fn as_ref(&self) -> &BlockEntity { + &self.block + } +} + +impl Block for DampedSpringEntity {} + /// Joint settings entity component. #[derive(Copy, Clone, Parsable)] pub struct TweakableJointDampingComponent { diff --git a/src/techblox/blocks/tyre.rs b/src/techblox/blocks/tyre.rs index bc6a248..6889cae 100644 --- a/src/techblox/blocks/tyre.rs +++ b/src/techblox/blocks/tyre.rs @@ -1,5 +1,7 @@ +use std::convert::AsRef; + use crate::techblox::{SerializedEntityDescriptor, Parsable, SerializedEntityComponent, -blocks::{BlockEntity}}; +blocks::{BlockEntity, Block}}; use libfj_parsable_macro_derive::*; /// Tire entity descriptor @@ -26,3 +28,11 @@ impl SerializedEntityDescriptor for TyreEntity { Self::hash("TyreEntityDescriptorV1") // 1517625162 } } + +impl AsRef for TyreEntity { + fn as_ref(&self) -> &BlockEntity { + &self.block + } +} + +impl Block for TyreEntity {} diff --git a/src/techblox/blocks/wheel_rig.rs b/src/techblox/blocks/wheel_rig.rs index 9622eef..ecda159 100644 --- a/src/techblox/blocks/wheel_rig.rs +++ b/src/techblox/blocks/wheel_rig.rs @@ -1,5 +1,7 @@ +use std::convert::AsRef; + use crate::techblox::{SerializedEntityDescriptor, Parsable, SerializedEntityComponent, -blocks::{BlockEntity, TweakableJointDampingComponent}}; +blocks::{BlockEntity, TweakableJointDampingComponent, Block}}; use libfj_parsable_macro_derive::*; /// Wheel rig entity descriptor @@ -37,6 +39,14 @@ impl SerializedEntityDescriptor for WheelRigEntity { } } +impl AsRef for WheelRigEntity { + fn as_ref(&self) -> &BlockEntity { + &self.block + } +} + +impl Block for WheelRigEntity {} + /// Wheel rig entity descriptor #[derive(Copy, Clone, Parsable)] pub struct WheelRigSteerableEntity { @@ -68,6 +78,14 @@ impl SerializedEntityDescriptor for WheelRigSteerableEntity { } } +impl AsRef for WheelRigSteerableEntity { + fn as_ref(&self) -> &BlockEntity { + &self.block.as_ref() + } +} + +impl Block for WheelRigSteerableEntity {} + /// Wheel rig settings entity component. #[derive(Copy, Clone, Parsable)] pub struct WheelRigTweakableStruct { diff --git a/src/techblox/entity_traits.rs b/src/techblox/entity_traits.rs index 407310d..c3ec1f8 100644 --- a/src/techblox/entity_traits.rs +++ b/src/techblox/entity_traits.rs @@ -1,4 +1,5 @@ use std::io::{Read, Write}; +use std::any::Any; /// Standard trait for parsing Techblox game save data. pub trait Parsable { @@ -26,7 +27,7 @@ pub trait SerializedEntityDescriptor: Parsable { /// Serializable entity component. /// Components are the atomic unit of entities. -pub trait SerializedEntityComponent: Parsable { +pub trait SerializedEntityComponent: Parsable + Any { /// Raw size of struct, in bytes. fn size() -> usize where Self: Sized { std::mem::size_of::() diff --git a/src/techblox/gamesave.rs b/src/techblox/gamesave.rs index 7668dca..7f863ea 100644 --- a/src/techblox/gamesave.rs +++ b/src/techblox/gamesave.rs @@ -1,9 +1,9 @@ use chrono::{naive::NaiveDate, Datelike}; use std::io::{Read, Write}; -use crate::techblox::{EntityHeader, BlockGroupEntity, parse_i64, parse_u32, Parsable, SerializedEntityDescriptor, +use crate::techblox::{EntityHeader, BlockGroupEntity, parse_i64, parse_u32, Parsable, SerializedFlyCamEntity, SerializedPhysicsCameraEntity}; -use crate::techblox::blocks::{lookup_hashname, SerializedWireEntity, SerializedGlobalWireSettingsEntity}; +use crate::techblox::blocks::{lookup_hashname, SerializedWireEntity, SerializedGlobalWireSettingsEntity, Block}; /// A collection of cubes and other data from a GameSave.techblox file //#[derive(Clone)] @@ -37,7 +37,7 @@ pub struct GameSave { pub cube_headers: Vec, /// Blocks - pub cube_entities: Vec>, + pub cube_entities: Vec>, /// Amount of wires in the save data, as claimed by the file. pub wire_len: u32, @@ -89,7 +89,7 @@ impl Parsable for GameSave { // parse cube data let mut cubes_h = Vec::::with_capacity(cube_count as usize); - let mut cubes_e = Vec::>::with_capacity(cube_count as usize); + let mut cubes_e = Vec::>::with_capacity(cube_count as usize); for _i in 0..cube_count { let header = EntityHeader::parse(data)?; let hash = header.hash; diff --git a/tests/techblox_parsing.rs b/tests/techblox_parsing.rs index 09de5ad..1494aca 100644 --- a/tests/techblox_parsing.rs +++ b/tests/techblox_parsing.rs @@ -6,6 +6,8 @@ use libfj::techblox::{SerializedEntityDescriptor, Parsable, blocks, EntityHeader use std::io::{Read, Seek}; #[cfg(feature = "techblox")] use std::fs::{File, OpenOptions}; +#[cfg(feature = "techblox")] +use std::convert::AsRef; #[cfg(feature = "techblox")] const GAMESAVE_PATH: &str = "tests/GameSave.Techblox"; @@ -184,6 +186,10 @@ fn techblox_gamesave_parse_all() -> Result<(), ()> { for i in 0..(gs.group_len as usize) { assert_eq!(gs.group_headers[i].component_count, techblox::BlockGroupEntity::serialized_components()); assert_eq!(gs.group_headers[i].hash, gs.cube_groups[i].hash_name()); + /*let pos = format!("({}, {}, {})", gs.cube_groups[i].block_group_transform.block_group_grid_position.x, gs.cube_groups[i].block_group_transform.block_group_grid_position.y, gs.cube_groups[i].block_group_transform.block_group_grid_position.z); + let rot = format!("({}, {}, {}, {})", gs.cube_groups[i].block_group_transform.block_group_grid_rotation.value.x, gs.cube_groups[i].block_group_transform.block_group_grid_rotation.value.y, gs.cube_groups[i].block_group_transform.block_group_grid_rotation.value.z, + gs.cube_groups[i].block_group_transform.block_group_grid_rotation.value.w); + println!("block id: {}, position: {}, rotation: {}", gs.cube_groups[i].saved_block_group_id.saved_block_group_id, pos, rot);*/ } for i in 1..(gs.cube_len as usize) { //assert_eq!(gs.cube_headers[i-1].hash, gs.cube_headers[i].hash); @@ -221,3 +227,29 @@ fn techblox_gamesave_parse_all() -> Result<(), ()> { assert_eq!(in_file.stream_position().unwrap(), out_file.stream_position().unwrap()); Ok(()) } + +#[cfg(feature = "techblox")] +#[test] +fn techblox_gamesave_block_groups() -> Result<(), ()> { + let mut in_file = File::open(GAMESAVE_PATH_ALL).map_err(|_| ())?; + let mut buf = Vec::new(); + in_file.read_to_end(&mut buf).map_err(|_| ())?; + let gs = techblox::GameSave::parse(&mut buf.as_slice()).map_err(|_| ())?; + + for block_trait in &gs.cube_entities { + let block: &blocks::BlockEntity = block_trait.as_ref().as_ref(); + //println!("Block @ ({}, {}, {})", block.pos_component.position.x, block.pos_component.position.y, block.pos_component.position.z); + assert!(is_in_block_groups(block.group_component.current_block_group, &gs.cube_groups)); + } + Ok(()) +} + +#[cfg(feature = "techblox")] +fn is_in_block_groups(id: i32, block_groups: &Vec) -> bool { + for bg in block_groups { + if bg.saved_block_group_id.saved_block_group_id == id { + return true; + } + } + false +}