2022-10-12 23:39:26 +02:00
|
|
|
|
//=============================================================================//
|
|
|
|
|
//
|
|
|
|
|
// Purpose: Valve Pak utility class.
|
|
|
|
|
//
|
|
|
|
|
//=============================================================================//
|
|
|
|
|
// packedstore.cpp
|
|
|
|
|
//
|
2022-11-16 00:54:51 +01:00
|
|
|
|
// Note: VPK's are created in pairs of a directory file and pack file(s).
|
|
|
|
|
// - <locale><target>_<level>.bsp.pak000_dir.vpk --> directory file.
|
|
|
|
|
// - <target>_<level>.bsp.pak000_<patch>.vpk --> pack file.
|
|
|
|
|
//
|
|
|
|
|
// - Assets larger than 1MiB are fragmented into chunks of 1MiB or smaller (ENTRY_MAX_LEN).
|
|
|
|
|
// - A VPK directory file could be patched up to 512 times before full rebuild is required.
|
2022-10-12 23:39:26 +02:00
|
|
|
|
//
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
2022-06-02 01:59:03 +02:00
|
|
|
|
#include "core/stdafx.h"
|
|
|
|
|
#include "tier1/cvar.h"
|
|
|
|
|
#include "mathlib/adler32.h"
|
|
|
|
|
#include "mathlib/crc32.h"
|
2022-06-04 13:55:24 +02:00
|
|
|
|
#include "mathlib/sha1.h"
|
2022-11-23 12:18:33 +01:00
|
|
|
|
#include "filesystem/filesystem.h"
|
|
|
|
|
#include "vpc/keyvalues.h"
|
2022-06-02 01:59:03 +02:00
|
|
|
|
#include "vpklib/packedstore.h"
|
2022-03-04 12:22:17 +01:00
|
|
|
|
|
2022-10-02 12:17:03 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-17 20:37:12 +01:00
|
|
|
|
// Static buffers for fragmenting/compressing the source files and decompressing
|
2022-10-02 12:17:03 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-10-02 19:24:00 +02:00
|
|
|
|
static uint8_t s_EntryBuf[ENTRY_MAX_LEN];
|
|
|
|
|
static uint8_t s_DecompBuf[ENTRY_MAX_LEN];
|
2022-10-02 12:17:03 +02:00
|
|
|
|
|
2022-06-02 01:59:03 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: initialize parameters for compression algorithm
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CPackedStore::InitLzCompParams(void)
|
|
|
|
|
{
|
|
|
|
|
/*| PARAMETERS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/
|
2022-06-05 12:28:49 +02:00
|
|
|
|
m_lzCompParams.m_dict_size_log2 = VPK_DICT_SIZE;
|
2022-09-11 00:16:31 +02:00
|
|
|
|
m_lzCompParams.m_level = GetCompressionLevel();
|
|
|
|
|
m_lzCompParams.m_compress_flags = lzham_compress_flags::LZHAM_COMP_FLAG_DETERMINISTIC_PARSING;
|
2022-11-17 20:37:12 +01:00
|
|
|
|
m_lzCompParams.m_max_helper_threads = fs_packedstore_max_helper_threads->GetInt();
|
2022-06-02 01:59:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: initialize parameters for decompression algorithm
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void CPackedStore::InitLzDecompParams(void)
|
|
|
|
|
{
|
|
|
|
|
/*| PARAMETERS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/
|
2022-06-05 12:28:49 +02:00
|
|
|
|
m_lzDecompParams.m_dict_size_log2 = VPK_DICT_SIZE;
|
2022-12-04 01:33:10 +01:00
|
|
|
|
m_lzDecompParams.m_decompress_flags = lzham_decompress_flags::LZHAM_DECOMP_FLAG_OUTPUT_UNBUFFERED;
|
2022-06-02 01:59:03 +02:00
|
|
|
|
m_lzDecompParams.m_struct_size = sizeof(lzham_decompress_params);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-11 00:16:31 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: gets the LZHAM compression level
|
|
|
|
|
// output : lzham_compress_level
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
lzham_compress_level CPackedStore::GetCompressionLevel(void) const
|
|
|
|
|
{
|
|
|
|
|
const char* pszLevel = fs_packedstore_compression_level->GetString();
|
|
|
|
|
|
|
|
|
|
if(strcmp(pszLevel, "fastest") == NULL)
|
|
|
|
|
return lzham_compress_level::LZHAM_COMP_LEVEL_FASTEST;
|
|
|
|
|
else if (strcmp(pszLevel, "faster") == NULL)
|
|
|
|
|
return lzham_compress_level::LZHAM_COMP_LEVEL_FASTER;
|
|
|
|
|
else if (strcmp(pszLevel, "default") == NULL)
|
|
|
|
|
return lzham_compress_level::LZHAM_COMP_LEVEL_DEFAULT;
|
|
|
|
|
else if (strcmp(pszLevel, "better") == NULL)
|
|
|
|
|
return lzham_compress_level::LZHAM_COMP_LEVEL_BETTER;
|
|
|
|
|
else if (strcmp(pszLevel, "uber") == NULL)
|
|
|
|
|
return lzham_compress_level::LZHAM_COMP_LEVEL_UBER;
|
|
|
|
|
else
|
|
|
|
|
return lzham_compress_level::LZHAM_COMP_LEVEL_DEFAULT;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-02 01:59:03 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: obtains and returns the entry block to the vector
|
2022-11-23 17:09:48 +01:00
|
|
|
|
// Input : hDirectoryFile -
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
// output : vector<VPKEntryBlock_t>
|
2022-06-02 01:59:03 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 17:09:48 +01:00
|
|
|
|
vector<VPKEntryBlock_t> CPackedStore::GetEntryBlocks(FileHandle_t hDirectoryFile) const
|
2022-06-02 01:59:03 +02:00
|
|
|
|
{
|
|
|
|
|
string svName, svPath, svExtension;
|
2022-11-23 17:09:48 +01:00
|
|
|
|
vector<VPKEntryBlock_t> vEntryBlocks;
|
|
|
|
|
while (!(svExtension = FileSystem()->ReadString(hDirectoryFile)).empty())
|
2022-06-02 01:59:03 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
while (!(svPath = FileSystem()->ReadString(hDirectoryFile)).empty())
|
2022-06-02 01:59:03 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
while (!(svName = FileSystem()->ReadString(hDirectoryFile)).empty())
|
2022-06-02 01:59:03 +02:00
|
|
|
|
{
|
2022-09-11 00:16:31 +02:00
|
|
|
|
const string svFilePath = FormatEntryPath(svPath, svName, svExtension);
|
2022-11-23 17:09:48 +01:00
|
|
|
|
vEntryBlocks.push_back(VPKEntryBlock_t(hDirectoryFile, svFilePath));
|
2022-06-02 01:59:03 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-23 17:09:48 +01:00
|
|
|
|
return vEntryBlocks;
|
2022-06-02 01:59:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: scans the input directory and returns the paths to the vector
|
2022-11-23 17:09:48 +01:00
|
|
|
|
// Input : &svWorkspace -
|
|
|
|
|
// Output : vpk keyvalues vector of all existing entry paths
|
2022-06-02 01:59:03 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 17:09:48 +01:00
|
|
|
|
vector<VPKKeyValues_t> CPackedStore::GetEntryValues(const string& svWorkspace) const
|
2022-06-02 01:59:03 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
vector<VPKKeyValues_t> vEntryValues;
|
|
|
|
|
vector<string> vIgnoredList = GetIgnoreList(svWorkspace);
|
2022-06-06 23:08:53 +02:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
fs::recursive_directory_iterator dir(svWorkspace), end;
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
while (dir != end)
|
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
const vector<string>::iterator it = std::find(vIgnoredList.begin(), vIgnoredList.end(),
|
2022-06-07 13:44:31 +02:00
|
|
|
|
GetExtension(dir->path().filename().u8string(), true, true));
|
2022-11-23 17:09:48 +01:00
|
|
|
|
if (it != vIgnoredList.end())
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
{
|
2022-06-07 13:44:31 +02:00
|
|
|
|
dir.disable_recursion_pending(); // Skip all ignored folders and extensions.
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
}
|
2022-09-10 00:07:42 +02:00
|
|
|
|
else if (dir->file_size() > 0) // Empty files are not supported.
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
const string svEntryPath = dir->path().u8string();
|
|
|
|
|
if (!GetExtension(svEntryPath).empty())
|
2022-09-10 00:07:42 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
vEntryValues.push_back(VPKKeyValues_t(ConvertToUnixPath(svEntryPath)));
|
2022-09-10 00:07:42 +02:00
|
|
|
|
}
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
}
|
|
|
|
|
dir++;
|
|
|
|
|
}
|
2022-11-23 17:09:48 +01:00
|
|
|
|
return vEntryValues;
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 17:09:48 +01:00
|
|
|
|
// Purpose: scans the input directory and returns the values to the vector if path exists in manifest
|
|
|
|
|
// Input : &svWorkspace -
|
2022-11-23 12:18:33 +01:00
|
|
|
|
// *pManifestKV -
|
2022-11-23 17:09:48 +01:00
|
|
|
|
// Output : vpk keyvalues vector of all existing and included entry paths
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 17:09:48 +01:00
|
|
|
|
vector<VPKKeyValues_t> CPackedStore::GetEntryValues(const string& svWorkspace, KeyValues* pManifestKV) const
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
vector<VPKKeyValues_t> vEntryValues;
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
|
|
|
|
if (!pManifestKV)
|
|
|
|
|
{
|
2023-02-04 15:59:45 +01:00
|
|
|
|
Warning(eDLL_T::FS, "Invalid VPK build manifest KV; unable to parse entry list\n");
|
2022-11-23 17:09:48 +01:00
|
|
|
|
return vEntryValues;
|
2022-11-23 12:18:33 +01:00
|
|
|
|
}
|
2022-06-06 23:08:53 +02:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
vector<string> vIgnoredList = GetIgnoreList(svWorkspace);
|
|
|
|
|
fs::recursive_directory_iterator dir(svWorkspace), end;
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
while (dir != end)
|
2022-06-02 01:59:03 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
const vector<string>::iterator it = std::find(vIgnoredList.begin(), vIgnoredList.end(),
|
2022-06-07 13:44:31 +02:00
|
|
|
|
GetExtension(dir->path().filename().u8string(), true, true));
|
2022-11-23 17:09:48 +01:00
|
|
|
|
if (it != vIgnoredList.end())
|
2022-06-02 01:59:03 +02:00
|
|
|
|
{
|
2022-06-07 13:44:31 +02:00
|
|
|
|
dir.disable_recursion_pending(); // Skip all ignored folders and extensions.
|
2023-01-26 03:00:53 +01:00
|
|
|
|
continue;
|
2022-06-02 01:59:03 +02:00
|
|
|
|
}
|
2023-01-26 03:00:53 +01:00
|
|
|
|
const string svFullPath = ConvertToWinPath(dir->path().u8string());
|
|
|
|
|
if (!GetExtension(svFullPath).empty())
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
{
|
2023-01-26 03:00:53 +01:00
|
|
|
|
// Remove workspace path by offsetting it by its size.
|
|
|
|
|
const char* pszEntry = (svFullPath.c_str() + svWorkspace.length());
|
|
|
|
|
KeyValues* pEntryKV = pManifestKV->FindKey(pszEntry);
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
2023-01-26 03:00:53 +01:00
|
|
|
|
if (pEntryKV)
|
|
|
|
|
{
|
|
|
|
|
if (!dir->file_size()) // Empty files are not supported.
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
{
|
2023-01-26 03:00:53 +01:00
|
|
|
|
Warning(eDLL_T::FS, "File '%s' listed in build manifest appears truncated\n", dir->path().relative_path().c_str());
|
|
|
|
|
continue;
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
}
|
2023-01-26 03:00:53 +01:00
|
|
|
|
|
|
|
|
|
vEntryValues.push_back(VPKKeyValues_t(
|
|
|
|
|
ConvertToUnixPath(svFullPath),
|
|
|
|
|
pEntryKV->GetInt("preloadSize", NULL),
|
|
|
|
|
pEntryKV->GetInt("loadFlags", static_cast<uint32_t>(EPackedLoadFlags::LOAD_VISIBLE) | static_cast<uint32_t>(EPackedLoadFlags::LOAD_CACHE)),
|
|
|
|
|
pEntryKV->GetInt("textureFlags", static_cast<uint16_t>(EPackedTextureFlags::TEXTURE_DEFAULT)),
|
|
|
|
|
pEntryKV->GetBool("useCompression", true),
|
|
|
|
|
pEntryKV->GetBool("useDataSharing", true))
|
|
|
|
|
);
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
dir++;
|
2022-06-02 01:59:03 +02:00
|
|
|
|
}
|
2022-11-23 17:09:48 +01:00
|
|
|
|
return vEntryValues;
|
2022-06-02 01:59:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-10-11 15:37:34 +02:00
|
|
|
|
// Purpose: gets the parts of the directory file name
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
// Input : &svDirectoryName -
|
2022-11-16 00:54:51 +01:00
|
|
|
|
// nCaptureGroup - (1 = locale + target, 2 = level)
|
2022-10-11 15:37:34 +02:00
|
|
|
|
// Output : part of directory file name as string
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-06-05 17:28:39 +02:00
|
|
|
|
string CPackedStore::GetNameParts(const string& svDirectoryName, int nCaptureGroup) const
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
{
|
|
|
|
|
std::smatch smRegexMatches;
|
2022-10-11 15:37:34 +02:00
|
|
|
|
std::regex_search(svDirectoryName, smRegexMatches, DIR_REGEX);
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
|
2022-06-05 17:28:39 +02:00
|
|
|
|
return smRegexMatches[nCaptureGroup].str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-16 00:54:51 +01:00
|
|
|
|
// Purpose: gets the level name from the directory file name
|
2022-06-05 17:28:39 +02:00
|
|
|
|
// Input : &svDirectoryName -
|
2022-11-16 00:54:51 +01:00
|
|
|
|
// Output : level name as string (e.g. "mp_rr_box")
|
2022-06-05 17:28:39 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-16 00:54:51 +01:00
|
|
|
|
string CPackedStore::GetLevelName(const string& svDirectoryName) const
|
2022-06-05 17:28:39 +02:00
|
|
|
|
{
|
|
|
|
|
std::smatch smRegexMatches;
|
2022-10-11 15:37:34 +02:00
|
|
|
|
std::regex_search(svDirectoryName, smRegexMatches, DIR_REGEX);
|
2022-06-05 17:28:39 +02:00
|
|
|
|
|
|
|
|
|
return smRegexMatches[1].str() + smRegexMatches[2].str();
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 12:18:33 +01:00
|
|
|
|
// Purpose: gets the manifest file associated with the VPK name (must be freed after wards)
|
2022-11-16 00:54:51 +01:00
|
|
|
|
// Input : &svWorkspace -
|
2022-06-06 23:08:53 +02:00
|
|
|
|
// &svManifestName -
|
2022-11-23 17:09:48 +01:00
|
|
|
|
// Output : KeyValues (build manifest pointer)
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 12:18:33 +01:00
|
|
|
|
KeyValues* CPackedStore::GetManifest(const string& svWorkspace, const string& svManifestName) const
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
string svPathOut = fmt::format("{:s}{:s}{:s}.{:s}", svWorkspace, "manifest/", svManifestName, "txt");
|
|
|
|
|
KeyValues* pManifestKV = FileSystem()->LoadKeyValues(IFileSystem::TYPE_COMMON, svPathOut.c_str(), "GAME");
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
if (!pManifestKV)
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
Warning(eDLL_T::FS, "Failed to parse VPK build manifest: '%s'\n", svPathOut.c_str());
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
}
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
|
|
|
|
return pManifestKV;
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-06 23:08:53 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: gets the contents from the global ignore list (.vpkignore)
|
2022-11-16 00:54:51 +01:00
|
|
|
|
// Input : &svWorkspace -
|
|
|
|
|
// Output : a string vector of ignored directories/files and extensions
|
2022-06-06 23:08:53 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-16 00:54:51 +01:00
|
|
|
|
vector<string> CPackedStore::GetIgnoreList(const string& svWorkspace) const
|
2022-06-06 23:08:53 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
string svIgnore = svWorkspace + ".vpkignore";
|
2022-11-24 11:48:23 +01:00
|
|
|
|
FileHandle_t hIgnoreFile = FileSystem()->Open(svIgnore.c_str(), "rt", "GAME");
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
|
|
|
|
if (!hIgnoreFile)
|
|
|
|
|
{
|
|
|
|
|
Warning(eDLL_T::FS, "No ignore file provided; continuing build without...\n");
|
|
|
|
|
return vector<string>();
|
|
|
|
|
}
|
2022-06-06 23:08:53 +02:00
|
|
|
|
|
|
|
|
|
vector<string> vIgnore;
|
2022-11-23 12:18:33 +01:00
|
|
|
|
char szIgnore[MAX_PATH];
|
|
|
|
|
|
|
|
|
|
while (FileSystem()->ReadLine(szIgnore, sizeof(szIgnore) - 1, hIgnoreFile))
|
2022-06-06 23:08:53 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
if (!strstr(szIgnore, "//"))
|
2022-06-06 23:08:53 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
if (char* pEOL = strchr(szIgnore, '\n'))
|
2022-06-06 23:08:53 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
// Null newline character.
|
|
|
|
|
*pEOL = '\0';
|
|
|
|
|
if (pEOL - szIgnore > 0)
|
2022-06-06 23:08:53 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
// Null carriage return.
|
|
|
|
|
if (*(pEOL - 1) == '\r')
|
|
|
|
|
{
|
|
|
|
|
*(pEOL - 1) = '\0';
|
|
|
|
|
}
|
2022-06-06 23:08:53 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
|
|
|
|
vIgnore.push_back(szIgnore);
|
2022-06-06 23:08:53 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
|
|
|
|
FileSystem()->Close(hIgnoreFile);
|
2022-06-06 23:08:53 +02:00
|
|
|
|
return vIgnore;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-02 01:59:03 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-06-06 14:54:22 +02:00
|
|
|
|
// Purpose: formats the file entry path
|
2022-11-23 12:18:33 +01:00
|
|
|
|
// Input : &svPath -
|
2022-06-06 23:08:53 +02:00
|
|
|
|
// &svName -
|
|
|
|
|
// &svExtension -
|
2022-10-11 15:37:34 +02:00
|
|
|
|
// Output : formatted entry path
|
2022-06-02 01:59:03 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 12:18:33 +01:00
|
|
|
|
string CPackedStore::FormatEntryPath(const string& svPath, const string& svName, const string& svExtension) const
|
2022-06-02 01:59:03 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
return fmt::format("{:s}{:s}{:s}.{:s}", svPath, svPath.empty() ? "" : "/", svName, svExtension);
|
2022-06-02 01:59:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: builds the VPK manifest file
|
|
|
|
|
// Input : &vBlock -
|
2022-11-23 17:09:48 +01:00
|
|
|
|
// &svWorkspace -
|
2022-06-06 23:08:53 +02:00
|
|
|
|
// &svManifestName -
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 12:18:33 +01:00
|
|
|
|
void CPackedStore::BuildManifest(const vector<VPKEntryBlock_t>& vBlock, const string& svWorkspace, const string& svManifestName) const
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
KeyValues kv("BuildManifest");
|
|
|
|
|
KeyValues* pManifestKV = kv.FindKey("BuildManifest", true);
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
|
2022-10-09 12:08:54 +02:00
|
|
|
|
for (const VPKEntryBlock_t& vEntry : vBlock)
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
{
|
2022-11-16 00:54:51 +01:00
|
|
|
|
const VPKChunkDescriptor_t& vDescriptor = vEntry.m_vFragments[0];
|
2022-11-23 12:18:33 +01:00
|
|
|
|
KeyValues* pEntryKV = pManifestKV->FindKey(ConvertToWinPath(vEntry.m_svEntryPath).c_str(), true);
|
|
|
|
|
|
|
|
|
|
pEntryKV->SetInt("preloadSize", vEntry.m_iPreloadSize);
|
|
|
|
|
pEntryKV->SetInt("loadFlags", vDescriptor.m_nLoadFlags);
|
|
|
|
|
pEntryKV->SetInt("textureFlags", vDescriptor.m_nTextureFlags);
|
|
|
|
|
pEntryKV->SetBool("useCompression", vDescriptor.m_nCompressedSize != vDescriptor.m_nUncompressedSize);
|
|
|
|
|
pEntryKV->SetBool("useDataSharing", true);
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
string svPathOut = fmt::format("{:s}{:s}{:s}.{:s}", svWorkspace, "manifest/", svManifestName, "txt");
|
|
|
|
|
CUtlBuffer uBuf(0i64, 0, CUtlBuffer::TEXT_BUFFER);
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
kv.RecursiveSaveToFile(uBuf, 0);
|
|
|
|
|
|
2023-02-04 15:59:45 +01:00
|
|
|
|
FileSystem()->CreateDirHierarchy(fmt::format("{:s}{:s}", svWorkspace, "manifest/").c_str(), "GAME");
|
2022-11-23 12:18:33 +01:00
|
|
|
|
FileSystem()->WriteFile(svPathOut.c_str(), "GAME", uBuf);
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-02 01:59:03 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: validates extraction result with precomputed CRC32 hash
|
2022-11-23 17:09:48 +01:00
|
|
|
|
// Input : &svAssetPath -
|
2022-12-04 01:33:10 +01:00
|
|
|
|
// : nFileCRC -
|
2022-06-02 01:59:03 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-12-04 01:33:10 +01:00
|
|
|
|
void CPackedStore::ValidateCRC32PostDecomp(const string& svAssetPath, const uint32_t nFileCRC)
|
2022-06-02 01:59:03 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
FileHandle_t hAsset = FileSystem()->Open(svAssetPath.c_str(), "rb", "GAME");
|
|
|
|
|
if (!hAsset)
|
|
|
|
|
{
|
|
|
|
|
Error(eDLL_T::FS, NO_ERROR, "%s - Unable to open '%s' (insufficient rights?)\n", __FUNCTION__, svAssetPath.c_str());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
uint32_t nLen = FileSystem()->Size(hAsset);
|
|
|
|
|
uint8_t* pBuf = MemAllocSingleton()->Alloc<uint8_t>(nLen);
|
|
|
|
|
|
|
|
|
|
FileSystem()->Read(pBuf, nLen, hAsset);
|
|
|
|
|
FileSystem()->Close(hAsset);
|
|
|
|
|
|
2022-12-04 01:33:10 +01:00
|
|
|
|
uint32_t nCrc32 = crc32::update(NULL, pBuf, nLen);
|
2022-11-23 12:18:33 +01:00
|
|
|
|
MemAllocSingleton()->Free(pBuf);
|
2022-06-02 01:59:03 +02:00
|
|
|
|
|
2022-12-04 01:33:10 +01:00
|
|
|
|
if (nCrc32 != nFileCRC)
|
2022-06-02 01:59:03 +02:00
|
|
|
|
{
|
2022-12-04 01:33:10 +01:00
|
|
|
|
Warning(eDLL_T::FS, "Computed checksum '0x%lX' doesn't match expected checksum '0x%lX'. File may be corrupt!\n", nCrc32, nFileCRC);
|
|
|
|
|
nCrc32 = NULL;
|
2022-06-02 01:59:03 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-16 00:54:51 +01:00
|
|
|
|
// Purpose: packs all files from workspace path into VPK file
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
// Input : &vPair -
|
2022-11-16 00:54:51 +01:00
|
|
|
|
// &svWorkspace -
|
|
|
|
|
// &svBuildPath -
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
// bManifestOnly -
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-16 00:54:51 +01:00
|
|
|
|
void CPackedStore::PackWorkspace(const VPKPair_t& vPair, const string& svWorkspace, const string& svBuildPath, bool bManifestOnly)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
const string svPackFilePath = string(svBuildPath + vPair.m_svPackName);
|
2022-11-23 12:18:33 +01:00
|
|
|
|
FileHandle_t hPackFile = FileSystem()->Open(svPackFilePath.c_str(), "wb", "GAME");
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
if (!hPackFile)
|
|
|
|
|
{
|
|
|
|
|
Error(eDLL_T::FS, NO_ERROR, "%s - Unable to write to '%s' (read-only?)\n", __FUNCTION__, svPackFilePath.c_str());
|
|
|
|
|
return;
|
|
|
|
|
}
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
vector<VPKKeyValues_t> vEntryValues;
|
2022-11-23 12:18:33 +01:00
|
|
|
|
vector<VPKEntryBlock_t> vEntryBlocks;
|
|
|
|
|
KeyValues* pManifestKV = nullptr;
|
2022-06-06 23:08:53 +02:00
|
|
|
|
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
if (bManifestOnly)
|
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
pManifestKV = GetManifest(svWorkspace, GetLevelName(vPair.m_svDirectoryName));
|
2022-11-23 17:09:48 +01:00
|
|
|
|
vEntryValues = GetEntryValues(svWorkspace, pManifestKV);
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
|
|
|
|
if (pManifestKV)
|
|
|
|
|
{
|
|
|
|
|
pManifestKV->DeleteThis();
|
|
|
|
|
}
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
}
|
2022-06-05 12:28:49 +02:00
|
|
|
|
else // Pack all files in workspace.
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
vEntryValues = GetEntryValues(svWorkspace);
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
}
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-17 20:37:12 +01:00
|
|
|
|
uint64_t nSharedTotal = NULL;
|
|
|
|
|
uint32_t nSharedCount = NULL;
|
2022-06-05 17:28:39 +02:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
for (size_t i = 0, ps = vEntryValues.size(); i < ps; i++)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
const VPKKeyValues_t& vEntryValue = vEntryValues[i];
|
|
|
|
|
FileHandle_t hAsset = FileSystem()->Open(vEntryValue.m_svEntryPath.c_str(), "rb", "GAME");
|
2022-11-23 12:18:33 +01:00
|
|
|
|
if (!hAsset)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
Error(eDLL_T::FS, NO_ERROR, "%s - Unable to open '%s' (insufficient rights?)\n", __FUNCTION__, vEntryValue.m_svEntryPath.c_str());
|
2022-11-23 12:18:33 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-10-02 19:24:00 +02:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
const char* szDestPath = (vEntryValue.m_svEntryPath.c_str() + svWorkspace.length());
|
2022-11-23 12:18:33 +01:00
|
|
|
|
uint32_t nLen = FileSystem()->Size(hAsset);
|
|
|
|
|
uint8_t* pBuf = MemAllocSingleton()->Alloc<uint8_t>(nLen);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
FileSystem()->Read(pBuf, nLen, hAsset);
|
|
|
|
|
FileSystem()->Seek(hAsset, 0, FileSystemSeek_t::FILESYSTEM_SEEK_HEAD);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
DevMsg(eDLL_T::FS, "Packing entry '%zu' ('%s')\n", i, szDestPath);
|
2022-11-23 17:09:48 +01:00
|
|
|
|
vEntryBlocks.push_back(VPKEntryBlock_t(pBuf, nLen, FileSystem()->Tell(hPackFile), vEntryValue.m_iPreloadSize, 0, vEntryValue.m_nLoadFlags, vEntryValue.m_nTextureFlags, szDestPath));
|
2022-10-02 02:16:51 +02:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
VPKEntryBlock_t& vEntryBlock = vEntryBlocks[i];
|
|
|
|
|
for (size_t j = 0, es = vEntryBlock.m_vFragments.size(); j < es; j++)
|
2022-11-23 12:18:33 +01:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
VPKChunkDescriptor_t& vDescriptor = vEntryBlock.m_vFragments[j];
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
FileSystem()->Read(s_EntryBuf, vDescriptor.m_nCompressedSize, hAsset);
|
|
|
|
|
vDescriptor.m_nPackFileOffset = FileSystem()->Tell(hPackFile);
|
2022-10-02 19:24:00 +02:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
if (vEntryValue.m_bUseDataSharing)
|
2022-11-23 12:18:33 +01:00
|
|
|
|
{
|
|
|
|
|
string svEntryHash = sha1(string(reinterpret_cast<char*>(s_EntryBuf), vDescriptor.m_nUncompressedSize));
|
|
|
|
|
auto p = m_mChunkHashMap.insert({ svEntryHash, vDescriptor });
|
2022-06-04 13:55:24 +02:00
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
if (!p.second) // Map to existing chunk to avoid having copies of the same data.
|
2022-06-04 13:55:24 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
DevMsg(eDLL_T::FS, "Mapping chunk '%zu' ('%s') to existing chunk at '0x%llx'\n", j, svEntryHash.c_str(), p.first->second.m_nPackFileOffset);
|
2022-10-02 12:17:03 +02:00
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
vDescriptor = p.first->second;
|
|
|
|
|
nSharedTotal += vDescriptor.m_nCompressedSize;
|
|
|
|
|
nSharedCount++;
|
2022-10-02 12:17:03 +02:00
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
continue;
|
2022-10-02 19:24:00 +02:00
|
|
|
|
}
|
2022-11-23 12:18:33 +01:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
if (vEntryValue.m_bUseCompression)
|
2022-11-23 12:18:33 +01:00
|
|
|
|
{
|
2022-12-04 14:17:14 +01:00
|
|
|
|
lzham_compress_status_t lzCompStatus = lzham_compress_memory(&m_lzCompParams, s_EntryBuf, &vDescriptor.m_nCompressedSize, s_EntryBuf,
|
2022-12-04 01:33:10 +01:00
|
|
|
|
vDescriptor.m_nUncompressedSize, nullptr);
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
2022-12-04 14:17:14 +01:00
|
|
|
|
if (lzCompStatus != lzham_compress_status_t::LZHAM_COMP_STATUS_SUCCESS)
|
2022-10-02 19:24:00 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
Warning(eDLL_T::FS, "Status '%d' for chunk '%zu' within entry '%zu' in block '%hu' (chunk packed without compression)\n",
|
2022-12-04 14:17:14 +01:00
|
|
|
|
lzCompStatus, j, i, vEntryBlocks[i].m_iPackFileIndex);
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
2022-10-02 19:24:00 +02:00
|
|
|
|
vDescriptor.m_nCompressedSize = vDescriptor.m_nUncompressedSize;
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-23 12:18:33 +01:00
|
|
|
|
else // Write data uncompressed.
|
|
|
|
|
{
|
|
|
|
|
vDescriptor.m_nCompressedSize = vDescriptor.m_nUncompressedSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vDescriptor.m_bIsCompressed = vDescriptor.m_nCompressedSize != vDescriptor.m_nUncompressedSize;
|
|
|
|
|
FileSystem()->Write(s_EntryBuf, vDescriptor.m_nCompressedSize, hPackFile);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
|
|
|
|
MemAllocSingleton()->Free(pBuf);
|
|
|
|
|
FileSystem()->Close(hAsset);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
|
|
|
|
DevMsg(eDLL_T::FS, "*** Build block totaling '%zu' bytes with '%zu' shared bytes among '%lu' chunks\n", FileSystem()->Tell(hPackFile), nSharedTotal, nSharedCount);
|
|
|
|
|
FileSystem()->Close(hPackFile);
|
2022-10-02 12:17:03 +02:00
|
|
|
|
|
2022-06-06 14:54:22 +02:00
|
|
|
|
m_mChunkHashMap.clear();
|
2022-10-02 19:24:00 +02:00
|
|
|
|
memset(s_EntryBuf, '\0', sizeof(s_EntryBuf));
|
2022-06-05 17:28:39 +02:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
VPKDir_t vDirectory;
|
|
|
|
|
vDirectory.BuildDirectoryFile(svBuildPath + vPair.m_svDirectoryName, vEntryBlocks);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-16 00:54:51 +01:00
|
|
|
|
// Purpose: rebuilds manifest and extracts all files from specified VPK file
|
2022-11-23 17:09:48 +01:00
|
|
|
|
// Input : &vDirectory -
|
2022-11-16 00:54:51 +01:00
|
|
|
|
// &svWorkspace -
|
2022-06-02 02:00:35 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 17:09:48 +01:00
|
|
|
|
void CPackedStore::UnpackWorkspace(const VPKDir_t& vDirectory, const string& svWorkspace)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
if (vDirectory.m_vHeader.m_nHeaderMarker != VPK_HEADER_MARKER ||
|
|
|
|
|
vDirectory.m_vHeader.m_nMajorVersion != VPK_MAJOR_VERSION ||
|
|
|
|
|
vDirectory.m_vHeader.m_nMinorVersion != VPK_MINOR_VERSION)
|
2022-06-05 17:28:39 +02:00
|
|
|
|
{
|
2022-09-14 01:14:51 +02:00
|
|
|
|
Error(eDLL_T::FS, NO_ERROR, "Unsupported VPK directory file (invalid header criteria)\n");
|
2022-06-05 17:28:39 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
BuildManifest(vDirectory.m_vEntryBlocks, svWorkspace, GetLevelName(vDirectory.m_svDirectoryPath));
|
|
|
|
|
const string svPath = RemoveFileName(vDirectory.m_svDirectoryPath) + '/';
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
for (size_t i = 0, fs = vDirectory.m_vPackFile.size(); i < fs; i++)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
const string svPackFile = svPath + vDirectory.m_vPackFile[i];
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
|
|
|
|
// Read from each pack file.
|
|
|
|
|
FileHandle_t hPackFile = FileSystem()->Open(svPackFile.c_str(), "rb", "GAME");
|
|
|
|
|
if (!hPackFile)
|
|
|
|
|
{
|
|
|
|
|
Error(eDLL_T::FS, NO_ERROR, "%s - Unable to open '%s' (insufficient rights?)\n", __FUNCTION__, svPackFile.c_str());
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
for (size_t j = 0, es = vDirectory.m_vEntryBlocks.size(); j < es; j++)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
const VPKEntryBlock_t& vEntryBlock = vDirectory.m_vEntryBlocks[j];
|
|
|
|
|
if (vEntryBlock.m_iPackFileIndex != static_cast<uint16_t>(i))
|
2022-06-04 03:12:46 +02:00
|
|
|
|
{
|
2022-10-02 19:24:00 +02:00
|
|
|
|
continue;
|
2022-06-04 03:12:46 +02:00
|
|
|
|
}
|
2022-06-04 03:19:05 +02:00
|
|
|
|
else // Chunk belongs to this block.
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2023-02-04 15:59:45 +01:00
|
|
|
|
string svFilePath;
|
|
|
|
|
CreateDirectories(svWorkspace + vEntryBlock.m_svEntryPath, &svFilePath);
|
2022-11-23 12:18:33 +01:00
|
|
|
|
FileHandle_t hAsset = FileSystem()->Open(svFilePath.c_str(), "wb", "GAME");
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
if (!hAsset)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
Error(eDLL_T::FS, NO_ERROR, "%s - Unable to write to '%s' (read-only?)\n", __FUNCTION__, svFilePath.c_str());
|
2022-06-04 03:12:46 +02:00
|
|
|
|
continue;
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
DevMsg(eDLL_T::FS, "Unpacking entry '%zu' from block '%zu' ('%s')\n", j, i, vEntryBlock.m_svEntryPath.c_str());
|
|
|
|
|
for (size_t k = 0, cs = vEntryBlock.m_vFragments.size(); k < cs; k++)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
const VPKChunkDescriptor_t& vChunk = vEntryBlock.m_vFragments[k];
|
2022-06-06 14:54:22 +02:00
|
|
|
|
m_nChunkCount++;
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
FileSystem()->Seek(hPackFile, vChunk.m_nPackFileOffset, FileSystemSeek_t::FILESYSTEM_SEEK_HEAD);
|
|
|
|
|
FileSystem()->Read(s_EntryBuf, vChunk.m_nCompressedSize, hPackFile);
|
2022-06-04 03:12:46 +02:00
|
|
|
|
|
2022-06-06 14:54:22 +02:00
|
|
|
|
if (vChunk.m_bIsCompressed)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-10-02 19:24:00 +02:00
|
|
|
|
size_t nDstLen = sizeof(s_DecompBuf);
|
|
|
|
|
assert(vChunk.m_nCompressedSize <= nDstLen);
|
|
|
|
|
|
|
|
|
|
if (vChunk.m_nCompressedSize > nDstLen)
|
|
|
|
|
break; // Corrupt or invalid chunk descriptor.
|
|
|
|
|
|
2022-12-04 14:17:14 +01:00
|
|
|
|
lzham_decompress_status_t lzDecompStatus = lzham_decompress_memory(&m_lzDecompParams, s_DecompBuf,
|
2022-12-04 01:33:10 +01:00
|
|
|
|
&nDstLen, s_EntryBuf, vChunk.m_nCompressedSize, nullptr);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-12-04 14:17:14 +01:00
|
|
|
|
if (lzDecompStatus != lzham_decompress_status_t::LZHAM_DECOMP_STATUS_SUCCESS)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-09-14 01:14:51 +02:00
|
|
|
|
Error(eDLL_T::FS, NO_ERROR, "Status '%d' for chunk '%zu' within entry '%zu' in block '%hu' (chunk not decompressed)\n",
|
2022-12-04 14:17:14 +01:00
|
|
|
|
lzDecompStatus, m_nChunkCount, i, vEntryBlock.m_iPackFileIndex);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
2022-06-04 03:12:46 +02:00
|
|
|
|
else // If successfully decompressed, write to file.
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
FileSystem()->Write(s_DecompBuf, nDstLen, hAsset);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-02 19:24:00 +02:00
|
|
|
|
else // If not compressed, write source data into output file.
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
FileSystem()->Write(s_EntryBuf, vChunk.m_nUncompressedSize, hAsset);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
FileSystem()->Close(hAsset);
|
2022-11-23 17:09:48 +01:00
|
|
|
|
if (m_nChunkCount == vEntryBlock.m_vFragments.size()) // Only validate after last entry in block had been written.
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-17 20:37:12 +01:00
|
|
|
|
m_nChunkCount = NULL;
|
2022-12-04 01:33:10 +01:00
|
|
|
|
ValidateCRC32PostDecomp(svFilePath, vEntryBlock.m_nFileCRC);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
2022-10-02 19:24:00 +02:00
|
|
|
|
}
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
2022-11-23 12:18:33 +01:00
|
|
|
|
FileSystem()->Close(hPackFile);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
2022-10-02 19:24:00 +02:00
|
|
|
|
memset(s_EntryBuf, '\0', sizeof(s_EntryBuf));
|
|
|
|
|
memset(s_DecompBuf, '\0', sizeof(s_DecompBuf));
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: 'VPKKeyValues_t' memory constructor
|
|
|
|
|
// Input : &svEntryPath -
|
|
|
|
|
// iPreloadSize -
|
|
|
|
|
// nLoadFlags -
|
|
|
|
|
// nTextureFlags -
|
|
|
|
|
// bUseCompression -
|
|
|
|
|
// bUseDataSharing -
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
VPKKeyValues_t::VPKKeyValues_t(const string& svEntryPath, uint16_t iPreloadSize, uint32_t nLoadFlags, uint16_t nTextureFlags, bool bUseCompression, bool bUseDataSharing)
|
|
|
|
|
{
|
|
|
|
|
m_svEntryPath = svEntryPath;
|
|
|
|
|
m_iPreloadSize = iPreloadSize;
|
|
|
|
|
m_nLoadFlags = nLoadFlags;
|
|
|
|
|
m_nTextureFlags = nTextureFlags;
|
|
|
|
|
m_bUseCompression = bUseCompression;
|
|
|
|
|
m_bUseDataSharing = bUseDataSharing;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-02 02:00:35 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
// Purpose: 'VPKEntryBlock_t' file constructor
|
2022-11-23 17:09:48 +01:00
|
|
|
|
// Input : hDirectoryFile -
|
2022-11-23 14:49:40 +01:00
|
|
|
|
// &svEntryPath -
|
2022-06-02 02:00:35 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 17:09:48 +01:00
|
|
|
|
VPKEntryBlock_t::VPKEntryBlock_t(FileHandle_t hDirectoryFile, const string& svEntryPath)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-16 00:54:51 +01:00
|
|
|
|
m_svEntryPath = svEntryPath; // Set the entry path.
|
2022-11-23 14:49:40 +01:00
|
|
|
|
StringReplace(m_svEntryPath, "\\", "/"); // Flip windows-style backslash to forward slash.
|
2023-02-04 15:59:45 +01:00
|
|
|
|
StringReplace(m_svEntryPath, " /", ""); // Remove space character representing VPK root.
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileSystem()->Read(&m_nFileCRC, sizeof(uint32_t), hDirectoryFile); //
|
|
|
|
|
FileSystem()->Read(&m_iPreloadSize, sizeof(uint16_t), hDirectoryFile); //
|
|
|
|
|
FileSystem()->Read(&m_iPackFileIndex, sizeof(uint16_t), hDirectoryFile); //
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
|
|
|
|
uint16_t nMarker = 0;
|
2022-11-16 00:54:51 +01:00
|
|
|
|
do // Loop through all chunks in the entry and add to list.
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
VPKChunkDescriptor_t entry(hDirectoryFile);
|
2022-11-16 00:54:51 +01:00
|
|
|
|
m_vFragments.push_back(entry);
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileSystem()->Read(&nMarker, sizeof(nMarker), hDirectoryFile);
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
|
|
|
|
} while (nMarker != static_cast<uint16_t>(PACKFILEINDEX_END));
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: 'VPKEntryBlock_t' memory constructor
|
2022-11-23 12:18:33 +01:00
|
|
|
|
// Input : *pData -
|
2022-11-23 17:09:48 +01:00
|
|
|
|
// nLen
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
// nOffset -
|
2022-11-16 00:54:51 +01:00
|
|
|
|
// iPreloadSize -
|
|
|
|
|
// iPackFileIndex -
|
2022-06-06 23:08:53 +02:00
|
|
|
|
// nLoadFlags -
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
// nTextureFlags -
|
2022-11-16 00:54:51 +01:00
|
|
|
|
// &svEntryPath -
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 12:18:33 +01:00
|
|
|
|
VPKEntryBlock_t::VPKEntryBlock_t(const uint8_t* pData, size_t nLen, int64_t nOffset, uint16_t iPreloadSize,
|
2022-11-16 00:54:51 +01:00
|
|
|
|
uint16_t iPackFileIndex, uint32_t nLoadFlags, uint16_t nTextureFlags, const string& svEntryPath)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
m_nFileCRC = crc32::update(NULL, pData, nLen);
|
2022-11-16 00:54:51 +01:00
|
|
|
|
m_iPreloadSize = iPreloadSize;
|
|
|
|
|
m_iPackFileIndex = iPackFileIndex;
|
2022-06-06 14:54:22 +02:00
|
|
|
|
m_svEntryPath = svEntryPath;
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
size_t nFragmentCount = (nLen + ENTRY_MAX_LEN - 1) / ENTRY_MAX_LEN;
|
|
|
|
|
size_t nFileSize = nLen;
|
2022-06-02 02:00:35 +02:00
|
|
|
|
int64_t nCurrentOffset = nOffset;
|
2022-06-05 17:28:39 +02:00
|
|
|
|
|
2022-11-16 00:54:51 +01:00
|
|
|
|
for (size_t i = 0; i < nFragmentCount; i++) // Fragment data into 1 MiB chunks.
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-16 00:54:51 +01:00
|
|
|
|
size_t nSize = std::min<uint64_t>(ENTRY_MAX_LEN, nFileSize);
|
|
|
|
|
nFileSize -= nSize;
|
|
|
|
|
m_vFragments.push_back(VPKChunkDescriptor_t(nLoadFlags, nTextureFlags, nCurrentOffset, nSize, nSize));
|
2022-06-02 02:00:35 +02:00
|
|
|
|
nCurrentOffset += nSize;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-06-06 14:54:22 +02:00
|
|
|
|
// Purpose: 'VPKChunkDescriptor_t' file constructor
|
2022-11-23 17:09:48 +01:00
|
|
|
|
// Input : hDirectoryFile -
|
2022-06-05 17:28:39 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 17:09:48 +01:00
|
|
|
|
VPKChunkDescriptor_t::VPKChunkDescriptor_t(FileHandle_t hDirectoryFile)
|
2022-06-05 17:28:39 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileSystem()->Read(&m_nLoadFlags, sizeof(uint32_t), hDirectoryFile); //
|
|
|
|
|
FileSystem()->Read(&m_nTextureFlags, sizeof(uint16_t), hDirectoryFile); //
|
|
|
|
|
FileSystem()->Read(&m_nPackFileOffset, sizeof(uint64_t), hDirectoryFile); //
|
|
|
|
|
FileSystem()->Read(&m_nCompressedSize, sizeof(uint64_t), hDirectoryFile); //
|
|
|
|
|
FileSystem()->Read(&m_nUncompressedSize, sizeof(uint64_t), hDirectoryFile); //
|
2022-11-16 00:54:51 +01:00
|
|
|
|
m_bIsCompressed = (m_nCompressedSize != m_nUncompressedSize);
|
2022-06-05 17:28:39 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-06-06 14:54:22 +02:00
|
|
|
|
// Purpose: 'VPKChunkDescriptor_t' memory constructor
|
2022-06-06 23:08:53 +02:00
|
|
|
|
// Input : nLoadFlags -
|
|
|
|
|
// nTextureFlags -
|
|
|
|
|
// nArchiveOffset -
|
|
|
|
|
// nCompressedSize -
|
|
|
|
|
// nUncompressedSize -
|
Proper VPK repacking
Initial proper implementation pending cleanup.
The new system builds a manifest file when a VPK is unpacked. The manifest files contains data such as the entry flags and texture flags. It also contains a field determining whether the file should be compressed or not.
When a user repacks a pack, the system attempts to load this manifest file and does a lookup to the object to retrieve the flags (most of these flags are unknown, but they are used by the engine and are necessary for stuff like cubemaps and texture files to work correctly. Cubemaps won't work with proper flags, and textures (decals, particle system components, etc..) will look washed out without them.
I think some also determine whether a file within the VPK should be cached or not, so simply marking everything as 0x101 will probably end up in more CPU time and higher filesystem cache usage (depot/ is only 0x1, I don't think anything there is getting cached ever without the 0x100 flag).
User could also repack a VPK while excluding anything that is not in the manifest file. So you could unpack all VPK's into a single directory (each VPK has its own manifest file tied to its level name), and rebuild all the VPK's with only the files that where originally in them.
fs_pack_vpk command usage: <locale> <context> <level_name> <manifest_only>
locale determines the pak language (default english), context determines whether is a server/client vpk, level_name determines the BSP name of the pak, manifest_only determines whether the pack system should only include files within the manifest (leaving this arg out will build all files into the vpk).
The VPK workspace path is determined with ConVar 'fs_packedstore_workspace'.
2022-06-04 01:08:23 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-10-09 12:08:54 +02:00
|
|
|
|
VPKChunkDescriptor_t::VPKChunkDescriptor_t(uint32_t nLoadFlags, uint16_t nTextureFlags,
|
2022-11-23 17:09:48 +01:00
|
|
|
|
uint64_t nPackFileOffset, uint64_t nCompressedSize, uint64_t nUncompressedSize)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-06-06 14:54:22 +02:00
|
|
|
|
m_nLoadFlags = nLoadFlags;
|
2022-06-02 02:00:35 +02:00
|
|
|
|
m_nTextureFlags = nTextureFlags;
|
2022-11-23 17:09:48 +01:00
|
|
|
|
m_nPackFileOffset = nPackFileOffset;
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
|
|
|
|
m_nCompressedSize = nCompressedSize;
|
|
|
|
|
m_nUncompressedSize = nUncompressedSize;
|
2022-12-04 14:17:14 +01:00
|
|
|
|
|
|
|
|
|
m_bIsCompressed = (m_nCompressedSize != m_nUncompressedSize);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: builds a valid file name for the VPK
|
|
|
|
|
// Input : svLanguage -
|
|
|
|
|
// svTarget -
|
|
|
|
|
// &svLevel -
|
|
|
|
|
// nPatch -
|
|
|
|
|
// Output : a vpk file pair (block and directory file names)
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
VPKPair_t::VPKPair_t(string svLanguage, string svTarget, const string& svLevel, int nPatch)
|
|
|
|
|
{
|
|
|
|
|
if (std::find(DIR_LOCALE.begin(), DIR_LOCALE.end(), svLanguage) == DIR_LOCALE.end())
|
|
|
|
|
{
|
|
|
|
|
svLanguage = DIR_LOCALE[0];
|
|
|
|
|
}
|
|
|
|
|
if (std::find(DIR_TARGET.begin(), DIR_TARGET.end(), svTarget) == DIR_TARGET.end())
|
|
|
|
|
{
|
|
|
|
|
svTarget = DIR_TARGET[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_svPackName = fmt::format("{:s}_{:s}.bsp.pak000_{:03d}{:s}", svTarget, svLevel, nPatch, ".vpk");
|
|
|
|
|
m_svDirectoryName = fmt::format("{:s}{:s}_{:s}.bsp.pak000_{:s}", svLanguage, svTarget, svLevel, "dir.vpk");
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-02 02:00:35 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: 'VPKDir_t' file constructor
|
2022-11-16 00:54:51 +01:00
|
|
|
|
// Input : &svPath -
|
2022-06-02 02:00:35 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 17:09:48 +01:00
|
|
|
|
VPKDir_t::VPKDir_t(const string& svDirectoryPath)
|
|
|
|
|
{
|
|
|
|
|
Init(svDirectoryPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: 'VPKDir_t' file constructor with sanitation
|
|
|
|
|
// Input : svDirectoryName -
|
|
|
|
|
// bSanitizeName - retrieve the directory file name from block name
|
|
|
|
|
// Output : VPKDir_t
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
VPKDir_t::VPKDir_t(const string& svDirectoryPath, bool bSanitizeName)
|
|
|
|
|
{
|
|
|
|
|
if (!bSanitizeName)
|
|
|
|
|
{
|
|
|
|
|
Init(svDirectoryPath);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::smatch smRegexMatches;
|
|
|
|
|
std::regex_search(svDirectoryPath, smRegexMatches, BLOCK_REGEX);
|
|
|
|
|
|
|
|
|
|
if (smRegexMatches.empty())
|
|
|
|
|
{
|
|
|
|
|
Init(svDirectoryPath);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string svSanitizedName = svDirectoryPath;
|
|
|
|
|
StringReplace(svSanitizedName, smRegexMatches[0], "pak000_dir");
|
|
|
|
|
|
|
|
|
|
bool bHasLocale = false;
|
|
|
|
|
for (const string& svLocale : DIR_LOCALE)
|
|
|
|
|
{
|
|
|
|
|
if (svSanitizedName.find(svLocale) != string::npos)
|
|
|
|
|
{
|
|
|
|
|
bHasLocale = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!bHasLocale) // Only sanitize if no locale was provided.
|
|
|
|
|
{
|
|
|
|
|
string svPackDirPrefix;
|
|
|
|
|
svPackDirPrefix.append(DIR_LOCALE[0]);
|
|
|
|
|
|
|
|
|
|
for (const string& svTarget : DIR_TARGET)
|
|
|
|
|
{
|
|
|
|
|
if (svSanitizedName.find(svTarget) != string::npos)
|
|
|
|
|
{
|
|
|
|
|
svPackDirPrefix.append(svTarget);
|
|
|
|
|
StringReplace(svSanitizedName, svTarget, svPackDirPrefix);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Init(svSanitizedName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: 'VPKDir_t' file constructor
|
|
|
|
|
// Input : &svDirectoryPath -
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void VPKDir_t::Init(const string& svDirectoryPath)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
// Create stream to read from each pack file.
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileHandle_t hDirectory = FileSystem()->Open(svDirectoryPath.c_str(), "rb", "GAME");
|
2022-11-23 12:18:33 +01:00
|
|
|
|
if (!hDirectory)
|
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
Error(eDLL_T::FS, NO_ERROR, "%s - Unable to open '%s' (insufficient rights?)\n", __FUNCTION__, svDirectoryPath.c_str());
|
2022-11-23 12:18:33 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
FileSystem()->Read(&m_vHeader.m_nHeaderMarker, sizeof(uint32_t), hDirectory);
|
|
|
|
|
FileSystem()->Read(&m_vHeader.m_nMajorVersion, sizeof(uint16_t), hDirectory); //
|
|
|
|
|
FileSystem()->Read(&m_vHeader.m_nMinorVersion, sizeof(uint16_t), hDirectory); //
|
|
|
|
|
FileSystem()->Read(&m_vHeader.m_nDirectorySize, sizeof(uint32_t), hDirectory); //
|
|
|
|
|
FileSystem()->Read(&m_vHeader.m_nSignatureSize, sizeof(uint32_t), hDirectory); //
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
m_vEntryBlocks = g_pPackedStore->GetEntryBlocks(hDirectory);
|
2022-11-23 17:09:48 +01:00
|
|
|
|
m_svDirectoryPath = svDirectoryPath; // Set path to vpk directory file.
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-23 12:18:33 +01:00
|
|
|
|
m_nPackFileCount = 0;
|
2022-11-16 00:54:51 +01:00
|
|
|
|
for (VPKEntryBlock_t vEntry : m_vEntryBlocks)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-16 00:54:51 +01:00
|
|
|
|
if (vEntry.m_iPackFileIndex > m_nPackFileCount)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-16 00:54:51 +01:00
|
|
|
|
m_nPackFileCount = vEntry.m_iPackFileIndex;
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-16 00:54:51 +01:00
|
|
|
|
for (uint16_t i = 0; i < m_nPackFileCount + 1; i++)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
string svPackPath = GetPackFile(svDirectoryPath, i);
|
|
|
|
|
m_vPackFile.push_back(svPackPath);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: formats pack file path for specific directory file
|
|
|
|
|
// Input : &svDirectoryPath -
|
|
|
|
|
// iPackFileIndex -
|
|
|
|
|
// output : string
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
string VPKDir_t::GetPackFile(const string& svDirectoryPath, uint16_t iPackFileIndex) const
|
|
|
|
|
{
|
|
|
|
|
string svPackChunkName = StripLocalePrefix(svDirectoryPath);
|
|
|
|
|
string svPackChunkIndex = fmt::format("{:s}{:03d}", "pak000_", iPackFileIndex);
|
|
|
|
|
|
|
|
|
|
StringReplace(svPackChunkName, "pak000_dir", svPackChunkIndex);
|
|
|
|
|
return svPackChunkName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: strips locale prefix from file path
|
|
|
|
|
// Input : &svDirectoryPath -
|
|
|
|
|
// Output : directory filename without locale prefix
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
string VPKDir_t::StripLocalePrefix(const string& svDirectoryPath) const
|
|
|
|
|
{
|
|
|
|
|
string svFileName = GetFileName(svDirectoryPath);
|
|
|
|
|
|
|
|
|
|
for (const string& svLocale : DIR_LOCALE)
|
|
|
|
|
{
|
|
|
|
|
if (svFileName.find(svLocale) != string::npos)
|
|
|
|
|
{
|
|
|
|
|
StringReplace(svFileName, svLocale, "");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
2022-11-23 17:09:48 +01:00
|
|
|
|
return svFileName;
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 12:27:57 +01:00
|
|
|
|
// Purpose: writes the vpk directory header
|
2022-11-23 17:09:48 +01:00
|
|
|
|
// Input : hDirectoryFile -
|
2022-06-02 02:00:35 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 17:09:48 +01:00
|
|
|
|
void VPKDir_t::WriteHeader(FileHandle_t hDirectoryFile) const
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileSystem()->Write(&m_vHeader.m_nHeaderMarker, sizeof(uint32_t), hDirectoryFile);
|
|
|
|
|
FileSystem()->Write(&m_vHeader.m_nMajorVersion, sizeof(uint16_t), hDirectoryFile);
|
|
|
|
|
FileSystem()->Write(&m_vHeader.m_nMinorVersion, sizeof(uint16_t), hDirectoryFile);
|
|
|
|
|
FileSystem()->Write(&m_vHeader.m_nDirectorySize, sizeof(uint32_t), hDirectoryFile);
|
|
|
|
|
FileSystem()->Write(&m_vHeader.m_nSignatureSize, sizeof(uint32_t), hDirectoryFile);
|
2022-11-23 12:27:57 +01:00
|
|
|
|
}
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-23 12:27:57 +01:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: writes the directory tree size
|
2022-11-23 17:09:48 +01:00
|
|
|
|
// Input : hDirectoryFile -
|
2022-11-23 12:27:57 +01:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 17:09:48 +01:00
|
|
|
|
void VPKDir_t::WriteTreeSize(FileHandle_t hDirectoryFile) const
|
2022-11-23 12:27:57 +01:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileSystem()->Seek(hDirectoryFile, offsetof(VPKDir_t, m_vHeader.m_nDirectorySize), FileSystemSeek_t::FILESYSTEM_SEEK_HEAD);
|
|
|
|
|
FileSystem()->Write(&m_vHeader.m_nDirectorySize, sizeof(uint32_t), hDirectoryFile);
|
|
|
|
|
FileSystem()->Write(&PACKFILEINDEX_SEP, sizeof(uint32_t), hDirectoryFile);
|
2022-11-23 12:27:57 +01:00
|
|
|
|
}
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-23 12:27:57 +01:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: writes the vpk chunk descriptors
|
2022-11-23 17:09:48 +01:00
|
|
|
|
// Input : hDirectoryFile -
|
2022-11-23 12:27:57 +01:00
|
|
|
|
// &vMap -
|
|
|
|
|
// Output : number of descriptors written
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 17:09:48 +01:00
|
|
|
|
uint64_t VPKDir_t::WriteDescriptor(FileHandle_t hDirectoryFile, std::map<string, std::map<string, std::list<VPKEntryBlock_t>>>& vMap) const
|
2022-11-23 12:27:57 +01:00
|
|
|
|
{
|
|
|
|
|
uint64_t nDescriptors = NULL;
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
|
|
|
|
for (auto& iKeyValue : vMap)
|
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileSystem()->Write(iKeyValue.first.c_str(), (iKeyValue.first.length() + 1), hDirectoryFile);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
for (auto& jKeyValue : iKeyValue.second)
|
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileSystem()->Write(jKeyValue.first.c_str(), (jKeyValue.first.length() + 1), hDirectoryFile);
|
2022-06-05 17:28:39 +02:00
|
|
|
|
for (auto& vEntry : jKeyValue.second)
|
2022-06-02 02:00:35 +02:00
|
|
|
|
{
|
2022-11-23 12:18:33 +01:00
|
|
|
|
string pszEntryPath = GetFileName(vEntry.m_svEntryPath, true);
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileSystem()->Write(pszEntryPath.c_str(), (pszEntryPath.length() + 1), hDirectoryFile);
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileSystem()->Write(&vEntry.m_nFileCRC, sizeof(uint32_t), hDirectoryFile);
|
|
|
|
|
FileSystem()->Write(&vEntry.m_iPreloadSize, sizeof(uint16_t), hDirectoryFile);
|
|
|
|
|
FileSystem()->Write(&vEntry.m_iPackFileIndex, sizeof(uint16_t), hDirectoryFile);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-16 00:54:51 +01:00
|
|
|
|
for (size_t i = 0, nc = vEntry.m_vFragments.size(); i < nc; i++)
|
2022-10-09 12:08:54 +02:00
|
|
|
|
{
|
|
|
|
|
/*Write chunk descriptor*/
|
2022-11-16 00:54:51 +01:00
|
|
|
|
const VPKChunkDescriptor_t* pDescriptor = &vEntry.m_vFragments[i];
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileSystem()->Write(&pDescriptor->m_nLoadFlags, sizeof(uint32_t), hDirectoryFile);
|
|
|
|
|
FileSystem()->Write(&pDescriptor->m_nTextureFlags, sizeof(uint16_t), hDirectoryFile);
|
|
|
|
|
FileSystem()->Write(&pDescriptor->m_nPackFileOffset, sizeof(uint64_t), hDirectoryFile);
|
|
|
|
|
FileSystem()->Write(&pDescriptor->m_nCompressedSize, sizeof(uint64_t), hDirectoryFile);
|
|
|
|
|
FileSystem()->Write(&pDescriptor->m_nUncompressedSize, sizeof(uint64_t), hDirectoryFile);
|
2022-10-09 12:08:54 +02:00
|
|
|
|
|
|
|
|
|
if (i != (nc - 1))
|
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileSystem()->Write(&PACKFILEINDEX_SEP, sizeof(uint16_t), hDirectoryFile);
|
2022-10-09 12:08:54 +02:00
|
|
|
|
}
|
2022-11-16 00:54:51 +01:00
|
|
|
|
else // Mark end of entry.
|
2022-10-09 12:08:54 +02:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileSystem()->Write(&PACKFILEINDEX_END, sizeof(uint16_t), hDirectoryFile);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
2022-10-09 12:08:54 +02:00
|
|
|
|
nDescriptors++;
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileSystem()->Write(&PACKFILEINDEX_SEP, sizeof(uint8_t), hDirectoryFile);
|
2022-11-23 12:27:57 +01:00
|
|
|
|
}
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileSystem()->Write(&PACKFILEINDEX_SEP, sizeof(uint8_t), hDirectoryFile);
|
2022-11-23 12:27:57 +01:00
|
|
|
|
}
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileSystem()->Write(&PACKFILEINDEX_SEP, sizeof(uint8_t), hDirectoryFile);
|
2022-11-23 12:27:57 +01:00
|
|
|
|
|
|
|
|
|
return nDescriptors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: builds the vpk directory tree
|
|
|
|
|
// Input : &vEntryBlocks -
|
|
|
|
|
// &vMap -
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
void VPKDir_t::BuildDirectoryTree(const vector<VPKEntryBlock_t>& vEntryBlocks, std::map<string, std::map<string, std::list<VPKEntryBlock_t>>>& vMap) const
|
|
|
|
|
{
|
|
|
|
|
for (const VPKEntryBlock_t& vBlock : vEntryBlocks)
|
|
|
|
|
{
|
|
|
|
|
string svExtension = GetExtension(vBlock.m_svEntryPath);
|
|
|
|
|
string svFilePath = RemoveFileName(vBlock.m_svEntryPath);
|
|
|
|
|
|
|
|
|
|
if (svFilePath.empty())
|
|
|
|
|
{
|
|
|
|
|
svFilePath = ' '; // Has to be padded with a space character if empty [root].
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
2022-11-23 12:27:57 +01:00
|
|
|
|
if (!vMap.count(svExtension))
|
|
|
|
|
{
|
|
|
|
|
vMap.insert({ svExtension, std::map<string, std::list<VPKEntryBlock_t>>() });
|
|
|
|
|
}
|
|
|
|
|
if (!vMap[svExtension].count(svFilePath))
|
|
|
|
|
{
|
|
|
|
|
vMap[svExtension].insert({ svFilePath, std::list<VPKEntryBlock_t>() });
|
|
|
|
|
}
|
|
|
|
|
vMap[svExtension][svFilePath].push_back(vBlock);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
2022-11-23 12:27:57 +01:00
|
|
|
|
}
|
2022-11-23 12:18:33 +01:00
|
|
|
|
|
2022-11-23 12:27:57 +01:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Purpose: builds the vpk directory file
|
2022-11-23 17:09:48 +01:00
|
|
|
|
// Input : &svDirectoryPath -
|
2022-11-23 12:27:57 +01:00
|
|
|
|
// &vEntryBlocks -
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-11-23 17:09:48 +01:00
|
|
|
|
void VPKDir_t::BuildDirectoryFile(const string& svDirectoryPath, const vector<VPKEntryBlock_t>& vEntryBlocks)
|
2022-11-23 12:27:57 +01:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileHandle_t hDirectoryFile = FileSystem()->Open(svDirectoryPath.c_str(), "wb", "GAME");
|
|
|
|
|
if (!hDirectoryFile)
|
2022-11-23 12:27:57 +01:00
|
|
|
|
{
|
2022-11-23 17:09:48 +01:00
|
|
|
|
Error(eDLL_T::FS, NO_ERROR, "%s - Unable to write to '%s' (read-only?)\n", __FUNCTION__, svDirectoryPath.c_str());
|
2022-11-23 12:27:57 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2022-06-02 02:00:35 +02:00
|
|
|
|
|
2022-11-23 12:27:57 +01:00
|
|
|
|
auto vMap = std::map<string, std::map<string, std::list<VPKEntryBlock_t>>>();
|
|
|
|
|
BuildDirectoryTree(vEntryBlocks, vMap);
|
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
WriteHeader(hDirectoryFile);
|
|
|
|
|
uint64_t nDescriptors = WriteDescriptor(hDirectoryFile, vMap);
|
2022-06-05 17:28:39 +02:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
m_vHeader.m_nDirectorySize = static_cast<uint32_t>(FileSystem()->Tell(hDirectoryFile) - sizeof(VPKDirHeader_t));
|
|
|
|
|
WriteTreeSize(hDirectoryFile);
|
2022-11-23 12:27:57 +01:00
|
|
|
|
|
2022-11-23 17:09:48 +01:00
|
|
|
|
FileSystem()->Close(hDirectoryFile);
|
2022-11-23 12:27:57 +01:00
|
|
|
|
DevMsg(eDLL_T::FS, "*** Build directory totaling '%zu' bytes with '%zu' entries and '%zu' descriptors\n",
|
2022-08-08 17:51:09 +02:00
|
|
|
|
size_t(sizeof(VPKDirHeader_t) + m_vHeader.m_nDirectorySize), vEntryBlocks.size(), nDescriptors);
|
2022-06-02 02:00:35 +02:00
|
|
|
|
}
|
2022-11-16 00:54:51 +01:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Singleton
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-06-02 01:59:03 +02:00
|
|
|
|
CPackedStore* g_pPackedStore = new CPackedStore();
|