From 0aad5a42cb9fb3ce2ce1ccf53ccaaef2513995f4 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 15 Jan 2022 23:14:37 +0100 Subject: [PATCH] Dump structured data def structs --- src/Common/Game/IW4/IW4_Assets.h | 3 +- .../StructuredDataDefDumper.cpp | 50 +++++- .../StructuredDataDefDumper.h | 11 +- .../AssetDumperStructuredDataDefSet.cpp | 151 +++++++++++++++++- .../AssetDumperStructuredDataDefSet.h | 2 + 5 files changed, 210 insertions(+), 7 deletions(-) diff --git a/src/Common/Game/IW4/IW4_Assets.h b/src/Common/Game/IW4/IW4_Assets.h index d2aae8fa..5027b5b2 100644 --- a/src/Common/Game/IW4/IW4_Assets.h +++ b/src/Common/Game/IW4/IW4_Assets.h @@ -2031,7 +2031,8 @@ namespace IW4 DATA_ENUM_ARRAY = 0x7, DATA_FLOAT = 0x8, DATA_SHORT = 0x9, - DATA_COUNT = 0xA, + + DATA_COUNT }; struct StructuredDataEnumEntry diff --git a/src/ObjWriting/Dumping/StructuredDataDef/StructuredDataDefDumper.cpp b/src/ObjWriting/Dumping/StructuredDataDef/StructuredDataDefDumper.cpp index 8ef7b075..27289b71 100644 --- a/src/ObjWriting/Dumping/StructuredDataDef/StructuredDataDefDumper.cpp +++ b/src/ObjWriting/Dumping/StructuredDataDef/StructuredDataDefDumper.cpp @@ -83,7 +83,7 @@ void StructuredDataDefDumper::EndEnum() m_stream << ",\n"; Indent(); - m_stream << entry; + m_stream << "\"" << entry << "\""; } if (!firstEntry) @@ -94,6 +94,7 @@ void StructuredDataDefDumper::EndEnum() m_stream << "};\n"; m_block = Block::BLOCK_NONE; m_flags.m_empty_line_before_block = true; + m_enum_entries.clear(); } void StructuredDataDefDumper::WriteEnumEntry(const std::string& entryName, const size_t entryValue) @@ -141,3 +142,50 @@ void StructuredDataDefDumper::EndStruct() m_block = Block::BLOCK_NONE; m_flags.m_empty_line_before_block = true; } + +void StructuredDataDefDumper::BeginProperty(const std::string& propertyName) +{ + assert(m_flags.m_in_version); + assert(m_block == Block::BLOCK_STRUCT); + + if (m_block != Block::BLOCK_STRUCT) + return; + + m_property_name = propertyName; + + m_block = Block::BLOCK_PROPERTY; +} + +void StructuredDataDefDumper::AddPropertyArraySpecifier(const std::string& specifierName) +{ + m_property_array_specifiers.emplace_back(specifierName); +} + +void StructuredDataDefDumper::SetPropertyTypeName(const std::string& typeName) +{ + m_property_type_name = typeName; +} + +void StructuredDataDefDumper::EndProperty() +{ + assert(m_block == Block::BLOCK_PROPERTY); + + if (m_block != Block::BLOCK_PROPERTY) + return; + + Indent(); + + m_stream << m_property_type_name << " " << m_property_name; + + for(const auto& arraySpecifierName : m_property_array_specifiers) + { + m_stream << "[" << arraySpecifierName << "]"; + } + + m_stream << ";\n"; + + m_block = Block::BLOCK_STRUCT; + m_property_array_specifiers.clear(); + m_property_name = std::string(); + m_property_type_name = std::string(); +} diff --git a/src/ObjWriting/Dumping/StructuredDataDef/StructuredDataDefDumper.h b/src/ObjWriting/Dumping/StructuredDataDef/StructuredDataDefDumper.h index 0cb4293c..dc26cd31 100644 --- a/src/ObjWriting/Dumping/StructuredDataDef/StructuredDataDefDumper.h +++ b/src/ObjWriting/Dumping/StructuredDataDef/StructuredDataDefDumper.h @@ -10,7 +10,8 @@ class StructuredDataDefDumper : AbstractTextDumper { BLOCK_NONE = 0, BLOCK_ENUM = 1, - BLOCK_STRUCT = 2 + BLOCK_STRUCT = 2, + BLOCK_PROPERTY = 3 } m_block; struct @@ -23,6 +24,10 @@ class StructuredDataDefDumper : AbstractTextDumper std::vector m_enum_entries; size_t m_enum_size; + std::string m_property_name; + std::string m_property_type_name; + std::vector m_property_array_specifiers; + public: explicit StructuredDataDefDumper(std::ostream& stream); @@ -35,4 +40,8 @@ public: void BeginStruct(const std::string& structName); void EndStruct(); + void BeginProperty(const std::string& propertyName); + void AddPropertyArraySpecifier(const std::string& specifierName); + void SetPropertyTypeName(const std::string& typeName); + void EndProperty(); }; diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.cpp b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.cpp index c1760bf4..070452a7 100644 --- a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.cpp +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.cpp @@ -22,12 +22,12 @@ void AssetDumperStructuredDataDefSet::DumpEnum(StructuredDataDefDumper& dumper, dumper.BeginEnum(ss.str(), static_cast(_enum->entryCount)); - for(auto i = 0; i < _enum->entryCount; i++) + for (auto i = 0; i < _enum->entryCount; i++) { const auto& entry = _enum->entries[i]; assert(entry.string); - if(!entry.string) + if (!entry.string) continue; dumper.WriteEnumEntry(entry.string, entry.index); @@ -36,6 +36,146 @@ void AssetDumperStructuredDataDefSet::DumpEnum(StructuredDataDefDumper& dumper, dumper.EndEnum(); } +void AssetDumperStructuredDataDefSet::DumpProperty(StructuredDataDefDumper& dumper, const StructuredDataStructProperty& property, const StructuredDataDef* def, const int rootStructIndex) +{ + dumper.BeginProperty(property.name); + + auto currentType = property.type; + auto stopTypeIteration = false; + do + { + switch (currentType.type) + { + case DATA_INT: + dumper.SetPropertyTypeName("int"); + stopTypeIteration = true; + break; + case DATA_BYTE: + dumper.SetPropertyTypeName("byte"); + stopTypeIteration = true; + break; + case DATA_BOOL: + dumper.SetPropertyTypeName("bool"); + stopTypeIteration = true; + break; + case DATA_FLOAT: + dumper.SetPropertyTypeName("float"); + stopTypeIteration = true; + break; + case DATA_SHORT: + dumper.SetPropertyTypeName("short"); + stopTypeIteration = true; + break; + case DATA_STRING: + { + std::ostringstream ss; + ss << "string(" << currentType.u.stringDataLength << ")"; + dumper.SetPropertyTypeName(ss.str()); + stopTypeIteration = true; + break; + } + case DATA_ENUM: + { + std::ostringstream ss; + ss << "ENUM_" << currentType.u.enumIndex; + dumper.SetPropertyTypeName(ss.str()); + stopTypeIteration = true; + break; + } + case DATA_STRUCT: + { + if (currentType.u.structIndex == rootStructIndex) + { + dumper.SetPropertyTypeName("root"); + } + else + { + std::ostringstream ss; + ss << "STRUCT_" << currentType.u.enumIndex; + dumper.SetPropertyTypeName(ss.str()); + } + stopTypeIteration = true; + break; + } + case DATA_INDEXED_ARRAY: + { + if (def->indexedArrays == nullptr + || currentType.u.indexedArrayIndex < 0 + || currentType.u.indexedArrayIndex >= def->indexedArrayCount) + { + assert(false); + dumper.SetPropertyTypeName("ERRORTYPE"); + stopTypeIteration = true; + } + else + { + const auto& indexedArray = def->indexedArrays[currentType.u.indexedArrayIndex]; + dumper.AddPropertyArraySpecifier(std::to_string(indexedArray.arraySize)); + currentType = indexedArray.elementType; + } + break; + } + case DATA_ENUM_ARRAY: + { + if (def->enumedArrays == nullptr + || currentType.u.enumedArrayIndex < 0 + || currentType.u.enumedArrayIndex >= def->enumedArrayCount) + { + assert(false); + dumper.SetPropertyTypeName("ERRORTYPE"); + stopTypeIteration = true; + } + else + { + const auto& enumedArray = def->enumedArrays[currentType.u.enumedArrayIndex]; + std::ostringstream ss; + ss << "ENUM_" << enumedArray.enumIndex; + dumper.AddPropertyArraySpecifier(ss.str()); + currentType = enumedArray.elementType; + } + break; + } + + default: + break; + } + } + while (!stopTypeIteration); + + dumper.EndProperty(); +} + +void AssetDumperStructuredDataDefSet::DumpStruct(StructuredDataDefDumper& dumper, const int structIndex, const StructuredDataStruct* _struct, const StructuredDataDef* def, const bool isRoot) +{ + if (!_struct->properties || _struct->propertyCount <= 0) + return; + + std::string structName; + + if (isRoot) + { + structName = "root"; + } + else + { + std::ostringstream ss; + ss << "STRUCT_" << structIndex; + structName = ss.str(); + } + + dumper.BeginStruct(structName); + + const auto rootStructIndex = def->rootType.type == DATA_STRUCT ? def->rootType.u.structIndex : -1; + for (auto i = 0; i < _struct->propertyCount; i++) + { + const auto& property = _struct->properties[i]; + + DumpProperty(dumper, property, def, rootStructIndex); + } + + dumper.EndStruct(); +} + void AssetDumperStructuredDataDefSet::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) { const auto* set = asset->Asset(); @@ -46,7 +186,7 @@ void AssetDumperStructuredDataDefSet::DumpAsset(AssetDumpingContext& context, XA StructuredDataDefDumper dumper(*assetFile); - for(auto defIndex = 0u; defIndex < set->defCount; defIndex++) + for (auto defIndex = 0u; defIndex < set->defCount; defIndex++) { const auto& def = set->defs[defIndex]; @@ -55,7 +195,10 @@ void AssetDumperStructuredDataDefSet::DumpAsset(AssetDumpingContext& context, XA for (auto enumIndex = 0; enumIndex < def.enumCount; enumIndex++) DumpEnum(dumper, enumIndex, &def.enums[enumIndex]); - // TODO + const auto rootStructIndex = def.rootType.type == DATA_STRUCT ? def.rootType.u.structIndex : -1; + assert(rootStructIndex >= 0); + for (auto structIndex = 0; structIndex < def.structCount; structIndex++) + DumpStruct(dumper, structIndex, &def.structs[structIndex], &def, structIndex == rootStructIndex); dumper.EndVersion(); } diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.h b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.h index d1d9506a..995735b4 100644 --- a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.h +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperStructuredDataDefSet.h @@ -9,6 +9,8 @@ namespace IW4 class AssetDumperStructuredDataDefSet final : public AbstractAssetDumper { static void DumpEnum(StructuredDataDefDumper& dumper, int enumIndex, const StructuredDataEnum* _enum); + static void DumpProperty(StructuredDataDefDumper& dumper, const StructuredDataStructProperty& property, const StructuredDataDef* def, int rootStructIndex); + static void DumpStruct(StructuredDataDefDumper& dumper, int structIndex, const StructuredDataStruct* _struct, const StructuredDataDef* def, bool isRoot); protected: bool ShouldDump(XAssetInfo* asset) override;