diff --git a/src/Linker/Linker.cpp b/src/Linker/Linker.cpp index a6d67d11..6ea8434e 100644 --- a/src/Linker/Linker.cpp +++ b/src/Linker/Linker.cpp @@ -15,6 +15,7 @@ #include "SearchPath/SearchPathFilesystem.h" #include "ObjContainer/IWD/IWD.h" #include "LinkerArgs.h" +#include "ZoneWriting.h" #include "ZoneCreation/ZoneCreationContext.h" #include "ZoneCreation/IZoneCreator.h" #include "Game/IW4/ZoneCreatorIW4.h" @@ -446,6 +447,13 @@ class Linker::Impl if (!stream.is_open()) return false; + if(!ZoneWriting::WriteZone(stream, zone)) + { + std::cout << "Writing zone failed." << std::endl; + stream.close(); + return false; + } + stream.close(); return true; } diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp index 1c428493..c38e92ef 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.cpp @@ -1,7 +1,179 @@ #include "ZoneWriteTemplate.h" +#include #include +#include "Internal/BaseTemplate.h" + +class ZoneWriteTemplate::Internal final : BaseTemplate +{ + enum class MemberWriteType + { + ARRAY_POINTER, + DYNAMIC_ARRAY, + EMBEDDED, + EMBEDDED_ARRAY, + POINTER_ARRAY, + SINGLE_POINTER + }; + + static std::string WriterClassName(StructureInformation* asset) + { + std::ostringstream str; + str << "Writer_" << asset->m_definition->m_name; + return str.str(); + } + + void PrintHeaderConstructor() const + { + LINE(WriterClassName(m_env.m_asset) << "("<m_definition->GetFullName()<<"* asset, Zone* zone, IZoneOutputStream* stream);") + } + + void PrintHeaderMainWriteMethodDeclaration(const StructureInformation* info) const + { + LINE("void Write(" << info->m_definition->GetFullName() << "** pAsset);") + } + + void PrintHeaderGetNameMethodDeclaration(const StructureInformation* info) const + { + LINE("static std::string GetAssetName("<m_definition->GetFullName()<<"* pAsset);") + } + + void PrintConstructorMethod() + { + LINE(WriterClassName(m_env.m_asset) << "::" << WriterClassName(m_env.m_asset) << "("<m_definition->GetFullName()<<"* asset, Zone* zone, IZoneOutputStream* stream)") + + m_intendation++; + LINE_START(": AssetWriter(zone->m_pools->GetAsset("<m_asset_enum_entry->m_name<<", GetAssetName(asset))"<<", zone, stream)") + LINE_END("") + m_intendation--; + + LINE("{") + m_intendation++; + + m_intendation--; + LINE("}") + } + + void PrintMainWriteMethod() + { + LINE("void " << WriterClassName(m_env.m_asset) << "::Write(" << m_env.m_asset->m_definition->GetFullName() << "** pAsset)") + LINE("{") + m_intendation++; + + LINE("assert(pAsset != nullptr);") + + m_intendation--; + LINE("}") + } + + void PrintGetNameMethod() + { + LINE("std::string " << WriterClassName(m_env.m_asset) << "::GetAssetName(" << m_env.m_asset->m_definition->GetFullName() << "* pAsset)") + LINE("{") + m_intendation++; + + if (!m_env.m_asset->m_name_chain.empty()) + { + LINE_START("return pAsset") + + auto first = true; + for (auto* member : m_env.m_asset->m_name_chain) + { + if (first) + { + first = false; + LINE_MIDDLE("->" << member->m_member->m_name) + } + else + { + LINE_MIDDLE("." << member->m_member->m_name) + } + } + LINE_END(";") + } + else + { + LINE("return \"" << m_env.m_asset->m_definition->m_name << "\";") + } + + m_intendation--; + LINE("}") + } + +public: + Internal(std::ostream& stream, RenderingContext* context) + : BaseTemplate(stream, context) + { + } + + void Header() + { + LINE("// ====================================================================") + LINE("// This file has been generated by ZoneCodeGenerator.") + LINE("// Do not modify. ") + LINE("// Any changes will be discarded when regenerating.") + LINE("// ====================================================================") + LINE("") + LINE("#pragma once") + LINE("") + LINE("#include \"Writing/AssetWriter.h\"") + LINE("#include \"Game/" << m_env.m_game << "/" << m_env.m_game << ".h\"") + LINE("#include ") + LINE("") + LINE("namespace " << m_env.m_game) + LINE("{") + m_intendation++; + LINE("class " << WriterClassName(m_env.m_asset) << " final : public AssetWriter") + LINE("{") + m_intendation++; + + PrintHeaderGetNameMethodDeclaration(m_env.m_asset); + LINE("") + + m_intendation--; + LINE("public:") + m_intendation++; + PrintHeaderConstructor(); + PrintHeaderMainWriteMethodDeclaration(m_env.m_asset); + + m_intendation--; + LINE("};") + m_intendation--; + LINE("}") + } + + void Source() + { + LINE("// ====================================================================") + LINE("// This file has been generated by ZoneCodeGenerator.") + LINE("// Do not modify. ") + LINE("// Any changes will be discarded when regenerating.") + LINE("// ====================================================================") + LINE("") + LINE("#include \"" << Lower(m_env.m_asset->m_definition->m_name) << "_write_db.h\"") + LINE("#include ") + LINE("") + + if (!m_env.m_referenced_assets.empty()) + { + LINE("// Referenced Assets:") + for (auto* type : m_env.m_referenced_assets) + { + LINE("#include \"../" << Lower(type->m_type->m_name) << "/" << Lower(type->m_type->m_name) << "_write_db.h\"") + } + LINE("") + } + LINE("using namespace " << m_env.m_game << ";") + LINE("") + PrintConstructorMethod(); + LINE("") + PrintMainWriteMethod(); + LINE("") + PrintGetNameMethod(); + } +}; + std::vector ZoneWriteTemplate::GetFilesToRender(RenderingContext* context) { std::vector files; @@ -27,4 +199,18 @@ std::vector ZoneWriteTemplate::GetFilesToRender(RenderingConte void ZoneWriteTemplate::RenderFile(std::ostream& stream, const int fileTag, RenderingContext* context) { + Internal internal(stream, context); + + if (fileTag == TAG_HEADER) + { + internal.Header(); + } + else if (fileTag == TAG_SOURCE) + { + internal.Source(); + } + else + { + std::cout << "Unknown tag for ZoneWriteTemplate: " << fileTag << "\n"; + } } diff --git a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.h b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.h index 0aee63f4..afbbe2f1 100644 --- a/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.h +++ b/src/ZoneCodeGeneratorLib/Generating/Templates/ZoneWriteTemplate.h @@ -6,6 +6,8 @@ class ZoneWriteTemplate final : public ICodeTemplate static constexpr int TAG_HEADER = 1; static constexpr int TAG_SOURCE = 2; + class Internal; + public: std::vector GetFilesToRender(RenderingContext* context) override; void RenderFile(std::ostream& stream, int fileTag, RenderingContext* context) override; diff --git a/src/ZoneCommon/Pool/ZoneAssetPools.cpp b/src/ZoneCommon/Pool/ZoneAssetPools.cpp index 3bf5a67c..8b177df3 100644 --- a/src/ZoneCommon/Pool/ZoneAssetPools.cpp +++ b/src/ZoneCommon/Pool/ZoneAssetPools.cpp @@ -16,6 +16,11 @@ XAssetInfoGeneric* ZoneAssetPools::AddAsset(const asset_type_t type, std::string return assetInfo; } +size_t ZoneAssetPools::GetTotalAssetCount() const +{ + return m_assets_in_order.size(); +} + ZoneAssetPools::iterator ZoneAssetPools::begin() const { return m_assets_in_order.begin(); diff --git a/src/ZoneCommon/Pool/ZoneAssetPools.h b/src/ZoneCommon/Pool/ZoneAssetPools.h index d304f15c..42dd7047 100644 --- a/src/ZoneCommon/Pool/ZoneAssetPools.h +++ b/src/ZoneCommon/Pool/ZoneAssetPools.h @@ -1,10 +1,12 @@ #pragma once +#include +#include +#include +#include "Utils/ClassUtils.h" #include "XAssetInfo.h" #include "Zone/ZoneTypes.h" #include "Zone/Zone.h" -#include -#include class Zone; class XAssetInfoGeneric; @@ -30,6 +32,8 @@ public: virtual void InitPoolStatic(asset_type_t type, size_t capacity) = 0; virtual void InitPoolDynamic(asset_type_t type) = 0; + _NODISCARD size_t GetTotalAssetCount() const; + iterator begin() const; iterator end() const; }; diff --git a/src/ZoneWriting.lua b/src/ZoneWriting.lua index d51d5d3b..693662e4 100644 --- a/src/ZoneWriting.lua +++ b/src/ZoneWriting.lua @@ -37,12 +37,14 @@ function ZoneWriting:project() files { path.join(folder, "ZoneWriting/**.h"), - path.join(folder, "ZoneWriting/**.cpp") + path.join(folder, "ZoneWriting/**.cpp"), + ZoneCode:allWriteFiles() } vpaths { ["*"] = { - path.join(folder, "ZoneWriting") + path.join(folder, "ZoneWriting"), + path.join(BuildFolder(), "src/ZoneCode") } } @@ -50,6 +52,7 @@ function ZoneWriting:project() Crypto:include(includes) Utils:include(includes) zlib:include(includes) + ZoneCode:include(includes) ZoneCode:use() end diff --git a/src/ZoneWriting/Game/T6/ContentWriterT6.cpp b/src/ZoneWriting/Game/T6/ContentWriterT6.cpp index e69de29b..028fb13f 100644 --- a/src/ZoneWriting/Game/T6/ContentWriterT6.cpp +++ b/src/ZoneWriting/Game/T6/ContentWriterT6.cpp @@ -0,0 +1,257 @@ +#include "ContentWriterT6.h" + +#include +#include + +#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 "Writing/WritingException.h" + +using namespace T6; + +ContentWriter::ContentWriter() + : varXAssetList(nullptr), + varXAsset(nullptr), + varScriptStringList(nullptr) +{ +} + +void ContentWriter::CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const +{ + if (!m_zone->m_script_strings.empty()) + { + assert(m_zone->m_script_strings.size() <= SCR_STRING_MAX + 1); + xAssetList.stringList.count = m_zone->m_script_strings.size(); + xAssetList.stringList.strings = static_cast(memory.Alloc(sizeof(const char*) * m_zone->m_script_strings.size())); + + for (auto i = 0u; i < m_zone->m_script_strings.size(); i++) + { + xAssetList.stringList.strings[i] = m_zone->m_script_strings[i].c_str(); + } + } + else + { + xAssetList.stringList.count = 0; + xAssetList.stringList.strings = nullptr; + } + + xAssetList.dependCount = 0; + xAssetList.depends = nullptr; + + const auto assetCount = m_zone->m_pools->GetTotalAssetCount(); + if (assetCount > 0) + { + xAssetList.assetCount = assetCount; + xAssetList.assets = static_cast(memory.Alloc(sizeof(XAsset) * assetCount)); + + const auto end = m_zone->m_pools->end(); + auto index = 0u; + for (auto i = m_zone->m_pools->begin(); i != end; ++i) + { + auto& asset = xAssetList.assets[index++]; + asset.type = static_cast((*i)->m_type); + asset.header.data = (*i)->m_ptr; + } + } + else + { + xAssetList.assetCount = 0; + xAssetList.assets = nullptr; + } +} + +void ContentWriter::WriteScriptStringList(const bool atStreamStart) +{ + assert(m_zone->m_script_strings.empty()); + + m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); + + if (atStreamStart) + varScriptStringList = m_stream->Write(varScriptStringList); + + if (varScriptStringList->strings != nullptr) + { + m_stream->Align(alignof(const char*)); + varXString = varScriptStringList->strings; + WriteXStringArray(true, varScriptStringList->count); + + m_stream->MarkFollowing(varScriptStringList->strings); + } + + m_stream->PopBlock(); +} + +void ContentWriter::WriteXAsset(const bool atStreamStart) +{ +#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); \ + break; \ + } + + assert(varXAsset != nullptr); + + if (atStreamStart) + varXAsset = m_stream->Write(varXAsset); + + switch (varXAsset->type) + { + WRITE_ASSET(ASSET_TYPE_PHYSPRESET, PhysPreset, physPreset) + WRITE_ASSET(ASSET_TYPE_PHYSCONSTRAINTS, PhysConstraints, physConstraints) + WRITE_ASSET(ASSET_TYPE_DESTRUCTIBLEDEF, DestructibleDef, destructibleDef) + WRITE_ASSET(ASSET_TYPE_XANIMPARTS, XAnimParts, parts) + WRITE_ASSET(ASSET_TYPE_XMODEL, XModel, model) + WRITE_ASSET(ASSET_TYPE_MATERIAL, Material, material) + WRITE_ASSET(ASSET_TYPE_TECHNIQUE_SET, MaterialTechniqueSet, techniqueSet) + WRITE_ASSET(ASSET_TYPE_IMAGE, GfxImage, image) + WRITE_ASSET(ASSET_TYPE_SOUND, SndBank, sound) + WRITE_ASSET(ASSET_TYPE_SOUND_PATCH, SndPatch, soundPatch) + WRITE_ASSET(ASSET_TYPE_CLIPMAP, clipMap_t, clipMap) + WRITE_ASSET(ASSET_TYPE_CLIPMAP_PVS, clipMap_t, clipMap) + WRITE_ASSET(ASSET_TYPE_COMWORLD, ComWorld, comWorld) + WRITE_ASSET(ASSET_TYPE_GAMEWORLD_SP, GameWorldSp, gameWorldSp) + WRITE_ASSET(ASSET_TYPE_GAMEWORLD_MP, GameWorldMp, gameWorldMp) + WRITE_ASSET(ASSET_TYPE_MAP_ENTS, MapEnts, mapEnts) + WRITE_ASSET(ASSET_TYPE_GFXWORLD, GfxWorld, gfxWorld) + WRITE_ASSET(ASSET_TYPE_LIGHT_DEF, GfxLightDef, lightDef) + WRITE_ASSET(ASSET_TYPE_FONT, Font_s, font) + WRITE_ASSET(ASSET_TYPE_FONTICON, FontIcon, fontIcon) + WRITE_ASSET(ASSET_TYPE_MENULIST, MenuList, menuList) + WRITE_ASSET(ASSET_TYPE_MENU, menuDef_t, menu) + WRITE_ASSET(ASSET_TYPE_LOCALIZE_ENTRY, LocalizeEntry, localize) + WRITE_ASSET(ASSET_TYPE_WEAPON, WeaponVariantDef, weapon) + WRITE_ASSET(ASSET_TYPE_ATTACHMENT, WeaponAttachment, attachment) + WRITE_ASSET(ASSET_TYPE_ATTACHMENT_UNIQUE, WeaponAttachmentUnique, attachmentUnique) + WRITE_ASSET(ASSET_TYPE_WEAPON_CAMO, WeaponCamo, weaponCamo) + WRITE_ASSET(ASSET_TYPE_SNDDRIVER_GLOBALS, SndDriverGlobals, sndDriverGlobals) + WRITE_ASSET(ASSET_TYPE_FX, FxEffectDef, fx) + WRITE_ASSET(ASSET_TYPE_IMPACT_FX, FxImpactTable, impactFx) + WRITE_ASSET(ASSET_TYPE_RAWFILE, RawFile, rawfile) + WRITE_ASSET(ASSET_TYPE_STRINGTABLE, StringTable, stringTable) + WRITE_ASSET(ASSET_TYPE_LEADERBOARD, LeaderboardDef, leaderboardDef) + WRITE_ASSET(ASSET_TYPE_XGLOBALS, XGlobals, xGlobals) + WRITE_ASSET(ASSET_TYPE_DDL, ddlRoot_t, ddlRoot) + WRITE_ASSET(ASSET_TYPE_GLASSES, Glasses, glasses) + WRITE_ASSET(ASSET_TYPE_EMBLEMSET, EmblemSet, emblemSet) + WRITE_ASSET(ASSET_TYPE_SCRIPTPARSETREE, ScriptParseTree, scriptParseTree) + WRITE_ASSET(ASSET_TYPE_KEYVALUEPAIRS, KeyValuePairs, keyValuePairs) + WRITE_ASSET(ASSET_TYPE_VEHICLEDEF, VehicleDef, vehicleDef) + WRITE_ASSET(ASSET_TYPE_MEMORYBLOCK, MemoryBlock, memoryBlock); + WRITE_ASSET(ASSET_TYPE_ADDON_MAP_ENTS, AddonMapEnts, addonMapEnts) + WRITE_ASSET(ASSET_TYPE_TRACER, TracerDef, tracerDef) + WRITE_ASSET(ASSET_TYPE_SKINNEDVERTS, SkinnedVertsDef, skinnedVertsDef) + WRITE_ASSET(ASSET_TYPE_QDB, Qdb, qdb) + WRITE_ASSET(ASSET_TYPE_SLUG, Slug, slug) + WRITE_ASSET(ASSET_TYPE_FOOTSTEP_TABLE, FootstepTableDef, footstepTableDef) + WRITE_ASSET(ASSET_TYPE_FOOTSTEPFX_TABLE, FootstepFXTableDef, footstepFXTableDef) + WRITE_ASSET(ASSET_TYPE_ZBARRIER, ZBarrierDef, zbarrierDef) + + default: + { + std::ostringstream str; + str << "Unsupported asset type: " << varXAsset->type << "."; + throw WritingException(str.str()); + } + } + +#undef WRITE_ASSET +} + +void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t count) +{ + assert(varXAsset != nullptr); + + if (atStreamStart) + varXAsset = m_stream->Write(varXAsset, count); + + for (size_t index = 0; index < count; index++) + { + WriteXAsset(false); + varXAsset++; + } +} + +void ContentWriter::WriteContent(Zone* zone, IZoneOutputStream* stream) +{ + m_zone = zone; + 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))); + + varScriptStringList = &varXAssetList->stringList; + WriteScriptStringList(false); + + if (varXAssetList->depends != nullptr) + { + m_stream->Align(alignof(const char*)); + varXString = varXAssetList->depends; + WriteXStringArray(true, varXAssetList->dependCount); + m_stream->MarkFollowing(varXAssetList->depends); + } + + if (varXAssetList->assets != nullptr) + { + m_stream->Align(alignof(XAsset)); + varXAsset = varXAssetList->assets; + WriteXAssetArray(true, varXAssetList->assetCount); + m_stream->MarkFollowing(varXAssetList->assets); + } + + m_stream->PopBlock(); +} diff --git a/src/ZoneWriting/Game/T6/ContentWriterT6.h b/src/ZoneWriting/Game/T6/ContentWriterT6.h index 7800f742..af4d56fd 100644 --- a/src/ZoneWriting/Game/T6/ContentWriterT6.h +++ b/src/ZoneWriting/Game/T6/ContentWriterT6.h @@ -7,13 +7,16 @@ namespace T6 { class ContentWriter final : public ContentWriterBase, public IContentWritingEntryPoint { + XAssetList* varXAssetList; XAsset* varXAsset; ScriptStringList* varScriptStringList; - void LoadScriptStringList(bool atStreamStart); + void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const; - void LoadXAsset(bool atStreamStart); - void LoadXAssetArray(bool atStreamStart, size_t count); + void WriteScriptStringList(bool atStreamStart); + + void WriteXAsset(bool atStreamStart); + void WriteXAssetArray(bool atStreamStart, size_t count); public: ContentWriter(); diff --git a/src/ZoneWriting/Writing/AssetWriter.cpp b/src/ZoneWriting/Writing/AssetWriter.cpp index e69de29b..7eaa807e 100644 --- a/src/ZoneWriting/Writing/AssetWriter.cpp +++ b/src/ZoneWriting/Writing/AssetWriter.cpp @@ -0,0 +1,44 @@ +#include "AssetWriter.h" + +#include +#include +#include + +AssetWriter::AssetWriter(XAssetInfoGeneric* asset, Zone* zone, IZoneOutputStream* stream) + : ContentWriterBase(zone, stream), + m_asset(asset), + varScriptString(nullptr) +{ +} + +scr_string_t AssetWriter::UseScriptString(const scr_string_t scrString) const +{ + if (m_asset->m_zone == m_zone) + return scrString; + + const auto strValue = m_asset->m_zone->m_script_strings[scrString]; + const auto scrStringEntry = std::find(m_zone->m_script_strings.begin(), m_zone->m_script_strings.end(), strValue); + assert(scrStringEntry != m_zone->m_script_strings.end()); + + if (scrStringEntry != m_zone->m_script_strings.end()) + { + return static_cast(std::distance(scrStringEntry, m_zone->m_script_strings.begin())); + } + + return 0; +} + +void AssetWriter::WriteScriptStringArray(const bool atStreamStart, const size_t count) +{ + assert(varScriptString != nullptr); + + if (atStreamStart) + varScriptString = m_stream->Write(varScriptString, count); + + auto* ptr = varScriptString; + for (size_t index = 0; index < count; index++) + { + *ptr = UseScriptString(*ptr); + ptr++; + } +} diff --git a/src/ZoneWriting/Writing/AssetWriter.h b/src/ZoneWriting/Writing/AssetWriter.h index 04a59d49..8dafb3a2 100644 --- a/src/ZoneWriting/Writing/AssetWriter.h +++ b/src/ZoneWriting/Writing/AssetWriter.h @@ -1,6 +1,20 @@ #pragma once -class AssetWriter +#include "Utils/ClassUtils.h" +#include "Zone/Zone.h" +#include "Zone/ZoneTypes.h" +#include "Pool/XAssetInfo.h" +#include "ContentWriterBase.h" + +class AssetWriter : public ContentWriterBase { - -}; \ No newline at end of file + XAssetInfoGeneric* m_asset; + +protected: + scr_string_t* varScriptString; + + AssetWriter(XAssetInfoGeneric* asset, Zone* zone, IZoneOutputStream* stream); + + _NODISCARD scr_string_t UseScriptString(scr_string_t scrString) const; + void WriteScriptStringArray(bool atStreamStart, size_t count); +}; diff --git a/src/ZoneWriting/Writing/ContentWriterBase.cpp b/src/ZoneWriting/Writing/ContentWriterBase.cpp index e69de29b..acacbd21 100644 --- a/src/ZoneWriting/Writing/ContentWriterBase.cpp +++ b/src/ZoneWriting/Writing/ContentWriterBase.cpp @@ -0,0 +1,47 @@ +#include "ContentWriterBase.h" + +#include + +ContentWriterBase::ContentWriterBase() + : varXString(nullptr), + m_zone(nullptr), + m_stream(nullptr) +{ +} + +ContentWriterBase::ContentWriterBase(Zone* zone, IZoneOutputStream* stream) + : varXString(nullptr), + m_zone(zone), + m_stream(stream) +{ +} + +void ContentWriterBase::WriteXString(const bool atStreamStart) +{ + assert(varXString != nullptr); + + if (atStreamStart) + varXString = m_stream->Write(varXString); + + if (m_stream->ReusableShouldWrite(varXString)) + { + m_stream->Align(alignof(const char)); + m_stream->WriteNullTerminated(*varXString); + + m_stream->MarkFollowing(*varXString); + } +} + +void ContentWriterBase::WriteXStringArray(const bool atStreamStart, const size_t count) +{ + assert(varXString != nullptr); + + if (atStreamStart) + varXString = m_stream->Write(varXString, count); + + for (size_t index = 0; index < count; index++) + { + WriteXString(false); + varXString++; + } +} diff --git a/src/ZoneWriting/Writing/ContentWriterBase.h b/src/ZoneWriting/Writing/ContentWriterBase.h index 5cf0a471..e3e85711 100644 --- a/src/ZoneWriting/Writing/ContentWriterBase.h +++ b/src/ZoneWriting/Writing/ContentWriterBase.h @@ -6,9 +6,6 @@ class ContentWriterBase { protected: - static constexpr void* PTR_FOLLOWING = reinterpret_cast(-1); - static constexpr void* PTR_INSERT = reinterpret_cast(-2); - const char** varXString; Zone* m_zone; @@ -17,7 +14,7 @@ protected: ContentWriterBase(); ContentWriterBase(Zone* zone, IZoneOutputStream* stream); - void WriteXString(bool atStreamStart) const; + void WriteXString(bool atStreamStart); void WriteXStringArray(bool atStreamStart, size_t count); public: diff --git a/src/ZoneWriting/Zone/Stream/IZoneOutputStream.h b/src/ZoneWriting/Zone/Stream/IZoneOutputStream.h index b5a484dc..71a752e0 100644 --- a/src/ZoneWriting/Zone/Stream/IZoneOutputStream.h +++ b/src/ZoneWriting/Zone/Stream/IZoneOutputStream.h @@ -9,42 +9,52 @@ class IZoneOutputStream : public IZoneStream { public: + static constexpr void* PTR_FOLLOWING = reinterpret_cast(-1); + static constexpr void* PTR_INSERT = reinterpret_cast(-2); + virtual void Align(int alignTo) = 0; - virtual void* WriteDataRaw(void* dst, size_t size) = 0; - virtual void* WriteDataInBlock(void* dst, size_t size) = 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(void* dst) = 0; + virtual void WriteNullTerminated(const void* dst) = 0; virtual bool ReusableShouldWrite(void** pPtr, size_t size, size_t count, std::type_index type) = 0; + virtual void MarkFollowing(void** pPtr) = 0; template bool ReusableShouldWrite(T** pPtr) { - return ReusableShouldWrite(pPtr, sizeof(T), 1, std::type_index(typeid(T))); + return ReusableShouldWrite(reinterpret_cast(reinterpret_cast(pPtr)), sizeof(T), 1, std::type_index(typeid(T))); } template - bool ReusableShouldWrite(T** pPtr, size_t count) + bool ReusableShouldWrite(T** pPtr, const size_t count) { - return ReusableShouldWrite(pPtr, sizeof(T), count, std::type_index(typeid(T))); + return ReusableShouldWrite(reinterpret_cast(reinterpret_cast(pPtr)), sizeof(T), count, std::type_index(typeid(T))); } template T* Write(T* dst) { - return static_cast(WriteDataInBlock(const_cast(reinterpret_cast(dst)), sizeof(T))); + return static_cast(WriteDataInBlock(reinterpret_cast(dst), sizeof(T))); } template T* Write(T* dst, const uint32_t count) { - return static_cast(WriteDataInBlock(const_cast(reinterpret_cast(dst)), count * sizeof(T))); + return static_cast(WriteDataInBlock(reinterpret_cast(dst), count * sizeof(T))); } template T* WritePartial(T* dst, const size_t size) { - return static_cast(WriteDataInBlock(const_cast(reinterpret_cast(dst)), 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 index 92c03637..d1f7c1cf 100644 --- a/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.cpp +++ b/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.cpp @@ -64,7 +64,7 @@ void InMemoryZoneOutputStream::Align(const int align) { assert(!m_block_stack.empty()); - if (align > 0) + if (align > 1) { auto* block = m_block_stack.top(); @@ -75,14 +75,14 @@ void InMemoryZoneOutputStream::Align(const int align) } } -void* InMemoryZoneOutputStream::WriteDataRaw(void* src, const size_t size) +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(void* src, const size_t size) +void* InMemoryZoneOutputStream::WriteDataInBlock(const void* src, const size_t size) { assert(!m_block_stack.empty()); @@ -130,9 +130,9 @@ void InMemoryZoneOutputStream::IncBlockPos(const size_t size) } } -void InMemoryZoneOutputStream::WriteNullTerminated(void* src) +void InMemoryZoneOutputStream::WriteNullTerminated(const void* src) { - const auto len = strlen(static_cast(src)); + const auto len = strlen(static_cast(src)); WriteDataInBlock(src, len + 1); } @@ -161,9 +161,20 @@ uintptr_t InMemoryZoneOutputStream::InsertPointer() return result; } +void InMemoryZoneOutputStream::MarkFollowing(void** pPtr) +{ + assert(!m_block_stack.empty()); + assert(pPtr != nullptr); + *pPtr = m_block_stack.top()->m_type == XBlock::Type::BLOCK_TYPE_TEMP ? PTR_INSERT : PTR_FOLLOWING; +} + bool InMemoryZoneOutputStream::ReusableShouldWrite(void** pPtr, const size_t entrySize, const size_t entryCount, std::type_index type) { assert(!m_block_stack.empty()); + assert(pPtr != nullptr); + + if (*pPtr == nullptr) + return false; const auto inTemp = m_block_stack.top()->m_type == XBlock::Type::BLOCK_TYPE_TEMP; const auto foundEntriesForType = m_reusable_entries.find(type); @@ -173,8 +184,7 @@ bool InMemoryZoneOutputStream::ReusableShouldWrite(void** pPtr, const size_t ent auto zoneOffset = inTemp ? InsertPointer() : GetCurrentZonePointer(); entries.emplace_back(*pPtr, entrySize, entryCount, zoneOffset); m_reusable_entries.emplace(std::make_pair(type, std::move(entries))); - - *pPtr = inTemp ? PTR_INSERT : PTR_FOLLOWING; + return true; } @@ -190,7 +200,6 @@ bool InMemoryZoneOutputStream::ReusableShouldWrite(void** pPtr, const size_t ent auto zoneOffset = inTemp ? InsertPointer() : GetCurrentZonePointer(); foundEntriesForType->second.emplace_back(*pPtr, entrySize, entryCount, zoneOffset); - - *pPtr = inTemp ? PTR_INSERT : PTR_FOLLOWING; + return true; } diff --git a/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.h b/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.h index aa01081a..183ea4bb 100644 --- a/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.h +++ b/src/ZoneWriting/Zone/Stream/Impl/InMemoryZoneOutputStream.h @@ -9,9 +9,6 @@ class InMemoryZoneOutputStream final : public IZoneOutputStream { - static constexpr void* PTR_FOLLOWING = reinterpret_cast(-1); - static constexpr void* PTR_INSERT = reinterpret_cast(-2); - class ReusableEntry { public: @@ -44,9 +41,10 @@ public: void PushBlock(block_t block) override; block_t PopBlock() override; void Align(int align) override; - void* WriteDataRaw(void* src, size_t size) override; - void* WriteDataInBlock(void* src, size_t size) 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(void* src) override; + void WriteNullTerminated(const void* src) override; + void MarkFollowing(void** pPtr) override; bool ReusableShouldWrite(void** pPtr, size_t entrySize, size_t entryCount, std::type_index type) override; };