diff --git a/r5dev/public/ipackedstore.h b/r5dev/public/ipackedstore.h index 76a5118b..4e26ea44 100644 --- a/r5dev/public/ipackedstore.h +++ b/r5dev/public/ipackedstore.h @@ -1,7 +1,7 @@ #ifndef IPACKEDSTORE_H #define IPACKEDSTORE_H -enum class EPackedLoadFlags : int +enum EPackedLoadFlags { LOAD_NONE, LOAD_VISIBLE = 1 << 0, // Visible to FileSystem. @@ -11,7 +11,7 @@ enum class EPackedLoadFlags : int LOAD_TEXTURE_UNK2 = 1 << 20, }; -enum class EPackedTextureFlags : short +enum EPackedTextureFlags { TEXTURE_NONE, TEXTURE_DEFAULT = 1 << 3, diff --git a/r5dev/vpklib/packedstore.cpp b/r5dev/vpklib/packedstore.cpp index 6eedd014..9ac89222 100644 --- a/r5dev/vpklib/packedstore.cpp +++ b/r5dev/vpklib/packedstore.cpp @@ -582,9 +582,9 @@ void CPackedStore::UnpackWorkspace(const VPKDir_t& vpkDir, const char* workspace BuildManifest(vpkDir.m_EntryBlocks, workspacePath, GetLevelName(vpkDir.m_DirFilePath)); const CUtlString basePath = vpkDir.m_DirFilePath.StripFilename(false); - FOR_EACH_VEC(vpkDir.m_PackFiles, i) + for (uint16_t packFileIndex : vpkDir.m_PakFileIndices) { - const CUtlString packFile = basePath + vpkDir.m_PackFiles[i]; + const CUtlString packFile = basePath + vpkDir.GetPackFileNameForIndex(packFileIndex); // Read from each pack file. FileHandle_t hPackFile = FileSystem()->Open(packFile.Get(), "rb", "GAME"); @@ -598,7 +598,7 @@ void CPackedStore::UnpackWorkspace(const VPKDir_t& vpkDir, const char* workspace { const VPKEntryBlock_t& entryBlock = vpkDir.m_EntryBlocks[j]; - if (entryBlock.m_iPackFileIndex != uint16_t(i)) + if (entryBlock.m_iPackFileIndex != packFileIndex) { // Chunk doesn't belongs to this block. continue; @@ -616,7 +616,8 @@ void CPackedStore::UnpackWorkspace(const VPKDir_t& vpkDir, const char* workspace continue; } - DevMsg(eDLL_T::FS, "Unpacking entry '%i' from block '%i' ('%s')\n", j, i, entryBlock.m_EntryPath.Get()); + DevMsg(eDLL_T::FS, "Unpacking entry '%i' from block '%i' ('%s')\n", + j, entryBlock.m_iPackFileIndex, entryBlock.m_EntryPath.Get()); FOR_EACH_VEC(entryBlock.m_Fragments, k) { @@ -642,8 +643,8 @@ void CPackedStore::UnpackWorkspace(const VPKDir_t& vpkDir, const char* workspace if (lzDecompStatus != lzham_decompress_status_t::LZHAM_DECOMP_STATUS_SUCCESS) { - Error(eDLL_T::FS, NO_ERROR, "Status '%d' for chunk '%zu' within entry '%zu' in block '%hu' (chunk not decompressed)\n", - lzDecompStatus, k, j, i); + Error(eDLL_T::FS, NO_ERROR, "Status '%d' for chunk '%i' within entry '%i' in block '%hu' (chunk not decompressed)\n", + lzDecompStatus, k, j, packFileIndex); } else // If successfully decompressed, write to file. { @@ -906,37 +907,26 @@ void VPKDir_t::Init(const CUtlString& dirFilePath) FileSystem()->Read(&m_Header.m_nSignatureSize, sizeof(uint32_t), hDirFile); // g_pPackedStore->GetEntryBlocks(m_EntryBlocks, hDirFile); - m_DirFilePath = dirFilePath; // Set path to vpk directory file. - m_PackFileCount = 0; + // Obtain every referenced pack file from the directory tree. FOR_EACH_VEC(m_EntryBlocks, i) { const VPKEntryBlock_t& entryBlock = m_EntryBlocks[i]; - - if (entryBlock.m_iPackFileIndex > m_PackFileCount) - { - m_PackFileCount = entryBlock.m_iPackFileIndex; - } - } - - for (uint16_t i = 0; i < m_PackFileCount + 1; i++) - { - m_PackFiles.AddToTail(GetPackFile(dirFilePath, i)); + m_PakFileIndices.insert(entryBlock.m_iPackFileIndex); } FileSystem()->Close(hDirFile); } //----------------------------------------------------------------------------- -// Purpose: formats pack file path for specific directory file -// Input : &directoryPath - -// iPackFileIndex - +// Purpose: formats pack file path for specified patch +// Input : iPackFileIndex - (patch) // output : string //----------------------------------------------------------------------------- -CUtlString VPKDir_t::GetPackFile(const CUtlString& directoryPath, uint16_t iPackFileIndex) const +CUtlString VPKDir_t::GetPackFileNameForIndex(uint16_t iPackFileIndex) const { - CUtlString packChunkName = StripLocalePrefix(directoryPath); + CUtlString packChunkName = StripLocalePrefix(m_DirFilePath); CUtlString packChunkIndex; packChunkIndex.Format("pak000_%03d", iPackFileIndex); diff --git a/r5dev/vpklib/packedstore.h b/r5dev/vpklib/packedstore.h index f3c34dcb..b3ff0bbd 100644 --- a/r5dev/vpklib/packedstore.h +++ b/r5dev/vpklib/packedstore.h @@ -44,10 +44,18 @@ static const char* const DIR_LOCALE[] "tchinese" }; +//----------------------------------------------------------------------------- +// KeyValues structure for the VPK manifest file. This struct gets populated by +// the VPK's corresponding manifest file, which ultimately determines how each +// asset is getting packed into the VPK. +//----------------------------------------------------------------------------- struct VPKKeyValues_t { - static constexpr uint16_t TEXTURE_FLAGS_DEFAULT = static_cast(EPackedTextureFlags::TEXTURE_DEFAULT); - static constexpr uint32_t LOAD_FLAGS_DEFAULT = static_cast(EPackedLoadFlags::LOAD_VISIBLE) | static_cast(EPackedLoadFlags::LOAD_CACHE); + static constexpr uint16_t TEXTURE_FLAGS_DEFAULT = + EPackedTextureFlags::TEXTURE_DEFAULT; + + static constexpr uint32_t LOAD_FLAGS_DEFAULT = + EPackedLoadFlags::LOAD_VISIBLE | EPackedLoadFlags::LOAD_CACHE; CUtlString m_EntryPath; uint16_t m_iPreloadSize; @@ -56,17 +64,29 @@ struct VPKKeyValues_t bool m_bUseCompression; bool m_bDeduplicate; - VPKKeyValues_t(const CUtlString& svEntryPath = "", uint16_t iPreloadSize = NULL, uint32_t nLoadFlags = LOAD_FLAGS_DEFAULT, - uint16_t nTextureFlags = TEXTURE_FLAGS_DEFAULT, bool bUseCompression = true, bool bDeduplicate = true); + VPKKeyValues_t(const CUtlString& svEntryPath = "", + uint16_t iPreloadSize = NULL, + uint32_t nLoadFlags = LOAD_FLAGS_DEFAULT, + uint16_t nTextureFlags = TEXTURE_FLAGS_DEFAULT, + bool bUseCompression = true, bool bDeduplicate = true); }; +//----------------------------------------------------------------------------- +// An asset packed into a VPK is carved into 'ENTRY_MAX_LEN' chunks, the chunk +// is then optionally compressed. A chunk is NOT compressed if the compressed +// size equals the uncompressed size. +//----------------------------------------------------------------------------- struct VPKChunkDescriptor_t { - uint32_t m_nLoadFlags; // Load flags. - uint16_t m_nTextureFlags; // Texture flags (only used if the entry is a vtf). - uint64_t m_nPackFileOffset; // Offset in pack file. - uint64_t m_nCompressedSize; // Compressed size of chunk. - uint64_t m_nUncompressedSize; // Uncompressed size of chunk. + uint32_t m_nLoadFlags; + + // Texture flags (only used if the entry is a vtf). + uint16_t m_nTextureFlags; + + // Offset in pack file. + uint64_t m_nPackFileOffset; + uint64_t m_nCompressedSize; + uint64_t m_nUncompressedSize; VPKChunkDescriptor_t() : m_nLoadFlags(0) @@ -77,16 +97,27 @@ struct VPKChunkDescriptor_t { } VPKChunkDescriptor_t(FileHandle_t hDirectoryFile); - VPKChunkDescriptor_t(uint32_t nLoadFlags, uint16_t nTextureFlags, uint64_t nPackFileOffset, uint64_t nCompressedSize, uint64_t nUncompressedSize); + VPKChunkDescriptor_t(uint32_t nLoadFlags, uint16_t nTextureFlags, + uint64_t nPackFileOffset, uint64_t nCompressedSize, uint64_t nUncompressedSize); }; +//----------------------------------------------------------------------------- +// An asset packed into a VPK is represented as an entry block. +//----------------------------------------------------------------------------- struct VPKEntryBlock_t { - uint32_t m_nFileCRC; // Crc32 for the uncompressed entry. - uint16_t m_iPreloadSize; // Preload bytes. - uint16_t m_iPackFileIndex; // Index of the pack file that contains this entry. - CUtlVector m_Fragments; // Vector of all the chunks of a given entry (chunks have a size limit of 1 MiB, anything over this limit is fragmented into smaller chunks). - CUtlString m_EntryPath; // Path to entry within vpk. + // Crc32 for the uncompressed entry. + uint32_t m_nFileCRC; + uint16_t m_iPreloadSize; + + // Index of the pack file that contains this entry. + uint16_t m_iPackFileIndex; + + // Vector of all the chunks of a given entry + // (chunks have a size limit of 1 MiB, anything + // over this limit is fragmented into smaller chunks). + CUtlVector m_Fragments; + CUtlString m_EntryPath; VPKEntryBlock_t(FileHandle_t pFile, const char* svEntryPath); VPKEntryBlock_t(const uint8_t* pData, size_t nLen, int64_t nOffset, uint16_t iPreloadSize, @@ -103,30 +134,30 @@ struct VPKEntryBlock_t } }; +//----------------------------------------------------------------------------- +// The VPK directory file header. +//----------------------------------------------------------------------------- struct VPKDirHeader_t { - uint32_t m_nHeaderMarker; // File magic. - uint16_t m_nMajorVersion; // Vpk major version. - uint16_t m_nMinorVersion; // Vpk minor version. - uint32_t m_nDirectorySize; // Directory tree size. - uint32_t m_nSignatureSize; // Directory signature. -}; - -struct VPKPair_t -{ - CUtlString m_PackName; - CUtlString m_DirName; - - VPKPair_t(const char* svLocale, const char* svTarget, const char* svLevel, int nPatch); + uint32_t m_nHeaderMarker; // File magic. + uint16_t m_nMajorVersion; // Vpk major version. + uint16_t m_nMinorVersion; // Vpk minor version. + uint32_t m_nDirectorySize; // Directory tree size. + uint32_t m_nSignatureSize; // Directory signature. }; +//----------------------------------------------------------------------------- +// The VPK directory tree structure. +//----------------------------------------------------------------------------- struct VPKDir_t { - VPKDirHeader_t m_Header; // Dir header. - CUtlVector m_EntryBlocks; // Vector of entry blocks. - uint16_t m_PackFileCount; // Number of pack patches (pack file count-1). - CUtlVector m_PackFiles; // Vector of pack file names. - CUtlString m_DirFilePath; // Path to vpk_dir file. + VPKDirHeader_t m_Header; + CUtlVector m_EntryBlocks; + CUtlString m_DirFilePath; + + // This set only contains packfile indices used + // by the directory tree, notated as pak000_xxx. + std::set m_PakFileIndices; class CTreeBuilder { @@ -145,7 +176,6 @@ struct VPKDir_t { m_Header.m_nHeaderMarker = VPK_HEADER_MARKER; m_Header.m_nMajorVersion = VPK_MAJOR_VERSION; m_Header.m_nMinorVersion = VPK_MINOR_VERSION; m_Header.m_nDirectorySize = NULL, m_Header.m_nSignatureSize = NULL; - m_PackFileCount = NULL; }; VPKDir_t(const CUtlString& svDirectoryFile); VPKDir_t(const CUtlString& svDirectoryFile, bool bSanitizeName); @@ -153,7 +183,7 @@ struct VPKDir_t void Init(const CUtlString& svPath); CUtlString StripLocalePrefix(const CUtlString& svDirectoryFile) const; - CUtlString GetPackFile(const CUtlString& svDirectoryPath, uint16_t iPackFileIndex) const; + CUtlString GetPackFileNameForIndex(uint16_t iPackFileIndex) const; void WriteHeader(FileHandle_t hDirectoryFile) const; void WriteTreeSize(FileHandle_t hDirectoryFile) const; @@ -161,6 +191,22 @@ struct VPKDir_t void BuildDirectoryFile(const CUtlString& svDirectoryFile, const CUtlVector& entryBlocks); }; +//----------------------------------------------------------------------------- +// Contains the VPK directory name, and the pack file name. Used for building +// the VPK file. +// !TODO[ AMOS ]: Remove this when patching is implemented! +//----------------------------------------------------------------------------- +struct VPKPair_t +{ + CUtlString m_PackName; + CUtlString m_DirName; + + VPKPair_t(const char* svLocale, const char* svTarget, const char* svLevel, int nPatch); +}; + +//----------------------------------------------------------------------------- +// VPK utility class. +//----------------------------------------------------------------------------- class CPackedStore { public: @@ -190,11 +236,11 @@ public: void UnpackWorkspace(const VPKDir_t& vpkDir, const char* workspaceName = ""); private: - lzham_compress_params m_lzCompParams; // LZham compression parameters. - lzham_decompress_params m_lzDecompParams; // LZham decompression parameters. + lzham_compress_params m_lzCompParams; // LZham compression parameters. + lzham_decompress_params m_lzDecompParams; // LZham decompression parameters. std::unordered_map m_ChunkHashMap; }; /////////////////////////////////////////////////////////////////////////////// extern CPackedStore* g_pPackedStore; -#endif // PACKEDSTORE_H \ No newline at end of file +#endif // PACKEDSTORE_H