@@ -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<BlockEntity> for BlockEntity { | |||
fn as_ref(&self) -> &Self { | |||
self | |||
} | |||
} | |||
pub trait Block: SerializedEntityDescriptor + AsRef<BlockEntity> {} | |||
impl Block for BlockEntity {} |
@@ -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, | |||
} | |||
@@ -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<BlockEntity> for EngineBlockEntity { | |||
fn as_ref(&self) -> &BlockEntity { | |||
&self.block | |||
} | |||
} | |||
impl Block for EngineBlockEntity {} | |||
/// Engine settings entity component. | |||
#[derive(Copy, Clone, Parsable)] | |||
pub struct EngineBlockTweakableComponent { | |||
@@ -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<BlockEntity> for JointBlockEntity { | |||
fn as_ref(&self) -> &BlockEntity { | |||
&self.block | |||
} | |||
} | |||
impl Block for JointBlockEntity {} |
@@ -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<Box<dyn SerializedEntityDescriptor>> { | |||
pub fn lookup_hashname(hash: u32, data: &mut dyn Read) -> | |||
std::io::Result<Box<dyn Block>> { | |||
Ok(match hash { | |||
1357220432 /*StandardBlockEntityDescriptorV4*/ => Box::new(BlockEntity::parse(data)?), | |||
2281299333 /*PilotSeatEntityDescriptorV4*/ => Box::new(PilotSeatEntity::parse(data)?), | |||
@@ -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, | |||
@@ -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<BlockEntity> for PassengerSeatEntity { | |||
fn as_ref(&self) -> &BlockEntity { | |||
&self.block | |||
} | |||
} | |||
impl Block for PassengerSeatEntity {} |
@@ -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<BlockEntity> for PilotSeatEntity { | |||
fn as_ref(&self) -> &BlockEntity { | |||
&self.block | |||
} | |||
} | |||
impl Block for PilotSeatEntity {} | |||
/// Seat settings entity component. | |||
#[derive(Copy, Clone, Parsable)] | |||
pub struct SeatFollowCamComponent { | |||
@@ -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<BlockEntity> 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<BlockEntity> for DampedSpringEntity { | |||
fn as_ref(&self) -> &BlockEntity { | |||
&self.block | |||
} | |||
} | |||
impl Block for DampedSpringEntity {} | |||
/// Joint settings entity component. | |||
#[derive(Copy, Clone, Parsable)] | |||
pub struct TweakableJointDampingComponent { | |||
@@ -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<BlockEntity> for TyreEntity { | |||
fn as_ref(&self) -> &BlockEntity { | |||
&self.block | |||
} | |||
} | |||
impl Block for TyreEntity {} |
@@ -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<BlockEntity> 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<BlockEntity> 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 { | |||
@@ -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::<Self>() | |||
@@ -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<EntityHeader>, | |||
/// Blocks | |||
pub cube_entities: Vec<Box<dyn SerializedEntityDescriptor>>, | |||
pub cube_entities: Vec<Box<dyn Block>>, | |||
/// 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::<EntityHeader>::with_capacity(cube_count as usize); | |||
let mut cubes_e = Vec::<Box<dyn SerializedEntityDescriptor>>::with_capacity(cube_count as usize); | |||
let mut cubes_e = Vec::<Box<dyn Block>>::with_capacity(cube_count as usize); | |||
for _i in 0..cube_count { | |||
let header = EntityHeader::parse(data)?; | |||
let hash = header.hash; | |||
@@ -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<techblox::BlockGroupEntity>) -> bool { | |||
for bg in block_groups { | |||
if bg.saved_block_group_id.saved_block_group_id == id { | |||
return true; | |||
} | |||
} | |||
false | |||
} |