From 77af856a87182eec8cdfd38e3aec41a54db77b53 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Mon, 5 Jan 2026 10:42:37 +0000 Subject: [PATCH 01/20] chore: remove ifdefs for disabling certain system tests * Previously reading written zones was disabled * Reenable it to test for success in writing correct zones --- test/SystemTests/Game/IW3/SimpleZoneIW3.cpp | 3 --- test/SystemTests/Game/IW4/SimpleZoneIW4.cpp | 3 --- test/SystemTests/Game/IW5/SimpleZoneIW5.cpp | 3 --- test/SystemTests/Game/T5/SimpleZoneT5.cpp | 3 --- test/SystemTests/Game/T6/ExtendAndDereferenceT6.cpp | 3 --- test/SystemTests/Game/T6/ReuseGlobalAssetPoolsAssetsT6.cpp | 3 --- test/SystemTests/Game/T6/SimpleZoneT6.cpp | 3 --- 7 files changed, 21 deletions(-) diff --git a/test/SystemTests/Game/IW3/SimpleZoneIW3.cpp b/test/SystemTests/Game/IW3/SimpleZoneIW3.cpp index 4092878a..d2d989b7 100644 --- a/test/SystemTests/Game/IW3/SimpleZoneIW3.cpp +++ b/test/SystemTests/Game/IW3/SimpleZoneIW3.cpp @@ -46,8 +46,6 @@ namespace REQUIRE(linkerResult); - // x64 for now produces invalid zones, don't try to load them yet -#ifdef ARCH_x86 const auto expectedZonePath = (fs::path(outputPath) / "SimpleZoneIW3.ff").string(); auto maybeZone = ZoneLoading::LoadZone(expectedZonePath, std::nullopt); REQUIRE(maybeZone); @@ -60,6 +58,5 @@ namespace REQUIRE(zone->m_name == "SimpleZoneIW3"); REQUIRE(pools->GetTotalAssetCount() == 1); REQUIRE(pools->m_raw_file->GetAsset("SimpleZone.txt")); -#endif } } // namespace diff --git a/test/SystemTests/Game/IW4/SimpleZoneIW4.cpp b/test/SystemTests/Game/IW4/SimpleZoneIW4.cpp index f89314a7..b41799ee 100644 --- a/test/SystemTests/Game/IW4/SimpleZoneIW4.cpp +++ b/test/SystemTests/Game/IW4/SimpleZoneIW4.cpp @@ -46,8 +46,6 @@ namespace REQUIRE(linkerResult); - // x64 for now produces invalid zones, don't try to load them yet -#ifdef ARCH_x86 const auto expectedZonePath = (fs::path(outputPath) / "SimpleZoneIW4.ff").string(); auto maybeZone = ZoneLoading::LoadZone(expectedZonePath, std::nullopt); REQUIRE(maybeZone); @@ -60,6 +58,5 @@ namespace REQUIRE(zone->m_name == "SimpleZoneIW4"); REQUIRE(pools->GetTotalAssetCount() == 1); REQUIRE(pools->m_raw_file->GetAsset("SimpleZone.txt")); -#endif } } // namespace diff --git a/test/SystemTests/Game/IW5/SimpleZoneIW5.cpp b/test/SystemTests/Game/IW5/SimpleZoneIW5.cpp index bd3c80d3..3d5979ce 100644 --- a/test/SystemTests/Game/IW5/SimpleZoneIW5.cpp +++ b/test/SystemTests/Game/IW5/SimpleZoneIW5.cpp @@ -46,8 +46,6 @@ namespace REQUIRE(linkerResult); - // x64 for now produces invalid zones, don't try to load them yet -#ifdef ARCH_x86 const auto expectedZonePath = (fs::path(outputPath) / "SimpleZoneIW5.ff").string(); auto maybeZone = ZoneLoading::LoadZone(expectedZonePath, std::nullopt); REQUIRE(maybeZone); @@ -60,6 +58,5 @@ namespace REQUIRE(zone->m_name == "SimpleZoneIW5"); REQUIRE(pools->GetTotalAssetCount() == 1); REQUIRE(pools->m_raw_file->GetAsset("SimpleZone.txt")); -#endif } } // namespace diff --git a/test/SystemTests/Game/T5/SimpleZoneT5.cpp b/test/SystemTests/Game/T5/SimpleZoneT5.cpp index 7ba904b0..6f85e0de 100644 --- a/test/SystemTests/Game/T5/SimpleZoneT5.cpp +++ b/test/SystemTests/Game/T5/SimpleZoneT5.cpp @@ -46,8 +46,6 @@ namespace REQUIRE(linkerResult); - // x64 for now produces invalid zones, don't try to load them yet -#ifdef ARCH_x86 const auto expectedZonePath = (fs::path(outputPath) / "SimpleZoneT5.ff").string(); auto maybeZone = ZoneLoading::LoadZone(expectedZonePath, std::nullopt); REQUIRE(maybeZone); @@ -60,6 +58,5 @@ namespace REQUIRE(zone->m_name == "SimpleZoneT5"); REQUIRE(pools->GetTotalAssetCount() == 1); REQUIRE(pools->m_raw_file->GetAsset("SimpleZone.txt")); -#endif } } // namespace diff --git a/test/SystemTests/Game/T6/ExtendAndDereferenceT6.cpp b/test/SystemTests/Game/T6/ExtendAndDereferenceT6.cpp index b83e2fa6..17ad84bc 100644 --- a/test/SystemTests/Game/T6/ExtendAndDereferenceT6.cpp +++ b/test/SystemTests/Game/T6/ExtendAndDereferenceT6.cpp @@ -115,8 +115,6 @@ namespace REQUIRE(material->Asset()->techniqueSet->techniques[T6::TECHNIQUE_UNLIT]); } - // x64 for now produces invalid zones, don't try to load them yet -#ifdef ARCH_x86 TEST_CASE("Extend and dereference(T6)", "[t6][system][simple]") { const auto testDir = oat::paths::GetSystemTestsDirectory() / "Game/T6/ExtendAndDereference"; @@ -126,5 +124,4 @@ namespace BuildCombinedZone(testDir, outputPath); CheckCombinedZoneContent(outputPath); } -#endif } // namespace diff --git a/test/SystemTests/Game/T6/ReuseGlobalAssetPoolsAssetsT6.cpp b/test/SystemTests/Game/T6/ReuseGlobalAssetPoolsAssetsT6.cpp index eb553278..44975b54 100644 --- a/test/SystemTests/Game/T6/ReuseGlobalAssetPoolsAssetsT6.cpp +++ b/test/SystemTests/Game/T6/ReuseGlobalAssetPoolsAssetsT6.cpp @@ -122,8 +122,6 @@ namespace REQUIRE(zone->m_script_strings.Value(xmodel->Asset()->boneNames[2]) == "EarRight2"); } - // x64 for now produces invalid zones, don't try to load them yet -#ifdef ARCH_x86 TEST_CASE("Reuse assets from global asset pool(T6)", "[t6][system][simple]") { const auto testDir = oat::paths::GetSystemTestsDirectory() / "Game/T6/ReuseGlobalAssetPoolsAssets"; @@ -133,5 +131,4 @@ namespace BuildTestZone(testDir, outputPath); CheckTestZoneContent(outputPath); } -#endif } // namespace diff --git a/test/SystemTests/Game/T6/SimpleZoneT6.cpp b/test/SystemTests/Game/T6/SimpleZoneT6.cpp index e2eae4c9..8cb4076f 100644 --- a/test/SystemTests/Game/T6/SimpleZoneT6.cpp +++ b/test/SystemTests/Game/T6/SimpleZoneT6.cpp @@ -46,8 +46,6 @@ namespace REQUIRE(linkerResult); - // x64 for now produces invalid zones, don't try to load them yet -#ifdef ARCH_x86 const auto expectedZonePath = (fs::path(outputPath) / "SimpleZoneT6.ff").string(); auto maybeZone = ZoneLoading::LoadZone(expectedZonePath, std::nullopt); REQUIRE(maybeZone); @@ -60,6 +58,5 @@ namespace REQUIRE(zone->m_name == "SimpleZoneT6"); REQUIRE(pools->GetTotalAssetCount() == 1); REQUIRE(pools->m_raw_file->GetAsset("SimpleZone.txt")); -#endif } } // namespace From 86b7e55e5b0283753d72910f36b4d93fe4c6af36 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Tue, 6 Jan 2026 10:30:16 +0000 Subject: [PATCH 02/20] refactor: add game name to generated load and write files --- src/ZoneCode.lua | 49 ++++++++++----- .../Templates/AssetStructTestsTemplate.cpp | 5 +- .../Generating/Templates/ZoneLoadTemplate.cpp | 55 +++++++++++++++-- .../Generating/Templates/ZoneLoadTemplate.h | 3 + .../Generating/Templates/ZoneMarkTemplate.cpp | 18 +++--- .../Templates/ZoneWriteTemplate.cpp | 59 +++++++++++++++++-- .../Generating/Templates/ZoneWriteTemplate.h | 3 + src/ZoneLoading/Game/IW3/ContentLoaderIW3.cpp | 26 +------- src/ZoneLoading/Game/IW4/ContentLoaderIW4.cpp | 36 +---------- src/ZoneLoading/Game/IW5/ContentLoaderIW5.cpp | 41 +------------ src/ZoneLoading/Game/T5/ContentLoaderT5.cpp | 33 +---------- src/ZoneLoading/Game/T6/ContentLoaderT6.cpp | 49 +-------------- src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp | 26 +------- src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp | 36 +---------- src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp | 41 +------------ src/ZoneWriting/Game/T5/ContentWriterT5.cpp | 33 +---------- src/ZoneWriting/Game/T6/ContentWriterT6.cpp | 49 +-------------- 17 files changed, 168 insertions(+), 394 deletions(-) diff --git a/src/ZoneCode.lua b/src/ZoneCode.lua index 29c9a75d..61f6694f 100644 --- a/src/ZoneCode.lua +++ b/src/ZoneCode.lua @@ -198,16 +198,22 @@ ZoneCode.Assets = { } function ZoneCode:outputForAssets(assetList) + buildoutputs { + "%{wks.location}/src/ZoneCode/Game/%{file.basename}/AssetLoader%{file.basename}.h", + "%{wks.location}/src/ZoneCode/Game/%{file.basename}/AssetMarker%{file.basename}.h", + "%{wks.location}/src/ZoneCode/Game/%{file.basename}/AssetWriter%{file.basename}.h", + } + for i = 1, #assetList do local assetNameLower = string.lower(assetList[i]) buildoutputs { - "%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_load_db.cpp", - "%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_load_db.h", - "%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_mark_db.cpp", - "%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_mark_db.h", - "%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_write_db.cpp", - "%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_write_db.h", - "%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_struct_test.cpp", + "%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_%{string.lower(file.basename)}_load_db.cpp", + "%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_%{string.lower(file.basename)}_load_db.h", + "%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_%{string.lower(file.basename)}_mark_db.cpp", + "%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_%{string.lower(file.basename)}_mark_db.h", + "%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_%{string.lower(file.basename)}_write_db.cpp", + "%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_%{string.lower(file.basename)}_write_db.h", + "%{wks.location}/src/ZoneCode/Game/%{file.basename}/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_%{string.lower(file.basename)}_struct_test.cpp", } end end @@ -216,9 +222,11 @@ function ZoneCode:allTestFiles() result = {} for game, assets in pairs(self.Assets) do + local gameLower = string.lower(game) + for i, assetName in ipairs(assets) do local assetNameLower = string.lower(assetName) - table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_struct_test.cpp") + table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_" .. gameLower .. "_struct_test.cpp") end end @@ -229,12 +237,13 @@ function ZoneCode:allMarkFiles() result = {} for game, assets in pairs(self.Assets) do + local gameLower = string.lower(game) -- PerAsset for i, assetName in ipairs(assets) do local assetNameLower = string.lower(assetName) - table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_mark_db.cpp") - table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_mark_db.h") + table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_" .. gameLower .. "_mark_db.cpp") + table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_" .. gameLower .. "_mark_db.h") end -- PerTemplate @@ -248,11 +257,17 @@ function ZoneCode:allLoadFiles() result = {} for game, assets in pairs(self.Assets) do + local gameLower = string.lower(game) + + -- PerAsset for i, assetName in ipairs(assets) do local assetNameLower = string.lower(assetName) - table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_load_db.cpp") - table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_load_db.h") + table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_" .. gameLower .. "_load_db.cpp") + table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_" .. gameLower .. "_load_db.h") end + + -- PerTemplate + table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/AssetLoader" .. game .. ".h") end return result @@ -262,11 +277,17 @@ function ZoneCode:allWriteFiles() result = {} for game, assets in pairs(self.Assets) do + local gameLower = string.lower(game) + + -- PerAsset for i, assetName in ipairs(assets) do local assetNameLower = string.lower(assetName) - table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_write_db.cpp") - table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_write_db.h") + table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_" .. gameLower .. "_write_db.cpp") + table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/XAssets/" .. assetNameLower .. "/" .. assetNameLower .. "_" .. gameLower .. "_write_db.h") end + + -- PerTemplate + table.insert(result, "%{wks.location}/src/ZoneCode/Game/" .. game .. "/AssetWriter" .. game .. ".h") end return result diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/AssetStructTestsTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/AssetStructTestsTemplate.cpp index f908d324..4cfa9078 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/AssetStructTestsTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/AssetStructTestsTemplate.cpp @@ -87,7 +87,10 @@ std::vector AssetStructTestsTemplate::GetFilesToRenderOncePerA auto assetName = context.m_asset->m_definition->m_name; utils::MakeStringLowerCase(assetName); - files.emplace_back(std::format("XAssets/{0}/{0}_struct_test.cpp", assetName), TAG_SOURCE); + auto gameName = context.m_game; + utils::MakeStringLowerCase(gameName); + + files.emplace_back(std::format("XAssets/{0}/{0}_{1}_struct_test.cpp", assetName, gameName), TAG_SOURCE); return files; } diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp index 9a0f58ba..128d0770 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp @@ -12,6 +12,33 @@ namespace { constexpr int TAG_HEADER = 1; constexpr int TAG_SOURCE = 2; + constexpr int TAG_ALL_LOADERS = 3; + + class PerTemplate final : BaseTemplate + { + public: + PerTemplate(std::ostream& stream, const OncePerTemplateRenderingContext& context) + : BaseTemplate(stream), + m_env(context) + { + } + + void AllLoaders() const + { + AddGeneratedHint(); + + LINE("#pragma once") + LINE("") + + for (const auto* asset : m_env.m_assets) + { + LINEF("#include \"Game/{0}/XAssets/{1}/{1}_{2}_load_db.h\"", m_env.m_game, Lower(asset->m_definition->m_name), Lower(m_env.m_game)) + } + } + + private: + const OncePerTemplateRenderingContext& m_env; + }; class PerAsset final : BaseTemplate { @@ -135,7 +162,7 @@ namespace { AddGeneratedHint(); - LINEF("#include \"{0}_load_db.h\"", Lower(m_env.m_asset->m_definition->m_name)) + LINEF("#include \"{0}_{1}_load_db.h\"", Lower(m_env.m_asset->m_definition->m_name), Lower(m_env.m_game)) LINE("") LINEF("#include \"Game/{0}/AssetMarker{0}.h\"", m_env.m_game) LINE("") @@ -147,7 +174,7 @@ namespace LINE("// Referenced Assets:") for (const auto* type : m_env.m_referenced_assets) { - LINEF("#include \"../{0}/{0}_load_db.h\"", Lower(type->m_type->m_name)) + LINEF("#include \"../{0}/{0}_{1}_load_db.h\"", Lower(type->m_type->m_name), Lower(m_env.m_game)) } } @@ -2192,6 +2219,23 @@ namespace }; } // namespace +std::vector ZoneLoadTemplate::GetFilesToRenderOncePerTemplate(const OncePerTemplateRenderingContext& context) +{ + std::vector files; + + files.emplace_back(std::format("AssetLoader{0}.h", context.m_game), TAG_ALL_LOADERS); + + return files; +} + +void ZoneLoadTemplate::RenderOncePerTemplateFile(std::ostream& stream, const CodeTemplateFileTag fileTag, const OncePerTemplateRenderingContext& context) +{ + assert(fileTag == TAG_ALL_LOADERS); + + const PerTemplate t(stream, context); + t.AllLoaders(); +} + std::vector ZoneLoadTemplate::GetFilesToRenderOncePerAsset(const OncePerAssetRenderingContext& context) { std::vector files; @@ -2199,8 +2243,11 @@ std::vector ZoneLoadTemplate::GetFilesToRenderOncePerAsset(con auto assetName = context.m_asset->m_definition->m_name; utils::MakeStringLowerCase(assetName); - files.emplace_back(std::format("XAssets/{0}/{0}_load_db.h", assetName), TAG_HEADER); - files.emplace_back(std::format("XAssets/{0}/{0}_load_db.cpp", assetName), TAG_SOURCE); + auto gameName = context.m_game; + utils::MakeStringLowerCase(gameName); + + files.emplace_back(std::format("XAssets/{0}/{0}_{1}_load_db.h", assetName, gameName), TAG_HEADER); + files.emplace_back(std::format("XAssets/{0}/{0}_{1}_load_db.cpp", assetName, gameName), TAG_SOURCE); return files; } diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.h b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.h index d269b57c..04787ea8 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.h +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.h @@ -5,6 +5,9 @@ class ZoneLoadTemplate final : public ICodeTemplate { public: + std::vector GetFilesToRenderOncePerTemplate(const OncePerTemplateRenderingContext& context) override; + void RenderOncePerTemplateFile(std::ostream& stream, CodeTemplateFileTag fileTag, const OncePerTemplateRenderingContext& context) override; + std::vector GetFilesToRenderOncePerAsset(const OncePerAssetRenderingContext& context) override; void RenderOncePerAssetFile(std::ostream& stream, CodeTemplateFileTag fileTag, const OncePerAssetRenderingContext& context) override; }; diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp index 4c29fcfc..df1177cb 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp @@ -32,10 +32,7 @@ namespace for (const auto* asset : m_env.m_assets) { - auto lowerAssetName = asset->m_definition->m_name; - utils::MakeStringLowerCase(lowerAssetName); - - LINEF("#include \"Game/{0}/XAssets/{1}/{1}_mark_db.h\"", m_env.m_game, lowerAssetName) + LINEF("#include \"Game/{0}/XAssets/{1}/{1}_{2}_mark_db.h\"", m_env.m_game, Lower(asset->m_definition->m_name), Lower(m_env.m_game)) } } @@ -142,7 +139,7 @@ namespace { AddGeneratedHint(); - LINEF("#include \"{0}_mark_db.h\"", Lower(m_env.m_asset->m_definition->m_name)) + LINEF("#include \"{0}_{1}_mark_db.h\"", Lower(m_env.m_asset->m_definition->m_name), Lower(m_env.m_game)) if (!m_env.m_referenced_assets.empty()) { @@ -150,7 +147,7 @@ namespace LINE("// Referenced Assets:") for (const auto* type : m_env.m_referenced_assets) { - LINEF("#include \"../{0}/{0}_mark_db.h\"", Lower(type->m_type->m_name)) + LINEF("#include \"../{0}/{0}_{1}_mark_db.h\"", Lower(type->m_type->m_name), Lower(m_env.m_game)) } } LINE("") @@ -802,7 +799,7 @@ void ZoneMarkTemplate::RenderOncePerTemplateFile(std::ostream& stream, const Cod { assert(fileTag == TAG_ALL_MARKERS); - PerTemplate t(stream, context); + const PerTemplate t(stream, context); t.AllMarkers(); } @@ -813,8 +810,11 @@ std::vector ZoneMarkTemplate::GetFilesToRenderOncePerAsset(con auto assetName = context.m_asset->m_definition->m_name; utils::MakeStringLowerCase(assetName); - files.emplace_back(std::format("XAssets/{0}/{0}_mark_db.h", assetName), TAG_HEADER); - files.emplace_back(std::format("XAssets/{0}/{0}_mark_db.cpp", assetName), TAG_SOURCE); + auto gameName = context.m_game; + utils::MakeStringLowerCase(gameName); + + files.emplace_back(std::format("XAssets/{0}/{0}_{1}_mark_db.h", assetName, gameName), TAG_HEADER); + files.emplace_back(std::format("XAssets/{0}/{0}_{1}_mark_db.cpp", assetName, gameName), TAG_SOURCE); return files; } diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp index 69b016c8..921a3388 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp @@ -2,6 +2,7 @@ #include "Domain/Computations/StructureComputations.h" #include "Internal/BaseTemplate.h" +#include "Utils/StringUtils.h" #include #include @@ -11,6 +12,33 @@ namespace { constexpr CodeTemplateFileTag TAG_HEADER = 1; constexpr CodeTemplateFileTag TAG_SOURCE = 2; + constexpr CodeTemplateFileTag TAG_ALL_WRITERS = 3; + + class PerTemplate final : BaseTemplate + { + public: + PerTemplate(std::ostream& stream, const OncePerTemplateRenderingContext& context) + : BaseTemplate(stream), + m_env(context) + { + } + + void AllWriters() const + { + AddGeneratedHint(); + + LINE("#pragma once") + LINE("") + + for (const auto* asset : m_env.m_assets) + { + LINEF("#include \"Game/{0}/XAssets/{1}/{1}_{2}_write_db.h\"", m_env.m_game, Lower(asset->m_definition->m_name), Lower(m_env.m_game)) + } + } + + private: + const OncePerTemplateRenderingContext& m_env; + }; class PerAsset final : BaseTemplate { @@ -111,7 +139,7 @@ namespace { AddGeneratedHint(); - LINEF("#include \"{0}_write_db.h\"", Lower(m_env.m_asset->m_definition->m_name)) + LINEF("#include \"{0}_{1}_write_db.h\"", Lower(m_env.m_asset->m_definition->m_name), Lower(m_env.m_game)) if (!m_env.m_referenced_assets.empty()) { @@ -119,7 +147,7 @@ namespace LINE("// Referenced Assets:") for (const auto* type : m_env.m_referenced_assets) { - LINEF("#include \"../{0}/{0}_write_db.h\"", Lower(type->m_type->m_name)) + LINEF("#include \"../{0}/{0}_{1}_write_db.h\"", Lower(type->m_type->m_name), Lower(m_env.m_game)) } } @@ -1228,16 +1256,35 @@ namespace }; } // namespace +std::vector ZoneWriteTemplate::GetFilesToRenderOncePerTemplate(const OncePerTemplateRenderingContext& context) +{ + std::vector files; + + files.emplace_back(std::format("AssetWriter{0}.h", context.m_game), TAG_ALL_WRITERS); + + return files; +} + +void ZoneWriteTemplate::RenderOncePerTemplateFile(std::ostream& stream, const CodeTemplateFileTag fileTag, const OncePerTemplateRenderingContext& context) +{ + assert(fileTag == TAG_ALL_WRITERS); + + const PerTemplate t(stream, context); + t.AllWriters(); +} + std::vector ZoneWriteTemplate::GetFilesToRenderOncePerAsset(const OncePerAssetRenderingContext& context) { std::vector files; auto assetName = context.m_asset->m_definition->m_name; - for (auto& c : assetName) - c = static_cast(tolower(c)); + utils::MakeStringLowerCase(assetName); - files.emplace_back(std::format("XAssets/{0}/{0}_write_db.h", assetName), TAG_HEADER); - files.emplace_back(std::format("XAssets/{0}/{0}_write_db.cpp", assetName), TAG_SOURCE); + auto gameName = context.m_game; + utils::MakeStringLowerCase(gameName); + + files.emplace_back(std::format("XAssets/{0}/{0}_{1}_write_db.h", assetName, gameName), TAG_HEADER); + files.emplace_back(std::format("XAssets/{0}/{0}_{1}_write_db.cpp", assetName, gameName), TAG_SOURCE); return files; } diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.h b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.h index 84b1bfd4..ab6220cd 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.h +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.h @@ -5,6 +5,9 @@ class ZoneWriteTemplate final : public ICodeTemplate { public: + std::vector GetFilesToRenderOncePerTemplate(const OncePerTemplateRenderingContext& context) override; + void RenderOncePerTemplateFile(std::ostream& stream, CodeTemplateFileTag fileTag, const OncePerTemplateRenderingContext& context) override; + std::vector GetFilesToRenderOncePerAsset(const OncePerAssetRenderingContext& context) override; void RenderOncePerAssetFile(std::ostream& stream, CodeTemplateFileTag fileTag, const OncePerAssetRenderingContext& context) override; }; diff --git a/src/ZoneLoading/Game/IW3/ContentLoaderIW3.cpp b/src/ZoneLoading/Game/IW3/ContentLoaderIW3.cpp index 169efdf6..eadf6c3c 100644 --- a/src/ZoneLoading/Game/IW3/ContentLoaderIW3.cpp +++ b/src/ZoneLoading/Game/IW3/ContentLoaderIW3.cpp @@ -1,31 +1,7 @@ #include "ContentLoaderIW3.h" +#include "Game/IW3/AssetLoaderIW3.h" #include "Game/IW3/IW3.h" -#include "Game/IW3/XAssets/clipmap_t/clipmap_t_load_db.h" -#include "Game/IW3/XAssets/comworld/comworld_load_db.h" -#include "Game/IW3/XAssets/font_s/font_s_load_db.h" -#include "Game/IW3/XAssets/fxeffectdef/fxeffectdef_load_db.h" -#include "Game/IW3/XAssets/fximpacttable/fximpacttable_load_db.h" -#include "Game/IW3/XAssets/gameworldmp/gameworldmp_load_db.h" -#include "Game/IW3/XAssets/gameworldsp/gameworldsp_load_db.h" -#include "Game/IW3/XAssets/gfximage/gfximage_load_db.h" -#include "Game/IW3/XAssets/gfxlightdef/gfxlightdef_load_db.h" -#include "Game/IW3/XAssets/gfxworld/gfxworld_load_db.h" -#include "Game/IW3/XAssets/loadedsound/loadedsound_load_db.h" -#include "Game/IW3/XAssets/localizeentry/localizeentry_load_db.h" -#include "Game/IW3/XAssets/mapents/mapents_load_db.h" -#include "Game/IW3/XAssets/material/material_load_db.h" -#include "Game/IW3/XAssets/materialtechniqueset/materialtechniqueset_load_db.h" -#include "Game/IW3/XAssets/menudef_t/menudef_t_load_db.h" -#include "Game/IW3/XAssets/menulist/menulist_load_db.h" -#include "Game/IW3/XAssets/physpreset/physpreset_load_db.h" -#include "Game/IW3/XAssets/rawfile/rawfile_load_db.h" -#include "Game/IW3/XAssets/snd_alias_list_t/snd_alias_list_t_load_db.h" -#include "Game/IW3/XAssets/sndcurve/sndcurve_load_db.h" -#include "Game/IW3/XAssets/stringtable/stringtable_load_db.h" -#include "Game/IW3/XAssets/weapondef/weapondef_load_db.h" -#include "Game/IW3/XAssets/xanimparts/xanimparts_load_db.h" -#include "Game/IW3/XAssets/xmodel/xmodel_load_db.h" #include "Loading/Exception/UnsupportedAssetTypeException.h" #include diff --git a/src/ZoneLoading/Game/IW4/ContentLoaderIW4.cpp b/src/ZoneLoading/Game/IW4/ContentLoaderIW4.cpp index 50650731..6f041a62 100644 --- a/src/ZoneLoading/Game/IW4/ContentLoaderIW4.cpp +++ b/src/ZoneLoading/Game/IW4/ContentLoaderIW4.cpp @@ -1,41 +1,7 @@ #include "ContentLoaderIW4.h" +#include "Game/IW4/AssetLoaderIW4.h" #include "Game/IW4/IW4.h" -#include "Game/IW4/XAssets/addonmapents/addonmapents_load_db.h" -#include "Game/IW4/XAssets/clipmap_t/clipmap_t_load_db.h" -#include "Game/IW4/XAssets/comworld/comworld_load_db.h" -#include "Game/IW4/XAssets/font_s/font_s_load_db.h" -#include "Game/IW4/XAssets/fxeffectdef/fxeffectdef_load_db.h" -#include "Game/IW4/XAssets/fximpacttable/fximpacttable_load_db.h" -#include "Game/IW4/XAssets/fxworld/fxworld_load_db.h" -#include "Game/IW4/XAssets/gameworldmp/gameworldmp_load_db.h" -#include "Game/IW4/XAssets/gameworldsp/gameworldsp_load_db.h" -#include "Game/IW4/XAssets/gfximage/gfximage_load_db.h" -#include "Game/IW4/XAssets/gfxlightdef/gfxlightdef_load_db.h" -#include "Game/IW4/XAssets/gfxworld/gfxworld_load_db.h" -#include "Game/IW4/XAssets/leaderboarddef/leaderboarddef_load_db.h" -#include "Game/IW4/XAssets/loadedsound/loadedsound_load_db.h" -#include "Game/IW4/XAssets/localizeentry/localizeentry_load_db.h" -#include "Game/IW4/XAssets/mapents/mapents_load_db.h" -#include "Game/IW4/XAssets/material/material_load_db.h" -#include "Game/IW4/XAssets/materialpixelshader/materialpixelshader_load_db.h" -#include "Game/IW4/XAssets/materialtechniqueset/materialtechniqueset_load_db.h" -#include "Game/IW4/XAssets/materialvertexdeclaration/materialvertexdeclaration_load_db.h" -#include "Game/IW4/XAssets/materialvertexshader/materialvertexshader_load_db.h" -#include "Game/IW4/XAssets/menudef_t/menudef_t_load_db.h" -#include "Game/IW4/XAssets/menulist/menulist_load_db.h" -#include "Game/IW4/XAssets/physcollmap/physcollmap_load_db.h" -#include "Game/IW4/XAssets/physpreset/physpreset_load_db.h" -#include "Game/IW4/XAssets/rawfile/rawfile_load_db.h" -#include "Game/IW4/XAssets/snd_alias_list_t/snd_alias_list_t_load_db.h" -#include "Game/IW4/XAssets/sndcurve/sndcurve_load_db.h" -#include "Game/IW4/XAssets/stringtable/stringtable_load_db.h" -#include "Game/IW4/XAssets/structureddatadefset/structureddatadefset_load_db.h" -#include "Game/IW4/XAssets/tracerdef/tracerdef_load_db.h" -#include "Game/IW4/XAssets/vehicledef/vehicledef_load_db.h" -#include "Game/IW4/XAssets/weaponcompletedef/weaponcompletedef_load_db.h" -#include "Game/IW4/XAssets/xanimparts/xanimparts_load_db.h" -#include "Game/IW4/XAssets/xmodel/xmodel_load_db.h" #include "Loading/Exception/UnsupportedAssetTypeException.h" #include diff --git a/src/ZoneLoading/Game/IW5/ContentLoaderIW5.cpp b/src/ZoneLoading/Game/IW5/ContentLoaderIW5.cpp index ada66414..b36e2df5 100644 --- a/src/ZoneLoading/Game/IW5/ContentLoaderIW5.cpp +++ b/src/ZoneLoading/Game/IW5/ContentLoaderIW5.cpp @@ -1,46 +1,7 @@ #include "ContentLoaderIW5.h" +#include "Game/IW5/AssetLoaderIW5.h" #include "Game/IW5/IW5.h" -#include "Game/IW5/XAssets/addonmapents/addonmapents_load_db.h" -#include "Game/IW5/XAssets/clipmap_t/clipmap_t_load_db.h" -#include "Game/IW5/XAssets/comworld/comworld_load_db.h" -#include "Game/IW5/XAssets/font_s/font_s_load_db.h" -#include "Game/IW5/XAssets/fxeffectdef/fxeffectdef_load_db.h" -#include "Game/IW5/XAssets/fximpacttable/fximpacttable_load_db.h" -#include "Game/IW5/XAssets/fxworld/fxworld_load_db.h" -#include "Game/IW5/XAssets/gfximage/gfximage_load_db.h" -#include "Game/IW5/XAssets/gfxlightdef/gfxlightdef_load_db.h" -#include "Game/IW5/XAssets/gfxworld/gfxworld_load_db.h" -#include "Game/IW5/XAssets/glassworld/glassworld_load_db.h" -#include "Game/IW5/XAssets/leaderboarddef/leaderboarddef_load_db.h" -#include "Game/IW5/XAssets/loadedsound/loadedsound_load_db.h" -#include "Game/IW5/XAssets/localizeentry/localizeentry_load_db.h" -#include "Game/IW5/XAssets/mapents/mapents_load_db.h" -#include "Game/IW5/XAssets/material/material_load_db.h" -#include "Game/IW5/XAssets/materialpixelshader/materialpixelshader_load_db.h" -#include "Game/IW5/XAssets/materialtechniqueset/materialtechniqueset_load_db.h" -#include "Game/IW5/XAssets/materialvertexdeclaration/materialvertexdeclaration_load_db.h" -#include "Game/IW5/XAssets/materialvertexshader/materialvertexshader_load_db.h" -#include "Game/IW5/XAssets/menudef_t/menudef_t_load_db.h" -#include "Game/IW5/XAssets/menulist/menulist_load_db.h" -#include "Game/IW5/XAssets/pathdata/pathdata_load_db.h" -#include "Game/IW5/XAssets/physcollmap/physcollmap_load_db.h" -#include "Game/IW5/XAssets/physpreset/physpreset_load_db.h" -#include "Game/IW5/XAssets/rawfile/rawfile_load_db.h" -#include "Game/IW5/XAssets/scriptfile/scriptfile_load_db.h" -#include "Game/IW5/XAssets/snd_alias_list_t/snd_alias_list_t_load_db.h" -#include "Game/IW5/XAssets/sndcurve/sndcurve_load_db.h" -#include "Game/IW5/XAssets/stringtable/stringtable_load_db.h" -#include "Game/IW5/XAssets/structureddatadefset/structureddatadefset_load_db.h" -#include "Game/IW5/XAssets/surfacefxtable/surfacefxtable_load_db.h" -#include "Game/IW5/XAssets/tracerdef/tracerdef_load_db.h" -#include "Game/IW5/XAssets/vehicledef/vehicledef_load_db.h" -#include "Game/IW5/XAssets/vehicletrack/vehicletrack_load_db.h" -#include "Game/IW5/XAssets/weaponattachment/weaponattachment_load_db.h" -#include "Game/IW5/XAssets/weaponcompletedef/weaponcompletedef_load_db.h" -#include "Game/IW5/XAssets/xanimparts/xanimparts_load_db.h" -#include "Game/IW5/XAssets/xmodel/xmodel_load_db.h" -#include "Game/IW5/XAssets/xmodelsurfs/xmodelsurfs_load_db.h" #include "Loading/Exception/UnsupportedAssetTypeException.h" #include diff --git a/src/ZoneLoading/Game/T5/ContentLoaderT5.cpp b/src/ZoneLoading/Game/T5/ContentLoaderT5.cpp index d8549be4..2959c432 100644 --- a/src/ZoneLoading/Game/T5/ContentLoaderT5.cpp +++ b/src/ZoneLoading/Game/T5/ContentLoaderT5.cpp @@ -1,38 +1,7 @@ #include "ContentLoaderT5.h" +#include "Game/T5/AssetLoaderT5.h" #include "Game/T5/T5.h" -#include "Game/T5/XAssets/clipmap_t/clipmap_t_load_db.h" -#include "Game/T5/XAssets/comworld/comworld_load_db.h" -#include "Game/T5/XAssets/ddlroot_t/ddlroot_t_load_db.h" -#include "Game/T5/XAssets/destructibledef/destructibledef_load_db.h" -#include "Game/T5/XAssets/emblemset/emblemset_load_db.h" -#include "Game/T5/XAssets/font_s/font_s_load_db.h" -#include "Game/T5/XAssets/fxeffectdef/fxeffectdef_load_db.h" -#include "Game/T5/XAssets/fximpacttable/fximpacttable_load_db.h" -#include "Game/T5/XAssets/gameworldmp/gameworldmp_load_db.h" -#include "Game/T5/XAssets/gameworldsp/gameworldsp_load_db.h" -#include "Game/T5/XAssets/gfximage/gfximage_load_db.h" -#include "Game/T5/XAssets/gfxlightdef/gfxlightdef_load_db.h" -#include "Game/T5/XAssets/gfxworld/gfxworld_load_db.h" -#include "Game/T5/XAssets/glasses/glasses_load_db.h" -#include "Game/T5/XAssets/localizeentry/localizeentry_load_db.h" -#include "Game/T5/XAssets/mapents/mapents_load_db.h" -#include "Game/T5/XAssets/material/material_load_db.h" -#include "Game/T5/XAssets/materialtechniqueset/materialtechniqueset_load_db.h" -#include "Game/T5/XAssets/menudef_t/menudef_t_load_db.h" -#include "Game/T5/XAssets/menulist/menulist_load_db.h" -#include "Game/T5/XAssets/packindex/packindex_load_db.h" -#include "Game/T5/XAssets/physconstraints/physconstraints_load_db.h" -#include "Game/T5/XAssets/physpreset/physpreset_load_db.h" -#include "Game/T5/XAssets/rawfile/rawfile_load_db.h" -#include "Game/T5/XAssets/sndbank/sndbank_load_db.h" -#include "Game/T5/XAssets/snddriverglobals/snddriverglobals_load_db.h" -#include "Game/T5/XAssets/sndpatch/sndpatch_load_db.h" -#include "Game/T5/XAssets/stringtable/stringtable_load_db.h" -#include "Game/T5/XAssets/weaponvariantdef/weaponvariantdef_load_db.h" -#include "Game/T5/XAssets/xanimparts/xanimparts_load_db.h" -#include "Game/T5/XAssets/xglobals/xglobals_load_db.h" -#include "Game/T5/XAssets/xmodel/xmodel_load_db.h" #include "Loading/Exception/UnsupportedAssetTypeException.h" #include diff --git a/src/ZoneLoading/Game/T6/ContentLoaderT6.cpp b/src/ZoneLoading/Game/T6/ContentLoaderT6.cpp index 9c6dce81..86cb2bd7 100644 --- a/src/ZoneLoading/Game/T6/ContentLoaderT6.cpp +++ b/src/ZoneLoading/Game/T6/ContentLoaderT6.cpp @@ -1,54 +1,7 @@ #include "ContentLoaderT6.h" +#include "Game/T6/AssetLoaderT6.h" #include "Game/T6/T6.h" -#include "Game/T6/XAssets/addonmapents/addonmapents_load_db.h" -#include "Game/T6/XAssets/clipmap_t/clipmap_t_load_db.h" -#include "Game/T6/XAssets/comworld/comworld_load_db.h" -#include "Game/T6/XAssets/ddlroot_t/ddlroot_t_load_db.h" -#include "Game/T6/XAssets/destructibledef/destructibledef_load_db.h" -#include "Game/T6/XAssets/emblemset/emblemset_load_db.h" -#include "Game/T6/XAssets/font_s/font_s_load_db.h" -#include "Game/T6/XAssets/fonticon/fonticon_load_db.h" -#include "Game/T6/XAssets/footstepfxtabledef/footstepfxtabledef_load_db.h" -#include "Game/T6/XAssets/footsteptabledef/footsteptabledef_load_db.h" -#include "Game/T6/XAssets/fxeffectdef/fxeffectdef_load_db.h" -#include "Game/T6/XAssets/fximpacttable/fximpacttable_load_db.h" -#include "Game/T6/XAssets/gameworldmp/gameworldmp_load_db.h" -#include "Game/T6/XAssets/gameworldsp/gameworldsp_load_db.h" -#include "Game/T6/XAssets/gfximage/gfximage_load_db.h" -#include "Game/T6/XAssets/gfxlightdef/gfxlightdef_load_db.h" -#include "Game/T6/XAssets/gfxworld/gfxworld_load_db.h" -#include "Game/T6/XAssets/glasses/glasses_load_db.h" -#include "Game/T6/XAssets/keyvaluepairs/keyvaluepairs_load_db.h" -#include "Game/T6/XAssets/leaderboarddef/leaderboarddef_load_db.h" -#include "Game/T6/XAssets/localizeentry/localizeentry_load_db.h" -#include "Game/T6/XAssets/mapents/mapents_load_db.h" -#include "Game/T6/XAssets/material/material_load_db.h" -#include "Game/T6/XAssets/materialtechniqueset/materialtechniqueset_load_db.h" -#include "Game/T6/XAssets/memoryblock/memoryblock_load_db.h" -#include "Game/T6/XAssets/menudef_t/menudef_t_load_db.h" -#include "Game/T6/XAssets/menulist/menulist_load_db.h" -#include "Game/T6/XAssets/physconstraints/physconstraints_load_db.h" -#include "Game/T6/XAssets/physpreset/physpreset_load_db.h" -#include "Game/T6/XAssets/qdb/qdb_load_db.h" -#include "Game/T6/XAssets/rawfile/rawfile_load_db.h" -#include "Game/T6/XAssets/scriptparsetree/scriptparsetree_load_db.h" -#include "Game/T6/XAssets/skinnedvertsdef/skinnedvertsdef_load_db.h" -#include "Game/T6/XAssets/slug/slug_load_db.h" -#include "Game/T6/XAssets/sndbank/sndbank_load_db.h" -#include "Game/T6/XAssets/snddriverglobals/snddriverglobals_load_db.h" -#include "Game/T6/XAssets/sndpatch/sndpatch_load_db.h" -#include "Game/T6/XAssets/stringtable/stringtable_load_db.h" -#include "Game/T6/XAssets/tracerdef/tracerdef_load_db.h" -#include "Game/T6/XAssets/vehicledef/vehicledef_load_db.h" -#include "Game/T6/XAssets/weaponattachment/weaponattachment_load_db.h" -#include "Game/T6/XAssets/weaponattachmentunique/weaponattachmentunique_load_db.h" -#include "Game/T6/XAssets/weaponcamo/weaponcamo_load_db.h" -#include "Game/T6/XAssets/weaponvariantdef/weaponvariantdef_load_db.h" -#include "Game/T6/XAssets/xanimparts/xanimparts_load_db.h" -#include "Game/T6/XAssets/xglobals/xglobals_load_db.h" -#include "Game/T6/XAssets/xmodel/xmodel_load_db.h" -#include "Game/T6/XAssets/zbarrierdef/zbarrierdef_load_db.h" #include "Loading/Exception/UnsupportedAssetTypeException.h" #include diff --git a/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp b/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp index 04765117..9e07914c 100644 --- a/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp +++ b/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp @@ -1,30 +1,6 @@ #include "ContentWriterIW3.h" -#include "Game/IW3/XAssets/clipmap_t/clipmap_t_write_db.h" -#include "Game/IW3/XAssets/comworld/comworld_write_db.h" -#include "Game/IW3/XAssets/font_s/font_s_write_db.h" -#include "Game/IW3/XAssets/fxeffectdef/fxeffectdef_write_db.h" -#include "Game/IW3/XAssets/fximpacttable/fximpacttable_write_db.h" -#include "Game/IW3/XAssets/gameworldmp/gameworldmp_write_db.h" -#include "Game/IW3/XAssets/gameworldsp/gameworldsp_write_db.h" -#include "Game/IW3/XAssets/gfximage/gfximage_write_db.h" -#include "Game/IW3/XAssets/gfxlightdef/gfxlightdef_write_db.h" -#include "Game/IW3/XAssets/gfxworld/gfxworld_write_db.h" -#include "Game/IW3/XAssets/loadedsound/loadedsound_write_db.h" -#include "Game/IW3/XAssets/localizeentry/localizeentry_write_db.h" -#include "Game/IW3/XAssets/mapents/mapents_write_db.h" -#include "Game/IW3/XAssets/material/material_write_db.h" -#include "Game/IW3/XAssets/materialtechniqueset/materialtechniqueset_write_db.h" -#include "Game/IW3/XAssets/menudef_t/menudef_t_write_db.h" -#include "Game/IW3/XAssets/menulist/menulist_write_db.h" -#include "Game/IW3/XAssets/physpreset/physpreset_write_db.h" -#include "Game/IW3/XAssets/rawfile/rawfile_write_db.h" -#include "Game/IW3/XAssets/snd_alias_list_t/snd_alias_list_t_write_db.h" -#include "Game/IW3/XAssets/sndcurve/sndcurve_write_db.h" -#include "Game/IW3/XAssets/stringtable/stringtable_write_db.h" -#include "Game/IW3/XAssets/weapondef/weapondef_write_db.h" -#include "Game/IW3/XAssets/xanimparts/xanimparts_write_db.h" -#include "Game/IW3/XAssets/xmodel/xmodel_write_db.h" +#include "Game/IW3/AssetWriterIW3.h" #include "Writing/WritingException.h" #include diff --git a/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp b/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp index 26cf1935..0d3e0d06 100644 --- a/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp +++ b/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp @@ -1,40 +1,6 @@ #include "ContentWriterIW4.h" -#include "Game/IW4/XAssets/addonmapents/addonmapents_write_db.h" -#include "Game/IW4/XAssets/clipmap_t/clipmap_t_write_db.h" -#include "Game/IW4/XAssets/comworld/comworld_write_db.h" -#include "Game/IW4/XAssets/font_s/font_s_write_db.h" -#include "Game/IW4/XAssets/fxeffectdef/fxeffectdef_write_db.h" -#include "Game/IW4/XAssets/fximpacttable/fximpacttable_write_db.h" -#include "Game/IW4/XAssets/fxworld/fxworld_write_db.h" -#include "Game/IW4/XAssets/gameworldmp/gameworldmp_write_db.h" -#include "Game/IW4/XAssets/gameworldsp/gameworldsp_write_db.h" -#include "Game/IW4/XAssets/gfximage/gfximage_write_db.h" -#include "Game/IW4/XAssets/gfxlightdef/gfxlightdef_write_db.h" -#include "Game/IW4/XAssets/gfxworld/gfxworld_write_db.h" -#include "Game/IW4/XAssets/leaderboarddef/leaderboarddef_write_db.h" -#include "Game/IW4/XAssets/loadedsound/loadedsound_write_db.h" -#include "Game/IW4/XAssets/localizeentry/localizeentry_write_db.h" -#include "Game/IW4/XAssets/mapents/mapents_write_db.h" -#include "Game/IW4/XAssets/material/material_write_db.h" -#include "Game/IW4/XAssets/materialpixelshader/materialpixelshader_write_db.h" -#include "Game/IW4/XAssets/materialtechniqueset/materialtechniqueset_write_db.h" -#include "Game/IW4/XAssets/materialvertexdeclaration/materialvertexdeclaration_write_db.h" -#include "Game/IW4/XAssets/materialvertexshader/materialvertexshader_write_db.h" -#include "Game/IW4/XAssets/menudef_t/menudef_t_write_db.h" -#include "Game/IW4/XAssets/menulist/menulist_write_db.h" -#include "Game/IW4/XAssets/physcollmap/physcollmap_write_db.h" -#include "Game/IW4/XAssets/physpreset/physpreset_write_db.h" -#include "Game/IW4/XAssets/rawfile/rawfile_write_db.h" -#include "Game/IW4/XAssets/snd_alias_list_t/snd_alias_list_t_write_db.h" -#include "Game/IW4/XAssets/sndcurve/sndcurve_write_db.h" -#include "Game/IW4/XAssets/stringtable/stringtable_write_db.h" -#include "Game/IW4/XAssets/structureddatadefset/structureddatadefset_write_db.h" -#include "Game/IW4/XAssets/tracerdef/tracerdef_write_db.h" -#include "Game/IW4/XAssets/vehicledef/vehicledef_write_db.h" -#include "Game/IW4/XAssets/weaponcompletedef/weaponcompletedef_write_db.h" -#include "Game/IW4/XAssets/xanimparts/xanimparts_write_db.h" -#include "Game/IW4/XAssets/xmodel/xmodel_write_db.h" +#include "Game/IW4/AssetWriterIW4.h" #include "Writing/WritingException.h" #include diff --git a/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp b/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp index 266d8cfb..ee0af8d3 100644 --- a/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp +++ b/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp @@ -1,45 +1,6 @@ #include "ContentWriterIW5.h" -#include "Game/IW5/XAssets/addonmapents/addonmapents_write_db.h" -#include "Game/IW5/XAssets/clipmap_t/clipmap_t_write_db.h" -#include "Game/IW5/XAssets/comworld/comworld_write_db.h" -#include "Game/IW5/XAssets/font_s/font_s_write_db.h" -#include "Game/IW5/XAssets/fxeffectdef/fxeffectdef_write_db.h" -#include "Game/IW5/XAssets/fximpacttable/fximpacttable_write_db.h" -#include "Game/IW5/XAssets/fxworld/fxworld_write_db.h" -#include "Game/IW5/XAssets/gfximage/gfximage_write_db.h" -#include "Game/IW5/XAssets/gfxlightdef/gfxlightdef_write_db.h" -#include "Game/IW5/XAssets/gfxworld/gfxworld_write_db.h" -#include "Game/IW5/XAssets/glassworld/glassworld_write_db.h" -#include "Game/IW5/XAssets/leaderboarddef/leaderboarddef_write_db.h" -#include "Game/IW5/XAssets/loadedsound/loadedsound_write_db.h" -#include "Game/IW5/XAssets/localizeentry/localizeentry_write_db.h" -#include "Game/IW5/XAssets/mapents/mapents_write_db.h" -#include "Game/IW5/XAssets/material/material_write_db.h" -#include "Game/IW5/XAssets/materialpixelshader/materialpixelshader_write_db.h" -#include "Game/IW5/XAssets/materialtechniqueset/materialtechniqueset_write_db.h" -#include "Game/IW5/XAssets/materialvertexdeclaration/materialvertexdeclaration_write_db.h" -#include "Game/IW5/XAssets/materialvertexshader/materialvertexshader_write_db.h" -#include "Game/IW5/XAssets/menudef_t/menudef_t_write_db.h" -#include "Game/IW5/XAssets/menulist/menulist_write_db.h" -#include "Game/IW5/XAssets/pathdata/pathdata_write_db.h" -#include "Game/IW5/XAssets/physcollmap/physcollmap_write_db.h" -#include "Game/IW5/XAssets/physpreset/physpreset_write_db.h" -#include "Game/IW5/XAssets/rawfile/rawfile_write_db.h" -#include "Game/IW5/XAssets/scriptfile/scriptfile_write_db.h" -#include "Game/IW5/XAssets/snd_alias_list_t/snd_alias_list_t_write_db.h" -#include "Game/IW5/XAssets/sndcurve/sndcurve_write_db.h" -#include "Game/IW5/XAssets/stringtable/stringtable_write_db.h" -#include "Game/IW5/XAssets/structureddatadefset/structureddatadefset_write_db.h" -#include "Game/IW5/XAssets/surfacefxtable/surfacefxtable_write_db.h" -#include "Game/IW5/XAssets/tracerdef/tracerdef_write_db.h" -#include "Game/IW5/XAssets/vehicledef/vehicledef_write_db.h" -#include "Game/IW5/XAssets/vehicletrack/vehicletrack_write_db.h" -#include "Game/IW5/XAssets/weaponattachment/weaponattachment_write_db.h" -#include "Game/IW5/XAssets/weaponcompletedef/weaponcompletedef_write_db.h" -#include "Game/IW5/XAssets/xanimparts/xanimparts_write_db.h" -#include "Game/IW5/XAssets/xmodel/xmodel_write_db.h" -#include "Game/IW5/XAssets/xmodelsurfs/xmodelsurfs_write_db.h" +#include "Game/IW5/AssetWriterIW5.h" #include "Writing/WritingException.h" #include diff --git a/src/ZoneWriting/Game/T5/ContentWriterT5.cpp b/src/ZoneWriting/Game/T5/ContentWriterT5.cpp index 08efc2ee..e57067d5 100644 --- a/src/ZoneWriting/Game/T5/ContentWriterT5.cpp +++ b/src/ZoneWriting/Game/T5/ContentWriterT5.cpp @@ -1,37 +1,6 @@ #include "ContentWriterT5.h" -#include "Game/T5/XAssets/clipmap_t/clipmap_t_write_db.h" -#include "Game/T5/XAssets/comworld/comworld_write_db.h" -#include "Game/T5/XAssets/ddlroot_t/ddlroot_t_write_db.h" -#include "Game/T5/XAssets/destructibledef/destructibledef_write_db.h" -#include "Game/T5/XAssets/emblemset/emblemset_write_db.h" -#include "Game/T5/XAssets/font_s/font_s_write_db.h" -#include "Game/T5/XAssets/fxeffectdef/fxeffectdef_write_db.h" -#include "Game/T5/XAssets/fximpacttable/fximpacttable_write_db.h" -#include "Game/T5/XAssets/gameworldmp/gameworldmp_write_db.h" -#include "Game/T5/XAssets/gameworldsp/gameworldsp_write_db.h" -#include "Game/T5/XAssets/gfximage/gfximage_write_db.h" -#include "Game/T5/XAssets/gfxlightdef/gfxlightdef_write_db.h" -#include "Game/T5/XAssets/gfxworld/gfxworld_write_db.h" -#include "Game/T5/XAssets/glasses/glasses_write_db.h" -#include "Game/T5/XAssets/localizeentry/localizeentry_write_db.h" -#include "Game/T5/XAssets/mapents/mapents_write_db.h" -#include "Game/T5/XAssets/material/material_write_db.h" -#include "Game/T5/XAssets/materialtechniqueset/materialtechniqueset_write_db.h" -#include "Game/T5/XAssets/menudef_t/menudef_t_write_db.h" -#include "Game/T5/XAssets/menulist/menulist_write_db.h" -#include "Game/T5/XAssets/packindex/packindex_write_db.h" -#include "Game/T5/XAssets/physconstraints/physconstraints_write_db.h" -#include "Game/T5/XAssets/physpreset/physpreset_write_db.h" -#include "Game/T5/XAssets/rawfile/rawfile_write_db.h" -#include "Game/T5/XAssets/sndbank/sndbank_write_db.h" -#include "Game/T5/XAssets/snddriverglobals/snddriverglobals_write_db.h" -#include "Game/T5/XAssets/sndpatch/sndpatch_write_db.h" -#include "Game/T5/XAssets/stringtable/stringtable_write_db.h" -#include "Game/T5/XAssets/weaponvariantdef/weaponvariantdef_write_db.h" -#include "Game/T5/XAssets/xanimparts/xanimparts_write_db.h" -#include "Game/T5/XAssets/xglobals/xglobals_write_db.h" -#include "Game/T5/XAssets/xmodel/xmodel_write_db.h" +#include "Game/T5/AssetWriterT5.h" #include "Writing/WritingException.h" #include diff --git a/src/ZoneWriting/Game/T6/ContentWriterT6.cpp b/src/ZoneWriting/Game/T6/ContentWriterT6.cpp index 95c4eb04..d929bfa5 100644 --- a/src/ZoneWriting/Game/T6/ContentWriterT6.cpp +++ b/src/ZoneWriting/Game/T6/ContentWriterT6.cpp @@ -1,53 +1,6 @@ #include "ContentWriterT6.h" -#include "Game/T6/XAssets/addonmapents/addonmapents_write_db.h" -#include "Game/T6/XAssets/clipmap_t/clipmap_t_write_db.h" -#include "Game/T6/XAssets/comworld/comworld_write_db.h" -#include "Game/T6/XAssets/ddlroot_t/ddlroot_t_write_db.h" -#include "Game/T6/XAssets/destructibledef/destructibledef_write_db.h" -#include "Game/T6/XAssets/emblemset/emblemset_write_db.h" -#include "Game/T6/XAssets/font_s/font_s_write_db.h" -#include "Game/T6/XAssets/fonticon/fonticon_write_db.h" -#include "Game/T6/XAssets/footstepfxtabledef/footstepfxtabledef_write_db.h" -#include "Game/T6/XAssets/footsteptabledef/footsteptabledef_write_db.h" -#include "Game/T6/XAssets/fxeffectdef/fxeffectdef_write_db.h" -#include "Game/T6/XAssets/fximpacttable/fximpacttable_write_db.h" -#include "Game/T6/XAssets/gameworldmp/gameworldmp_write_db.h" -#include "Game/T6/XAssets/gameworldsp/gameworldsp_write_db.h" -#include "Game/T6/XAssets/gfximage/gfximage_write_db.h" -#include "Game/T6/XAssets/gfxlightdef/gfxlightdef_write_db.h" -#include "Game/T6/XAssets/gfxworld/gfxworld_write_db.h" -#include "Game/T6/XAssets/glasses/glasses_write_db.h" -#include "Game/T6/XAssets/keyvaluepairs/keyvaluepairs_write_db.h" -#include "Game/T6/XAssets/leaderboarddef/leaderboarddef_write_db.h" -#include "Game/T6/XAssets/localizeentry/localizeentry_write_db.h" -#include "Game/T6/XAssets/mapents/mapents_write_db.h" -#include "Game/T6/XAssets/material/material_write_db.h" -#include "Game/T6/XAssets/materialtechniqueset/materialtechniqueset_write_db.h" -#include "Game/T6/XAssets/memoryblock/memoryblock_write_db.h" -#include "Game/T6/XAssets/menudef_t/menudef_t_write_db.h" -#include "Game/T6/XAssets/menulist/menulist_write_db.h" -#include "Game/T6/XAssets/physconstraints/physconstraints_write_db.h" -#include "Game/T6/XAssets/physpreset/physpreset_write_db.h" -#include "Game/T6/XAssets/qdb/qdb_write_db.h" -#include "Game/T6/XAssets/rawfile/rawfile_write_db.h" -#include "Game/T6/XAssets/scriptparsetree/scriptparsetree_write_db.h" -#include "Game/T6/XAssets/skinnedvertsdef/skinnedvertsdef_write_db.h" -#include "Game/T6/XAssets/slug/slug_write_db.h" -#include "Game/T6/XAssets/sndbank/sndbank_write_db.h" -#include "Game/T6/XAssets/snddriverglobals/snddriverglobals_write_db.h" -#include "Game/T6/XAssets/sndpatch/sndpatch_write_db.h" -#include "Game/T6/XAssets/stringtable/stringtable_write_db.h" -#include "Game/T6/XAssets/tracerdef/tracerdef_write_db.h" -#include "Game/T6/XAssets/vehicledef/vehicledef_write_db.h" -#include "Game/T6/XAssets/weaponattachment/weaponattachment_write_db.h" -#include "Game/T6/XAssets/weaponattachmentunique/weaponattachmentunique_write_db.h" -#include "Game/T6/XAssets/weaponcamo/weaponcamo_write_db.h" -#include "Game/T6/XAssets/weaponvariantdef/weaponvariantdef_write_db.h" -#include "Game/T6/XAssets/xanimparts/xanimparts_write_db.h" -#include "Game/T6/XAssets/xglobals/xglobals_write_db.h" -#include "Game/T6/XAssets/xmodel/xmodel_write_db.h" -#include "Game/T6/XAssets/zbarrierdef/zbarrierdef_write_db.h" +#include "Game/T6/AssetWriterT6.h" #include "Writing/WritingException.h" #include From ac9bdd21da0b453914a775ac38b6e18c6e417786 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Tue, 6 Jan 2026 12:59:43 +0000 Subject: [PATCH 03/20] chore: use vector for ZoneInputStream block offsets --- src/ZoneLoading/Zone/Stream/ZoneInputStream.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ZoneLoading/Zone/Stream/ZoneInputStream.cpp b/src/ZoneLoading/Zone/Stream/ZoneInputStream.cpp index f6722962..58b44655 100644 --- a/src/ZoneLoading/Zone/Stream/ZoneInputStream.cpp +++ b/src/ZoneLoading/Zone/Stream/ZoneInputStream.cpp @@ -53,6 +53,7 @@ namespace MemoryManager& memory, std::optional> progressCallback) : m_blocks(blocks), + m_block_offsets(blocks.size()), m_stream(stream), m_memory(memory), m_pointer_byte_count(pointerBitCount / 8u), @@ -67,9 +68,7 @@ namespace 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); + std::memset(m_block_offsets.data(), 0, sizeof(decltype(m_block_offsets)::value_type) * m_block_offsets.size()); m_insert_block = blocks[insertBlock]; @@ -488,7 +487,7 @@ namespace } std::vector& m_blocks; - std::unique_ptr m_block_offsets; + std::vector m_block_offsets; std::stack m_block_stack; std::stack m_temp_offsets; From ac24e4f893075f7e71460520f116dec5340fbf2f Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Tue, 6 Jan 2026 13:29:32 +0000 Subject: [PATCH 04/20] refactor: combined ZoneOutputStream interface with impl --- .../Templates/ZoneWriteTemplate.cpp | 4 +- src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp | 2 +- src/ZoneWriting/Game/IW3/ContentWriterIW3.h | 3 +- .../Game/IW3/ZoneWriterFactoryIW3.cpp | 2 +- src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp | 2 +- src/ZoneWriting/Game/IW4/ContentWriterIW4.h | 3 +- .../Game/IW4/ZoneWriterFactoryIW4.cpp | 2 +- src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp | 2 +- src/ZoneWriting/Game/IW5/ContentWriterIW5.h | 3 +- .../Game/IW5/ZoneWriterFactoryIW5.cpp | 2 +- src/ZoneWriting/Game/T5/ContentWriterT5.cpp | 2 +- src/ZoneWriting/Game/T5/ContentWriterT5.h | 5 +- .../Game/T5/ZoneWriterFactoryT5.cpp | 2 +- src/ZoneWriting/Game/T6/ContentWriterT6.cpp | 2 +- src/ZoneWriting/Game/T6/ContentWriterT6.h | 3 +- .../Game/T6/ZoneWriterFactoryT6.cpp | 3 +- src/ZoneWriting/Writing/AssetWriter.cpp | 2 +- src/ZoneWriting/Writing/AssetWriter.h | 3 +- src/ZoneWriting/Writing/ContentWriterBase.cpp | 2 +- src/ZoneWriting/Writing/ContentWriterBase.h | 6 +- .../Writing/IContentWritingEntryPoint.h | 4 +- .../Steps/StepWriteZoneContentToMemory.cpp | 13 +- .../Steps/StepWriteZoneContentToMemory.h | 10 +- .../Stream/Impl/InMemoryZoneOutputStream.cpp | 218 -------------- .../Stream/Impl/InMemoryZoneOutputStream.h | 51 ---- .../Stream}/InMemoryZoneData.cpp | 0 .../Stream}/InMemoryZoneData.h | 0 .../Zone/Stream/ZoneOutputStream.cpp | 276 ++++++++++++++++++ ...IZoneOutputStream.h => ZoneOutputStream.h} | 37 ++- 29 files changed, 354 insertions(+), 310 deletions(-) delete mode 100644 src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.cpp delete mode 100644 src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.h rename src/ZoneWriting/{Writing => Zone/Stream}/InMemoryZoneData.cpp (100%) rename src/ZoneWriting/{Writing => Zone/Stream}/InMemoryZoneData.h (100%) create mode 100644 src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp rename src/ZoneWriting/Zone/Stream/{IZoneOutputStream.h => ZoneOutputStream.h} (53%) diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp index 921a3388..6952c402 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp @@ -253,7 +253,7 @@ namespace void PrintHeaderConstructor() const { - LINEF("{0}({1}* asset, const Zone& zone, IZoneOutputStream& stream);", WriterClassName(m_env.m_asset), m_env.m_asset->m_definition->GetFullName()) + LINEF("{0}({1}* asset, const Zone& zone, ZoneOutputStream& stream);", WriterClassName(m_env.m_asset), m_env.m_asset->m_definition->GetFullName()) } void PrintVariableInitialization(const DataDefinition* def) const @@ -279,7 +279,7 @@ namespace void PrintConstructorMethod() { LINEF( - "{0}::{0}({1}* asset, const Zone& zone, IZoneOutputStream& stream)", WriterClassName(m_env.m_asset), m_env.m_asset->m_definition->GetFullName()) + "{0}::{0}({1}* asset, const Zone& zone, ZoneOutputStream& stream)", WriterClassName(m_env.m_asset), m_env.m_asset->m_definition->GetFullName()) m_intendation++; LINEF(": AssetWriter(zone.m_pools->GetAssetOrAssetReference({0}::EnumEntry, NonReferenceAssetName(AssetName<{0}>(*asset))), zone, stream)", diff --git a/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp b/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp index 9e07914c..72475a26 100644 --- a/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp +++ b/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp @@ -146,7 +146,7 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun } } -void ContentWriter::WriteContent(IZoneOutputStream& stream) +void ContentWriter::WriteContent(ZoneOutputStream& stream) { m_stream = &stream; diff --git a/src/ZoneWriting/Game/IW3/ContentWriterIW3.h b/src/ZoneWriting/Game/IW3/ContentWriterIW3.h index 3421a923..195df96c 100644 --- a/src/ZoneWriting/Game/IW3/ContentWriterIW3.h +++ b/src/ZoneWriting/Game/IW3/ContentWriterIW3.h @@ -1,4 +1,5 @@ #pragma once + #include "Game/IW3/IW3.h" #include "Writing/ContentWriterBase.h" #include "Writing/IContentWritingEntryPoint.h" @@ -10,7 +11,7 @@ namespace IW3 public: explicit ContentWriter(const Zone& zone); - void WriteContent(IZoneOutputStream& stream) override; + void WriteContent(ZoneOutputStream& stream) override; private: void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const; diff --git a/src/ZoneWriting/Game/IW3/ZoneWriterFactoryIW3.cpp b/src/ZoneWriting/Game/IW3/ZoneWriterFactoryIW3.cpp index c9f47bb2..350e4971 100644 --- a/src/ZoneWriting/Game/IW3/ZoneWriterFactoryIW3.cpp +++ b/src/ZoneWriting/Game/IW3/ZoneWriterFactoryIW3.cpp @@ -52,7 +52,7 @@ std::unique_ptr ZoneWriterFactory::CreateWriter(const Zone& zone) co SetupBlocks(*writer); auto contentInMemory = std::make_unique( - std::make_unique(zone), zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); + std::make_unique(zone), zone, 32u, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); auto* contentInMemoryPtr = contentInMemory.get(); writer->AddWritingStep(std::move(contentInMemory)); diff --git a/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp b/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp index 0d3e0d06..36592259 100644 --- a/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp +++ b/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp @@ -156,7 +156,7 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun } } -void ContentWriter::WriteContent(IZoneOutputStream& stream) +void ContentWriter::WriteContent(ZoneOutputStream& stream) { m_stream = &stream; diff --git a/src/ZoneWriting/Game/IW4/ContentWriterIW4.h b/src/ZoneWriting/Game/IW4/ContentWriterIW4.h index 0217af78..e5212c60 100644 --- a/src/ZoneWriting/Game/IW4/ContentWriterIW4.h +++ b/src/ZoneWriting/Game/IW4/ContentWriterIW4.h @@ -1,4 +1,5 @@ #pragma once + #include "Game/IW4/IW4.h" #include "Writing/ContentWriterBase.h" #include "Writing/IContentWritingEntryPoint.h" @@ -10,7 +11,7 @@ namespace IW4 public: explicit ContentWriter(const Zone& zone); - void WriteContent(IZoneOutputStream& stream) override; + void WriteContent(ZoneOutputStream& stream) override; private: void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const; diff --git a/src/ZoneWriting/Game/IW4/ZoneWriterFactoryIW4.cpp b/src/ZoneWriting/Game/IW4/ZoneWriterFactoryIW4.cpp index 0f9f1daa..941f76e6 100644 --- a/src/ZoneWriting/Game/IW4/ZoneWriterFactoryIW4.cpp +++ b/src/ZoneWriting/Game/IW4/ZoneWriterFactoryIW4.cpp @@ -67,7 +67,7 @@ std::unique_ptr ZoneWriterFactory::CreateWriter(const Zone& zone) co SetupBlocks(*writer); auto contentInMemory = std::make_unique( - std::make_unique(zone), zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); + std::make_unique(zone), zone, 32u, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); auto* contentInMemoryPtr = contentInMemory.get(); writer->AddWritingStep(std::move(contentInMemory)); diff --git a/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp b/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp index ee0af8d3..b5ecf4b2 100644 --- a/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp +++ b/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp @@ -159,7 +159,7 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun } } -void ContentWriter::WriteContent(IZoneOutputStream& stream) +void ContentWriter::WriteContent(ZoneOutputStream& stream) { m_stream = &stream; diff --git a/src/ZoneWriting/Game/IW5/ContentWriterIW5.h b/src/ZoneWriting/Game/IW5/ContentWriterIW5.h index 1e8d64a1..6bf2ace2 100644 --- a/src/ZoneWriting/Game/IW5/ContentWriterIW5.h +++ b/src/ZoneWriting/Game/IW5/ContentWriterIW5.h @@ -1,4 +1,5 @@ #pragma once + #include "Game/IW5/IW5.h" #include "Writing/ContentWriterBase.h" #include "Writing/IContentWritingEntryPoint.h" @@ -10,7 +11,7 @@ namespace IW5 public: explicit ContentWriter(const Zone& zone); - void WriteContent(IZoneOutputStream& stream) override; + void WriteContent(ZoneOutputStream& stream) override; private: void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const; diff --git a/src/ZoneWriting/Game/IW5/ZoneWriterFactoryIW5.cpp b/src/ZoneWriting/Game/IW5/ZoneWriterFactoryIW5.cpp index 00338ed7..90ed3208 100644 --- a/src/ZoneWriting/Game/IW5/ZoneWriterFactoryIW5.cpp +++ b/src/ZoneWriting/Game/IW5/ZoneWriterFactoryIW5.cpp @@ -68,7 +68,7 @@ std::unique_ptr ZoneWriterFactory::CreateWriter(const Zone& zone) co SetupBlocks(*writer); auto contentInMemory = std::make_unique( - std::make_unique(zone), zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); + std::make_unique(zone), zone, 32u, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); auto* contentInMemoryPtr = contentInMemory.get(); writer->AddWritingStep(std::move(contentInMemory)); diff --git a/src/ZoneWriting/Game/T5/ContentWriterT5.cpp b/src/ZoneWriting/Game/T5/ContentWriterT5.cpp index e57067d5..8c0c2ce6 100644 --- a/src/ZoneWriting/Game/T5/ContentWriterT5.cpp +++ b/src/ZoneWriting/Game/T5/ContentWriterT5.cpp @@ -152,7 +152,7 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun } } -void ContentWriter::WriteContent(IZoneOutputStream& stream) +void ContentWriter::WriteContent(ZoneOutputStream& stream) { m_stream = &stream; diff --git a/src/ZoneWriting/Game/T5/ContentWriterT5.h b/src/ZoneWriting/Game/T5/ContentWriterT5.h index 50c78edb..1c0cc137 100644 --- a/src/ZoneWriting/Game/T5/ContentWriterT5.h +++ b/src/ZoneWriting/Game/T5/ContentWriterT5.h @@ -1,4 +1,5 @@ #pragma once + #include "Game/T5/T5.h" #include "Writing/ContentWriterBase.h" #include "Writing/IContentWritingEntryPoint.h" @@ -8,9 +9,9 @@ namespace T5 class ContentWriter final : public ContentWriterBase, public IContentWritingEntryPoint { public: - ContentWriter(const Zone& zone); + explicit ContentWriter(const Zone& zone); - void WriteContent(IZoneOutputStream& stream) override; + void WriteContent(ZoneOutputStream& stream) override; private: void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const; diff --git a/src/ZoneWriting/Game/T5/ZoneWriterFactoryT5.cpp b/src/ZoneWriting/Game/T5/ZoneWriterFactoryT5.cpp index cd5ca5bf..4cb65a9b 100644 --- a/src/ZoneWriting/Game/T5/ZoneWriterFactoryT5.cpp +++ b/src/ZoneWriting/Game/T5/ZoneWriterFactoryT5.cpp @@ -50,7 +50,7 @@ std::unique_ptr ZoneWriterFactory::CreateWriter(const Zone& zone) co SetupBlocks(*writer); auto contentInMemory = std::make_unique( - std::make_unique(zone), zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); + std::make_unique(zone), zone, 32u, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); auto* contentInMemoryPtr = contentInMemory.get(); writer->AddWritingStep(std::move(contentInMemory)); diff --git a/src/ZoneWriting/Game/T6/ContentWriterT6.cpp b/src/ZoneWriting/Game/T6/ContentWriterT6.cpp index d929bfa5..234f80f5 100644 --- a/src/ZoneWriting/Game/T6/ContentWriterT6.cpp +++ b/src/ZoneWriting/Game/T6/ContentWriterT6.cpp @@ -167,7 +167,7 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun } } -void ContentWriter::WriteContent(IZoneOutputStream& stream) +void ContentWriter::WriteContent(ZoneOutputStream& stream) { m_stream = &stream; diff --git a/src/ZoneWriting/Game/T6/ContentWriterT6.h b/src/ZoneWriting/Game/T6/ContentWriterT6.h index 3f78b034..4bb08580 100644 --- a/src/ZoneWriting/Game/T6/ContentWriterT6.h +++ b/src/ZoneWriting/Game/T6/ContentWriterT6.h @@ -1,4 +1,5 @@ #pragma once + #include "Game/T6/T6.h" #include "Writing/ContentWriterBase.h" #include "Writing/IContentWritingEntryPoint.h" @@ -10,7 +11,7 @@ namespace T6 public: explicit ContentWriter(const Zone& zone); - void WriteContent(IZoneOutputStream& stream) override; + void WriteContent(ZoneOutputStream& stream) override; private: void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const; diff --git a/src/ZoneWriting/Game/T6/ZoneWriterFactoryT6.cpp b/src/ZoneWriting/Game/T6/ZoneWriterFactoryT6.cpp index 536e08b6..fb3796f8 100644 --- a/src/ZoneWriting/Game/T6/ZoneWriterFactoryT6.cpp +++ b/src/ZoneWriting/Game/T6/ZoneWriterFactoryT6.cpp @@ -106,7 +106,7 @@ std::unique_ptr ZoneWriterFactory::CreateWriter(const Zone& zone) co SetupBlocks(*writer); auto contentInMemory = std::make_unique( - std::make_unique(zone), zone, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); + std::make_unique(zone), zone, 32u, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); auto* contentInMemoryPtr = contentInMemory.get(); writer->AddWritingStep(std::move(contentInMemory)); @@ -119,7 +119,6 @@ std::unique_ptr ZoneWriterFactory::CreateWriter(const Zone& zone) co AddXChunkProcessor(*writer, zone, isEncrypted, &dataToSignProvider, &xChunksProcessor); // Start of the XFile struct - // m_writer->AddWritingStep(std::make_unique(8)); // Skip size and externalSize fields since they are not interesting for us writer->AddWritingStep(std::make_unique(contentInMemoryPtr)); writer->AddWritingStep(std::make_unique(zone)); diff --git a/src/ZoneWriting/Writing/AssetWriter.cpp b/src/ZoneWriting/Writing/AssetWriter.cpp index 4dc9752c..e052927e 100644 --- a/src/ZoneWriting/Writing/AssetWriter.cpp +++ b/src/ZoneWriting/Writing/AssetWriter.cpp @@ -2,7 +2,7 @@ #include -AssetWriter::AssetWriter(XAssetInfoGeneric* asset, const Zone& zone, IZoneOutputStream& stream) +AssetWriter::AssetWriter(XAssetInfoGeneric* asset, const Zone& zone, ZoneOutputStream& stream) : ContentWriterBase(zone, stream), m_asset(asset), varScriptString(nullptr), diff --git a/src/ZoneWriting/Writing/AssetWriter.h b/src/ZoneWriting/Writing/AssetWriter.h index 188828c1..b3357054 100644 --- a/src/ZoneWriting/Writing/AssetWriter.h +++ b/src/ZoneWriting/Writing/AssetWriter.h @@ -2,14 +2,13 @@ #include "ContentWriterBase.h" #include "Pool/XAssetInfo.h" -#include "Utils/ClassUtils.h" #include "Zone/Zone.h" #include "Zone/ZoneTypes.h" class AssetWriter : public ContentWriterBase { protected: - AssetWriter(XAssetInfoGeneric* asset, const Zone& zone, IZoneOutputStream& stream); + AssetWriter(XAssetInfoGeneric* asset, const Zone& zone, ZoneOutputStream& stream); [[nodiscard]] static const char* NonReferenceAssetName(const char* assetName); [[nodiscard]] scr_string_t UseScriptString(scr_string_t scrString) const; diff --git a/src/ZoneWriting/Writing/ContentWriterBase.cpp b/src/ZoneWriting/Writing/ContentWriterBase.cpp index b4d775a1..71f603d9 100644 --- a/src/ZoneWriting/Writing/ContentWriterBase.cpp +++ b/src/ZoneWriting/Writing/ContentWriterBase.cpp @@ -10,7 +10,7 @@ ContentWriterBase::ContentWriterBase(const Zone& zone) { } -ContentWriterBase::ContentWriterBase(const Zone& zone, IZoneOutputStream& stream) +ContentWriterBase::ContentWriterBase(const Zone& zone, ZoneOutputStream& stream) : m_zone(zone), m_stream(&stream), varXString(nullptr), diff --git a/src/ZoneWriting/Writing/ContentWriterBase.h b/src/ZoneWriting/Writing/ContentWriterBase.h index 06dd121c..9a58959d 100644 --- a/src/ZoneWriting/Writing/ContentWriterBase.h +++ b/src/ZoneWriting/Writing/ContentWriterBase.h @@ -1,13 +1,13 @@ #pragma once -#include "Zone/Stream/IZoneOutputStream.h" +#include "Zone/Stream/ZoneOutputStream.h" #include "Zone/Zone.h" class ContentWriterBase { protected: explicit ContentWriterBase(const Zone& zone); - ContentWriterBase(const Zone& zone, IZoneOutputStream& stream); + ContentWriterBase(const Zone& zone, ZoneOutputStream& stream); public: virtual ~ContentWriterBase() = default; @@ -21,7 +21,7 @@ protected: void WriteXStringArray(bool atStreamStart, size_t count); const Zone& m_zone; - IZoneOutputStream* m_stream; + ZoneOutputStream* m_stream; const char** varXString; const char** varXStringWritten; diff --git a/src/ZoneWriting/Writing/IContentWritingEntryPoint.h b/src/ZoneWriting/Writing/IContentWritingEntryPoint.h index af0d5672..3cd3d140 100644 --- a/src/ZoneWriting/Writing/IContentWritingEntryPoint.h +++ b/src/ZoneWriting/Writing/IContentWritingEntryPoint.h @@ -1,6 +1,6 @@ #pragma once -#include "Zone/Stream/IZoneOutputStream.h" +#include "Zone/Stream/ZoneOutputStream.h" class IContentWritingEntryPoint { @@ -12,5 +12,5 @@ public: IContentWritingEntryPoint& operator=(const IContentWritingEntryPoint& other) = default; IContentWritingEntryPoint& operator=(IContentWritingEntryPoint&& other) noexcept = default; - virtual void WriteContent(IZoneOutputStream& stream) = 0; + virtual void WriteContent(ZoneOutputStream& stream) = 0; }; diff --git a/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToMemory.cpp b/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToMemory.cpp index 76d5f1ee..01cbc332 100644 --- a/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToMemory.cpp +++ b/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToMemory.cpp @@ -1,14 +1,16 @@ #include "StepWriteZoneContentToMemory.h" -#include "Zone/Stream/Impl/InMemoryZoneOutputStream.h" +#include "Zone/Stream/ZoneOutputStream.h" StepWriteZoneContentToMemory::StepWriteZoneContentToMemory(std::unique_ptr entryPoint, const Zone& zone, - const int offsetBlockBitCount, + const unsigned pointerBitCount, + const unsigned offsetBlockBitCount, const block_t insertBlock) : m_content_loader(std::move(entryPoint)), m_zone_data(std::make_unique()), m_zone(zone), + m_pointer_bit_count(pointerBitCount), m_offset_block_bit_count(offsetBlockBitCount), m_insert_block(insertBlock) { @@ -16,12 +18,11 @@ StepWriteZoneContentToMemory::StepWriteZoneContentToMemory(std::unique_ptr blocks; - blocks.reserve(zoneWriter->m_blocks.size()); + m_blocks.reserve(zoneWriter->m_blocks.size()); for (const auto& block : zoneWriter->m_blocks) - blocks.emplace_back(block.get()); + m_blocks.emplace_back(block.get()); - const auto zoneOutputStream = std::make_unique(m_zone_data.get(), std::move(blocks), m_offset_block_bit_count, m_insert_block); + const auto zoneOutputStream = ZoneOutputStream::Create(m_pointer_bit_count, m_offset_block_bit_count, m_blocks, m_insert_block, *m_zone_data); m_content_loader->WriteContent(*zoneOutputStream); } diff --git a/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToMemory.h b/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToMemory.h index 8bc43c48..89f38ba7 100644 --- a/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToMemory.h +++ b/src/ZoneWriting/Writing/Steps/StepWriteZoneContentToMemory.h @@ -2,14 +2,15 @@ #include "Writing/IContentWritingEntryPoint.h" #include "Writing/IWritingStep.h" -#include "Writing/InMemoryZoneData.h" +#include "Zone/Stream/InMemoryZoneData.h" #include class StepWriteZoneContentToMemory final : public IWritingStep { public: - StepWriteZoneContentToMemory(std::unique_ptr entryPoint, const Zone& zone, int offsetBlockBitCount, block_t insertBlock); + StepWriteZoneContentToMemory( + std::unique_ptr entryPoint, const Zone& zone, unsigned pointerBitCount, unsigned offsetBlockBitCount, block_t insertBlock); void PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) override; [[nodiscard]] InMemoryZoneData* GetData() const; @@ -18,6 +19,9 @@ private: std::unique_ptr m_content_loader; std::unique_ptr m_zone_data; const Zone& m_zone; - int m_offset_block_bit_count; + std::vector m_blocks; + + unsigned m_pointer_bit_count; + unsigned m_offset_block_bit_count; block_t m_insert_block; }; diff --git a/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.cpp b/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.cpp deleted file mode 100644 index 6eff9d3f..00000000 --- a/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include "InMemoryZoneOutputStream.h" - -#include -#include - -InMemoryZoneOutputStream::InMemoryZoneOutputStream(InMemoryZoneData* zoneData, std::vector blocks, const int blockBitCount, const block_t insertBlock) - : m_zone_data(zoneData), - m_blocks(std::move(blocks)), - m_block_bit_count(blockBitCount), - m_insert_block(m_blocks[insertBlock]) -{ -} - -InMemoryZoneOutputStream::ReusableEntry::ReusableEntry(void* startPtr, const size_t entrySize, const size_t entryCount, const uintptr_t startZonePtr) - : m_start_ptr(startPtr), - m_end_ptr(reinterpret_cast(reinterpret_cast(startPtr) + entrySize * entryCount)), - m_start_zone_ptr(startZonePtr), - m_entry_size(entrySize), - m_entry_count(entryCount) -{ -} - -void InMemoryZoneOutputStream::PushBlock(const block_t block) -{ - assert(block >= 0 && block < static_cast(m_blocks.size())); - - auto* newBlock = m_blocks[block]; - - assert(newBlock->m_index == block); - - m_block_stack.push(newBlock); - - if (newBlock->m_type == XBlockType::BLOCK_TYPE_TEMP) - { - if (m_temp_sizes.empty()) - m_temp_sizes.push(0); - else - m_temp_sizes.push(m_temp_sizes.top()); - } -} - -block_t InMemoryZoneOutputStream::PopBlock() -{ - assert(!m_block_stack.empty()); - - if (m_block_stack.empty()) - return -1; - - auto* poppedBlock = m_block_stack.top(); - m_block_stack.pop(); - - // If temp block is popped, see if its size is bigger than the current maximum temp size - if (poppedBlock->m_type == XBlockType::BLOCK_TYPE_TEMP) - { - const auto tempSize = m_temp_sizes.top(); - m_temp_sizes.pop(); - - if (tempSize > poppedBlock->m_buffer_size) - poppedBlock->m_buffer_size = tempSize; - } - - return poppedBlock->m_index; -} - -void InMemoryZoneOutputStream::Align(const int align) -{ - assert(!m_block_stack.empty()); - - if (align > 1) - { - auto* block = m_block_stack.top(); - - if (block->m_type == XBlockType::BLOCK_TYPE_TEMP) - m_temp_sizes.top() = (m_temp_sizes.top() + align - 1) / align * align; - else - block->m_buffer_size = (block->m_buffer_size + align - 1) / align * align; - } -} - -void* InMemoryZoneOutputStream::WriteDataRaw(const void* src, const size_t size) -{ - auto* result = m_zone_data->GetBufferOfSize(size); - memcpy(result, src, size); - return result; -} - -void* InMemoryZoneOutputStream::WriteDataInBlock(const void* src, const size_t size) -{ - assert(!m_block_stack.empty()); - - if (m_block_stack.empty()) - return nullptr; - - auto* block = m_block_stack.top(); - - void* result = nullptr; - switch (block->m_type) - { - case XBlockType::BLOCK_TYPE_TEMP: - case XBlockType::BLOCK_TYPE_NORMAL: - result = m_zone_data->GetBufferOfSize(size); - memcpy(result, src, size); - break; - - case XBlockType::BLOCK_TYPE_RUNTIME: - break; - - case XBlockType::BLOCK_TYPE_DELAY: - assert(false); - break; - } - - IncBlockPos(size); - return result; -} - -void InMemoryZoneOutputStream::IncBlockPos(const size_t size) -{ - assert(!m_block_stack.empty()); - - if (m_block_stack.empty()) - return; - - auto* block = m_block_stack.top(); - if (block->m_type == XBlockType::BLOCK_TYPE_TEMP) - { - m_temp_sizes.top() += size; - } - else - { - block->m_buffer_size += size; - } -} - -void InMemoryZoneOutputStream::WriteNullTerminated(const void* src) -{ - const auto len = strlen(static_cast(src)); - WriteDataInBlock(src, len + 1); -} - -uintptr_t InMemoryZoneOutputStream::GetCurrentZonePointer() -{ - assert(!m_block_stack.empty()); - assert(m_block_stack.top()->m_type == XBlockType::BLOCK_TYPE_NORMAL); - - uintptr_t ptr = 0; - ptr |= static_cast(m_block_stack.top()->m_index) << (sizeof(uintptr_t) * 8 - m_block_bit_count); - ptr |= m_block_stack.top()->m_buffer_size & (UINTPTR_MAX >> m_block_bit_count); - ptr++; - - return ptr; -} - -uintptr_t InMemoryZoneOutputStream::InsertPointer() -{ - PushBlock(m_insert_block->m_index); - - Align(sizeof(uintptr_t)); - const auto result = GetCurrentZonePointer(); - IncBlockPos(sizeof(uintptr_t)); - - PopBlock(); - - return result; -} - -void InMemoryZoneOutputStream::MarkFollowing(void** pPtr) -{ - assert(!m_block_stack.empty()); - assert(pPtr != nullptr); - *pPtr = m_block_stack.top()->m_type == XBlockType::BLOCK_TYPE_TEMP ? PTR_INSERT : PTR_FOLLOWING; -} - -bool InMemoryZoneOutputStream::ReusableShouldWrite(void** pPtr, const size_t entrySize, const std::type_index type) -{ - assert(!m_block_stack.empty()); - assert(pPtr != nullptr); - - if (*pPtr == nullptr) - return false; - - const auto foundEntriesForType = m_reusable_entries.find(type); - if (foundEntriesForType == m_reusable_entries.end()) - { - return true; - } - - for (const auto& entry : foundEntriesForType->second) - { - if (*pPtr >= entry.m_start_ptr && *pPtr < entry.m_end_ptr) - { - assert((reinterpret_cast(*pPtr) - reinterpret_cast(entry.m_start_ptr)) % entrySize == 0); - *pPtr = reinterpret_cast(entry.m_start_zone_ptr + (reinterpret_cast(*pPtr) - reinterpret_cast(entry.m_start_ptr))); - return false; - } - } - - return true; -} - -void InMemoryZoneOutputStream::ReusableAddOffset(void* ptr, size_t size, size_t count, std::type_index type) -{ - assert(!m_block_stack.empty()); - - const auto inTemp = m_block_stack.top()->m_type == XBlockType::BLOCK_TYPE_TEMP; - auto zoneOffset = inTemp ? InsertPointer() : GetCurrentZonePointer(); - const auto foundEntriesForType = m_reusable_entries.find(type); - if (foundEntriesForType == m_reusable_entries.end()) - { - std::vector entries; - entries.emplace_back(ptr, size, count, zoneOffset); - m_reusable_entries.emplace(std::make_pair(type, std::move(entries))); - } - else - { - foundEntriesForType->second.emplace_back(ptr, size, count, zoneOffset); - } -} diff --git a/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.h b/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.h deleted file mode 100644 index 3f2f8947..00000000 --- a/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once -#include "Writing/InMemoryZoneData.h" -#include "Zone/Stream/IZoneOutputStream.h" -#include "Zone/XBlock.h" - -#include -#include -#include - -class InMemoryZoneOutputStream final : public IZoneOutputStream -{ - class ReusableEntry - { - public: - void* m_start_ptr; - void* m_end_ptr; - uintptr_t m_start_zone_ptr; - size_t m_entry_size; - size_t m_entry_count; - - ReusableEntry(void* startPtr, size_t entrySize, size_t entryCount, uintptr_t startZonePtr); - }; - - InMemoryZoneData* m_zone_data; - std::vector m_blocks; - - std::stack m_block_stack; - std::stack m_temp_sizes; - - int m_block_bit_count; - XBlock* m_insert_block; - - std::unordered_map> m_reusable_entries; - - uintptr_t GetCurrentZonePointer(); - uintptr_t InsertPointer(); - -public: - InMemoryZoneOutputStream(InMemoryZoneData* zoneData, std::vector blocks, int blockBitCount, block_t insertBlock); - - void PushBlock(block_t block) override; - block_t PopBlock() override; - void Align(int align) override; - void* WriteDataRaw(const void* src, size_t size) override; - void* WriteDataInBlock(const void* src, size_t size) override; - void IncBlockPos(size_t size) override; - void WriteNullTerminated(const void* src) override; - void MarkFollowing(void** pPtr) override; - bool ReusableShouldWrite(void** pPtr, size_t entrySize, std::type_index type) override; - void ReusableAddOffset(void* ptr, size_t size, size_t count, std::type_index type) override; -}; diff --git a/src/ZoneWriting/Writing/InMemoryZoneData.cpp b/src/ZoneWriting/Zone/Stream/InMemoryZoneData.cpp similarity index 100% rename from src/ZoneWriting/Writing/InMemoryZoneData.cpp rename to src/ZoneWriting/Zone/Stream/InMemoryZoneData.cpp diff --git a/src/ZoneWriting/Writing/InMemoryZoneData.h b/src/ZoneWriting/Zone/Stream/InMemoryZoneData.h similarity index 100% rename from src/ZoneWriting/Writing/InMemoryZoneData.h rename to src/ZoneWriting/Zone/Stream/InMemoryZoneData.h diff --git a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp new file mode 100644 index 00000000..836a3d2e --- /dev/null +++ b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp @@ -0,0 +1,276 @@ +#include "ZoneOutputStream.h" + +#include "InMemoryZoneData.h" +#include "Utils/Alignment.h" +#include "Zone/XBlock.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + inline const auto PTR_FOLLOWING = reinterpret_cast(-1); + inline const auto PTR_INSERT = reinterpret_cast(-2); + + class ReusableEntry + { + public: + ReusableEntry(void* startPtr, const size_t entrySize, const size_t entryCount, const uintptr_t startZonePtr) + : m_start_ptr(startPtr), + m_end_ptr(reinterpret_cast(reinterpret_cast(startPtr) + entrySize * entryCount)), + m_start_zone_ptr(startZonePtr), + m_entry_size(entrySize), + m_entry_count(entryCount) + { + } + + void* m_start_ptr; + void* m_end_ptr; + uintptr_t m_start_zone_ptr; + size_t m_entry_size; + size_t m_entry_count; + }; + + class InMemoryZoneOutputStream final : public ZoneOutputStream + { + public: + InMemoryZoneOutputStream( + const unsigned pointerBitCount, const unsigned blockBitCount, std::vector& blocks, const block_t insertBlock, InMemoryZoneData& zoneData) + : m_zone_data(zoneData), + m_blocks(blocks), + m_block_bit_count(blockBitCount), + m_pointer_byte_count(pointerBitCount / 8u) + { + assert(pointerBitCount % 8u == 0u); + assert(insertBlock < static_cast(blocks.size())); + + m_insert_block = blocks[insertBlock]; + } + + [[nodiscard]] unsigned GetPointerBitCount() const override + { + return m_pointer_byte_count * 8u; + } + + void PushBlock(const block_t block) override + { + assert(block < static_cast(m_blocks.size())); + + auto* newBlock = m_blocks[block]; + + assert(newBlock->m_index == block); + + m_block_stack.push(newBlock); + + if (newBlock->m_type == XBlockType::BLOCK_TYPE_TEMP) + { + if (m_temp_sizes.empty()) + m_temp_sizes.push(0); + else + m_temp_sizes.push(m_temp_sizes.top()); + } + } + + block_t PopBlock() override + { + assert(!m_block_stack.empty()); + + if (m_block_stack.empty()) + return -1; + + auto* poppedBlock = m_block_stack.top(); + m_block_stack.pop(); + + // If temp block is popped, see if its size is bigger than the current maximum temp size + if (poppedBlock->m_type == XBlockType::BLOCK_TYPE_TEMP) + { + const auto tempSize = m_temp_sizes.top(); + m_temp_sizes.pop(); + + poppedBlock->m_buffer_size = std::max(tempSize, poppedBlock->m_buffer_size); + } + + return poppedBlock->m_index; + } + + void Align(const unsigned align) override + { + assert(!m_block_stack.empty()); + + if (align > 1) + { + auto* block = m_block_stack.top(); + + if (block->m_type == XBlockType::BLOCK_TYPE_TEMP) + m_temp_sizes.top() = utils::Align(m_temp_sizes.top(), static_cast(align)); + else + block->m_buffer_size = utils::Align(block->m_buffer_size, static_cast(align)); + } + } + + void* WriteDataRaw(const void* src, const size_t size) override + { + auto* result = m_zone_data.GetBufferOfSize(size); + memcpy(result, src, size); + return result; + } + + void* WriteDataInBlock(const void* src, const size_t size) override + { + assert(!m_block_stack.empty()); + + if (m_block_stack.empty()) + return nullptr; + + const auto* block = m_block_stack.top(); + + void* result = nullptr; + switch (block->m_type) + { + case XBlockType::BLOCK_TYPE_TEMP: + case XBlockType::BLOCK_TYPE_NORMAL: + result = m_zone_data.GetBufferOfSize(size); + memcpy(result, src, size); + break; + + case XBlockType::BLOCK_TYPE_RUNTIME: + break; + + case XBlockType::BLOCK_TYPE_DELAY: + assert(false); + break; + } + + IncBlockPos(size); + return result; + } + + void IncBlockPos(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_type == XBlockType::BLOCK_TYPE_TEMP) + { + m_temp_sizes.top() += size; + } + else + { + block->m_buffer_size += size; + } + } + + void WriteNullTerminated(const void* src) override + { + const auto len = strlen(static_cast(src)); + WriteDataInBlock(src, len + 1); + } + + void MarkFollowing(void** pPtr) override + { + assert(!m_block_stack.empty()); + assert(pPtr != nullptr); + *pPtr = m_block_stack.top()->m_type == XBlockType::BLOCK_TYPE_TEMP ? PTR_INSERT : PTR_FOLLOWING; + } + + bool ReusableShouldWrite(void** pPtr, const size_t entrySize, const std::type_index type) override + { + assert(!m_block_stack.empty()); + assert(pPtr != nullptr); + + if (*pPtr == nullptr) + return false; + + const auto foundEntriesForType = m_reusable_entries.find(type); + if (foundEntriesForType == m_reusable_entries.end()) + { + return true; + } + + for (const auto& entry : foundEntriesForType->second) + { + if (*pPtr >= entry.m_start_ptr && *pPtr < entry.m_end_ptr) + { + assert((reinterpret_cast(*pPtr) - reinterpret_cast(entry.m_start_ptr)) % entrySize == 0); + *pPtr = + reinterpret_cast(entry.m_start_zone_ptr + (reinterpret_cast(*pPtr) - reinterpret_cast(entry.m_start_ptr))); + return false; + } + } + + return true; + } + + void ReusableAddOffset(void* ptr, size_t size, size_t count, std::type_index type) override + { + assert(!m_block_stack.empty()); + + const auto inTemp = m_block_stack.top()->m_type == XBlockType::BLOCK_TYPE_TEMP; + auto zoneOffset = inTemp ? InsertPointer() : GetCurrentZonePointer(); + const auto foundEntriesForType = m_reusable_entries.find(type); + if (foundEntriesForType == m_reusable_entries.end()) + { + std::vector entries; + entries.emplace_back(ptr, size, count, zoneOffset); + m_reusable_entries.emplace(std::make_pair(type, std::move(entries))); + } + else + { + foundEntriesForType->second.emplace_back(ptr, size, count, zoneOffset); + } + } + + private: + uintptr_t GetCurrentZonePointer() + { + assert(!m_block_stack.empty()); + assert(m_block_stack.top()->m_type == XBlockType::BLOCK_TYPE_NORMAL); + + uintptr_t ptr = 0; + ptr |= static_cast(m_block_stack.top()->m_index) << (sizeof(uintptr_t) * 8 - m_block_bit_count); + ptr |= m_block_stack.top()->m_buffer_size & (UINTPTR_MAX >> m_block_bit_count); + ptr++; + + return ptr; + } + + uintptr_t InsertPointer() + { + PushBlock(m_insert_block->m_index); + + Align(sizeof(uintptr_t)); + const auto result = GetCurrentZonePointer(); + IncBlockPos(sizeof(uintptr_t)); + + PopBlock(); + + return result; + } + + InMemoryZoneData& m_zone_data; + std::vector& m_blocks; + + std::stack m_block_stack; + std::stack m_temp_sizes; + + unsigned m_block_bit_count; + unsigned m_pointer_byte_count; + XBlock* m_insert_block; + + std::unordered_map> m_reusable_entries; + }; +} // namespace + +std::unique_ptr + ZoneOutputStream::Create(unsigned pointerBitCount, unsigned blockBitCount, std::vector& blocks, block_t insertBlock, InMemoryZoneData& zoneData) +{ + return std::make_unique(pointerBitCount, blockBitCount, blocks, insertBlock, zoneData); +} diff --git a/src/ZoneWriting/Zone/Stream/IZoneOutputStream.h b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h similarity index 53% rename from src/ZoneWriting/Zone/Stream/IZoneOutputStream.h rename to src/ZoneWriting/Zone/Stream/ZoneOutputStream.h index 43b795bd..95981657 100644 --- a/src/ZoneWriting/Zone/Stream/IZoneOutputStream.h +++ b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h @@ -1,20 +1,46 @@ #pragma once +#include "InMemoryZoneData.h" #include "Zone/Stream/IZoneStream.h" +#include "Zone/XBlock.h" #include +#include #include #include +#include -class IZoneOutputStream : public IZoneStream +class ZoneOutputStream : public IZoneStream { public: - inline static void* const PTR_FOLLOWING = reinterpret_cast(-1); - inline static void* const PTR_INSERT = reinterpret_cast(-2); + /** + * \brief Returns the configured bits that make up a pointer. + */ + [[nodiscard]] virtual unsigned GetPointerBitCount() const = 0; - virtual void Align(int alignTo) = 0; + /** + * \brief Aligns the write position in the current block with the specified value. + * \param align The alignment value that the write position is aligned with. This should typically be the alignment of the struct that + * should be written afterward. + */ + virtual void Align(unsigned align) = 0; + /** + * \brief Write data to the zone data without considering the current block or advancing the block position. + * The data is written directly to the specified location instead of block memory. + * \param dst The memory location to write data to. + * \param size The amount of data to write. + */ virtual void* WriteDataRaw(const void* dst, size_t size) = 0; + + /** + * \brief Write data with the current blocks write operation into its block memory. + * Depending on the block type, the underlying stream might be written to or not. + * The current block position is advanced by the number of bytes written. + * The destination must be inside the current block's memory space, otherwise an exception is thrown. + * \param dst The destination where the data is written to. Must be inside the current block's memory bounds. + * \param size The amount of data to write. + */ virtual void* WriteDataInBlock(const void* dst, size_t size) = 0; virtual void IncBlockPos(size_t size) = 0; virtual void WriteNullTerminated(const void* dst) = 0; @@ -57,4 +83,7 @@ public: { MarkFollowing(reinterpret_cast(reinterpret_cast(&ptr))); } + + static std::unique_ptr + Create(unsigned pointerBitCount, unsigned blockBitCount, std::vector& blocks, block_t insertBlock, InMemoryZoneData& zoneData); }; From 9900544f7109c973c9d404ee216131d0c2b20edb Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Tue, 6 Jan 2026 22:37:46 +0000 Subject: [PATCH 05/20] refactor: return ZoneOutputOffset when writing via ZoneOutputStream --- src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp | 33 +++++-- src/ZoneWriting/Game/IW3/ContentWriterIW3.h | 4 + src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp | 33 +++++-- src/ZoneWriting/Game/IW4/ContentWriterIW4.h | 4 + src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp | 33 +++++-- src/ZoneWriting/Game/IW5/ContentWriterIW5.h | 4 + src/ZoneWriting/Game/T5/ContentWriterT5.cpp | 33 +++++-- src/ZoneWriting/Game/T5/ContentWriterT5.h | 4 + src/ZoneWriting/Game/T6/ContentWriterT6.cpp | 41 ++++++--- src/ZoneWriting/Game/T6/ContentWriterT6.h | 4 + src/ZoneWriting/Writing/AssetWriter.cpp | 9 +- src/ZoneWriting/Writing/AssetWriter.h | 2 +- src/ZoneWriting/Writing/ContentWriterBase.cpp | 17 ++-- src/ZoneWriting/Writing/ContentWriterBase.h | 2 +- .../Zone/Stream/ZoneOutputStream.cpp | 86 +++++++++++++++---- .../Zone/Stream/ZoneOutputStream.h | 45 ++++++---- 16 files changed, 262 insertions(+), 92 deletions(-) diff --git a/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp b/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp index 72475a26..7acc1f11 100644 --- a/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp +++ b/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp @@ -60,15 +60,18 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart) m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); if (atStreamStart) - varScriptStringList = m_stream->Write(varScriptStringList); + varScriptStringListWritten = m_stream->Write(varScriptStringList); if (varScriptStringList->strings != nullptr) { - m_stream->Align(alignof(const char*)); + m_stream->Align(4); varXString = varScriptStringList->strings; WriteXStringArray(true, varScriptStringList->count); - m_stream->MarkFollowing(varScriptStringList->strings); +#ifdef ARCH_x86 + static_assert(offsetof(ScriptStringList, strings) == 4u); +#endif + m_stream->MarkFollowing(varScriptStringListWritten.WithInnerOffset(4)); } m_stream->PopBlock(); @@ -90,7 +93,7 @@ void ContentWriter::WriteXAsset(const bool atStreamStart) assert(varXAsset != nullptr); if (atStreamStart) - varXAsset = m_stream->Write(varXAsset); + varXAssetWritten = m_stream->Write(varXAsset); switch (varXAsset->type) { @@ -137,12 +140,17 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun assert(varXAsset != nullptr); if (atStreamStart) - varXAsset = m_stream->Write(varXAsset, count); + varXAssetWritten = m_stream->Write(varXAsset, count); for (size_t index = 0; index < count; index++) { WriteXAsset(false); varXAsset++; + +#ifdef ARCH_x86 + static_assert(sizeof(XAsset) == 8u); +#endif + varXAssetWritten.Inc(8u); } } @@ -157,17 +165,26 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream) CreateXAssetList(assetList, memory); - varXAssetList = static_cast(m_stream->WriteDataRaw(&assetList, sizeof(assetList))); + varXAssetList = &assetList; + varXAssetListWritten = m_stream->WriteDataRaw(&assetList, sizeof(assetList)); +#ifdef ARCH_x86 + static_assert(offsetof(XAssetList, stringList) == 0u); +#endif varScriptStringList = &varXAssetList->stringList; + varScriptStringListWritten = varXAssetListWritten.WithInnerOffset(0); WriteScriptStringList(false); if (varXAssetList->assets != nullptr) { - m_stream->Align(alignof(XAsset)); + m_stream->Align(4); varXAsset = varXAssetList->assets; WriteXAssetArray(true, varXAssetList->assetCount); - m_stream->MarkFollowing(varXAssetList->assets); + +#ifdef ARCH_x86 + static_assert(offsetof(XAssetList, assets) == 12u); +#endif + m_stream->MarkFollowing(varXAssetListWritten.WithInnerOffset(12)); } m_stream->PopBlock(); diff --git a/src/ZoneWriting/Game/IW3/ContentWriterIW3.h b/src/ZoneWriting/Game/IW3/ContentWriterIW3.h index 195df96c..b604fdf8 100644 --- a/src/ZoneWriting/Game/IW3/ContentWriterIW3.h +++ b/src/ZoneWriting/Game/IW3/ContentWriterIW3.h @@ -24,5 +24,9 @@ namespace IW3 XAssetList* varXAssetList; XAsset* varXAsset; ScriptStringList* varScriptStringList; + + ZoneOutputOffset varXAssetListWritten; + ZoneOutputOffset varXAssetWritten; + ZoneOutputOffset varScriptStringListWritten; }; } // namespace IW3 diff --git a/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp b/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp index 36592259..b6f12ad2 100644 --- a/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp +++ b/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp @@ -60,15 +60,18 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart) m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); if (atStreamStart) - varScriptStringList = m_stream->Write(varScriptStringList); + varScriptStringListWritten = m_stream->Write(varScriptStringList); if (varScriptStringList->strings != nullptr) { - m_stream->Align(alignof(const char*)); + m_stream->Align(4); varXString = varScriptStringList->strings; WriteXStringArray(true, varScriptStringList->count); - m_stream->MarkFollowing(varScriptStringList->strings); +#ifdef ARCH_x86 + static_assert(offsetof(ScriptStringList, strings) == 4u); +#endif + m_stream->MarkFollowing(varScriptStringListWritten.WithInnerOffset(4)); } m_stream->PopBlock(); @@ -90,7 +93,7 @@ void ContentWriter::WriteXAsset(const bool atStreamStart) assert(varXAsset != nullptr); if (atStreamStart) - varXAsset = m_stream->Write(varXAsset); + varXAssetWritten = m_stream->Write(varXAsset); switch (varXAsset->type) { @@ -147,12 +150,17 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun assert(varXAsset != nullptr); if (atStreamStart) - varXAsset = m_stream->Write(varXAsset, count); + varXAssetWritten = m_stream->Write(varXAsset, count); for (size_t index = 0; index < count; index++) { WriteXAsset(false); varXAsset++; + +#ifdef ARCH_x86 + static_assert(sizeof(XAsset) == 8u); +#endif + varXAssetWritten.Inc(8u); } } @@ -167,17 +175,26 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream) CreateXAssetList(assetList, memory); - varXAssetList = static_cast(m_stream->WriteDataRaw(&assetList, sizeof(assetList))); + varXAssetList = &assetList; + varXAssetListWritten = m_stream->WriteDataRaw(&assetList, sizeof(assetList)); +#ifdef ARCH_x86 + static_assert(offsetof(XAssetList, stringList) == 0u); +#endif varScriptStringList = &varXAssetList->stringList; + varScriptStringListWritten = varXAssetListWritten.WithInnerOffset(0); WriteScriptStringList(false); if (varXAssetList->assets != nullptr) { - m_stream->Align(alignof(XAsset)); + m_stream->Align(4); varXAsset = varXAssetList->assets; WriteXAssetArray(true, varXAssetList->assetCount); - m_stream->MarkFollowing(varXAssetList->assets); + +#ifdef ARCH_x86 + static_assert(offsetof(XAssetList, assets) == 12u); +#endif + m_stream->MarkFollowing(varXAssetListWritten.WithInnerOffset(12)); } m_stream->PopBlock(); diff --git a/src/ZoneWriting/Game/IW4/ContentWriterIW4.h b/src/ZoneWriting/Game/IW4/ContentWriterIW4.h index e5212c60..101c8041 100644 --- a/src/ZoneWriting/Game/IW4/ContentWriterIW4.h +++ b/src/ZoneWriting/Game/IW4/ContentWriterIW4.h @@ -24,5 +24,9 @@ namespace IW4 XAssetList* varXAssetList; XAsset* varXAsset; ScriptStringList* varScriptStringList; + + ZoneOutputOffset varXAssetListWritten; + ZoneOutputOffset varXAssetWritten; + ZoneOutputOffset varScriptStringListWritten; }; } // namespace IW4 diff --git a/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp b/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp index b5ecf4b2..554ad4c0 100644 --- a/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp +++ b/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp @@ -60,15 +60,18 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart) m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); if (atStreamStart) - varScriptStringList = m_stream->Write(varScriptStringList); + varScriptStringListWritten = m_stream->Write(varScriptStringList); if (varScriptStringList->strings != nullptr) { - m_stream->Align(alignof(const char*)); + m_stream->Align(4); varXString = varScriptStringList->strings; WriteXStringArray(true, varScriptStringList->count); - m_stream->MarkFollowing(varScriptStringList->strings); +#ifdef ARCH_x86 + static_assert(offsetof(ScriptStringList, strings) == 4u); +#endif + m_stream->MarkFollowing(varScriptStringListWritten.WithInnerOffset(4)); } m_stream->PopBlock(); @@ -90,7 +93,7 @@ void ContentWriter::WriteXAsset(const bool atStreamStart) assert(varXAsset != nullptr); if (atStreamStart) - varXAsset = m_stream->Write(varXAsset); + varXAssetWritten = m_stream->Write(varXAsset); switch (varXAsset->type) { @@ -150,12 +153,17 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun assert(varXAsset != nullptr); if (atStreamStart) - varXAsset = m_stream->Write(varXAsset, count); + varXAssetWritten = m_stream->Write(varXAsset, count); for (size_t index = 0; index < count; index++) { WriteXAsset(false); varXAsset++; + +#ifdef ARCH_x86 + static_assert(sizeof(XAsset) == 8u); +#endif + varXAssetWritten.Inc(8u); } } @@ -170,17 +178,26 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream) CreateXAssetList(assetList, memory); - varXAssetList = static_cast(m_stream->WriteDataRaw(&assetList, sizeof(assetList))); + varXAssetList = &assetList; + varXAssetListWritten = m_stream->WriteDataRaw(&assetList, sizeof(assetList)); +#ifdef ARCH_x86 + static_assert(offsetof(XAssetList, stringList) == 0u); +#endif varScriptStringList = &varXAssetList->stringList; + varScriptStringListWritten = varXAssetListWritten.WithInnerOffset(0); WriteScriptStringList(false); if (varXAssetList->assets != nullptr) { - m_stream->Align(alignof(XAsset)); + m_stream->Align(4); varXAsset = varXAssetList->assets; WriteXAssetArray(true, varXAssetList->assetCount); - m_stream->MarkFollowing(varXAssetList->assets); + +#ifdef ARCH_x86 + static_assert(offsetof(XAssetList, assets) == 12u); +#endif + m_stream->MarkFollowing(varXAssetListWritten.WithInnerOffset(12)); } m_stream->PopBlock(); diff --git a/src/ZoneWriting/Game/IW5/ContentWriterIW5.h b/src/ZoneWriting/Game/IW5/ContentWriterIW5.h index 6bf2ace2..82830b08 100644 --- a/src/ZoneWriting/Game/IW5/ContentWriterIW5.h +++ b/src/ZoneWriting/Game/IW5/ContentWriterIW5.h @@ -24,5 +24,9 @@ namespace IW5 XAssetList* varXAssetList; XAsset* varXAsset; ScriptStringList* varScriptStringList; + + ZoneOutputOffset varXAssetListWritten; + ZoneOutputOffset varXAssetWritten; + ZoneOutputOffset varScriptStringListWritten; }; } // namespace IW5 diff --git a/src/ZoneWriting/Game/T5/ContentWriterT5.cpp b/src/ZoneWriting/Game/T5/ContentWriterT5.cpp index 8c0c2ce6..ae2c40ce 100644 --- a/src/ZoneWriting/Game/T5/ContentWriterT5.cpp +++ b/src/ZoneWriting/Game/T5/ContentWriterT5.cpp @@ -60,15 +60,18 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart) m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); if (atStreamStart) - varScriptStringList = m_stream->Write(varScriptStringList); + varScriptStringListWritten = m_stream->Write(varScriptStringList); if (varScriptStringList->strings != nullptr) { - m_stream->Align(alignof(const char*)); + m_stream->Align(4); varXString = varScriptStringList->strings; WriteXStringArray(true, varScriptStringList->count); - m_stream->MarkFollowing(varScriptStringList->strings); +#ifdef ARCH_x86 + static_assert(offsetof(ScriptStringList, strings) == 4u); +#endif + m_stream->MarkFollowing(varScriptStringListWritten.WithInnerOffset(4)); } m_stream->PopBlock(); @@ -90,7 +93,7 @@ void ContentWriter::WriteXAsset(const bool atStreamStart) assert(varXAsset != nullptr); if (atStreamStart) - varXAsset = m_stream->Write(varXAsset); + varXAssetWritten = m_stream->Write(varXAsset); switch (varXAsset->type) { @@ -143,12 +146,17 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun assert(varXAsset != nullptr); if (atStreamStart) - varXAsset = m_stream->Write(varXAsset, count); + varXAssetWritten = m_stream->Write(varXAsset, count); for (size_t index = 0; index < count; index++) { WriteXAsset(false); varXAsset++; + +#ifdef ARCH_x86 + static_assert(sizeof(XAsset) == 8u); +#endif + varXAssetWritten.Inc(8u); } } @@ -163,17 +171,26 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream) CreateXAssetList(assetList, memory); - varXAssetList = static_cast(m_stream->WriteDataRaw(&assetList, sizeof(assetList))); + varXAssetList = &assetList; + varXAssetListWritten = m_stream->WriteDataRaw(&assetList, sizeof(assetList)); +#ifdef ARCH_x86 + static_assert(offsetof(XAssetList, stringList) == 0u); +#endif varScriptStringList = &varXAssetList->stringList; + varScriptStringListWritten = varXAssetListWritten.WithInnerOffset(0); WriteScriptStringList(false); if (varXAssetList->assets != nullptr) { - m_stream->Align(alignof(XAsset)); + m_stream->Align(4); varXAsset = varXAssetList->assets; WriteXAssetArray(true, varXAssetList->assetCount); - m_stream->MarkFollowing(varXAssetList->assets); + +#ifdef ARCH_x86 + static_assert(offsetof(XAssetList, assets) == 12u); +#endif + m_stream->MarkFollowing(varXAssetListWritten.WithInnerOffset(12)); } m_stream->PopBlock(); diff --git a/src/ZoneWriting/Game/T5/ContentWriterT5.h b/src/ZoneWriting/Game/T5/ContentWriterT5.h index 1c0cc137..094c5e62 100644 --- a/src/ZoneWriting/Game/T5/ContentWriterT5.h +++ b/src/ZoneWriting/Game/T5/ContentWriterT5.h @@ -24,5 +24,9 @@ namespace T5 XAssetList* varXAssetList; XAsset* varXAsset; ScriptStringList* varScriptStringList; + + ZoneOutputOffset varXAssetListWritten; + ZoneOutputOffset varXAssetWritten; + ZoneOutputOffset varScriptStringListWritten; }; } // namespace T5 diff --git a/src/ZoneWriting/Game/T6/ContentWriterT6.cpp b/src/ZoneWriting/Game/T6/ContentWriterT6.cpp index 234f80f5..c9544b45 100644 --- a/src/ZoneWriting/Game/T6/ContentWriterT6.cpp +++ b/src/ZoneWriting/Game/T6/ContentWriterT6.cpp @@ -63,15 +63,18 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart) m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); if (atStreamStart) - varScriptStringList = m_stream->Write(varScriptStringList); + varScriptStringListWritten = m_stream->Write(varScriptStringList); if (varScriptStringList->strings != nullptr) { - m_stream->Align(alignof(const char*)); + m_stream->Align(4); varXString = varScriptStringList->strings; WriteXStringArray(true, varScriptStringList->count); - m_stream->MarkFollowing(varScriptStringList->strings); +#ifdef ARCH_x86 + static_assert(offsetof(ScriptStringList, strings) == 4u); +#endif + m_stream->MarkFollowing(varScriptStringListWritten.WithInnerOffset(4)); } m_stream->PopBlock(); @@ -90,7 +93,7 @@ void ContentWriter::WriteXAsset(const bool atStreamStart) assert(varXAsset != nullptr); if (atStreamStart) - varXAsset = m_stream->Write(varXAsset); + varXAssetWritten = m_stream->Write(varXAsset); switch (varXAsset->type) { @@ -158,12 +161,17 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun assert(varXAsset != nullptr); if (atStreamStart) - varXAsset = m_stream->Write(varXAsset, count); + varXAssetWritten = m_stream->Write(varXAsset, count); for (size_t index = 0; index < count; index++) { WriteXAsset(false); varXAsset++; + +#ifdef ARCH_x86 + static_assert(sizeof(XAsset) == 8u); +#endif + varXAssetWritten.Inc(8u); } } @@ -178,25 +186,38 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream) CreateXAssetList(assetList, memory); - varXAssetList = static_cast(m_stream->WriteDataRaw(&assetList, sizeof(assetList))); + varXAssetList = &assetList; + varXAssetListWritten = m_stream->WriteDataRaw(&assetList, sizeof(assetList)); +#ifdef ARCH_x86 + static_assert(offsetof(XAssetList, stringList) == 0u); +#endif varScriptStringList = &varXAssetList->stringList; + varScriptStringListWritten = varXAssetListWritten.WithInnerOffset(0); WriteScriptStringList(false); if (varXAssetList->depends != nullptr) { - m_stream->Align(alignof(const char*)); + m_stream->Align(4); varXString = varXAssetList->depends; WriteXStringArray(true, varXAssetList->dependCount); - m_stream->MarkFollowing(varXAssetList->depends); + +#ifdef ARCH_x86 + static_assert(offsetof(XAssetList, depends) == 12u); +#endif + m_stream->MarkFollowing(varXAssetListWritten.WithInnerOffset(12)); } if (varXAssetList->assets != nullptr) { - m_stream->Align(alignof(XAsset)); + m_stream->Align(4); varXAsset = varXAssetList->assets; WriteXAssetArray(true, varXAssetList->assetCount); - m_stream->MarkFollowing(varXAssetList->assets); + +#ifdef ARCH_x86 + static_assert(offsetof(XAssetList, assets) == 20u); +#endif + m_stream->MarkFollowing(varXAssetListWritten.WithInnerOffset(20)); } m_stream->PopBlock(); diff --git a/src/ZoneWriting/Game/T6/ContentWriterT6.h b/src/ZoneWriting/Game/T6/ContentWriterT6.h index 4bb08580..7fb5ce20 100644 --- a/src/ZoneWriting/Game/T6/ContentWriterT6.h +++ b/src/ZoneWriting/Game/T6/ContentWriterT6.h @@ -24,5 +24,9 @@ namespace T6 XAssetList* varXAssetList; XAsset* varXAsset; ScriptStringList* varScriptStringList; + + ZoneOutputOffset varXAssetListWritten; + ZoneOutputOffset varXAssetWritten; + ZoneOutputOffset varScriptStringListWritten; }; } // namespace T6 diff --git a/src/ZoneWriting/Writing/AssetWriter.cpp b/src/ZoneWriting/Writing/AssetWriter.cpp index e052927e..ecd8d70c 100644 --- a/src/ZoneWriting/Writing/AssetWriter.cpp +++ b/src/ZoneWriting/Writing/AssetWriter.cpp @@ -38,12 +38,13 @@ void AssetWriter::WriteScriptStringArray(const bool atStreamStart, const size_t varScriptStringWritten = m_stream->Write(varScriptString, count); } - assert(varScriptStringWritten != nullptr); + assert(varScriptStringWritten.Offset() != nullptr); - auto* ptr = varScriptStringWritten; for (size_t index = 0; index < count; index++) { - *ptr = UseScriptString(*ptr); - ptr++; + *static_cast(varScriptStringWritten.Offset()) = UseScriptString(*varScriptString); + + varScriptString++; + varScriptStringWritten.Inc(sizeof(scr_string_t)); } } diff --git a/src/ZoneWriting/Writing/AssetWriter.h b/src/ZoneWriting/Writing/AssetWriter.h index b3357054..10220241 100644 --- a/src/ZoneWriting/Writing/AssetWriter.h +++ b/src/ZoneWriting/Writing/AssetWriter.h @@ -17,5 +17,5 @@ protected: XAssetInfoGeneric* m_asset; scr_string_t* varScriptString; - scr_string_t* varScriptStringWritten; + ZoneOutputOffset varScriptStringWritten; }; diff --git a/src/ZoneWriting/Writing/ContentWriterBase.cpp b/src/ZoneWriting/Writing/ContentWriterBase.cpp index 71f603d9..b4b52a42 100644 --- a/src/ZoneWriting/Writing/ContentWriterBase.cpp +++ b/src/ZoneWriting/Writing/ContentWriterBase.cpp @@ -26,15 +26,15 @@ void ContentWriterBase::WriteXString(const bool atStreamStart) varXStringWritten = m_stream->Write(varXString); } - assert(varXStringWritten != nullptr); + assert(varXStringWritten.Offset() != nullptr); - if (m_stream->ReusableShouldWrite(varXStringWritten)) + if (m_stream->ReusableShouldWrite(*varXString, varXStringWritten)) { - m_stream->Align(alignof(const char)); - m_stream->ReusableAddOffset(*varXStringWritten); - m_stream->WriteNullTerminated(*varXStringWritten); + m_stream->Align(1); + m_stream->ReusableAddOffset(*varXString); + m_stream->WriteNullTerminated(*varXString); - m_stream->MarkFollowing(*varXStringWritten); + m_stream->MarkFollowing(varXStringWritten); } } @@ -46,11 +46,12 @@ void ContentWriterBase::WriteXStringArray(const bool atStreamStart, const size_t varXStringWritten = m_stream->Write(varXString, count); } - assert(varXStringWritten != nullptr); + assert(varXStringWritten.Offset() != nullptr); for (size_t index = 0; index < count; index++) { WriteXString(false); - varXStringWritten++; + varXString++; + varXStringWritten.Inc(m_stream->GetPointerByteCount()); } } diff --git a/src/ZoneWriting/Writing/ContentWriterBase.h b/src/ZoneWriting/Writing/ContentWriterBase.h index 9a58959d..47da7b56 100644 --- a/src/ZoneWriting/Writing/ContentWriterBase.h +++ b/src/ZoneWriting/Writing/ContentWriterBase.h @@ -24,5 +24,5 @@ protected: ZoneOutputStream* m_stream; const char** varXString; - const char** varXStringWritten; + ZoneOutputOffset varXStringWritten; }; diff --git a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp index 836a3d2e..d8a209be 100644 --- a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp +++ b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp @@ -44,7 +44,13 @@ namespace : m_zone_data(zoneData), m_blocks(blocks), m_block_bit_count(blockBitCount), - m_pointer_byte_count(pointerBitCount / 8u) + m_pointer_byte_count(pointerBitCount / 8u), + + // -1 + m_zone_ptr_following(std::numeric_limits::max() >> ((sizeof(std::uintptr_t) * 8u) - pointerBitCount)), + + // -2 + m_zone_ptr_insert((std::numeric_limits::max() >> ((sizeof(std::uintptr_t) * 8u) - pointerBitCount)) - 1u) { assert(pointerBitCount % 8u == 0u); assert(insertBlock < static_cast(blocks.size())); @@ -52,9 +58,9 @@ namespace m_insert_block = blocks[insertBlock]; } - [[nodiscard]] unsigned GetPointerBitCount() const override + [[nodiscard]] unsigned GetPointerByteCount() const override { - return m_pointer_byte_count * 8u; + return m_pointer_byte_count; } void PushBlock(const block_t block) override @@ -113,19 +119,20 @@ namespace } } - void* WriteDataRaw(const void* src, const size_t size) override + ZoneOutputOffset WriteDataRaw(const void* src, const size_t size) override { auto* result = m_zone_data.GetBufferOfSize(size); memcpy(result, src, size); - return result; + + return ZoneOutputOffset(result); } - void* WriteDataInBlock(const void* src, const size_t size) override + ZoneOutputOffset WriteDataInBlock(const void* src, const size_t size) override { assert(!m_block_stack.empty()); if (m_block_stack.empty()) - return nullptr; + return ZoneOutputOffset(); const auto* block = m_block_stack.top(); @@ -147,7 +154,8 @@ namespace } IncBlockPos(size); - return result; + + return ZoneOutputOffset(result); } void IncBlockPos(const size_t size) override @@ -174,19 +182,30 @@ namespace WriteDataInBlock(src, len + 1); } - void MarkFollowing(void** pPtr) override + void MarkFollowing(const ZoneOutputOffset outputOffset) override { assert(!m_block_stack.empty()); - assert(pPtr != nullptr); - *pPtr = m_block_stack.top()->m_type == XBlockType::BLOCK_TYPE_TEMP ? PTR_INSERT : PTR_FOLLOWING; + + auto* ptr = static_cast(outputOffset.Offset()); + assert(ptr != nullptr); + + if (m_block_stack.top()->m_type == XBlockType::BLOCK_TYPE_TEMP) + { + for (auto i = 0u; i < m_pointer_byte_count; i++) + ptr[i] = reinterpret_cast(&m_zone_ptr_insert)[i]; + } + else + { + for (auto i = 0u; i < m_pointer_byte_count; i++) + ptr[i] = reinterpret_cast(&m_zone_ptr_following)[i]; + } } - bool ReusableShouldWrite(void** pPtr, const size_t entrySize, const std::type_index type) override + bool ReusableShouldWrite(void* ptr, const ZoneOutputOffset outputOffset, const size_t entrySize, const std::type_index type) override { assert(!m_block_stack.empty()); - assert(pPtr != nullptr); - if (*pPtr == nullptr) + if (ptr == nullptr) return false; const auto foundEntriesForType = m_reusable_entries.find(type); @@ -197,11 +216,14 @@ namespace for (const auto& entry : foundEntriesForType->second) { - if (*pPtr >= entry.m_start_ptr && *pPtr < entry.m_end_ptr) + if (ptr >= entry.m_start_ptr && ptr < entry.m_end_ptr) { - assert((reinterpret_cast(*pPtr) - reinterpret_cast(entry.m_start_ptr)) % entrySize == 0); - *pPtr = - reinterpret_cast(entry.m_start_zone_ptr + (reinterpret_cast(*pPtr) - reinterpret_cast(entry.m_start_ptr))); + assert((reinterpret_cast(ptr) - reinterpret_cast(entry.m_start_ptr)) % entrySize == 0); + const auto finalZonePointer = entry.m_start_zone_ptr + (reinterpret_cast(ptr) - reinterpret_cast(entry.m_start_ptr)); + + for (auto i = 0u; i < m_pointer_byte_count; i++) + static_cast(ptr)[i] = reinterpret_cast(&finalZonePointer)[i]; + return false; } } @@ -265,10 +287,38 @@ namespace unsigned m_pointer_byte_count; XBlock* m_insert_block; + uintptr_t m_zone_ptr_following; + uintptr_t m_zone_ptr_insert; + std::unordered_map> m_reusable_entries; }; } // namespace +ZoneOutputOffset::ZoneOutputOffset() + : m_offset(nullptr) +{ +} + +ZoneOutputOffset::ZoneOutputOffset(void* offset) + : m_offset(offset) +{ +} + +void* ZoneOutputOffset::Offset() const +{ + return m_offset; +} + +void ZoneOutputOffset::Inc(const size_t size) +{ + m_offset = static_cast(static_cast(m_offset) + size); +} + +ZoneOutputOffset ZoneOutputOffset::WithInnerOffset(const size_t innerOffset) const +{ + return ZoneOutputOffset(static_cast(m_offset) + innerOffset); +} + std::unique_ptr ZoneOutputStream::Create(unsigned pointerBitCount, unsigned blockBitCount, std::vector& blocks, block_t insertBlock, InMemoryZoneData& zoneData) { diff --git a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h index 95981657..3b6aa2ff 100644 --- a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h +++ b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h @@ -10,13 +10,27 @@ #include #include +class ZoneOutputOffset +{ +public: + ZoneOutputOffset(); + explicit ZoneOutputOffset(void* offset); + + [[nodiscard]] void* Offset() const; + void Inc(size_t size); + [[nodiscard]] ZoneOutputOffset WithInnerOffset(size_t innerOffset) const; + +private: + void* m_offset; +}; + class ZoneOutputStream : public IZoneStream { public: /** * \brief Returns the configured bits that make up a pointer. */ - [[nodiscard]] virtual unsigned GetPointerBitCount() const = 0; + [[nodiscard]] virtual unsigned GetPointerByteCount() const = 0; /** * \brief Aligns the write position in the current block with the specified value. @@ -31,7 +45,7 @@ public: * \param dst The memory location to write data to. * \param size The amount of data to write. */ - virtual void* WriteDataRaw(const void* dst, size_t size) = 0; + virtual ZoneOutputOffset WriteDataRaw(const void* dst, size_t size) = 0; /** * \brief Write data with the current blocks write operation into its block memory. @@ -41,17 +55,17 @@ public: * \param dst The destination where the data is written to. Must be inside the current block's memory bounds. * \param size The amount of data to write. */ - virtual void* WriteDataInBlock(const void* dst, size_t size) = 0; + virtual ZoneOutputOffset WriteDataInBlock(const void* dst, size_t size) = 0; virtual void IncBlockPos(size_t size) = 0; virtual void WriteNullTerminated(const void* dst) = 0; - virtual bool ReusableShouldWrite(void** pPtr, size_t size, std::type_index type) = 0; + virtual bool ReusableShouldWrite(void* pPtr, ZoneOutputOffset outputOffset, size_t size, std::type_index type) = 0; virtual void ReusableAddOffset(void* ptr, size_t size, size_t count, std::type_index type) = 0; - virtual void MarkFollowing(void** pPtr) = 0; + virtual void MarkFollowing(ZoneOutputOffset offset) = 0; - template bool ReusableShouldWrite(T** pPtr) + template bool ReusableShouldWrite(T* pPtr, const ZoneOutputOffset outputOffset) { - return ReusableShouldWrite(reinterpret_cast(reinterpret_cast(pPtr)), sizeof(T), std::type_index(typeid(T))); + return ReusableShouldWrite(const_cast(reinterpret_cast(pPtr)), outputOffset, sizeof(T), std::type_index(typeid(T))); } template void ReusableAddOffset(T* ptr) @@ -64,24 +78,19 @@ public: ReusableAddOffset(const_cast(reinterpret_cast(ptr)), sizeof(T), count, std::type_index(typeid(T))); } - template T* Write(T* dst) + template ZoneOutputOffset Write(T* dst) { - return static_cast(WriteDataInBlock(reinterpret_cast(dst), sizeof(T))); + return WriteDataInBlock(reinterpret_cast(dst), sizeof(T)); } - template T* Write(T* dst, const size_t count) + template ZoneOutputOffset Write(T* dst, const size_t count) { - return static_cast(WriteDataInBlock(reinterpret_cast(dst), count * sizeof(T))); + return WriteDataInBlock(reinterpret_cast(dst), count * sizeof(T)); } - template T* WritePartial(T* dst, const size_t size) + ZoneOutputOffset WritePartial(const void* dst, const size_t size) { - return static_cast(WriteDataInBlock(reinterpret_cast(dst), size)); - } - - template void MarkFollowing(T*& ptr) - { - MarkFollowing(reinterpret_cast(reinterpret_cast(&ptr))); + return WriteDataInBlock(dst, size); } static std::unique_ptr From 2b2590b8fbb2c5c67124f82b063bf51c38c717cd Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 9 Jan 2026 18:18:18 +0000 Subject: [PATCH 06/20] fix: not correctly returning bad result for failed zone loading --- src/ZoneLoading/ZoneLoading.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ZoneLoading/ZoneLoading.cpp b/src/ZoneLoading/ZoneLoading.cpp index e7d4962b..49e267da 100644 --- a/src/ZoneLoading/ZoneLoading.cpp +++ b/src/ZoneLoading/ZoneLoading.cpp @@ -7,7 +7,9 @@ #include #include #include +#include +using namespace std::string_literals; namespace fs = std::filesystem; result::Expected, std::string> ZoneLoading::LoadZone(const std::string& path, @@ -41,5 +43,9 @@ result::Expected, std::string> ZoneLoading::LoadZone(const auto loadedZone = zoneLoader->LoadZone(file); file.close(); + + if (!loadedZone) + return result::Unexpected("Loading zone failed."s); + return std::move(loadedZone); } From 6ea2e7faadf28e6f5a919c385ec47122ac31e360 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 9 Jan 2026 17:41:03 +0000 Subject: [PATCH 07/20] refactor: use ZoneOutputOffset for written variables --- .../Generating/BaseRenderingContext.cpp | 21 +++ .../Generating/BaseRenderingContext.h | 21 +++ .../OncePerAssetRenderingContext.cpp | 9 +- .../Generating/OncePerAssetRenderingContext.h | 11 +- .../OncePerTemplateRenderingContext.cpp | 9 +- .../OncePerTemplateRenderingContext.h | 10 +- .../Templates/AssetStructTestsTemplate.cpp | 2 +- .../Templates/Internal/BaseTemplate.cpp | 84 +++++----- .../Templates/Internal/BaseTemplate.h | 20 ++- .../Generating/Templates/ZoneLoadTemplate.cpp | 47 +----- .../Generating/Templates/ZoneMarkTemplate.cpp | 4 +- .../Templates/ZoneWriteTemplate.cpp | 154 ++++++++++++------ src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp | 5 +- src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp | 5 +- src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp | 5 +- src/ZoneWriting/Game/T5/ContentWriterT5.cpp | 5 +- src/ZoneWriting/Game/T6/ContentWriterT6.cpp | 5 +- src/ZoneWriting/Writing/AssetWriter.cpp | 8 +- src/ZoneWriting/Writing/AssetWriter.h | 2 +- .../Zone/Stream/ZoneOutputStream.cpp | 3 +- 20 files changed, 241 insertions(+), 189 deletions(-) create mode 100644 src/ZoneCodeGeneratorLib/Generating/BaseRenderingContext.cpp create mode 100644 src/ZoneCodeGeneratorLib/Generating/BaseRenderingContext.h diff --git a/src/ZoneCodeGeneratorLib/Generating/BaseRenderingContext.cpp b/src/ZoneCodeGeneratorLib/Generating/BaseRenderingContext.cpp new file mode 100644 index 00000000..24a79bce --- /dev/null +++ b/src/ZoneCodeGeneratorLib/Generating/BaseRenderingContext.cpp @@ -0,0 +1,21 @@ +#include "BaseRenderingContext.h" + +BaseRenderingContext::BaseRenderingContext(std::string game, const Architecture gameArchitecture, std::vector fastFileBlocks) + : m_game(std::move(game)), + m_architecture_mismatch(gameArchitecture != OWN_ARCHITECTURE), + m_pointer_size(GetPointerSizeForArchitecture(gameArchitecture)), + m_blocks(std::move(fastFileBlocks)), + m_default_normal_block(nullptr), + m_default_temp_block(nullptr) +{ + for (const auto* block : m_blocks) + { + if (block->m_is_default) + { + if (block->m_type == FastFileBlockType::NORMAL && m_default_normal_block == nullptr) + m_default_normal_block = block; + else if (block->m_type == FastFileBlockType::TEMP && m_default_temp_block == nullptr) + m_default_temp_block = block; + } + } +} diff --git a/src/ZoneCodeGeneratorLib/Generating/BaseRenderingContext.h b/src/ZoneCodeGeneratorLib/Generating/BaseRenderingContext.h new file mode 100644 index 00000000..4d5949f3 --- /dev/null +++ b/src/ZoneCodeGeneratorLib/Generating/BaseRenderingContext.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Persistence/IDataRepository.h" + +#include +#include + +class BaseRenderingContext +{ +public: + std::string m_game; + bool m_architecture_mismatch; + unsigned m_pointer_size; + std::vector m_blocks; + + const FastFileBlock* m_default_normal_block; + const FastFileBlock* m_default_temp_block; + +protected: + BaseRenderingContext(std::string game, Architecture gameArchitecture, std::vector fastFileBlocks); +}; diff --git a/src/ZoneCodeGeneratorLib/Generating/OncePerAssetRenderingContext.cpp b/src/ZoneCodeGeneratorLib/Generating/OncePerAssetRenderingContext.cpp index 1eed2adf..0152888a 100644 --- a/src/ZoneCodeGeneratorLib/Generating/OncePerAssetRenderingContext.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/OncePerAssetRenderingContext.cpp @@ -21,14 +21,9 @@ RenderingUsedType::RenderingUsedType(const DataDefinition* type, StructureInform OncePerAssetRenderingContext::OncePerAssetRenderingContext(std::string game, const Architecture gameArchitecture, std::vector fastFileBlocks) - : m_game(std::move(game)), - m_architecture_mismatch(gameArchitecture != OWN_ARCHITECTURE), - m_pointer_size(GetPointerSizeForArchitecture(gameArchitecture)), - m_blocks(std::move(fastFileBlocks)), + : BaseRenderingContext(std::move(game), gameArchitecture, std::move(fastFileBlocks)), m_asset(nullptr), - m_has_actions(false), - m_default_normal_block(nullptr), - m_default_temp_block(nullptr) + m_has_actions(false) { for (const auto* block : m_blocks) { diff --git a/src/ZoneCodeGeneratorLib/Generating/OncePerAssetRenderingContext.h b/src/ZoneCodeGeneratorLib/Generating/OncePerAssetRenderingContext.h index 62bb914a..2ffbb9bf 100644 --- a/src/ZoneCodeGeneratorLib/Generating/OncePerAssetRenderingContext.h +++ b/src/ZoneCodeGeneratorLib/Generating/OncePerAssetRenderingContext.h @@ -1,5 +1,6 @@ #pragma once +#include "BaseRenderingContext.h" #include "Domain/Computations/MemberComputations.h" #include "Domain/Information/StructureInformation.h" #include "Persistence/IDataRepository.h" @@ -24,16 +25,11 @@ public: bool m_pointer_array_reference_is_reusable; }; -class OncePerAssetRenderingContext +class OncePerAssetRenderingContext : public BaseRenderingContext { public: static std::unique_ptr BuildContext(const IDataRepository* repository, StructureInformation* asset); - std::string m_game; - bool m_architecture_mismatch; - unsigned m_pointer_size; - std::vector m_blocks; - StructureInformation* m_asset; std::vector m_used_types; @@ -41,9 +37,6 @@ public: std::vector m_referenced_assets; bool m_has_actions; - const FastFileBlock* m_default_normal_block; - const FastFileBlock* m_default_temp_block; - private: OncePerAssetRenderingContext(std::string game, Architecture gameArchitecture, std::vector fastFileBlocks); diff --git a/src/ZoneCodeGeneratorLib/Generating/OncePerTemplateRenderingContext.cpp b/src/ZoneCodeGeneratorLib/Generating/OncePerTemplateRenderingContext.cpp index bbc2c17b..3985e4a5 100644 --- a/src/ZoneCodeGeneratorLib/Generating/OncePerTemplateRenderingContext.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/OncePerTemplateRenderingContext.cpp @@ -8,13 +8,8 @@ OncePerTemplateRenderingContext::OncePerTemplateRenderingContext(std::string gam const Architecture gameArchitecture, std::vector fastFileBlocks, std::vector assets) - : m_game(std::move(game)), - m_architecture_mismatch(gameArchitecture != OWN_ARCHITECTURE), - m_pointer_size(GetPointerSizeForArchitecture(gameArchitecture)), - m_blocks(std::move(fastFileBlocks)), - m_assets(std::move(assets)), - m_default_normal_block(nullptr), - m_default_temp_block(nullptr) + : BaseRenderingContext(std::move(game), gameArchitecture, std::move(fastFileBlocks)), + m_assets(std::move(assets)) { for (const auto* block : m_blocks) { diff --git a/src/ZoneCodeGeneratorLib/Generating/OncePerTemplateRenderingContext.h b/src/ZoneCodeGeneratorLib/Generating/OncePerTemplateRenderingContext.h index 8f619916..3b1adc04 100644 --- a/src/ZoneCodeGeneratorLib/Generating/OncePerTemplateRenderingContext.h +++ b/src/ZoneCodeGeneratorLib/Generating/OncePerTemplateRenderingContext.h @@ -1,24 +1,18 @@ #pragma once +#include "BaseRenderingContext.h" #include "Persistence/IDataRepository.h" #include #include -class OncePerTemplateRenderingContext +class OncePerTemplateRenderingContext : public BaseRenderingContext { public: static std::unique_ptr BuildContext(const IDataRepository* repository); - std::string m_game; - bool m_architecture_mismatch; - unsigned m_pointer_size; - std::vector m_blocks; std::vector m_assets; - const FastFileBlock* m_default_normal_block; - const FastFileBlock* m_default_temp_block; - private: OncePerTemplateRenderingContext(std::string game, Architecture gameArchitecture, diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/AssetStructTestsTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/AssetStructTestsTemplate.cpp index 4cfa9078..1b851e06 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/AssetStructTestsTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/AssetStructTestsTemplate.cpp @@ -15,7 +15,7 @@ namespace { public: PerAsset(std::ostream& stream, const OncePerAssetRenderingContext& context) - : BaseTemplate(stream), + : BaseTemplate(stream, context), m_env(context) { } diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.cpp index 89b535cb..b9a3778b 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.cpp @@ -5,9 +5,10 @@ #include -BaseTemplate::BaseTemplate(std::ostream& stream) +BaseTemplate::BaseTemplate(std::ostream& stream, const BaseRenderingContext& context) : m_out(stream), - m_intendation(0u) + m_intendation(0u), + m_env(context) { } @@ -61,13 +62,6 @@ void BaseTemplate::MakeTypeVarNameInternal(const DataDefinition* def, std::ostri MakeSafeTypeNameInternal(def, str); } -void BaseTemplate::MakeTypeWrittenVarNameInternal(const DataDefinition* def, std::ostringstream& str) -{ - str << "var"; - MakeSafeTypeNameInternal(def, str); - str << "Written"; -} - void BaseTemplate::MakeTypePtrVarNameInternal(const DataDefinition* def, std::ostringstream& str) { str << "var"; @@ -75,13 +69,6 @@ void BaseTemplate::MakeTypePtrVarNameInternal(const DataDefinition* def, std::os str << "Ptr"; } -void BaseTemplate::MakeTypeWrittenPtrVarNameInternal(const DataDefinition* def, std::ostringstream& str) -{ - str << "var"; - MakeSafeTypeNameInternal(def, str); - str << "PtrWritten"; -} - void BaseTemplate::MakeArrayIndicesInternal(const DeclarationModifierComputations& modifierComputations, std::ostringstream& str) { for (const auto index : modifierComputations.GetArrayIndices()) @@ -97,13 +84,6 @@ std::string BaseTemplate::MakeTypeVarName(const DataDefinition* def) return str.str(); } -std::string BaseTemplate::MakeTypeWrittenVarName(const DataDefinition* def) -{ - std::ostringstream str; - MakeTypeWrittenVarNameInternal(def, str); - return str.str(); -} - std::string BaseTemplate::MakeTypePtrVarName(const DataDefinition* def) { std::ostringstream str; @@ -111,13 +91,6 @@ std::string BaseTemplate::MakeTypePtrVarName(const DataDefinition* def) return str.str(); } -std::string BaseTemplate::MakeTypeWrittenPtrVarName(const DataDefinition* def) -{ - std::ostringstream str; - MakeTypeWrittenPtrVarNameInternal(def, str); - return str.str(); -} - std::string BaseTemplate::MakeSafeTypeName(const DataDefinition* def) { std::ostringstream str; @@ -135,17 +108,6 @@ std::string BaseTemplate::MakeMemberAccess(const StructureInformation* info, con return str.str(); } -std::string - BaseTemplate::MakeWrittenMemberAccess(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier) -{ - std::ostringstream str; - MakeTypeWrittenVarNameInternal(info->m_definition, str); - str << "->" << member->m_member->m_name; - MakeArrayIndicesInternal(modifier, str); - - return str.str(); -} - std::string BaseTemplate::MakeTypeDecl(const TypeDeclaration* decl) { std::ostringstream str; @@ -299,3 +261,43 @@ std::string BaseTemplate::MakeEvaluation(const IEvaluation* evaluation) MakeEvaluationInternal(evaluation, str); return str.str(); } + +size_t BaseTemplate::SizeForDeclModifierLevel(const MemberInformation& memberInfo, const size_t level) const +{ + const auto& declModifiers = memberInfo.m_member->m_type_declaration->m_declaration_modifiers; + if (declModifiers.empty()) + return memberInfo.m_member->m_type_declaration->GetSize(); + + if (level == 0) + return memberInfo.m_member->m_type_declaration->GetSize(); + + size_t currentSize = memberInfo.m_member->m_type_declaration->m_type->GetSize(); + const auto end = declModifiers.rbegin() + (declModifiers.size() - level); + for (auto i = declModifiers.rbegin(); i != end; ++i) + { + if ((*i)->GetType() == DeclarationModifierType::POINTER) + currentSize = m_env.m_pointer_size; + else + currentSize *= dynamic_cast(i->get())->m_size; + } + + return currentSize; +} + +size_t BaseTemplate::OffsetForMemberModifier(const MemberInformation& memberInfo, + const DeclarationModifierComputations& modifier, + const size_t nestedBaseOffset) const +{ + size_t curOffset = memberInfo.m_member->m_offset; + + auto curLevel = 0u; + for (const auto index : modifier.GetArrayIndices()) + { + if (index > 0) + curOffset += index * SizeForDeclModifierLevel(memberInfo, curLevel + 1); + + curLevel++; + } + + return curOffset + nestedBaseOffset; +} diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.h b/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.h index fb01b398..e20e5e54 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.h +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.h @@ -5,6 +5,7 @@ #include "Domain/Evaluation/OperandDynamic.h" #include "Domain/Evaluation/OperandStatic.h" #include "Domain/Evaluation/Operation.h" +#include "Generating/BaseRenderingContext.h" #include #include @@ -14,7 +15,7 @@ class BaseTemplate protected: static constexpr auto INTENDATION = " "; - explicit BaseTemplate(std::ostream& stream); + explicit BaseTemplate(std::ostream& stream, const BaseRenderingContext& context); void DoIntendation() const; @@ -23,13 +24,9 @@ protected: static std::string Upper(std::string str); static std::string Lower(std::string str); static std::string MakeTypeVarName(const DataDefinition* def); - static std::string MakeTypeWrittenVarName(const DataDefinition* def); static std::string MakeTypePtrVarName(const DataDefinition* def); - static std::string MakeTypeWrittenPtrVarName(const DataDefinition* def); static std::string MakeSafeTypeName(const DataDefinition* def); static std::string MakeMemberAccess(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier); - static std::string - MakeWrittenMemberAccess(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier); static std::string MakeTypeDecl(const TypeDeclaration* decl); static std::string MakeFollowingReferences(const std::vector& modifiers); static std::string MakeArrayIndices(const DeclarationModifierComputations& modifierComputations); @@ -37,20 +34,25 @@ protected: static std::string MakeArrayCount(const ArrayDeclarationModifier* arrayModifier); static std::string MakeEvaluation(const IEvaluation* evaluation); + static void MakeSafeTypeNameInternal(const DataDefinition* def, std::ostringstream& str); + static void MakeArrayIndicesInternal(const DeclarationModifierComputations& modifierComputations, std::ostringstream& str); + + [[nodiscard]] size_t SizeForDeclModifierLevel(const MemberInformation& memberInfo, size_t level) const; + [[nodiscard]] size_t + OffsetForMemberModifier(const MemberInformation& memberInfo, const DeclarationModifierComputations& modifier, size_t nestedBaseOffset) const; + std::ostream& m_out; unsigned m_intendation; private: - static void MakeSafeTypeNameInternal(const DataDefinition* def, std::ostringstream& str); static void MakeTypeVarNameInternal(const DataDefinition* def, std::ostringstream& str); - static void MakeTypeWrittenVarNameInternal(const DataDefinition* def, std::ostringstream& str); static void MakeTypePtrVarNameInternal(const DataDefinition* def, std::ostringstream& str); - static void MakeTypeWrittenPtrVarNameInternal(const DataDefinition* def, std::ostringstream& str); - static void MakeArrayIndicesInternal(const DeclarationModifierComputations& modifierComputations, std::ostringstream& str); static void MakeOperandStatic(const OperandStatic* op, std::ostringstream& str); static void MakeOperandDynamic(const OperandDynamic* op, std::ostringstream& str); static void MakeOperation(const Operation* operation, std::ostringstream& str); static void MakeEvaluationInternal(const IEvaluation* evaluation, std::ostringstream& str); + + const BaseRenderingContext& m_env; }; #define LINE(x) \ diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp index 128d0770..6c213543 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp @@ -18,7 +18,7 @@ namespace { public: PerTemplate(std::ostream& stream, const OncePerTemplateRenderingContext& context) - : BaseTemplate(stream), + : BaseTemplate(stream, context), m_env(context) { } @@ -44,7 +44,7 @@ namespace { public: PerAsset(std::ostream& stream, const OncePerAssetRenderingContext& context) - : BaseTemplate(stream), + : BaseTemplate(stream, context), m_env(context) { } @@ -267,7 +267,7 @@ namespace return std::format("{0}** var{1}Ptr;", def->GetFullName(), MakeSafeTypeName(def)); } - bool ShouldGenerateFillMethod(const RenderingUsedType& type) + static bool ShouldGenerateFillMethod(const RenderingUsedType& type) { const auto isNotForeignAsset = type.m_is_context_asset || !type.m_info || !StructureComputations(type.m_info).IsAsset(); const auto hasMismatchingStructure = @@ -372,47 +372,6 @@ namespace LINE("}") } - [[nodiscard]] size_t SizeForDeclModifierLevel(const MemberInformation& memberInfo, const size_t level) const - { - const auto& declModifiers = memberInfo.m_member->m_type_declaration->m_declaration_modifiers; - if (declModifiers.empty()) - return memberInfo.m_member->m_type_declaration->GetSize(); - - if (level == 0) - return memberInfo.m_member->m_type_declaration->GetSize(); - - size_t currentSize = memberInfo.m_member->m_type_declaration->m_type->GetSize(); - const auto end = declModifiers.rbegin() + (declModifiers.size() - level); - for (auto i = declModifiers.rbegin(); i != end; ++i) - { - if ((*i)->GetType() == DeclarationModifierType::POINTER) - currentSize = m_env.m_pointer_size; - else - currentSize *= dynamic_cast(i->get())->m_size; - } - - return currentSize; - } - - [[nodiscard]] size_t - OffsetForMemberModifier(const MemberInformation& memberInfo, const DeclarationModifierComputations& modifier, const size_t nestedBaseOffset) const - { - size_t curOffset = memberInfo.m_member->m_offset; - - const auto& declModifiers = memberInfo.m_member->m_type_declaration->m_declaration_modifiers; - auto curDeclModifier = declModifiers.begin(); - auto curLevel = 0u; - for (const auto index : modifier.GetArrayIndices()) - { - if (index > 0) - curOffset += index * SizeForDeclModifierLevel(memberInfo, curLevel + 1); - - curLevel++; - } - - return curOffset + nestedBaseOffset; - } - void PrintFillStruct_Member_DynamicArray(const StructureInformation& structInfo, const MemberInformation& memberInfo, const DeclarationModifierComputations& modifier, diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp index df1177cb..3dcc8873 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp @@ -18,7 +18,7 @@ namespace { public: PerTemplate(std::ostream& stream, const OncePerTemplateRenderingContext& context) - : BaseTemplate(stream), + : BaseTemplate(stream, context), m_env(context) { } @@ -44,7 +44,7 @@ namespace { public: PerAsset(std::ostream& stream, const OncePerAssetRenderingContext& context) - : BaseTemplate(stream), + : BaseTemplate(stream, context), m_env(context) { } diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp index 6952c402..c4d96493 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp @@ -18,7 +18,7 @@ namespace { public: PerTemplate(std::ostream& stream, const OncePerTemplateRenderingContext& context) - : BaseTemplate(stream), + : BaseTemplate(stream, context), m_env(context) { } @@ -44,7 +44,7 @@ namespace { public: PerAsset(std::ostream& stream, const OncePerAssetRenderingContext& context) - : BaseTemplate(stream), + : BaseTemplate(stream, context), m_env(context) { } @@ -106,8 +106,8 @@ namespace LINE("") LINE(VariableDecl(m_env.m_asset->m_definition)) - LINE(WrittenVariableDecl(m_env.m_asset->m_definition)) LINE(PointerVariableDecl(m_env.m_asset->m_definition)) + LINE(WrittenVariableDecl(m_env.m_asset->m_definition)) LINE(WrittenPointerVariableDecl(m_env.m_asset->m_definition)) LINE("") @@ -115,18 +115,25 @@ namespace for (const auto* type : m_env.m_used_types) { if (type->m_info && !type->m_info->m_definition->m_anonymous && !type->m_info->m_is_leaf && !StructureComputations(type->m_info).IsAsset()) - { LINE(VariableDecl(type->m_type)) - LINE(WrittenVariableDecl(type->m_type)) - } } for (const auto* type : m_env.m_used_types) { if (type->m_pointer_array_reference_exists && !type->m_is_context_asset) - { LINE(PointerVariableDecl(type->m_type)) + } + + LINE("") + + for (const auto* type : m_env.m_used_types) + { + if (type->m_info && !type->m_info->m_definition->m_anonymous && !type->m_info->m_is_leaf && !StructureComputations(type->m_info).IsAsset()) + LINE(WrittenVariableDecl(type->m_type)) + } + for (const auto* type : m_env.m_used_types) + { + if (type->m_pointer_array_reference_exists && !type->m_is_context_asset) LINE(WrittenPointerVariableDecl(type->m_type)) - } } m_intendation--; @@ -213,7 +220,7 @@ namespace static std::string WrittenVariableDecl(const DataDefinition* def) { - return std::format("{0}* var{1}Written;", def->GetFullName(), MakeSafeTypeName(def)); + return std::format("ZoneOutputOffset var{0}Written;", MakeSafeTypeName(def)); } static std::string PointerVariableDecl(const DataDefinition* def) @@ -223,7 +230,7 @@ namespace static std::string WrittenPointerVariableDecl(const DataDefinition* def) { - return std::format("{0}** var{1}PtrWritten;", def->GetFullName(), MakeSafeTypeName(def)); + return std::format("ZoneOutputOffset var{0}PtrWritten;", MakeSafeTypeName(def)); } void PrintHeaderPtrArrayWriteMethodDeclaration(const DataDefinition* def) const @@ -248,7 +255,7 @@ namespace void PrintHeaderMainWriteMethodDeclaration(const StructureInformation* info) const { - LINEF("void Write({0}** pAsset);", info->m_definition->GetFullName()) + LINEF("void Write({0}* pAsset, ZoneOutputOffset pointerWrittenOffset);", info->m_definition->GetFullName()) } void PrintHeaderConstructor() const @@ -261,19 +268,60 @@ namespace LINEF("var{0} = nullptr;", def->m_name) } - void PrintWrittenVariableInitialization(const DataDefinition* def) const - { - LINEF("var{0}Written = nullptr;", def->m_name) - } - void PrintPointerVariableInitialization(const DataDefinition* def) const { LINEF("var{0}Ptr = nullptr;", def->m_name) } - void PrintWrittenPointerVariableInitialization(const DataDefinition* def) const + static void MakeTypeWrittenPtrVarNameInternal(const DataDefinition* def, std::ostringstream& str) { - LINEF("var{0}PtrWritten = nullptr;", def->m_name) + str << "var"; + MakeSafeTypeNameInternal(def, str); + str << "PtrWritten"; + } + + static void MakeTypeWrittenVarNameInternal(const DataDefinition* def, std::ostringstream& str) + { + str << "var"; + MakeSafeTypeNameInternal(def, str); + str << "Written"; + } + + static std::string MakeTypeWrittenVarName(const DataDefinition* def) + { + std::ostringstream str; + MakeTypeWrittenVarNameInternal(def, str); + return str.str(); + } + + static std::string MakeTypeWrittenPtrVarName(const DataDefinition* def) + { + std::ostringstream str; + MakeTypeWrittenPtrVarNameInternal(def, str); + return str.str(); + } + + std::string + MakeWrittenMemberAccess(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier) const + { + std::ostringstream str; + MakeTypeWrittenVarNameInternal(info->m_definition, str); + str << ".WithInnerOffset("; + + if (m_env.m_architecture_mismatch) + { + str << OffsetForMemberModifier(*member, modifier, 0); + } + else + { + str << "offsetof(" << info->m_definition->GetFullName() << ", " << member->m_member->m_name; + MakeArrayIndicesInternal(modifier, str); + str << ')'; + } + + str << ')'; + + return str.str(); } void PrintConstructorMethod() @@ -290,26 +338,18 @@ namespace m_intendation++; PrintVariableInitialization(m_env.m_asset->m_definition); - PrintWrittenVariableInitialization(m_env.m_asset->m_definition); PrintPointerVariableInitialization(m_env.m_asset->m_definition); - PrintWrittenPointerVariableInitialization(m_env.m_asset->m_definition); LINE("") for (const auto* type : m_env.m_used_types) { if (type->m_info && !type->m_info->m_definition->m_anonymous && !type->m_info->m_is_leaf && !StructureComputations(type->m_info).IsAsset()) - { PrintVariableInitialization(type->m_type); - PrintWrittenVariableInitialization(type->m_type); - } } for (const auto* type : m_env.m_used_types) { if (type->m_info && type->m_pointer_array_reference_exists && !type->m_is_context_asset) - { PrintPointerVariableInitialization(type->m_type); - PrintWrittenPointerVariableInitialization(type->m_type); - } } m_intendation--; @@ -334,7 +374,7 @@ namespace } else if (writeType == MemberWriteType::EMBEDDED) { - LINEF("{0} = UseScriptString({1});", MakeWrittenMemberAccess(info, member, modifier), MakeMemberAccess(info, member, modifier)) + LINEF("UseScriptString({0}, {1});", MakeMemberAccess(info, member, modifier), MakeWrittenMemberAccess(info, member, modifier)) } else { @@ -351,7 +391,7 @@ namespace if (writeType == MemberWriteType::SINGLE_POINTER) { LINEF("{0} writer({1}, m_zone, *m_stream);", WriterClassName(member->m_type), MakeMemberAccess(info, member, modifier)) - LINEF("writer.Write(&{0});", MakeWrittenMemberAccess(info, member, modifier)) + LINEF("writer.Write({0}, {1});", MakeMemberAccess(info, member, modifier), MakeWrittenMemberAccess(info, member, modifier)) } else if (writeType == MemberWriteType::POINTER_ARRAY) { @@ -373,18 +413,20 @@ namespace { if (member->m_member->m_type_declaration->m_is_const) { - LINEF("varXStringWritten = &{0};", MakeWrittenMemberAccess(info, member, modifier)) + LINEF("varXString = &{0};", MakeMemberAccess(info, member, modifier)) } else { - LINEF("varXStringWritten = const_cast(&{0});", MakeWrittenMemberAccess(info, member, modifier)) + LINEF("varXString = const_cast(&{0});", MakeMemberAccess(info, member, modifier)) } + LINEF("varXStringWritten = {0};", MakeWrittenMemberAccess(info, member, modifier)) LINE("WriteXString(false);") } else if (writeType == MemberWriteType::POINTER_ARRAY) { if (modifier.IsArray()) { + LINEF("varXString = {0};", MakeMemberAccess(info, member, modifier)) LINEF("varXStringWritten = {0};", MakeWrittenMemberAccess(info, member, modifier)) LINEF("WriteXStringArray(false, {0});", modifier.GetArraySize()) } @@ -507,7 +549,7 @@ namespace else { LINEF("{0} = &{1};", MakeTypeVarName(member->m_member->m_type_declaration->m_type), MakeMemberAccess(info, member, modifier)) - LINEF("{0} = &{1};", MakeTypeWrittenVarName(member->m_member->m_type_declaration->m_type), MakeWrittenMemberAccess(info, member, modifier)) + LINEF("{0} = {1};", MakeTypeWrittenVarName(member->m_member->m_type_declaration->m_type), MakeWrittenMemberAccess(info, member, modifier)) LINEF("Write_{0}(false);", MakeSafeTypeName(member->m_member->m_type_declaration->m_type)) } } @@ -730,6 +772,14 @@ namespace return member->m_is_reusable; } + std::string MakeReusableInnerOffset(const DataDefinition* dataDefinition, const Variable* member) const + { + if (m_env.m_architecture_mismatch) + return std::to_string(member->m_offset); + + return std::format("offsetof({0}, {1})", dataDefinition->GetFullName(), member->m_name); + } + void WriteMember_Reuse(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier, @@ -741,7 +791,10 @@ namespace return; } - LINEF("if (m_stream->ReusableShouldWrite(&{0}))", MakeWrittenMemberAccess(info, member, modifier)) + LINEF("if (m_stream->ReusableShouldWrite({0}, {1}.WithInnerOffset({2})))", + MakeMemberAccess(info, member, modifier), + MakeTypeWrittenVarName(info->m_definition), + MakeReusableInnerOffset(info->m_definition, member->m_member)) LINE("{") m_intendation++; @@ -1001,17 +1054,17 @@ namespace } else { - LINEF("{0} = m_stream->WritePartial<{1}>({2}, offsetof({1}, {3}));", + LINEF("{0} = m_stream->WritePartial({1}, offsetof({2}, {3}));", MakeTypeWrittenVarName(info->m_definition), - info->m_definition->GetFullName(), MakeTypeVarName(info->m_definition), + info->m_definition->GetFullName(), dynamicMember->m_member->m_name) } m_intendation--; LINE("") - LINEF("assert({0} != nullptr);", MakeTypeWrittenVarName(info->m_definition)) + LINEF("assert({0}.Offset() != nullptr);", MakeTypeWrittenVarName(info->m_definition)) } else { @@ -1063,7 +1116,7 @@ namespace m_intendation--; LINE("") - LINEF("assert({0} != nullptr);", MakeTypeWrittenPtrVarName(info->m_definition)) + LINEF("assert({0}.Offset() != nullptr);", MakeTypeWrittenPtrVarName(info->m_definition)) LINE("") if (inTemp) @@ -1071,7 +1124,7 @@ namespace LINEF("m_stream->PushBlock({0});", m_env.m_default_temp_block->m_name) LINE("") } - LINEF("if (m_stream->ReusableShouldWrite({0}))", MakeTypeWrittenPtrVarName(info->m_definition)) + LINEF("if (m_stream->ReusableShouldWrite(*{0}, {1}))", MakeTypePtrVarName(info->m_definition), MakeTypeWrittenPtrVarName(info->m_definition)) LINE("{") m_intendation++; @@ -1089,7 +1142,7 @@ namespace } LINE("") - LINEF("m_stream->MarkFollowing(*{0});", MakeTypeWrittenPtrVarName(info->m_definition)) + LINEF("m_stream->MarkFollowing({0});", MakeTypeWrittenPtrVarName(info->m_definition)) m_intendation--; LINE("}") @@ -1106,7 +1159,9 @@ namespace void PrintMainWriteMethod() { - LINEF("void {0}::Write({1}** pAsset)", WriterClassName(m_env.m_asset), m_env.m_asset->m_definition->GetFullName()) + LINEF("void {0}::Write({1}* pAsset, const ZoneOutputOffset pointerWrittenOffset)", + WriterClassName(m_env.m_asset), + m_env.m_asset->m_definition->GetFullName()) LINE("{") m_intendation++; @@ -1116,9 +1171,8 @@ namespace LINE("") LINEF("auto* zoneAsset = static_cast<{0}*>(m_asset->m_ptr);", m_env.m_asset->m_definition->GetFullName()) LINEF("{0} = &zoneAsset;", MakeTypePtrVarName(m_env.m_asset->m_definition)) - LINEF("{0} = &zoneAsset;", MakeTypeWrittenPtrVarName(m_env.m_asset->m_definition)) + LINEF("{0} = pointerWrittenOffset;", MakeTypeWrittenPtrVarName(m_env.m_asset->m_definition)) LINEF("WritePtr_{0}(false);", MakeSafeTypeName(m_env.m_asset->m_definition)) - LINE("*pAsset = zoneAsset;") m_intendation--; LINE("}") @@ -1142,7 +1196,7 @@ namespace { LINEF("m_stream->Write<{0}>(*{1});", def->GetFullName(), MakeTypePtrVarName(def)) } - LINEF("m_stream->MarkFollowing(*{0});", MakeTypeWrittenPtrVarName(def)) + LINEF("m_stream->MarkFollowing({0});", MakeTypeWrittenPtrVarName(def)) } void PrintWritePtrArrayMethod_PointerCheck(const DataDefinition* def, const StructureInformation* info, const bool reusable) @@ -1154,13 +1208,13 @@ namespace if (info && StructureComputations(info).IsAsset()) { LINEF("{0} writer(*{1}, m_zone, *m_stream);", WriterClassName(info), MakeTypePtrVarName(def)) - LINEF("writer.Write({0});", MakeTypeWrittenPtrVarName(def)) + LINEF("writer.Write(*{0}, {1});", MakeTypePtrVarName(def), MakeTypeWrittenPtrVarName(def)) } else { if (reusable) { - LINEF("if (m_stream->ReusableShouldWrite({0}))", MakeTypeWrittenPtrVarName(def)) + LINEF("if (m_stream->ReusableShouldWrite(*{0}, {1}))", MakeTypePtrVarName(def), MakeTypeWrittenPtrVarName(def)) LINE("{") m_intendation++; @@ -1194,11 +1248,11 @@ namespace m_intendation--; LINE("") - LINEF("assert({0} != nullptr);", MakeTypeWrittenPtrVarName(def)) + LINEF("assert({0}.Offset() != nullptr);", MakeTypeWrittenPtrVarName(def)) LINE("") LINEF("{0}** var = {1};", def->GetFullName(), MakeTypePtrVarName(def)) - LINEF("{0}** varWritten = {1};", def->GetFullName(), MakeTypeWrittenPtrVarName(def)) + LINEF("ZoneOutputOffset varWritten = {1};", def->GetFullName(), MakeTypeWrittenPtrVarName(def)) LINE("for (size_t index = 0; index < count; index++)") LINE("{") m_intendation++; @@ -1208,7 +1262,7 @@ namespace PrintWritePtrArrayMethod_PointerCheck(def, info, reusable); LINE("") LINE("var++;") - LINE("varWritten++;") + LINE("varWritten.Inc(m_stream->GetPointerByteCount());") m_intendation--; LINE("}") @@ -1230,11 +1284,11 @@ namespace m_intendation--; LINE("") - LINEF("assert({0} != nullptr);", MakeTypeWrittenVarName(def)) + LINEF("assert({0}.Offset() != nullptr);", MakeTypeWrittenVarName(def)) LINE("") LINEF("{0}* var = {1};", def->GetFullName(), MakeTypeVarName(def)) - LINEF("{0}* varWritten = {1};", def->GetFullName(), MakeTypeWrittenVarName(def)) + LINEF("ZoneOutputOffset varWritten = {1};", def->GetFullName(), MakeTypeWrittenVarName(def)) LINE("for (size_t index = 0; index < count; index++)") LINE("{") m_intendation++; @@ -1243,7 +1297,7 @@ namespace LINEF("{0} = varWritten;", MakeTypeWrittenVarName(info->m_definition)) LINEF("Write_{0}(false);", info->m_definition->m_name) LINE("var++;") - LINE("varWritten++;") + LINE("varWritten.Inc(m_stream->GetPointerByteCount());") m_intendation--; LINE("}") diff --git a/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp b/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp index 7acc1f11..34d9fbd6 100644 --- a/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp +++ b/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp @@ -79,11 +79,14 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart) void ContentWriter::WriteXAsset(const bool atStreamStart) { +#ifdef ARCH_x86 + static_assert(offsetof(XAsset, header.data) == 4u); +#endif #define WRITE_ASSET(type_index, typeName, headerEntry) \ case type_index: \ { \ Writer_##typeName writer(varXAsset->header.headerEntry, m_zone, *m_stream); \ - writer.Write(&varXAsset->header.headerEntry); \ + writer.Write(varXAsset->header.headerEntry, varXAssetWritten.WithInnerOffset(4)); \ break; \ } #define SKIP_ASSET(type_index, typeName, headerEntry) \ diff --git a/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp b/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp index b6f12ad2..1017573d 100644 --- a/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp +++ b/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp @@ -79,11 +79,14 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart) void ContentWriter::WriteXAsset(const bool atStreamStart) { +#ifdef ARCH_x86 + static_assert(offsetof(XAsset, header.data) == 4u); +#endif #define WRITE_ASSET(type_index, typeName, headerEntry) \ case type_index: \ { \ Writer_##typeName writer(varXAsset->header.headerEntry, m_zone, *m_stream); \ - writer.Write(&varXAsset->header.headerEntry); \ + writer.Write(varXAsset->header.headerEntry, varXAssetWritten.WithInnerOffset(4)); \ break; \ } #define SKIP_ASSET(type_index, typeName, headerEntry) \ diff --git a/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp b/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp index 554ad4c0..fef99578 100644 --- a/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp +++ b/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp @@ -79,11 +79,14 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart) void ContentWriter::WriteXAsset(const bool atStreamStart) { +#ifdef ARCH_x86 + static_assert(offsetof(XAsset, header.data) == 4u); +#endif #define WRITE_ASSET(type_index, typeName, headerEntry) \ case type_index: \ { \ Writer_##typeName writer(varXAsset->header.headerEntry, m_zone, *m_stream); \ - writer.Write(&varXAsset->header.headerEntry); \ + writer.Write(varXAsset->header.headerEntry, varXAssetWritten.WithInnerOffset(4)); \ break; \ } #define SKIP_ASSET(type_index, typeName, headerEntry) \ diff --git a/src/ZoneWriting/Game/T5/ContentWriterT5.cpp b/src/ZoneWriting/Game/T5/ContentWriterT5.cpp index ae2c40ce..9814fe6d 100644 --- a/src/ZoneWriting/Game/T5/ContentWriterT5.cpp +++ b/src/ZoneWriting/Game/T5/ContentWriterT5.cpp @@ -79,11 +79,14 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart) void ContentWriter::WriteXAsset(const bool atStreamStart) { +#ifdef ARCH_x86 + static_assert(offsetof(XAsset, header.data) == 4u); +#endif #define WRITE_ASSET(type_index, typeName, headerEntry) \ case type_index: \ { \ Writer_##typeName writer(varXAsset->header.headerEntry, m_zone, *m_stream); \ - writer.Write(&varXAsset->header.headerEntry); \ + writer.Write(varXAsset->header.headerEntry, varXAssetWritten.WithInnerOffset(4)); \ break; \ } #define SKIP_ASSET(type_index, typeName, headerEntry) \ diff --git a/src/ZoneWriting/Game/T6/ContentWriterT6.cpp b/src/ZoneWriting/Game/T6/ContentWriterT6.cpp index c9544b45..3f40d075 100644 --- a/src/ZoneWriting/Game/T6/ContentWriterT6.cpp +++ b/src/ZoneWriting/Game/T6/ContentWriterT6.cpp @@ -82,11 +82,14 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart) void ContentWriter::WriteXAsset(const bool atStreamStart) { +#ifdef ARCH_x86 + static_assert(offsetof(XAsset, header.data) == 4u); +#endif #define WRITE_ASSET(type_index, typeName, headerEntry) \ case type_index: \ { \ Writer_##typeName writer(varXAsset->header.headerEntry, m_zone, *m_stream); \ - writer.Write(&varXAsset->header.headerEntry); \ + writer.Write(varXAsset->header.headerEntry, varXAssetWritten.WithInnerOffset(4)); \ break; \ } diff --git a/src/ZoneWriting/Writing/AssetWriter.cpp b/src/ZoneWriting/Writing/AssetWriter.cpp index ecd8d70c..80a1e99f 100644 --- a/src/ZoneWriting/Writing/AssetWriter.cpp +++ b/src/ZoneWriting/Writing/AssetWriter.cpp @@ -18,16 +18,16 @@ const char* AssetWriter::NonReferenceAssetName(const char* assetName) return assetName; } -scr_string_t AssetWriter::UseScriptString(const scr_string_t scrString) const +void AssetWriter::UseScriptString(const scr_string_t scrString, const ZoneOutputOffset written) const { assert(scrString < m_asset->m_zone->m_script_strings.Count()); if (m_asset->m_zone == &m_zone) - return scrString; + return; // The asset comes from a different zone, we need to translate it const auto strValue = m_asset->m_zone->m_script_strings.CValue(scrString); - return m_zone.m_script_strings.GetScriptString(strValue); + *static_cast(written.Offset()) = m_zone.m_script_strings.GetScriptString(strValue); } void AssetWriter::WriteScriptStringArray(const bool atStreamStart, const size_t count) @@ -42,7 +42,7 @@ void AssetWriter::WriteScriptStringArray(const bool atStreamStart, const size_t for (size_t index = 0; index < count; index++) { - *static_cast(varScriptStringWritten.Offset()) = UseScriptString(*varScriptString); + UseScriptString(*varScriptString, varScriptStringWritten); varScriptString++; varScriptStringWritten.Inc(sizeof(scr_string_t)); diff --git a/src/ZoneWriting/Writing/AssetWriter.h b/src/ZoneWriting/Writing/AssetWriter.h index 10220241..863a6a6c 100644 --- a/src/ZoneWriting/Writing/AssetWriter.h +++ b/src/ZoneWriting/Writing/AssetWriter.h @@ -11,7 +11,7 @@ protected: AssetWriter(XAssetInfoGeneric* asset, const Zone& zone, ZoneOutputStream& stream); [[nodiscard]] static const char* NonReferenceAssetName(const char* assetName); - [[nodiscard]] scr_string_t UseScriptString(scr_string_t scrString) const; + void UseScriptString(scr_string_t scrString, ZoneOutputOffset written) const; void WriteScriptStringArray(bool atStreamStart, size_t count); XAssetInfoGeneric* m_asset; diff --git a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp index d8a209be..42952a21 100644 --- a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp +++ b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp @@ -220,9 +220,10 @@ namespace { assert((reinterpret_cast(ptr) - reinterpret_cast(entry.m_start_ptr)) % entrySize == 0); const auto finalZonePointer = entry.m_start_zone_ptr + (reinterpret_cast(ptr) - reinterpret_cast(entry.m_start_ptr)); + auto* writtenPtrOffset = outputOffset.Offset(); for (auto i = 0u; i < m_pointer_byte_count; i++) - static_cast(ptr)[i] = reinterpret_cast(&finalZonePointer)[i]; + static_cast(writtenPtrOffset)[i] = reinterpret_cast(&finalZonePointer)[i]; return false; } From 2a1f6158e4dd638abc59add6634fc55be3293c2f Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 9 Jan 2026 21:02:24 +0000 Subject: [PATCH 08/20] fix: writing bad zone sizes with x64 hosts --- src/ZoneLoading/Loading/Steps/StepAllocXBlocks.cpp | 4 ++-- src/ZoneWriting/Writing/Steps/StepWriteZoneSizes.cpp | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ZoneLoading/Loading/Steps/StepAllocXBlocks.cpp b/src/ZoneLoading/Loading/Steps/StepAllocXBlocks.cpp index 7e75ceca..d2111d04 100644 --- a/src/ZoneLoading/Loading/Steps/StepAllocXBlocks.cpp +++ b/src/ZoneLoading/Loading/Steps/StepAllocXBlocks.cpp @@ -13,8 +13,8 @@ namespace { const auto blockCount = static_cast(zoneLoader.m_blocks.size()); - const auto blockSizes = std::make_unique(blockCount); - stream.Load(blockSizes.get(), sizeof(xblock_size_t) * blockCount); + std::vector blockSizes(blockCount); + stream.Load(blockSizes.data(), sizeof(xblock_size_t) * blockCount); uint64_t totalMemory = 0; for (unsigned int block = 0; block < blockCount; block++) diff --git a/src/ZoneWriting/Writing/Steps/StepWriteZoneSizes.cpp b/src/ZoneWriting/Writing/Steps/StepWriteZoneSizes.cpp index 282159a8..349be0e7 100644 --- a/src/ZoneWriting/Writing/Steps/StepWriteZoneSizes.cpp +++ b/src/ZoneWriting/Writing/Steps/StepWriteZoneSizes.cpp @@ -1,5 +1,7 @@ #include "StepWriteZoneSizes.h" +#include + StepWriteZoneSizes::StepWriteZoneSizes(StepWriteZoneContentToMemory* memory) : m_memory(memory) { @@ -7,8 +9,8 @@ StepWriteZoneSizes::StepWriteZoneSizes(StepWriteZoneContentToMemory* memory) void StepWriteZoneSizes::PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) { - auto totalSize = static_cast(m_memory->GetData()->m_total_size); - size_t externalSize = 0; + const auto totalSize = static_cast(m_memory->GetData()->m_total_size); + constexpr uint32_t externalSize = 0; stream->Write(&totalSize, sizeof(totalSize)); stream->Write(&externalSize, sizeof(externalSize)); From 257ef39b2008e2597fd8d0fbc7ea99783bac42cb Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 9 Jan 2026 23:29:42 +0000 Subject: [PATCH 09/20] feat: add fill in ContentWriter classes for writing with x64 hosts --- .../Templates/ZoneWriteTemplate.cpp | 4 +- src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp | 50 +++++++++++------ src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp | 50 +++++++++++------ src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp | 50 +++++++++++------ src/ZoneWriting/Game/T5/ContentWriterT5.cpp | 50 +++++++++++------ src/ZoneWriting/Game/T6/ContentWriterT6.cpp | 53 ++++++++++++------ src/ZoneWriting/Writing/ContentWriterBase.cpp | 7 ++- .../Zone/Stream/ZoneOutputStream.cpp | 56 ++++++++++++++++--- .../Zone/Stream/ZoneOutputStream.h | 34 ++++++++++- 9 files changed, 259 insertions(+), 95 deletions(-) diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp index c4d96493..d7d29c95 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp @@ -306,7 +306,7 @@ namespace { std::ostringstream str; MakeTypeWrittenVarNameInternal(info->m_definition, str); - str << ".WithInnerOffset("; + str << ".AtOffset("; if (m_env.m_architecture_mismatch) { @@ -791,7 +791,7 @@ namespace return; } - LINEF("if (m_stream->ReusableShouldWrite({0}, {1}.WithInnerOffset({2})))", + LINEF("if (m_stream->ReusableShouldWrite({0}, {1}.AtOffset({2})))", MakeMemberAccess(info, member, modifier), MakeTypeWrittenVarName(info->m_definition), MakeReusableInnerOffset(info->m_definition, member->m_member)) diff --git a/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp b/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp index 34d9fbd6..e904524d 100644 --- a/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp +++ b/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp @@ -57,10 +57,7 @@ void ContentWriter::CreateXAssetList(XAssetList& xAssetList, MemoryManager& memo void ContentWriter::WriteScriptStringList(const bool atStreamStart) { - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - - if (atStreamStart) - varScriptStringListWritten = m_stream->Write(varScriptStringList); + assert(!atStreamStart); if (varScriptStringList->strings != nullptr) { @@ -71,10 +68,8 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart) #ifdef ARCH_x86 static_assert(offsetof(ScriptStringList, strings) == 4u); #endif - m_stream->MarkFollowing(varScriptStringListWritten.WithInnerOffset(4)); + m_stream->MarkFollowing(varScriptStringListWritten.AtOffset(4)); } - - m_stream->PopBlock(); } void ContentWriter::WriteXAsset(const bool atStreamStart) @@ -86,7 +81,7 @@ void ContentWriter::WriteXAsset(const bool atStreamStart) case type_index: \ { \ Writer_##typeName writer(varXAsset->header.headerEntry, m_zone, *m_stream); \ - writer.Write(varXAsset->header.headerEntry, varXAssetWritten.WithInnerOffset(4)); \ + writer.Write(varXAsset->header.headerEntry, varXAssetWritten.AtOffset(4)); \ break; \ } #define SKIP_ASSET(type_index, typeName, headerEntry) \ @@ -142,17 +137,27 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun { assert(varXAsset != nullptr); +#ifdef ARCH_x86 + static_assert(sizeof(XAsset) == 8u); +#endif + if (atStreamStart) + { +#ifdef ARCH_x86 varXAssetWritten = m_stream->Write(varXAsset, count); +#else + const auto fill = m_stream->WriteWithFill(8u * count); + varXAssetWritten = fill.Offset(); + + for (size_t index = 0; index < count; index++) + fill.Fill(varXAsset[index].type, 8u * index); +#endif + } for (size_t index = 0; index < count; index++) { WriteXAsset(false); varXAsset++; - -#ifdef ARCH_x86 - static_assert(sizeof(XAsset) == 8u); -#endif varXAssetWritten.Inc(8u); } } @@ -161,21 +166,34 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream) { m_stream = &stream; - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - MemoryManager memory; XAssetList assetList{}; CreateXAssetList(assetList, memory); varXAssetList = &assetList; + +#ifdef ARCH_x86 + static_assert(sizeof(XAssetList) == 16); + static_assert(offsetof(XAssetList, assetCount) == 8u); varXAssetListWritten = m_stream->WriteDataRaw(&assetList, sizeof(assetList)); +#else + const auto fillAccessor = m_stream->WriteWithFill(16u); + varXAssetListWritten = fillAccessor.Offset(); + + varScriptStringList = &varXAssetList->stringList; + fillAccessor.Fill(varScriptStringList->count, 0u); + + fillAccessor.Fill(varXAssetList->assetCount, 8u); +#endif + + m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); #ifdef ARCH_x86 static_assert(offsetof(XAssetList, stringList) == 0u); #endif varScriptStringList = &varXAssetList->stringList; - varScriptStringListWritten = varXAssetListWritten.WithInnerOffset(0); + varScriptStringListWritten = varXAssetListWritten.AtOffset(0); WriteScriptStringList(false); if (varXAssetList->assets != nullptr) @@ -187,7 +205,7 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream) #ifdef ARCH_x86 static_assert(offsetof(XAssetList, assets) == 12u); #endif - m_stream->MarkFollowing(varXAssetListWritten.WithInnerOffset(12)); + m_stream->MarkFollowing(varXAssetListWritten.AtOffset(12)); } m_stream->PopBlock(); diff --git a/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp b/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp index 1017573d..c0fbc85a 100644 --- a/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp +++ b/src/ZoneWriting/Game/IW4/ContentWriterIW4.cpp @@ -57,10 +57,7 @@ void ContentWriter::CreateXAssetList(XAssetList& xAssetList, MemoryManager& memo void ContentWriter::WriteScriptStringList(const bool atStreamStart) { - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - - if (atStreamStart) - varScriptStringListWritten = m_stream->Write(varScriptStringList); + assert(!atStreamStart); if (varScriptStringList->strings != nullptr) { @@ -71,10 +68,8 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart) #ifdef ARCH_x86 static_assert(offsetof(ScriptStringList, strings) == 4u); #endif - m_stream->MarkFollowing(varScriptStringListWritten.WithInnerOffset(4)); + m_stream->MarkFollowing(varScriptStringListWritten.AtOffset(4)); } - - m_stream->PopBlock(); } void ContentWriter::WriteXAsset(const bool atStreamStart) @@ -86,7 +81,7 @@ void ContentWriter::WriteXAsset(const bool atStreamStart) case type_index: \ { \ Writer_##typeName writer(varXAsset->header.headerEntry, m_zone, *m_stream); \ - writer.Write(varXAsset->header.headerEntry, varXAssetWritten.WithInnerOffset(4)); \ + writer.Write(varXAsset->header.headerEntry, varXAssetWritten.AtOffset(4)); \ break; \ } #define SKIP_ASSET(type_index, typeName, headerEntry) \ @@ -152,17 +147,27 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun { assert(varXAsset != nullptr); +#ifdef ARCH_x86 + static_assert(sizeof(XAsset) == 8u); +#endif + if (atStreamStart) + { +#ifdef ARCH_x86 varXAssetWritten = m_stream->Write(varXAsset, count); +#else + const auto fill = m_stream->WriteWithFill(8u * count); + varXAssetWritten = fill.Offset(); + + for (size_t index = 0; index < count; index++) + fill.Fill(varXAsset[index].type, 8u * index); +#endif + } for (size_t index = 0; index < count; index++) { WriteXAsset(false); varXAsset++; - -#ifdef ARCH_x86 - static_assert(sizeof(XAsset) == 8u); -#endif varXAssetWritten.Inc(8u); } } @@ -171,21 +176,34 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream) { m_stream = &stream; - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - MemoryManager memory; XAssetList assetList{}; CreateXAssetList(assetList, memory); varXAssetList = &assetList; + +#ifdef ARCH_x86 + static_assert(sizeof(XAssetList) == 16); + static_assert(offsetof(XAssetList, assetCount) == 8u); varXAssetListWritten = m_stream->WriteDataRaw(&assetList, sizeof(assetList)); +#else + const auto fillAccessor = m_stream->WriteWithFill(16u); + varXAssetListWritten = fillAccessor.Offset(); + + varScriptStringList = &varXAssetList->stringList; + fillAccessor.Fill(varScriptStringList->count, 0u); + + fillAccessor.Fill(varXAssetList->assetCount, 8u); +#endif + + m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); #ifdef ARCH_x86 static_assert(offsetof(XAssetList, stringList) == 0u); #endif varScriptStringList = &varXAssetList->stringList; - varScriptStringListWritten = varXAssetListWritten.WithInnerOffset(0); + varScriptStringListWritten = varXAssetListWritten.AtOffset(0); WriteScriptStringList(false); if (varXAssetList->assets != nullptr) @@ -197,7 +215,7 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream) #ifdef ARCH_x86 static_assert(offsetof(XAssetList, assets) == 12u); #endif - m_stream->MarkFollowing(varXAssetListWritten.WithInnerOffset(12)); + m_stream->MarkFollowing(varXAssetListWritten.AtOffset(12)); } m_stream->PopBlock(); diff --git a/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp b/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp index fef99578..d701903c 100644 --- a/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp +++ b/src/ZoneWriting/Game/IW5/ContentWriterIW5.cpp @@ -57,10 +57,7 @@ void ContentWriter::CreateXAssetList(XAssetList& xAssetList, MemoryManager& memo void ContentWriter::WriteScriptStringList(const bool atStreamStart) { - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - - if (atStreamStart) - varScriptStringListWritten = m_stream->Write(varScriptStringList); + assert(!atStreamStart); if (varScriptStringList->strings != nullptr) { @@ -71,10 +68,8 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart) #ifdef ARCH_x86 static_assert(offsetof(ScriptStringList, strings) == 4u); #endif - m_stream->MarkFollowing(varScriptStringListWritten.WithInnerOffset(4)); + m_stream->MarkFollowing(varScriptStringListWritten.AtOffset(4)); } - - m_stream->PopBlock(); } void ContentWriter::WriteXAsset(const bool atStreamStart) @@ -86,7 +81,7 @@ void ContentWriter::WriteXAsset(const bool atStreamStart) case type_index: \ { \ Writer_##typeName writer(varXAsset->header.headerEntry, m_zone, *m_stream); \ - writer.Write(varXAsset->header.headerEntry, varXAssetWritten.WithInnerOffset(4)); \ + writer.Write(varXAsset->header.headerEntry, varXAssetWritten.AtOffset(4)); \ break; \ } #define SKIP_ASSET(type_index, typeName, headerEntry) \ @@ -155,17 +150,27 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun { assert(varXAsset != nullptr); +#ifdef ARCH_x86 + static_assert(sizeof(XAsset) == 8u); +#endif + if (atStreamStart) + { +#ifdef ARCH_x86 varXAssetWritten = m_stream->Write(varXAsset, count); +#else + const auto fill = m_stream->WriteWithFill(8u * count); + varXAssetWritten = fill.Offset(); + + for (size_t index = 0; index < count; index++) + fill.Fill(varXAsset[index].type, 8u * index); +#endif + } for (size_t index = 0; index < count; index++) { WriteXAsset(false); varXAsset++; - -#ifdef ARCH_x86 - static_assert(sizeof(XAsset) == 8u); -#endif varXAssetWritten.Inc(8u); } } @@ -174,21 +179,34 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream) { m_stream = &stream; - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - MemoryManager memory; XAssetList assetList{}; CreateXAssetList(assetList, memory); varXAssetList = &assetList; + +#ifdef ARCH_x86 + static_assert(sizeof(XAssetList) == 16); + static_assert(offsetof(XAssetList, assetCount) == 8u); varXAssetListWritten = m_stream->WriteDataRaw(&assetList, sizeof(assetList)); +#else + const auto fillAccessor = m_stream->WriteWithFill(16u); + varXAssetListWritten = fillAccessor.Offset(); + + varScriptStringList = &varXAssetList->stringList; + fillAccessor.Fill(varScriptStringList->count, 0u); + + fillAccessor.Fill(varXAssetList->assetCount, 8u); +#endif + + m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); #ifdef ARCH_x86 static_assert(offsetof(XAssetList, stringList) == 0u); #endif varScriptStringList = &varXAssetList->stringList; - varScriptStringListWritten = varXAssetListWritten.WithInnerOffset(0); + varScriptStringListWritten = varXAssetListWritten.AtOffset(0); WriteScriptStringList(false); if (varXAssetList->assets != nullptr) @@ -200,7 +218,7 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream) #ifdef ARCH_x86 static_assert(offsetof(XAssetList, assets) == 12u); #endif - m_stream->MarkFollowing(varXAssetListWritten.WithInnerOffset(12)); + m_stream->MarkFollowing(varXAssetListWritten.AtOffset(12)); } m_stream->PopBlock(); diff --git a/src/ZoneWriting/Game/T5/ContentWriterT5.cpp b/src/ZoneWriting/Game/T5/ContentWriterT5.cpp index 9814fe6d..253a022a 100644 --- a/src/ZoneWriting/Game/T5/ContentWriterT5.cpp +++ b/src/ZoneWriting/Game/T5/ContentWriterT5.cpp @@ -57,10 +57,7 @@ void ContentWriter::CreateXAssetList(XAssetList& xAssetList, MemoryManager& memo void ContentWriter::WriteScriptStringList(const bool atStreamStart) { - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - - if (atStreamStart) - varScriptStringListWritten = m_stream->Write(varScriptStringList); + assert(!atStreamStart); if (varScriptStringList->strings != nullptr) { @@ -71,10 +68,8 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart) #ifdef ARCH_x86 static_assert(offsetof(ScriptStringList, strings) == 4u); #endif - m_stream->MarkFollowing(varScriptStringListWritten.WithInnerOffset(4)); + m_stream->MarkFollowing(varScriptStringListWritten.AtOffset(4)); } - - m_stream->PopBlock(); } void ContentWriter::WriteXAsset(const bool atStreamStart) @@ -86,7 +81,7 @@ void ContentWriter::WriteXAsset(const bool atStreamStart) case type_index: \ { \ Writer_##typeName writer(varXAsset->header.headerEntry, m_zone, *m_stream); \ - writer.Write(varXAsset->header.headerEntry, varXAssetWritten.WithInnerOffset(4)); \ + writer.Write(varXAsset->header.headerEntry, varXAssetWritten.AtOffset(4)); \ break; \ } #define SKIP_ASSET(type_index, typeName, headerEntry) \ @@ -148,17 +143,27 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun { assert(varXAsset != nullptr); +#ifdef ARCH_x86 + static_assert(sizeof(XAsset) == 8u); +#endif + if (atStreamStart) + { +#ifdef ARCH_x86 varXAssetWritten = m_stream->Write(varXAsset, count); +#else + const auto fill = m_stream->WriteWithFill(8u * count); + varXAssetWritten = fill.Offset(); + + for (size_t index = 0; index < count; index++) + fill.Fill(varXAsset[index].type, 8u * index); +#endif + } for (size_t index = 0; index < count; index++) { WriteXAsset(false); varXAsset++; - -#ifdef ARCH_x86 - static_assert(sizeof(XAsset) == 8u); -#endif varXAssetWritten.Inc(8u); } } @@ -167,21 +172,34 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream) { m_stream = &stream; - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - MemoryManager memory; XAssetList assetList{}; CreateXAssetList(assetList, memory); varXAssetList = &assetList; + +#ifdef ARCH_x86 + static_assert(sizeof(XAssetList) == 16); + static_assert(offsetof(XAssetList, assetCount) == 8u); varXAssetListWritten = m_stream->WriteDataRaw(&assetList, sizeof(assetList)); +#else + const auto fillAccessor = m_stream->WriteWithFill(16u); + varXAssetListWritten = fillAccessor.Offset(); + + varScriptStringList = &varXAssetList->stringList; + fillAccessor.Fill(varScriptStringList->count, 0u); + + fillAccessor.Fill(varXAssetList->assetCount, 8u); +#endif + + m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); #ifdef ARCH_x86 static_assert(offsetof(XAssetList, stringList) == 0u); #endif varScriptStringList = &varXAssetList->stringList; - varScriptStringListWritten = varXAssetListWritten.WithInnerOffset(0); + varScriptStringListWritten = varXAssetListWritten.AtOffset(0); WriteScriptStringList(false); if (varXAssetList->assets != nullptr) @@ -193,7 +211,7 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream) #ifdef ARCH_x86 static_assert(offsetof(XAssetList, assets) == 12u); #endif - m_stream->MarkFollowing(varXAssetListWritten.WithInnerOffset(12)); + m_stream->MarkFollowing(varXAssetListWritten.AtOffset(12)); } m_stream->PopBlock(); diff --git a/src/ZoneWriting/Game/T6/ContentWriterT6.cpp b/src/ZoneWriting/Game/T6/ContentWriterT6.cpp index 3f40d075..14af265a 100644 --- a/src/ZoneWriting/Game/T6/ContentWriterT6.cpp +++ b/src/ZoneWriting/Game/T6/ContentWriterT6.cpp @@ -60,10 +60,7 @@ void ContentWriter::CreateXAssetList(XAssetList& xAssetList, MemoryManager& memo void ContentWriter::WriteScriptStringList(const bool atStreamStart) { - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - - if (atStreamStart) - varScriptStringListWritten = m_stream->Write(varScriptStringList); + assert(!atStreamStart); if (varScriptStringList->strings != nullptr) { @@ -74,10 +71,8 @@ void ContentWriter::WriteScriptStringList(const bool atStreamStart) #ifdef ARCH_x86 static_assert(offsetof(ScriptStringList, strings) == 4u); #endif - m_stream->MarkFollowing(varScriptStringListWritten.WithInnerOffset(4)); + m_stream->MarkFollowing(varScriptStringListWritten.AtOffset(4)); } - - m_stream->PopBlock(); } void ContentWriter::WriteXAsset(const bool atStreamStart) @@ -89,7 +84,7 @@ void ContentWriter::WriteXAsset(const bool atStreamStart) case type_index: \ { \ Writer_##typeName writer(varXAsset->header.headerEntry, m_zone, *m_stream); \ - writer.Write(varXAsset->header.headerEntry, varXAssetWritten.WithInnerOffset(4)); \ + writer.Write(varXAsset->header.headerEntry, varXAssetWritten.AtOffset(4)); \ break; \ } @@ -162,18 +157,27 @@ void ContentWriter::WriteXAsset(const bool atStreamStart) void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t count) { assert(varXAsset != nullptr); +#ifdef ARCH_x86 + static_assert(sizeof(XAsset) == 8u); +#endif if (atStreamStart) + { +#ifdef ARCH_x86 varXAssetWritten = m_stream->Write(varXAsset, count); +#else + const auto fill = m_stream->WriteWithFill(8u * count); + varXAssetWritten = fill.Offset(); + + for (size_t index = 0; index < count; index++) + fill.Fill(varXAsset[index].type, 8u * index); +#endif + } for (size_t index = 0; index < count; index++) { WriteXAsset(false); varXAsset++; - -#ifdef ARCH_x86 - static_assert(sizeof(XAsset) == 8u); -#endif varXAssetWritten.Inc(8u); } } @@ -182,21 +186,36 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream) { m_stream = &stream; - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - MemoryManager memory; XAssetList assetList{}; CreateXAssetList(assetList, memory); varXAssetList = &assetList; + +#ifdef ARCH_x86 + static_assert(sizeof(XAssetList) == 24); + static_assert(offsetof(XAssetList, dependCount) == 8u); + static_assert(offsetof(XAssetList, assetCount) == 16u); varXAssetListWritten = m_stream->WriteDataRaw(&assetList, sizeof(assetList)); +#else + const auto fillAccessor = m_stream->WriteWithFill(24u); + varXAssetListWritten = fillAccessor.Offset(); + + varScriptStringList = &varXAssetList->stringList; + fillAccessor.Fill(varScriptStringList->count, 0u); + + fillAccessor.Fill(varXAssetList->dependCount, 8u); + fillAccessor.Fill(varXAssetList->assetCount, 16u); +#endif + + m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); #ifdef ARCH_x86 static_assert(offsetof(XAssetList, stringList) == 0u); #endif varScriptStringList = &varXAssetList->stringList; - varScriptStringListWritten = varXAssetListWritten.WithInnerOffset(0); + varScriptStringListWritten = varXAssetListWritten.AtOffset(0); WriteScriptStringList(false); if (varXAssetList->depends != nullptr) @@ -208,7 +227,7 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream) #ifdef ARCH_x86 static_assert(offsetof(XAssetList, depends) == 12u); #endif - m_stream->MarkFollowing(varXAssetListWritten.WithInnerOffset(12)); + m_stream->MarkFollowing(varXAssetListWritten.AtOffset(12)); } if (varXAssetList->assets != nullptr) @@ -220,7 +239,7 @@ void ContentWriter::WriteContent(ZoneOutputStream& stream) #ifdef ARCH_x86 static_assert(offsetof(XAssetList, assets) == 20u); #endif - m_stream->MarkFollowing(varXAssetListWritten.WithInnerOffset(20)); + m_stream->MarkFollowing(varXAssetListWritten.AtOffset(20)); } m_stream->PopBlock(); diff --git a/src/ZoneWriting/Writing/ContentWriterBase.cpp b/src/ZoneWriting/Writing/ContentWriterBase.cpp index b4b52a42..e9a596fc 100644 --- a/src/ZoneWriting/Writing/ContentWriterBase.cpp +++ b/src/ZoneWriting/Writing/ContentWriterBase.cpp @@ -23,7 +23,7 @@ void ContentWriterBase::WriteXString(const bool atStreamStart) if (atStreamStart) { assert(varXString != nullptr); - varXStringWritten = m_stream->Write(varXString); + varXStringWritten = m_stream->WriteWithFill(m_stream->GetPointerByteCount()).Offset(); } assert(varXStringWritten.Offset() != nullptr); @@ -40,10 +40,11 @@ void ContentWriterBase::WriteXString(const bool atStreamStart) void ContentWriterBase::WriteXStringArray(const bool atStreamStart, const size_t count) { + const auto pointerByteCount = m_stream->GetPointerByteCount(); if (atStreamStart) { assert(varXString != nullptr); - varXStringWritten = m_stream->Write(varXString, count); + varXStringWritten = m_stream->WriteWithFill(pointerByteCount * count).Offset(); } assert(varXStringWritten.Offset() != nullptr); @@ -52,6 +53,6 @@ void ContentWriterBase::WriteXStringArray(const bool atStreamStart, const size_t { WriteXString(false); varXString++; - varXStringWritten.Inc(m_stream->GetPointerByteCount()); + varXStringWritten.Inc(pointerByteCount); } } diff --git a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp index 42952a21..e89523b4 100644 --- a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp +++ b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp @@ -14,9 +14,6 @@ namespace { - inline const auto PTR_FOLLOWING = reinterpret_cast(-1); - inline const auto PTR_INSERT = reinterpret_cast(-2); - class ReusableEntry { public: @@ -182,6 +179,35 @@ namespace WriteDataInBlock(src, len + 1); } + ZoneStreamFillWriteAccessor WriteWithFill(const size_t size) override + { + // If no block has been pushed, load raw + if (!m_block_stack.empty()) + { + const auto* block = m_block_stack.top(); + + void* result = nullptr; + switch (block->m_type) + { + case XBlockType::BLOCK_TYPE_TEMP: + case XBlockType::BLOCK_TYPE_NORMAL: + result = m_zone_data.GetBufferOfSize(size); + break; + + case XBlockType::BLOCK_TYPE_RUNTIME: + case XBlockType::BLOCK_TYPE_DELAY: + assert(false); + break; + } + + IncBlockPos(size); + + return ZoneStreamFillWriteAccessor(result, size); + } + + return ZoneStreamFillWriteAccessor(m_zone_data.GetBufferOfSize(size), size); + } + void MarkFollowing(const ZoneOutputOffset outputOffset) override { assert(!m_block_stack.empty()); @@ -305,9 +331,9 @@ ZoneOutputOffset::ZoneOutputOffset(void* offset) { } -void* ZoneOutputOffset::Offset() const +ZoneOutputOffset ZoneOutputOffset::AtOffset(const size_t innerOffset) const { - return m_offset; + return ZoneOutputOffset(static_cast(m_offset) + innerOffset); } void ZoneOutputOffset::Inc(const size_t size) @@ -315,9 +341,9 @@ void ZoneOutputOffset::Inc(const size_t size) m_offset = static_cast(static_cast(m_offset) + size); } -ZoneOutputOffset ZoneOutputOffset::WithInnerOffset(const size_t innerOffset) const +void* ZoneOutputOffset::Offset() const { - return ZoneOutputOffset(static_cast(m_offset) + innerOffset); + return m_offset; } std::unique_ptr @@ -325,3 +351,19 @@ std::unique_ptr { return std::make_unique(pointerBitCount, blockBitCount, blocks, insertBlock, zoneData); } + +ZoneStreamFillWriteAccessor::ZoneStreamFillWriteAccessor(void* blockBuffer, const size_t bufferSize) + : m_block_buffer(blockBuffer), + m_buffer_size(bufferSize) +{ +} + +ZoneStreamFillWriteAccessor ZoneStreamFillWriteAccessor::AtOffset(const size_t offset) const +{ + return ZoneStreamFillWriteAccessor(static_cast(m_block_buffer) + offset, m_buffer_size - offset); +} + +ZoneOutputOffset ZoneStreamFillWriteAccessor::Offset() const +{ + return ZoneOutputOffset(m_block_buffer); +} diff --git a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h index 3b6aa2ff..46e8e472 100644 --- a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h +++ b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h @@ -4,6 +4,7 @@ #include "Zone/Stream/IZoneStream.h" #include "Zone/XBlock.h" +#include #include #include #include @@ -16,14 +17,41 @@ public: ZoneOutputOffset(); explicit ZoneOutputOffset(void* offset); - [[nodiscard]] void* Offset() const; + [[nodiscard]] ZoneOutputOffset AtOffset(size_t innerOffset) const; void Inc(size_t size); - [[nodiscard]] ZoneOutputOffset WithInnerOffset(size_t innerOffset) const; + [[nodiscard]] void* Offset() const; private: void* m_offset; }; +class ZoneStreamFillWriteAccessor +{ +public: + ZoneStreamFillWriteAccessor(void* blockBuffer, size_t bufferSize); + + [[nodiscard]] ZoneStreamFillWriteAccessor AtOffset(size_t offset) const; + [[nodiscard]] ZoneOutputOffset Offset() const; + + template void Fill(const T& value, const size_t offset) const + { + assert(offset + sizeof(T) <= m_buffer_size); + + *reinterpret_cast(static_cast(m_block_buffer) + offset) = value; + } + + template void FillArray(T (&value)[S], const size_t offset) const + { + assert(offset + sizeof(T) * S <= m_buffer_size); + + std::memcpy(static_cast(m_block_buffer) + offset, value, sizeof(T) * S); + } + +private: + void* m_block_buffer; + size_t m_buffer_size; +}; + class ZoneOutputStream : public IZoneStream { public: @@ -59,6 +87,8 @@ public: virtual void IncBlockPos(size_t size) = 0; virtual void WriteNullTerminated(const void* dst) = 0; + virtual ZoneStreamFillWriteAccessor WriteWithFill(size_t size) = 0; + virtual bool ReusableShouldWrite(void* pPtr, ZoneOutputOffset outputOffset, size_t size, std::type_index type) = 0; virtual void ReusableAddOffset(void* ptr, size_t size, size_t count, std::type_index type) = 0; virtual void MarkFollowing(ZoneOutputOffset offset) = 0; From 7dffc77ed7852c26052f757fa1162ff054bda821 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 10 Jan 2026 01:08:04 +0000 Subject: [PATCH 10/20] refactor: fill structs in templates when writing on x64 hosts --- .../Templates/Internal/BaseTemplate.cpp | 10 + .../Templates/Internal/BaseTemplate.h | 3 + .../Generating/Templates/ZoneLoadTemplate.cpp | 13 +- .../Templates/ZoneWriteTemplate.cpp | 393 ++++++++++++++++-- .../Zone/Stream/ZoneOutputStream.cpp | 8 +- .../Zone/Stream/ZoneOutputStream.h | 1 + 6 files changed, 384 insertions(+), 44 deletions(-) diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.cpp index b9a3778b..dca825c9 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.cpp @@ -1,6 +1,7 @@ #include "BaseTemplate.h" #include "Domain/Computations/MemberComputations.h" +#include "Domain/Computations/StructureComputations.h" #include "Domain/Definition/ArrayDeclarationModifier.h" #include @@ -262,6 +263,15 @@ std::string BaseTemplate::MakeEvaluation(const IEvaluation* evaluation) return str.str(); } +bool BaseTemplate::ShouldGenerateFillMethod(const RenderingUsedType& type) +{ + const auto isNotForeignAsset = type.m_is_context_asset || !type.m_info || !StructureComputations(type.m_info).IsAsset(); + const auto hasMismatchingStructure = type.m_info && type.m_type == type.m_info->m_definition && !type.m_info->m_has_matching_cross_platform_structure; + const auto isEmbeddedDynamic = type.m_info && type.m_info->m_embedded_reference_exists && StructureComputations(type.m_info).GetDynamicMember(); + + return isNotForeignAsset && (hasMismatchingStructure || isEmbeddedDynamic); +} + size_t BaseTemplate::SizeForDeclModifierLevel(const MemberInformation& memberInfo, const size_t level) const { const auto& declModifiers = memberInfo.m_member->m_type_declaration->m_declaration_modifiers; diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.h b/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.h index e20e5e54..d35a76fc 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.h +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.h @@ -6,6 +6,7 @@ #include "Domain/Evaluation/OperandStatic.h" #include "Domain/Evaluation/Operation.h" #include "Generating/BaseRenderingContext.h" +#include "Generating/OncePerAssetRenderingContext.h" #include #include @@ -34,6 +35,8 @@ protected: static std::string MakeArrayCount(const ArrayDeclarationModifier* arrayModifier); static std::string MakeEvaluation(const IEvaluation* evaluation); + static bool ShouldGenerateFillMethod(const RenderingUsedType& type); + static void MakeSafeTypeNameInternal(const DataDefinition* def, std::ostringstream& str); static void MakeArrayIndicesInternal(const DeclarationModifierComputations& modifierComputations, std::ostringstream& str); diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp index 6c213543..5ef45bc6 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp @@ -267,16 +267,6 @@ namespace return std::format("{0}** var{1}Ptr;", def->GetFullName(), MakeSafeTypeName(def)); } - static bool ShouldGenerateFillMethod(const RenderingUsedType& type) - { - const auto isNotForeignAsset = type.m_is_context_asset || !type.m_info || !StructureComputations(type.m_info).IsAsset(); - const auto hasMismatchingStructure = - type.m_info && type.m_type == type.m_info->m_definition && !type.m_info->m_has_matching_cross_platform_structure; - const auto isEmbeddedDynamic = type.m_info && type.m_info->m_embedded_reference_exists && StructureComputations(type.m_info).GetDynamicMember(); - - return isNotForeignAsset && (hasMismatchingStructure || isEmbeddedDynamic); - } - void PrintFillStructMethodDeclaration(const StructureInformation* info) const { LINEF("void FillStruct_{0}(const ZoneStreamFillReadAccessor& fillAccessor);", MakeSafeTypeName(info->m_definition)) @@ -355,7 +345,8 @@ namespace for (const auto* type : m_env.m_used_types) { - if (type->m_info && !type->m_info->m_definition->m_anonymous && !type->m_info->m_is_leaf && !StructureComputations(type->m_info).IsAsset()) + if (type->m_info && !type->m_info->m_definition->m_anonymous + && (!type->m_info->m_is_leaf || !type->m_info->m_has_matching_cross_platform_structure) && !StructureComputations(type->m_info).IsAsset()) { PrintVariableInitialization(type->m_type); } diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp index d7d29c95..f5a73817 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp @@ -79,6 +79,16 @@ namespace m_intendation++; // Method Declarations + if (m_env.m_architecture_mismatch) + { + for (const auto* type : m_env.m_used_types) + { + if (ShouldGenerateFillMethod(*type)) + { + PrintFillStructMethodDeclaration(type->m_info); + } + } + } for (const auto* type : m_env.m_used_types) { if (type->m_pointer_array_reference_exists) @@ -114,7 +124,8 @@ namespace // Variable Declarations: type varType; for (const auto* type : m_env.m_used_types) { - if (type->m_info && !type->m_info->m_definition->m_anonymous && !type->m_info->m_is_leaf && !StructureComputations(type->m_info).IsAsset()) + if (type->m_info && !type->m_info->m_definition->m_anonymous + && (!type->m_info->m_is_leaf || !type->m_info->m_has_matching_cross_platform_structure) && !StructureComputations(type->m_info).IsAsset()) LINE(VariableDecl(type->m_type)) } for (const auto* type : m_env.m_used_types) @@ -167,6 +178,17 @@ namespace LINE("") PrintMainWriteMethod(); + if (m_env.m_architecture_mismatch) + { + for (const auto* type : m_env.m_used_types) + { + if (ShouldGenerateFillMethod(*type)) + { + LINE("") + PrintFillStructMethod(type->m_info); + } + } + } for (const auto* type : m_env.m_used_types) { if (type->m_pointer_array_reference_exists) @@ -233,6 +255,11 @@ namespace return std::format("ZoneOutputOffset var{0}PtrWritten;", MakeSafeTypeName(def)); } + void PrintFillStructMethodDeclaration(const StructureInformation* info) const + { + LINEF("void FillStruct_{0}(const ZoneStreamFillWriteAccessor& fillAccessor);", MakeSafeTypeName(info->m_definition)) + } + void PrintHeaderPtrArrayWriteMethodDeclaration(const DataDefinition* def) const { LINEF("void WritePtrArray_{0}(bool atStreamStart, size_t count);", MakeSafeTypeName(def)) @@ -343,7 +370,8 @@ namespace for (const auto* type : m_env.m_used_types) { - if (type->m_info && !type->m_info->m_definition->m_anonymous && !type->m_info->m_is_leaf && !StructureComputations(type->m_info).IsAsset()) + if (type->m_info && !type->m_info->m_definition->m_anonymous + && (!type->m_info->m_is_leaf || !type->m_info->m_has_matching_cross_platform_structure) && !StructureComputations(type->m_info).IsAsset()) PrintVariableInitialization(type->m_type); } for (const auto* type : m_env.m_used_types) @@ -444,7 +472,7 @@ namespace } } - void WriteMember_ArrayPointer(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier) const + void WriteMember_ArrayPointer(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier) { const MemberComputations computations(member); LINEF("m_stream->MarkFollowing({0});", MakeWrittenMemberAccess(info, member, modifier)) @@ -455,6 +483,20 @@ namespace MakeSafeTypeName(member->m_member->m_type_declaration->m_type), MakeEvaluation(modifier.GetArrayPointerCountEvaluation())) } + else if (member->m_type && !member->m_type->m_has_matching_cross_platform_structure) + { + LINEF("const auto fillArraySize = static_cast({0});", MakeEvaluation(modifier.GetArrayPointerCountEvaluation())) + LINEF("const auto fill = m_stream->WriteWithFill({0} * fillArraySize);", member->m_member->m_type_declaration->m_type->GetSize()) + LINE("for (auto i = 0uz; i < fillArraySize; i++)") + LINE("{") + m_intendation++; + LINEF("{0} = &{1}[i];", MakeTypeVarName(member->m_type->m_definition), MakeMemberAccess(info, member, modifier)) + LINEF("FillStruct_{0}(fill.AtOffset(i * {1}));", + MakeSafeTypeName(member->m_type->m_definition), + member->m_member->m_type_declaration->m_type->GetSize()) + m_intendation--; + LINE("}") + } else { LINEF("m_stream->Write<{0}{1}>({2}, {3});", @@ -571,6 +613,13 @@ namespace LINEF("{0} = {1};", MakeTypeVarName(member->m_member->m_type_declaration->m_type), MakeMemberAccess(info, member, modifier)) LINEF("Write_{0}(true);", MakeSafeTypeName(member->m_type->m_definition)) } + else if (member->m_type && !member->m_type->m_has_matching_cross_platform_structure) + { + LINEF("{0} = {1};", MakeTypeVarName(member->m_member->m_type_declaration->m_type), MakeMemberAccess(info, member, modifier)) + LINEF("FillStruct_{0}(m_stream->WriteWithFill({1}));", + MakeSafeTypeName(member->m_member->m_type_declaration->m_type), + member->m_member->m_type_declaration->m_type->GetSize()) + } else { LINEF("m_stream->Write<{0}{1}>({2});", @@ -583,7 +632,7 @@ namespace void WriteMember_TypeCheck(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier, - const MemberWriteType writeType) const + const MemberWriteType writeType) { if (member->m_is_string) { @@ -667,7 +716,7 @@ namespace void WriteMember_InsertReuse(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier, - const MemberWriteType writeType) const + const MemberWriteType writeType) { if (!WriteMember_ShouldMakeInsertReuse(member, modifier, writeType)) { @@ -733,7 +782,7 @@ namespace void WriteMember_Align(const StructureInformation* info, const MemberInformation* member, const DeclarationModifierComputations& modifier, - const MemberWriteType writeType) const + const MemberWriteType writeType) { if (!WriteMember_ShouldMakeAlign(member, modifier, writeType)) { @@ -1042,27 +1091,40 @@ namespace if (!(info->m_definition->GetType() == DataDefinitionType::UNION && dynamicMember)) { LINE("if (atStreamStart)") - m_intendation++; - if (dynamicMember == nullptr) + if (info->m_has_matching_cross_platform_structure) { - LINEF("{0} = m_stream->Write<{1}>({2}); // Size: {3}", - MakeTypeWrittenVarName(info->m_definition), - info->m_definition->GetFullName(), - MakeTypeVarName(info->m_definition), - info->m_definition->GetSize()) + m_intendation++; + if (dynamicMember == nullptr) + { + LINEF("{0} = m_stream->Write<{1}>({2}); // Size: {3}", + MakeTypeWrittenVarName(info->m_definition), + info->m_definition->GetFullName(), + MakeTypeVarName(info->m_definition), + info->m_definition->GetSize()) + } + else + { + LINEF("{0} = m_stream->WritePartial({1}, offsetof({2}, {3}));", + MakeTypeWrittenVarName(info->m_definition), + MakeTypeVarName(info->m_definition), + info->m_definition->GetFullName(), + dynamicMember->m_member->m_name) + } + m_intendation--; } else { - LINEF("{0} = m_stream->WritePartial({1}, offsetof({2}, {3}));", - MakeTypeWrittenVarName(info->m_definition), - MakeTypeVarName(info->m_definition), - info->m_definition->GetFullName(), - dynamicMember->m_member->m_name) + LINE("{") + m_intendation++; + LINEF("const auto fillAccessor = m_stream->WriteWithFill({0});", + dynamicMember == nullptr ? info->m_definition->GetSize() : dynamicMember->m_member->m_offset) + LINEF("{0} = fillAccessor.Offset();", MakeTypeWrittenVarName(info->m_definition)) + LINEF("FillStruct_{0}(fillAccessor);", MakeSafeTypeName(info->m_definition)) + m_intendation--; + LINE("}") } - m_intendation--; - LINE("") LINEF("assert({0}.Offset() != nullptr);", MakeTypeWrittenVarName(info->m_definition)) } @@ -1109,10 +1171,7 @@ namespace LINE("if (atStreamStart)") m_intendation++; - LINEF("{0} = m_stream->Write<{1}*>({2});", - MakeTypeWrittenPtrVarName(info->m_definition), - info->m_definition->GetFullName(), - MakeTypePtrVarName(info->m_definition)) + LINEF("{0} = m_stream->WriteWithFill(m_stream->GetPointerByteCount()).Offset();", MakeTypeWrittenPtrVarName(info->m_definition)) m_intendation--; LINE("") @@ -1178,6 +1237,253 @@ namespace LINE("}") } + void PrintFillStruct_Member_EmbeddedArray(const StructureInformation& structInfo, + const MemberInformation& memberInfo, + const DeclarationModifierComputations& modifier, + const size_t nestedBaseOffset) + { + if (memberInfo.m_type && !memberInfo.m_type->m_has_matching_cross_platform_structure) + { + LINEF("for (auto i = 0u; i < std::extent_v; i++)", structInfo.m_definition->m_name, memberInfo.m_member->m_name) + LINE("{") + m_intendation++; + LINEF("{0} = &{1}[i];", MakeTypeVarName(memberInfo.m_member->m_type_declaration->m_type), MakeMemberAccess(&structInfo, &memberInfo, modifier)) + LINEF("FillStruct_{0}(fillAccessor.AtOffset({1} + i * {2}));", + MakeSafeTypeName(memberInfo.m_member->m_type_declaration->m_type), + OffsetForMemberModifier(memberInfo, modifier, nestedBaseOffset), + memberInfo.m_member->m_type_declaration->m_type->GetSize()) + m_intendation--; + LINE("}") + } + else + { + LINEF("fillAccessor.FillArray({0}, {1});", + MakeMemberAccess(&structInfo, &memberInfo, modifier), + OffsetForMemberModifier(memberInfo, modifier, nestedBaseOffset)) + } + } + + void PrintFillStruct_Member_Embedded(const StructureInformation& structInfo, + const MemberInformation& memberInfo, + const DeclarationModifierComputations& modifier, + const size_t nestedBaseOffset) + { + const auto hasAnonymousType = memberInfo.m_type && memberInfo.m_type->m_definition->m_anonymous; + + if (!hasAnonymousType) + { + const auto hasMismatchingStructure = memberInfo.m_type && !memberInfo.m_type->m_has_matching_cross_platform_structure; + const auto hasDynamicMember = memberInfo.m_type && StructureComputations(memberInfo.m_type).GetDynamicMember(); + if (hasMismatchingStructure || hasDynamicMember) + { + LINEF("{0} = &{1};", MakeTypeVarName(memberInfo.m_member->m_type_declaration->m_type), MakeMemberAccess(&structInfo, &memberInfo, modifier)) + LINEF("FillStruct_{0}(fillAccessor.AtOffset({1}));", + MakeSafeTypeName(memberInfo.m_member->m_type_declaration->m_type), + OffsetForMemberModifier(memberInfo, modifier, nestedBaseOffset)) + } + else + { + LINEF("fillAccessor.Fill({0}, {1});", + MakeMemberAccess(&structInfo, &memberInfo, modifier), + OffsetForMemberModifier(memberInfo, modifier, nestedBaseOffset)) + } + } + else if (memberInfo.m_member->m_name.empty()) + { + const auto anonymousMemberOffset = memberInfo.m_member->m_offset + nestedBaseOffset; + for (const auto& anonymousMember : memberInfo.m_type->m_ordered_members) + { + PrintFillStruct_Member(structInfo, *anonymousMember, DeclarationModifierComputations(anonymousMember.get()), anonymousMemberOffset); + } + } + else + { + LINEF("#error Unsupported anonymous struct with name: {0}", memberInfo.m_member->m_name) + } + } + + void PrintFillStruct_Member_ReferenceArray(const StructureInformation& info, + const MemberInformation& member, + const DeclarationModifierComputations& modifier, + const size_t nestedBaseOffset) + { + for (const auto& entry : modifier.GetArrayEntries()) + { + PrintFillStruct_Member(info, member, entry, nestedBaseOffset); + } + } + + // nestedBaseOffset: Base offset in case member is part of a nested anonymous sub-struct + void PrintFillStruct_Member(const StructureInformation& structInfo, + const MemberInformation& memberInfo, + const DeclarationModifierComputations& modifier, + const size_t nestedBaseOffset) + { + if (modifier.IsDynamicArray()) + { + } + else if (modifier.IsArray() && modifier.GetNextDeclarationModifier() == nullptr) + { + PrintFillStruct_Member_EmbeddedArray(structInfo, memberInfo, modifier, nestedBaseOffset); + } + else if (modifier.GetDeclarationModifier() == nullptr) + { + PrintFillStruct_Member_Embedded(structInfo, memberInfo, modifier, nestedBaseOffset); + } + else if (modifier.IsArray()) + { + PrintFillStruct_Member_ReferenceArray(structInfo, memberInfo, modifier, nestedBaseOffset); + } + else + { + assert(false); + LINEF("#error PrintFillStruct_Member failed @ {0}", memberInfo.m_member->m_name) + } + } + + void PrintFillStruct_Member_Condition_Union(const StructureInformation& structInfo, + const MemberInformation& member, + const DeclarationModifierComputations& modifier) + { + const MemberComputations computations(&member); + + if (computations.IsFirstUsedMember()) + { + if (member.m_condition) + { + LINEF("if ({0})", MakeEvaluation(member.m_condition.get())) + LINE("{") + m_intendation++; + + PrintFillStruct_Member(structInfo, member, modifier, 0u); + + m_intendation--; + LINE("}") + } + else + { + PrintFillStruct_Member(structInfo, member, modifier, 0u); + } + } + else if (computations.IsLastUsedMember()) + { + if (member.m_condition) + { + LINEF("else if ({0})", MakeEvaluation(member.m_condition.get())) + LINE("{") + m_intendation++; + + PrintFillStruct_Member(structInfo, member, modifier, 0u); + + m_intendation--; + LINE("}") + } + else + { + LINE("else") + LINE("{") + m_intendation++; + + PrintFillStruct_Member(structInfo, member, modifier, 0u); + + m_intendation--; + LINE("}") + } + } + else + { + if (member.m_condition) + { + LINEF("else if ({0})", MakeEvaluation(member.m_condition.get())) + LINE("{") + m_intendation++; + + PrintFillStruct_Member(structInfo, member, modifier, 0u); + + m_intendation--; + LINE("}") + } + else + { + LINEF("#error Middle member of union2 must have condition ({0})", member.m_member->m_name) + } + } + } + + static bool ShouldFillMember(const DeclarationModifierComputations& modifier) + { + return !modifier.HasPointerModifier(); + } + + void PrintFillStruct_Struct(const StructureInformation& info) + { + const auto* dynamicMember = StructureComputations(&info).GetDynamicMember(); + + if (dynamicMember) + { + if (info.m_definition->GetType() == DataDefinitionType::UNION) + { + for (const auto& member : info.m_ordered_members) + { + const MemberComputations computations(member.get()); + if (computations.ShouldIgnore()) + continue; + + DeclarationModifierComputations modifier(member.get()); + if (!ShouldFillMember(modifier)) + continue; + + PrintFillStruct_Member_Condition_Union(info, *member, modifier); + } + } + else + { + for (const auto& member : info.m_ordered_members) + { + const MemberComputations computations(member.get()); + if (computations.ShouldIgnore() || member.get() == dynamicMember) + continue; + + DeclarationModifierComputations modifier(member.get()); + if (!ShouldFillMember(modifier)) + continue; + + PrintFillStruct_Member(info, *member, modifier, 0u); + } + } + } + else + { + for (const auto& member : info.m_ordered_members) + { + const MemberComputations computations(member.get()); + if (computations.ShouldIgnore()) + continue; + + DeclarationModifierComputations modifier(member.get()); + if (!ShouldFillMember(modifier)) + continue; + + PrintFillStruct_Member(info, *member, modifier, 0u); + } + } + } + + void PrintFillStructMethod(const StructureInformation* info) + { + LINEF("void {0}::FillStruct_{1}(const ZoneStreamFillWriteAccessor& fillAccessor)", + WriterClassName(m_env.m_asset), + MakeSafeTypeName(info->m_definition)) + + LINE("{") + m_intendation++; + + PrintFillStruct_Struct(*info); + + m_intendation--; + LINE("}") + } + void PrintWritePtrArrayMethod_Loading(const DataDefinition* def, const StructureInformation* info, const bool reusable) const { LINEF("m_stream->Align({0});", def->GetAlignment()) @@ -1244,7 +1550,7 @@ namespace LINE("if (atStreamStart)") m_intendation++; - LINEF("{0} = m_stream->Write<{1}*>({2}, count);", MakeTypeWrittenPtrVarName(def), def->GetFullName(), MakeTypePtrVarName(def)) + LINEF("{0} = m_stream->WriteWithFill(m_stream->GetPointerByteCount() * count).Offset();", MakeTypeWrittenPtrVarName(def)) m_intendation--; LINE("") @@ -1279,9 +1585,38 @@ namespace LINEF("assert({0} != nullptr);", MakeTypeVarName(def)) LINE("") LINE("if (atStreamStart)") - m_intendation++; - LINEF("{0} = m_stream->Write<{1}>({2}, count);", MakeTypeWrittenVarName(def), def->GetFullName(), MakeTypeVarName(def)) - m_intendation--; + + if (info->m_has_matching_cross_platform_structure) + { + m_intendation++; + LINEF("{0} = m_stream->Write<{1}>({2}, count);", MakeTypeWrittenVarName(def), def->GetFullName(), MakeTypeVarName(def)) + m_intendation--; + } + else + { + LINE("{") + m_intendation++; + + LINEF("const auto arrayFill = m_stream->WriteWithFill({0} * count);", def->GetSize()) + LINEF("{0} = arrayFill.Offset();", MakeTypeWrittenVarName(info->m_definition)) + LINEF("auto* arrayStart = {0};", MakeTypeVarName(def)) + LINEF("auto* var = {0};", MakeTypeVarName(def)) + LINE("for (size_t index = 0; index < count; index++)") + LINE("{") + m_intendation++; + + LINEF("{0} = var;", MakeTypeVarName(info->m_definition)) + LINEF("FillStruct_{0}(arrayFill.AtOffset(0 + {1} * index));", info->m_definition->m_name, def->GetSize()) + LINE("var++;") + + m_intendation--; + LINE("}") + + LINEF("{0} = arrayStart;", MakeTypeVarName(def)) + + m_intendation--; + LINE("}") + } LINE("") LINEF("assert({0}.Offset() != nullptr);", MakeTypeWrittenVarName(def)) @@ -1297,7 +1632,7 @@ namespace LINEF("{0} = varWritten;", MakeTypeWrittenVarName(info->m_definition)) LINEF("Write_{0}(false);", info->m_definition->m_name) LINE("var++;") - LINE("varWritten.Inc(m_stream->GetPointerByteCount());") + LINEF("varWritten.Inc({0});", def->GetSize()) m_intendation--; LINE("}") diff --git a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp index e89523b4..6806f2fe 100644 --- a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp +++ b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp @@ -284,8 +284,8 @@ namespace assert(m_block_stack.top()->m_type == XBlockType::BLOCK_TYPE_NORMAL); uintptr_t ptr = 0; - ptr |= static_cast(m_block_stack.top()->m_index) << (sizeof(uintptr_t) * 8 - m_block_bit_count); - ptr |= m_block_stack.top()->m_buffer_size & (UINTPTR_MAX >> m_block_bit_count); + ptr |= static_cast(m_block_stack.top()->m_index) << (m_pointer_byte_count * 8 - m_block_bit_count); + ptr |= m_block_stack.top()->m_buffer_size & (UINTPTR_MAX >> (m_block_bit_count + (sizeof(uintptr_t) - m_pointer_byte_count) * 8)); ptr++; return ptr; @@ -295,9 +295,9 @@ namespace { PushBlock(m_insert_block->m_index); - Align(sizeof(uintptr_t)); + Align(m_pointer_byte_count); const auto result = GetCurrentZonePointer(); - IncBlockPos(sizeof(uintptr_t)); + IncBlockPos(m_pointer_byte_count); PopBlock(); diff --git a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h index 46e8e472..b9d67d13 100644 --- a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h +++ b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include From 1dc25ee20ab705e65433eb74093c05ed5a637430 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sun, 11 Jan 2026 14:27:48 +0100 Subject: [PATCH 11/20] fix: use correct written variable for WriteArray zone code methods --- .../Generating/Templates/ZoneWriteTemplate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp index f5a73817..0c9f2da2 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp @@ -1598,7 +1598,7 @@ namespace m_intendation++; LINEF("const auto arrayFill = m_stream->WriteWithFill({0} * count);", def->GetSize()) - LINEF("{0} = arrayFill.Offset();", MakeTypeWrittenVarName(info->m_definition)) + LINEF("{0} = arrayFill.Offset();", MakeTypeWrittenVarName(def)) LINEF("auto* arrayStart = {0};", MakeTypeVarName(def)) LINEF("auto* var = {0};", MakeTypeVarName(def)) LINE("for (size_t index = 0; index < count; index++)") From 0be778cf5cdedd6a90591991c4e2260d42bbffec Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sun, 11 Jan 2026 21:43:01 +0000 Subject: [PATCH 12/20] fix: do not fill in runtime block members --- .../Templates/ZoneWriteTemplate.cpp | 27 ++++++++++++------- .../Zone/Stream/ZoneOutputStream.cpp | 2 ++ .../Zone/Stream/ZoneOutputStream.h | 2 ++ 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp index 0c9f2da2..a8d21d53 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp @@ -486,16 +486,23 @@ namespace else if (member->m_type && !member->m_type->m_has_matching_cross_platform_structure) { LINEF("const auto fillArraySize = static_cast({0});", MakeEvaluation(modifier.GetArrayPointerCountEvaluation())) - LINEF("const auto fill = m_stream->WriteWithFill({0} * fillArraySize);", member->m_member->m_type_declaration->m_type->GetSize()) - LINE("for (auto i = 0uz; i < fillArraySize; i++)") - LINE("{") - m_intendation++; - LINEF("{0} = &{1}[i];", MakeTypeVarName(member->m_type->m_definition), MakeMemberAccess(info, member, modifier)) - LINEF("FillStruct_{0}(fill.AtOffset(i * {1}));", - MakeSafeTypeName(member->m_type->m_definition), - member->m_member->m_type_declaration->m_type->GetSize()) - m_intendation--; - LINE("}") + if (!computations.IsInRuntimeBlock()) + { + LINEF("const auto fill = m_stream->WriteWithFill({0} * fillArraySize);", member->m_member->m_type_declaration->m_type->GetSize()) + LINE("for (auto i = 0uz; i < fillArraySize; i++)") + LINE("{") + m_intendation++; + LINEF("{0} = &{1}[i];", MakeTypeVarName(member->m_type->m_definition), MakeMemberAccess(info, member, modifier)) + LINEF("FillStruct_{0}(fill.AtOffset(i * {1}));", + MakeSafeTypeName(member->m_type->m_definition), + member->m_member->m_type_declaration->m_type->GetSize()) + m_intendation--; + LINE("}") + } + else + { + LINEF("m_stream->IncBlockPos({0} * fillArraySize);", member->m_member->m_type_declaration->m_type->GetSize()) + } } else { diff --git a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp index 6806f2fe..e7dd69d7 100644 --- a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp +++ b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp @@ -360,10 +360,12 @@ ZoneStreamFillWriteAccessor::ZoneStreamFillWriteAccessor(void* blockBuffer, cons ZoneStreamFillWriteAccessor ZoneStreamFillWriteAccessor::AtOffset(const size_t offset) const { + assert(m_block_buffer); return ZoneStreamFillWriteAccessor(static_cast(m_block_buffer) + offset, m_buffer_size - offset); } ZoneOutputOffset ZoneStreamFillWriteAccessor::Offset() const { + assert(m_block_buffer); return ZoneOutputOffset(m_block_buffer); } diff --git a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h index b9d67d13..8dba427b 100644 --- a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h +++ b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h @@ -36,6 +36,7 @@ public: template void Fill(const T& value, const size_t offset) const { + assert(m_block_buffer); assert(offset + sizeof(T) <= m_buffer_size); *reinterpret_cast(static_cast(m_block_buffer) + offset) = value; @@ -43,6 +44,7 @@ public: template void FillArray(T (&value)[S], const size_t offset) const { + assert(m_block_buffer); assert(offset + sizeof(T) * S <= m_buffer_size); std::memcpy(static_cast(m_block_buffer) + offset, value, sizeof(T) * S); From 51300bb47ca6cab5b2bec0f7b755ac55e93dbcdc Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Wed, 14 Jan 2026 16:22:04 +0000 Subject: [PATCH 13/20] chore: const params in InvalidLookupPositionException --- .../Loading/Exception/InvalidLookupPositionException.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ZoneLoading/Loading/Exception/InvalidLookupPositionException.cpp b/src/ZoneLoading/Loading/Exception/InvalidLookupPositionException.cpp index 66c6d92c..863fd138 100644 --- a/src/ZoneLoading/Loading/Exception/InvalidLookupPositionException.cpp +++ b/src/ZoneLoading/Loading/Exception/InvalidLookupPositionException.cpp @@ -2,7 +2,7 @@ #include -InvalidLookupPositionException::InvalidLookupPositionException(block_t block, size_t offset) +InvalidLookupPositionException::InvalidLookupPositionException(const block_t block, const size_t offset) : m_block(block), m_offset(offset) { From 9f559fdcd07b4e28e7bb48aca2823bf133556e2b Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Wed, 14 Jan 2026 18:36:25 +0000 Subject: [PATCH 14/20] fix: ReusableAddOffset not respecting differing block and memory sizes --- .../Templates/ZoneWriteTemplate.cpp | 28 +++++++++++-------- .../Zone/Stream/ZoneOutputStream.cpp | 16 +++++++---- .../Zone/Stream/ZoneOutputStream.h | 11 ++++++-- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp index a8d21d53..8969ecc1 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp @@ -731,31 +731,37 @@ namespace return; } + LINE_STARTF("m_stream->ReusableAddOffset({0}", MakeMemberAccess(info, member, modifier)) + if (writeType == MemberWriteType::ARRAY_POINTER) { - LINEF("m_stream->ReusableAddOffset({0}, {1});", - MakeMemberAccess(info, member, modifier), - MakeEvaluation(modifier.GetArrayPointerCountEvaluation())) + if (member->m_type && !member->m_type->m_has_matching_cross_platform_structure) + { + LINE_MIDDLEF(", {0}", member->m_type->m_definition->GetSize()) + } + + LINE_MIDDLEF(", {0}", MakeEvaluation(modifier.GetArrayPointerCountEvaluation())) } else if (writeType == MemberWriteType::POINTER_ARRAY) { + if (member->m_type && !member->m_type->m_has_matching_cross_platform_structure) + { + LINE_MIDDLEF(", {0}", m_env.m_pointer_size) + } + const auto* evaluation = modifier.GetPointerArrayCountEvaluation(); if (evaluation) { - LINEF("m_stream->ReusableAddOffset({0}, {1});", - MakeMemberAccess(info, member, modifier), - MakeEvaluation(modifier.GetPointerArrayCountEvaluation())) + LINE_MIDDLEF(", {0}", MakeEvaluation(modifier.GetPointerArrayCountEvaluation())) } else { - LINEF("m_stream->ReusableAddOffset({0}, {1});", MakeMemberAccess(info, member, modifier), modifier.GetArraySize()) + LINE_MIDDLEF(", {0}", modifier.GetArraySize()) } } - else - { - LINEF("m_stream->ReusableAddOffset({0});", MakeMemberAccess(info, member, modifier)) - } + + LINE_END(");") WriteMember_TypeCheck(info, member, modifier, writeType); } diff --git a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp index e7dd69d7..2075773a 100644 --- a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp +++ b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp @@ -17,12 +17,13 @@ namespace class ReusableEntry { public: - ReusableEntry(void* startPtr, const size_t entrySize, const size_t entryCount, const uintptr_t startZonePtr) + ReusableEntry(void* startPtr, const size_t entrySize, const size_t entryCount, const size_t blockSize, const uintptr_t startZonePtr) : m_start_ptr(startPtr), m_end_ptr(reinterpret_cast(reinterpret_cast(startPtr) + entrySize * entryCount)), m_start_zone_ptr(startZonePtr), m_entry_size(entrySize), - m_entry_count(entryCount) + m_entry_count(entryCount), + m_block_size(blockSize) { } @@ -31,6 +32,7 @@ namespace uintptr_t m_start_zone_ptr; size_t m_entry_size; size_t m_entry_count; + size_t m_block_size; }; class InMemoryZoneOutputStream final : public ZoneOutputStream @@ -245,7 +247,9 @@ namespace if (ptr >= entry.m_start_ptr && ptr < entry.m_end_ptr) { assert((reinterpret_cast(ptr) - reinterpret_cast(entry.m_start_ptr)) % entrySize == 0); - const auto finalZonePointer = entry.m_start_zone_ptr + (reinterpret_cast(ptr) - reinterpret_cast(entry.m_start_ptr)); + + const auto entryIndex = (reinterpret_cast(ptr) - reinterpret_cast(entry.m_start_ptr)) / entry.m_entry_size; + const auto finalZonePointer = entry.m_start_zone_ptr + entryIndex * entry.m_block_size; auto* writtenPtrOffset = outputOffset.Offset(); for (auto i = 0u; i < m_pointer_byte_count; i++) @@ -258,7 +262,7 @@ namespace return true; } - void ReusableAddOffset(void* ptr, size_t size, size_t count, std::type_index type) override + void ReusableAddOffset(void* ptr, const size_t size, const size_t count, const size_t blockSize, std::type_index type) override { assert(!m_block_stack.empty()); @@ -268,12 +272,12 @@ namespace if (foundEntriesForType == m_reusable_entries.end()) { std::vector entries; - entries.emplace_back(ptr, size, count, zoneOffset); + entries.emplace_back(ptr, size, count, blockSize, zoneOffset); m_reusable_entries.emplace(std::make_pair(type, std::move(entries))); } else { - foundEntriesForType->second.emplace_back(ptr, size, count, zoneOffset); + foundEntriesForType->second.emplace_back(ptr, size, count, blockSize, zoneOffset); } } diff --git a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h index 8dba427b..0a32486e 100644 --- a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h +++ b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h @@ -93,7 +93,7 @@ public: virtual ZoneStreamFillWriteAccessor WriteWithFill(size_t size) = 0; virtual bool ReusableShouldWrite(void* pPtr, ZoneOutputOffset outputOffset, size_t size, std::type_index type) = 0; - virtual void ReusableAddOffset(void* ptr, size_t size, size_t count, std::type_index type) = 0; + virtual void ReusableAddOffset(void* ptr, size_t size, size_t count, size_t blockSize, std::type_index type) = 0; virtual void MarkFollowing(ZoneOutputOffset offset) = 0; template bool ReusableShouldWrite(T* pPtr, const ZoneOutputOffset outputOffset) @@ -103,12 +103,17 @@ public: template void ReusableAddOffset(T* ptr) { - ReusableAddOffset(const_cast(reinterpret_cast(ptr)), sizeof(T), 1, std::type_index(typeid(T))); + ReusableAddOffset(const_cast(reinterpret_cast(ptr)), sizeof(T), 1, sizeof(T), std::type_index(typeid(T))); } template void ReusableAddOffset(T* ptr, const size_t count) { - ReusableAddOffset(const_cast(reinterpret_cast(ptr)), sizeof(T), count, std::type_index(typeid(T))); + ReusableAddOffset(const_cast(reinterpret_cast(ptr)), sizeof(T), count, sizeof(T), std::type_index(typeid(T))); + } + + template void ReusableAddOffset(T* ptr, const size_t blockSize, const size_t count) + { + ReusableAddOffset(const_cast(reinterpret_cast(ptr)), sizeof(T), count, blockSize, std::type_index(typeid(T))); } template ZoneOutputOffset Write(T* dst) From 00546740e48f01a88184408052762793c82b264e Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Wed, 14 Jan 2026 22:14:43 +0000 Subject: [PATCH 15/20] fix: filling union members that are not supposed to be written * This causes some pointers to be partially overwritten when filling in the wrong order as well --- src/Common/Game/IW3/IW3_Assets.h | 2 +- src/Common/Game/IW4/IW4_Assets.h | 2 +- src/Common/Game/IW5/IW5_Assets.h | 2 +- .../Game/IW3/XAssets/MaterialTechniqueSet.txt | 5 ++ .../Game/IW4/XAssets/MaterialTechniqueSet.txt | 7 +- .../Game/IW5/XAssets/MaterialTechniqueSet.txt | 7 +- .../Game/T5/XAssets/MaterialTechniqueSet.txt | 7 +- .../Game/T6/XAssets/MaterialTechniqueSet.txt | 7 +- .../Computations/MemberComputations.cpp | 8 +-- .../Domain/Computations/MemberComputations.h | 4 +- .../Computations/StructureComputations.cpp | 4 +- .../Computations/StructureComputations.h | 2 +- .../Generating/Templates/ZoneLoadTemplate.cpp | 12 ++-- .../Generating/Templates/ZoneMarkTemplate.cpp | 4 +- .../Templates/ZoneWriteTemplate.cpp | 68 +++++++------------ 15 files changed, 72 insertions(+), 69 deletions(-) diff --git a/src/Common/Game/IW3/IW3_Assets.h b/src/Common/Game/IW3/IW3_Assets.h index 596ed16c..e9bcb463 100644 --- a/src/Common/Game/IW3/IW3_Assets.h +++ b/src/Common/Game/IW3/IW3_Assets.h @@ -2594,8 +2594,8 @@ namespace IW3 union entryInternalData { - int op; Operand operand; + int op; }; enum expressionEntryType : int diff --git a/src/Common/Game/IW4/IW4_Assets.h b/src/Common/Game/IW4/IW4_Assets.h index c06c59f7..1e3437e1 100644 --- a/src/Common/Game/IW4/IW4_Assets.h +++ b/src/Common/Game/IW4/IW4_Assets.h @@ -2044,8 +2044,8 @@ namespace IW4 union entryInternalData { - int op; Operand operand; + int op; }; enum expressionEntryType : int diff --git a/src/Common/Game/IW5/IW5_Assets.h b/src/Common/Game/IW5/IW5_Assets.h index befefc05..4613e8b0 100644 --- a/src/Common/Game/IW5/IW5_Assets.h +++ b/src/Common/Game/IW5/IW5_Assets.h @@ -2608,8 +2608,8 @@ namespace IW5 union entryInternalData { - int op; Operand operand; + int op; }; struct expressionEntry diff --git a/src/ZoneCode/Game/IW3/XAssets/MaterialTechniqueSet.txt b/src/ZoneCode/Game/IW3/XAssets/MaterialTechniqueSet.txt index 406c7870..50fda5da 100644 --- a/src/ZoneCode/Game/IW3/XAssets/MaterialTechniqueSet.txt +++ b/src/ZoneCode/Game/IW3/XAssets/MaterialTechniqueSet.txt @@ -27,6 +27,11 @@ use MaterialShaderArgument; set condition u::literalConst type == MTL_ARG_LITERAL_VERTEX_CONST || type == MTL_ARG_LITERAL_PIXEL_CONST; set reusable u::literalConst; +set condition u::codeConst type == MTL_ARG_CODE_VERTEX_CONST +|| type == MTL_ARG_CODE_PIXEL_CONST; +set condition u::codeSampler type == MTL_ARG_CODE_PIXEL_SAMPLER; +set condition u::nameHash type == MTL_ARG_MATERIAL_VERTEX_CONST +|| type == MTL_ARG_MATERIAL_PIXEL_CONST || type == MTL_ARG_MATERIAL_PIXEL_SAMPLER; // MaterialPixelShader set string MaterialPixelShader::name; diff --git a/src/ZoneCode/Game/IW4/XAssets/MaterialTechniqueSet.txt b/src/ZoneCode/Game/IW4/XAssets/MaterialTechniqueSet.txt index 4769818a..9daf9333 100644 --- a/src/ZoneCode/Game/IW4/XAssets/MaterialTechniqueSet.txt +++ b/src/ZoneCode/Game/IW4/XAssets/MaterialTechniqueSet.txt @@ -23,4 +23,9 @@ set count args perPrimArgCount + perObjArgCount + stableArgCount; use MaterialShaderArgument; set condition u::literalConst type == MTL_ARG_LITERAL_VERTEX_CONST || type == MTL_ARG_LITERAL_PIXEL_CONST; -set reusable u::literalConst; \ No newline at end of file +set reusable u::literalConst; +set condition u::codeConst type == MTL_ARG_CODE_VERTEX_CONST +|| type == MTL_ARG_CODE_PIXEL_CONST; +set condition u::codeSampler type == MTL_ARG_CODE_PIXEL_SAMPLER; +set condition u::nameHash type == MTL_ARG_MATERIAL_VERTEX_CONST +|| type == MTL_ARG_MATERIAL_PIXEL_CONST || type == MTL_ARG_MATERIAL_PIXEL_SAMPLER; \ No newline at end of file diff --git a/src/ZoneCode/Game/IW5/XAssets/MaterialTechniqueSet.txt b/src/ZoneCode/Game/IW5/XAssets/MaterialTechniqueSet.txt index 4769818a..9daf9333 100644 --- a/src/ZoneCode/Game/IW5/XAssets/MaterialTechniqueSet.txt +++ b/src/ZoneCode/Game/IW5/XAssets/MaterialTechniqueSet.txt @@ -23,4 +23,9 @@ set count args perPrimArgCount + perObjArgCount + stableArgCount; use MaterialShaderArgument; set condition u::literalConst type == MTL_ARG_LITERAL_VERTEX_CONST || type == MTL_ARG_LITERAL_PIXEL_CONST; -set reusable u::literalConst; \ No newline at end of file +set reusable u::literalConst; +set condition u::codeConst type == MTL_ARG_CODE_VERTEX_CONST +|| type == MTL_ARG_CODE_PIXEL_CONST; +set condition u::codeSampler type == MTL_ARG_CODE_PIXEL_SAMPLER; +set condition u::nameHash type == MTL_ARG_MATERIAL_VERTEX_CONST +|| type == MTL_ARG_MATERIAL_PIXEL_CONST || type == MTL_ARG_MATERIAL_PIXEL_SAMPLER; \ No newline at end of file diff --git a/src/ZoneCode/Game/T5/XAssets/MaterialTechniqueSet.txt b/src/ZoneCode/Game/T5/XAssets/MaterialTechniqueSet.txt index e539d863..b1f51957 100644 --- a/src/ZoneCode/Game/T5/XAssets/MaterialTechniqueSet.txt +++ b/src/ZoneCode/Game/T5/XAssets/MaterialTechniqueSet.txt @@ -46,4 +46,9 @@ set count GfxPixelShaderLoadDef::program programSize; use MaterialShaderArgument; set condition u::literalConst type == MTL_ARG_LITERAL_VERTEX_CONST || type == MTL_ARG_LITERAL_PIXEL_CONST; -set reusable u::literalConst; \ No newline at end of file +set reusable u::literalConst; +set condition u::codeConst type == MTL_ARG_CODE_VERTEX_CONST +|| type == MTL_ARG_CODE_PIXEL_CONST; +set condition u::codeSampler type == MTL_ARG_CODE_PIXEL_SAMPLER; +set condition u::nameHash type == MTL_ARG_MATERIAL_VERTEX_CONST +|| type == MTL_ARG_MATERIAL_PIXEL_CONST || type == MTL_ARG_MATERIAL_PIXEL_SAMPLER; \ No newline at end of file diff --git a/src/ZoneCode/Game/T6/XAssets/MaterialTechniqueSet.txt b/src/ZoneCode/Game/T6/XAssets/MaterialTechniqueSet.txt index 92a9f878..06ee267d 100644 --- a/src/ZoneCode/Game/T6/XAssets/MaterialTechniqueSet.txt +++ b/src/ZoneCode/Game/T6/XAssets/MaterialTechniqueSet.txt @@ -51,4 +51,9 @@ set count GfxPixelShaderLoadDef::program programSize; use MaterialShaderArgument; set condition u::literalConst type == MTL_ARG_LITERAL_VERTEX_CONST || type == MTL_ARG_LITERAL_PIXEL_CONST; -set reusable u::literalConst; \ No newline at end of file +set reusable u::literalConst; +set condition u::codeConst type == MTL_ARG_CODE_VERTEX_CONST +|| type == MTL_ARG_CODE_PIXEL_CONST; +set condition u::codeSampler type == MTL_ARG_CODE_PIXEL_SAMPLER; +set condition u::nameHash type == MTL_ARG_MATERIAL_VERTEX_CONST +|| type == MTL_ARG_MATERIAL_PIXEL_CONST || type == MTL_ARG_MATERIAL_PIXEL_SAMPLER; \ No newline at end of file diff --git a/src/ZoneCodeGeneratorLib/Domain/Computations/MemberComputations.cpp b/src/ZoneCodeGeneratorLib/Domain/Computations/MemberComputations.cpp index 7cfddc4d..9bbafa40 100644 --- a/src/ZoneCodeGeneratorLib/Domain/Computations/MemberComputations.cpp +++ b/src/ZoneCodeGeneratorLib/Domain/Computations/MemberComputations.cpp @@ -189,15 +189,15 @@ bool MemberComputations::IsInRuntimeBlock() const return m_info->m_fast_file_block != nullptr && m_info->m_fast_file_block->m_type == FastFileBlockType::RUNTIME; } -bool MemberComputations::IsFirstUsedMember() const +bool MemberComputations::IsFirstUsedMember(const bool includeLeafs) const { - const auto parentUsedMembers = StructureComputations(m_info->m_parent).GetUsedMembers(); + const auto parentUsedMembers = StructureComputations(m_info->m_parent).GetUsedMembers(includeLeafs); return !parentUsedMembers.empty() && parentUsedMembers[0] == m_info; } -bool MemberComputations::IsLastUsedMember() const +bool MemberComputations::IsLastUsedMember(const bool includeLeafs) const { - const auto parentUsedMembers = StructureComputations(m_info->m_parent).GetUsedMembers(); + const auto parentUsedMembers = StructureComputations(m_info->m_parent).GetUsedMembers(includeLeafs); return !parentUsedMembers.empty() && parentUsedMembers[parentUsedMembers.size() - 1] == m_info; } diff --git a/src/ZoneCodeGeneratorLib/Domain/Computations/MemberComputations.h b/src/ZoneCodeGeneratorLib/Domain/Computations/MemberComputations.h index 2ab179f6..5468ab82 100644 --- a/src/ZoneCodeGeneratorLib/Domain/Computations/MemberComputations.h +++ b/src/ZoneCodeGeneratorLib/Domain/Computations/MemberComputations.h @@ -25,8 +25,8 @@ public: [[nodiscard]] bool IsNotInDefaultNormalBlock() const; [[nodiscard]] bool IsInTempBlock() const; [[nodiscard]] bool IsInRuntimeBlock() const; - [[nodiscard]] bool IsFirstUsedMember() const; - [[nodiscard]] bool IsLastUsedMember() const; + [[nodiscard]] bool IsFirstUsedMember(bool includeLeafs) const; + [[nodiscard]] bool IsLastUsedMember(bool includeLeafs) const; [[nodiscard]] bool HasDynamicArraySize() const; [[nodiscard]] bool IsDynamicMember() const; [[nodiscard]] bool IsAfterPartialLoad() const; diff --git a/src/ZoneCodeGeneratorLib/Domain/Computations/StructureComputations.cpp b/src/ZoneCodeGeneratorLib/Domain/Computations/StructureComputations.cpp index 5e434f75..92cd8193 100644 --- a/src/ZoneCodeGeneratorLib/Domain/Computations/StructureComputations.cpp +++ b/src/ZoneCodeGeneratorLib/Domain/Computations/StructureComputations.cpp @@ -38,7 +38,7 @@ bool StructureComputations::HasNonDynamicMember() const return false; } -std::vector StructureComputations::GetUsedMembers() const +std::vector StructureComputations::GetUsedMembers(const bool includeLeafs) const { std::vector members; @@ -54,7 +54,7 @@ std::vector StructureComputations::GetUsedMembers() const { for (const auto& member : m_info->m_ordered_members) { - if (!member->m_is_leaf && !MemberComputations(member.get()).ShouldIgnore()) + if ((includeLeafs || !member->m_is_leaf) && !MemberComputations(member.get()).ShouldIgnore()) members.push_back(member.get()); } } diff --git a/src/ZoneCodeGeneratorLib/Domain/Computations/StructureComputations.h b/src/ZoneCodeGeneratorLib/Domain/Computations/StructureComputations.h index 2792bdb4..2dfbb2c8 100644 --- a/src/ZoneCodeGeneratorLib/Domain/Computations/StructureComputations.h +++ b/src/ZoneCodeGeneratorLib/Domain/Computations/StructureComputations.h @@ -10,7 +10,7 @@ public: [[nodiscard]] bool IsAsset() const; [[nodiscard]] MemberInformation* GetDynamicMember() const; [[nodiscard]] bool HasNonDynamicMember() const; - [[nodiscard]] std::vector GetUsedMembers() const; + [[nodiscard]] std::vector GetUsedMembers(bool includeLeafs) const; [[nodiscard]] bool IsInTempBlock() const; private: diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp index 5ef45bc6..7d04375a 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp @@ -596,7 +596,7 @@ namespace { const MemberComputations computations(&member); - if (computations.IsFirstUsedMember()) + if (computations.IsFirstUsedMember(false)) { if (member.m_condition) { @@ -614,7 +614,7 @@ namespace PrintFillStruct_Member(structInfo, member, DeclarationModifierComputations(&member), 0u); } } - else if (computations.IsLastUsedMember()) + else if (computations.IsLastUsedMember(false)) { if (member.m_condition) { @@ -810,7 +810,7 @@ namespace if (computations.ShouldIgnore()) continue; - if (computations.IsFirstUsedMember()) + if (computations.IsFirstUsedMember(false)) { LINE("") if (member->m_condition) @@ -829,7 +829,7 @@ namespace PrintDynamicOversize_DynamicMember(info, *member); } } - else if (computations.IsLastUsedMember()) + else if (computations.IsLastUsedMember(false)) { if (member->m_condition) { @@ -1788,7 +1788,7 @@ namespace { const MemberComputations computations(member); - if (computations.IsFirstUsedMember()) + if (computations.IsFirstUsedMember(false)) { LINE("") if (member->m_condition) @@ -1807,7 +1807,7 @@ namespace LoadMember_Reference(info, member, DeclarationModifierComputations(member)); } } - else if (computations.IsLastUsedMember()) + else if (computations.IsLastUsedMember(false)) { if (member->m_condition) { diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp index 3dcc8873..050c993a 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneMarkTemplate.cpp @@ -670,7 +670,7 @@ namespace { const MemberComputations computations(member); - if (computations.IsFirstUsedMember()) + if (computations.IsFirstUsedMember(false)) { LINE("") if (member->m_condition) @@ -689,7 +689,7 @@ namespace MarkMember_Reference(info, member, DeclarationModifierComputations(member)); } } - else if (computations.IsLastUsedMember()) + else if (computations.IsLastUsedMember(false)) { if (member->m_condition) { diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp index 8969ecc1..f80b4a5a 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp @@ -1010,7 +1010,7 @@ namespace { const MemberComputations computations(member); - if (computations.IsFirstUsedMember()) + if (computations.IsFirstUsedMember(false)) { LINE("") if (member->m_condition) @@ -1029,7 +1029,7 @@ namespace WriteMember_Reference(info, member, DeclarationModifierComputations(member)); } } - else if (computations.IsLastUsedMember()) + else if (computations.IsLastUsedMember(false)) { if (member->m_condition) { @@ -1326,12 +1326,20 @@ namespace } } + static bool ShouldFillMember(const DeclarationModifierComputations& modifier) + { + return !modifier.HasPointerModifier(); + } + // nestedBaseOffset: Base offset in case member is part of a nested anonymous sub-struct void PrintFillStruct_Member(const StructureInformation& structInfo, const MemberInformation& memberInfo, const DeclarationModifierComputations& modifier, const size_t nestedBaseOffset) { + if (!ShouldFillMember(modifier)) + return; + if (modifier.IsDynamicArray()) { } @@ -1360,7 +1368,7 @@ namespace { const MemberComputations computations(&member); - if (computations.IsFirstUsedMember()) + if (computations.IsFirstUsedMember(true)) { if (member.m_condition) { @@ -1378,7 +1386,7 @@ namespace PrintFillStruct_Member(structInfo, member, modifier, 0u); } } - else if (computations.IsLastUsedMember()) + else if (computations.IsLastUsedMember(true)) { if (member.m_condition) { @@ -1423,49 +1431,10 @@ namespace } } - static bool ShouldFillMember(const DeclarationModifierComputations& modifier) - { - return !modifier.HasPointerModifier(); - } - void PrintFillStruct_Struct(const StructureInformation& info) { const auto* dynamicMember = StructureComputations(&info).GetDynamicMember(); - - if (dynamicMember) - { - if (info.m_definition->GetType() == DataDefinitionType::UNION) - { - for (const auto& member : info.m_ordered_members) - { - const MemberComputations computations(member.get()); - if (computations.ShouldIgnore()) - continue; - - DeclarationModifierComputations modifier(member.get()); - if (!ShouldFillMember(modifier)) - continue; - - PrintFillStruct_Member_Condition_Union(info, *member, modifier); - } - } - else - { - for (const auto& member : info.m_ordered_members) - { - const MemberComputations computations(member.get()); - if (computations.ShouldIgnore() || member.get() == dynamicMember) - continue; - - DeclarationModifierComputations modifier(member.get()); - if (!ShouldFillMember(modifier)) - continue; - - PrintFillStruct_Member(info, *member, modifier, 0u); - } - } - } - else + if (info.m_definition->GetType() == DataDefinitionType::UNION) { for (const auto& member : info.m_ordered_members) { @@ -1474,9 +1443,18 @@ namespace continue; DeclarationModifierComputations modifier(member.get()); - if (!ShouldFillMember(modifier)) + PrintFillStruct_Member_Condition_Union(info, *member, modifier); + } + } + else + { + for (const auto& member : info.m_ordered_members) + { + const MemberComputations computations(member.get()); + if (computations.ShouldIgnore() || member.get() == dynamicMember) continue; + DeclarationModifierComputations modifier(member.get()); PrintFillStruct_Member(info, *member, modifier, 0u); } } From 2840489a3896ee729d11690e05b0bc0304cf0669 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Wed, 14 Jan 2026 22:42:43 +0000 Subject: [PATCH 16/20] fix: only fill used union members when loading --- .../Generating/Templates/ZoneLoadTemplate.cpp | 48 +++++++------------ 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp index 7d04375a..cd8c10e6 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp @@ -596,7 +596,7 @@ namespace { const MemberComputations computations(&member); - if (computations.IsFirstUsedMember(false)) + if (computations.IsFirstUsedMember(true)) { if (member.m_condition) { @@ -614,7 +614,7 @@ namespace PrintFillStruct_Member(structInfo, member, DeclarationModifierComputations(&member), 0u); } } - else if (computations.IsLastUsedMember(false)) + else if (computations.IsLastUsedMember(true)) { if (member.m_condition) { @@ -668,35 +668,7 @@ namespace } const auto* dynamicMember = StructureComputations(&info).GetDynamicMember(); - - if (dynamicMember) - { - if (info.m_definition->GetType() == DataDefinitionType::UNION) - { - for (const auto& member : info.m_ordered_members) - { - const MemberComputations computations(member.get()); - if (computations.ShouldIgnore()) - continue; - - PrintFillStruct_Member_Condition_Union(info, *member); - } - } - else - { - for (const auto& member : info.m_ordered_members) - { - const MemberComputations computations(member.get()); - if (computations.ShouldIgnore() || member.get() == dynamicMember) - continue; - - PrintFillStruct_Member(info, *member, DeclarationModifierComputations(member.get()), 0u); - } - - PrintFillStruct_Member_Condition_Struct(info, *dynamicMember); - } - } - else + if (info.m_definition->GetType() == DataDefinitionType::UNION) { for (const auto& member : info.m_ordered_members) { @@ -704,8 +676,22 @@ namespace if (computations.ShouldIgnore()) continue; + PrintFillStruct_Member_Condition_Union(info, *member); + } + } + else + { + for (const auto& member : info.m_ordered_members) + { + const MemberComputations computations(member.get()); + if (computations.ShouldIgnore() || member.get() == dynamicMember) + continue; + PrintFillStruct_Member(info, *member, DeclarationModifierComputations(member.get()), 0u); } + + if (dynamicMember) + PrintFillStruct_Member_Condition_Struct(info, *dynamicMember); } } From 47dcab33e9c2a6c2dceda7febea5a49ec46350de Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Thu, 15 Jan 2026 23:56:39 +0000 Subject: [PATCH 17/20] chore: add systemtest to test rebuilding of vanilla zones --- .../Zone/XChunk/XChunkProcessorInflate.cpp | 2 +- test/SystemTests/RebuildVanillaZonesTests.cpp | 96 +++++++++++++++++++ 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 test/SystemTests/RebuildVanillaZonesTests.cpp diff --git a/src/ZoneCommon/Zone/XChunk/XChunkProcessorInflate.cpp b/src/ZoneCommon/Zone/XChunk/XChunkProcessorInflate.cpp index 9d1058ce..bf3b0880 100644 --- a/src/ZoneCommon/Zone/XChunk/XChunkProcessorInflate.cpp +++ b/src/ZoneCommon/Zone/XChunk/XChunkProcessorInflate.cpp @@ -27,7 +27,7 @@ size_t XChunkProcessorInflate::Process(unsigned streamNumber, const uint8_t* inp ret = inflate(&stream, Z_FULL_FLUSH); if (ret != Z_STREAM_END) { - con::error("inflate of stream failed with error code {}: {}", streamNumber, ret, stream.msg); + con::error("inflate of stream {} failed with error code {}: {}", streamNumber, ret, stream.msg); throw XChunkException(std::format("Zone has invalid or unsupported compression: {}", stream.msg)); } diff --git a/test/SystemTests/RebuildVanillaZonesTests.cpp b/test/SystemTests/RebuildVanillaZonesTests.cpp new file mode 100644 index 00000000..82fa2567 --- /dev/null +++ b/test/SystemTests/RebuildVanillaZonesTests.cpp @@ -0,0 +1,96 @@ +#include "Game/T6/GameAssetPoolT6.h" +#include "OatTestPaths.h" +#include "Utils/Logging/Log.h" +#include "Utils/StringUtils.h" +#include "ZoneLoading.h" +#include "ZoneWriting.h" + +#include +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; +using namespace std::literals; + +/* + * This test is only run when the user defines the environment variable OAT_FASTFILE_DIR containing the path to a folder containing fastfiles. + */ +namespace +{ + void EnsureCanRebuildFastFile(const fs::path& outputPath, const fs::path& fastFilePath) + { + const auto fastFilePathStr = fastFilePath.string(); + const auto tempFilePath = outputPath / "temp.ff"; + const auto tempFilePathStr = tempFilePath.string(); + + con::info("Testing for rebuild: {}", fastFilePathStr); + + auto maybeZone = ZoneLoading::LoadZone(fastFilePathStr, std::nullopt); + REQUIRE(maybeZone.has_value()); + + auto zone = std::move(*maybeZone); + zone->m_name = "temp"; + + { + std::ofstream outStream(tempFilePath, std::ios::out | std::ios::binary); + REQUIRE(outStream.is_open()); + + const auto linkingResult = ZoneWriting::WriteZone(outStream, *zone); + REQUIRE(linkingResult); + } + + auto maybeRebuiltZone = ZoneLoading::LoadZone(tempFilePathStr, std::nullopt); + REQUIRE(maybeRebuiltZone.has_value()); + + auto rebuiltZone = std::move(*maybeRebuiltZone); + + const auto& pools = *zone->m_pools; + const auto& rebuiltPools = *rebuiltZone->m_pools; + + const auto totalAssetCount = pools.GetTotalAssetCount(); + REQUIRE(totalAssetCount == rebuiltPools.GetTotalAssetCount()); + + auto zoneIter = pools.begin(); + auto zoneEnd = pools.end(); + auto rebuiltZoneIter = rebuiltPools.begin(); + auto rebuiltZoneEnd = rebuiltPools.end(); + + while (zoneIter != zoneEnd) + { + REQUIRE(rebuiltZoneIter != rebuiltZoneEnd); + + REQUIRE((*zoneIter)->m_type == (*rebuiltZoneIter)->m_type); + REQUIRE((*zoneIter)->m_name == (*rebuiltZoneIter)->m_name); + + ++zoneIter; + ++rebuiltZoneIter; + } + } + + TEST_CASE("Rebuild vanilla zones", "[custom]") + { + auto* fastFilePathStr = std::getenv("OAT_FASTFILE_DIR"); + if (!fastFilePathStr) + return; + + const auto outputPath = oat::paths::GetTempDirectory("RebuildVanillaZones"); + const fs::path fastFilePath(fastFilePathStr); + + fs::directory_iterator iterator(fastFilePath); + const auto end = fs::end(iterator); + for (auto i = fs::begin(iterator); i != end; ++i) + { + if (!i->is_regular_file()) + continue; + + const auto path = i->path(); + auto extension = path.extension().string(); + utils::MakeStringLowerCase(extension); + if (extension == ".ff") + EnsureCanRebuildFastFile(outputPath, path); + } + } +} // namespace From f95745fb8758d17e92df0cb21257babcc4953e21 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 16 Jan 2026 00:04:03 +0000 Subject: [PATCH 18/20] fix: not writing to script string var for embedded script string arrays --- .../Generating/Templates/ZoneWriteTemplate.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp index f80b4a5a..0efb9fce 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp @@ -397,6 +397,7 @@ namespace } else if (writeType == MemberWriteType::EMBEDDED_ARRAY) { + LINEF("varScriptString = {0};", MakeMemberAccess(info, member, modifier)) LINEF("varScriptStringWritten = {0};", MakeWrittenMemberAccess(info, member, modifier)) LINEF("WriteScriptStringArray(false, {0});", MakeArrayCount(dynamic_cast(modifier.GetDeclarationModifier()))) } From 7c52fde1f8f62a9201236dbe64d6d56cb979079d Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 17 Jan 2026 00:15:59 +0000 Subject: [PATCH 19/20] fix: crash on writing float44 type due to misaligned memory * the compiler in release builds optimizes to use movaps * this opcode requires memory alignment to 16 byte * the written memory buffer may be misaligned at this position --- src/ZoneWriting/Zone/Stream/ZoneOutputStream.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h index 0a32486e..34d9bcc7 100644 --- a/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h +++ b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h @@ -34,7 +34,9 @@ public: [[nodiscard]] ZoneStreamFillWriteAccessor AtOffset(size_t offset) const; [[nodiscard]] ZoneOutputOffset Offset() const; - template void Fill(const T& value, const size_t offset) const + template + requires(sizeof(T) <= sizeof(uintptr_t)) + void Fill(const T& value, const size_t offset) const { assert(m_block_buffer); assert(offset + sizeof(T) <= m_buffer_size); @@ -42,6 +44,16 @@ public: *reinterpret_cast(static_cast(m_block_buffer) + offset) = value; } + template + requires(sizeof(T) > sizeof(uintptr_t)) + void Fill(const T& value, const size_t offset) const + { + assert(m_block_buffer); + assert(offset + sizeof(T) <= m_buffer_size); + + std::memcpy(static_cast(m_block_buffer) + offset, &value, sizeof(T)); + } + template void FillArray(T (&value)[S], const size_t offset) const { assert(m_block_buffer); From 5b6b82424b2d7e182c9577f1d26b7102015af43f Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sun, 18 Jan 2026 17:12:13 +0100 Subject: [PATCH 20/20] fix: marking invalid offset as written in WritePtrArray methods --- .../Generating/Templates/ZoneWriteTemplate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp index 0efb9fce..683440eb 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp @@ -1494,7 +1494,7 @@ namespace { LINEF("m_stream->Write<{0}>(*{1});", def->GetFullName(), MakeTypePtrVarName(def)) } - LINEF("m_stream->MarkFollowing({0});", MakeTypeWrittenPtrVarName(def)) + LINEF("m_stream->MarkFollowing(varWritten);") } void PrintWritePtrArrayMethod_PointerCheck(const DataDefinition* def, const StructureInformation* info, const bool reusable)