diff --git a/src/dependency/minidef/src/CppGen.cpp b/src/dependency/minidef/src/CppGen.cpp index e1403d5..86e5869 100644 --- a/src/dependency/minidef/src/CppGen.cpp +++ b/src/dependency/minidef/src/CppGen.cpp @@ -16,6 +16,7 @@ namespace WriteTemplates constexpr char FileHeaderStart[] = R"END(#pragma once #include +#include namespace Gen { @@ -101,24 +102,115 @@ namespace Gen )END"; constexpr char LoadFuncBodyStart1[] = R"END( bool Load(%s* obj, uint32_t count, Deserializer& serializer) { +)END"; + constexpr char LoadFuncBodySetupStart2[] = + R"END( const char* typeName = Meta::Metadata.TypeDefinitions[%s::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[%s::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { +)END"; + constexpr char LoadFuncBodyQuickLoad2[] = R"END( isOk = Load(%sobj[i].%s, %u, serializer) && isOk; +)END"; + constexpr char LoadFuncBodySetupEnd[] = R"END( } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; +)END"; + constexpr char LoadFuncBodyMemberCheck4[] = + R"END( if (bx::strCmp(memberName, "%s") == 0 && bx::strCmp(memberTypeName, "%s") == 0) + { + WriteDestinations[i] = offsetof(%s, %s); + } +)END"; + constexpr char LoadFuncBodyTypeUpgradeStart[] = R"END( } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + )END"; - constexpr char LoadFuncBodyType3[] = R"END( isOk = Load(%sobj[i].%s, %u, serializer) && isOk; + constexpr char LoadFuncBodyTypeUpgradeMember3[] = R"END( if (bx::strCmp(memberName, "%s") == 0) + { + auto* fieldPtr = reinterpret_cast<%s*>(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, %u, serializer) && isOk; + continue; + } )END"; - constexpr char LoadFuncBodyNative[] = R"END( isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; -)END"; - constexpr char LoadFuncBodyEnum2[] = R"END( %s& val = (%s&)obj[i]; - isOk = Load(&val, 1, serializer) && isOk; -)END"; - constexpr char LoadFuncBodyEnd[] = R"END( } + constexpr char LoadFuncBodyTypeUpgradeEnd[] = R"END( assert(false); + } + } + assert(isOk); + return isOk; + } +)END"; + constexpr char LoadFuncBodyNative[] = R"END( bool isOk = true; + for (int32_t i = 0; i < count; ++i) + { + isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; + } + return isOk; + } +)END"; + constexpr char LoadFuncBodyEnum2[] = R"END( bool isOk = true; + for (int32_t i = 0; i < count; ++i) + { + %s& val = (%s&)obj[i]; + isOk = Load(&val, 1, serializer) && isOk; + } return isOk; } )END"; - constexpr char MetadataStart1[] = R"END( namespace Meta { + struct StrRef + { + uint16_t Offset; + uint16_t Size; + }; + struct TypeDef { uint32_t Size = 0; @@ -126,6 +218,7 @@ namespace Gen char Name[64]{"Dummy"}; uint16_t ChildCount = 0; uint16_t ChildIndices[64]{0}; + StrRef MemberNameIndices[64]{0}; }; struct EnumDef @@ -140,7 +233,7 @@ namespace Gen { )END"; - constexpr char MetadataTypeEntry5[] = R"END( TypeDef{sizeof(%s), %u, "%s", %u, {%s}}, + constexpr char MetadataTypeEntry6[] = R"END( TypeDef{sizeof(%s), %u, "%s", %u, {%s}, {%s}}, )END"; constexpr char MetadataEnumStart1[] = R"END( }; EnumDef EnumDefinitions[%u] @@ -148,7 +241,8 @@ namespace Gen )END"; constexpr char MetadataEnumEntry2[] = R"END( EnumDef{sizeof(%s::Enum), %u}, )END"; - constexpr char MetadataEnd[] = R"END( }; + constexpr char MetadataEnd1[] = R"END( }; + char MemberNameBuffer[64*64*64]{"%s"}; }; constexpr MetadataTable Metadata; @@ -317,7 +411,6 @@ void CppFileWriter::WriteSaveLoadMethods(const Def::DefinitionFile& definitions) WriteCpp(WriteTemplates::LoadFuncBodyStart1, nameBuf); WriteCpp(WriteTemplates::LoadFuncBodyEnum2, fieldBuf, fieldBuf); - WriteCpp(WriteTemplates::LoadFuncBodyEnd); } for (uint16_t typeIdx = 0; typeIdx < definitions.TypeCount; ++typeIdx) { @@ -329,13 +422,13 @@ void CppFileWriter::WriteSaveLoadMethods(const Def::DefinitionFile& definitions) Write(WriteTemplates::LoadFuncHeader1, typeName); WriteCpp(WriteTemplates::SaveFuncBodyStart1, typeName); - for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx) + if ((int32_t)t.TypeFlags & (int32_t)Def::ETypeFlags::IsNative) { - if (Def::IsFieldNative(definitions, t, fieldIdx)) - { - WriteCpp(WriteTemplates::SaveFuncBodyNative); - } - else + WriteCpp(WriteTemplates::SaveFuncBodyNative); + } + else + { + for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx) { WriteCpp(WriteTemplates::SaveFuncBodyType3, t.FieldArraySizes[fieldIdx] > 0 ? "" : "&", @@ -346,30 +439,55 @@ void CppFileWriter::WriteSaveLoadMethods(const Def::DefinitionFile& definitions) WriteCpp(WriteTemplates::SaveFuncBodyEnd); WriteCpp(WriteTemplates::LoadFuncBodyStart1, typeName); - for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx) + if ((int32_t)t.TypeFlags & (int32_t)Def::ETypeFlags::IsNative) { - if (Def::IsFieldNative(definitions, t, fieldIdx)) + WriteCpp(WriteTemplates::LoadFuncBodyNative); + } + else + { + WriteCpp(WriteTemplates::LoadFuncBodySetupStart2, typeName, typeName); + for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx) { - WriteCpp(WriteTemplates::LoadFuncBodyNative); - } - else - { - WriteCpp(WriteTemplates::LoadFuncBodyType3, + WriteCpp(WriteTemplates::LoadFuncBodyQuickLoad2, t.FieldArraySizes[fieldIdx] > 0 ? "" : "&", t.FieldNames[fieldIdx], bx::max(1, t.FieldArraySizes[fieldIdx])); } + WriteCpp(WriteTemplates::LoadFuncBodySetupEnd); + char fieldTypeName[Def::MaxNameLength]{0}; + for (int32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx) + { + const char* fieldName = t.FieldNames[fieldIdx]; + PrintTypeName(fieldTypeName, sizeof(fieldTypeName), t.FieldTypes[fieldIdx], definitions); + WriteCpp(WriteTemplates::LoadFuncBodyMemberCheck4, fieldName, fieldTypeName, typeName, fieldName); + } + WriteCpp(WriteTemplates::LoadFuncBodyTypeUpgradeStart); + for (uint32_t fieldIdx = 0; fieldIdx < t.FieldCount; ++fieldIdx) + { + const char* fieldName = t.FieldNames[fieldIdx]; + PrintTypeName(fieldTypeName, sizeof(fieldTypeName), t.FieldTypes[fieldIdx], definitions); + WriteCpp(WriteTemplates::LoadFuncBodyTypeUpgradeMember3, + fieldName, + fieldTypeName, + bx::max(1, t.FieldArraySizes[fieldIdx])); + } + WriteCpp(WriteTemplates::LoadFuncBodyTypeUpgradeEnd); } - WriteCpp(WriteTemplates::LoadFuncBodyEnd); } } +namespace +{ + char MemberNameBuffer[64 * 64 * 64]{0}; +} void CppFileWriter::WriteMetadata(const Def::DefinitionFile& definitions) { + uint32_t memberNameBufferIdx = 0; Write(WriteTemplates::MetadataStart1, definitions.TypeCount); for (uint16_t i = 0; i < definitions.TypeCount; ++i) { auto& type = definitions.Types[i]; + char fieldStr[256]{0}; for (int32_t j = 0; j < type.FieldCount; ++j) { @@ -378,16 +496,31 @@ void CppFileWriter::WriteMetadata(const Def::DefinitionFile& definitions) bx::snprintf(numBuf, sizeof(numBuf), "%u", type.FieldTypes[j].TypeIdx); bx::strCat(fieldStr, sizeof(fieldStr), numBuf); } + char typeStr[Def::MaxNameLength]{0}; PrintTypeName(typeStr, sizeof(typeStr), {i, Def::EFieldType::DefinedClass}, definitions); - Write(WriteTemplates::MetadataTypeEntry5, typeStr, type.Hash, type.Name, type.FieldCount, fieldStr); + + char memberIdxStr[256]{0}; + for (int32_t j = 0; j < type.FieldCount; ++j) + { + if (j != 0) bx::strCat(memberIdxStr, sizeof(memberIdxStr), ", "); + char numBuf[16]{0}; + bx::snprintf(numBuf, sizeof(numBuf), "{%u, %u}", memberNameBufferIdx, bx::strLen(type.FieldNames[j])); + bx::strCat(memberIdxStr, sizeof(memberIdxStr), numBuf); + + memberNameBufferIdx += bx::strCopy(&MemberNameBuffer[memberNameBufferIdx], + sizeof(MemberNameBuffer) - memberNameBufferIdx, + type.FieldNames[j]); + } + Write( + WriteTemplates::MetadataTypeEntry6, typeStr, type.Hash, type.Name, type.FieldCount, fieldStr, memberIdxStr); } Write(WriteTemplates::MetadataEnumStart1, definitions.EnumCount); for (int32_t i = 0; i < definitions.EnumCount; ++i) { Write(WriteTemplates::MetadataEnumEntry2, definitions.Enums[i].Name, definitions.Enums[i].Hash); } - Write(WriteTemplates::MetadataEnd); + Write(WriteTemplates::MetadataEnd1, MemberNameBuffer); } void CppFileWriter::GenerateCpp(const bx::FilePath& outDir, const Def::DefinitionFile& definitions) diff --git a/src/dependency/minidef/src/TypeDef.h b/src/dependency/minidef/src/TypeDef.h index 9c826af..46a5d2a 100644 --- a/src/dependency/minidef/src/TypeDef.h +++ b/src/dependency/minidef/src/TypeDef.h @@ -69,10 +69,4 @@ namespace Def Def::Enum Enums[MaxTypes]; int32_t EnumCount = 0; }; - - inline bool IsFieldNative(const DefinitionFile& definitions, const Type& type, int32_t fieldIdx) - { - return ((int32_t)definitions.Types[type.FieldTypes[fieldIdx].TypeIdx].TypeFlags & - (int32_t)ETypeFlags::IsNative) > 0; - } } // namespace Def diff --git a/src/game/data/puzzles/0.pzl b/src/game/data/puzzles/0.pzl index b77e183..9cc6241 100644 --- a/src/game/data/puzzles/0.pzl +++ b/src/game/data/puzzles/0.pzl @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ef2d44462dab03d7e883594504094bbfdc4d3dcd6dc6c77eee5399a4be29e627 -size 26220 +oid sha256:ca6a40c1c01e7b8af1f496e0f1d6608a267ce9eabc320bdef9267cc342137a2d +size 8214 diff --git a/src/game/data/static/puzzle.dat b/src/game/data/static/puzzle.dat index b1d11fc..0b34d83 100644 Binary files a/src/game/data/static/puzzle.dat and b/src/game/data/static/puzzle.dat differ diff --git a/src/game/data/static/uiconfig.dat b/src/game/data/static/uiconfig.dat index b9ced5b..b95573c 100644 Binary files a/src/game/data/static/uiconfig.dat and b/src/game/data/static/uiconfig.dat differ diff --git a/src/game/mini.def b/src/game/mini.def index 89311b6..9459712 100644 --- a/src/game/mini.def +++ b/src/game/mini.def @@ -98,6 +98,7 @@ type PuzzleVisualSettings { Vec4 TileBaseColor Vec4 TileDotColor + Vec3 Test Vec4 DisabledCardTint } diff --git a/src/gen/Def.h b/src/gen/Def.h index f1ef204..f8724e8 100644 --- a/src/gen/Def.h +++ b/src/gen/Def.h @@ -4,6 +4,7 @@ #include "Generated.h" #include "bx/string.h" #include +#include #include namespace Gen @@ -27,6 +28,43 @@ namespace Gen Defs[DefCount] = def; ++DefCount; } + + int32_t FindHash(uint32_t hash) + { + for (int32_t i = 0; i < DefCount; ++i) + { + if (Defs[i].Hash == hash) + { + return i; + } + } + return -1; + } + + const int32_t FindDefByName(const char* name) + { + for (int32_t i = 0; i < DefCount; ++i) + { + if (bx::strCmp(name, Defs[i].Name) == 0) + { + return i; + } + } + return -1; + } + + void PatchChildIndices() + { + for (int32_t i = 0; i < DefCount; ++i) + { + for (int32_t j = 0; j < Defs[i].ChildCount; ++j) + { + int32_t idx = FindHash(Meta::Metadata.TypeDefinitions[Defs[i].ChildIndices[j]].Hash); + assert(idx >= 0); + Defs[i].ChildIndices[j] = idx; + } + } + } }; struct EmbeddedTypeInfoHeader @@ -37,6 +75,7 @@ namespace Gen uint16_t BaseTypeIdx = 0; uint16_t TypeCount = 0; uint32_t TypeDataSize = 0; + uint32_t MemberDataSize = 0; }; struct Serializer @@ -87,18 +126,21 @@ namespace Gen typeBuf.AddDef(Meta::Metadata.TypeDefinitions[def.ChildIndices[j]]); } } + typeBuf.PatchChildIndices(); EmbeddedTypeInfoHeader header; header.BaseTypeHash = baseDef.Hash; header.BaseTypeIdx = 0; header.TypeCount = typeBuf.DefCount; header.TypeDataSize = header.TypeCount * sizeof(Meta::TypeDef); + header.MemberDataSize = bx::strLen(Meta::Metadata.MemberNameBuffer); if (!Write(&header, sizeof(header))) return false; for (int32_t i = 0; i < typeBuf.DefCount; ++i) { if (!Write(&typeBuf.Defs[i], sizeof(typeBuf.Defs[i]))) return false; } + Write(Meta::Metadata.MemberNameBuffer, header.MemberDataSize); if (!Save(&data, 1, *this)) { @@ -132,6 +174,9 @@ namespace Gen bx::FilePath Path; bx::FileReader Reader; + char MemberNameBuf[64 * 64 * 64]{0}; + EmbeddedTypeTableBuffer TypeBuf; + bool Init(const bx::FilePath& path, const char* _4cc) { Path = path; @@ -185,28 +230,30 @@ namespace Gen if (header.BaseTypeHash != baseTypeDef.Hash) { LOG_WARN("Hash mismatch! %u != %u", header.BaseTypeHash, baseTypeDef.Hash); - - // TODO: patch data - data = {}; - return false; } - else + + TypeBuf.DefCount = header.TypeCount; + for (int32_t i = 0; i < TypeBuf.DefCount; ++i) { - LOG("Hash match!"); + Read(&TypeBuf.Defs[i], sizeof(TypeBuf.Defs[i])); + } - // Skip definitions, we know they match - Reader.seek(header.TypeDataSize); + Read(MemberNameBuf, header.MemberDataSize); - if (!Load(&data, 1, *this)) - { - LOG_ERROR("Failed to load: %s", Err.getMessage().getCPtr()); - return false; - } + if (!Load(&data, 1, *this)) + { + LOG_ERROR("Failed to load: %s", Err.getMessage().getCPtr()); + return false; } return true; } + void Skip(uint32_t byteCount) + { + Reader.seek(byteCount); + } + void Finish() { Reader.close(); @@ -218,6 +265,18 @@ namespace Gen } }; + inline uint32_t FindNameInMetadata(const Meta::MetadataTable& meta, const char* name) + { + for (int32_t i = 0; i < BX_COUNTOF(meta.TypeDefinitions); ++i) + { + if (bx::strCmp(meta.TypeDefinitions[i].Name, name) == 0) + { + return i; + } + } + return -1; + } + template bool Save(const T* obj, uint32_t count, Serializer& serializer); template bool Load(T* obj, uint32_t count, Deserializer& serializer); } // namespace Gen diff --git a/src/gen/Generated.cpp b/src/gen/Generated.cpp index 171cdd6..dc86184 100644 --- a/src/gen/Generated.cpp +++ b/src/gen/Generated.cpp @@ -16,7 +16,7 @@ namespace Gen bool Load(PuzzleElementType::Enum* obj, uint32_t count, Deserializer& serializer) { bool isOk = true; - for (uint32_t i = 0; i < count; ++i) + for (int32_t i = 0; i < count; ++i) { uint8_t& val = (uint8_t&)obj[i]; isOk = Load(&val, 1, serializer) && isOk; @@ -36,7 +36,7 @@ namespace Gen bool Load(EMaterial::Enum* obj, uint32_t count, Deserializer& serializer) { bool isOk = true; - for (uint32_t i = 0; i < count; ++i) + for (int32_t i = 0; i < count; ++i) { int32_t& val = (int32_t&)obj[i]; isOk = Load(&val, 1, serializer) && isOk; @@ -48,14 +48,16 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { + isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } bool Load(int8_t* obj, uint32_t count, Deserializer& serializer) { bool isOk = true; - for (uint32_t i = 0; i < count; ++i) + for (int32_t i = 0; i < count; ++i) { + isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } @@ -64,14 +66,16 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { + isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } bool Load(int16_t* obj, uint32_t count, Deserializer& serializer) { bool isOk = true; - for (uint32_t i = 0; i < count; ++i) + for (int32_t i = 0; i < count; ++i) { + isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } @@ -80,14 +84,16 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { + isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } bool Load(int32_t* obj, uint32_t count, Deserializer& serializer) { bool isOk = true; - for (uint32_t i = 0; i < count; ++i) + for (int32_t i = 0; i < count; ++i) { + isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } @@ -96,14 +102,16 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { + isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } bool Load(int64_t* obj, uint32_t count, Deserializer& serializer) { bool isOk = true; - for (uint32_t i = 0; i < count; ++i) + for (int32_t i = 0; i < count; ++i) { + isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } @@ -112,14 +120,16 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { + isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } bool Load(uint8_t* obj, uint32_t count, Deserializer& serializer) { bool isOk = true; - for (uint32_t i = 0; i < count; ++i) + for (int32_t i = 0; i < count; ++i) { + isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } @@ -128,14 +138,16 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { + isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } bool Load(uint16_t* obj, uint32_t count, Deserializer& serializer) { bool isOk = true; - for (uint32_t i = 0; i < count; ++i) + for (int32_t i = 0; i < count; ++i) { + isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } @@ -144,14 +156,16 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { + isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } bool Load(uint32_t* obj, uint32_t count, Deserializer& serializer) { bool isOk = true; - for (uint32_t i = 0; i < count; ++i) + for (int32_t i = 0; i < count; ++i) { + isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } @@ -160,14 +174,16 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { + isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } bool Load(uint64_t* obj, uint32_t count, Deserializer& serializer) { bool isOk = true; - for (uint32_t i = 0; i < count; ++i) + for (int32_t i = 0; i < count; ++i) { + isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } @@ -176,14 +192,16 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { + isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } bool Load(bool* obj, uint32_t count, Deserializer& serializer) { bool isOk = true; - for (uint32_t i = 0; i < count; ++i) + for (int32_t i = 0; i < count; ++i) { + isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } @@ -192,14 +210,16 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { + isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } bool Load(float* obj, uint32_t count, Deserializer& serializer) { bool isOk = true; - for (uint32_t i = 0; i < count; ++i) + for (int32_t i = 0; i < count; ++i) { + isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } @@ -208,14 +228,16 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { + isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } bool Load(double* obj, uint32_t count, Deserializer& serializer) { bool isOk = true; - for (uint32_t i = 0; i < count; ++i) + for (int32_t i = 0; i < count; ++i) { + isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } @@ -224,14 +246,16 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { + isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } bool Load(char* obj, uint32_t count, Deserializer& serializer) { bool isOk = true; - for (uint32_t i = 0; i < count; ++i) + for (int32_t i = 0; i < count; ++i) { + isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; } return isOk; } @@ -240,19 +264,96 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(&obj[i].x, 1, serializer) && isOk; + isOk = Save(&obj[i].y, 1, serializer) && isOk; } return isOk; } bool Load(Vec2* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[Vec2::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[Vec2::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(&obj[i].x, 1, serializer) && isOk; + isOk = Load(&obj[i].y, 1, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "x") == 0 && bx::strCmp(memberTypeName, "float") == 0) + { + WriteDestinations[i] = offsetof(Vec2, x); + } + if (bx::strCmp(memberName, "y") == 0 && bx::strCmp(memberTypeName, "float") == 0) + { + WriteDestinations[i] = offsetof(Vec2, y); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "x") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "y") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const Vec3* obj, uint32_t count, Serializer& serializer) @@ -260,21 +361,108 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(&obj[i].x, 1, serializer) && isOk; + isOk = Save(&obj[i].y, 1, serializer) && isOk; + isOk = Save(&obj[i].z, 1, serializer) && isOk; } return isOk; } bool Load(Vec3* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[Vec3::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[Vec3::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(&obj[i].x, 1, serializer) && isOk; + isOk = Load(&obj[i].y, 1, serializer) && isOk; + isOk = Load(&obj[i].z, 1, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "x") == 0 && bx::strCmp(memberTypeName, "float") == 0) + { + WriteDestinations[i] = offsetof(Vec3, x); + } + if (bx::strCmp(memberName, "y") == 0 && bx::strCmp(memberTypeName, "float") == 0) + { + WriteDestinations[i] = offsetof(Vec3, y); + } + if (bx::strCmp(memberName, "z") == 0 && bx::strCmp(memberTypeName, "float") == 0) + { + WriteDestinations[i] = offsetof(Vec3, z); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "x") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "y") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "z") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const Vec4* obj, uint32_t count, Serializer& serializer) @@ -282,23 +470,120 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(&obj[i].x, 1, serializer) && isOk; + isOk = Save(&obj[i].y, 1, serializer) && isOk; + isOk = Save(&obj[i].z, 1, serializer) && isOk; + isOk = Save(&obj[i].w, 1, serializer) && isOk; } return isOk; } bool Load(Vec4* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[Vec4::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[Vec4::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(&obj[i].x, 1, serializer) && isOk; + isOk = Load(&obj[i].y, 1, serializer) && isOk; + isOk = Load(&obj[i].z, 1, serializer) && isOk; + isOk = Load(&obj[i].w, 1, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "x") == 0 && bx::strCmp(memberTypeName, "float") == 0) + { + WriteDestinations[i] = offsetof(Vec4, x); + } + if (bx::strCmp(memberName, "y") == 0 && bx::strCmp(memberTypeName, "float") == 0) + { + WriteDestinations[i] = offsetof(Vec4, y); + } + if (bx::strCmp(memberName, "z") == 0 && bx::strCmp(memberTypeName, "float") == 0) + { + WriteDestinations[i] = offsetof(Vec4, z); + } + if (bx::strCmp(memberName, "w") == 0 && bx::strCmp(memberTypeName, "float") == 0) + { + WriteDestinations[i] = offsetof(Vec4, w); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "x") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "y") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "z") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "w") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const Mat3* obj, uint32_t count, Serializer& serializer) @@ -306,17 +591,84 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(obj[i].M, 9, serializer) && isOk; } return isOk; } bool Load(Mat3* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[Mat3::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[Mat3::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(obj[i].M, 9, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "M") == 0 && bx::strCmp(memberTypeName, "float") == 0) + { + WriteDestinations[i] = offsetof(Mat3, M); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "M") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 9, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const Mat4* obj, uint32_t count, Serializer& serializer) @@ -324,17 +676,84 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(obj[i].M, 16, serializer) && isOk; } return isOk; } bool Load(Mat4* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[Mat4::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[Mat4::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(obj[i].M, 16, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "M") == 0 && bx::strCmp(memberTypeName, "float") == 0) + { + WriteDestinations[i] = offsetof(Mat4, M); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "M") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 16, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const Transform* obj, uint32_t count, Serializer& serializer) @@ -352,15 +771,122 @@ namespace Gen } bool Load(Transform* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[Transform::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[Transform::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(&obj[i].M, 1, serializer) && isOk; + isOk = Load(&obj[i].MI, 1, serializer) && isOk; + isOk = Load(&obj[i].Position, 1, serializer) && isOk; + isOk = Load(&obj[i].Rotation, 1, serializer) && isOk; + isOk = Load(&obj[i].Scale, 1, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "M") == 0 && bx::strCmp(memberTypeName, "Mat4") == 0) + { + WriteDestinations[i] = offsetof(Transform, M); + } + if (bx::strCmp(memberName, "MI") == 0 && bx::strCmp(memberTypeName, "Mat4") == 0) + { + WriteDestinations[i] = offsetof(Transform, MI); + } + if (bx::strCmp(memberName, "Position") == 0 && bx::strCmp(memberTypeName, "Vec3") == 0) + { + WriteDestinations[i] = offsetof(Transform, Position); + } + if (bx::strCmp(memberName, "Rotation") == 0 && bx::strCmp(memberTypeName, "Mat4") == 0) + { + WriteDestinations[i] = offsetof(Transform, Rotation); + } + if (bx::strCmp(memberName, "Scale") == 0 && bx::strCmp(memberTypeName, "Vec3") == 0) + { + WriteDestinations[i] = offsetof(Transform, Scale); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = Load(&obj[i].M, 1, serializer) && isOk; - isOk = Load(&obj[i].MI, 1, serializer) && isOk; - isOk = Load(&obj[i].Position, 1, serializer) && isOk; - isOk = Load(&obj[i].Rotation, 1, serializer) && isOk; - isOk = Load(&obj[i].Scale, 1, serializer) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "M") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "MI") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "Position") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "Rotation") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "Scale") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const AssetHandle* obj, uint32_t count, Serializer& serializer) @@ -368,17 +894,84 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(&obj[i].Idx, 1, serializer) && isOk; } return isOk; } bool Load(AssetHandle* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[AssetHandle::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[AssetHandle::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(&obj[i].Idx, 1, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "Idx") == 0 && bx::strCmp(memberTypeName, "uint32_t") == 0) + { + WriteDestinations[i] = offsetof(AssetHandle, Idx); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "Idx") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const ModelHandle* obj, uint32_t count, Serializer& serializer) @@ -386,19 +979,96 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(&obj[i].ModelIdx, 1, serializer) && isOk; isOk = Save(&obj[i].Asset, 1, serializer) && isOk; } return isOk; } bool Load(ModelHandle* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[ModelHandle::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[ModelHandle::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(&obj[i].ModelIdx, 1, serializer) && isOk; + isOk = Load(&obj[i].Asset, 1, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "ModelIdx") == 0 && bx::strCmp(memberTypeName, "uint16_t") == 0) + { + WriteDestinations[i] = offsetof(ModelHandle, ModelIdx); + } + if (bx::strCmp(memberName, "Asset") == 0 && bx::strCmp(memberTypeName, "AssetHandle") == 0) + { + WriteDestinations[i] = offsetof(ModelHandle, Asset); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = Load(&obj[i].Asset, 1, serializer) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "ModelIdx") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "Asset") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const TextureHandle* obj, uint32_t count, Serializer& serializer) @@ -406,19 +1076,96 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(&obj[i].TextureIdx, 1, serializer) && isOk; isOk = Save(&obj[i].Asset, 1, serializer) && isOk; } return isOk; } bool Load(TextureHandle* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[TextureHandle::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[TextureHandle::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(&obj[i].TextureIdx, 1, serializer) && isOk; + isOk = Load(&obj[i].Asset, 1, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "TextureIdx") == 0 && bx::strCmp(memberTypeName, "uint16_t") == 0) + { + WriteDestinations[i] = offsetof(TextureHandle, TextureIdx); + } + if (bx::strCmp(memberName, "Asset") == 0 && bx::strCmp(memberTypeName, "AssetHandle") == 0) + { + WriteDestinations[i] = offsetof(TextureHandle, Asset); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = Load(&obj[i].Asset, 1, serializer) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "TextureIdx") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "Asset") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const PuzPos* obj, uint32_t count, Serializer& serializer) @@ -426,19 +1173,96 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(&obj[i].X, 1, serializer) && isOk; + isOk = Save(&obj[i].Y, 1, serializer) && isOk; } return isOk; } bool Load(PuzPos* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[PuzPos::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[PuzPos::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(&obj[i].X, 1, serializer) && isOk; + isOk = Load(&obj[i].Y, 1, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "X") == 0 && bx::strCmp(memberTypeName, "int8_t") == 0) + { + WriteDestinations[i] = offsetof(PuzPos, X); + } + if (bx::strCmp(memberName, "Y") == 0 && bx::strCmp(memberTypeName, "int8_t") == 0) + { + WriteDestinations[i] = offsetof(PuzPos, Y); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "X") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "Y") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const StaticPuzzleCard* obj, uint32_t count, Serializer& serializer) @@ -446,7 +1270,7 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(obj[i].Elements, 4, serializer) && isOk; isOk = Save(&obj[i].ModelHandle, 1, serializer) && isOk; isOk = Save(&obj[i].BoardTextureHandle, 1, serializer) && isOk; } @@ -454,13 +1278,100 @@ namespace Gen } bool Load(StaticPuzzleCard* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[StaticPuzzleCard::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[StaticPuzzleCard::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(obj[i].Elements, 4, serializer) && isOk; + isOk = Load(&obj[i].ModelHandle, 1, serializer) && isOk; + isOk = Load(&obj[i].BoardTextureHandle, 1, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "Elements") == 0 && bx::strCmp(memberTypeName, "PuzzleElementType::Enum") == 0) + { + WriteDestinations[i] = offsetof(StaticPuzzleCard, Elements); + } + if (bx::strCmp(memberName, "ModelHandle") == 0 && bx::strCmp(memberTypeName, "ModelHandle") == 0) + { + WriteDestinations[i] = offsetof(StaticPuzzleCard, ModelHandle); + } + if (bx::strCmp(memberName, "BoardTextureHandle") == 0 && bx::strCmp(memberTypeName, "TextureHandle") == 0) + { + WriteDestinations[i] = offsetof(StaticPuzzleCard, BoardTextureHandle); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = Load(&obj[i].ModelHandle, 1, serializer) && isOk; - isOk = Load(&obj[i].BoardTextureHandle, 1, serializer) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "Elements") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 4, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "ModelHandle") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "BoardTextureHandle") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const StaticPuzzleCardHandle* obj, uint32_t count, Serializer& serializer) @@ -468,17 +1379,84 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(&obj[i].Idx, 1, serializer) && isOk; } return isOk; } bool Load(StaticPuzzleCardHandle* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[StaticPuzzleCardHandle::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[StaticPuzzleCardHandle::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(&obj[i].Idx, 1, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "Idx") == 0 && bx::strCmp(memberTypeName, "uint16_t") == 0) + { + WriteDestinations[i] = offsetof(StaticPuzzleCardHandle, Idx); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "Idx") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const PuzzleVisualSettings* obj, uint32_t count, Serializer& serializer) @@ -488,19 +1466,118 @@ namespace Gen { isOk = Save(&obj[i].TileBaseColor, 1, serializer) && isOk; isOk = Save(&obj[i].TileDotColor, 1, serializer) && isOk; + isOk = Save(&obj[i].Test, 1, serializer) && isOk; isOk = Save(&obj[i].DisabledCardTint, 1, serializer) && isOk; } return isOk; } bool Load(PuzzleVisualSettings* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[PuzzleVisualSettings::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[PuzzleVisualSettings::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(&obj[i].TileBaseColor, 1, serializer) && isOk; + isOk = Load(&obj[i].TileDotColor, 1, serializer) && isOk; + isOk = Load(&obj[i].Test, 1, serializer) && isOk; + isOk = Load(&obj[i].DisabledCardTint, 1, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "TileBaseColor") == 0 && bx::strCmp(memberTypeName, "Vec4") == 0) + { + WriteDestinations[i] = offsetof(PuzzleVisualSettings, TileBaseColor); + } + if (bx::strCmp(memberName, "TileDotColor") == 0 && bx::strCmp(memberTypeName, "Vec4") == 0) + { + WriteDestinations[i] = offsetof(PuzzleVisualSettings, TileDotColor); + } + if (bx::strCmp(memberName, "Test") == 0 && bx::strCmp(memberTypeName, "Vec3") == 0) + { + WriteDestinations[i] = offsetof(PuzzleVisualSettings, Test); + } + if (bx::strCmp(memberName, "DisabledCardTint") == 0 && bx::strCmp(memberTypeName, "Vec4") == 0) + { + WriteDestinations[i] = offsetof(PuzzleVisualSettings, DisabledCardTint); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = Load(&obj[i].TileBaseColor, 1, serializer) && isOk; - isOk = Load(&obj[i].TileDotColor, 1, serializer) && isOk; - isOk = Load(&obj[i].DisabledCardTint, 1, serializer) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "TileBaseColor") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "TileDotColor") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "Test") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "DisabledCardTint") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const StaticPuzzleData* obj, uint32_t count, Serializer& serializer) @@ -515,12 +1592,89 @@ namespace Gen } bool Load(StaticPuzzleData* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[StaticPuzzleData::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[StaticPuzzleData::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(obj[i].Cards, 64, serializer) && isOk; + isOk = Load(&obj[i].Visuals, 1, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "Cards") == 0 && bx::strCmp(memberTypeName, "StaticPuzzleCard") == 0) + { + WriteDestinations[i] = offsetof(StaticPuzzleData, Cards); + } + if (bx::strCmp(memberName, "Visuals") == 0 && bx::strCmp(memberTypeName, "PuzzleVisualSettings") == 0) + { + WriteDestinations[i] = offsetof(StaticPuzzleData, Visuals); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = Load(obj[i].Cards, 64, serializer) && isOk; - isOk = Load(&obj[i].Visuals, 1, serializer) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "Cards") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 64, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "Visuals") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const PuzzleCardStack* obj, uint32_t count, Serializer& serializer) @@ -529,20 +1683,107 @@ namespace Gen for (uint32_t i = 0; i < count; ++i) { isOk = Save(&obj[i].RefCard, 1, serializer) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(&obj[i].MaxAvailableCount, 1, serializer) && isOk; + isOk = Save(&obj[i].UsedCount, 1, serializer) && isOk; } return isOk; } bool Load(PuzzleCardStack* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[PuzzleCardStack::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[PuzzleCardStack::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(&obj[i].RefCard, 1, serializer) && isOk; + isOk = Load(&obj[i].MaxAvailableCount, 1, serializer) && isOk; + isOk = Load(&obj[i].UsedCount, 1, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "RefCard") == 0 && bx::strCmp(memberTypeName, "StaticPuzzleCardHandle") == 0) + { + WriteDestinations[i] = offsetof(PuzzleCardStack, RefCard); + } + if (bx::strCmp(memberName, "MaxAvailableCount") == 0 && bx::strCmp(memberTypeName, "uint8_t") == 0) + { + WriteDestinations[i] = offsetof(PuzzleCardStack, MaxAvailableCount); + } + if (bx::strCmp(memberName, "UsedCount") == 0 && bx::strCmp(memberTypeName, "uint8_t") == 0) + { + WriteDestinations[i] = offsetof(PuzzleCardStack, UsedCount); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = Load(&obj[i].RefCard, 1, serializer) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "RefCard") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "MaxAvailableCount") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "UsedCount") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const PlacedPuzzleCard* obj, uint32_t count, Serializer& serializer) @@ -552,21 +1793,118 @@ namespace Gen { isOk = Save(&obj[i].RefCard, 1, serializer) && isOk; isOk = Save(&obj[i].Position, 1, serializer) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(&obj[i].Rotation, 1, serializer) && isOk; + isOk = Save(&obj[i].IsLocked, 1, serializer) && isOk; } return isOk; } bool Load(PlacedPuzzleCard* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[PlacedPuzzleCard::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[PlacedPuzzleCard::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(&obj[i].RefCard, 1, serializer) && isOk; + isOk = Load(&obj[i].Position, 1, serializer) && isOk; + isOk = Load(&obj[i].Rotation, 1, serializer) && isOk; + isOk = Load(&obj[i].IsLocked, 1, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "RefCard") == 0 && bx::strCmp(memberTypeName, "StaticPuzzleCardHandle") == 0) + { + WriteDestinations[i] = offsetof(PlacedPuzzleCard, RefCard); + } + if (bx::strCmp(memberName, "Position") == 0 && bx::strCmp(memberTypeName, "PuzPos") == 0) + { + WriteDestinations[i] = offsetof(PlacedPuzzleCard, Position); + } + if (bx::strCmp(memberName, "Rotation") == 0 && bx::strCmp(memberTypeName, "uint8_t") == 0) + { + WriteDestinations[i] = offsetof(PlacedPuzzleCard, Rotation); + } + if (bx::strCmp(memberName, "IsLocked") == 0 && bx::strCmp(memberTypeName, "bool") == 0) + { + WriteDestinations[i] = offsetof(PlacedPuzzleCard, IsLocked); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = Load(&obj[i].RefCard, 1, serializer) && isOk; - isOk = Load(&obj[i].Position, 1, serializer) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "RefCard") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "Position") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "Rotation") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "IsLocked") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const PuzzleData* obj, uint32_t count, Serializer& serializer) @@ -574,35 +1912,192 @@ namespace Gen bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(&obj[i].ID, 1, serializer) && isOk; + isOk = Save(obj[i].PuzzleName, 64, serializer) && isOk; + isOk = Save(&obj[i].WidthTiles, 1, serializer) && isOk; + isOk = Save(&obj[i].HeightTiles, 1, serializer) && isOk; + isOk = Save(&obj[i].AvailableCardCount, 1, serializer) && isOk; isOk = Save(obj[i].AvailableCards, 16, serializer) && isOk; isOk = Save(obj[i].PlacedCards, 256, serializer) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(obj[i].BackgroundTiles, 1024, serializer) && isOk; + isOk = Save(&obj[i].GoalPositionCount, 1, serializer) && isOk; isOk = Save(obj[i].GoalPositions, 16, serializer) && isOk; } return isOk; } bool Load(PuzzleData* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[PuzzleData::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[PuzzleData::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(&obj[i].ID, 1, serializer) && isOk; + isOk = Load(obj[i].PuzzleName, 64, serializer) && isOk; + isOk = Load(&obj[i].WidthTiles, 1, serializer) && isOk; + isOk = Load(&obj[i].HeightTiles, 1, serializer) && isOk; + isOk = Load(&obj[i].AvailableCardCount, 1, serializer) && isOk; + isOk = Load(obj[i].AvailableCards, 16, serializer) && isOk; + isOk = Load(obj[i].PlacedCards, 256, serializer) && isOk; + isOk = Load(obj[i].BackgroundTiles, 1024, serializer) && isOk; + isOk = Load(&obj[i].GoalPositionCount, 1, serializer) && isOk; + isOk = Load(obj[i].GoalPositions, 16, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "ID") == 0 && bx::strCmp(memberTypeName, "uint16_t") == 0) + { + WriteDestinations[i] = offsetof(PuzzleData, ID); + } + if (bx::strCmp(memberName, "PuzzleName") == 0 && bx::strCmp(memberTypeName, "char") == 0) + { + WriteDestinations[i] = offsetof(PuzzleData, PuzzleName); + } + if (bx::strCmp(memberName, "WidthTiles") == 0 && bx::strCmp(memberTypeName, "uint8_t") == 0) + { + WriteDestinations[i] = offsetof(PuzzleData, WidthTiles); + } + if (bx::strCmp(memberName, "HeightTiles") == 0 && bx::strCmp(memberTypeName, "uint8_t") == 0) + { + WriteDestinations[i] = offsetof(PuzzleData, HeightTiles); + } + if (bx::strCmp(memberName, "AvailableCardCount") == 0 && bx::strCmp(memberTypeName, "uint32_t") == 0) + { + WriteDestinations[i] = offsetof(PuzzleData, AvailableCardCount); + } + if (bx::strCmp(memberName, "AvailableCards") == 0 && bx::strCmp(memberTypeName, "PuzzleCardStack") == 0) + { + WriteDestinations[i] = offsetof(PuzzleData, AvailableCards); + } + if (bx::strCmp(memberName, "PlacedCards") == 0 && bx::strCmp(memberTypeName, "PlacedPuzzleCard") == 0) + { + WriteDestinations[i] = offsetof(PuzzleData, PlacedCards); + } + if (bx::strCmp(memberName, "BackgroundTiles") == 0 && bx::strCmp(memberTypeName, "PuzzleElementType::Enum") == 0) + { + WriteDestinations[i] = offsetof(PuzzleData, BackgroundTiles); + } + if (bx::strCmp(memberName, "GoalPositionCount") == 0 && bx::strCmp(memberTypeName, "uint32_t") == 0) + { + WriteDestinations[i] = offsetof(PuzzleData, GoalPositionCount); + } + if (bx::strCmp(memberName, "GoalPositions") == 0 && bx::strCmp(memberTypeName, "PuzPos") == 0) + { + WriteDestinations[i] = offsetof(PuzzleData, GoalPositions); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = Load(obj[i].AvailableCards, 16, serializer) && isOk; - isOk = Load(obj[i].PlacedCards, 256, serializer) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = Load(obj[i].GoalPositions, 16, serializer) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "ID") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "PuzzleName") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 64, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "WidthTiles") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "HeightTiles") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "AvailableCardCount") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "AvailableCards") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 16, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "PlacedCards") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 256, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "BackgroundTiles") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1024, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "GoalPositionCount") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "GoalPositions") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 16, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } bool Save(const SavedEntityRenderData* obj, uint32_t count, Serializer& serializer) @@ -613,26 +2108,153 @@ namespace Gen isOk = Save(&obj[i].BaseColor, 1, serializer) && isOk; isOk = Save(&obj[i].HighlightColor, 1, serializer) && isOk; isOk = Save(&obj[i].TF, 1, serializer) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(&obj[i].Material, 1, serializer) && isOk; isOk = Save(&obj[i].Texture, 1, serializer) && isOk; isOk = Save(&obj[i].Model, 1, serializer) && isOk; - isOk = serializer.Write(&obj[i], sizeof(obj[i])) && isOk; + isOk = Save(&obj[i].Visible, 1, serializer) && isOk; } return isOk; } bool Load(SavedEntityRenderData* obj, uint32_t count, Deserializer& serializer) { + const char* typeName = Meta::Metadata.TypeDefinitions[SavedEntityRenderData::TypeIdx].Name; + + // Quick match + int32_t matchedHashIdx = + serializer.TypeBuf.FindHash(Meta::Metadata.TypeDefinitions[SavedEntityRenderData::TypeIdx].Hash); + if (matchedHashIdx >= 0) + { + assert(bx::strCmp(serializer.TypeBuf.Defs[matchedHashIdx].Name, typeName) == 0); + bool isOk = true; + for (uint32_t i = 0; i < count; ++i) + { + isOk = Load(&obj[i].BaseColor, 1, serializer) && isOk; + isOk = Load(&obj[i].HighlightColor, 1, serializer) && isOk; + isOk = Load(&obj[i].TF, 1, serializer) && isOk; + isOk = Load(&obj[i].Material, 1, serializer) && isOk; + isOk = Load(&obj[i].Texture, 1, serializer) && isOk; + isOk = Load(&obj[i].Model, 1, serializer) && isOk; + isOk = Load(&obj[i].Visible, 1, serializer) && isOk; + } + // if we're not ok here, something went really wrong + assert(isOk); + return isOk; + } + + // Failed to resolve hash, the type definition chaned since the file was saved! try to match by name. + int32_t nameMatchIdx = serializer.TypeBuf.FindDefByName(typeName); + if (nameMatchIdx < 0) + { + // Name match failed, caller has to handle this and potentially skip some bytes + return false; + } + + // Successfully matched name, but we need to follow the definition of the file now! + const Meta::TypeDef& matchedDef = serializer.TypeBuf.Defs[nameMatchIdx]; + + // Figure out new member mapping + uint64_t WriteDestinations[64]; + for (int32_t i = 0; i < BX_COUNTOF(WriteDestinations); ++i) + { + WriteDestinations[i] = UINT64_MAX; + } + for (uint32_t i = 0; i < matchedDef.ChildCount; ++i) + { + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[i].Offset], matchedDef.MemberNameIndices[i].Size}; + const char* memberTypeName = serializer.TypeBuf.Defs[matchedDef.ChildIndices[i]].Name; + if (bx::strCmp(memberName, "BaseColor") == 0 && bx::strCmp(memberTypeName, "Vec4") == 0) + { + WriteDestinations[i] = offsetof(SavedEntityRenderData, BaseColor); + } + if (bx::strCmp(memberName, "HighlightColor") == 0 && bx::strCmp(memberTypeName, "Vec4") == 0) + { + WriteDestinations[i] = offsetof(SavedEntityRenderData, HighlightColor); + } + if (bx::strCmp(memberName, "TF") == 0 && bx::strCmp(memberTypeName, "Transform") == 0) + { + WriteDestinations[i] = offsetof(SavedEntityRenderData, TF); + } + if (bx::strCmp(memberName, "Material") == 0 && bx::strCmp(memberTypeName, "EMaterial::Enum") == 0) + { + WriteDestinations[i] = offsetof(SavedEntityRenderData, Material); + } + if (bx::strCmp(memberName, "Texture") == 0 && bx::strCmp(memberTypeName, "TextureHandle") == 0) + { + WriteDestinations[i] = offsetof(SavedEntityRenderData, Texture); + } + if (bx::strCmp(memberName, "Model") == 0 && bx::strCmp(memberTypeName, "ModelHandle") == 0) + { + WriteDestinations[i] = offsetof(SavedEntityRenderData, Model); + } + if (bx::strCmp(memberName, "Visible") == 0 && bx::strCmp(memberTypeName, "bool") == 0) + { + WriteDestinations[i] = offsetof(SavedEntityRenderData, Visible); + } + } + + // Start reading in file order, skipping things that we don't know by name and type bool isOk = true; for (uint32_t i = 0; i < count; ++i) { - isOk = Load(&obj[i].BaseColor, 1, serializer) && isOk; - isOk = Load(&obj[i].HighlightColor, 1, serializer) && isOk; - isOk = Load(&obj[i].TF, 1, serializer) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; - isOk = Load(&obj[i].Texture, 1, serializer) && isOk; - isOk = Load(&obj[i].Model, 1, serializer) && isOk; - isOk = serializer.Read(&obj[i], sizeof(obj[i])) && isOk; + uint8_t* objBasePtr = reinterpret_cast(&obj[i]); + + for (uint32_t j = 0; j < matchedDef.ChildCount; ++j) + { + const Meta::TypeDef& childDef = serializer.TypeBuf.Defs[matchedDef.ChildIndices[j]]; + const bx::StringView memberName = {&serializer.MemberNameBuf[matchedDef.MemberNameIndices[j].Offset], matchedDef.MemberNameIndices[j].Size}; + if (WriteDestinations[j] == UINT64_MAX) + { + // Unknown member name or type changed + serializer.Skip(childDef.Size); + continue; + } + + if (bx::strCmp(memberName, "BaseColor") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "HighlightColor") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "TF") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "Material") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "Texture") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "Model") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + if (bx::strCmp(memberName, "Visible") == 0) + { + auto* fieldPtr = reinterpret_cast(objBasePtr + WriteDestinations[j]); + isOk = Load(fieldPtr, 1, serializer) && isOk; + continue; + } + assert(false); + } } + assert(isOk); return isOk; } } diff --git a/src/gen/Generated.h b/src/gen/Generated.h index d9944f3..b486bfe 100644 --- a/src/gen/Generated.h +++ b/src/gen/Generated.h @@ -1,5 +1,6 @@ #pragma once #include +#include namespace Gen { @@ -158,6 +159,7 @@ namespace Gen static constexpr uint16_t TypeIdx = 24; Vec4 TileBaseColor = {}; Vec4 TileDotColor = {}; + Vec3 Test = {}; Vec4 DisabledCardTint = {}; }; struct StaticPuzzleData @@ -272,6 +274,12 @@ namespace Gen bool Load(SavedEntityRenderData* obj, uint32_t count, Deserializer& serializer); namespace Meta { + struct StrRef + { + uint16_t Offset; + uint16_t Size; + }; + struct TypeDef { uint32_t Size = 0; @@ -279,6 +287,7 @@ namespace Gen char Name[64]{"Dummy"}; uint16_t ChildCount = 0; uint16_t ChildIndices[64]{0}; + StrRef MemberNameIndices[64]{0}; }; struct EnumDef @@ -291,42 +300,43 @@ namespace Gen { TypeDef TypeDefinitions[30] { - TypeDef{sizeof(int8_t), 0, "i8", 0, {}}, - TypeDef{sizeof(int16_t), 1, "i16", 0, {}}, - TypeDef{sizeof(int32_t), 2, "i32", 0, {}}, - TypeDef{sizeof(int64_t), 3, "i64", 0, {}}, - TypeDef{sizeof(uint8_t), 4, "u8", 0, {}}, - TypeDef{sizeof(uint16_t), 5, "u16", 0, {}}, - TypeDef{sizeof(uint32_t), 6, "u32", 0, {}}, - TypeDef{sizeof(uint64_t), 7, "u64", 0, {}}, - TypeDef{sizeof(bool), 8, "b", 0, {}}, - TypeDef{sizeof(float), 9, "f32", 0, {}}, - TypeDef{sizeof(double), 10, "f64", 0, {}}, - TypeDef{sizeof(char), 11, "str", 0, {}}, - TypeDef{sizeof(Vec2), 2667033957, "Vec2", 2, {9, 9}}, - TypeDef{sizeof(Vec3), 473740858, "Vec3", 3, {9, 9, 9}}, - TypeDef{sizeof(Vec4), 2507696603, "Vec4", 4, {9, 9, 9, 9}}, - TypeDef{sizeof(Mat3), 3364737048, "Mat3", 1, {9}}, - TypeDef{sizeof(Mat4), 1650094019, "Mat4", 1, {9}}, - TypeDef{sizeof(Transform), 4103530190, "Transform", 5, {16, 16, 13, 16, 13}}, - TypeDef{sizeof(AssetHandle), 2609735487, "AssetHandle", 1, {6}}, - TypeDef{sizeof(ModelHandle), 298089627, "ModelHandle", 2, {5, 18}}, - TypeDef{sizeof(TextureHandle), 1633273761, "TextureHandle", 2, {5, 18}}, - TypeDef{sizeof(PuzPos), 1834398141, "PuzPos", 2, {0, 0}}, - TypeDef{sizeof(StaticPuzzleCard), 3413177578, "StaticPuzzleCard", 3, {0, 19, 20}}, - TypeDef{sizeof(StaticPuzzleCardHandle), 1742502768, "StaticPuzzleCardHandle", 1, {5}}, - TypeDef{sizeof(PuzzleVisualSettings), 4208425878, "PuzzleVisualSettings", 3, {14, 14, 14}}, - TypeDef{sizeof(StaticPuzzleData), 423465540, "StaticPuzzleData", 2, {22, 24}}, - TypeDef{sizeof(PuzzleCardStack), 53538532, "PuzzleCardStack", 3, {23, 4, 4}}, - TypeDef{sizeof(PlacedPuzzleCard), 3555575973, "PlacedPuzzleCard", 4, {23, 21, 4, 8}}, - TypeDef{sizeof(PuzzleData), 3349686056, "PuzzleData", 10, {5, 11, 4, 4, 6, 26, 27, 0, 6, 21}}, - TypeDef{sizeof(SavedEntityRenderData), 3172756855, "SavedEntityRenderData", 7, {14, 14, 17, 1, 20, 19, 8}}, + TypeDef{sizeof(int8_t), 0, "i8", 0, {}, {}}, + TypeDef{sizeof(int16_t), 1, "i16", 0, {}, {}}, + TypeDef{sizeof(int32_t), 2, "i32", 0, {}, {}}, + TypeDef{sizeof(int64_t), 3, "i64", 0, {}, {}}, + TypeDef{sizeof(uint8_t), 4, "u8", 0, {}, {}}, + TypeDef{sizeof(uint16_t), 5, "u16", 0, {}, {}}, + TypeDef{sizeof(uint32_t), 6, "u32", 0, {}, {}}, + TypeDef{sizeof(uint64_t), 7, "u64", 0, {}, {}}, + TypeDef{sizeof(bool), 8, "b", 0, {}, {}}, + TypeDef{sizeof(float), 9, "f32", 0, {}, {}}, + TypeDef{sizeof(double), 10, "f64", 0, {}, {}}, + TypeDef{sizeof(char), 11, "str", 0, {}, {}}, + TypeDef{sizeof(Vec2), 2667033957, "Vec2", 2, {9, 9}, {{0, 1}, {1, 1}}}, + TypeDef{sizeof(Vec3), 473740858, "Vec3", 3, {9, 9, 9}, {{2, 1}, {3, 1}, {4, 1}}}, + TypeDef{sizeof(Vec4), 2507696603, "Vec4", 4, {9, 9, 9, 9}, {{5, 1}, {6, 1}, {7, 1}, {8, 1}}}, + TypeDef{sizeof(Mat3), 3364737048, "Mat3", 1, {9}, {{9, 1}}}, + TypeDef{sizeof(Mat4), 1650094019, "Mat4", 1, {9}, {{10, 1}}}, + TypeDef{sizeof(Transform), 4103530190, "Transform", 5, {16, 16, 13, 16, 13}, {{11, 1}, {12, 2}, {14, 8}, {22, 8}, {30, 5}}}, + TypeDef{sizeof(AssetHandle), 2609735487, "AssetHandle", 1, {6}, {{35, 3}}}, + TypeDef{sizeof(ModelHandle), 298089627, "ModelHandle", 2, {5, 18}, {{38, 8}, {46, 5}}}, + TypeDef{sizeof(TextureHandle), 1633273761, "TextureHandle", 2, {5, 18}, {{51, 10}, {61, 5}}}, + TypeDef{sizeof(PuzPos), 1834398141, "PuzPos", 2, {0, 0}, {{66, 1}, {67, 1}}}, + TypeDef{sizeof(StaticPuzzleCard), 3413177578, "StaticPuzzleCard", 3, {0, 19, 20}, {{68, 8}, {76, 11}, {87, 18}}}, + TypeDef{sizeof(StaticPuzzleCardHandle), 1742502768, "StaticPuzzleCardHandle", 1, {5}, {{105, 3}}}, + TypeDef{sizeof(PuzzleVisualSettings), 2302077481, "PuzzleVisualSettings", 4, {14, 14, 13, 14}, {{108, 13}, {121, 12}, {133, 4}, {137, 16}}}, + TypeDef{sizeof(StaticPuzzleData), 3618749873, "StaticPuzzleData", 2, {22, 24}, {{153, 5}, {158, 7}}}, + TypeDef{sizeof(PuzzleCardStack), 53538532, "PuzzleCardStack", 3, {23, 4, 4}, {{165, 7}, {172, 17}, {189, 9}}}, + TypeDef{sizeof(PlacedPuzzleCard), 3555575973, "PlacedPuzzleCard", 4, {23, 21, 4, 8}, {{198, 7}, {205, 8}, {213, 8}, {221, 8}}}, + TypeDef{sizeof(PuzzleData), 3349686056, "PuzzleData", 10, {5, 11, 4, 4, 6, 26, 27, 0, 6, 21}, {{229, 2}, {231, 10}, {241, 10}, {251, 11}, {262, 18}, {280, 14}, {294, 11}, {305, 15}, {320, 17}, {337, 13}}}, + TypeDef{sizeof(SavedEntityRenderData), 3172756855, "SavedEntityRenderData", 7, {14, 14, 17, 1, 20, 19, 8}, {{350, 9}, {359, 14}, {373, 2}, {375, 8}, {383, 7}, {390, 5}, {395, 7}}}, }; EnumDef EnumDefinitions[2] { EnumDef{sizeof(PuzzleElementType::Enum), 2983807453}, EnumDef{sizeof(EMaterial::Enum), 2024002654}, }; + char MemberNameBuffer[64*64*64]{"xyxyzxyzwMMMMIPositionRotationScaleIdxModelIdxAssetTextureIdxAssetXYElementsModelHandleBoardTextureHandleIdxTileBaseColorTileDotColorTestDisabledCardTintCardsVisualsRefCardMaxAvailableCountUsedCountRefCardPositionRotationIsLockedIDPuzzleNameWidthTilesHeightTilesAvailableCardCountAvailableCardsPlacedCardsBackgroundTilesGoalPositionCountGoalPositionsBaseColorHighlightColorTFMaterialTextureModelVisible"}; }; constexpr MetadataTable Metadata; diff --git a/src/notes.txt b/src/notes.txt index 157009f..7f2e422 100644 --- a/src/notes.txt +++ b/src/notes.txt @@ -1,24 +1,13 @@ 4 bytes: 4cc File type idendifier -16 bytes: TypeInfoHeader -4 | 4 | 2 | 2 | 4 -Version | Base Type Hash | Base Type Idx | Type Count | Type Data Size -// If base type hash matches, skip past type data (using type data size) -// and just load binary blob directly +20 bytes: TypeInfoHeader +4 | 4 | 2 | 2 | 4 | 4 +Version | Base Type Hash | Base Type Idx | Type Count | Type Data Size | Member Data Size TypeDataSize bytes: TypeDefs - -// TODO: field table -name | array size -test | 1 - a | 1 - b | 1 - c | 1 - d | 32 +MemberDataSize bytes: Member data names, indexed from TypeDef // todo: enum table for upgrading strings? -xxx bytes: BaseType actual data - -[blob] +xxx bytes: actual data, Load/Save with BaseType diff --git a/tools/minidef.exe b/tools/minidef.exe index 23a98d3..757f646 100644 --- a/tools/minidef.exe +++ b/tools/minidef.exe @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4b4dd6b889ae15863809233066d3bb8e99fd3395a09b5302d74fb00ed940fcdc -size 160768 +oid sha256:6e101b18da1ba1e37156b03bc19ba3ee488d6eb02acbf491063f1d1f56dddaad +size 167424 diff --git a/tools/minidef.rdbg b/tools/minidef.rdbg index 4113ddf..b7af373 100644 Binary files a/tools/minidef.rdbg and b/tools/minidef.rdbg differ