diff --git a/resources/test/tagcontainer.sav b/resources/test/tagcontainer.sav new file mode 100644 index 0000000..ef40fe8 Binary files /dev/null and b/resources/test/tagcontainer.sav differ diff --git a/src/properties/struct_property.rs b/src/properties/struct_property.rs index 3b641d6..d762f2d 100644 --- a/src/properties/struct_property.rs +++ b/src/properties/struct_property.rs @@ -80,6 +80,8 @@ pub enum StructPropertyValue { LinearColor(LinearColor), /// An `IntPoint` value. IntPoint(IntPoint), + /// A `GameplayTagContainer` value. + GameplayTagContainer(Vec), /// A custom struct value. CustomStruct(HashableIndexMap>), } @@ -168,6 +170,7 @@ impl StructProperty { "LinearColor" => StructPropertyValue::read_linearcolor(cursor)?, "IntPoint" => StructPropertyValue::read_intpoint(cursor)?, "Guid" => StructPropertyValue::read_guid(cursor)?, + "GameplayTagContainer" => StructPropertyValue::read_gameplaytagcontainer(cursor)?, _ => StructPropertyValue::read_custom(cursor, options)?, }; Ok(value) @@ -344,6 +347,14 @@ impl PropertyTrait for StructPropertyValue { cursor.write_guid(guid)?; Ok(16) } + StructPropertyValue::GameplayTagContainer(tags) => { + let mut len = tags.len(); + cursor.write_i32::(len as i32)?; + for gameplaytag in tags { + len += cursor.write_string(gameplaytag)?; + } + Ok(len) + } StructPropertyValue::CustomStruct(properties) => { let mut len = 0; for (key, values) in properties { @@ -380,6 +391,15 @@ impl StructPropertyValue { Ok(StructPropertyValue::CustomStruct(properties)) } + fn read_gameplaytagcontainer(cursor: &mut R) -> Result { + let len = cursor.read_i32::()?; + let mut tags: Vec = Vec::with_capacity(len as usize); + for _ in 0..len { + tags.push(cursor.read_string()?); + } + Ok(Self::GameplayTagContainer(tags)) + } + fn read_guid(cursor: &mut R) -> Result { Ok(Self::Guid(cursor.read_guid()?)) } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 8b0c72c..74a4051 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -8,6 +8,7 @@ pub mod profile0; pub mod regression; pub mod saveslot3; pub mod slot1; +pub mod tagcontainer; pub mod vector2d; pub const ASSERT_FAILED_PATH: &str = "resources/test/assert_failed.sav"; @@ -30,3 +31,4 @@ pub const SLOT3_PATH: &str = "resources/test/Slot3.sav"; pub const TEXT_PROPERTY_NOARRAY: &str = "resources/test/text_property_noarray.bin"; pub const TRANSFORM_PATH: &str = "resources/test/transform.sav"; pub const VECTOR2D_PATH: &str = "resources/test/vector2d.sav"; +pub const TAGCONTAINER_PATH: &str = "resources/test/tagcontainer.sav"; diff --git a/tests/common/tagcontainer.rs b/tests/common/tagcontainer.rs new file mode 100644 index 0000000..4c8b907 --- /dev/null +++ b/tests/common/tagcontainer.rs @@ -0,0 +1,81 @@ +pub const TAGCONTAINER_JSON: &str = r#"{ + "header": { + "type": "Version2", + "package_file_version": 522, + "engine_version": { + "major": 4, + "minor": 27, + "patch": 2, + "change_list": 0, + "branch": "++UE4+Release-4.27" + }, + "custom_version_format": 3, + "custom_versions": { + "FB0C82A7-5943-A720-142C-548C50CF2396": 6, + "FA7AF5FC-8342-7650-58E6-A9B9322DA0FF": 68, + "A7FBD240-E54C-484B-755A-38B09E494E88": 7, + "2923A576-B545-2309-41D8-AE98D86A2FCF": 5, + "0769BC5F-AE40-C855-84F1-678E3FF1FF5E": 1, + "4E7CE782-A543-2333-C513-6BB4F30D3197": 0, + "22D5549C-BE4F-26A8-4607-2194D082B461": 43, + "E432D8B0-0D4F-891F-B77E-CFACA24AFD36": 10, + "2843C6E1-534D-2CA2-868E-6CA38CBD1764": 0, + "3CC15E37-FB48-E406-F084-00B57E712A26": 4, + "ED68B0E4-E942-94F4-0BDA-31A241BB462E": 40, + "3F74FCCF-8044-B043-DF14-919373201D17": 37, + "B5492BB0-E944-20BB-B732-04A36003E452": 3, + "5C10E4A4-B549-A159-C440-C5A7EEDF7E54": 0, + "C931C839-DC47-E65A-179C-449A7C8E1C3E": 0, + "331BF078-984F-EAEB-EA84-B4B9A25AB9CC": 14, + "0F383166-E043-4D2D-27CF-09805AA95669": 0, + "9F8BF812-FC4A-7588-0CD9-7CA629BD3A38": 45, + "4CE75A7B-104C-70D2-9857-58A95A2A210B": 13, + "186929D7-DD4B-D61D-A864-E29D8438C13C": 3, + "7852A1C2-FE4A-E7BF-FF90-176C55F71D53": 1, + "D4A3AC6E-C14C-EC40-ED8B-86B7C58F4209": 3, + "DD75E529-2746-A3E0-76D2-109DEADC2C23": 17, + "5DA643AF-4749-D37F-8E3E-739805BBC1D9": 15, + "EC6C266B-8F4B-C71E-D9E4-0BA307FC4209": 1, + "613DF70D-EA47-3FA2-E989-27B79A49410C": 1, + "86181D60-844F-64AC-DED3-16AAD6C7EA0D": 47, + "686308E7-584C-236B-701B-3984915E2616": 1, + "D6BCFF9D-5801-4F49-8212-21E288A8923C": 10, + "ACD0AEF2-6F41-FE9A-7FAA-6486FCD626FA": 1, + "0B1F4F17-A545-C6B4-E82E-3FB17D91FBD0": 10, + "834AF935-6C40-58E2-F509-18A37C241096": 41, + "6EC18FB6-E242-1B8B-5C21-53B4FE448805": 1, + "0685E1B2-C2CF-7342-BBF4-4EA507BA8B75": 1, + "3689F564-BA42-1BFD-8972-96BA4EFAD0D5": 1, + "27D80E6F-9548-09A6-8D99-919CA40E1890": 2, + "E79E7F71-3A49-B0E9-3291-B3880781381B": 8, + "50326854-AF48-9980-9698-C88BB7F9ADFB": 0, + "194D0C43-7049-5471-699B-6987E5B090DF": 15, + "BD32FEAA-144C-9553-255E-6AB6DDD13210": 1, + "8EE1AF23-584E-E14C-52C2-618DB7BE53B9": 11, + "EAB762A4-3A4E-99F4-1FEC-C199B2E12482": 4, + "BDFDB52E-104D-AC01-8FF3-3681DAA59333": 5, + "4F359D50-2F49-E6F6-B285-49A71C633C07": 0, + "40EB564A-DC11-F510-7E34-D392E76AC9B2": 2, + "004A8AD7-9746-58E8-B519-A8BAB4467D48": 18, + "86F87955-1F4C-3A93-7B08-BA832FB96163": 2, + "52BE2F61-0B40-53DA-914F-0D917C85B19F": 1, + "367A23A4-C941-EACA-F818-A28FF31B6858": 4, + "753F4E80-494B-8870-068C-D6A4DCB67E3C": 5, + "F20A68FB-A34B-EF59-B519-A8BA3D44C873": 2, + "0EB75099-174E-1AB4-0DFA-CCBBD67F8157": 1 + }, + "save_game_class_name": "/Script/Example.SaveGame" + }, + "properties": { + "TagTest": { + "type": "StructProperty", + "type_name": "GameplayTagContainer", + "GameplayTagContainer": [ + "Character.Appearance.OverallColor.Gold", + "Character.Appearance.OverallColor.White", + "Character.Appearance.FluffColor.Red", + "Character.Appearance.FluffColor.Blue" + ] + } + } +}"#; diff --git a/tests/gvas.rs b/tests/gvas.rs index 62b487c..7c0890c 100644 --- a/tests/gvas.rs +++ b/tests/gvas.rs @@ -137,6 +137,11 @@ fn slot3() { test_gvas_file(SLOT3_PATH); } +#[test] +fn tagcontainer() { + test_gvas_file(TAGCONTAINER_PATH); +} + #[test] fn text_property_noarray() { test_gvas_file(TEXT_PROPERTY_NOARRAY); diff --git a/tests/serde_tests/serde_json_round_trip.rs b/tests/serde_tests/serde_json_round_trip.rs index 3fe9a74..4179d47 100644 --- a/tests/serde_tests/serde_json_round_trip.rs +++ b/tests/serde_tests/serde_json_round_trip.rs @@ -90,6 +90,11 @@ fn serde_slot3() { test_file(SLOT3_PATH); } +#[test] +fn serde_tagcontainer() { + test_file(TAGCONTAINER_PATH); +} + #[ignore] // This test takes ~5 seconds to run #[test] fn serde_transform() { diff --git a/tests/serde_tests/serde_json_template.rs b/tests/serde_tests/serde_json_template.rs index 8b71502..18ff46f 100644 --- a/tests/serde_tests/serde_json_template.rs +++ b/tests/serde_tests/serde_json_template.rs @@ -102,6 +102,11 @@ fn file_saveslot_03() { ) } +#[test] +fn file_tagcontainer() { + file(TAGCONTAINER_PATH, tagcontainer::TAGCONTAINER_JSON) +} + #[test] fn file_vector2d() { file(VECTOR2D_PATH, vector2d::VECTOR2D_JSON) @@ -1579,6 +1584,23 @@ fn struct_array_index() { ) } +#[test] +fn struct_gameplaytag() { + serde_json( + &Property::from(StructPropertyValue::GameplayTagContainer(vec![ + String::from("Gameplaytag.One"), + String::from("Gameplaytag.Two"), + ])), + r#"{ + "type": "StructPropertyValue", + "GameplayTagContainer": [ + "Gameplaytag.One", + "Gameplaytag.Two" + ] +}"#, + ) +} + #[test] fn text_empty() { serde_json(