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.

1738 lines
48 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #if defined(_WIN32) && !defined(_X360)
  9. #include "winlite.h"
  10. #endif
  11. #ifdef OSX
  12. #include <Carbon/Carbon.h>
  13. #include <sys/sysctl.h>
  14. #endif
  15. #if defined(LINUX)
  16. #include <unistd.h>
  17. #include <fcntl.h>
  18. #include "SDL.h"
  19. #endif
  20. #include "quakedef.h"
  21. #include "igame.h"
  22. #include "errno.h"
  23. #include "host.h"
  24. #include "profiling.h"
  25. #include "server.h"
  26. #include "vengineserver_impl.h"
  27. #include "filesystem_engine.h"
  28. #include "sys.h"
  29. #include "sys_dll.h"
  30. #include "ivideomode.h"
  31. #include "host_cmd.h"
  32. #include "crtmemdebug.h"
  33. #include "sv_log.h"
  34. #include "sv_main.h"
  35. #include "traceinit.h"
  36. #include "dt_test.h"
  37. #include "keys.h"
  38. #include "gl_matsysiface.h"
  39. #include "tier0/icommandline.h"
  40. #include "tier0/stacktools.h"
  41. #include "cmd.h"
  42. #include <ihltvdirector.h>
  43. #include <ireplaydirector.h>
  44. #include "MapReslistGenerator.h"
  45. #include "DevShotGenerator.h"
  46. #include "cdll_engine_int.h"
  47. #include "dt_send.h"
  48. #include "idedicatedexports.h"
  49. #include "cvar.h"
  50. #include "cl_steamauth.h"
  51. #include "status.h"
  52. #include "tier0/logging.h"
  53. #include "tier2/tier2_logging.h"
  54. #include "vgui_baseui_interface.h"
  55. #include "tier0/systeminformation.h"
  56. #ifdef _WIN32
  57. #if !defined( _X360 )
  58. #include <io.h>
  59. #endif
  60. #endif
  61. #include "toolframework/itoolframework.h"
  62. #if defined( _X360 )
  63. #include "xbox/xbox_win32stubs.h"
  64. #elif defined( _PS3 )
  65. #include "ps3/ps3_console.h"
  66. #include "sys/tty.h"
  67. #endif
  68. // memdbgon must be the last include file in a .cpp file!!!
  69. #include "tier0/memdbgon.h"
  70. #define ONE_HUNDRED_TWENTY_EIGHT_MB (128 * 1024 * 1024)
  71. ConVar mem_min_heapsize( "mem_min_heapsize", "48", 0, "Minimum amount of memory to dedicate to engine hunk and datacache (in mb)" );
  72. ConVar mem_max_heapsize( "mem_max_heapsize", "512", 0, "Maximum amount of memory to dedicate to engine hunk and datacache (in mb)" );
  73. ConVar mem_max_heapsize_dedicated( "mem_max_heapsize_dedicated", "64", 0, "Maximum amount of memory to dedicate to engine hunk and datacache, for dedicated server (in mb)" );
  74. #define MINIMUM_WIN_MEMORY (unsigned)(mem_min_heapsize.GetInt()*1024*1024)
  75. #define MAXIMUM_WIN_MEMORY MAX( (unsigned)(mem_max_heapsize.GetInt()*1024*1024), MINIMUM_WIN_MEMORY )
  76. #define MAXIMUM_DEDICATED_MEMORY (unsigned)(mem_max_heapsize_dedicated.GetInt()*1024*1024)
  77. DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_SERVER_LOG, "ServerLog", LCF_DO_NOT_ECHO );
  78. char *CheckParm(const char *psz, char **ppszValue = NULL);
  79. void SeedRandomNumberGenerator( bool random_invariant );
  80. void Con_ColorPrintf( const Color& clr, const char *fmt, ... );
  81. void COM_ShutdownFileSystem( void );
  82. void COM_InitFilesystem( const char *pFullModPath );
  83. modinfo_t gmodinfo;
  84. extern HWND *pmainwindow;
  85. char gszDisconnectReason[256];
  86. char gszExtendedDisconnectReason[256];
  87. bool gfExtendedError = false;
  88. uint8 g_eSteamLoginFailure = 0;
  89. bool g_bV3SteamInterface = false;
  90. CreateInterfaceFn g_AppSystemFactory = NULL;
  91. static bool s_bIsDedicated = false;
  92. ConVar *sv_noclipduringpause = NULL;
  93. // Special mode where the client uses a console window and has no graphics. Useful for stress-testing a server
  94. // without having to round up 32 people.
  95. bool g_bTextMode = false;
  96. // Set to true when we exit from an error.
  97. bool g_bInErrorExit = false;
  98. static FileFindHandle_t g_hfind = FILESYSTEM_INVALID_FIND_HANDLE;
  99. // The extension DLL directory--one entry per loaded DLL
  100. CSysModule *g_GameDLL = NULL;
  101. // Prototype of an global method function
  102. typedef void (DLLEXPORT * PFN_GlobalMethod)( edict_t *pEntity );
  103. IServerGameDLL *serverGameDLL = NULL;
  104. bool g_bServerGameDLLGreaterThanV5;
  105. IServerGameEnts *serverGameEnts = NULL;
  106. IServerGameClients *serverGameClients = NULL;
  107. int g_iServerGameClientsVersion = 0; // This matches the number at the end of the interface name (so for "ServerGameClients004", this would be 4).
  108. IHLTVDirector *serverGameDirector = NULL;
  109. IReplayDirector *serverReplayDirector = NULL;
  110. IServerGameTags *serverGameTags = NULL;
  111. void Sys_InitArgv( char *lpCmdLine );
  112. void Sys_ShutdownArgv( void );
  113. extern bool s_bIsDedicatedServer;
  114. //-----------------------------------------------------------------------------
  115. // Purpose: Compare file times
  116. // Input : ft1 -
  117. // ft2 -
  118. // Output : int
  119. //-----------------------------------------------------------------------------
  120. int Sys_CompareFileTime( long ft1, long ft2 )
  121. {
  122. if ( ft1 < ft2 )
  123. {
  124. return -1;
  125. }
  126. else if ( ft1 > ft2 )
  127. {
  128. return 1;
  129. }
  130. return 0;
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Is slash?
  134. //-----------------------------------------------------------------------------
  135. inline bool IsSlash( char c )
  136. {
  137. return ( c == '\\') || ( c == '/' );
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Purpose: Create specified directory
  141. // Input : *path -
  142. // Output : void Sys_mkdir
  143. //-----------------------------------------------------------------------------
  144. void Sys_mkdir( const char *path, const char *pPathID /*= 0*/ )
  145. {
  146. char testpath[ MAX_OSPATH ];
  147. // Remove any terminal backslash or /
  148. Q_strncpy( testpath, path, sizeof( testpath ) );
  149. int nLen = Q_strlen( testpath );
  150. if ( (nLen > 0) && IsSlash( testpath[ nLen - 1 ] ) )
  151. {
  152. testpath[ nLen - 1 ] = 0;
  153. }
  154. // Look for URL
  155. if ( !pPathID )
  156. {
  157. pPathID = "MOD";
  158. }
  159. if ( IsSlash( testpath[0] ) && IsSlash( testpath[1] ) )
  160. {
  161. pPathID = NULL;
  162. }
  163. Q_FixSlashes( testpath );
  164. if ( g_pFileSystem->FileExists( testpath, pPathID ) )
  165. {
  166. // if there is a file of the same name as the directory we want to make, just kill it
  167. if ( !g_pFileSystem->IsDirectory( testpath, pPathID ) )
  168. {
  169. g_pFileSystem->RemoveFile( testpath, pPathID );
  170. }
  171. }
  172. g_pFileSystem->CreateDirHierarchy( path, pPathID );
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Purpose:
  176. // Input : *path -
  177. // *basename -
  178. // Output : char *Sys_FindFirst
  179. //-----------------------------------------------------------------------------
  180. const char *Sys_FindFirst(const char *path, char *basename, int namelength )
  181. {
  182. if (g_hfind != FILESYSTEM_INVALID_FIND_HANDLE)
  183. {
  184. Sys_Error ("Sys_FindFirst without close");
  185. g_pFileSystem->FindClose(g_hfind);
  186. }
  187. const char* psz = g_pFileSystem->FindFirst(path, &g_hfind);
  188. if (basename && psz)
  189. {
  190. Q_FileBase(psz, basename, namelength );
  191. }
  192. return psz;
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Purpose: Sys_FindFirst with a path ID filter.
  196. //-----------------------------------------------------------------------------
  197. const char *Sys_FindFirstEx( const char *pWildcard, const char *pPathID, char *basename, int namelength )
  198. {
  199. if (g_hfind != FILESYSTEM_INVALID_FIND_HANDLE)
  200. {
  201. Sys_Error ("Sys_FindFirst without close");
  202. g_pFileSystem->FindClose(g_hfind);
  203. }
  204. const char* psz = g_pFileSystem->FindFirstEx( pWildcard, pPathID, &g_hfind);
  205. if (basename && psz)
  206. {
  207. Q_FileBase(psz, basename, namelength );
  208. }
  209. return psz;
  210. }
  211. //-----------------------------------------------------------------------------
  212. // Purpose:
  213. // Input : *basename -
  214. // Output : char *Sys_FindNext
  215. //-----------------------------------------------------------------------------
  216. const char* Sys_FindNext(char *basename, int namelength)
  217. {
  218. const char *psz = g_pFileSystem->FindNext(g_hfind);
  219. if ( basename && psz )
  220. {
  221. Q_FileBase(psz, basename, namelength );
  222. }
  223. return psz;
  224. }
  225. //-----------------------------------------------------------------------------
  226. // Purpose:
  227. // Output : void Sys_FindClose
  228. //-----------------------------------------------------------------------------
  229. void Sys_FindClose(void)
  230. {
  231. if ( FILESYSTEM_INVALID_FIND_HANDLE != g_hfind )
  232. {
  233. g_pFileSystem->FindClose(g_hfind);
  234. g_hfind = FILESYSTEM_INVALID_FIND_HANDLE;
  235. }
  236. }
  237. //-----------------------------------------------------------------------------
  238. // Purpose: OS Specific initializations
  239. //-----------------------------------------------------------------------------
  240. void Sys_Init( void )
  241. {
  242. // Set default FPU control word to truncate (chop) mode for optimized _ftol()
  243. // This does not "stick", the mode is restored somewhere down the line.
  244. // Sys_TruncateFPU();
  245. }
  246. //-----------------------------------------------------------------------------
  247. // Purpose:
  248. //-----------------------------------------------------------------------------
  249. void Sys_Shutdown( void )
  250. {
  251. }
  252. //-----------------------------------------------------------------------------
  253. // Purpose: Print to system console
  254. // Input : *fmt -
  255. // ... -
  256. // Output : void Sys_Printf
  257. //-----------------------------------------------------------------------------
  258. void Sys_Printf(char *fmt, ...)
  259. {
  260. va_list argptr;
  261. char text[1024];
  262. va_start (argptr,fmt);
  263. Q_vsnprintf (text, sizeof( text ), fmt, argptr);
  264. va_end (argptr);
  265. if ( developer.GetInt() )
  266. {
  267. #ifdef _WIN32
  268. wchar_t unicode[2048];
  269. ::MultiByteToWideChar(CP_UTF8, 0, text, -1, unicode, sizeof( unicode ) / sizeof(wchar_t));
  270. unicode[(sizeof( unicode ) / sizeof(wchar_t)) - 1] = L'\0';
  271. OutputDebugStringW( unicode );
  272. Sleep( 0 );
  273. #else
  274. fprintf( stderr, "%s", text );
  275. #endif
  276. }
  277. if ( s_bIsDedicated )
  278. {
  279. printf( "%s", text );
  280. }
  281. }
  282. bool Sys_MessageBox(const char *title, const char *info, bool bShowOkAndCancel)
  283. {
  284. #ifdef _WIN32
  285. if (IDOK == ::MessageBox(NULL, title, info, MB_ICONEXCLAMATION | (bShowOkAndCancel ? MB_OKCANCEL : MB_OK)))
  286. {
  287. return true;
  288. }
  289. return false;
  290. #elif defined( LINUX ) && !defined( DEDICATED )
  291. int buttonid = 0;
  292. SDL_MessageBoxData messageboxdata = { 0 };
  293. SDL_MessageBoxButtonData buttondata[] =
  294. {
  295. { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 1, "OK" },
  296. { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 0, "Cancel" },
  297. };
  298. messageboxdata.window = GetAssertDialogParent();
  299. messageboxdata.title = title;
  300. messageboxdata.message = info;
  301. messageboxdata.numbuttons = bShowOkAndCancel ? 2 : 1;
  302. messageboxdata.buttons = buttondata;
  303. SDL_ShowMessageBox( &messageboxdata, &buttonid );
  304. return ( buttonid == 1 );
  305. #elif defined ( POSIX )
  306. Warning( "%s\n", info );
  307. return true;
  308. #else
  309. #error "implement me"
  310. #endif
  311. }
  312. bool g_bUpdateMinidumpComment = true;
  313. #if !defined(NO_STEAM) && !defined(DEDICATED) && !defined(LINUX)
  314. void BuildMinidumpComment( char const *pchSysErrorText );
  315. #endif
  316. //-----------------------------------------------------------------------------
  317. // Purpose: Exit engine with error
  318. // Input : *error -
  319. // ... -
  320. // Output : void Sys_Error
  321. //-----------------------------------------------------------------------------
  322. void Sys_Error_Internal( bool bMinidump, const char *error, va_list argsList )
  323. {
  324. char text[1024];
  325. static bool bReentry = false; // Don't meltdown
  326. Q_vsnprintf( text, sizeof( text ), error, argsList );
  327. if ( bReentry )
  328. {
  329. fprintf( stderr, "%s\n", text );
  330. return;
  331. }
  332. bReentry = true;
  333. if ( s_bIsDedicated )
  334. {
  335. printf( "%s\n", text );
  336. }
  337. else
  338. {
  339. Sys_Printf( "%s\n", text );
  340. }
  341. g_bInErrorExit = true;
  342. #if !defined( DEDICATED )
  343. if ( IsPC() && videomode )
  344. videomode->Shutdown();
  345. #endif
  346. if ( IsPC() &&
  347. !CommandLine()->FindParm( "-makereslists" ) &&
  348. !CommandLine()->FindParm( "-nomessagebox" ) )
  349. {
  350. #ifdef _WIN32
  351. ::MessageBox( NULL, text, "Engine Error", MB_OK | MB_TOPMOST );
  352. #elif defined ( LINUX )
  353. Sys_MessageBox( "Engine Error", text, false );
  354. #endif
  355. }
  356. if ( IsPC() )
  357. {
  358. DebuggerBreakIfDebugging();
  359. }
  360. else
  361. {
  362. DebuggerBreak();
  363. }
  364. #if !defined( _X360 )
  365. #if !defined(NO_STEAM) && !defined(DEDICATED) && !defined(LINUX)
  366. Status_Update();
  367. BuildMinidumpComment( text );
  368. g_bUpdateMinidumpComment = false;
  369. #endif
  370. if ( bMinidump && !Plat_IsInDebugSession() && !CommandLine()->FindParm( "-nominidumps") )
  371. {
  372. #ifdef WIN32
  373. // MiniDumpWrite() has problems capturing the calling thread's context
  374. // unless it is called with an exception context. So fake an exception.
  375. __try
  376. {
  377. RaiseException
  378. (
  379. 0, // dwExceptionCode
  380. EXCEPTION_NONCONTINUABLE, // dwExceptionFlags
  381. 0, // nNumberOfArguments,
  382. NULL // const ULONG_PTR* lpArguments
  383. );
  384. // Never get here (non-continuable exception)
  385. }
  386. // Write the minidump from inside the filter (GetExceptionInformation() is only
  387. // valid in the filter)
  388. __except ( SteamAPI_WriteMiniDump( 0, GetExceptionInformation(), build_number() ), EXCEPTION_EXECUTE_HANDLER )
  389. {
  390. // We always get here because the above filter evaluates to EXCEPTION_EXECUTE_HANDLER
  391. }
  392. #elif defined( OSX )
  393. // Doing this doesn't quite work the way we want because there is no "crashing" thread
  394. // and we see "No thread was identified as the cause of the crash; No signature could be created because we do not know which thread crashed" on the back end
  395. //SteamAPI_WriteMiniDump( 0, NULL, build_number() );
  396. printf("\n ##### Sys_Error: %s", text );
  397. fflush(stdout );
  398. int *p = 0;
  399. *p = 0xdeadbeef;
  400. #elif defined( LINUX )
  401. // Doing this doesn't quite work the way we want because there is no "crashing" thread
  402. // and we see "No thread was identified as the cause of the crash; No signature could be created because we do not know which thread crashed" on the back end
  403. //SteamAPI_WriteMiniDump( 0, NULL, build_number() );
  404. int *p = 0;
  405. *p = 0xdeadbeef;
  406. #else
  407. //!!BUG!! "need minidump impl on sys_error"
  408. #endif
  409. }
  410. #endif // _X360
  411. host_initialized = false;
  412. Plat_ExitProcess( 100 );
  413. }
  414. //-----------------------------------------------------------------------------
  415. // Purpose: Exit engine with error
  416. // Input : *error -
  417. // ... -
  418. // Output : void Sys_Error
  419. //-----------------------------------------------------------------------------
  420. void Sys_Error(const char *error, ...)
  421. {
  422. va_list argptr;
  423. va_start( argptr, error );
  424. Sys_Error_Internal( true, error, argptr );
  425. va_end( argptr );
  426. }
  427. //-----------------------------------------------------------------------------
  428. // Purpose: Exit engine with error
  429. // Input : *error -
  430. // ... -
  431. // Output : void Sys_Error
  432. //-----------------------------------------------------------------------------
  433. void Sys_Exit(const char *error, ...)
  434. {
  435. va_list argptr;
  436. va_start( argptr, error );
  437. Sys_Error_Internal( false, error, argptr );
  438. va_end( argptr );
  439. }
  440. bool IsInErrorExit()
  441. {
  442. return g_bInErrorExit;
  443. }
  444. //-----------------------------------------------------------------------------
  445. // Purpose:
  446. // Input : msec -
  447. // Output : void Sys_Sleep
  448. //-----------------------------------------------------------------------------
  449. void Sys_Sleep( int msec )
  450. {
  451. ThreadSleep( msec );
  452. }
  453. //-----------------------------------------------------------------------------
  454. // Purpose:
  455. // Input : hInst -
  456. // ulInit -
  457. // lpReserved -
  458. // Output : BOOL WINAPI DllMain
  459. //-----------------------------------------------------------------------------
  460. #if defined(_WIN32) && !defined( _X360 )
  461. BOOL WINAPI DllMain(HANDLE hInst, ULONG ulInit, LPVOID lpReserved)
  462. {
  463. InitCRTMemDebug();
  464. if (ulInit == DLL_PROCESS_ATTACH)
  465. {
  466. }
  467. else if (ulInit == DLL_PROCESS_DETACH)
  468. {
  469. }
  470. return TRUE;
  471. }
  472. #endif
  473. //-----------------------------------------------------------------------------
  474. // Purpose: Allocate memory for engine hunk
  475. // Input : *parms -
  476. //-----------------------------------------------------------------------------
  477. void Sys_InitMemory( void )
  478. {
  479. // Allow overrides
  480. if ( CommandLine()->FindParm( "-minmemory" ) )
  481. {
  482. host_parms.memsize = MINIMUM_WIN_MEMORY;
  483. return;
  484. }
  485. host_parms.memsize = 0;
  486. #ifdef _WIN32
  487. #if (_MSC_VER > 1200)
  488. // MSVC 6.0 doesn't support GlobalMemoryStatusEx()
  489. if ( IsPC() )
  490. {
  491. OSVERSIONINFOEX osvi;
  492. ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
  493. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  494. if ( GetVersionEx ((OSVERSIONINFO *)&osvi) )
  495. {
  496. if ( osvi.dwPlatformId >= VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion >= 5 )
  497. {
  498. MEMORYSTATUSEX memStat;
  499. ZeroMemory(&memStat, sizeof(MEMORYSTATUSEX));
  500. memStat.dwLength = sizeof(MEMORYSTATUSEX);
  501. if ( GlobalMemoryStatusEx( &memStat ) )
  502. {
  503. if ( memStat.ullTotalPhys > 0xFFFFFFFFUL )
  504. {
  505. host_parms.memsize = 0xFFFFFFFFUL;
  506. }
  507. else
  508. {
  509. host_parms.memsize = memStat.ullTotalPhys;
  510. }
  511. }
  512. }
  513. }
  514. }
  515. #endif // (_MSC_VER > 1200)
  516. if ( !IsGameConsole() )
  517. {
  518. if ( host_parms.memsize == 0 )
  519. {
  520. MEMORYSTATUS lpBuffer;
  521. // Get OS Memory status
  522. lpBuffer.dwLength = sizeof(MEMORYSTATUS);
  523. GlobalMemoryStatus( &lpBuffer );
  524. if ( lpBuffer.dwTotalPhys <= 0 )
  525. {
  526. host_parms.memsize = MAXIMUM_WIN_MEMORY;
  527. }
  528. else
  529. {
  530. host_parms.memsize = lpBuffer.dwTotalPhys;
  531. }
  532. }
  533. if ( host_parms.memsize < ONE_HUNDRED_TWENTY_EIGHT_MB )
  534. {
  535. Sys_Error( "Available memory less than 128MB!!! %i\n", host_parms.memsize );
  536. }
  537. // take one quarter the physical memory
  538. if ( host_parms.memsize <= 512*1024*1024)
  539. {
  540. host_parms.memsize >>= 2;
  541. // Apply cap of 64MB for 512MB systems
  542. // this keeps the code the same as HL2 gold
  543. // but allows us to use more memory on 1GB+ systems
  544. if (host_parms.memsize > MAXIMUM_DEDICATED_MEMORY)
  545. {
  546. host_parms.memsize = MAXIMUM_DEDICATED_MEMORY;
  547. }
  548. }
  549. else
  550. {
  551. // just take one quarter, no cap
  552. host_parms.memsize >>= 2;
  553. }
  554. // At least MINIMUM_WIN_MEMORY mb, even if we have to swap a lot.
  555. if (host_parms.memsize < MINIMUM_WIN_MEMORY)
  556. {
  557. host_parms.memsize = MINIMUM_WIN_MEMORY;
  558. }
  559. // Apply cap
  560. if (host_parms.memsize > MAXIMUM_WIN_MEMORY)
  561. {
  562. host_parms.memsize = MAXIMUM_WIN_MEMORY;
  563. }
  564. }
  565. else
  566. {
  567. host_parms.memsize = 128*1024*1024;
  568. }
  569. #elif defined ( DEDICATED )
  570. // hard code 32 mb for dedicated servers
  571. host_parms.memsize = MAXIMUM_DEDICATED_MEMORY;
  572. #elif defined(POSIX)
  573. uint64_t memsize = ONE_HUNDRED_TWENTY_EIGHT_MB;
  574. #if defined(OSX)
  575. int mib[2] = { CTL_HW, HW_MEMSIZE };
  576. u_int namelen = sizeof(mib) / sizeof(mib[0]);
  577. size_t len = sizeof(memsize);
  578. if (sysctl(mib, namelen, &memsize, &len, NULL, 0) < 0)
  579. {
  580. memsize = ONE_HUNDRED_TWENTY_EIGHT_MB;
  581. }
  582. #elif defined(LINUX)
  583. const int fd = open("/proc/meminfo", O_RDONLY);
  584. if (fd < 0)
  585. {
  586. Sys_Error( "Can't open /proc/meminfo (%s)!\n", strerror(errno) );
  587. }
  588. char buf[1024 * 16];
  589. const ssize_t br = read(fd, buf, sizeof (buf));
  590. close(fd);
  591. if (br < 0)
  592. {
  593. Sys_Error( "Can't read /proc/meminfo (%s)!\n", strerror(errno) );
  594. }
  595. buf[br] = '\0';
  596. // Split up the buffer by lines...
  597. char *line = buf;
  598. for (char *ptr = buf; *ptr; ptr++)
  599. {
  600. if (*ptr == '\n')
  601. {
  602. // we've got a complete line.
  603. *ptr = '\0';
  604. unsigned long long ull = 0;
  605. if (sscanf(line, "MemTotal: %llu kB", &ull) == 1)
  606. {
  607. // found it!
  608. memsize = ((uint64_t) ull) * 1024;
  609. break;
  610. }
  611. line = ptr;
  612. }
  613. }
  614. #else
  615. #error Write me.
  616. #endif
  617. if ( memsize > 0xFFFFFFFFUL )
  618. {
  619. host_parms.memsize = 0xFFFFFFFFUL;
  620. }
  621. else
  622. {
  623. host_parms.memsize = memsize;
  624. }
  625. if ( host_parms.memsize < ONE_HUNDRED_TWENTY_EIGHT_MB )
  626. {
  627. Sys_Error( "Available memory less than 128MB!!! %i\n", host_parms.memsize );
  628. }
  629. // take one quarter the physical memory
  630. if ( host_parms.memsize <= 512*1024*1024)
  631. {
  632. host_parms.memsize >>= 2;
  633. // Apply cap of 64MB for 512MB systems
  634. // this keeps the code the same as HL2 gold
  635. // but allows us to use more memory on 1GB+ systems
  636. if (host_parms.memsize > MAXIMUM_DEDICATED_MEMORY)
  637. {
  638. host_parms.memsize = MAXIMUM_DEDICATED_MEMORY;
  639. }
  640. }
  641. else
  642. {
  643. // just take one quarter, no cap
  644. host_parms.memsize >>= 2;
  645. }
  646. // At least MINIMUM_WIN_MEMORY mb, even if we have to swap a lot.
  647. if (host_parms.memsize < MINIMUM_WIN_MEMORY)
  648. {
  649. host_parms.memsize = MINIMUM_WIN_MEMORY;
  650. }
  651. // Apply cap
  652. if (host_parms.memsize > MAXIMUM_WIN_MEMORY)
  653. {
  654. host_parms.memsize = MAXIMUM_WIN_MEMORY;
  655. }
  656. #elif defined( _PS3 )
  657. host_parms.memsize = 128*1024*1024;
  658. #else
  659. #error Write me.
  660. #endif
  661. }
  662. //-----------------------------------------------------------------------------
  663. // Purpose:
  664. // Input : *parms -
  665. // Output : Returns true on success, false on failure.
  666. //-----------------------------------------------------------------------------
  667. void Sys_ShutdownMemory( void )
  668. {
  669. host_parms.memsize = 0;
  670. }
  671. //-----------------------------------------------------------------------------
  672. // Purpose:
  673. //-----------------------------------------------------------------------------
  674. void Sys_InitAuthentication( void )
  675. {
  676. }
  677. //-----------------------------------------------------------------------------
  678. // Purpose:
  679. //-----------------------------------------------------------------------------
  680. void Sys_ShutdownAuthentication( void )
  681. {
  682. }
  683. //-----------------------------------------------------------------------------
  684. // Debug library spew output
  685. //-----------------------------------------------------------------------------
  686. #ifdef _PS3
  687. #include "tls_ps3.h"
  688. #define g_bInSpew GetTLSGlobals()->bEngineConsoleIsInSpew
  689. #else
  690. CTHREADLOCALINT g_bInSpew;
  691. #endif
  692. #include "tier1/fmtstr.h"
  693. static ConVar sys_minidumpspewlines( "sys_minidumpspewlines", "500", FCVAR_RELEASE, "Lines of crash dump console spew to keep." );
  694. static CUtlLinkedList< CUtlString > g_SpewHistory;
  695. static int g_nSpewLines = 1;
  696. static CThreadFastMutex g_SpewMutex;
  697. static void AddSpewRecord( char const *pMsg )
  698. {
  699. #if !defined( DEDICATED ) && !defined( _GAMECONSOLE )
  700. CUtlString str;
  701. str.Format( "%d(%f): %s", g_nSpewLines, Plat_FloatTime(), pMsg );
  702. AUTO_LOCK_FM( g_SpewMutex );
  703. ++g_nSpewLines;
  704. if ( g_SpewHistory.Count() > sys_minidumpspewlines.GetInt() )
  705. {
  706. g_SpewHistory.Remove( g_SpewHistory.Head() );
  707. }
  708. g_SpewHistory.AddToTail( str );
  709. #endif
  710. }
  711. void GetSpew( char *buf, size_t buflen )
  712. {
  713. AUTO_LOCK_FM( g_SpewMutex );
  714. // Walk list backward
  715. char *pcur = buf;
  716. int remainder = (int)buflen - 1;
  717. // Walk backward(
  718. for ( int i = g_SpewHistory.Tail(); i != g_SpewHistory.InvalidIndex(); i = g_SpewHistory.Previous( i ) )
  719. {
  720. const CUtlString &rec = g_SpewHistory[ i ];
  721. int len = rec.Length();
  722. int tocopy = MIN( len, remainder );
  723. if ( tocopy <= 0 )
  724. break;
  725. Q_memcpy( pcur, rec.String(), tocopy );
  726. remainder -= tocopy;
  727. pcur += tocopy;
  728. if ( remainder <= 0 )
  729. break;
  730. }
  731. *pcur = 0;
  732. }
  733. #ifdef _PS3
  734. DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_PSGL, "PSGL" );
  735. DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_VJOBS, "VJOBS" );
  736. DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_PHYSICS, "PHYSICS" );
  737. DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_LOADING, "LOADING" );
  738. #endif
  739. class CEngineConsoleLoggingListener : public ILoggingListener
  740. {
  741. public:
  742. virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage )
  743. {
  744. if ( ( pContext->m_Flags & LCF_DO_NOT_ECHO ) != 0 )
  745. {
  746. if ( pContext->m_ChannelID == LOG_SERVER_LOG )
  747. {
  748. g_Log.Print( pMessage );
  749. }
  750. return;
  751. }
  752. #if defined( _PS3 ) && !defined( _CERT )
  753. if( pContext->m_ChannelID == LOG_PSGL )
  754. {
  755. uint wrote;
  756. // write to TTY USR1
  757. sys_tty_write( SYS_TTYP3, pMessage, V_strlen(pMessage), &wrote );
  758. return;
  759. }
  760. else if( pContext->m_ChannelID == LOG_VJOBS )
  761. {
  762. uint wrote;
  763. // write to TTY USR2
  764. sys_tty_write( SYS_TTYP4, pMessage, V_strlen(pMessage), &wrote );
  765. return;
  766. }
  767. else if( pContext->m_ChannelID == LOG_PHYSICS )
  768. {
  769. uint wrote;
  770. // write to TTY USR3
  771. sys_tty_write( SYS_TTYP5, pMessage, V_strlen(pMessage), &wrote );
  772. return;
  773. }
  774. else if( pContext->m_ChannelID == LOG_LOADING )
  775. {
  776. uint wrote;
  777. // write to TTY USR4
  778. sys_tty_write( SYS_TTYP6, pMessage, V_strlen(pMessage), &wrote );
  779. return;
  780. }
  781. // NOTE: SYS_TTYP13 is taken by vxconsole
  782. COMPILE_TIME_ASSERT( SYS_TTYP13 == 13 );
  783. #endif
  784. bool suppress = g_bInSpew ? true : false;
  785. g_bInSpew = true;
  786. AddSpewRecord( pMessage );
  787. if ( !suppress )
  788. {
  789. // If this is a dedicated server, then we have taken over its spew function, but we still
  790. // want its vgui console to show the spew, so pass it into the dedicated server.
  791. if ( dedicated )
  792. {
  793. if ( ! IsChildProcess() ) // do NOT let subprocesses output to stdout.
  794. {
  795. // This is not actually a varargs-style printf function; it simply takes a char*
  796. dedicated->Sys_Printf( (char *) pMessage ); // stupid header has char * instead of const char *
  797. }
  798. else
  799. {
  800. #ifdef _LINUX
  801. SendStringToParentProcess( va( "#%02d:%s", g_nForkID, pMessage ) );
  802. #endif
  803. }
  804. }
  805. #ifndef _CERT
  806. if ( g_bTextMode )
  807. {
  808. printf( "%s", pMessage );
  809. }
  810. #endif
  811. Color spewColor = pContext->m_Color;
  812. switch ( pContext->m_Severity )
  813. {
  814. #ifndef DEDICATED
  815. case LS_MESSAGE:
  816. if ( pContext->m_Color == UNSPECIFIED_LOGGING_COLOR )
  817. {
  818. #if !defined( _X360 )
  819. spewColor.SetColor( 255, 255, 255, 255 );
  820. #else
  821. spewColor.SetColor( 0, 0, 0, 255 );
  822. #endif
  823. }
  824. break;
  825. case LS_WARNING:
  826. spewColor.SetColor( 255, 90, 90, 255 );
  827. break;
  828. case LS_ASSERT:
  829. spewColor.SetColor( 255, 20, 20, 255 );
  830. break;
  831. case LS_ERROR:
  832. spewColor.SetColor( 20, 70, 255, 255 );
  833. break;
  834. #endif
  835. }
  836. Con_ColorPrintf( spewColor, "%s", pMessage );
  837. }
  838. g_bInSpew = false;
  839. if ( pContext->m_Severity == LS_ERROR )
  840. {
  841. Sys_Error( "%s", pMessage );
  842. }
  843. }
  844. };
  845. static CEngineConsoleLoggingListener s_EngineLoggingListener;
  846. static CFileLoggingListener s_FileLoggingListener;
  847. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CFileLoggingListener, IFileLoggingListener, FILELOGGINGLISTENER_INTERFACE_VERSION, s_FileLoggingListener );
  848. void DeveloperChangeCallback( IConVar *pConVar, const char *pOldString, float flOldValue )
  849. {
  850. // Set the "developer" spew group to the value...
  851. ConVarRef var( pConVar );
  852. int val = var.GetInt();
  853. LoggingSystem_SetChannelSpewLevelByTag( "Developer", val >= 1 ? LS_MESSAGE : LS_ERROR );
  854. LoggingSystem_SetChannelSpewLevelByTag( "DeveloperVerbose", val >= 2 ? LS_MESSAGE : LS_ERROR );
  855. }
  856. //-----------------------------------------------------------------------------
  857. // Purpose: factory comglomerator, gets the client, server, and gameui dlls together
  858. //-----------------------------------------------------------------------------
  859. void *GameFactory( const char *pName, int *pReturnCode )
  860. {
  861. void *pRetVal = NULL;
  862. // first ask the app factory
  863. pRetVal = g_AppSystemFactory( pName, pReturnCode );
  864. if (pRetVal)
  865. return pRetVal;
  866. // ask matchmaking
  867. extern CreateInterfaceFn g_pfnMatchmakingFactory;
  868. pRetVal = g_pfnMatchmakingFactory( pName, pReturnCode );
  869. if (pRetVal)
  870. return pRetVal;
  871. #ifndef DEDICATED
  872. // now ask the client dll
  873. if (ClientDLL_GetFactory())
  874. {
  875. pRetVal = ClientDLL_GetFactory()( pName, pReturnCode );
  876. if (pRetVal)
  877. return pRetVal;
  878. }
  879. // gameui.dll
  880. if (EngineVGui()->GetGameUIFactory())
  881. {
  882. pRetVal = EngineVGui()->GetGameUIFactory()( pName, pReturnCode );
  883. if (pRetVal)
  884. return pRetVal;
  885. }
  886. #endif
  887. // server dll factory access would go here when needed
  888. // ask vjobs
  889. #ifdef ENGINE_MANAGES_VJOBS
  890. extern CreateInterfaceFn g_pfnVjobsFactory;
  891. pRetVal = g_pfnVjobsFactory( pName, pReturnCode );
  892. if( pRetVal )
  893. return pRetVal;
  894. #endif
  895. return NULL;
  896. }
  897. // factory instance
  898. CreateInterfaceFn g_GameSystemFactory = GameFactory;
  899. //-----------------------------------------------------------------------------
  900. // Purpose:
  901. // Input : *lpOrgCmdLine -
  902. // launcherFactory -
  903. // *pwnd -
  904. // bIsDedicated -
  905. // Output : int
  906. //-----------------------------------------------------------------------------
  907. int Sys_InitGame( CreateInterfaceFn appSystemFactory, const char* pBaseDir, void *pwnd, int bIsDedicated )
  908. {
  909. #ifdef BENCHMARK
  910. if ( bIsDedicated )
  911. {
  912. Error( "Dedicated server isn't supported by this benchmark!" );
  913. }
  914. #endif
  915. extern void InitMathlib( void );
  916. InitMathlib();
  917. FileSystem_SetWhitelistSpewFlags();
  918. // Activate console, non-dev spew
  919. // Must happen before developer.InstallChangeCallback because that callback may reset it
  920. LoggingSystem_SetChannelSpewLevelByTag( "Console", LS_MESSAGE );
  921. LoggingSystem_PushLoggingState();
  922. LoggingSystem_RegisterLoggingListener( &s_EngineLoggingListener );
  923. LoggingSystem_RegisterLoggingListener( &s_FileLoggingListener );
  924. // Install debug spew output....
  925. developer.InstallChangeCallback( DeveloperChangeCallback );
  926. // Assume failure
  927. host_initialized = false;
  928. // Grab main window pointer
  929. pmainwindow = (HWND *)pwnd;
  930. // Remember that this is a dedicated server
  931. s_bIsDedicated = bIsDedicated ? true : false;
  932. memset( &gmodinfo, 0, sizeof( modinfo_t ) );
  933. static char s_pBaseDir[256];
  934. Q_strncpy( s_pBaseDir, pBaseDir, sizeof( s_pBaseDir ) );
  935. Q_strlower( s_pBaseDir );
  936. Q_FixSlashes( s_pBaseDir );
  937. host_parms.basedir = s_pBaseDir;
  938. #ifdef LINUX
  939. if ( CommandLine()->FindParm ( "-pidfile" ) )
  940. {
  941. FileHandle_t pidFile = g_pFileSystem->Open( CommandLine()->ParmValue ( "-pidfile", "srcds.pid" ), "w+" );
  942. if ( pidFile )
  943. {
  944. char dir[MAX_PATH];
  945. getcwd( dir, sizeof(dir) );
  946. g_pFileSystem->FPrintf( pidFile, "%i\n", getpid() );
  947. g_pFileSystem->Close(pidFile);
  948. }
  949. else
  950. {
  951. Warning("Unable to open pidfile (%s)\n", CommandLine()->CheckParm ( "-pidfile" ));
  952. }
  953. }
  954. #endif
  955. // Initialize clock
  956. TRACEINIT( Sys_Init(), Sys_Shutdown() );
  957. #if defined(_DEBUG)
  958. if ( IsPC() )
  959. {
  960. if( !CommandLine()->FindParm( "-nodttest" ) && !CommandLine()->FindParm( "-dti" ) )
  961. {
  962. RunDataTableTest();
  963. }
  964. }
  965. #endif
  966. // NOTE: Can't use COM_CheckParm here because it hasn't been set up yet.
  967. SeedRandomNumberGenerator( CommandLine()->FindParm( "-random_invariant" ) != 0 );
  968. TRACEINIT( Sys_InitMemory(), Sys_ShutdownMemory() );
  969. TRACEINIT( Host_Init( s_bIsDedicated ), Host_Shutdown() );
  970. if ( !host_initialized )
  971. {
  972. return 0;
  973. }
  974. TRACEINIT( Sys_InitAuthentication(), Sys_ShutdownAuthentication() );
  975. MapReslistGenerator_BuildMapList();
  976. #if !defined(NO_STEAM) && !defined(DEDICATED) && !defined(LINUX)
  977. Status_Update();
  978. BuildMinidumpComment( NULL );
  979. #endif
  980. return 1;
  981. }
  982. //-----------------------------------------------------------------------------
  983. // Purpose:
  984. //-----------------------------------------------------------------------------
  985. void Sys_ShutdownGame( void )
  986. {
  987. TRACESHUTDOWN( Sys_ShutdownAuthentication() );
  988. TRACESHUTDOWN( Host_Shutdown() );
  989. TRACESHUTDOWN( Sys_ShutdownMemory() );
  990. // TRACESHUTDOWN( Sys_ShutdownArgv() );
  991. TRACESHUTDOWN( Sys_Shutdown() );
  992. // Remove debug spew output....
  993. developer.RemoveChangeCallback( DeveloperChangeCallback );
  994. LoggingSystem_PopLoggingState();
  995. }
  996. //
  997. // Try to load a single DLL. If it conforms to spec, keep it loaded, and add relevant
  998. // info to the DLL directory. If not, ignore it entirely.
  999. //
  1000. CreateInterfaceFn g_ServerFactory;
  1001. static bool LoadThisDll( char *szDllFilename, bool bServerOnly )
  1002. {
  1003. CSysModule *pDLL = NULL;
  1004. // check signature, don't let users with modified binaries connect to secure servers, they will get VAC banned
  1005. if ( !bServerOnly && !Host_AllowLoadModule( szDllFilename, "GAMEBIN", false ) )
  1006. {
  1007. // not supposed to load this but we will anyway
  1008. Host_DisallowSecureServers();
  1009. }
  1010. // Load DLL, ignore if cannot
  1011. // ensures that the game.dll is running under Steam
  1012. // this will have to be undone when we want mods to be able to run
  1013. if ((pDLL = g_pFileSystem->LoadModule(szDllFilename, "GAMEBIN", false)) == NULL)
  1014. {
  1015. ConMsg("Failed to load %s\n", szDllFilename);
  1016. goto IgnoreThisDLL;
  1017. }
  1018. // Load interface factory and any interfaces exported by the game .dll
  1019. g_ServerFactory = Sys_GetFactory( pDLL );
  1020. if ( g_ServerFactory )
  1021. {
  1022. g_bServerGameDLLGreaterThanV5 = true;
  1023. serverGameDLL = (IServerGameDLL*)g_ServerFactory(INTERFACEVERSION_SERVERGAMEDLL, NULL);
  1024. if ( !serverGameDLL )
  1025. {
  1026. #ifdef REL_TO_STAGING_MERGE_TODO
  1027. // Need to merge eiface for this.
  1028. // g_bServerGameDLLGreaterThanV5 is true, so we get better stringtables
  1029. g_bServerGameDLLGreaterThanV5 = true;
  1030. serverGameDLL = (IServerGameDLL*)g_ServerFactory(INTERFACEVERSION_SERVERGAMEDLL_VERSION_5, NULL);
  1031. #endif
  1032. if ( !serverGameDLL )
  1033. {
  1034. Msg( "Could not get IServerGameDLL interface from library %s", szDllFilename );
  1035. goto IgnoreThisDLL;
  1036. }
  1037. }
  1038. serverGameEnts = (IServerGameEnts*)g_ServerFactory(INTERFACEVERSION_SERVERGAMEENTS, NULL);
  1039. if ( !serverGameEnts )
  1040. {
  1041. ConMsg( "Could not get IServerGameEnts interface from library %s", szDllFilename );
  1042. goto IgnoreThisDLL;
  1043. }
  1044. serverGameClients = (IServerGameClients*)g_ServerFactory(INTERFACEVERSION_SERVERGAMECLIENTS, NULL);
  1045. if ( serverGameClients )
  1046. {
  1047. g_iServerGameClientsVersion = 4;
  1048. }
  1049. else
  1050. {
  1051. // Try the previous version.
  1052. const char *pINTERFACEVERSION_SERVERGAMECLIENTS_V3 = "ServerGameClients003";
  1053. serverGameClients = (IServerGameClients*)g_ServerFactory(pINTERFACEVERSION_SERVERGAMECLIENTS_V3, NULL);
  1054. if ( serverGameClients )
  1055. {
  1056. g_iServerGameClientsVersion = 3;
  1057. }
  1058. else
  1059. {
  1060. ConMsg( "Could not get IServerGameClients interface from library %s", szDllFilename );
  1061. goto IgnoreThisDLL;
  1062. }
  1063. }
  1064. serverGameDirector = (IHLTVDirector*)g_ServerFactory(INTERFACEVERSION_HLTVDIRECTOR, NULL);
  1065. if ( !serverGameDirector )
  1066. {
  1067. ConMsg( "Could not get IHLTVDirector interface from library %s", szDllFilename );
  1068. // this is not a critical
  1069. }
  1070. serverReplayDirector = (IReplayDirector*)g_ServerFactory(INTERFACEVERSION_REPLAYDIRECTOR, NULL);
  1071. if ( !serverReplayDirector )
  1072. {
  1073. ConMsg( "Could not get IReplayDirector interface from library %s", szDllFilename );
  1074. // this is not a critical
  1075. }
  1076. serverGameTags = (IServerGameTags*)g_ServerFactory(INTERFACEVERSION_SERVERGAMETAGS, NULL);
  1077. // Possible that this is NULL - optional interface
  1078. }
  1079. else
  1080. {
  1081. ConMsg( "Could not find factory interface in library %s", szDllFilename );
  1082. goto IgnoreThisDLL;
  1083. }
  1084. g_GameDLL = pDLL;
  1085. return true;
  1086. IgnoreThisDLL:
  1087. if (pDLL != NULL)
  1088. {
  1089. g_pFileSystem->UnloadModule(pDLL);
  1090. serverGameDLL = NULL;
  1091. serverGameEnts = NULL;
  1092. serverGameClients = NULL;
  1093. }
  1094. return false;
  1095. }
  1096. //
  1097. // Scan DLL directory, load all DLLs that conform to spec.
  1098. //
  1099. void LoadEntityDLLs( const char *szBaseDir, bool bServerOnly )
  1100. {
  1101. memset( &gmodinfo, 0, sizeof( modinfo_t ) );
  1102. gmodinfo.version = 1;
  1103. gmodinfo.svonly = true;
  1104. // Run through all DLLs found in the extension DLL directory
  1105. g_GameDLL = NULL;
  1106. sv_noclipduringpause = NULL;
  1107. // Listing file for this game.
  1108. KeyValues *modinfo = new KeyValues("modinfo");
  1109. if (modinfo->LoadFromFile(g_pFileSystem, "gameinfo.txt"))
  1110. {
  1111. Q_strncpy( gmodinfo.szInfo, modinfo->GetString("url_info"), sizeof( gmodinfo.szInfo ) );
  1112. Q_strncpy( gmodinfo.szDL, modinfo->GetString("url_dl"), sizeof( gmodinfo.szDL ) );
  1113. gmodinfo.version = modinfo->GetInt("version");
  1114. gmodinfo.size = modinfo->GetInt("size");
  1115. gmodinfo.svonly = modinfo->GetBool("svonly");
  1116. gmodinfo.cldll = modinfo->GetBool("cldll");
  1117. Q_strncpy( gmodinfo.szHLVersion, modinfo->GetString("hlversion"), sizeof( gmodinfo.szHLVersion ) );
  1118. }
  1119. modinfo->deleteThis();
  1120. // Load the game .dll
  1121. char szDllFilename[ MAX_PATH ];
  1122. #if defined( _WIN32 )
  1123. // [mpritchar] cstrike15 - we now look for server_valve.dll { Valve's datacenter specific version of server }
  1124. // first and load it if we find it, otherwise load server.dll
  1125. if ( s_bIsDedicatedServer && !CommandLine()->FindParm( "-novalveds" ) )
  1126. {
  1127. Q_snprintf( szDllFilename, sizeof( szDllFilename ), "server_valve" DLL_EXT_STRING );
  1128. LoadThisDll( szDllFilename, bServerOnly );
  1129. }
  1130. if ( !serverGameDLL )
  1131. {
  1132. Q_snprintf( szDllFilename, sizeof( szDllFilename ), "server" DLL_EXT_STRING );
  1133. LoadThisDll( szDllFilename, bServerOnly );
  1134. }
  1135. #elif defined( _PS3 )
  1136. Q_snprintf( szDllFilename, sizeof( szDllFilename ), "server" DLL_EXT_STRING );
  1137. LoadThisDll( szDllFilename, bServerOnly );
  1138. #elif defined( LINUX )
  1139. if ( s_bIsDedicatedServer && !CommandLine()->FindParm( "-novalveds" ) )
  1140. {
  1141. Q_snprintf( szDllFilename, sizeof( szDllFilename ), "server_valve" );
  1142. LoadThisDll( szDllFilename, bServerOnly );
  1143. }
  1144. if ( !serverGameDLL )
  1145. {
  1146. Q_snprintf( szDllFilename, sizeof( szDllFilename ), "server" );
  1147. LoadThisDll( szDllFilename, bServerOnly );
  1148. }
  1149. #elif defined( POSIX )
  1150. Q_snprintf( szDllFilename, sizeof( szDllFilename ), "server" );
  1151. LoadThisDll( szDllFilename, bServerOnly );
  1152. #else
  1153. #error "define server.dll type"
  1154. #endif
  1155. if ( serverGameDLL )
  1156. {
  1157. Msg("Game.dll loaded for \"%s\"\n", (char *)serverGameDLL->GetGameDescription());
  1158. }
  1159. }
  1160. //-----------------------------------------------------------------------------
  1161. // Purpose: Retrieves a string value from the registry
  1162. //-----------------------------------------------------------------------------
  1163. #if defined(_WIN32)
  1164. void Sys_GetRegKeyValueUnderRoot( HKEY rootKey, const char *pszSubKey, const char *pszElement, char *pszReturnString, int nReturnLength, const char *pszDefaultValue )
  1165. {
  1166. LONG lResult; // Registry function result code
  1167. HKEY hKey; // Handle of opened/created key
  1168. char szBuff[128]; // Temp. buffer
  1169. ULONG dwDisposition; // Type of key opening event
  1170. DWORD dwType; // Type of key
  1171. DWORD dwSize; // Size of element data
  1172. // Assume the worst
  1173. Q_strncpy(pszReturnString, pszDefaultValue, nReturnLength );
  1174. // Create it if it doesn't exist. (Create opens the key otherwise)
  1175. lResult = RegCreateKeyEx(
  1176. rootKey, // handle of open key
  1177. pszSubKey, // address of name of subkey to open
  1178. 0ul, // DWORD ulOptions, // reserved
  1179. "String", // Type of value
  1180. REG_OPTION_NON_VOLATILE, // Store permanently in reg.
  1181. KEY_ALL_ACCESS, // REGSAM samDesired, // security access mask
  1182. NULL,
  1183. &hKey, // Key we are creating
  1184. &dwDisposition); // Type of creation
  1185. if (lResult != ERROR_SUCCESS) // Failure
  1186. return;
  1187. // First time, just set to Valve default
  1188. if (dwDisposition == REG_CREATED_NEW_KEY)
  1189. {
  1190. // Just Set the Values according to the defaults
  1191. lResult = RegSetValueEx( hKey, pszElement, 0, REG_SZ, (CONST BYTE *)pszDefaultValue, Q_strlen(pszDefaultValue) + 1 );
  1192. }
  1193. else
  1194. {
  1195. // We opened the existing key. Now go ahead and find out how big the key is.
  1196. dwSize = nReturnLength;
  1197. lResult = RegQueryValueEx( hKey, pszElement, 0, &dwType, (unsigned char *)szBuff, &dwSize );
  1198. // Success?
  1199. if (lResult == ERROR_SUCCESS)
  1200. {
  1201. // Only copy strings, and only copy as much data as requested.
  1202. if (dwType == REG_SZ)
  1203. {
  1204. Q_strncpy(pszReturnString, szBuff, nReturnLength);
  1205. pszReturnString[nReturnLength - 1] = '\0';
  1206. }
  1207. }
  1208. else
  1209. // Didn't find it, so write out new value
  1210. {
  1211. // Just Set the Values according to the defaults
  1212. lResult = RegSetValueEx( hKey, pszElement, 0, REG_SZ, (CONST BYTE *)pszDefaultValue, Q_strlen(pszDefaultValue) + 1 );
  1213. }
  1214. };
  1215. // Always close this key before exiting.
  1216. RegCloseKey(hKey);
  1217. }
  1218. //-----------------------------------------------------------------------------
  1219. // Purpose: Retrieves a DWORD value from the registry
  1220. //-----------------------------------------------------------------------------
  1221. void Sys_GetRegKeyValueUnderRootInt( HKEY rootKey, const char *pszSubKey, const char *pszElement, long *plReturnValue, const long lDefaultValue )
  1222. {
  1223. LONG lResult; // Registry function result code
  1224. HKEY hKey; // Handle of opened/created key
  1225. ULONG dwDisposition; // Type of key opening event
  1226. DWORD dwType; // Type of key
  1227. DWORD dwSize; // Size of element data
  1228. // Assume the worst
  1229. // Set the return value to the default
  1230. *plReturnValue = lDefaultValue;
  1231. // Create it if it doesn't exist. (Create opens the key otherwise)
  1232. lResult = RegCreateKeyEx(
  1233. rootKey, // handle of open key
  1234. pszSubKey, // address of name of subkey to open
  1235. 0ul, // DWORD ulOptions, // reserved
  1236. "String", // Type of value
  1237. REG_OPTION_NON_VOLATILE, // Store permanently in reg.
  1238. KEY_ALL_ACCESS, // REGSAM samDesired, // security access mask
  1239. NULL,
  1240. &hKey, // Key we are creating
  1241. &dwDisposition); // Type of creation
  1242. if (lResult != ERROR_SUCCESS) // Failure
  1243. return;
  1244. // First time, just set to Valve default
  1245. if (dwDisposition == REG_CREATED_NEW_KEY)
  1246. {
  1247. // Just Set the Values according to the defaults
  1248. lResult = RegSetValueEx( hKey, pszElement, 0, REG_DWORD, (CONST BYTE *)&lDefaultValue, sizeof( DWORD ) );
  1249. }
  1250. else
  1251. {
  1252. // We opened the existing key. Now go ahead and find out how big the key is.
  1253. dwSize = sizeof( DWORD );
  1254. lResult = RegQueryValueEx( hKey, pszElement, 0, &dwType, (unsigned char *)plReturnValue, &dwSize );
  1255. // Success?
  1256. if (lResult != ERROR_SUCCESS)
  1257. // Didn't find it, so write out new value
  1258. {
  1259. // Just Set the Values according to the defaults
  1260. lResult = RegSetValueEx( hKey, pszElement, 0, REG_DWORD, (LPBYTE)&lDefaultValue, sizeof( DWORD ) );
  1261. }
  1262. };
  1263. // Always close this key before exiting.
  1264. RegCloseKey(hKey);
  1265. }
  1266. void Sys_SetRegKeyValueUnderRoot( HKEY rootKey, const char *pszSubKey, const char *pszElement, const char *pszValue )
  1267. {
  1268. LONG lResult; // Registry function result code
  1269. HKEY hKey; // Handle of opened/created key
  1270. //char szBuff[128]; // Temp. buffer
  1271. ULONG dwDisposition; // Type of key opening event
  1272. //DWORD dwType; // Type of key
  1273. //DWORD dwSize; // Size of element data
  1274. // Create it if it doesn't exist. (Create opens the key otherwise)
  1275. lResult = RegCreateKeyEx(
  1276. rootKey, // handle of open key
  1277. pszSubKey, // address of name of subkey to open
  1278. 0ul, // DWORD ulOptions, // reserved
  1279. "String", // Type of value
  1280. REG_OPTION_NON_VOLATILE, // Store permanently in reg.
  1281. KEY_ALL_ACCESS, // REGSAM samDesired, // security access mask
  1282. NULL,
  1283. &hKey, // Key we are creating
  1284. &dwDisposition); // Type of creation
  1285. if (lResult != ERROR_SUCCESS) // Failure
  1286. return;
  1287. // First time, just set to Valve default
  1288. if (dwDisposition == REG_CREATED_NEW_KEY)
  1289. {
  1290. // Just Set the Values according to the defaults
  1291. lResult = RegSetValueEx( hKey, pszElement, 0, REG_SZ, (CONST BYTE *)pszValue, Q_strlen(pszValue) + 1 );
  1292. }
  1293. else
  1294. {
  1295. /*
  1296. // FIXE: We might want to support a mode where we only create this key, we don't overwrite values already present
  1297. // We opened the existing key. Now go ahead and find out how big the key is.
  1298. dwSize = nReturnLength;
  1299. lResult = RegQueryValueEx( hKey, pszElement, 0, &dwType, (unsigned char *)szBuff, &dwSize );
  1300. // Success?
  1301. if (lResult == ERROR_SUCCESS)
  1302. {
  1303. // Only copy strings, and only copy as much data as requested.
  1304. if (dwType == REG_SZ)
  1305. {
  1306. Q_strncpy(pszReturnString, szBuff, nReturnLength);
  1307. pszReturnString[nReturnLength - 1] = '\0';
  1308. }
  1309. }
  1310. else
  1311. */
  1312. // Didn't find it, so write out new value
  1313. {
  1314. // Just Set the Values according to the defaults
  1315. lResult = RegSetValueEx( hKey, pszElement, 0, REG_SZ, (CONST BYTE *)pszValue, Q_strlen(pszValue) + 1 );
  1316. }
  1317. };
  1318. // Always close this key before exiting.
  1319. RegCloseKey(hKey);
  1320. }
  1321. #endif
  1322. void Sys_GetRegKeyValue( char *pszSubKey, char *pszElement, char *pszReturnString, int nReturnLength, char *pszDefaultValue )
  1323. {
  1324. #if defined(_WIN32)
  1325. Sys_GetRegKeyValueUnderRoot( HKEY_CURRENT_USER, pszSubKey, pszElement, pszReturnString, nReturnLength, pszDefaultValue );
  1326. #else
  1327. //hushed Assert( !"Impl me" );
  1328. Q_strncpy( pszReturnString, pszDefaultValue, nReturnLength );
  1329. #endif
  1330. }
  1331. void Sys_GetRegKeyValueInt( char *pszSubKey, char *pszElement, long *plReturnValue, long lDefaultValue)
  1332. {
  1333. #if defined(_WIN32)
  1334. Sys_GetRegKeyValueUnderRootInt( HKEY_CURRENT_USER, pszSubKey, pszElement, plReturnValue, lDefaultValue );
  1335. #else
  1336. //hushed Assert( !"Impl me" );
  1337. *plReturnValue = lDefaultValue;
  1338. #endif
  1339. }
  1340. void Sys_SetRegKeyValue( char *pszSubKey, char *pszElement, const char *pszValue )
  1341. {
  1342. #if defined(_WIN32)
  1343. Sys_SetRegKeyValueUnderRoot( HKEY_CURRENT_USER, pszSubKey, pszElement, pszValue );
  1344. #else
  1345. //hushed Assert( !"Impl me" );
  1346. #endif
  1347. }
  1348. #define SOURCE_ENGINE_APP_CLASS "Valve.Source"
  1349. void Sys_CreateFileAssociations( int count, FileAssociationInfo *list )
  1350. {
  1351. #if defined(_WIN32)
  1352. if ( IsX360() )
  1353. return;
  1354. char appname[ 512 ];
  1355. GetModuleFileName( 0, appname, sizeof( appname ) );
  1356. Q_FixSlashes( appname );
  1357. Q_strlower( appname );
  1358. char quoted_appname_with_arg[ 512 ];
  1359. Q_snprintf( quoted_appname_with_arg, sizeof( quoted_appname_with_arg ), "\"%s\" \"%%1\"", appname );
  1360. char base_exe_name[ 256 ];
  1361. Q_FileBase( appname, base_exe_name, sizeof( base_exe_name) );
  1362. Q_DefaultExtension( base_exe_name, ".exe", sizeof( base_exe_name ) );
  1363. // HKEY_CLASSES_ROOT/Valve.Source/shell/open/command == "u:\tf2\hl2.exe" "%1" quoted
  1364. Sys_SetRegKeyValueUnderRoot( HKEY_CLASSES_ROOT, va( "%s\\shell\\open\\command", SOURCE_ENGINE_APP_CLASS ), "", quoted_appname_with_arg );
  1365. // HKEY_CLASSES_ROOT/Applications/hl2.exe/shell/open/command == "u:\tf2\hl2.exe" "%1" quoted
  1366. Sys_SetRegKeyValueUnderRoot( HKEY_CLASSES_ROOT, va( "Applications\\%s\\shell\\open\\command", base_exe_name ), "", quoted_appname_with_arg );
  1367. for ( int i = 0; i < count ; i++ )
  1368. {
  1369. FileAssociationInfo *fa = &list[ i ];
  1370. char binding[32];
  1371. binding[0] = 0;
  1372. // Create file association for our .exe
  1373. // HKEY_CLASSES_ROOT/.dem == "Valve.Source"
  1374. Sys_GetRegKeyValueUnderRoot( HKEY_CLASSES_ROOT, fa->extension, "", binding, sizeof(binding), "" );
  1375. if ( Q_strlen( binding ) == 0 )
  1376. {
  1377. Sys_SetRegKeyValueUnderRoot( HKEY_CLASSES_ROOT, fa->extension, "", SOURCE_ENGINE_APP_CLASS );
  1378. }
  1379. }
  1380. #endif
  1381. }
  1382. void Sys_NoCrashDialog()
  1383. {
  1384. #if defined(_WIN32)
  1385. ::SetErrorMode(SetErrorMode(SEM_NOGPFAULTERRORBOX) | SEM_NOGPFAULTERRORBOX);
  1386. #endif
  1387. }
  1388. void Sys_TestSendKey( const char *pKey )
  1389. {
  1390. #if defined(_WIN32)
  1391. int key = pKey[0];
  1392. if ( pKey[0] == '\\' && pKey[1] == 'r' )
  1393. {
  1394. key = VK_RETURN;
  1395. }
  1396. HWND hWnd = (HWND)game->GetMainWindow();
  1397. PostMessageA( hWnd, WM_KEYDOWN, key, 0 );
  1398. PostMessageA( hWnd, WM_KEYUP, key, 0 );
  1399. //void Key_Event (int key, bool down);
  1400. //Key_Event( key, 1 );
  1401. //Key_Event( key, 0 );
  1402. #endif
  1403. }
  1404. void Sys_OutputDebugString(const char *msg)
  1405. {
  1406. Plat_DebugString( msg );
  1407. }
  1408. //-----------------------------------------------------------------------------
  1409. // Purpose:
  1410. //-----------------------------------------------------------------------------
  1411. void UnloadEntityDLLs( void )
  1412. {
  1413. if ( !g_GameDLL )
  1414. return;
  1415. // Unlink the cvars associated with game DLL
  1416. FileSystem_UnloadModule( g_GameDLL );
  1417. g_GameDLL = NULL;
  1418. serverGameDLL = NULL;
  1419. serverGameEnts = NULL;
  1420. serverGameClients = NULL;
  1421. sv_noclipduringpause = NULL;
  1422. }
  1423. CON_COMMAND( star_memory, "Dump memory stats" )
  1424. {
  1425. // get a current stat of available memory
  1426. // 32 MB is reserved and fixed by OS, so not reporting to allow memory loggers sync
  1427. #ifdef LINUX
  1428. struct mallinfo memstats = mallinfo( );
  1429. Msg( "sbrk size: %.2f MB, Used: %.2f MB, #mallocs = %d\n",
  1430. memstats.arena / ( 1024.0 * 1024.0), memstats.uordblks / ( 1024.0 * 1024.0 ), memstats.hblks );
  1431. #elif OSX
  1432. struct mstats memstats = mstats( );
  1433. Msg( "Available %.2f MB, Used: %.2f MB, #mallocs = %d\n",
  1434. memstats.bytes_free / ( 1024.0 * 1024.0), memstats.bytes_used / ( 1024.0 * 1024.0 ), memstats.chunks_used );
  1435. #elif defined( _PS3 )
  1436. Msg( "Memory info on PS3: not implemented.\n" );
  1437. #else
  1438. MEMORYSTATUSEX statex;
  1439. statex.dwLength = sizeof( MEMORYSTATUSEX );
  1440. GlobalMemoryStatusEx( &statex );
  1441. Msg( "Available: %.2f MB, Used: %.2f MB, Free: %.2f MB\n",
  1442. statex.ullTotalPhys/( 1024.0f*1024.0f ) - 32.0f,
  1443. ( statex.ullTotalPhys - statex.ullAvailPhys )/( 1024.0f*1024.0f ) - 32.0f,
  1444. statex.ullAvailPhys/( 1024.0f*1024.0f ) );
  1445. #endif
  1446. }
  1447. #if defined( ENABLE_RUNTIME_STACK_TRANSLATION )
  1448. //NOTE: These convars are here because they can't be directly in tier0.
  1449. // They're more like one-way convars in that they send off the changes, but might not have the same starting value as the actual value
  1450. // So if you change the defaults, change the defaults in tier0/dbg.cpp to match.
  1451. // I considered adding some callback functionality to reinforce the bond a bit better. But that seems hairy.
  1452. static void warningcallstacks_enable_callback( IConVar *var, const char *pOldValue, float flOldValue )
  1453. {
  1454. _Warning_AlwaysSpewCallStack_Enable( ((ConVar *)var)->GetBool() );
  1455. }
  1456. ConVar warningcallstacks_enable( "warningcallstacks_enable", "0", FCVAR_DEVELOPMENTONLY, "All Warning()/DevWarning()/... calls will attach a callstack", warningcallstacks_enable_callback );
  1457. static void warningcallstacks_length_callback( IConVar *var, const char *pOldValue, float flOldValue )
  1458. {
  1459. _Warning_AlwaysSpewCallStack_Length( ((ConVar *)var)->GetInt() );
  1460. }
  1461. ConVar warningcallstacks_length( "warningcallstacks_length", "5", FCVAR_DEVELOPMENTONLY, "Length of automatic warning callstacks", warningcallstacks_length_callback );
  1462. static void errorcallstacks_enable_callback( IConVar *var, const char *pOldValue, float flOldValue )
  1463. {
  1464. _Error_AlwaysSpewCallStack_Enable( ((ConVar *)var)->GetBool() );
  1465. }
  1466. ConVar errorcallstacks_enable( "errorcallstacks_enable", "0", FCVAR_DEVELOPMENTONLY, "All Error() calls will attach a callstack", errorcallstacks_enable_callback );
  1467. static void errorcallstacks_length_callback( IConVar *var, const char *pOldValue, float flOldValue )
  1468. {
  1469. _Error_AlwaysSpewCallStack_Length( ((ConVar *)var)->GetInt() );
  1470. }
  1471. ConVar errorcallstacks_length( "errorcallstacks_length", "20", FCVAR_DEVELOPMENTONLY, "Length of automatic error callstacks", errorcallstacks_length_callback );
  1472. #endif //#if defined( ENABLE_RUNTIME_STACK_TRANSLATION )