summaryrefslogtreecommitdiff
path: root/engine/DownloadListGenerator.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/DownloadListGenerator.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'engine/DownloadListGenerator.cpp')
-rw-r--r--engine/DownloadListGenerator.cpp453
1 files changed, 453 insertions, 0 deletions
diff --git a/engine/DownloadListGenerator.cpp b/engine/DownloadListGenerator.cpp
new file mode 100644
index 0000000..b5bc317
--- /dev/null
+++ b/engine/DownloadListGenerator.cpp
@@ -0,0 +1,453 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "mathlib/vector.h"
+#include "DownloadListGenerator.h"
+#include "filesystem.h"
+#include "filesystem_engine.h"
+#include "sys.h"
+#include "cmd.h"
+#include "common.h"
+#include "quakedef.h"
+#include "vengineserver_impl.h"
+#include "tier1/strtools.h"
+#include "tier0/icommandline.h"
+#include "checksum_engine.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <tier0/dbg.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+CDownloadListGenerator g_DownloadListGenerator;
+CDownloadListGenerator &DownloadListGenerator()
+{
+ return g_DownloadListGenerator;
+}
+
+ConVar sv_logdownloadlist( "sv_logdownloadlist", IsX360() ? "0" : "1" );
+
+extern int GetSvPureMode();
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CDownloadListGenerator::CDownloadListGenerator()
+ : m_AlreadyWrittenFileNames( 0, 0, true )
+{
+ m_hReslistFile = FILESYSTEM_INVALID_HANDLE;
+ m_pStringTable = NULL;
+ m_mapName[0] = 0;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CDownloadListGenerator::SetStringTable( INetworkStringTable *pStringTable )
+{
+ if ( IsX360() )
+ {
+ // not supporting
+ return;
+ }
+
+ m_pStringTable = pStringTable;
+
+ // reset the duplication list
+ m_AlreadyWrittenFileNames.RemoveAll();
+
+ // add in the bsp file to the list, and its node graph and nav mesh
+ char path[_MAX_PATH];
+ Q_snprintf(path, sizeof(path), "maps\\%s.bsp", m_mapName);
+ OnResourcePrecached(path);
+
+ bool useNodeGraph = true;
+ KeyValues *modinfo = new KeyValues("ModInfo");
+ if ( modinfo->LoadFromFile( g_pFileSystem, "gameinfo.txt" ) )
+ {
+ useNodeGraph = modinfo->GetInt( "nodegraph", 1 ) != 0;
+ }
+ modinfo->deleteThis();
+
+ if ( useNodeGraph )
+ {
+ Q_snprintf(path, sizeof(path), "maps\\graphs\\%s.ain", m_mapName);
+ OnResourcePrecached(path);
+ }
+
+ Q_snprintf(path, sizeof(path), "maps\\%s.nav", m_mapName);
+ OnResourcePrecached(path);
+
+ char resfilename[MAX_OSPATH];
+ KeyValues *resfilekeys = new KeyValues( "resourefiles" );
+
+ Q_snprintf( resfilename, sizeof( resfilename), "maps/%s.res", m_mapName );
+
+ if ( resfilekeys->LoadFromFile( g_pFileSystem, resfilename, "GAME" ) )
+ {
+ KeyValues *entry = resfilekeys->GetFirstSubKey();
+ while ( entry )
+ {
+ OnResourcePrecached( entry->GetName() );
+ entry = entry->GetNextKey();
+ }
+ }
+ resfilekeys->deleteThis();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: call to mark level load/end
+//-----------------------------------------------------------------------------
+void CDownloadListGenerator::OnLevelLoadStart(const char *levelName)
+{
+ if ( IsX360() )
+ {
+ // not supporting
+ return;
+ }
+
+ // close the previous level reslist, if any
+ if (m_hReslistFile != FILESYSTEM_INVALID_HANDLE)
+ {
+ g_pFileSystem->Close(m_hReslistFile);
+ m_hReslistFile = FILESYSTEM_INVALID_HANDLE;
+ }
+
+ // reset the duplication list
+ m_AlreadyWrittenFileNames.RemoveAll();
+
+ if ( sv_logdownloadlist.GetBool() )
+ {
+ // open the new level reslist
+ char path[MAX_OSPATH];
+ g_pFileSystem->CreateDirHierarchy( "DownloadLists", "MOD" );
+ Q_snprintf(path, sizeof(path), "DownloadLists/%s.lst", levelName);
+ m_hReslistFile = g_pFileSystem->Open(path, "wt", "GAME");
+ }
+
+ // add a slash to the end of com_gamedir, so we can only deal with files for this mod
+ Q_snprintf( m_gameDir, sizeof(m_gameDir), "%s/", com_gamedir );
+ Q_FixSlashes( m_gameDir );
+
+ // save off the map name
+ Q_snprintf( m_mapName, sizeof( m_mapName ), "%s", levelName );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: call to mark level load/end
+//-----------------------------------------------------------------------------
+void CDownloadListGenerator::OnLevelLoadEnd()
+{
+ if ( IsX360() )
+ {
+ // not supporting
+ return;
+ }
+
+ if ( m_hReslistFile != FILESYSTEM_INVALID_HANDLE )
+ {
+ g_pFileSystem->Close(m_hReslistFile);
+ m_hReslistFile = FILESYSTEM_INVALID_HANDLE;
+ }
+ m_pStringTable = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: logs and handles mdl files being precaches
+//-----------------------------------------------------------------------------
+void CDownloadListGenerator::OnModelPrecached(const char *relativePathFileName)
+{
+ if ( IsX360() )
+ {
+ // not supporting
+ return;
+ }
+
+ if (Q_strstr(relativePathFileName, ".vmt"))
+ {
+ // it's a materials file, make sure that it starts in the materials directory, and we get the .vtf
+ char file[_MAX_PATH];
+
+ if (!Q_strnicmp(relativePathFileName, "materials", strlen("materials")))
+ {
+ Q_strncpy(file, relativePathFileName, sizeof(file));
+ }
+ else
+ {
+ // prepend the materials directory
+ Q_snprintf(file, sizeof(file), "materials\\%s", relativePathFileName);
+ }
+
+ OnResourcePrecached(file);
+
+ // get the matching vtf file
+ char *ext = Q_strstr(file, ".vmt");
+ if (ext)
+ {
+ Q_strncpy(ext, ".vtf", 5);
+ OnResourcePrecached(file);
+ }
+ }
+ else
+ {
+ OnResourcePrecached(relativePathFileName);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: logs sound file access
+//-----------------------------------------------------------------------------
+void CDownloadListGenerator::OnSoundPrecached(const char *relativePathFileName)
+{
+ if ( IsX360() )
+ {
+ // not supporting
+ return;
+ }
+
+ // skip any special characters
+ if (!V_isalnum(relativePathFileName[0]))
+ {
+ ++relativePathFileName;
+ }
+
+ // prepend the sound/ directory if necessary
+ char file[_MAX_PATH];
+ if (!Q_strnicmp(relativePathFileName, "sound", strlen("sound")))
+ {
+ Q_strncpy(file, relativePathFileName, sizeof(file));
+ }
+ else
+ {
+ // prepend the materials directory
+ Q_snprintf(file, sizeof(file), "sound\\%s", relativePathFileName);
+ }
+
+ OnResourcePrecached(file);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: logs the precache as a file access
+//-----------------------------------------------------------------------------
+void CDownloadListGenerator::OnResourcePrecached(const char *relativePathFileName)
+{
+ if ( IsX360() )
+ {
+ // not supporting
+ return;
+ }
+
+ // ignore empty string
+ if (relativePathFileName[0] == 0)
+ {
+ return;
+ }
+
+ // ignore files that start with '*' since they signify special models
+ if (relativePathFileName[0] == '*')
+ {
+ return;
+ }
+
+ char fullPath[_MAX_PATH];
+ if (g_pFileSystem->GetLocalPath(relativePathFileName, fullPath, sizeof(fullPath)))
+ {
+ OnResourcePrecachedFullPath( fullPath, relativePathFileName);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: marks a precached file as needing a specific CRC on the client
+//-----------------------------------------------------------------------------
+void CDownloadListGenerator::ForceSimpleMaterial( const char *relativePathFileName )
+{
+ if ( IsX360() )
+ {
+ // not supporting
+ return;
+ }
+
+ if ( !m_pStringTable )
+ return;
+
+ if ( !Q_stristr(relativePathFileName, ".vmt") && !Q_stristr(relativePathFileName, ".vtf"))
+ {
+ DevMsg( "Tried to enforce simple material on %s\n", relativePathFileName );
+ return;
+ }
+
+ // it's a materials file, make sure that it starts in the materials directory, and we get the .vtf
+ char szFixedFilename[_MAX_PATH];
+ if (!Q_strnicmp(relativePathFileName, "materials", strlen("materials")))
+ {
+ V_strcpy_safe( szFixedFilename, relativePathFileName );
+ }
+ else
+ {
+ // prepend the materials directory
+ V_sprintf_safe( szFixedFilename, "materials\\%s", relativePathFileName );
+ }
+ V_FixSlashes( szFixedFilename );
+ if ( !g_pFullFileSystem->FileExists( szFixedFilename, "game" ) )
+ {
+ DevMsg( "Cannot force simple material on %s; file not found\n", szFixedFilename );
+ return;
+ }
+
+ ExactFileUserData userData;
+ userData.consistencyType = CONSISTENCY_SIMPLE_MATERIAL;
+ userData.crc = 0;
+
+ // Only set consistency data if pure, otherwise just create entry in download list
+ if ( GetSvPureMode() < 0 )
+ {
+ m_pStringTable->AddString( true, szFixedFilename );
+ }
+ else
+ {
+ int index = m_pStringTable->FindStringIndex( szFixedFilename );
+ if ( index != INVALID_STRING_INDEX )
+ {
+ m_pStringTable->SetStringUserData( index, sizeof( ExactFileUserData ), &userData );
+ }
+ else
+ {
+ m_pStringTable->AddString( true, szFixedFilename, sizeof( ExactFileUserData ), &userData );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: marks a precached model as having a maximum size on the client
+//-----------------------------------------------------------------------------
+void CDownloadListGenerator::ForceModelBounds( const char *relativePathFileName, const Vector &mins, const Vector &maxs )
+{
+ if ( IsX360() )
+ {
+ // not supporting
+ return;
+ }
+
+ if ( !m_pStringTable )
+ return;
+
+ if ( !relativePathFileName )
+ relativePathFileName = "";
+
+ if (!Q_stristr(relativePathFileName, ".mdl"))
+ {
+ DevMsg( "Warning - trying to enforce model bounds on %s\n", relativePathFileName );
+ return;
+ }
+
+ char relativeFileName[_MAX_PATH];
+ Q_strncpy( relativeFileName, relativePathFileName, sizeof( relativeFileName ) );
+ Q_FixSlashes( relativeFileName );
+
+ // Only set consistency data if pure, otherwise just create entry in download list
+ if ( GetSvPureMode() < 0 )
+ {
+ m_pStringTable->AddString( true, relativePathFileName );
+ }
+ else
+ {
+ ModelBoundsUserData userData;
+ userData.consistencyType = CONSISTENCY_BOUNDS;
+ userData.mins = mins;
+ userData.maxs = maxs;
+
+ int index = m_pStringTable->FindStringIndex( relativeFileName );
+ if ( index != INVALID_STRING_INDEX )
+ {
+ m_pStringTable->SetStringUserData( index, sizeof( ModelBoundsUserData ), &userData );
+ }
+ else
+ {
+ m_pStringTable->AddString( true, relativeFileName, sizeof( ModelBoundsUserData ), &userData );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Logs out file access to a file
+//-----------------------------------------------------------------------------
+void CDownloadListGenerator::OnResourcePrecachedFullPath( char *fullPathFileName, const char *relativeFileName )
+{
+ if ( IsX360() )
+ {
+ // not supporting
+ return;
+ }
+
+ Q_FixSlashes( fullPathFileName );
+
+ if ( !g_pFileSystem->FileExists( fullPathFileName ) )
+ {
+ return; // don't allow files for download the server doesn't have
+ }
+
+ if ( Q_strncasecmp( m_gameDir, fullPathFileName, Q_strlen( m_gameDir ) ) )
+ {
+ return; // the game dir must be part of the full name
+ }
+
+ // make sure the filename hasn't already been written
+ UtlSymId_t filename = m_AlreadyWrittenFileNames.Find( fullPathFileName );
+ if ( filename != UTL_INVAL_SYMBOL )
+ {
+ return;
+ }
+
+ // record in list, so we don't write it again
+ m_AlreadyWrittenFileNames.AddString( fullPathFileName );
+
+ // add extras for mdl's
+ if (Q_strstr(relativeFileName, ".mdl"))
+ {
+ // it's a model, get it's other files as well
+ char file[_MAX_PATH];
+ Q_strncpy(file, relativeFileName, sizeof(file) - 10);
+ char *ext = Q_strstr(file, ".mdl");
+
+ Q_strncpy(ext, ".vvd", 10);
+ OnResourcePrecached(file);
+
+ Q_strncpy(ext, ".ani", 10);
+ OnResourcePrecached(file);
+
+ Q_strncpy(ext, ".dx80.vtx", 10);
+ OnResourcePrecached(file);
+
+ Q_strncpy(ext, ".dx90.vtx", 10);
+ OnResourcePrecached(file);
+
+ Q_strncpy(ext, ".sw.vtx", 10);
+ OnResourcePrecached(file);
+
+ Q_strncpy(ext, ".phy", 10);
+ OnResourcePrecached(file);
+
+ Q_strncpy(ext, ".jpg", 10);
+ OnResourcePrecached(file);
+ }
+
+ FileHandle_t handle = m_hReslistFile;
+ if ( handle != FILESYSTEM_INVALID_HANDLE )
+ {
+ g_pFileSystem->Write("\"", 1, handle);
+ g_pFileSystem->Write( relativeFileName, Q_strlen(relativeFileName), handle );
+ g_pFileSystem->Write("\"\n", 2, handle);
+ }
+ if ( m_pStringTable )
+ {
+ m_pStringTable->AddString( true, relativeFileName );
+ }
+}
+
+
+