diff --git a/src/ZoneCodeGeneratorLib/Generating/RenderingContext.cpp b/src/ZoneCodeGeneratorLib/Generating/RenderingContext.cpp index c5ae8ff8..2ce6a650 100644 --- a/src/ZoneCodeGeneratorLib/Generating/RenderingContext.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/RenderingContext.cpp @@ -18,8 +18,9 @@ RenderingUsedType::RenderingUsedType(const DataDefinition* type, StructureInform { } -RenderingContext::RenderingContext(std::string game, std::vector fastFileBlocks) +RenderingContext::RenderingContext(std::string game, const Architecture gameArchitecture, std::vector fastFileBlocks) : m_game(std::move(game)), + m_architecture_mismatch(gameArchitecture != OWN_ARCHITECTURE), m_blocks(std::move(fastFileBlocks)), m_asset(nullptr), m_has_actions(false), @@ -190,7 +191,8 @@ bool RenderingContext::UsedTypeHasActions(const RenderingUsedType* usedType) con std::unique_ptr RenderingContext::BuildContext(const IDataRepository* repository, StructureInformation* asset) { - auto context = std::make_unique(RenderingContext(repository->GetGameName(), repository->GetAllFastFileBlocks())); + auto context = + std::make_unique(RenderingContext(repository->GetGameName(), repository->GetArchitecture(), repository->GetAllFastFileBlocks())); context->MakeAsset(repository, asset); context->CreateUsedTypeCollections(); diff --git a/src/ZoneCodeGeneratorLib/Generating/RenderingContext.h b/src/ZoneCodeGeneratorLib/Generating/RenderingContext.h index 06ba68cb..0527cbe7 100644 --- a/src/ZoneCodeGeneratorLib/Generating/RenderingContext.h +++ b/src/ZoneCodeGeneratorLib/Generating/RenderingContext.h @@ -30,6 +30,7 @@ public: static std::unique_ptr BuildContext(const IDataRepository* repository, StructureInformation* asset); std::string m_game; + bool m_architecture_mismatch; std::vector m_blocks; StructureInformation* m_asset; @@ -43,7 +44,7 @@ public: const FastFileBlock* m_default_temp_block; private: - RenderingContext(std::string game, std::vector fastFileBlocks); + RenderingContext(std::string game, Architecture gameArchitecture, std::vector fastFileBlocks); RenderingUsedType* AddUsedType(std::unique_ptr usedType); RenderingUsedType* GetBaseType(const IDataRepository* repository, MemberComputations* computations, RenderingUsedType* usedType); diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp index 87181ba2..ff0aed3a 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp @@ -60,6 +60,13 @@ namespace // Method Declarations for (const auto* type : m_env.m_used_types) + { + if (type->m_info && type->m_type == type->m_info->m_definition && !type->m_info->m_has_matching_cross_platform_structure) + { + PrintFillStructMethodDeclaration(type->m_info); + } + } + for (const auto* type : m_env.m_used_types) { if (type->m_pointer_array_reference_exists) { @@ -149,6 +156,14 @@ namespace LINE("") PrintMainLoadMethod(); + for (const auto* type : m_env.m_used_types) + { + if (type->m_info && type->m_type == type->m_info->m_definition && !type->m_info->m_has_matching_cross_platform_structure) + { + LINE("") + PrintFillStructMethod(type->m_info); + } + } for (const auto* type : m_env.m_used_types) { if (type->m_pointer_array_reference_exists) @@ -212,6 +227,11 @@ namespace return std::format("{0}** var{1}Ptr;", def->GetFullName(), MakeSafeTypeName(def)); } + void PrintFillStructMethodDeclaration(const StructureInformation* info) + { + LINEF("void FillStruct_{1}(const ZoneStreamFillReadAccessor& fillAccessor);", LoaderClassName(m_env.m_asset), MakeSafeTypeName(info->m_definition)) + } + void PrintHeaderPtrArrayLoadMethodDeclaration(const DataDefinition* def) const { LINEF("void LoadPtrArray_{0}(bool atStreamStart, size_t count);", MakeSafeTypeName(def)) @@ -297,6 +317,28 @@ namespace LINE("}") } + void PrintFillStructMethod(const StructureInformation* info) + { + LINEF("void {0}::FillStruct_{1}(const ZoneStreamFillReadAccessor& fillAccessor)", + LoaderClassName(m_env.m_asset), + MakeSafeTypeName(info->m_definition)) + + LINE("{") + m_intendation++; + + for (const auto& member : info->m_ordered_members) + { + const MemberComputations computations(member.get()); + if (computations.ShouldIgnore()) + continue; + + LINEF("// FillStruct_{0}();", MakeSafeTypeName(member->m_member->m_type_declaration->m_type)) + } + + m_intendation--; + LINE("}") + } + void PrintLoadPtrArrayMethod_Loading(const DataDefinition* def, const StructureInformation* info) const { LINEF("*{0} = m_stream->Alloc<{1}>({2});", MakeTypePtrVarName(def), def->GetFullName(), def->GetAlignment()) @@ -339,7 +381,7 @@ namespace LINE("{") m_intendation++; - LINEF("*{0} = m_stream->ConvertOffsetToPointer(*{0});", MakeTypePtrVarName(def)) + LINEF("*{0} = m_stream->ConvertOffsetToPointerNative(*{0});", MakeTypePtrVarName(def)) m_intendation--; LINE("}") @@ -765,7 +807,7 @@ namespace LINEF("{0}** toInsert = nullptr;", member->m_member->m_type_declaration->m_type->GetFullName()) LINE("if (ptr == PTR_INSERT)") m_intendation++; - LINEF("toInsert = m_stream->InsertPointer<{0}>();", member->m_member->m_type_declaration->m_type->GetFullName()) + LINEF("toInsert = m_stream->InsertPointerNative<{0}>();", member->m_member->m_type_declaration->m_type->GetFullName()) m_intendation--; LINE("") } @@ -823,7 +865,7 @@ namespace LINE("{") m_intendation++; - LINEF("{0} = m_stream->ConvertOffsetToAlias({0});", MakeMemberAccess(info, member, modifier)) + LINEF("{0} = m_stream->ConvertOffsetToAliasNative({0});", MakeMemberAccess(info, member, modifier)) m_intendation--; LINE("}") @@ -842,7 +884,7 @@ namespace LINE("{") m_intendation++; - LINEF("{0} = m_stream->ConvertOffsetToPointer({0});", MakeMemberAccess(info, member, modifier)) + LINEF("{0} = m_stream->ConvertOffsetToPointerNative({0});", MakeMemberAccess(info, member, modifier)) m_intendation--; LINE("}") @@ -1080,24 +1122,39 @@ namespace { LINE("") LINE("if (atStreamStart)") - m_intendation++; - if (dynamicMember == nullptr) + if (info->m_has_matching_cross_platform_structure) { - LINEF("m_stream->Load<{0}>({1}); // Size: {2}", - info->m_definition->GetFullName(), - MakeTypeVarName(info->m_definition), - info->m_definition->GetSize()) + m_intendation++; + + if (dynamicMember == nullptr) + { + LINEF("m_stream->Load<{0}>({1}); // Size: {2}", + info->m_definition->GetFullName(), + MakeTypeVarName(info->m_definition), + info->m_definition->GetSize()) + } + else + { + LINEF("m_stream->LoadPartial<{0}>({1}, offsetof({0}, {2}));", + info->m_definition->GetFullName(), + MakeTypeVarName(info->m_definition), + dynamicMember->m_member->m_name) + } + + m_intendation--; } else { - LINEF("m_stream->LoadPartial<{0}>({1}, offsetof({0}, {2}));", - info->m_definition->GetFullName(), - MakeTypeVarName(info->m_definition), - dynamicMember->m_member->m_name) - } + LINE("{") + m_intendation++; - m_intendation--; + LINEF("{0} = m_memory.Alloc<{1}>();", MakeTypeVarName(info->m_definition), info->m_definition->m_name) + LINEF("FillStruct_{0}(m_stream->LoadWithFill({1}));", MakeSafeTypeName(info->m_definition), info->m_definition->GetSize()) + + m_intendation--; + LINE("}") + } } else { @@ -1182,7 +1239,7 @@ namespace LINEF("{0}** toInsert = nullptr;", info->m_definition->GetFullName()) LINE("if (ptr == PTR_INSERT)") m_intendation++; - LINEF("toInsert = m_stream->InsertPointer<{0}>();", info->m_definition->GetFullName()) + LINEF("toInsert = m_stream->InsertPointerNative<{0}>();", info->m_definition->GetFullName()) m_intendation--; } @@ -1236,11 +1293,11 @@ namespace if (inTemp) { - LINEF("*{0} = m_stream->ConvertOffsetToAlias(*{0});", MakeTypePtrVarName(info->m_definition)) + LINEF("*{0} = m_stream->ConvertOffsetToAliasNative(*{0});", MakeTypePtrVarName(info->m_definition)) } else { - LINEF("*{0} = m_stream->ConvertOffsetToPointer(*{0});", MakeTypePtrVarName(info->m_definition)) + LINEF("*{0} = m_stream->ConvertOffsetToPointerNative(*{0});", MakeTypePtrVarName(info->m_definition)) } m_intendation--; diff --git a/src/ZoneCommon/Game/IW3/ZoneConstantsIW3.h b/src/ZoneCommon/Game/IW3/ZoneConstantsIW3.h index 45896c5e..e7efa17b 100644 --- a/src/ZoneCommon/Game/IW3/ZoneConstantsIW3.h +++ b/src/ZoneCommon/Game/IW3/ZoneConstantsIW3.h @@ -20,7 +20,7 @@ namespace IW3 static constexpr size_t AUTHED_CHUNK_SIZE = 0x2000; static constexpr unsigned AUTHED_CHUNK_COUNT_PER_GROUP = 256; - static constexpr int OFFSET_BLOCK_BIT_COUNT = 4; + static constexpr unsigned OFFSET_BLOCK_BIT_COUNT = 4u; static constexpr block_t INSERT_BLOCK = XFILE_BLOCK_VIRTUAL; }; } // namespace IW3 diff --git a/src/ZoneCommon/Game/IW4/ZoneConstantsIW4.h b/src/ZoneCommon/Game/IW4/ZoneConstantsIW4.h index 42a334cd..d405e4cf 100644 --- a/src/ZoneCommon/Game/IW4/ZoneConstantsIW4.h +++ b/src/ZoneCommon/Game/IW4/ZoneConstantsIW4.h @@ -43,7 +43,7 @@ namespace IW4 static constexpr size_t AUTHED_CHUNK_SIZE = 0x2000; static constexpr unsigned AUTHED_CHUNK_COUNT_PER_GROUP = 256; - static constexpr int OFFSET_BLOCK_BIT_COUNT = 4; + static constexpr unsigned OFFSET_BLOCK_BIT_COUNT = 4u; static constexpr block_t INSERT_BLOCK = XFILE_BLOCK_VIRTUAL; }; } // namespace IW4 diff --git a/src/ZoneCommon/Game/IW5/ZoneConstantsIW5.h b/src/ZoneCommon/Game/IW5/ZoneConstantsIW5.h index 27f6b9f5..0e56f83d 100644 --- a/src/ZoneCommon/Game/IW5/ZoneConstantsIW5.h +++ b/src/ZoneCommon/Game/IW5/ZoneConstantsIW5.h @@ -40,7 +40,7 @@ namespace IW5 static constexpr size_t AUTHED_CHUNK_SIZE = 0x2000; static constexpr unsigned AUTHED_CHUNK_COUNT_PER_GROUP = 256; - static constexpr int OFFSET_BLOCK_BIT_COUNT = 4; + static constexpr unsigned OFFSET_BLOCK_BIT_COUNT = 4u; static constexpr block_t INSERT_BLOCK = XFILE_BLOCK_VIRTUAL; }; } // namespace IW5 diff --git a/src/ZoneCommon/Game/T5/ZoneConstantsT5.h b/src/ZoneCommon/Game/T5/ZoneConstantsT5.h index 5b79dc2a..b36559ea 100644 --- a/src/ZoneCommon/Game/T5/ZoneConstantsT5.h +++ b/src/ZoneCommon/Game/T5/ZoneConstantsT5.h @@ -20,7 +20,7 @@ namespace T5 static constexpr size_t AUTHED_CHUNK_SIZE = 0x2000; static constexpr unsigned AUTHED_CHUNK_COUNT_PER_GROUP = 256; - static constexpr int OFFSET_BLOCK_BIT_COUNT = 3; + static constexpr unsigned OFFSET_BLOCK_BIT_COUNT = 3u; static constexpr block_t INSERT_BLOCK = XFILE_BLOCK_VIRTUAL; }; } // namespace T5 diff --git a/src/ZoneCommon/Game/T6/ZoneConstantsT6.h b/src/ZoneCommon/Game/T6/ZoneConstantsT6.h index d68535ca..10213294 100644 --- a/src/ZoneCommon/Game/T6/ZoneConstantsT6.h +++ b/src/ZoneCommon/Game/T6/ZoneConstantsT6.h @@ -27,7 +27,7 @@ namespace T6 static constexpr int XCHUNK_SIZE = 0x8000; static constexpr int XCHUNK_MAX_WRITE_SIZE = XCHUNK_SIZE - 0x40; static constexpr int VANILLA_BUFFER_SIZE = 0x80000; - static constexpr int OFFSET_BLOCK_BIT_COUNT = 3; + static constexpr unsigned OFFSET_BLOCK_BIT_COUNT = 3u; static constexpr block_t INSERT_BLOCK = XFILE_BLOCK_VIRTUAL; static constexpr size_t FILE_SUFFIX_ZERO_MIN_SIZE = 0x40; diff --git a/src/ZoneLoading/Game/IW3/ContentLoaderIW3.cpp b/src/ZoneLoading/Game/IW3/ContentLoaderIW3.cpp index ed3e3909..0abc492e 100644 --- a/src/ZoneLoading/Game/IW3/ContentLoaderIW3.cpp +++ b/src/ZoneLoading/Game/IW3/ContentLoaderIW3.cpp @@ -32,8 +32,8 @@ using namespace IW3; -ContentLoader::ContentLoader(Zone& zone) - : ContentLoaderBase(zone), +ContentLoader::ContentLoader(Zone& zone, ZoneInputStream& stream) + : ContentLoaderBase(zone, stream), varXAsset(nullptr), varScriptStringList(nullptr) { @@ -134,10 +134,8 @@ void ContentLoader::LoadXAssetArray(const bool atStreamStart, const size_t count } } -void ContentLoader::Load(ZoneInputStream& stream) +void ContentLoader::Load() { - m_stream = &stream; - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); XAssetList assetList{}; diff --git a/src/ZoneLoading/Game/IW3/ContentLoaderIW3.h b/src/ZoneLoading/Game/IW3/ContentLoaderIW3.h index fb44f42d..32533a9d 100644 --- a/src/ZoneLoading/Game/IW3/ContentLoaderIW3.h +++ b/src/ZoneLoading/Game/IW3/ContentLoaderIW3.h @@ -9,9 +9,8 @@ namespace IW3 class ContentLoader final : public ContentLoaderBase, public IContentLoadingEntryPoint { public: - explicit ContentLoader(Zone& zone); - - void Load(ZoneInputStream& stream) override; + ContentLoader(Zone& zone, ZoneInputStream& stream); + void Load() override; private: void LoadScriptStringList(bool atStreamStart); diff --git a/src/ZoneLoading/Game/IW3/ZoneLoaderFactoryIW3.cpp b/src/ZoneLoading/Game/IW3/ZoneLoaderFactoryIW3.cpp index 5de47662..557b976d 100644 --- a/src/ZoneLoading/Game/IW3/ZoneLoaderFactoryIW3.cpp +++ b/src/ZoneLoading/Game/IW3/ZoneLoaderFactoryIW3.cpp @@ -85,8 +85,14 @@ std::unique_ptr ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader& zoneLoader->AddLoadingStep(step::CreateStepAllocXBlocks()); // Start of the zone content - zoneLoader->AddLoadingStep( - step::CreateStepLoadZoneContent(std::make_unique(*zonePtr), ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK)); + zoneLoader->AddLoadingStep(step::CreateStepLoadZoneContent( + [&zonePtr](ZoneInputStream& stream) + { + return std::make_unique(*zonePtr, stream); + }, + 32u, + ZoneConstants::OFFSET_BLOCK_BIT_COUNT, + ZoneConstants::INSERT_BLOCK)); return zoneLoader; } diff --git a/src/ZoneLoading/Game/IW4/ContentLoaderIW4.cpp b/src/ZoneLoading/Game/IW4/ContentLoaderIW4.cpp index a15b7229..9f1481d0 100644 --- a/src/ZoneLoading/Game/IW4/ContentLoaderIW4.cpp +++ b/src/ZoneLoading/Game/IW4/ContentLoaderIW4.cpp @@ -42,25 +42,38 @@ using namespace IW4; -ContentLoader::ContentLoader(Zone& zone) - : ContentLoaderBase(zone), +ContentLoader::ContentLoader(Zone& zone, ZoneInputStream& stream) + : ContentLoaderBase(zone, stream), + varXAssetList(nullptr), varXAsset(nullptr), varScriptStringList(nullptr) { } +void ContentLoader::FillStruct_XAssetList(const ZoneStreamFillReadAccessor& fillAccessor) +{ + varScriptStringList = &varXAssetList->stringList; + FillStruct_ScriptStringList(fillAccessor.AtOffset(0u)); + + fillAccessor.Fill(varXAssetList->assetCount, 8u); + fillAccessor.FillPtr(varXAssetList->assets, 12u); +} + +void ContentLoader::FillStruct_ScriptStringList(const ZoneStreamFillReadAccessor& fillAccessor) const +{ + fillAccessor.Fill(varScriptStringList->count, 0u); + fillAccessor.FillPtr(varScriptStringList->strings, 4u); +} + void ContentLoader::LoadScriptStringList(const bool atStreamStart) { - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - - if (atStreamStart) - m_stream->Load(varScriptStringList); + assert(!atStreamStart); if (varScriptStringList->strings != nullptr) { assert(varScriptStringList->strings == PTR_FOLLOWING); - varScriptStringList->strings = m_stream->Alloc(alignof(const char*)); + varScriptStringList->strings = m_stream->Alloc(4); varXString = varScriptStringList->strings; LoadXStringArray(true, varScriptStringList->count); @@ -68,8 +81,6 @@ void ContentLoader::LoadScriptStringList(const bool atStreamStart) m_zone.m_script_strings.InitializeForExistingZone(varScriptStringList->strings, static_cast(varScriptStringList->count)); } - m_stream->PopBlock(); - assert(m_zone.m_script_strings.Count() <= SCR_STRING_MAX + 1); } @@ -154,15 +165,15 @@ void ContentLoader::LoadXAssetArray(const bool atStreamStart, const size_t count } } -void ContentLoader::Load(ZoneInputStream& stream) +void ContentLoader::Load() { - m_stream = &stream; + XAssetList assetList{}; + varXAssetList = &assetList; + + FillStruct_XAssetList(m_stream->LoadWithFill(16u)); m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - XAssetList assetList{}; - m_stream->LoadDataRaw(&assetList, sizeof(assetList)); - varScriptStringList = &assetList.stringList; LoadScriptStringList(false); diff --git a/src/ZoneLoading/Game/IW4/ContentLoaderIW4.h b/src/ZoneLoading/Game/IW4/ContentLoaderIW4.h index a3c30973..8b7452de 100644 --- a/src/ZoneLoading/Game/IW4/ContentLoaderIW4.h +++ b/src/ZoneLoading/Game/IW4/ContentLoaderIW4.h @@ -9,16 +9,19 @@ namespace IW4 class ContentLoader final : public ContentLoaderBase, public IContentLoadingEntryPoint { public: - explicit ContentLoader(Zone& zone); - - void Load(ZoneInputStream& stream) override; + explicit ContentLoader(Zone& zone, ZoneInputStream& stream); + void Load() override; private: + void FillStruct_XAssetList(const ZoneStreamFillReadAccessor& fillAccessor); + void FillStruct_ScriptStringList(const ZoneStreamFillReadAccessor& fillAccessor) const; + void LoadScriptStringList(bool atStreamStart); void LoadXAsset(bool atStreamStart) const; void LoadXAssetArray(bool atStreamStart, size_t count); + XAssetList* varXAssetList; XAsset* varXAsset; ScriptStringList* varScriptStringList; }; diff --git a/src/ZoneLoading/Game/IW4/ZoneLoaderFactoryIW4.cpp b/src/ZoneLoading/Game/IW4/ZoneLoaderFactoryIW4.cpp index 4cc808e0..7e13c582 100644 --- a/src/ZoneLoading/Game/IW4/ZoneLoaderFactoryIW4.cpp +++ b/src/ZoneLoading/Game/IW4/ZoneLoaderFactoryIW4.cpp @@ -207,8 +207,14 @@ std::unique_ptr ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader& zoneLoader->AddLoadingStep(step::CreateStepAllocXBlocks()); // Start of the zone content - zoneLoader->AddLoadingStep( - step::CreateStepLoadZoneContent(std::make_unique(*zonePtr), ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK)); + zoneLoader->AddLoadingStep(step::CreateStepLoadZoneContent( + [&zonePtr](ZoneInputStream& stream) + { + return std::make_unique(*zonePtr, stream); + }, + 32u, + ZoneConstants::OFFSET_BLOCK_BIT_COUNT, + ZoneConstants::INSERT_BLOCK)); return zoneLoader; } diff --git a/src/ZoneLoading/Game/IW5/ContentLoaderIW5.cpp b/src/ZoneLoading/Game/IW5/ContentLoaderIW5.cpp index 2558ab88..d9a99450 100644 --- a/src/ZoneLoading/Game/IW5/ContentLoaderIW5.cpp +++ b/src/ZoneLoading/Game/IW5/ContentLoaderIW5.cpp @@ -47,8 +47,8 @@ using namespace IW5; -ContentLoader::ContentLoader(Zone& zone) - : ContentLoaderBase(zone), +ContentLoader::ContentLoader(Zone& zone, ZoneInputStream& stream) + : ContentLoaderBase(zone, stream), varXAsset(nullptr), varScriptStringList(nullptr) { @@ -163,10 +163,8 @@ void ContentLoader::LoadXAssetArray(const bool atStreamStart, const size_t count } } -void ContentLoader::Load(ZoneInputStream& stream) +void ContentLoader::Load() { - m_stream = &stream; - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); XAssetList assetList{}; diff --git a/src/ZoneLoading/Game/IW5/ContentLoaderIW5.h b/src/ZoneLoading/Game/IW5/ContentLoaderIW5.h index b06631a2..e618f44f 100644 --- a/src/ZoneLoading/Game/IW5/ContentLoaderIW5.h +++ b/src/ZoneLoading/Game/IW5/ContentLoaderIW5.h @@ -9,9 +9,8 @@ namespace IW5 class ContentLoader final : public ContentLoaderBase, public IContentLoadingEntryPoint { public: - explicit ContentLoader(Zone& zone); - - void Load(ZoneInputStream& stream) override; + explicit ContentLoader(Zone& zone, ZoneInputStream& stream); + void Load() override; private: void LoadScriptStringList(bool atStreamStart); diff --git a/src/ZoneLoading/Game/IW5/ZoneLoaderFactoryIW5.cpp b/src/ZoneLoading/Game/IW5/ZoneLoaderFactoryIW5.cpp index 4e77a1ca..eeb68206 100644 --- a/src/ZoneLoading/Game/IW5/ZoneLoaderFactoryIW5.cpp +++ b/src/ZoneLoading/Game/IW5/ZoneLoaderFactoryIW5.cpp @@ -184,8 +184,14 @@ std::unique_ptr ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader& zoneLoader->AddLoadingStep(step::CreateStepAllocXBlocks()); // Start of the zone content - zoneLoader->AddLoadingStep( - step::CreateStepLoadZoneContent(std::make_unique(*zonePtr), ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK)); + zoneLoader->AddLoadingStep(step::CreateStepLoadZoneContent( + [&zonePtr](ZoneInputStream& stream) + { + return std::make_unique(*zonePtr, stream); + }, + 32u, + ZoneConstants::OFFSET_BLOCK_BIT_COUNT, + ZoneConstants::INSERT_BLOCK)); return zoneLoader; } diff --git a/src/ZoneLoading/Game/T5/ContentLoaderT5.cpp b/src/ZoneLoading/Game/T5/ContentLoaderT5.cpp index 2fe47338..5f31b3c9 100644 --- a/src/ZoneLoading/Game/T5/ContentLoaderT5.cpp +++ b/src/ZoneLoading/Game/T5/ContentLoaderT5.cpp @@ -39,8 +39,8 @@ using namespace T5; -ContentLoader::ContentLoader(Zone& zone) - : ContentLoaderBase(zone), +ContentLoader::ContentLoader(Zone& zone, ZoneInputStream& stream) + : ContentLoaderBase(zone, stream), varXAsset(nullptr), varScriptStringList(nullptr) { @@ -147,10 +147,8 @@ void ContentLoader::LoadXAssetArray(const bool atStreamStart, const size_t count } } -void ContentLoader::Load(ZoneInputStream& stream) +void ContentLoader::Load() { - m_stream = &stream; - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); XAssetList assetList{}; diff --git a/src/ZoneLoading/Game/T5/ContentLoaderT5.h b/src/ZoneLoading/Game/T5/ContentLoaderT5.h index 3fd035f4..1881cc57 100644 --- a/src/ZoneLoading/Game/T5/ContentLoaderT5.h +++ b/src/ZoneLoading/Game/T5/ContentLoaderT5.h @@ -9,9 +9,8 @@ namespace T5 class ContentLoader final : public ContentLoaderBase, public IContentLoadingEntryPoint { public: - explicit ContentLoader(Zone& zone); - - void Load(ZoneInputStream& stream) override; + explicit ContentLoader(Zone& zone, ZoneInputStream& stream); + void Load() override; private: void LoadScriptStringList(bool atStreamStart); diff --git a/src/ZoneLoading/Game/T5/ZoneLoaderFactoryT5.cpp b/src/ZoneLoading/Game/T5/ZoneLoaderFactoryT5.cpp index e04c9ead..555d955f 100644 --- a/src/ZoneLoading/Game/T5/ZoneLoaderFactoryT5.cpp +++ b/src/ZoneLoading/Game/T5/ZoneLoaderFactoryT5.cpp @@ -85,8 +85,14 @@ std::unique_ptr ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader& zoneLoader->AddLoadingStep(step::CreateStepAllocXBlocks()); // Start of the zone content - zoneLoader->AddLoadingStep( - step::CreateStepLoadZoneContent(std::make_unique(*zonePtr), ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK)); + zoneLoader->AddLoadingStep(step::CreateStepLoadZoneContent( + [&zonePtr](ZoneInputStream& stream) + { + return std::make_unique(*zonePtr, stream); + }, + 32u, + ZoneConstants::OFFSET_BLOCK_BIT_COUNT, + ZoneConstants::INSERT_BLOCK)); return zoneLoader; } diff --git a/src/ZoneLoading/Game/T6/ContentLoaderT6.cpp b/src/ZoneLoading/Game/T6/ContentLoaderT6.cpp index 287da637..33d74542 100644 --- a/src/ZoneLoading/Game/T6/ContentLoaderT6.cpp +++ b/src/ZoneLoading/Game/T6/ContentLoaderT6.cpp @@ -55,8 +55,8 @@ using namespace T6; -ContentLoader::ContentLoader(Zone& zone) - : ContentLoaderBase(zone), +ContentLoader::ContentLoader(Zone& zone, ZoneInputStream& stream) + : ContentLoaderBase(zone, stream), varXAsset(nullptr), varScriptStringList(nullptr) { @@ -176,10 +176,8 @@ void ContentLoader::LoadXAssetArray(const bool atStreamStart, const size_t count } } -void ContentLoader::Load(ZoneInputStream& stream) +void ContentLoader::Load() { - m_stream = &stream; - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); XAssetList assetList{}; diff --git a/src/ZoneLoading/Game/T6/ContentLoaderT6.h b/src/ZoneLoading/Game/T6/ContentLoaderT6.h index 1ef06b3a..acde76f7 100644 --- a/src/ZoneLoading/Game/T6/ContentLoaderT6.h +++ b/src/ZoneLoading/Game/T6/ContentLoaderT6.h @@ -9,9 +9,8 @@ namespace T6 class ContentLoader final : public ContentLoaderBase, public IContentLoadingEntryPoint { public: - explicit ContentLoader(Zone& zone); - - void Load(ZoneInputStream& stream) override; + explicit ContentLoader(Zone& zone, ZoneInputStream& stream); + void Load() override; private: void LoadScriptStringList(bool atStreamStart); diff --git a/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.cpp b/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.cpp index e2bb2d24..4df11d30 100644 --- a/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.cpp +++ b/src/ZoneLoading/Game/T6/ZoneLoaderFactoryT6.cpp @@ -203,8 +203,14 @@ std::unique_ptr ZoneLoaderFactory::CreateLoaderForHeader(ZoneHeader& zoneLoader->AddLoadingStep(step::CreateStepAllocXBlocks()); // Start of the zone content - zoneLoader->AddLoadingStep( - step::CreateStepLoadZoneContent(std::make_unique(*zonePtr), ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK)); + zoneLoader->AddLoadingStep(step::CreateStepLoadZoneContent( + [&zonePtr](ZoneInputStream& stream) + { + return std::make_unique(*zonePtr, stream); + }, + 32u, + ZoneConstants::OFFSET_BLOCK_BIT_COUNT, + ZoneConstants::INSERT_BLOCK)); if (isSecure) { diff --git a/src/ZoneLoading/Loading/ContentLoaderBase.cpp b/src/ZoneLoading/Loading/ContentLoaderBase.cpp index 1b4420f6..1a1b92d9 100644 --- a/src/ZoneLoading/Loading/ContentLoaderBase.cpp +++ b/src/ZoneLoading/Loading/ContentLoaderBase.cpp @@ -5,14 +5,6 @@ const void* ContentLoaderBase::PTR_FOLLOWING = reinterpret_cast(-1); const void* ContentLoaderBase::PTR_INSERT = reinterpret_cast(-2); -ContentLoaderBase::ContentLoaderBase(Zone& zone) - : varXString(nullptr), - m_zone(zone), - m_memory(zone.Memory()), - m_stream(nullptr) -{ -} - ContentLoaderBase::ContentLoaderBase(Zone& zone, ZoneInputStream& stream) : varXString(nullptr), m_zone(zone), @@ -37,7 +29,7 @@ void ContentLoaderBase::LoadXString(const bool atStreamStart) const } else { - *varXString = m_stream->ConvertOffsetToPointer(*varXString); + *varXString = m_stream->ConvertOffsetToPointerNative(*varXString); } } } diff --git a/src/ZoneLoading/Loading/ContentLoaderBase.h b/src/ZoneLoading/Loading/ContentLoaderBase.h index 51fe7cc8..3c99a915 100644 --- a/src/ZoneLoading/Loading/ContentLoaderBase.h +++ b/src/ZoneLoading/Loading/ContentLoaderBase.h @@ -17,7 +17,6 @@ public: ContentLoaderBase& operator=(ContentLoaderBase&& other) noexcept = delete; protected: - explicit ContentLoaderBase(Zone& zone); ContentLoaderBase(Zone& zone, ZoneInputStream& stream); void LoadXString(bool atStreamStart) const; @@ -27,5 +26,5 @@ protected: Zone& m_zone; MemoryManager& m_memory; - ZoneInputStream* m_stream; + ZoneInputStream* m_stream; // TODO: Change this to reference }; diff --git a/src/ZoneLoading/Loading/IContentLoadingEntryPoint.h b/src/ZoneLoading/Loading/IContentLoadingEntryPoint.h index 25a8db46..fd01844b 100644 --- a/src/ZoneLoading/Loading/IContentLoadingEntryPoint.h +++ b/src/ZoneLoading/Loading/IContentLoadingEntryPoint.h @@ -1,7 +1,5 @@ #pragma once -#include "Zone/Stream/ZoneInputStream.h" - class IContentLoadingEntryPoint { public: @@ -12,5 +10,5 @@ public: IContentLoadingEntryPoint& operator=(const IContentLoadingEntryPoint& other) = default; IContentLoadingEntryPoint& operator=(IContentLoadingEntryPoint&& other) noexcept = default; - virtual void Load(ZoneInputStream& stream) = 0; + virtual void Load() = 0; }; diff --git a/src/ZoneLoading/Loading/Steps/StepLoadZoneContent.cpp b/src/ZoneLoading/Loading/Steps/StepLoadZoneContent.cpp index 5b0ed359..651b36f6 100644 --- a/src/ZoneLoading/Loading/Steps/StepLoadZoneContent.cpp +++ b/src/ZoneLoading/Loading/Steps/StepLoadZoneContent.cpp @@ -7,8 +7,12 @@ namespace class StepLoadZoneContent final : public ILoadingStep { public: - StepLoadZoneContent(std::unique_ptr entryPoint, const int offsetBlockBitCount, const block_t insertBlock) - : m_content_loader(std::move(entryPoint)), + StepLoadZoneContent(std::function(ZoneInputStream&)> entryPointFactory, + const unsigned pointerBitCount, + const unsigned offsetBlockBitCount, + const block_t insertBlock) + : m_entry_point_factory(std::move(entryPointFactory)), + m_pointer_bit_count(pointerBitCount), m_offset_block_bit_count(offsetBlockBitCount), m_insert_block(insertBlock) { @@ -16,23 +20,29 @@ namespace void PerformStep(ZoneLoader& zoneLoader, ILoadingStream& stream) override { - const auto inputStream = ZoneInputStream::Create(zoneLoader.m_blocks, stream, m_offset_block_bit_count, m_insert_block); + const auto inputStream = ZoneInputStream::Create(m_pointer_bit_count, m_offset_block_bit_count, zoneLoader.m_blocks, m_insert_block, stream); - m_content_loader->Load(*inputStream); + const auto entryPoint = m_entry_point_factory(*inputStream); + assert(entryPoint); + + entryPoint->Load(); } private: - std::unique_ptr m_content_loader; - int m_offset_block_bit_count; + std::function(ZoneInputStream&)> m_entry_point_factory; + unsigned m_pointer_bit_count; + unsigned m_offset_block_bit_count; block_t m_insert_block; }; } // namespace namespace step { - std::unique_ptr - CreateStepLoadZoneContent(std::unique_ptr entryPoint, const int offsetBlockBitCount, const block_t insertBlock) + std::unique_ptr CreateStepLoadZoneContent(std::function(ZoneInputStream&)> entryPointFactory, + const unsigned pointerBitCount, + const unsigned offsetBlockBitCount, + const block_t insertBlock) { - return std::make_unique(std::move(entryPoint), offsetBlockBitCount, insertBlock); + return std::make_unique(std::move(entryPointFactory), pointerBitCount, offsetBlockBitCount, insertBlock); } } // namespace step diff --git a/src/ZoneLoading/Loading/Steps/StepLoadZoneContent.h b/src/ZoneLoading/Loading/Steps/StepLoadZoneContent.h index 2e1c2614..536ef1a4 100644 --- a/src/ZoneLoading/Loading/Steps/StepLoadZoneContent.h +++ b/src/ZoneLoading/Loading/Steps/StepLoadZoneContent.h @@ -2,11 +2,15 @@ #include "Loading/IContentLoadingEntryPoint.h" #include "Loading/ILoadingStep.h" +#include "Zone/Stream/ZoneInputStream.h" +#include #include namespace step { - std::unique_ptr - CreateStepLoadZoneContent(std::unique_ptr entryPoint, int offsetBlockBitCount, block_t insertBlock); + std::unique_ptr CreateStepLoadZoneContent(std::function(ZoneInputStream&)> entryPointFactory, + unsigned pointerBitCount, + unsigned offsetBlockBitCount, + block_t insertBlock); } diff --git a/src/ZoneLoading/Zone/Stream/ZoneInputStream.cpp b/src/ZoneLoading/Zone/Stream/ZoneInputStream.cpp index 86e3343f..572e8494 100644 --- a/src/ZoneLoading/Zone/Stream/ZoneInputStream.cpp +++ b/src/ZoneLoading/Zone/Stream/ZoneInputStream.cpp @@ -10,22 +10,38 @@ #include #include +ZoneStreamFillReadAccessor::ZoneStreamFillReadAccessor(const void* buffer, const size_t bufferSize, const unsigned pointerByteCount) + : m_buffer(buffer), + m_buffer_size(bufferSize), + m_pointer_byte_count(pointerByteCount) +{ +} + +ZoneStreamFillReadAccessor ZoneStreamFillReadAccessor::AtOffset(const size_t offset) const +{ + assert(offset < m_buffer_size); + return ZoneStreamFillReadAccessor(static_cast(m_buffer) + offset, m_buffer_size - offset, m_pointer_byte_count); +} + namespace { class XBlockInputStream final : public ZoneInputStream { public: - XBlockInputStream(std::vector& blocks, ILoadingStream& stream, const unsigned blockBitCount, const block_t insertBlock) + XBlockInputStream( + const unsigned pointerBitCount, const unsigned blockBitCount, std::vector& blocks, const block_t insertBlock, ILoadingStream& stream) : m_blocks(blocks), - m_stream(stream) + m_stream(stream), + m_pointer_byte_count(pointerBitCount / 8u), + m_block_bit_count(blockBitCount) { + assert(pointerBitCount % 8u == 0u); + assert(insertBlock < static_cast(blocks.size())); + const auto blockCount = static_cast(blocks.size()); m_block_offsets = std::make_unique(blockCount); std::memset(m_block_offsets.get(), 0, sizeof(size_t) * blockCount); - m_block_bit_count = blockBitCount; - - assert(insertBlock < static_cast(blocks.size())); m_insert_block = blocks[insertBlock]; } @@ -87,50 +103,42 @@ namespace void LoadDataInBlock(void* dst, const size_t size) override { - assert(!m_block_stack.empty()); - - if (m_block_stack.empty()) - return; - - auto* block = m_block_stack.top(); - - if (block->m_buffer > dst || block->m_buffer + block->m_buffer_size < dst) - throw OutOfBlockBoundsException(block); - - if (static_cast(dst) + size > block->m_buffer + block->m_buffer_size) - throw BlockOverflowException(block); - - // Theoretically ptr should always be at the current block offset. - assert(dst == &block->m_buffer[m_block_offsets[block->m_index]]); - - switch (block->m_type) + // If no block has been pushed, load raw + if (!m_block_stack.empty()) { - case XBlock::Type::BLOCK_TYPE_TEMP: - case XBlock::Type::BLOCK_TYPE_NORMAL: - m_stream.Load(dst, size); - break; + auto* block = m_block_stack.top(); - case XBlock::Type::BLOCK_TYPE_RUNTIME: - memset(dst, 0, size); - break; + if (block->m_buffer > dst || block->m_buffer + block->m_buffer_size < dst) + throw OutOfBlockBoundsException(block); - case XBlock::Type::BLOCK_TYPE_DELAY: - assert(false); - break; + if (static_cast(dst) + size > block->m_buffer + block->m_buffer_size) + throw BlockOverflowException(block); + + // Theoretically ptr should always be at the current block offset. + assert(dst == &block->m_buffer[m_block_offsets[block->m_index]]); + + switch (block->m_type) + { + case XBlock::Type::BLOCK_TYPE_TEMP: + case XBlock::Type::BLOCK_TYPE_NORMAL: + m_stream.Load(dst, size); + break; + + case XBlock::Type::BLOCK_TYPE_RUNTIME: + std::memset(dst, 0, size); + break; + + case XBlock::Type::BLOCK_TYPE_DELAY: + assert(false); + break; + } + + IncBlockPos(size); + } + else + { + m_stream.Load(dst, size); } - - IncBlockPos(size); - } - - void IncBlockPos(const size_t size) override - { - assert(!m_block_stack.empty()); - - if (m_block_stack.empty()) - return; - - const auto* block = m_block_stack.top(); - m_block_offsets[block->m_index] += size; } void LoadNullTerminated(void* dst) override @@ -162,25 +170,61 @@ namespace m_block_offsets[block->m_index] = offset; } - void** InsertPointer() override + ZoneStreamFillReadAccessor LoadWithFill(const size_t size) override + { + m_fill_buffer.reserve(size); + auto* dst = m_fill_buffer.data(); + + // If no block has been pushed, load raw + if (!m_block_stack.empty()) + { + const auto* block = m_block_stack.top(); + switch (block->m_type) + { + case XBlock::Type::BLOCK_TYPE_TEMP: + case XBlock::Type::BLOCK_TYPE_NORMAL: + m_stream.Load(dst, size); + break; + + case XBlock::Type::BLOCK_TYPE_RUNTIME: + std::memset(dst, 0, size); + break; + + case XBlock::Type::BLOCK_TYPE_DELAY: + assert(false); + break; + } + + IncBlockPos(size); + } + else + { + m_stream.Load(dst, size); + } + + return ZoneStreamFillReadAccessor(dst, size, m_pointer_byte_count); + } + + void* InsertPointer() override { m_block_stack.push(m_insert_block); - Align(alignof(void*)); + // Alignment of pointer should always be its size + Align(m_pointer_byte_count); - if (m_block_offsets[m_insert_block->m_index] + sizeof(void*) > m_insert_block->m_buffer_size) + if (m_block_offsets[m_insert_block->m_index] + m_pointer_byte_count > m_insert_block->m_buffer_size) throw BlockOverflowException(m_insert_block); - auto* ptr = reinterpret_cast(&m_insert_block->m_buffer[m_block_offsets[m_insert_block->m_index]]); + auto* ptr = static_cast(&m_insert_block->m_buffer[m_block_offsets[m_insert_block->m_index]]); - IncBlockPos(sizeof(void*)); + IncBlockPos(m_pointer_byte_count); m_block_stack.pop(); return ptr; } - void* ConvertOffsetToPointer(const void* offset) override + void* ConvertOffsetToPointerNative(const void* offset) override { // -1 because otherwise Block 0 Offset 0 would be just 0 which is already used to signalize a nullptr. // So all offsets are moved by 1. @@ -200,7 +244,7 @@ namespace return &block->m_buffer[blockOffset]; } - void* ConvertOffsetToAlias(const void* offset) override + void* ConvertOffsetToAliasNative(const void* offset) override { // For details see ConvertOffsetToPointer const auto offsetInt = reinterpret_cast(offset) - 1u; @@ -220,6 +264,17 @@ namespace } private: + void IncBlockPos(const size_t size) + { + assert(!m_block_stack.empty()); + + if (m_block_stack.empty()) + return; + + const auto* block = m_block_stack.top(); + m_block_offsets[block->m_index] += size; + } + void Align(const unsigned align) { assert(!m_block_stack.empty()); @@ -238,12 +293,16 @@ namespace std::stack m_temp_offsets; ILoadingStream& m_stream; + unsigned m_pointer_byte_count; unsigned m_block_bit_count; XBlock* m_insert_block; + + std::vector m_fill_buffer; }; } // namespace -std::unique_ptr ZoneInputStream::Create(std::vector& blocks, ILoadingStream& stream, unsigned blockBitCount, block_t insertBlock) +std::unique_ptr ZoneInputStream::Create( + const unsigned pointerBitCount, const unsigned blockBitCount, std::vector& blocks, const block_t insertBlock, ILoadingStream& stream) { - return std::make_unique(blocks, stream, blockBitCount, insertBlock); + return std::make_unique(pointerBitCount, blockBitCount, blocks, insertBlock, stream); } diff --git a/src/ZoneLoading/Zone/Stream/ZoneInputStream.h b/src/ZoneLoading/Zone/Stream/ZoneInputStream.h index 70acb592..8c7d0f26 100644 --- a/src/ZoneLoading/Zone/Stream/ZoneInputStream.h +++ b/src/ZoneLoading/Zone/Stream/ZoneInputStream.h @@ -4,23 +4,85 @@ #include "Zone/Stream/IZoneStream.h" #include "Zone/XBlock.h" +#include #include #include +class ZoneStreamFillReadAccessor +{ +public: + ZoneStreamFillReadAccessor(const void* buffer, size_t bufferSize, unsigned pointerByteCount); + + [[nodiscard]] ZoneStreamFillReadAccessor AtOffset(size_t offset) const; + + template void Fill(T& value, const size_t offset) const + { + assert(offset + sizeof(T) <= m_buffer_size); + + value = *reinterpret_cast(static_cast(m_buffer) + offset); + } + + template void FillArray(T* value, const size_t offset, const size_t arraySize) const + { + assert(offset + sizeof(T) * arraySize <= m_buffer_size); + + std::memcpy(value, static_cast(m_buffer) + offset, sizeof(T) * arraySize); + } + + template void FillPtr(T*& value, const size_t offset) const + { + assert(offset + m_pointer_byte_count <= m_buffer_size); + assert(m_pointer_byte_count <= sizeof(uintptr_t)); + + value = nullptr; + std::memcpy(&value, static_cast(m_buffer) + offset, m_pointer_byte_count); + } + +private: + const void* m_buffer; + size_t m_buffer_size; + unsigned m_pointer_byte_count; +}; + class ZoneInputStream : public IZoneStream { public: + /** + * \brief Retrieves the new read position in the current block by aligning the position with the specified value and then returning the current read + * position in the block. + * \param align The alignment value that the read position is aligned with before being returned. This should typically be the alignment of the struct that + * should be read afterward. + * \return A pointer to the memory in which following load calls will load data to. + */ virtual void* Alloc(unsigned align) = 0; + /** + * \copydoc ZoneInputStream#Alloc(unsigned) + */ template T* Alloc(const unsigned align) { return static_cast(Alloc(align)); } + /** + * \brief Loads data from the underlying stream without considering the current block or advancing the block position. + * The data is read directly to the specified location instead of block memory. + * \param dst The memory location to load data to. + * \param size The amount of data to load. + */ virtual void LoadDataRaw(void* dst, size_t size) = 0; + + /** + * \brief Loads data with the current blocks read operation into its block memory. + * Depending on the block type, the underlying stream might be read from or not. + * The current block position is advanced by the number of bytes read. + * The destination must be inside the current block's memory space, otherwise an exception is thrown. + * \param dst The destination where the data is loaded to. Must be inside the current block's memory bounds. + * \param size The amount of data to load. + */ virtual void LoadDataInBlock(void* dst, size_t size) = 0; - virtual void IncBlockPos(size_t size) = 0; virtual void LoadNullTerminated(void* dst) = 0; + virtual ZoneStreamFillReadAccessor LoadWithFill(size_t size) = 0; template void Load(T* dst) { @@ -37,26 +99,27 @@ public: LoadDataInBlock(const_cast(reinterpret_cast(dst)), size); } - virtual void** InsertPointer() = 0; + virtual void* InsertPointer() = 0; - template T** InsertPointer() + template T** InsertPointerNative() { - return reinterpret_cast(InsertPointer()); + return static_cast(InsertPointer()); } - virtual void* ConvertOffsetToPointer(const void* offset) = 0; + virtual void* ConvertOffsetToPointerNative(const void* offset) = 0; - template T* ConvertOffsetToPointer(T* offset) + template T* ConvertOffsetToPointerNative(T* offset) { - return static_cast(ConvertOffsetToPointer(static_cast(offset))); + return static_cast(ConvertOffsetToPointerNative(static_cast(offset))); } - virtual void* ConvertOffsetToAlias(const void* offset) = 0; + virtual void* ConvertOffsetToAliasNative(const void* offset) = 0; - template T* ConvertOffsetToAlias(T* offset) + template T* ConvertOffsetToAliasNative(T* offset) { - return static_cast(ConvertOffsetToAlias(static_cast(offset))); + return static_cast(ConvertOffsetToAliasNative(static_cast(offset))); } - static std::unique_ptr Create(std::vector& blocks, ILoadingStream& stream, unsigned blockBitCount, block_t insertBlock); + static std::unique_ptr + Create(unsigned pointerBitCount, unsigned blockBitCount, std::vector& blocks, block_t insertBlock, ILoadingStream& stream); };