mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-20 00:02:55 +00:00
Dump StructuredDataDef paddings
This commit is contained in:
parent
f235ffc431
commit
73564cf0f0
@ -4,9 +4,11 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
StructuredDataDefDumper::StructEntry::StructEntry(std::string stringValue, const size_t offset)
|
StructuredDataDefDumper::StructEntry::StructEntry(std::string stringValue, const size_t offset, const size_t sizeInBits, const size_t alignment)
|
||||||
: m_string_value(std::move(stringValue)),
|
: m_string_value(std::move(stringValue)),
|
||||||
m_offset(offset)
|
m_offset(offset),
|
||||||
|
m_size_in_bits(sizeInBits),
|
||||||
|
m_alignment(alignment)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,7 +18,9 @@ StructuredDataDefDumper::StructuredDataDefDumper(std::ostream& stream)
|
|||||||
m_flags{},
|
m_flags{},
|
||||||
m_enum_entry_count(0u),
|
m_enum_entry_count(0u),
|
||||||
m_struct_property_count(0u),
|
m_struct_property_count(0u),
|
||||||
m_current_property_offset(0u)
|
m_current_property_offset(0u),
|
||||||
|
m_current_property_size_in_bits(0u),
|
||||||
|
m_current_property_alignment(0u)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +79,7 @@ void StructuredDataDefDumper::BeginEnum(const std::string& enumName, const size_
|
|||||||
m_stream << "enum(" << enumReservedEntryCount << ") ";
|
m_stream << "enum(" << enumReservedEntryCount << ") ";
|
||||||
else
|
else
|
||||||
m_stream << "enum ";
|
m_stream << "enum ";
|
||||||
m_stream << enumName;
|
m_stream << enumName;
|
||||||
|
|
||||||
m_stream << "\n";
|
m_stream << "\n";
|
||||||
|
|
||||||
@ -130,7 +134,7 @@ void StructuredDataDefDumper::WriteEnumEntry(const std::string& entryName, const
|
|||||||
m_enum_entries[entryValue] = entryName;
|
m_enum_entries[entryValue] = entryName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StructuredDataDefDumper::BeginStruct(const std::string& structName, const size_t structPropertyCount)
|
void StructuredDataDefDumper::BeginStruct(const std::string& structName, const size_t structPropertyCount, const size_t structSizeInBits, const size_t structInitialOffset)
|
||||||
{
|
{
|
||||||
assert(m_flags.m_in_version);
|
assert(m_flags.m_in_version);
|
||||||
assert(m_block == Block::BLOCK_NONE);
|
assert(m_block == Block::BLOCK_NONE);
|
||||||
@ -139,6 +143,8 @@ void StructuredDataDefDumper::BeginStruct(const std::string& structName, const s
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
m_struct_property_count = structPropertyCount;
|
m_struct_property_count = structPropertyCount;
|
||||||
|
m_struct_size_in_bits = structSizeInBits;
|
||||||
|
m_struct_initial_offset = structInitialOffset;
|
||||||
m_struct_properties.reserve(structPropertyCount);
|
m_struct_properties.reserve(structPropertyCount);
|
||||||
|
|
||||||
if (m_flags.m_empty_line_before_block)
|
if (m_flags.m_empty_line_before_block)
|
||||||
@ -166,10 +172,34 @@ void StructuredDataDefDumper::EndStruct()
|
|||||||
return e1.m_offset < e2.m_offset;
|
return e1.m_offset < e2.m_offset;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
auto expectedOffset = m_struct_initial_offset;
|
||||||
for (auto& structProperty : m_struct_properties)
|
for (auto& structProperty : m_struct_properties)
|
||||||
{
|
{
|
||||||
|
if (structProperty.m_alignment > 0)
|
||||||
|
expectedOffset = (expectedOffset + structProperty.m_alignment - 1) / structProperty.m_alignment * structProperty.m_alignment;
|
||||||
|
|
||||||
|
if(expectedOffset != structProperty.m_offset)
|
||||||
|
{
|
||||||
|
assert(structProperty.m_offset > expectedOffset);
|
||||||
|
assert((structProperty.m_offset - expectedOffset) % 8 == 0);
|
||||||
|
Indent();
|
||||||
|
m_stream << "pad(" << (structProperty.m_offset - expectedOffset) << ");\n";
|
||||||
|
expectedOffset = structProperty.m_offset;
|
||||||
|
}
|
||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
m_stream << structProperty.m_string_value << ";\n";
|
m_stream << structProperty.m_string_value << ";\n";
|
||||||
|
|
||||||
|
expectedOffset += structProperty.m_size_in_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOffset = (expectedOffset + 7) / 8 * 8;
|
||||||
|
if (m_struct_size_in_bits > 0 && expectedOffset != m_struct_size_in_bits)
|
||||||
|
{
|
||||||
|
assert(m_struct_size_in_bits > expectedOffset);
|
||||||
|
assert((m_struct_size_in_bits - expectedOffset) % 8 == 0);
|
||||||
|
Indent();
|
||||||
|
m_stream << "pad(" << (m_struct_size_in_bits - expectedOffset) / 8 << ");\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
DecIndent();
|
DecIndent();
|
||||||
@ -179,9 +209,11 @@ void StructuredDataDefDumper::EndStruct()
|
|||||||
m_flags.m_empty_line_before_block = true;
|
m_flags.m_empty_line_before_block = true;
|
||||||
m_struct_properties.clear();
|
m_struct_properties.clear();
|
||||||
m_struct_property_count = 0u;
|
m_struct_property_count = 0u;
|
||||||
|
m_struct_initial_offset = 0u;
|
||||||
|
m_struct_size_in_bits = 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StructuredDataDefDumper::BeginProperty(const std::string& propertyName, const size_t propertyOffset)
|
void StructuredDataDefDumper::BeginProperty(const std::string& propertyName, const size_t propertyOffset, const size_t propertySizeInBits, const size_t alignment)
|
||||||
{
|
{
|
||||||
assert(m_flags.m_in_version);
|
assert(m_flags.m_in_version);
|
||||||
assert(m_block == Block::BLOCK_STRUCT);
|
assert(m_block == Block::BLOCK_STRUCT);
|
||||||
@ -191,6 +223,8 @@ void StructuredDataDefDumper::BeginProperty(const std::string& propertyName, con
|
|||||||
|
|
||||||
m_current_property_name = propertyName;
|
m_current_property_name = propertyName;
|
||||||
m_current_property_offset = propertyOffset;
|
m_current_property_offset = propertyOffset;
|
||||||
|
m_current_property_size_in_bits = propertySizeInBits;
|
||||||
|
m_current_property_alignment = alignment;
|
||||||
|
|
||||||
m_block = Block::BLOCK_PROPERTY;
|
m_block = Block::BLOCK_PROPERTY;
|
||||||
}
|
}
|
||||||
@ -226,7 +260,7 @@ void StructuredDataDefDumper::EndProperty()
|
|||||||
ss << " + " << m_current_property_offset % 8 << "bit";
|
ss << " + " << m_current_property_offset % 8 << "bit";
|
||||||
|
|
||||||
ss << " */ ";
|
ss << " */ ";
|
||||||
m_struct_properties.emplace_back(ss.str(), m_current_property_offset);
|
m_struct_properties.emplace_back(ss.str(), m_current_property_offset, m_current_property_size_in_bits, m_current_property_alignment);
|
||||||
|
|
||||||
m_block = Block::BLOCK_STRUCT;
|
m_block = Block::BLOCK_STRUCT;
|
||||||
m_current_property_array_specifiers.clear();
|
m_current_property_array_specifiers.clear();
|
||||||
|
@ -10,8 +10,10 @@ class StructuredDataDefDumper : AbstractTextDumper
|
|||||||
{
|
{
|
||||||
std::string m_string_value;
|
std::string m_string_value;
|
||||||
size_t m_offset;
|
size_t m_offset;
|
||||||
|
size_t m_size_in_bits;
|
||||||
|
size_t m_alignment;
|
||||||
|
|
||||||
StructEntry(std::string stringValue, size_t offset);
|
StructEntry(std::string stringValue, size_t offset, size_t sizeInBits, size_t alignment);
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Block
|
enum class Block
|
||||||
@ -34,8 +36,12 @@ class StructuredDataDefDumper : AbstractTextDumper
|
|||||||
|
|
||||||
std::vector<StructEntry> m_struct_properties;
|
std::vector<StructEntry> m_struct_properties;
|
||||||
size_t m_struct_property_count;
|
size_t m_struct_property_count;
|
||||||
|
size_t m_struct_initial_offset;
|
||||||
|
size_t m_struct_size_in_bits;
|
||||||
std::string m_current_property_name;
|
std::string m_current_property_name;
|
||||||
size_t m_current_property_offset;
|
size_t m_current_property_offset;
|
||||||
|
size_t m_current_property_size_in_bits;
|
||||||
|
size_t m_current_property_alignment;
|
||||||
std::string m_current_property_type_name;
|
std::string m_current_property_type_name;
|
||||||
std::vector<std::string> m_current_property_array_specifiers;
|
std::vector<std::string> m_current_property_array_specifiers;
|
||||||
|
|
||||||
@ -51,9 +57,9 @@ public:
|
|||||||
void EndEnum();
|
void EndEnum();
|
||||||
void WriteEnumEntry(const std::string& entryName, size_t entryValue);
|
void WriteEnumEntry(const std::string& entryName, size_t entryValue);
|
||||||
|
|
||||||
void BeginStruct(const std::string& structName, size_t structPropertyCount);
|
void BeginStruct(const std::string& structName, size_t structPropertyCount, size_t structSizeInBits, size_t structInitialOffset);
|
||||||
void EndStruct();
|
void EndStruct();
|
||||||
void BeginProperty(const std::string& propertyName, size_t propertyOffset);
|
void BeginProperty(const std::string& propertyName, size_t propertyOffset, size_t propertySizeInBits, size_t alignment);
|
||||||
void AddPropertyArraySpecifier(const std::string& specifierName);
|
void AddPropertyArraySpecifier(const std::string& specifierName);
|
||||||
void SetPropertyTypeName(const std::string& typeName);
|
void SetPropertyTypeName(const std::string& typeName);
|
||||||
void EndProperty();
|
void EndProperty();
|
||||||
|
@ -11,7 +11,7 @@ using namespace std::string_literals;
|
|||||||
|
|
||||||
bool AssetDumperStructuredDataDefSet::GetNextHeadValue(const StructuredDataDef* def, const bool isFirstStruct, const std::vector<bool>& structsIncludedInOrder, size_t& nextHeadValue)
|
bool AssetDumperStructuredDataDefSet::GetNextHeadValue(const StructuredDataDef* def, const bool isFirstStruct, const std::vector<bool>& structsIncludedInOrder, size_t& nextHeadValue)
|
||||||
{
|
{
|
||||||
if(isFirstStruct
|
if (isFirstStruct
|
||||||
&& def->rootType.type == DATA_STRUCT
|
&& def->rootType.type == DATA_STRUCT
|
||||||
&& def->rootType.u.structIndex >= 0
|
&& def->rootType.u.structIndex >= 0
|
||||||
&& def->rootType.u.structIndex < def->structCount)
|
&& def->rootType.u.structIndex < def->structCount)
|
||||||
@ -32,7 +32,7 @@ bool AssetDumperStructuredDataDefSet::GetNextHeadValue(const StructuredDataDef*
|
|||||||
|
|
||||||
StructuredDataType AssetDumperStructuredDataDefSet::GetBaseType(const StructuredDataDef* def, StructuredDataType type)
|
StructuredDataType AssetDumperStructuredDataDefSet::GetBaseType(const StructuredDataDef* def, StructuredDataType type)
|
||||||
{
|
{
|
||||||
while(true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (type.type == DATA_INDEXED_ARRAY)
|
if (type.type == DATA_INDEXED_ARRAY)
|
||||||
{
|
{
|
||||||
@ -69,7 +69,7 @@ std::vector<size_t> AssetDumperStructuredDataDefSet::CalculateStructDumpingOrder
|
|||||||
result.reserve(def->structCount);
|
result.reserve(def->structCount);
|
||||||
std::vector<bool> structIncludedInOrder(def->structCount);
|
std::vector<bool> structIncludedInOrder(def->structCount);
|
||||||
|
|
||||||
while(resultStructTail < structCount)
|
while (resultStructTail < structCount)
|
||||||
{
|
{
|
||||||
size_t nextHeadValue;
|
size_t nextHeadValue;
|
||||||
if (!GetNextHeadValue(def, resultStructHead == 0, structIncludedInOrder, nextHeadValue))
|
if (!GetNextHeadValue(def, resultStructHead == 0, structIncludedInOrder, nextHeadValue))
|
||||||
@ -78,17 +78,17 @@ std::vector<size_t> AssetDumperStructuredDataDefSet::CalculateStructDumpingOrder
|
|||||||
structIncludedInOrder[nextHeadValue] = true;
|
structIncludedInOrder[nextHeadValue] = true;
|
||||||
++resultStructHead;
|
++resultStructHead;
|
||||||
|
|
||||||
while(resultStructHead > resultStructTail)
|
while (resultStructHead > resultStructTail)
|
||||||
{
|
{
|
||||||
const auto& currentStruct = def->structs[result[resultStructTail++]];
|
const auto& currentStruct = def->structs[result[resultStructTail++]];
|
||||||
|
|
||||||
if(currentStruct.properties == nullptr)
|
if (currentStruct.properties == nullptr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for(auto i = 0; i < currentStruct.propertyCount; i++)
|
for (auto i = 0; i < currentStruct.propertyCount; i++)
|
||||||
{
|
{
|
||||||
const auto baseType = GetBaseType(def, currentStruct.properties[i].type);
|
const auto baseType = GetBaseType(def, currentStruct.properties[i].type);
|
||||||
if(baseType.type == DATA_STRUCT
|
if (baseType.type == DATA_STRUCT
|
||||||
&& baseType.u.structIndex >= 0
|
&& baseType.u.structIndex >= 0
|
||||||
&& static_cast<size_t>(baseType.u.structIndex) < structCount
|
&& static_cast<size_t>(baseType.u.structIndex) < structCount
|
||||||
&& structIncludedInOrder[static_cast<size_t>(baseType.u.structIndex)] == false)
|
&& structIncludedInOrder[static_cast<size_t>(baseType.u.structIndex)] == false)
|
||||||
@ -116,7 +116,7 @@ void AssetDumperStructuredDataDefSet::DumpEnum(StructuredDataDefDumper& dumper,
|
|||||||
|
|
||||||
dumper.BeginEnum(ss.str(), static_cast<size_t>(_enum->entryCount), static_cast<size_t>(_enum->reservedEntryCount));
|
dumper.BeginEnum(ss.str(), static_cast<size_t>(_enum->entryCount), static_cast<size_t>(_enum->reservedEntryCount));
|
||||||
|
|
||||||
if(_enum->entries && _enum->entryCount > 0)
|
if (_enum->entries && _enum->entryCount > 0)
|
||||||
{
|
{
|
||||||
for (auto i = 0; i < _enum->entryCount; i++)
|
for (auto i = 0; i < _enum->entryCount; i++)
|
||||||
{
|
{
|
||||||
@ -133,9 +133,72 @@ void AssetDumperStructuredDataDefSet::DumpEnum(StructuredDataDefDumper& dumper,
|
|||||||
dumper.EndEnum();
|
dumper.EndEnum();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t AssetDumperStructuredDataDefSet::GetPropertySizeInBits(const StructuredDataStructProperty& property, const StructuredDataDef* def)
|
||||||
|
{
|
||||||
|
switch (property.type.type)
|
||||||
|
{
|
||||||
|
case DATA_FLOAT:
|
||||||
|
case DATA_INT:
|
||||||
|
return 32;
|
||||||
|
case DATA_BYTE:
|
||||||
|
return 8;
|
||||||
|
case DATA_BOOL:
|
||||||
|
return 1;
|
||||||
|
case DATA_SHORT:
|
||||||
|
case DATA_ENUM:
|
||||||
|
return 16;
|
||||||
|
case DATA_STRING:
|
||||||
|
return property.type.u.stringDataLength * 8;
|
||||||
|
case DATA_STRUCT:
|
||||||
|
if (property.type.u.structIndex < 0 || property.type.u.structIndex >= def->structCount || def->structs == nullptr)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return static_cast<size_t>(def->structs[property.type.u.structIndex].size) * 8;
|
||||||
|
case DATA_INDEXED_ARRAY:
|
||||||
|
{
|
||||||
|
if (property.type.u.indexedArrayIndex < 0 || property.type.u.indexedArrayIndex >= def->indexedArrayCount || def->indexedArrays == nullptr)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const auto& indexedArray = def->indexedArrays[property.type.u.indexedArrayIndex];
|
||||||
|
const auto elementSize = indexedArray.elementType.type == DATA_BOOL ? 1 : indexedArray.elementSize * 8;
|
||||||
|
return elementSize * static_cast<size_t>(def->indexedArrays[property.type.u.indexedArrayIndex].arraySize);
|
||||||
|
}
|
||||||
|
case DATA_ENUM_ARRAY:
|
||||||
|
{
|
||||||
|
if (property.type.u.enumedArrayIndex < 0 || property.type.u.enumedArrayIndex >= def->enumedArrayCount || def->enumedArrays == nullptr)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& enumedArray = def->enumedArrays[property.type.u.enumedArrayIndex];
|
||||||
|
if (enumedArray.enumIndex < 0 || enumedArray.enumIndex >= def->enumCount || def->enums == nullptr)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto elementSize = enumedArray.elementType.type == DATA_BOOL ? 1 : enumedArray.elementSize * 8;
|
||||||
|
return elementSize * static_cast<size_t>(def->enums[enumedArray.enumIndex].reservedEntryCount);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AssetDumperStructuredDataDefSet::GetPropertyAlign(const StructuredDataStructProperty& property)
|
||||||
|
{
|
||||||
|
return property.type.type == DATA_BOOL ? 0 : 8;
|
||||||
|
}
|
||||||
|
|
||||||
void AssetDumperStructuredDataDefSet::DumpProperty(StructuredDataDefDumper& dumper, const StructuredDataStructProperty& property, const StructuredDataDef* def, const int rootStructIndex)
|
void AssetDumperStructuredDataDefSet::DumpProperty(StructuredDataDefDumper& dumper, const StructuredDataStructProperty& property, const StructuredDataDef* def, const int rootStructIndex)
|
||||||
{
|
{
|
||||||
dumper.BeginProperty(property.name, property.type.type == DATA_BOOL ? property.offset : property.offset * 8);
|
dumper.BeginProperty(property.name, property.type.type == DATA_BOOL ? property.offset : property.offset * 8, GetPropertySizeInBits(property, def), GetPropertyAlign(property));
|
||||||
|
|
||||||
auto currentType = property.type;
|
auto currentType = property.type;
|
||||||
auto stopTypeIteration = false;
|
auto stopTypeIteration = false;
|
||||||
@ -242,25 +305,32 @@ void AssetDumperStructuredDataDefSet::DumpProperty(StructuredDataDefDumper& dump
|
|||||||
dumper.EndProperty();
|
dumper.EndProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetDumperStructuredDataDefSet::DumpStruct(StructuredDataDefDumper& dumper, const size_t structIndex, const StructuredDataStruct* _struct, const StructuredDataDef* def, const int rootStructIndex)
|
void AssetDumperStructuredDataDefSet::DumpStruct(StructuredDataDefDumper& dumper, const size_t structIndex, const StructuredDataStruct* _struct, const StructuredDataDef* def,
|
||||||
|
const int rootStructIndex)
|
||||||
{
|
{
|
||||||
std::string structName;
|
std::string structName;
|
||||||
|
size_t actualStructSize;
|
||||||
|
size_t initialOffset;
|
||||||
if (static_cast<int>(structIndex) == rootStructIndex)
|
if (static_cast<int>(structIndex) == rootStructIndex)
|
||||||
{
|
{
|
||||||
structName = "root";
|
structName = "root";
|
||||||
|
actualStructSize = def->size;
|
||||||
|
initialOffset = 64;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << "STRUCT_" << structIndex;
|
ss << "STRUCT_" << structIndex;
|
||||||
structName = ss.str();
|
structName = ss.str();
|
||||||
|
actualStructSize = static_cast<size_t>(_struct->size);
|
||||||
|
initialOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dumper.WriteLineComment("BitOffset: "s + std::to_string(_struct->bitOffset));
|
dumper.WriteLineComment("BitOffset: "s + std::to_string(_struct->bitOffset));
|
||||||
dumper.WriteLineComment("Size: "s + std::to_string(_struct->size));
|
dumper.WriteLineComment("Size: "s + std::to_string(_struct->size));
|
||||||
dumper.BeginStruct(structName, static_cast<size_t>(_struct->propertyCount));
|
dumper.BeginStruct(structName, static_cast<size_t>(_struct->propertyCount), actualStructSize * 8, initialOffset);
|
||||||
|
|
||||||
if(_struct->properties && _struct->propertyCount > 0)
|
if (_struct->properties && _struct->propertyCount > 0)
|
||||||
{
|
{
|
||||||
for (auto i = 0; i < _struct->propertyCount; i++)
|
for (auto i = 0; i < _struct->propertyCount; i++)
|
||||||
{
|
{
|
||||||
|
@ -15,6 +15,8 @@ namespace IW4
|
|||||||
static StructuredDataType GetBaseType(const StructuredDataDef* def, StructuredDataType type);
|
static StructuredDataType GetBaseType(const StructuredDataDef* def, StructuredDataType type);
|
||||||
static std::vector<size_t> CalculateStructDumpingOrder(const StructuredDataDef* def);
|
static std::vector<size_t> CalculateStructDumpingOrder(const StructuredDataDef* def);
|
||||||
static void DumpEnum(StructuredDataDefDumper& dumper, int enumIndex, const StructuredDataEnum* _enum);
|
static void DumpEnum(StructuredDataDefDumper& dumper, int enumIndex, const StructuredDataEnum* _enum);
|
||||||
|
static size_t GetPropertySizeInBits(const StructuredDataStructProperty& property, const StructuredDataDef* def);
|
||||||
|
static size_t GetPropertyAlign(const StructuredDataStructProperty& property);
|
||||||
static void DumpProperty(StructuredDataDefDumper& dumper, const StructuredDataStructProperty& property, const StructuredDataDef* def, int rootStructIndex);
|
static void DumpProperty(StructuredDataDefDumper& dumper, const StructuredDataStructProperty& property, const StructuredDataDef* def, int rootStructIndex);
|
||||||
static void DumpStruct(StructuredDataDefDumper& dumper, size_t structIndex, const StructuredDataStruct* _struct, const StructuredDataDef* def, int rootStructIndex);
|
static void DumpStruct(StructuredDataDefDumper& dumper, size_t structIndex, const StructuredDataStruct* _struct, const StructuredDataDef* def, int rootStructIndex);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user