From 408746c54a0996afcce4cd41e3b89809db99a0a8 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Mon, 4 Aug 2025 21:24:45 +0200 Subject: [PATCH] refactor: streamline structured data def dumping --- src/ObjWriting/Game/IW4/ObjWriterIW4.cpp | 4 +- .../AssetDumperStructuredDataDefSet.cpp | 206 ----------------- .../AssetDumperStructuredDataDefSet.h | 28 --- .../StructuredDataDefDumperIW4.cpp | 208 ++++++++++++++++++ .../StructuredDataDefDumperIW4.h | 17 ++ 5 files changed, 227 insertions(+), 236 deletions(-) delete mode 100644 src/ObjWriting/Game/IW4/StructuredDataDef/AssetDumperStructuredDataDefSet.cpp delete mode 100644 src/ObjWriting/Game/IW4/StructuredDataDef/AssetDumperStructuredDataDefSet.h create mode 100644 src/ObjWriting/Game/IW4/StructuredDataDef/StructuredDataDefDumperIW4.cpp create mode 100644 src/ObjWriting/Game/IW4/StructuredDataDef/StructuredDataDefDumperIW4.h diff --git a/src/ObjWriting/Game/IW4/ObjWriterIW4.cpp b/src/ObjWriting/Game/IW4/ObjWriterIW4.cpp index a7874a66..fbfca499 100644 --- a/src/ObjWriting/Game/IW4/ObjWriterIW4.cpp +++ b/src/ObjWriting/Game/IW4/ObjWriterIW4.cpp @@ -20,7 +20,7 @@ #include "Sound/LoadedSoundDumperIW4.h" #include "Sound/SndCurveDumperIW4.h" #include "StringTable/StringTableDumperIW4.h" -#include "StructuredDataDef/AssetDumperStructuredDataDefSet.h" +#include "StructuredDataDef/StructuredDataDefDumperIW4.h" #include "Techset/TechsetDumperIW4.h" #include "Tracer/TracerDumperIW4.h" #include "Vehicle/VehicleDumperIW4.h" @@ -73,7 +73,7 @@ bool ObjWriter::DumpZone(AssetDumpingContext& context) const DUMP_ASSET_POOL(raw_file::Dumper, m_raw_file, ASSET_TYPE_RAWFILE) DUMP_ASSET_POOL(string_table::Dumper, m_string_table, ASSET_TYPE_STRINGTABLE) DUMP_ASSET_POOL(leaderboard::JsonDumper, m_leaderboard, ASSET_TYPE_LEADERBOARD) - DUMP_ASSET_POOL(AssetDumperStructuredDataDefSet, m_structed_data_def_set, ASSET_TYPE_STRUCTURED_DATA_DEF) + DUMP_ASSET_POOL(structured_data_def::Dumper, m_structed_data_def_set, ASSET_TYPE_STRUCTURED_DATA_DEF) DUMP_ASSET_POOL(tracer::Dumper, m_tracer, ASSET_TYPE_TRACER) DUMP_ASSET_POOL(vehicle::Dumper, m_vehicle, ASSET_TYPE_VEHICLE) DUMP_ASSET_POOL(addon_map_ents::Dumper, m_addon_map_ents, ASSET_TYPE_ADDON_MAP_ENTS) diff --git a/src/ObjWriting/Game/IW4/StructuredDataDef/AssetDumperStructuredDataDefSet.cpp b/src/ObjWriting/Game/IW4/StructuredDataDef/AssetDumperStructuredDataDefSet.cpp deleted file mode 100644 index f25c6bf4..00000000 --- a/src/ObjWriting/Game/IW4/StructuredDataDef/AssetDumperStructuredDataDefSet.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include "AssetDumperStructuredDataDefSet.h" - -#include "StructuredDataDef/StructuredDataDefDumper.h" - -#include -#include -#include - -using namespace IW4; -using namespace std::string_literals; - -CommonStructuredDataType AssetDumperStructuredDataDefSet::ConvertType(const CommonStructuredDataDef* def, const StructuredDataType in) -{ - CommonStructuredDataType out; - - switch (in.type) - { - case DATA_INT: - out.m_category = CommonStructuredDataTypeCategory::INT; - break; - case DATA_BYTE: - out.m_category = CommonStructuredDataTypeCategory::BYTE; - break; - case DATA_BOOL: - out.m_category = CommonStructuredDataTypeCategory::BOOL; - break; - case DATA_FLOAT: - out.m_category = CommonStructuredDataTypeCategory::FLOAT; - break; - case DATA_SHORT: - out.m_category = CommonStructuredDataTypeCategory::SHORT; - break; - case DATA_STRING: - out.m_category = CommonStructuredDataTypeCategory::STRING; - out.m_info.string_length = in.u.stringDataLength; - break; - case DATA_ENUM: - assert(!def->m_enums.empty()); - out.m_category = CommonStructuredDataTypeCategory::ENUM; - out.m_info.type_index = std::max(std::min(static_cast(in.u.enumIndex), def->m_enums.size() - 1uz), 0uz); - break; - case DATA_STRUCT: - assert(!def->m_structs.empty()); - out.m_category = CommonStructuredDataTypeCategory::STRUCT; - out.m_info.type_index = std::max(std::min(static_cast(in.u.structIndex), def->m_structs.size() - 1uz), 0uz); - break; - case DATA_INDEXED_ARRAY: - assert(!def->m_indexed_arrays.empty()); - out.m_category = CommonStructuredDataTypeCategory::INDEXED_ARRAY; - out.m_info.type_index = std::max(std::min(static_cast(in.u.indexedArrayIndex), def->m_indexed_arrays.size() - 1uz), 0uz); - break; - case DATA_ENUM_ARRAY: - assert(!def->m_enumed_arrays.empty()); - out.m_category = CommonStructuredDataTypeCategory::ENUM_ARRAY; - out.m_info.type_index = std::max(std::min(static_cast(in.u.enumedArrayIndex), def->m_enumed_arrays.size() - 1uz), 0uz); - break; - case DATA_COUNT: - default: - assert(false); - break; - } - - return out; -} - -void AssetDumperStructuredDataDefSet::ConvertEnum(CommonStructuredDataEnum* out, const StructuredDataEnum* in, const size_t enumIndex) -{ - out->m_name = "ENUM_" + std::to_string(enumIndex); - - if (in->reservedEntryCount > 0 && in->reservedEntryCount != in->entryCount) - out->m_reserved_entry_count = std::max(in->reservedEntryCount, 0); - else - out->m_reserved_entry_count = -1; - - out->m_entries.resize(static_cast(std::max(in->entryCount, 0))); - for (auto i = 0u; i < out->m_entries.size(); i++) - { - auto& outEntry = out->m_entries[i]; - const auto& inEntry = in->entries[i]; - - outEntry.m_name = std::string(inEntry.string); - outEntry.m_value = inEntry.index; - } - - out->SortEntriesByOffset(); -} - -void AssetDumperStructuredDataDefSet::ConvertStruct(const CommonStructuredDataDef* def, - const StructuredDataDef* gameDef, - CommonStructuredDataStruct* out, - const StructuredDataStruct* in, - const size_t structIndex) -{ - if (gameDef->rootType.type == DATA_STRUCT && structIndex == static_cast(gameDef->rootType.u.structIndex)) - { - out->m_name = "root"; - out->m_size_in_byte = gameDef->size; - } - else - { - out->m_name = "STRUCT_" + std::to_string(structIndex); - out->m_size_in_byte = static_cast(std::max(in->size, 0)); - } - - out->m_bit_offset = in->bitOffset; - - out->m_properties.resize(static_cast(std::max(in->propertyCount, 0))); - for (auto i = 0u; i < out->m_properties.size(); i++) - { - auto& outProperty = out->m_properties[i]; - const auto& inProperty = in->properties[i]; - - outProperty.m_name = std::string(inProperty.name); - outProperty.m_type = ConvertType(def, inProperty.type); - - if (inProperty.type.type == DATA_BOOL) - outProperty.m_offset_in_bits = inProperty.offset; - else - outProperty.m_offset_in_bits = inProperty.offset * 8; - } - - out->SortPropertiesByOffset(); -} - -void AssetDumperStructuredDataDefSet::ConvertIndexedArray(const CommonStructuredDataDef* def, - CommonStructuredDataIndexedArray* out, - const StructuredDataIndexedArray* in) -{ - out->m_element_count = static_cast(std::max(in->arraySize, 0)); - out->m_element_size_in_bits = in->elementType.type == DATA_BOOL ? 1 : in->elementSize * 8; - out->m_array_type = ConvertType(def, in->elementType); -} - -void AssetDumperStructuredDataDefSet::ConvertEnumedArray(const CommonStructuredDataDef* def, - CommonStructuredDataEnumedArray* out, - const StructuredDataEnumedArray* in) -{ - assert(!def->m_enums.empty()); - out->m_element_size_in_bits = in->elementType.type == DATA_BOOL ? 1 : in->elementSize * 8; - out->m_array_type = ConvertType(def, in->elementType); - out->m_enum_index = std::max(std::min(static_cast(in->enumIndex), def->m_enums.size() - 1uz), 0uz); - - if (def->m_enums.empty()) - { - assert(false); - return; - } - - out->m_element_count = def->m_enums[out->m_enum_index]->ElementCount(); -} - -std::unique_ptr AssetDumperStructuredDataDefSet::ConvertDef(const StructuredDataDef* in) -{ - auto out = std::make_unique(); - - out->m_version = in->version; - out->m_checksum = in->formatChecksum; - out->m_size_in_byte = in->size; - - out->m_enums.resize(static_cast(std::max(in->enumCount, 0))); - out->m_structs.resize(static_cast(std::max(in->structCount, 0))); - out->m_indexed_arrays.resize(static_cast(std::max(in->indexedArrayCount, 0))); - out->m_enumed_arrays.resize(static_cast(std::max(in->enumedArrayCount, 0))); - - for (auto i = 0u; i < out->m_enums.size(); i++) - { - auto _enum = std::make_unique(); - ConvertEnum(_enum.get(), &in->enums[i], i); - out->m_enums[i] = std::move(_enum); - } - for (auto i = 0u; i < out->m_structs.size(); i++) - { - auto _struct = std::make_unique(); - ConvertStruct(out.get(), in, _struct.get(), &in->structs[i], i); - out->m_structs[i] = std::move(_struct); - } - for (auto i = 0u; i < out->m_indexed_arrays.size(); i++) - ConvertIndexedArray(out.get(), &out->m_indexed_arrays[i], &in->indexedArrays[i]); - for (auto i = 0u; i < out->m_enumed_arrays.size(); i++) - ConvertEnumedArray(out.get(), &out->m_enumed_arrays[i], &in->enumedArrays[i]); - - out->m_root_type = ConvertType(out.get(), in->rootType); - - return out; -} - -bool AssetDumperStructuredDataDefSet::ShouldDump(XAssetInfo* asset) -{ - return true; -} - -void AssetDumperStructuredDataDefSet::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) -{ - const auto* set = asset->Asset(); - const auto assetFile = context.OpenAssetFile(asset->m_name); - - if (!assetFile || set->defs == nullptr) - return; - - StructuredDataDefDumper dumper(*assetFile); - for (auto i = 0u; i < set->defCount; i++) - { - const auto def = ConvertDef(&set->defs[i]); - dumper.DumpDef(*def); - } -} diff --git a/src/ObjWriting/Game/IW4/StructuredDataDef/AssetDumperStructuredDataDefSet.h b/src/ObjWriting/Game/IW4/StructuredDataDef/AssetDumperStructuredDataDefSet.h deleted file mode 100644 index 7859af57..00000000 --- a/src/ObjWriting/Game/IW4/StructuredDataDef/AssetDumperStructuredDataDefSet.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "Dumping/AbstractAssetDumper.h" -#include "Game/IW4/IW4.h" -#include "StructuredDataDef/CommonStructuredDataDef.h" - -#include - -namespace IW4 -{ - class AssetDumperStructuredDataDefSet final : public AbstractAssetDumper - { - static CommonStructuredDataType ConvertType(const CommonStructuredDataDef* def, StructuredDataType in); - static void ConvertEnum(CommonStructuredDataEnum* out, const StructuredDataEnum* in, size_t enumIndex); - static void ConvertStruct(const CommonStructuredDataDef* def, - const StructuredDataDef* gameDef, - CommonStructuredDataStruct* out, - const StructuredDataStruct* in, - size_t structIndex); - static void ConvertIndexedArray(const CommonStructuredDataDef* def, CommonStructuredDataIndexedArray* out, const StructuredDataIndexedArray* in); - static void ConvertEnumedArray(const CommonStructuredDataDef* def, CommonStructuredDataEnumedArray* out, const StructuredDataEnumedArray* in); - static std::unique_ptr ConvertDef(const StructuredDataDef* in); - - protected: - bool ShouldDump(XAssetInfo* asset) override; - void DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) override; - }; -} // namespace IW4 diff --git a/src/ObjWriting/Game/IW4/StructuredDataDef/StructuredDataDefDumperIW4.cpp b/src/ObjWriting/Game/IW4/StructuredDataDef/StructuredDataDefDumperIW4.cpp new file mode 100644 index 00000000..22177b7e --- /dev/null +++ b/src/ObjWriting/Game/IW4/StructuredDataDef/StructuredDataDefDumperIW4.cpp @@ -0,0 +1,208 @@ +#include "StructuredDataDefDumperIW4.h" + +#include "StructuredDataDef/StructuredDataDefDumper.h" + +#include +#include +#include + +using namespace IW4; +using namespace std::string_literals; + +namespace +{ + CommonStructuredDataType ConvertType(const CommonStructuredDataDef* def, const StructuredDataType in) + { + CommonStructuredDataType out; + + switch (in.type) + { + case DATA_INT: + out.m_category = CommonStructuredDataTypeCategory::INT; + break; + case DATA_BYTE: + out.m_category = CommonStructuredDataTypeCategory::BYTE; + break; + case DATA_BOOL: + out.m_category = CommonStructuredDataTypeCategory::BOOL; + break; + case DATA_FLOAT: + out.m_category = CommonStructuredDataTypeCategory::FLOAT; + break; + case DATA_SHORT: + out.m_category = CommonStructuredDataTypeCategory::SHORT; + break; + case DATA_STRING: + out.m_category = CommonStructuredDataTypeCategory::STRING; + out.m_info.string_length = in.u.stringDataLength; + break; + case DATA_ENUM: + assert(!def->m_enums.empty()); + out.m_category = CommonStructuredDataTypeCategory::ENUM; + out.m_info.type_index = std::max(std::min(static_cast(in.u.enumIndex), def->m_enums.size() - 1uz), 0uz); + break; + case DATA_STRUCT: + assert(!def->m_structs.empty()); + out.m_category = CommonStructuredDataTypeCategory::STRUCT; + out.m_info.type_index = std::max(std::min(static_cast(in.u.structIndex), def->m_structs.size() - 1uz), 0uz); + break; + case DATA_INDEXED_ARRAY: + assert(!def->m_indexed_arrays.empty()); + out.m_category = CommonStructuredDataTypeCategory::INDEXED_ARRAY; + out.m_info.type_index = std::max(std::min(static_cast(in.u.indexedArrayIndex), def->m_indexed_arrays.size() - 1uz), 0uz); + break; + case DATA_ENUM_ARRAY: + assert(!def->m_enumed_arrays.empty()); + out.m_category = CommonStructuredDataTypeCategory::ENUM_ARRAY; + out.m_info.type_index = std::max(std::min(static_cast(in.u.enumedArrayIndex), def->m_enumed_arrays.size() - 1uz), 0uz); + break; + case DATA_COUNT: + default: + assert(false); + break; + } + + return out; + } + + void ConvertEnum(CommonStructuredDataEnum* out, const StructuredDataEnum* in, const size_t enumIndex) + { + out->m_name = "ENUM_" + std::to_string(enumIndex); + + if (in->reservedEntryCount > 0 && in->reservedEntryCount != in->entryCount) + out->m_reserved_entry_count = std::max(in->reservedEntryCount, 0); + else + out->m_reserved_entry_count = -1; + + out->m_entries.resize(static_cast(std::max(in->entryCount, 0))); + for (auto i = 0u; i < out->m_entries.size(); i++) + { + auto& outEntry = out->m_entries[i]; + const auto& inEntry = in->entries[i]; + + outEntry.m_name = std::string(inEntry.string); + outEntry.m_value = inEntry.index; + } + + out->SortEntriesByOffset(); + } + + void ConvertStruct(const CommonStructuredDataDef* def, + const StructuredDataDef* gameDef, + CommonStructuredDataStruct* out, + const StructuredDataStruct* in, + const size_t structIndex) + { + if (gameDef->rootType.type == DATA_STRUCT && structIndex == static_cast(gameDef->rootType.u.structIndex)) + { + out->m_name = "root"; + out->m_size_in_byte = gameDef->size; + } + else + { + out->m_name = "STRUCT_" + std::to_string(structIndex); + out->m_size_in_byte = static_cast(std::max(in->size, 0)); + } + + out->m_bit_offset = in->bitOffset; + + out->m_properties.resize(static_cast(std::max(in->propertyCount, 0))); + for (auto i = 0u; i < out->m_properties.size(); i++) + { + auto& outProperty = out->m_properties[i]; + const auto& inProperty = in->properties[i]; + + outProperty.m_name = std::string(inProperty.name); + outProperty.m_type = ConvertType(def, inProperty.type); + + if (inProperty.type.type == DATA_BOOL) + outProperty.m_offset_in_bits = inProperty.offset; + else + outProperty.m_offset_in_bits = inProperty.offset * 8; + } + + out->SortPropertiesByOffset(); + } + + void ConvertIndexedArray(const CommonStructuredDataDef* def, CommonStructuredDataIndexedArray* out, const StructuredDataIndexedArray* in) + { + out->m_element_count = static_cast(std::max(in->arraySize, 0)); + out->m_element_size_in_bits = in->elementType.type == DATA_BOOL ? 1 : in->elementSize * 8; + out->m_array_type = ConvertType(def, in->elementType); + } + + void ConvertEnumedArray(const CommonStructuredDataDef* def, CommonStructuredDataEnumedArray* out, const StructuredDataEnumedArray* in) + { + assert(!def->m_enums.empty()); + out->m_element_size_in_bits = in->elementType.type == DATA_BOOL ? 1 : in->elementSize * 8; + out->m_array_type = ConvertType(def, in->elementType); + out->m_enum_index = std::max(std::min(static_cast(in->enumIndex), def->m_enums.size() - 1uz), 0uz); + + if (def->m_enums.empty()) + { + assert(false); + return; + } + + out->m_element_count = def->m_enums[out->m_enum_index]->ElementCount(); + } + + std::unique_ptr ConvertDef(const StructuredDataDef* in) + { + auto out = std::make_unique(); + + out->m_version = in->version; + out->m_checksum = in->formatChecksum; + out->m_size_in_byte = in->size; + + out->m_enums.resize(static_cast(std::max(in->enumCount, 0))); + out->m_structs.resize(static_cast(std::max(in->structCount, 0))); + out->m_indexed_arrays.resize(static_cast(std::max(in->indexedArrayCount, 0))); + out->m_enumed_arrays.resize(static_cast(std::max(in->enumedArrayCount, 0))); + + for (auto i = 0u; i < out->m_enums.size(); i++) + { + auto _enum = std::make_unique(); + ConvertEnum(_enum.get(), &in->enums[i], i); + out->m_enums[i] = std::move(_enum); + } + for (auto i = 0u; i < out->m_structs.size(); i++) + { + auto _struct = std::make_unique(); + ConvertStruct(out.get(), in, _struct.get(), &in->structs[i], i); + out->m_structs[i] = std::move(_struct); + } + for (auto i = 0u; i < out->m_indexed_arrays.size(); i++) + ConvertIndexedArray(out.get(), &out->m_indexed_arrays[i], &in->indexedArrays[i]); + for (auto i = 0u; i < out->m_enumed_arrays.size(); i++) + ConvertEnumedArray(out.get(), &out->m_enumed_arrays[i], &in->enumedArrays[i]); + + out->m_root_type = ConvertType(out.get(), in->rootType); + + return out; + } +} // namespace + +namespace IW4::structured_data_def +{ + bool Dumper::ShouldDump(XAssetInfo* asset) + { + return true; + } + + void Dumper::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) + { + const auto* set = asset->Asset(); + const auto assetFile = context.OpenAssetFile(asset->m_name); + + if (!assetFile || set->defs == nullptr) + return; + + StructuredDataDefDumper dumper(*assetFile); + for (auto i = 0u; i < set->defCount; i++) + { + const auto def = ConvertDef(&set->defs[i]); + dumper.DumpDef(*def); + } + } +} // namespace IW4::structured_data_def diff --git a/src/ObjWriting/Game/IW4/StructuredDataDef/StructuredDataDefDumperIW4.h b/src/ObjWriting/Game/IW4/StructuredDataDef/StructuredDataDefDumperIW4.h new file mode 100644 index 00000000..da36a645 --- /dev/null +++ b/src/ObjWriting/Game/IW4/StructuredDataDef/StructuredDataDefDumperIW4.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/IW4/IW4.h" +#include "StructuredDataDef/CommonStructuredDataDef.h" + +#include + +namespace IW4::structured_data_def +{ + class Dumper final : public AbstractAssetDumper + { + protected: + bool ShouldDump(XAssetInfo* asset) override; + void DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) override; + }; +} // namespace IW4::structured_data_def