|
- #[cfg(feature = "techblox")]
- use libfj::techblox;
- #[cfg(feature = "techblox")]
- use libfj::techblox::{SerializedEntityDescriptor, Parsable, blocks, EntityHeader};
- #[cfg(feature = "techblox")]
- 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";
- #[cfg(feature = "techblox")]
- const GAMESAVE_PATH_OUT: &str = "tests/GameSave.out.Techblox";
- #[cfg(feature = "techblox")]
- const GAMESAVE_PATH_ALL: &str = "tests/All.Techblox";
- #[cfg(feature = "techblox")]
- const GAMESAVE_PATH_ALL_OUT: &str = "tests/All.out.Techblox";
-
- #[cfg(feature = "techblox")]
- const HASHNAMES: &[&str] = &[
- "BlockGroupEntityDescriptorV0",
-
- "StandardBlockEntityDescriptorV4",
- "BatteryEntityDescriptorV4",
- "MotorEntityDescriptorV7",
- "LeverEntityDescriptorV7",
- "ButtonEntityDescriptorV6",
- "JointBlockEntityDescriptorV3",
- "ServoEntityDescriptorV7",
- "PistonEntityDescriptorV6",
- "DampedSpringEntityDescriptorV5",
- "DampedAngularSpringEntityDescriptorV4",
- "SpawnPointEntityDescriptorV6",
- "BuildingSpawnPointEntityDescriptorV4",
- "TriggerEntityDescriptorV6",
- "PilotSeatEntityDescriptorV4",
- "PilotSeatEntityDescriptorV3",
- "TextBlockEntityDescriptorV4",
- "PassengerSeatEntityDescriptorV4",
- "PassengerSeatEntityDescriptorV3",
- "LogicBlockEntityDescriptorV1",
- "TyreEntityDescriptorV1",
- "ObjectIDEntityDescriptorV1",
- "MoverEntityDescriptorV1",
- "RotatorEntityDescriptorV1",
- "DamperEntityDescriptorV1",
- "AdvancedDamperEntityDescriptorV1",
- "CoMEntityDescriptor",
- "FilterBlockEntityDescriptorV1",
- "ConstrainerEntityDescriptorV1",
- "NumberToTextBlockEntityDescriptorV1",
- "CentreHudBlockEntityDescriptorV1",
- "ObjectiveHudBlockEntityDescriptorV1",
- "GameStatsHudBlockEntityDescriptorV1",
- "GameOverHudBlockEntityDescriptorV1",
- "TimerBlockEntityDescriptorV1",
- "BitBlockEntityDescriptorV2",
- "ConstantBlockEntityDescriptor",
- "CounterBlockEntityDescriptorV1",
- "SimpleSfxEntityDescriptorV1",
- "LoopedSfxEntityDescriptorV1",
- "MusicBlockEntityDescriptorV1",
- "ProjectileBlockEntityDescriptorV1",
- "DamagingSurfaceEntityDescriptorV1",
- "DestructionManagerEntityDescriptorV1",
- "ChunkDestructionBlockEntityDescriptorV1",
- "ClusterDestructionBlockEntityDescriptorV1",
- "PickupBlockEntityDescriptorV1",
- "PointLightEntityDescriptorV1",
- "SpotLightEntityDescriptorV1",
- "SunLightEntityDescriptorV1",
- "AmbientLightEntityDescriptorV1",
- "FogEntityDescriptorV1",
- "SkyEntityDescriptorV1",
- "SynchronizedWireBlockEntityDescriptor",
- "WheelRigEntityDescriptor",
- "WheelRigSteerableEntityDescriptor",
- "EngineBlockEntityDescriptor",
-
- "WireEntityDescriptorMock",
- "GlobalWireSettingsEntityDescriptor",
- "FlyCamEntityDescriptorV0",
- "CharacterCameraEntityDescriptorV1",
- ];
-
- #[cfg(feature = "techblox")]
- #[test]
- fn techblox_gamesave_parse() -> Result<(), ()> {
- let mut f = File::open(GAMESAVE_PATH).map_err(|_| ())?;
- let mut buf = Vec::new();
- f.read_to_end(&mut buf).map_err(|_| ())?;
- let gs = techblox::GameSave::parse(&mut buf.as_slice()).map_err(|_| ())?;
- for i in 1..(gs.group_len as usize) {
- assert_eq!(gs.group_headers[i-1].hash, gs.group_headers[i].hash);
- //println!("#{} count {} vs {}", i, gs.group_headers[i-1].component_count, gs.group_headers[i].component_count);
- assert_eq!(gs.group_headers[i-1].component_count, gs.group_headers[i].component_count);
- }
- 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());
- }
- for i in 1..(gs.cube_len as usize) {
- //assert_eq!(gs.cube_headers[i-1].hash, gs.cube_headers[i].hash);
- //println!("#{} count {} vs {}", i, gs.cube_headers[i-1].component_count, gs.cube_headers[i].component_count);
- if gs.cube_headers[i-1].hash == gs.cube_headers[i].hash {
- assert_eq!(gs.group_headers[i-1].component_count, gs.group_headers[i].component_count);
- }
- }
- for i in 0..(gs.cube_len as usize) {
- assert!(gs.cube_headers[i].component_count >= blocks::BlockEntity::serialized_components());
- //println!("#{} components: {}", i, gs.cube_headers[i].component_count);
- assert_eq!(gs.cube_headers[i].hash, gs.cube_entities[i].hash_name());
- }
-
- //println!("Parsed wire settings hash: {} obsolete? {}", gs.wire_settings_header.hash, gs.wire_settings_entity.settings_component.obsolete != 0);
- assert_eq!(gs.wire_settings_header.hash, EntityHeader::from_name("GlobalWireSettingsEntityDescriptor", 0, 0, 0).hash);
- assert_eq!(gs.wire_settings_header.hash, gs.wire_settings_entity.hash_name());
-
- //println!("Parsed Flycam hash: {}", gs.flycam_header.hash);
- assert_eq!(gs.flycam_header.hash, EntityHeader::from_name("FlyCamEntityDescriptorV0", 0, 0, 0).hash);
- assert_eq!(gs.flycam_header.hash, gs.flycam_entity.hash_name());
-
- //println!("Parsed Phycam hash: {}", gs.phycam_header.hash);
- assert_eq!(gs.phycam_header.hash, EntityHeader::from_name("CharacterCameraEntityDescriptorV1", 0, 0, 0).hash);
- assert_eq!(gs.phycam_header.hash, gs.phycam_entity.hash_name());
-
- println!("{}", gs.to_string());
- Ok(())
- }
-
- #[allow(dead_code)]
- #[cfg(feature = "techblox")]
- //#[test]
- fn techblox_gamesave_brute_force() -> Result<(), ()> {
- // this is slow and not very important, so it's probably better to not test this
- let mut f = File::open(GAMESAVE_PATH).map_err(|_| ())?;
- let mut buf = Vec::new();
- f.read_to_end(&mut buf).map_err(|_| ())?;
- let gs = techblox::GameSave::parse(&mut buf.as_slice()).map_err(|_| ())?;
- println!("murmurhash3: {} -> {}", gs.group_headers[0].guess_name(), gs.group_headers[0].hash);
- Ok(())
- }
-
- #[cfg(feature = "techblox")]
- #[test]
- fn hash_tb_name() {
- for name in HASHNAMES {
- println!("MurmurHash3: {} -> {}", name, crate::techblox::EntityHeader::from_name(name, 0, 0, 0).hash);
- }
- }
-
- #[cfg(feature = "techblox")]
- #[test]
- fn techblox_gamesave_perfect_parse() -> 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(|_| ())?;
- let mut out_file = OpenOptions::new()
- .write(true)
- .truncate(true)
- .create(true)
- .open(GAMESAVE_PATH_OUT)
- .map_err(|_| ())?;
- gs.dump(&mut out_file).map_err(|_| ())?;
- assert_eq!(in_file.stream_position().unwrap(), out_file.stream_position().unwrap());
- Ok(())
- }
-
- #[cfg(feature = "techblox")]
- #[test]
- fn techblox_gamesave_parse_all() -> 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(|_| ())?;
-
- // verify
- for i in 1..(gs.group_len as usize) {
- assert_eq!(gs.group_headers[i-1].hash, gs.group_headers[i].hash);
- //println!("#{} count {} vs {}", i, gs.group_headers[i-1].component_count, gs.group_headers[i].component_count);
- assert_eq!(gs.group_headers[i-1].component_count, gs.group_headers[i].component_count);
- }
- 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);
- //println!("#{} count {} vs {}", i, gs.cube_headers[i-1].component_count, gs.cube_headers[i].component_count);
- if gs.cube_headers[i-1].hash == gs.cube_headers[i].hash {
- assert_eq!(gs.group_headers[i-1].component_count, gs.group_headers[i].component_count);
- }
- }
- for i in 0..(gs.cube_len as usize) {
- assert!(gs.cube_headers[i].component_count >= blocks::BlockEntity::serialized_components());
- //println!("#{} components: {}", i, gs.cube_headers[i].component_count);
- assert_eq!(gs.cube_headers[i].hash, gs.cube_entities[i].hash_name());
- }
-
- //println!("Parsed wire settings hash: {} obsolete? {}", gs.wire_settings_header.hash, gs.wire_settings_entity.settings_component.obsolete != 0);
- assert_eq!(gs.wire_settings_header.hash, EntityHeader::from_name("GlobalWireSettingsEntityDescriptor", 0, 0, 0).hash);
- assert_eq!(gs.wire_settings_header.hash, gs.wire_settings_entity.hash_name());
-
- //println!("Parsed Flycam hash: {}", gs.flycam_header.hash);
- assert_eq!(gs.flycam_header.hash, EntityHeader::from_name("FlyCamEntityDescriptorV0", 0, 0, 0).hash);
- assert_eq!(gs.flycam_header.hash, gs.flycam_entity.hash_name());
-
- //println!("Parsed Phycam hash: {}", gs.phycam_header.hash);
- assert_eq!(gs.phycam_header.hash, EntityHeader::from_name("CharacterCameraEntityDescriptorV1", 0, 0, 0).hash);
- assert_eq!(gs.phycam_header.hash, gs.phycam_entity.hash_name());
-
- // write out
- let mut out_file = OpenOptions::new()
- .write(true)
- .truncate(true)
- .create(true)
- .open(GAMESAVE_PATH_ALL_OUT)
- .map_err(|_| ())?;
- gs.dump(&mut out_file).map_err(|_| ())?;
- 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
- }
|