Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1186 lines
25 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "host.h"
  9. #include <ctype.h>
  10. #include "draw.h"
  11. #include "zone.h"
  12. #include "sys.h"
  13. #include <edict.h>
  14. #include <coordsize.h>
  15. #include <characterset.h>
  16. #include <bitbuf.h>
  17. #include "common.h"
  18. #include "traceinit.h"
  19. #include <filesystem.h>
  20. #include "filesystem_engine.h"
  21. #include <convar.h>
  22. #include "gl_matsysiface.h"
  23. #include "filesystem_init.h"
  24. #include <materialsystem/imaterialsystemhardwareconfig.h>
  25. #include <tier0/icommandline.h>
  26. #include <vstdlib/random.h>
  27. #include "sys_dll.h"
  28. #include "datacache/idatacache.h"
  29. #include "tier1/keyvalues.h"
  30. #ifndef DEDICATED
  31. #include "vgui_baseui_interface.h"
  32. #include "vgui/ISystem.h"
  33. #include "vgui_controls/Controls.h"
  34. #endif
  35. #include "matchmaking/imatchframework.h"
  36. #include "tier2/tier2.h"
  37. #include "cl_steamauth.h"
  38. #ifdef _X360
  39. #include "xbox/xbox_launch.h"
  40. #elif defined(_PS3)
  41. #include "tls_ps3.h"
  42. #include "ps3_pathinfo.h"
  43. #endif
  44. // memdbgon must be the last include file in a .cpp file!!!
  45. #include "tier0/memdbgon.h"
  46. // Things in other C files.
  47. #define MAX_LOG_DIRECTORIES 10000
  48. bool com_ignorecolons = false;
  49. // wordbreak parsing set
  50. static characterset_t g_BreakSet, g_BreakSetIncludingColons;
  51. #define COM_TOKEN_MAX_LENGTH 1024
  52. char com_token[COM_TOKEN_MAX_LENGTH];
  53. unsigned char com_character;
  54. /*
  55. All of Quake's data access is through a hierarchical file system, but the contents of
  56. the file system can be transparently merged from several sources.
  57. The "base directory" is the path to the directory holding the quake.exe and all
  58. game directories. The sys_* files pass this to host_init in engineparms->basedir.
  59. This can be overridden with the "-basedir" command line parm to allow code
  60. debugging in a different directory. The base directory is
  61. only used during filesystem initialization.
  62. The "game directory" is the first tree on the search path and directory
  63. that all generated files (savegames, screenshots, demos, config files) will
  64. be saved to. This can be overridden with the "-game" command line parameter.
  65. The game directory can never be changed while quake is executing.
  66. This is a precacution against having a malicious server instruct clients
  67. to write files over areas they shouldn't.
  68. The "cache directory" is only used during development to save network bandwidth,
  69. especially over ISDN / T1 lines. If there is a cache directory
  70. specified, when a file is found by the normal search path, it will be mirrored
  71. into the cache directory, then opened there.
  72. FIXME:
  73. The file "parms.txt" will be read out of the game directory and appended to the
  74. current command line arguments to allow different games to initialize startup
  75. parms differently. This could be used to add a "-sspeed 22050" for the high
  76. quality sound edition. Because they are added at the end, they will not override
  77. an explicit setting on the original command line.
  78. */
  79. /*
  80. ==============================
  81. COM_ExplainDisconnection
  82. ==============================
  83. */
  84. void COM_ExplainDisconnection( bool bPrint, const char *fmt, ... )
  85. {
  86. va_list argptr;
  87. char szString[1024];
  88. va_start ( argptr, fmt );
  89. Q_vsnprintf( szString, sizeof( szString ), fmt,argptr );
  90. va_end ( argptr );
  91. if ( !IsX360() )
  92. {
  93. Q_strncpy( gszDisconnectReason, szString, 256 );
  94. gfExtendedError = true;
  95. }
  96. if ( bPrint )
  97. {
  98. ConMsg( "%s\n", gszDisconnectReason );
  99. }
  100. char const *szNotificationReason = szString;
  101. if ( char const *szActualDisconnectReason = StringAfterPrefix( szString, "Disconnect: " ) )
  102. szNotificationReason = szActualDisconnectReason;
  103. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues(
  104. "OnEngineDisconnectReason", "reason", szNotificationReason ) );
  105. }
  106. /*
  107. ==============================
  108. COM_ExtendedExplainDisconnection
  109. ==============================
  110. */
  111. void COM_ExtendedExplainDisconnection( bool bPrint, const char *fmt, ... )
  112. {
  113. if ( !IsX360() )
  114. {
  115. va_list argptr;
  116. char string[1024];
  117. va_start (argptr, fmt);
  118. Q_vsnprintf(string, sizeof( string ), fmt,argptr);
  119. va_end (argptr);
  120. Q_strncpy( gszExtendedDisconnectReason, string, 256 );
  121. }
  122. if ( bPrint )
  123. {
  124. ConMsg( "%s\n", gszExtendedDisconnectReason );
  125. }
  126. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues(
  127. "OnEngineDisconnectReason", "reason", "" ) );
  128. }
  129. /*
  130. ==============
  131. COM_ReadChar
  132. Reads a single code point, turning unsupported
  133. UTF-8 characters into question marks
  134. ==============
  135. */
  136. const char *COM_ReadChar(const char *data)
  137. {
  138. if ( !data || !*data )
  139. return NULL;
  140. com_character = *data++;
  141. return data;
  142. }
  143. /*
  144. ==============
  145. COM_Parse
  146. Parse a token out of a string
  147. ==============
  148. */
  149. const char *COM_Parse (const char *data)
  150. {
  151. unsigned char c;
  152. int len;
  153. characterset_t *breaks;
  154. breaks = &g_BreakSetIncludingColons;
  155. if ( com_ignorecolons )
  156. breaks = &g_BreakSet;
  157. len = 0;
  158. com_token[0] = 0;
  159. if (!data)
  160. return NULL;
  161. // skip whitespace
  162. skipwhite:
  163. while ( (c = *data) <= ' ')
  164. {
  165. if (c == 0)
  166. return NULL; // end of file;
  167. data++;
  168. }
  169. // skip // comments
  170. if (c=='/' && data[1] == '/')
  171. {
  172. while (*data && *data != '\n')
  173. data++;
  174. goto skipwhite;
  175. }
  176. // handle quoted strings specially
  177. if (c == '\"')
  178. {
  179. data++;
  180. while (1)
  181. {
  182. c = *data++;
  183. if (c=='\"' || !c)
  184. {
  185. com_token[len] = 0;
  186. return data;
  187. }
  188. com_token[len] = c;
  189. len++;
  190. }
  191. }
  192. // parse single characters
  193. if ( IN_CHARACTERSET( *breaks, c ) )
  194. {
  195. com_token[len] = c;
  196. len++;
  197. com_token[len] = 0;
  198. return data+1;
  199. }
  200. // parse a regular word
  201. do
  202. {
  203. com_token[len] = c;
  204. data++;
  205. len++;
  206. c = *data;
  207. if ( IN_CHARACTERSET( *breaks, c ) )
  208. break;
  209. } while (c>32);
  210. com_token[len] = 0;
  211. return data;
  212. }
  213. /*
  214. ==============
  215. COM_AddNoise
  216. Changes n random bits in a data block
  217. ==============
  218. */
  219. void COM_AddNoise( unsigned char *data, int length, int number )
  220. {
  221. for ( int i = 0; i < number; i++ )
  222. {
  223. int randomByte = RandomInt( 0, length-1 );
  224. int randomBit = RandomInt( 0, 7 );
  225. // get original data
  226. unsigned char dataByte = data[randomByte];
  227. // flip bit
  228. if ( dataByte & randomBit )
  229. {
  230. dataByte &= ~randomBit;
  231. }
  232. else
  233. {
  234. dataByte |= randomBit;
  235. }
  236. // write back
  237. data[randomByte] = dataByte;
  238. }
  239. }
  240. /*
  241. ==============
  242. COM_Parse_Line
  243. Parse a line out of a string
  244. ==============
  245. */
  246. #pragma warning( disable : 4706 )
  247. const char *COM_ParseLine (const char *data)
  248. {
  249. int len = 0;
  250. while( data = COM_ReadChar( data ) )
  251. {
  252. if ( com_character < ' ' && com_character != '\t' )
  253. break;
  254. com_token[len++] = com_character;
  255. if ( len == COM_TOKEN_MAX_LENGTH-1 )
  256. break;
  257. }
  258. com_token[len] = 0;
  259. if ( len == COM_TOKEN_MAX_LENGTH-1 )
  260. {
  261. // if we stopped the line because it was too long, then
  262. // skip to the actual line end
  263. while( data = COM_ReadChar( data ) )
  264. {
  265. if ( com_character < ' ' && com_character != '\t' )
  266. break;
  267. }
  268. }
  269. // now eat control chars at the end of the line
  270. const char *nextChar;
  271. while( nextChar = COM_ReadChar( data ) )
  272. {
  273. if ( com_character >= ' ' )
  274. return data;
  275. else
  276. data = nextChar;
  277. }
  278. return NULL;
  279. }
  280. #pragma warning( default : 4706 )
  281. /*
  282. ==============
  283. COM_TokenWaiting
  284. Returns 1 if additional data is waiting to be processed on this line
  285. ==============
  286. */
  287. int COM_TokenWaiting( const char *buffer )
  288. {
  289. const char *p;
  290. p = buffer;
  291. while ( *p && *p!='\n')
  292. {
  293. if ( !V_isspace( *p ) || V_isalnum( *p ) )
  294. return 1;
  295. p++;
  296. }
  297. return 0;
  298. }
  299. /*
  300. ============
  301. va
  302. does a varargs printf into a temp buffer, so I don't need to have
  303. varargs versions of all text functions.
  304. ============
  305. */
  306. char *va( const char *format, ... )
  307. {
  308. va_list argptr;
  309. static char string[8][512];
  310. static int curstring = 0;
  311. curstring = ( curstring + 1 ) % 8;
  312. va_start (argptr, format);
  313. Q_vsnprintf( string[curstring], sizeof( string[curstring] ), format, argptr );
  314. va_end (argptr);
  315. return string[curstring];
  316. }
  317. /*
  318. ============
  319. vstr
  320. prints a vector into a temporary string
  321. bufffer.
  322. ============
  323. */
  324. const char *vstr(Vector& v)
  325. {
  326. static int idx = 0;
  327. static char string[16][1024];
  328. idx++;
  329. idx &= 15;
  330. Q_snprintf(string[idx], sizeof( string[idx] ), "%.2f %.2f %.2f", v[0], v[1], v[2]);
  331. return string[idx];
  332. }
  333. char com_basedir[MAX_OSPATH];
  334. char com_gamedir[MAX_OSPATH];
  335. /*
  336. ==================
  337. CL_CheckGameDirectory
  338. Client side game directory change.
  339. ==================
  340. */
  341. bool COM_CheckGameDirectory( const char *gamedir )
  342. {
  343. // Switch game directories if needed, or abort if it's not good.
  344. char szGD[ MAX_OSPATH ];
  345. if ( !gamedir || !gamedir[0] )
  346. {
  347. ConMsg( "Server didn't specify a gamedir, assuming no change\n" );
  348. return true;
  349. }
  350. // Rip out the current gamedir.
  351. Q_FileBase( com_gamedir, szGD, sizeof( szGD ) );
  352. if ( Q_stricmp( szGD, gamedir ) )
  353. {
  354. // We know szGD and gamedir aren't the same, but as long as one is 'portal2' and the other is 'portal_sixense2', go ahead and connect
  355. bool sixense_vs_not_sixense = false;
  356. if( (!Q_stricmp( szGD, "portal2" ) || !Q_stricmp( szGD, "portal2_sixense" )) && (!Q_stricmp( gamedir, "portal2" ) || !Q_stricmp( gamedir, "portal2_sixense" )) )
  357. {
  358. sixense_vs_not_sixense = true;
  359. }
  360. if( !sixense_vs_not_sixense )
  361. {
  362. // Changing game directories without restarting is not permitted any more
  363. ConMsg( "COM_CheckGameDirectory: game directories don't match (%s / %s)\n", szGD, gamedir );
  364. return false;
  365. }
  366. }
  367. return true;
  368. }
  369. //-----------------------------------------------------------------------------
  370. // Purpose: Finds the file in the search path.
  371. // Input : *filename -
  372. // *file -
  373. // Output : int
  374. //-----------------------------------------------------------------------------
  375. int COM_FindFile( const char *filename, FileHandle_t *file )
  376. {
  377. Assert( file );
  378. int filesize = -1;
  379. *file = g_pFileSystem->Open( filename, "rb" );
  380. if ( *file )
  381. {
  382. filesize = g_pFileSystem->Size( *file );
  383. }
  384. return filesize;
  385. }
  386. //-----------------------------------------------------------------------------
  387. // Purpose:
  388. // Input : *filename -
  389. // *file -
  390. // Output : int
  391. //-----------------------------------------------------------------------------
  392. int COM_OpenFile( const char *filename, FileHandle_t *file )
  393. {
  394. return COM_FindFile( (char *)filename, file );
  395. }
  396. /*
  397. ============
  398. COM_WriteFile
  399. The filename will be prefixed by the current game directory
  400. ============
  401. */
  402. void COM_WriteFile (const char *filename, void *data, int len)
  403. {
  404. FileHandle_t handle;
  405. int nameLen = strlen( filename ) + 2;
  406. char *pName = ( char * )stackalloc( nameLen );
  407. Q_snprintf( pName, nameLen, "%s", filename);
  408. Q_FixSlashes( pName );
  409. COM_CreatePath( pName );
  410. handle = g_pFileSystem->Open( pName, "wb" );
  411. if ( !handle )
  412. {
  413. Warning ("COM_WriteFile: failed on %s\n", pName);
  414. return;
  415. }
  416. g_pFileSystem->Write( data, len, handle );
  417. g_pFileSystem->Close( handle );
  418. }
  419. /*
  420. ============
  421. COM_CreatePath
  422. Only used for CopyFile
  423. ============
  424. */
  425. void COM_CreatePath (const char *path)
  426. {
  427. char temppath[512];
  428. Q_strncpy( temppath, path, sizeof(temppath) );
  429. for (char *ofs = temppath+1 ; *ofs ; ofs++)
  430. {
  431. if (*ofs == '/' || *ofs == '\\')
  432. { // create the directory
  433. char old = *ofs;
  434. *ofs = 0;
  435. Sys_mkdir (temppath);
  436. *ofs = old;
  437. }
  438. }
  439. }
  440. /*
  441. ===========
  442. COM_CopyFile
  443. Copies a file over from the net to the local cache, creating any directories
  444. needed. This is for the convenience of developers using ISDN from home.
  445. ===========
  446. */
  447. bool COM_CopyFile ( const char *netpath, const char *cachepath)
  448. {
  449. if ( IsX360() )
  450. return false;
  451. int remaining, count;
  452. char buf[4096];
  453. FileHandle_t in, out;
  454. in = g_pFileSystem->Open( netpath, "rb" );
  455. Assert( in );
  456. if ( in == FILESYSTEM_INVALID_HANDLE )
  457. return false;
  458. // create directories up to the cache file
  459. COM_CreatePath (cachepath);
  460. out = g_pFileSystem->Open( cachepath, "wb", "MOD" );
  461. Assert( out );
  462. if ( out == FILESYSTEM_INVALID_HANDLE )
  463. {
  464. g_pFileSystem->Close( in );
  465. return false;
  466. }
  467. remaining = g_pFileSystem->Size( in );
  468. while ( remaining > 0 )
  469. {
  470. if (remaining < sizeof(buf))
  471. {
  472. count = remaining;
  473. }
  474. else
  475. {
  476. count = sizeof(buf);
  477. }
  478. g_pFileSystem->Read( buf, count, in );
  479. g_pFileSystem->Write( buf, count, out );
  480. remaining -= count;
  481. }
  482. g_pFileSystem->Close( in );
  483. g_pFileSystem->Close( out );
  484. return true;
  485. }
  486. /*
  487. ===========
  488. COM_ExpandFilename
  489. Finds the file in the search path, copies over the name with the full path name.
  490. This doesn't search in the pak file.
  491. ===========
  492. */
  493. int COM_ExpandFilename( char *filename, int maxlength )
  494. {
  495. char expanded[MAX_OSPATH];
  496. if ( g_pFileSystem->GetLocalPath( filename, expanded, sizeof(expanded) ) != NULL )
  497. {
  498. Q_strncpy( filename, expanded, maxlength );
  499. return 1;
  500. }
  501. if ( filename && filename[0] != '*' )
  502. {
  503. Warning ("COM_ExpandFilename: can't find %s\n", filename);
  504. }
  505. return 0;
  506. }
  507. /*
  508. ===========
  509. COM_FileSize
  510. Returns the size of the file only.
  511. ===========
  512. */
  513. int COM_FileSize (const char *filename)
  514. {
  515. return g_pFileSystem->Size(filename);
  516. }
  517. //-----------------------------------------------------------------------------
  518. // Purpose: Close file handle
  519. // Input : hFile -
  520. //-----------------------------------------------------------------------------
  521. void COM_CloseFile( FileHandle_t hFile )
  522. {
  523. g_pFileSystem->Close( hFile );
  524. }
  525. /*
  526. ============
  527. COM_LoadFile
  528. Filename are reletive to the quake directory.
  529. Allways appends a 0 byte.
  530. ============
  531. */
  532. cache_user_t *loadcache;
  533. byte *loadbuf;
  534. int loadsize;
  535. byte *COM_LoadFile (const char *path, int usehunk, int *pLength)
  536. {
  537. FileHandle_t hFile;
  538. byte *buf = NULL;
  539. char base[128];
  540. int len;
  541. if (pLength)
  542. {
  543. *pLength = 0;
  544. }
  545. // look for it in the filesystem or pack files
  546. len = COM_OpenFile( path, &hFile );
  547. if ( !hFile )
  548. {
  549. return NULL;
  550. }
  551. // Extract the filename base name for hunk tag
  552. Q_FileBase( path, base, sizeof( base ) );
  553. unsigned bufSize = len + 1;
  554. if ( IsX360() )
  555. {
  556. bufSize = g_pFileSystem->GetOptimalReadSize( hFile, bufSize ); // align to sector
  557. }
  558. switch ( usehunk )
  559. {
  560. case 1:
  561. buf = (byte *)Hunk_AllocName (bufSize, base);
  562. break;
  563. case 2:
  564. AssertMsg( 0, "Temp alloc no longer supported\n" );
  565. break;
  566. case 3:
  567. AssertMsg( 0, "Cache alloc no longer supported\n" );
  568. break;
  569. case 4:
  570. {
  571. if (len+1 > loadsize)
  572. buf = (byte *)malloc(bufSize);
  573. else
  574. buf = loadbuf;
  575. }
  576. break;
  577. case 5:
  578. buf = (byte *)malloc(bufSize); // YWB: FIXME, this is evil.
  579. break;
  580. default:
  581. Sys_Error ("COM_LoadFile: bad usehunk");
  582. }
  583. if ( !buf )
  584. {
  585. Sys_Error ("COM_LoadFile: not enough space for %s", path);
  586. COM_CloseFile(hFile); // exit here to prevent fault on oom (kdb)
  587. return NULL;
  588. }
  589. g_pFileSystem->ReadEx( buf, bufSize, len, hFile );
  590. COM_CloseFile( hFile );
  591. ((byte *)buf)[ len ] = 0;
  592. if ( pLength )
  593. {
  594. *pLength = len;
  595. }
  596. return buf;
  597. }
  598. /*
  599. ===============
  600. COM_CopyFileChunk
  601. ===============
  602. */
  603. void COM_CopyFileChunk( FileHandle_t dst, FileHandle_t src, int nSize )
  604. {
  605. int copysize = nSize;
  606. char copybuf[COM_COPY_CHUNK_SIZE];
  607. while (copysize > COM_COPY_CHUNK_SIZE)
  608. {
  609. g_pFileSystem->Read ( copybuf, COM_COPY_CHUNK_SIZE, src );
  610. g_pFileSystem->Write( copybuf, COM_COPY_CHUNK_SIZE, dst );
  611. copysize -= COM_COPY_CHUNK_SIZE;
  612. }
  613. g_pFileSystem->Read ( copybuf, copysize, src );
  614. g_pFileSystem->Write( copybuf, copysize, dst );
  615. g_pFileSystem->Flush ( src );
  616. g_pFileSystem->Flush ( dst );
  617. }
  618. // uses malloc if larger than bufsize
  619. byte *COM_LoadStackFile (const char *path, void *buffer, int bufsize, int& filesize )
  620. {
  621. byte *buf;
  622. loadbuf = (byte *)buffer;
  623. loadsize = bufsize;
  624. buf = COM_LoadFile (path, 4, &filesize );
  625. return buf;
  626. }
  627. void COM_ShutdownFileSystem( void )
  628. {
  629. }
  630. /*
  631. ================
  632. COM_Shutdown
  633. Remove the searchpaths
  634. ================
  635. */
  636. void COM_Shutdown( void )
  637. {
  638. }
  639. //-----------------------------------------------------------------------------
  640. // Purpose: allocates memory and copys source text
  641. // Input : *in -
  642. // Output : char *CopyString
  643. //-----------------------------------------------------------------------------
  644. char *COM_StringCopy(const char *in)
  645. {
  646. int len = Q_strlen(in)+1;
  647. char *out = (char *)new char[ len ];
  648. Q_strncpy (out, in, len );
  649. return out;
  650. }
  651. void COM_StringFree(const char *in)
  652. {
  653. delete [] in;
  654. }
  655. void COM_SetupLogDir( const char *mapname )
  656. {
  657. #if defined( _CERT )
  658. return;
  659. #endif
  660. char gameDir[MAX_OSPATH];
  661. COM_GetGameDir( gameDir, sizeof( gameDir ) );
  662. // Blat out the all directories in the LOGDIR path
  663. g_pFileSystem->RemoveSearchPath( NULL, "LOGDIR" );
  664. // set the log directory
  665. if ( mapname && CommandLine()->FindParm("-uselogdir") )
  666. {
  667. int i;
  668. char sRelativeLogDir[MAX_PATH];
  669. for ( i = 0; i < MAX_LOG_DIRECTORIES; i++ )
  670. {
  671. Q_snprintf( sRelativeLogDir, sizeof( sRelativeLogDir ), "logs/%s/%04i", mapname, i );
  672. if ( !g_pFileSystem->IsDirectory( sRelativeLogDir, "GAME" ) )
  673. break;
  674. }
  675. // Loop at max
  676. if ( i == MAX_LOG_DIRECTORIES )
  677. {
  678. i = 0;
  679. Q_snprintf( sRelativeLogDir, sizeof( sRelativeLogDir ), "logs/%s/%04i", mapname, i );
  680. }
  681. // Make sure the directories we need exist.
  682. g_pFileSystem->CreateDirHierarchy( sRelativeLogDir, "GAME" );
  683. {
  684. static bool pathsetup = false;
  685. if ( !pathsetup )
  686. {
  687. pathsetup = true;
  688. // Set the search path
  689. char sLogDir[MAX_PATH];
  690. Q_snprintf( sLogDir, sizeof( sLogDir ), "%s/%s", gameDir, sRelativeLogDir );
  691. g_pFileSystem->AddSearchPath( sLogDir, "LOGDIR" );
  692. }
  693. }
  694. }
  695. else
  696. {
  697. // Default to the base game directory for logs.
  698. g_pFileSystem->AddSearchPath( gameDir, "LOGDIR" );
  699. }
  700. // no reason to have this as part of search path fallthrough
  701. // callers must explicitly request
  702. g_pFileSystem->MarkPathIDByRequestOnly( "LOGDIR", true );
  703. }
  704. /*
  705. ================
  706. COM_GetModDirectory - return the final directory in the game dir (i.e "cstrike", "hl2", rather than c:\blah\cstrike )
  707. ================
  708. */
  709. const char *COM_GetModDirectory()
  710. {
  711. static char modDir[MAX_PATH];
  712. if ( Q_strlen( modDir ) == 0 )
  713. {
  714. const char *gamedir = CommandLine()->ParmValue("-game", CommandLine()->ParmValue( "-defaultgamedir", "hl2" ) );
  715. Q_strncpy( modDir, gamedir, sizeof(modDir) );
  716. if ( strchr( modDir, '/' ) || strchr( modDir, '\\' ) )
  717. {
  718. Q_StripLastDir( modDir, sizeof(modDir) );
  719. int dirlen = Q_strlen( modDir );
  720. Q_strncpy( modDir, gamedir + dirlen, sizeof(modDir) - dirlen );
  721. }
  722. }
  723. return modDir;
  724. }
  725. /*
  726. ================
  727. COM_InitFilesystem
  728. ================
  729. */
  730. void COM_InitFilesystem( const char *pFullModPath )
  731. {
  732. CFSSearchPathsInit initInfo;
  733. #ifndef DEDICATED
  734. char language[128];
  735. // Fallback to English
  736. V_strncpy( language, "english", sizeof( language ) );
  737. if ( IsPC() )
  738. {
  739. #if !defined( NO_STEAM )
  740. if ( CommandLine()->CheckParm( "-language" ) )
  741. {
  742. Q_strncpy( language, CommandLine()->ParmValue( "-language", "english"), sizeof( language ) );
  743. }
  744. else
  745. {
  746. // get Steam client language
  747. memset( language, 0, sizeof( language ) );
  748. if ( Steam3Client().SteamApps() )
  749. {
  750. // just follow the language steam wants you to be
  751. const char *lang = Steam3Client().SteamApps()->GetCurrentGameLanguage();
  752. if ( lang && Q_strlen(lang) )
  753. {
  754. Q_strncpy( language, lang, sizeof(language) );
  755. }
  756. else
  757. Q_strncpy( language, "english", sizeof(language) );
  758. }
  759. else
  760. {
  761. Q_strncpy( language, "english", sizeof(language) );
  762. }
  763. }
  764. #endif // NO_STEAM
  765. }
  766. #if defined( _GAMECONSOLE )
  767. if ( XBX_IsAudioLocalized() )
  768. {
  769. // allow non-english audio localization for gameconsole configured language
  770. V_strncpy( language, XBX_GetLanguageString(), sizeof( language ) );
  771. }
  772. #endif
  773. if ( ( Q_strlen( language ) > 0 ) && ( Q_stricmp( language, "english" ) != 0 ) )
  774. {
  775. initInfo.m_pLanguage = language;
  776. }
  777. #endif
  778. initInfo.m_pFileSystem = g_pFileSystem;
  779. #if !defined(_PS3)
  780. initInfo.m_pDirectoryName = pFullModPath;
  781. #else
  782. char ps3NeedsAbsoluteModPath[256];
  783. #ifdef HDD_BOOT
  784. snprintf( ps3NeedsAbsoluteModPath, 256, "%s", pFullModPath );
  785. #else
  786. snprintf( ps3NeedsAbsoluteModPath, 256, "%s/%s", g_pPS3PathInfo->GameImagePath(), pFullModPath );
  787. #endif
  788. initInfo.m_pDirectoryName = ps3NeedsAbsoluteModPath;
  789. #endif
  790. if ( !initInfo.m_pDirectoryName )
  791. {
  792. initInfo.m_pDirectoryName = GetCurrentGame();
  793. }
  794. // Load gameinfo.txt and setup all the search paths, just like the tools do.
  795. FileSystem_LoadSearchPaths( initInfo );
  796. // The mod path becomes com_gamedir.
  797. Q_MakeAbsolutePath( com_gamedir, sizeof( com_gamedir ), initInfo.m_ModPath );
  798. // Set com_basedir.
  799. Q_strncpy ( com_basedir, GetBaseDirectory(), sizeof( com_basedir ) ); // the "root" directory where hl2.exe is
  800. Q_strlower( com_basedir );
  801. Q_FixSlashes( com_basedir );
  802. #ifndef DEDICATED
  803. EngineVGui()->SetVGUIDirectories();
  804. #endif
  805. // Set LOGDIR to be something reasonable
  806. COM_SetupLogDir( NULL );
  807. }
  808. const char *COM_DXLevelToString( int dxlevel )
  809. {
  810. bool bHalfPrecision = false;
  811. const char *pShaderDLLName = g_pMaterialSystemHardwareConfig->GetShaderDLLName();
  812. if( pShaderDLLName && Q_stristr( pShaderDLLName, "nvfx" ) )
  813. {
  814. bHalfPrecision = true;
  815. }
  816. switch( dxlevel )
  817. {
  818. case 60:
  819. return "gamemode - 6.0";
  820. case 70:
  821. return "gamemode - 7.0";
  822. case 80:
  823. return "gamemode - 8.0";
  824. case 81:
  825. return "gamemode - 8.1";
  826. case 82:
  827. if( bHalfPrecision )
  828. {
  829. return "gamemode - 8.1 with some 9.0 (half-precision)";
  830. }
  831. else
  832. {
  833. return "gamemode - 8.1 with some 9.0 (full-precision)";
  834. }
  835. case 90:
  836. if( bHalfPrecision )
  837. {
  838. return "gamemode - 9.0 (half-precision)";
  839. }
  840. else
  841. {
  842. return "gamemode - 9.0 (full-precision)";
  843. }
  844. case 92:
  845. return "9.0 Shader Model 2.0b";
  846. case 95:
  847. return "9.0 Shader Model 3.0";
  848. case 98:
  849. return "XBox 360";
  850. case 100:
  851. return "10.0 Shader Model 4.0";
  852. default:
  853. return "gamemode";
  854. }
  855. }
  856. const char *COM_FormatSeconds( int seconds )
  857. {
  858. static char string[64];
  859. int hours = 0;
  860. int minutes = seconds / 60;
  861. if ( minutes > 0 )
  862. {
  863. seconds -= (minutes * 60);
  864. hours = minutes / 60;
  865. if ( hours > 0 )
  866. {
  867. minutes -= (hours * 60);
  868. }
  869. }
  870. if ( hours > 0 )
  871. {
  872. Q_snprintf( string, sizeof(string), "%2i:%02i:%02i", hours, minutes, seconds );
  873. }
  874. else
  875. {
  876. Q_snprintf( string, sizeof(string), "%02i:%02i", minutes, seconds );
  877. }
  878. return string;
  879. }
  880. // Non-VarArgs version
  881. void COM_LogString( char const *pchFile, char const *pchString )
  882. {
  883. if ( !g_pFileSystem )
  884. {
  885. Assert( 0 );
  886. return;
  887. }
  888. FileHandle_t fp;
  889. const char *pfilename;
  890. if ( !pchFile )
  891. {
  892. pfilename = "hllog.txt";
  893. }
  894. else
  895. {
  896. pfilename = pchFile;
  897. }
  898. fp = g_pFileSystem->Open( pfilename, "a+t");
  899. if (fp)
  900. {
  901. g_pFileSystem->FPrintf(fp, "%s", pchString);
  902. g_pFileSystem->Close(fp);
  903. }
  904. }
  905. void COM_Log( const char *pszFile, const char *fmt, ...)
  906. {
  907. if ( !g_pFileSystem )
  908. {
  909. Assert( 0 );
  910. return;
  911. }
  912. va_list argptr;
  913. char string[8192];
  914. va_start (argptr,fmt);
  915. Q_vsnprintf(string, sizeof( string ), fmt,argptr);
  916. va_end (argptr);
  917. COM_LogString( pszFile, string );
  918. }
  919. //-----------------------------------------------------------------------------
  920. // Purpose:
  921. // Input : *filename1 -
  922. // *filename2 -
  923. // *iCompare -
  924. // Output : int
  925. //-----------------------------------------------------------------------------
  926. int COM_CompareFileTime(const char *filename1, const char *filename2, int *iCompare)
  927. {
  928. int bRet = 0;
  929. if ( iCompare )
  930. {
  931. *iCompare = 0;
  932. }
  933. if (filename1 && filename2)
  934. {
  935. long ft1 = g_pFileSystem->GetFileTime( filename1 );
  936. long ft2 = g_pFileSystem->GetFileTime( filename2 );
  937. if ( iCompare )
  938. {
  939. *iCompare = Sys_CompareFileTime( ft1, ft2 );
  940. }
  941. bRet = 1;
  942. }
  943. return bRet;
  944. }
  945. //-----------------------------------------------------------------------------
  946. // Purpose:
  947. // Input : *szGameDir -
  948. //-----------------------------------------------------------------------------
  949. void COM_GetGameDir(char *szGameDir, int maxlen)
  950. {
  951. if (!szGameDir) return;
  952. Q_strncpy(szGameDir, com_gamedir, maxlen );
  953. }
  954. //-----------------------------------------------------------------------------
  955. // Purpose: Parse a token from a file stream
  956. // Input : *data -
  957. // *token -
  958. // Output : char
  959. //-----------------------------------------------------------------------------
  960. const char *COM_ParseFile(const char *data, char *token, int maxtoken )
  961. {
  962. const char *return_data = COM_Parse(data);
  963. Q_strncpy(token, com_token, maxtoken);
  964. return return_data;
  965. }
  966. //-----------------------------------------------------------------------------
  967. // Purpose:
  968. // Output : void COM_Init
  969. //-----------------------------------------------------------------------------
  970. void COM_Init ( void )
  971. {
  972. CharacterSetBuild( &g_BreakSet, "{}()'" );
  973. CharacterSetBuild( &g_BreakSetIncludingColons, "{}()':" );
  974. }
  975. bool COM_IsValidPath( const char *pszFilename )
  976. {
  977. if ( !pszFilename )
  978. {
  979. return false;
  980. }
  981. if ( Q_strlen( pszFilename ) <= 0 ||
  982. Q_strstr( pszFilename, "\\\\" ) || // to protect network paths
  983. Q_strstr( pszFilename, ":" ) || // to protect absolute paths
  984. Q_strstr( pszFilename, ".." ) || // to protect relative paths
  985. Q_strstr( pszFilename, "\n" ) || // CFileSystem_Stdio::FS_fopen doesn't allow this
  986. Q_strstr( pszFilename, "\r" ) ) // CFileSystem_Stdio::FS_fopen doesn't allow this
  987. {
  988. return false;
  989. }
  990. return true;
  991. }