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.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/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/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 f908d324..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) { } @@ -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/Internal/BaseTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.cpp index 89b535cb..dca825c9 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.cpp @@ -1,13 +1,15 @@ #include "BaseTemplate.h" #include "Domain/Computations/MemberComputations.h" +#include "Domain/Computations/StructureComputations.h" #include "Domain/Definition/ArrayDeclarationModifier.h" #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 +63,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 +70,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 +85,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 +92,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 +109,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 +262,52 @@ std::string BaseTemplate::MakeEvaluation(const IEvaluation* evaluation) MakeEvaluationInternal(evaluation, str); 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; + 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..d35a76fc 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.h +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/Internal/BaseTemplate.h @@ -5,6 +5,8 @@ #include "Domain/Evaluation/OperandDynamic.h" #include "Domain/Evaluation/OperandStatic.h" #include "Domain/Evaluation/Operation.h" +#include "Generating/BaseRenderingContext.h" +#include "Generating/OncePerAssetRenderingContext.h" #include #include @@ -14,7 +16,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 +25,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 +35,27 @@ 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); + + [[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 9a0f58ba..cd8c10e6 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneLoadTemplate.cpp @@ -12,12 +12,39 @@ 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, context), + 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 { public: PerAsset(std::ostream& stream, const OncePerAssetRenderingContext& context) - : BaseTemplate(stream), + : BaseTemplate(stream, context), m_env(context) { } @@ -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)) } } @@ -240,16 +267,6 @@ namespace return std::format("{0}** var{1}Ptr;", def->GetFullName(), MakeSafeTypeName(def)); } - 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)) @@ -328,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); } @@ -345,47 +363,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, @@ -619,7 +596,7 @@ namespace { const MemberComputations computations(&member); - if (computations.IsFirstUsedMember()) + if (computations.IsFirstUsedMember(true)) { if (member.m_condition) { @@ -637,7 +614,7 @@ namespace PrintFillStruct_Member(structInfo, member, DeclarationModifierComputations(&member), 0u); } } - else if (computations.IsLastUsedMember()) + else if (computations.IsLastUsedMember(true)) { if (member.m_condition) { @@ -691,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) { @@ -727,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); } } @@ -833,7 +796,7 @@ namespace if (computations.ShouldIgnore()) continue; - if (computations.IsFirstUsedMember()) + if (computations.IsFirstUsedMember(false)) { LINE("") if (member->m_condition) @@ -852,7 +815,7 @@ namespace PrintDynamicOversize_DynamicMember(info, *member); } } - else if (computations.IsLastUsedMember()) + else if (computations.IsLastUsedMember(false)) { if (member->m_condition) { @@ -1811,7 +1774,7 @@ namespace { const MemberComputations computations(member); - if (computations.IsFirstUsedMember()) + if (computations.IsFirstUsedMember(false)) { LINE("") if (member->m_condition) @@ -1830,7 +1793,7 @@ namespace LoadMember_Reference(info, member, DeclarationModifierComputations(member)); } } - else if (computations.IsLastUsedMember()) + else if (computations.IsLastUsedMember(false)) { if (member->m_condition) { @@ -2192,6 +2155,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 +2179,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..050c993a 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) { } @@ -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)) } } @@ -47,7 +44,7 @@ namespace { public: PerAsset(std::ostream& stream, const OncePerAssetRenderingContext& context) - : BaseTemplate(stream), + : BaseTemplate(stream, context), m_env(context) { } @@ -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("") @@ -673,7 +670,7 @@ namespace { const MemberComputations computations(member); - if (computations.IsFirstUsedMember()) + if (computations.IsFirstUsedMember(false)) { LINE("") if (member->m_condition) @@ -692,7 +689,7 @@ namespace MarkMember_Reference(info, member, DeclarationModifierComputations(member)); } } - else if (computations.IsLastUsedMember()) + else if (computations.IsLastUsedMember(false)) { if (member->m_condition) { @@ -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..683440eb 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,12 +12,39 @@ 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, context), + 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 { public: PerAsset(std::ostream& stream, const OncePerAssetRenderingContext& context) - : BaseTemplate(stream), + : BaseTemplate(stream, context), m_env(context) { } @@ -51,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) @@ -78,27 +116,35 @@ 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("") // 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)) - 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--; @@ -111,7 +157,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 +165,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)) } } @@ -132,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) @@ -185,7 +242,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) @@ -195,7 +252,12 @@ 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 PrintFillStructMethodDeclaration(const StructureInformation* info) const + { + LINEF("void FillStruct_{0}(const ZoneStreamFillWriteAccessor& fillAccessor);", MakeSafeTypeName(info->m_definition)) } void PrintHeaderPtrArrayWriteMethodDeclaration(const DataDefinition* def) const @@ -220,12 +282,12 @@ 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 { - 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 @@ -233,25 +295,66 @@ 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 << ".AtOffset("; + + 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() { 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)", @@ -262,26 +365,19 @@ 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()) - { + 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); - 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--; @@ -301,12 +397,13 @@ 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()))) } 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 { @@ -323,7 +420,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) { @@ -345,18 +442,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()) } @@ -374,7 +473,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)) @@ -385,6 +484,27 @@ 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())) + 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 { LINEF("m_stream->Write<{0}{1}>({2}, {3});", @@ -479,7 +599,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)) } } @@ -501,6 +621,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});", @@ -513,7 +640,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) { @@ -597,7 +724,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)) { @@ -605,31 +732,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); } @@ -663,7 +796,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)) { @@ -702,6 +835,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, @@ -713,7 +854,10 @@ namespace return; } - LINEF("if (m_stream->ReusableShouldWrite(&{0}))", MakeWrittenMemberAccess(info, member, modifier)) + LINEF("if (m_stream->ReusableShouldWrite({0}, {1}.AtOffset({2})))", + MakeMemberAccess(info, member, modifier), + MakeTypeWrittenVarName(info->m_definition), + MakeReusableInnerOffset(info->m_definition, member->m_member)) LINE("{") m_intendation++; @@ -867,7 +1011,7 @@ namespace { const MemberComputations computations(member); - if (computations.IsFirstUsedMember()) + if (computations.IsFirstUsedMember(false)) { LINE("") if (member->m_condition) @@ -886,7 +1030,7 @@ namespace WriteMember_Reference(info, member, DeclarationModifierComputations(member)); } } - else if (computations.IsLastUsedMember()) + else if (computations.IsLastUsedMember(false)) { if (member->m_condition) { @@ -961,29 +1105,42 @@ 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}>({2}, offsetof({1}, {3}));", - MakeTypeWrittenVarName(info->m_definition), - info->m_definition->GetFullName(), - MakeTypeVarName(info->m_definition), - 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} != nullptr);", MakeTypeWrittenVarName(info->m_definition)) + LINEF("assert({0}.Offset() != nullptr);", MakeTypeWrittenVarName(info->m_definition)) } else { @@ -1028,14 +1185,11 @@ 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("") - LINEF("assert({0} != nullptr);", MakeTypeWrittenPtrVarName(info->m_definition)) + LINEF("assert({0}.Offset() != nullptr);", MakeTypeWrittenPtrVarName(info->m_definition)) LINE("") if (inTemp) @@ -1043,7 +1197,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++; @@ -1061,7 +1215,7 @@ namespace } LINE("") - LINEF("m_stream->MarkFollowing(*{0});", MakeTypeWrittenPtrVarName(info->m_definition)) + LINEF("m_stream->MarkFollowing({0});", MakeTypeWrittenPtrVarName(info->m_definition)) m_intendation--; LINE("}") @@ -1078,7 +1232,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++; @@ -1088,9 +1244,233 @@ 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("}") + } + + 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); + } + } + + 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()) + { + } + 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(true)) + { + 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(true)) + { + 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) + } + } + } + + void PrintFillStruct_Struct(const StructureInformation& info) + { + const auto* dynamicMember = StructureComputations(&info).GetDynamicMember(); + 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()); + 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); + } + } + } + + 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("}") @@ -1114,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) @@ -1126,13 +1506,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++; @@ -1162,15 +1542,15 @@ 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("") - 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++; @@ -1180,7 +1560,7 @@ namespace PrintWritePtrArrayMethod_PointerCheck(def, info, reusable); LINE("") LINE("var++;") - LINE("varWritten++;") + LINE("varWritten.Inc(m_stream->GetPointerByteCount());") m_intendation--; LINE("}") @@ -1197,16 +1577,45 @@ 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(def)) + 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} != 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++; @@ -1215,7 +1624,7 @@ namespace LINEF("{0} = varWritten;", MakeTypeWrittenVarName(info->m_definition)) LINEF("Write_{0}(false);", info->m_definition->m_name) LINE("var++;") - LINE("varWritten++;") + LINEF("varWritten.Inc({0});", def->GetSize()) m_intendation--; LINE("}") @@ -1228,16 +1637,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/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/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/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) { 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/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; 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); } diff --git a/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp b/src/ZoneWriting/Game/IW3/ContentWriterIW3.cpp index 04765117..e904524d 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 @@ -81,30 +57,31 @@ void ContentWriter::CreateXAssetList(XAssetList& xAssetList, MemoryManager& memo void ContentWriter::WriteScriptStringList(const bool atStreamStart) { - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - - if (atStreamStart) - varScriptStringList = m_stream->Write(varScriptStringList); + assert(!atStreamStart); 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.AtOffset(4)); } - - m_stream->PopBlock(); } 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.AtOffset(4)); \ break; \ } #define SKIP_ASSET(type_index, typeName, headerEntry) \ @@ -114,7 +91,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) { @@ -160,38 +137,75 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun { assert(varXAsset != nullptr); +#ifdef ARCH_x86 + static_assert(sizeof(XAsset) == 8u); +#endif + if (atStreamStart) - varXAsset = m_stream->Write(varXAsset, count); + { +#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++; + varXAssetWritten.Inc(8u); } } -void ContentWriter::WriteContent(IZoneOutputStream& stream) +void ContentWriter::WriteContent(ZoneOutputStream& stream) { m_stream = &stream; - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - MemoryManager memory; XAssetList assetList{}; CreateXAssetList(assetList, memory); - varXAssetList = static_cast(m_stream->WriteDataRaw(&assetList, sizeof(assetList))); + 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.AtOffset(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.AtOffset(12)); } m_stream->PopBlock(); diff --git a/src/ZoneWriting/Game/IW3/ContentWriterIW3.h b/src/ZoneWriting/Game/IW3/ContentWriterIW3.h index 3421a923..b604fdf8 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; @@ -23,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/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 26cf1935..c0fbc85a 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 @@ -91,30 +57,31 @@ void ContentWriter::CreateXAssetList(XAssetList& xAssetList, MemoryManager& memo void ContentWriter::WriteScriptStringList(const bool atStreamStart) { - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - - if (atStreamStart) - varScriptStringList = m_stream->Write(varScriptStringList); + assert(!atStreamStart); 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.AtOffset(4)); } - - m_stream->PopBlock(); } 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.AtOffset(4)); \ break; \ } #define SKIP_ASSET(type_index, typeName, headerEntry) \ @@ -124,7 +91,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) { @@ -180,38 +147,75 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun { assert(varXAsset != nullptr); +#ifdef ARCH_x86 + static_assert(sizeof(XAsset) == 8u); +#endif + if (atStreamStart) - varXAsset = m_stream->Write(varXAsset, count); + { +#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++; + varXAssetWritten.Inc(8u); } } -void ContentWriter::WriteContent(IZoneOutputStream& stream) +void ContentWriter::WriteContent(ZoneOutputStream& stream) { m_stream = &stream; - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - MemoryManager memory; XAssetList assetList{}; CreateXAssetList(assetList, memory); - varXAssetList = static_cast(m_stream->WriteDataRaw(&assetList, sizeof(assetList))); + 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.AtOffset(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.AtOffset(12)); } m_stream->PopBlock(); diff --git a/src/ZoneWriting/Game/IW4/ContentWriterIW4.h b/src/ZoneWriting/Game/IW4/ContentWriterIW4.h index 0217af78..101c8041 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; @@ -23,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/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 266d8cfb..d701903c 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 @@ -96,30 +57,31 @@ void ContentWriter::CreateXAssetList(XAssetList& xAssetList, MemoryManager& memo void ContentWriter::WriteScriptStringList(const bool atStreamStart) { - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - - if (atStreamStart) - varScriptStringList = m_stream->Write(varScriptStringList); + assert(!atStreamStart); 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.AtOffset(4)); } - - m_stream->PopBlock(); } 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.AtOffset(4)); \ break; \ } #define SKIP_ASSET(type_index, typeName, headerEntry) \ @@ -129,7 +91,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) { @@ -188,38 +150,75 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun { assert(varXAsset != nullptr); +#ifdef ARCH_x86 + static_assert(sizeof(XAsset) == 8u); +#endif + if (atStreamStart) - varXAsset = m_stream->Write(varXAsset, count); + { +#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++; + varXAssetWritten.Inc(8u); } } -void ContentWriter::WriteContent(IZoneOutputStream& stream) +void ContentWriter::WriteContent(ZoneOutputStream& stream) { m_stream = &stream; - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - MemoryManager memory; XAssetList assetList{}; CreateXAssetList(assetList, memory); - varXAssetList = static_cast(m_stream->WriteDataRaw(&assetList, sizeof(assetList))); + 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.AtOffset(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.AtOffset(12)); } m_stream->PopBlock(); diff --git a/src/ZoneWriting/Game/IW5/ContentWriterIW5.h b/src/ZoneWriting/Game/IW5/ContentWriterIW5.h index 1e8d64a1..82830b08 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; @@ -23,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/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 08efc2ee..253a022a 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 @@ -88,30 +57,31 @@ void ContentWriter::CreateXAssetList(XAssetList& xAssetList, MemoryManager& memo void ContentWriter::WriteScriptStringList(const bool atStreamStart) { - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - - if (atStreamStart) - varScriptStringList = m_stream->Write(varScriptStringList); + assert(!atStreamStart); 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.AtOffset(4)); } - - m_stream->PopBlock(); } 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.AtOffset(4)); \ break; \ } #define SKIP_ASSET(type_index, typeName, headerEntry) \ @@ -121,7 +91,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) { @@ -173,38 +143,75 @@ void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t coun { assert(varXAsset != nullptr); +#ifdef ARCH_x86 + static_assert(sizeof(XAsset) == 8u); +#endif + if (atStreamStart) - varXAsset = m_stream->Write(varXAsset, count); + { +#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++; + varXAssetWritten.Inc(8u); } } -void ContentWriter::WriteContent(IZoneOutputStream& stream) +void ContentWriter::WriteContent(ZoneOutputStream& stream) { m_stream = &stream; - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - MemoryManager memory; XAssetList assetList{}; CreateXAssetList(assetList, memory); - varXAssetList = static_cast(m_stream->WriteDataRaw(&assetList, sizeof(assetList))); + 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.AtOffset(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.AtOffset(12)); } m_stream->PopBlock(); diff --git a/src/ZoneWriting/Game/T5/ContentWriterT5.h b/src/ZoneWriting/Game/T5/ContentWriterT5.h index 50c78edb..094c5e62 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; @@ -23,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/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 95c4eb04..14af265a 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 @@ -107,37 +60,38 @@ void ContentWriter::CreateXAssetList(XAssetList& xAssetList, MemoryManager& memo void ContentWriter::WriteScriptStringList(const bool atStreamStart) { - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - - if (atStreamStart) - varScriptStringList = m_stream->Write(varScriptStringList); + assert(!atStreamStart); 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.AtOffset(4)); } - - m_stream->PopBlock(); } 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.AtOffset(4)); \ break; \ } assert(varXAsset != nullptr); if (atStreamStart) - varXAsset = m_stream->Write(varXAsset); + varXAssetWritten = m_stream->Write(varXAsset); switch (varXAsset->type) { @@ -203,47 +157,89 @@ 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) - varXAsset = m_stream->Write(varXAsset, count); + { +#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++; + varXAssetWritten.Inc(8u); } } -void ContentWriter::WriteContent(IZoneOutputStream& stream) +void ContentWriter::WriteContent(ZoneOutputStream& stream) { m_stream = &stream; - m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); - MemoryManager memory; XAssetList assetList{}; CreateXAssetList(assetList, memory); - varXAssetList = static_cast(m_stream->WriteDataRaw(&assetList, sizeof(assetList))); + 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.AtOffset(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.AtOffset(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.AtOffset(20)); } m_stream->PopBlock(); diff --git a/src/ZoneWriting/Game/T6/ContentWriterT6.h b/src/ZoneWriting/Game/T6/ContentWriterT6.h index 3f78b034..7fb5ce20 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; @@ -23,5 +24,9 @@ namespace T6 XAssetList* varXAssetList; XAsset* varXAsset; ScriptStringList* varScriptStringList; + + ZoneOutputOffset varXAssetListWritten; + ZoneOutputOffset varXAssetWritten; + ZoneOutputOffset varScriptStringListWritten; }; } // namespace T6 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..80a1e99f 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), @@ -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) @@ -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++; + 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 188828c1..863a6a6c 100644 --- a/src/ZoneWriting/Writing/AssetWriter.h +++ b/src/ZoneWriting/Writing/AssetWriter.h @@ -2,21 +2,20 @@ #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; + void UseScriptString(scr_string_t scrString, ZoneOutputOffset written) const; void WriteScriptStringArray(bool atStreamStart, size_t count); 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 b4d775a1..e9a596fc 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), @@ -23,34 +23,36 @@ 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 != 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); } } 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 != nullptr); + assert(varXStringWritten.Offset() != nullptr); for (size_t index = 0; index < count; index++) { WriteXString(false); - varXStringWritten++; + varXString++; + varXStringWritten.Inc(pointerByteCount); } } diff --git a/src/ZoneWriting/Writing/ContentWriterBase.h b/src/ZoneWriting/Writing/ContentWriterBase.h index 06dd121c..47da7b56 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,8 +21,8 @@ protected: void WriteXStringArray(bool atStreamStart, size_t count); const Zone& m_zone; - IZoneOutputStream* m_stream; + ZoneOutputStream* m_stream; const char** varXString; - const char** varXStringWritten; + ZoneOutputOffset 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/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)); diff --git a/src/ZoneWriting/Zone/Stream/IZoneOutputStream.h b/src/ZoneWriting/Zone/Stream/IZoneOutputStream.h deleted file mode 100644 index 43b795bd..00000000 --- a/src/ZoneWriting/Zone/Stream/IZoneOutputStream.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include "Zone/Stream/IZoneStream.h" - -#include -#include -#include - -class IZoneOutputStream : public IZoneStream -{ -public: - inline static void* const PTR_FOLLOWING = reinterpret_cast(-1); - inline static void* const PTR_INSERT = reinterpret_cast(-2); - - virtual void Align(int alignTo) = 0; - - virtual void* WriteDataRaw(const void* dst, size_t size) = 0; - virtual void* 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 void ReusableAddOffset(void* ptr, size_t size, size_t count, std::type_index type) = 0; - virtual void MarkFollowing(void** pPtr) = 0; - - template bool ReusableShouldWrite(T** pPtr) - { - return ReusableShouldWrite(reinterpret_cast(reinterpret_cast(pPtr)), sizeof(T), std::type_index(typeid(T))); - } - - template void ReusableAddOffset(T* ptr) - { - ReusableAddOffset(const_cast(reinterpret_cast(ptr)), sizeof(T), 1, 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))); - } - - template T* Write(T* dst) - { - return static_cast(WriteDataInBlock(reinterpret_cast(dst), sizeof(T))); - } - - template T* Write(T* dst, const size_t count) - { - return static_cast(WriteDataInBlock(reinterpret_cast(dst), count * sizeof(T))); - } - - template T* WritePartial(T* dst, const size_t size) - { - return static_cast(WriteDataInBlock(reinterpret_cast(dst), size)); - } - - template void MarkFollowing(T*& ptr) - { - MarkFollowing(reinterpret_cast(reinterpret_cast(&ptr))); - } -}; 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..2075773a --- /dev/null +++ b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.cpp @@ -0,0 +1,375 @@ +#include "ZoneOutputStream.h" + +#include "InMemoryZoneData.h" +#include "Utils/Alignment.h" +#include "Zone/XBlock.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + class ReusableEntry + { + public: + 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_block_size(blockSize) + { + } + + void* m_start_ptr; + void* m_end_ptr; + 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 + { + 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), + + // -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())); + + m_insert_block = blocks[insertBlock]; + } + + [[nodiscard]] unsigned GetPointerByteCount() const override + { + return m_pointer_byte_count; + } + + 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)); + } + } + + ZoneOutputOffset WriteDataRaw(const void* src, const size_t size) override + { + auto* result = m_zone_data.GetBufferOfSize(size); + memcpy(result, src, size); + + return ZoneOutputOffset(result); + } + + ZoneOutputOffset WriteDataInBlock(const void* src, const size_t size) override + { + assert(!m_block_stack.empty()); + + if (m_block_stack.empty()) + return ZoneOutputOffset(); + + 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 ZoneOutputOffset(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); + } + + 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()); + + 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* ptr, const ZoneOutputOffset outputOffset, const size_t entrySize, const std::type_index type) override + { + assert(!m_block_stack.empty()); + + if (ptr == 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 (ptr >= entry.m_start_ptr && ptr < entry.m_end_ptr) + { + assert((reinterpret_cast(ptr) - reinterpret_cast(entry.m_start_ptr)) % entrySize == 0); + + 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++) + static_cast(writtenPtrOffset)[i] = reinterpret_cast(&finalZonePointer)[i]; + + return false; + } + } + + return true; + } + + 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()); + + 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, blockSize, zoneOffset); + m_reusable_entries.emplace(std::make_pair(type, std::move(entries))); + } + else + { + foundEntriesForType->second.emplace_back(ptr, size, count, blockSize, 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) << (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; + } + + uintptr_t InsertPointer() + { + PushBlock(m_insert_block->m_index); + + Align(m_pointer_byte_count); + const auto result = GetCurrentZonePointer(); + IncBlockPos(m_pointer_byte_count); + + 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; + + 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) +{ +} + +ZoneOutputOffset ZoneOutputOffset::AtOffset(const size_t innerOffset) const +{ + return ZoneOutputOffset(static_cast(m_offset) + innerOffset); +} + +void ZoneOutputOffset::Inc(const size_t size) +{ + m_offset = static_cast(static_cast(m_offset) + size); +} + +void* ZoneOutputOffset::Offset() const +{ + return m_offset; +} + +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); +} + +ZoneStreamFillWriteAccessor::ZoneStreamFillWriteAccessor(void* blockBuffer, const size_t bufferSize) + : m_block_buffer(blockBuffer), + m_buffer_size(bufferSize) +{ +} + +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 new file mode 100644 index 00000000..34d9bcc7 --- /dev/null +++ b/src/ZoneWriting/Zone/Stream/ZoneOutputStream.h @@ -0,0 +1,148 @@ +#pragma once + +#include "InMemoryZoneData.h" +#include "Zone/Stream/IZoneStream.h" +#include "Zone/XBlock.h" + +#include +#include +#include +#include +#include +#include +#include + +class ZoneOutputOffset +{ +public: + ZoneOutputOffset(); + explicit ZoneOutputOffset(void* offset); + + [[nodiscard]] ZoneOutputOffset AtOffset(size_t innerOffset) const; + void Inc(size_t size); + [[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 + 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); + + *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); + 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: + /** + * \brief Returns the configured bits that make up a pointer. + */ + [[nodiscard]] virtual unsigned GetPointerByteCount() const = 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 ZoneOutputOffset 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 ZoneOutputOffset WriteDataInBlock(const void* dst, size_t size) = 0; + 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, size_t blockSize, std::type_index type) = 0; + virtual void MarkFollowing(ZoneOutputOffset offset) = 0; + + template bool ReusableShouldWrite(T* pPtr, const ZoneOutputOffset outputOffset) + { + return ReusableShouldWrite(const_cast(reinterpret_cast(pPtr)), outputOffset, sizeof(T), std::type_index(typeid(T))); + } + + template void ReusableAddOffset(T* ptr) + { + 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, 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) + { + return WriteDataInBlock(reinterpret_cast(dst), sizeof(T)); + } + + template ZoneOutputOffset Write(T* dst, const size_t count) + { + return WriteDataInBlock(reinterpret_cast(dst), count * sizeof(T)); + } + + ZoneOutputOffset WritePartial(const void* dst, const size_t size) + { + return WriteDataInBlock(dst, size); + } + + static std::unique_ptr + Create(unsigned pointerBitCount, unsigned blockBitCount, std::vector& blocks, block_t insertBlock, InMemoryZoneData& zoneData); +}; 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 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