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.

3053 lines
80 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. // HACKHACK fix this include
  7. #if defined( _WIN32 ) && !defined( _X360 )
  8. #define WIN32_LEAN_AND_MEAN
  9. #include <windows.h>
  10. #endif
  11. #include "tier0/vprof.h"
  12. #include "server.h"
  13. #include "host_cmd.h"
  14. #include "keys.h"
  15. #include "screen.h"
  16. #include "vengineserver_impl.h"
  17. #include "host_saverestore.h"
  18. #include "sv_filter.h"
  19. #include "gl_matsysiface.h"
  20. #include "pr_edict.h"
  21. #include "world.h"
  22. #include "checksum_engine.h"
  23. #include "const.h"
  24. #include "sv_main.h"
  25. #include "host.h"
  26. #include "demo.h"
  27. #include "cdll_int.h"
  28. #include "networkstringtableserver.h"
  29. #include "networkstringtableclient.h"
  30. #include "host_state.h"
  31. #include "string_t.h"
  32. #include "tier0/dbg.h"
  33. #include "testscriptmgr.h"
  34. #include "r_local.h"
  35. #include "PlayerState.h"
  36. #include "enginesingleuserfilter.h"
  37. #include "profile.h"
  38. #include "protocol.h"
  39. #include "cl_main.h"
  40. #include "sv_steamauth.h"
  41. #include "zone.h"
  42. #include "GameEventManager.h"
  43. #include "datacache/idatacache.h"
  44. #include "sys_dll.h"
  45. #include "cmd.h"
  46. #include "tier0/icommandline.h"
  47. #include "filesystem.h"
  48. #include "filesystem_engine.h"
  49. #include "icliententitylist.h"
  50. #include "icliententity.h"
  51. #include "hltvserver.h"
  52. #if defined( REPLAY_ENABLED )
  53. #include "replayserver.h"
  54. #endif
  55. #include "cdll_engine_int.h"
  56. #include "cl_steamauth.h"
  57. #include "cl_splitscreen.h"
  58. #ifndef DEDICATED
  59. #include "vgui_baseui_interface.h"
  60. #endif
  61. #include "sound.h"
  62. #include "voice.h"
  63. #include "sv_rcon.h"
  64. #if defined( _X360 )
  65. #include "xbox/xbox_console.h"
  66. #include "xbox/xbox_launch.h"
  67. #elif defined( _PS3 )
  68. #include "ps3/ps3_console.h"
  69. #include "tls_ps3.h"
  70. #endif
  71. #include "filesystem/IQueuedLoader.h"
  72. #include "filesystem/IXboxInstaller.h"
  73. #include "toolframework/itoolframework.h"
  74. #include "fmtstr.h"
  75. #include "tier3/tier3.h"
  76. #include "matchmaking/imatchframework.h"
  77. #include "tier2/tier2.h"
  78. #include "shaderapi/gpumemorystats.h"
  79. #include "snd_audio_source.h"
  80. #include "netconsole.h"
  81. #include "tier2/fileutils.h"
  82. #if POSIX
  83. #include <sys/types.h>
  84. #include <sys/wait.h>
  85. #include <sys/syscall.h>
  86. #include <sys/stat.h>
  87. #include <fcntl.h>
  88. #endif
  89. #include "ixboxsystem.h"
  90. extern IXboxSystem *g_pXboxSystem;
  91. extern IVEngineClient *engineClient;
  92. // memdbgon must be the last include file in a .cpp file!!!
  93. #include "tier0/memdbgon.h"
  94. #define STEAM_PREFIX "STEAM_"
  95. #ifndef DEDICATED
  96. bool g_bInEditMode = false;
  97. bool g_bInCommentaryMode = false;
  98. #endif
  99. KeyValues *g_pLaunchOptions = NULL;
  100. void PerformKick( cmd_source_t commandSource, int iSearchIndex, char* szSearchString, bool bForceKick, const char* pszMessage );
  101. ConVar host_name_store( "host_name_store", "1", FCVAR_RELEASE, "Whether hostname is recorded in game events and GOTV." );
  102. ConVar host_players_show( "host_players_show", "1", FCVAR_RELEASE, "How players are disclosed in server queries: 0 - query disabled, 1 - show only max players count, 2 - show all players" );
  103. ConVar host_info_show( "host_info_show", "1", FCVAR_RELEASE, "How server info gets disclosed in server queries: 0 - query disabled, 1 - show only general info, 2 - show full info" );
  104. ConVar host_rules_show( "host_rules_show", "1", FCVAR_RELEASE, "How server rules get disclosed in server queries: 0 - query disabled, 1 - query enabled" );
  105. static void HostnameChanged( IConVar *pConVar, const char *pOldValue, float flOldValue )
  106. {
  107. Steam3Server().NotifyOfServerNameChange();
  108. if ( sv.IsActive() && host_name_store.GetBool() )
  109. {
  110. // look up the descriptor first to avoid a DevMsg for HL2 and mods that don't define a
  111. // hostname_change event
  112. CGameEventDescriptor *descriptor = g_GameEventManager.GetEventDescriptor( "hostname_changed" );
  113. if ( descriptor )
  114. {
  115. IGameEvent *event = g_GameEventManager.CreateEvent( "hostname_changed" );
  116. if ( event )
  117. {
  118. ConVarRef var( pConVar );
  119. event->SetString( "hostname", var.GetString() );
  120. g_GameEventManager.FireEvent( event );
  121. }
  122. }
  123. }
  124. }
  125. ConVar host_name( "hostname", "", FCVAR_RELEASE, "Hostname for server.", false, 0.0f, false, 0.0f, HostnameChanged );
  126. ConVar host_map( "host_map", "", FCVAR_RELEASE, "Current map name." );
  127. bool CanShowHostTvStatus()
  128. {
  129. if ( !serverGameDLL )
  130. return true;
  131. if ( serverGameDLL->IsValveDS() )
  132. {
  133. // By default OFFICIAL server will NOT print TV information in "status" output
  134. // Running with -display_tv_status will reveal GOTV information
  135. static bool s_bCanShowHostTvStatusOFFICIAL = !!CommandLine()->FindParm( "-display_tv_status" );
  136. return s_bCanShowHostTvStatusOFFICIAL;
  137. }
  138. else
  139. {
  140. // By default COMMUNITY server will print TV information in "status" output
  141. // Running with -disable_tv_status will conceal GOTV information
  142. static bool s_bCanShowHostTvStatusCOMMUNITY = !CommandLine()->FindParm( "-disable_tv_status" );
  143. return s_bCanShowHostTvStatusCOMMUNITY;
  144. }
  145. }
  146. #ifdef _PS3
  147. ConVar ps3_host_quit_graceperiod( "ps3_host_quit_graceperiod", "7", FCVAR_DEVELOPMENTONLY, "Time granted for save operations to finish" );
  148. ConVar ps3_host_quit_debugpause( "ps3_host_quit_debugpause", "0", FCVAR_DEVELOPMENTONLY, "Time to stall quit for debug purposes" );
  149. #endif
  150. ConVar voice_recordtofile("voice_recordtofile", "0", FCVAR_RELEASE, "Record mic data and decompressed voice data into 'voice_micdata.wav' and 'voice_decompressed.wav'");
  151. ConVar voice_inputfromfile("voice_inputfromfile", "0",FCVAR_RELEASE, "Get voice input from 'voice_input.wav' rather than from the microphone.");
  152. uint GetSteamAppID()
  153. {
  154. #ifndef DEDICATED
  155. if ( Steam3Client().SteamUtils() )
  156. return Steam3Client().SteamUtils()->GetAppID();
  157. #endif
  158. if ( Steam3Server().SteamGameServerUtils() )
  159. return Steam3Server().SteamGameServerUtils()->GetAppID();
  160. return 215; // defaults to Source SDK Base (215) if no steam.inf can be found.
  161. }
  162. EUniverse GetSteamUniverse()
  163. {
  164. #ifndef DEDICATED
  165. if ( Steam3Client().SteamUtils() )
  166. return Steam3Client().SteamUtils()->GetConnectedUniverse();
  167. #endif
  168. if ( Steam3Server().SteamGameServerUtils() )
  169. return Steam3Server().SteamGameServerUtils()->GetConnectedUniverse();
  170. return k_EUniverseInvalid;
  171. }
  172. // Globals
  173. int gHostSpawnCount = 0;
  174. // If any quit handlers balk, then aborts quit sequence
  175. bool EngineTool_CheckQuitHandlers();
  176. #if defined( _GAMECONSOLE )
  177. void Host_Quit_f (void);
  178. void PS3_sysutil_callback_forwarder( uint64 uiStatus, uint64 uiParam );
  179. void Quit_gameconsole_f( bool bWarmRestart, bool bUnused )
  180. {
  181. #if defined( _DEMO )
  182. if ( Host_IsDemoExiting() )
  183. {
  184. // for safety, only want to play this under demo exit conditions
  185. // which guaranteed us a safe exiting context
  186. game->PlayVideoListAndWait( "media/DemoUpsellVids.txt" );
  187. }
  188. #endif
  189. #if defined( _X360 ) && defined( _DEMO )
  190. // demo version has to support variants of the launch structures
  191. // demo version must reply with exact demo launch structure if provided
  192. unsigned int launchID;
  193. int launchSize;
  194. void *pLaunchData;
  195. bool bValid = XboxLaunch()->GetLaunchData( &launchID, &pLaunchData, &launchSize );
  196. if ( bValid && Host_IsDemoHostedFromShell() )
  197. {
  198. XboxLaunch()->SetLaunchData( pLaunchData, launchSize, LF_UNKNOWNDATA );
  199. g_pMaterialSystem->PersistDisplay();
  200. XBX_DisconnectConsoleMonitor();
  201. const char *pImageName = XLAUNCH_KEYWORD_DEFAULT_APP;
  202. if ( launchID == LAUNCH_DATA_DEMO_ID )
  203. {
  204. pImageName = ((LD_DEMO*)pLaunchData)->szLauncherXEX;
  205. }
  206. XboxLaunch()->Launch( pImageName );
  207. return;
  208. }
  209. #endif
  210. #ifdef _X360
  211. // must be first, will cause a reset of the launch if we have never been re-launched
  212. // all further XboxLaunch() operations MUST be writes, otherwise reset
  213. int launchFlags = LF_EXITFROMGAME;
  214. // block until the installer stops
  215. g_pXboxInstaller->IsStopped( true );
  216. if ( g_pXboxInstaller->IsFullyInstalled() )
  217. {
  218. launchFlags |= LF_INSTALLEDTOCACHE;
  219. }
  220. // allocate the full payload
  221. int nPayloadSize = XboxLaunch()->MaxPayloadSize();
  222. byte *pPayload = (byte *)stackalloc( nPayloadSize );
  223. V_memset( pPayload, 0, sizeof( nPayloadSize ) );
  224. // payload is at least the command line
  225. // any user data needed must be placed AFTER the command line
  226. const char *pCmdLine = CommandLine()->GetCmdLine();
  227. int nCmdLineLength = (int)strlen( pCmdLine ) + 1;
  228. V_memcpy( pPayload, pCmdLine, min( nPayloadSize, nCmdLineLength ) );
  229. // add any other data here to payload, after the command line
  230. // ...
  231. // Collect settings to preserve across restarts
  232. int numGameUsers = XBX_GetNumGameUsers();
  233. char slot2ctrlr[4];
  234. char slot2guest[4];
  235. int ctrlr2storage[4];
  236. for ( int k = 0; k < 4; ++ k )
  237. {
  238. slot2ctrlr[k] = (char) XBX_GetUserId( k );
  239. slot2guest[k] = (char) XBX_GetUserIsGuest( k );
  240. ctrlr2storage[k] = XBX_GetStorageDeviceId( k );
  241. }
  242. // storage device may have changed since previous launch
  243. XboxLaunch()->SetStorageID( ctrlr2storage );
  244. // Close the storage devices
  245. g_pXboxSystem->CloseAllContainers();
  246. DWORD nUserID = XBX_GetPrimaryUserId();
  247. XboxLaunch()->SetUserID( nUserID );
  248. XboxLaunch()->SetSlotUsers( numGameUsers, slot2ctrlr, slot2guest );
  249. if ( bWarmRestart )
  250. {
  251. // a restart is an attempt at a hidden reboot-in-place
  252. launchFlags |= LF_WARMRESTART;
  253. }
  254. // set our own data and relaunch self
  255. bool bLaunch = XboxLaunch()->SetLaunchData( pPayload, nPayloadSize, launchFlags );
  256. #if defined( _DEMO )
  257. bLaunch = true;
  258. #endif
  259. if ( bLaunch )
  260. {
  261. // Can't send anything to VXConsole; about to abandon connection
  262. // VXConsole tries to respond but can't and throws the timeout crash
  263. // COM_TimestampedLog( "Launching: \"%s\" Flags: 0x%8.8x", pCmdLine, XboxLaunch()->GetLaunchFlags() );
  264. g_pMaterialSystem->PersistDisplay();
  265. XBX_DisconnectConsoleMonitor();
  266. #if defined( CSTRIKE15 )
  267. XboxLaunch()->SetLaunchData( NULL, 0, 0 );
  268. XboxLaunch()->Launch( XLAUNCH_KEYWORD_DASH_ARCADE );
  269. #else
  270. XboxLaunch()->Launch();
  271. #endif // defined( CSTRIKE15 )
  272. }
  273. #elif defined( _PS3 )
  274. // TODO: preserve when a "restart" is requested!
  275. Assert( !bWarmRestart );
  276. Assert( !bUnused );
  277. if ( bWarmRestart )
  278. {
  279. DevWarning( "TODO: PS3 quit_x360 restart is not implemented yet!\n" );
  280. }
  281. // Prevent re-entry
  282. static bool s_bQuitPreventReentry = false;
  283. if ( s_bQuitPreventReentry )
  284. return;
  285. s_bQuitPreventReentry = true;
  286. // We must go into single-threaded rendering
  287. Host_AllowQueuedMaterialSystem( false );
  288. // Make sure everybody received the EXITGAME callback, might happen multiple times now
  289. float const flTimeStampStart = Plat_FloatTime();
  290. float flGracePeriod = ps3_host_quit_graceperiod.GetFloat();
  291. flGracePeriod = MIN( 7, flGracePeriod );
  292. flGracePeriod = MAX( 0, flGracePeriod );
  293. float const flTimeStampForceShutdown = flTimeStampStart + flGracePeriod;
  294. uint64 uiLastCountdownNotificationSent = 0;
  295. for ( ; ; )
  296. {
  297. enum ShutdownSystemsWait_t
  298. {
  299. kSysSaveRestore,
  300. kSysSaveUtilV2,
  301. kSysSteamClient,
  302. kSysDebugPause,
  303. kSysShutdownSystemsCount
  304. };
  305. char const *szSystems[kSysShutdownSystemsCount] = {0};
  306. char const *szSystemsRequiredState[kSysShutdownSystemsCount] = {0};
  307. // Poll systems whether they are ready to shutdown
  308. if ( saverestore && saverestore->IsSaveInProgress() )
  309. szSystems[kSysSaveRestore] = "saverestore";
  310. extern bool SaveUtilV2_CanShutdown();
  311. if ( !SaveUtilV2_CanShutdown() )
  312. szSystems[kSysSaveUtilV2] = "SaveUtilV2";
  313. if ( Steam3Client().SteamUtils() && !Steam3Client().SteamUtils()->BIsReadyToShutdown() )
  314. szSystems[kSysSteamClient] = "steamclient";
  315. if ( ( ps3_host_quit_debugpause.GetFloat() > 0 ) && ( Plat_FloatTime() < flTimeStampStart + ps3_host_quit_debugpause.GetFloat() ) )
  316. szSystems[kSysDebugPause] = "debugpause";
  317. if ( !Q_memcmp( szSystemsRequiredState, szSystems, sizeof( szSystemsRequiredState ) ) )
  318. {
  319. DevMsg( "PS3 shutdown procedure: all systems ready (%.2f sec elapsed)\n", ( Plat_FloatTime() - flTimeStampStart ) );
  320. break;
  321. }
  322. uint64 uiCountdownNotification = 1 + ( flTimeStampForceShutdown - Plat_FloatTime() );
  323. if ( uiCountdownNotification != uiLastCountdownNotificationSent )
  324. {
  325. uiLastCountdownNotificationSent = uiCountdownNotification;
  326. PS3_sysutil_callback_forwarder( CELL_SYSUTIL_REQUEST_EXITGAME, uiCountdownNotification );
  327. DevWarning( "PS3 shutdown procedure: %.2f sec elapsed...\n", ( Plat_FloatTime() - flTimeStampStart ) );
  328. int nNotReadySystemsCount = 0;
  329. for ( int jj = 0; jj < ARRAYSIZE( szSystems ); ++ jj )
  330. {
  331. if ( szSystems[jj] )
  332. {
  333. DevWarning( " system not ready : %s\n", szSystems[jj] );
  334. ++ nNotReadySystemsCount;
  335. }
  336. }
  337. DevWarning( "PS3 shutdown procedure: waiting for %d systems to be ready for shutdown (%.2f sec remaining)...\n", nNotReadySystemsCount, ( flTimeStampForceShutdown - Plat_FloatTime() ) );
  338. }
  339. if ( Plat_FloatTime() >= flTimeStampForceShutdown )
  340. {
  341. DevWarning( "FORCING PS3 SHUTDOWN PROCEDURE: NOT ALL SYSTEMS READY (%.2f sec elapsed)...\n", ( Plat_FloatTime() - flTimeStampStart ) );
  342. break;
  343. }
  344. // Perform blank vsync'ed flips
  345. static ConVarRef mat_vsync( "mat_vsync" );
  346. mat_vsync.SetValue( true );
  347. g_pMaterialSystem->SetFlipPresentFrequency( 1 ); // let it flip every VSYNC, we let interrupt handler throttle this loop to conform with TCR#R092 [no more than 60 fps]
  348. // Dummy frame
  349. g_pMaterialSystem->BeginFrame( 1.0f/60.0f );
  350. CMatRenderContextPtr pRenderContext;
  351. pRenderContext.GetFrom( g_pMaterialSystem );
  352. pRenderContext->ClearColor4ub( 0, 0, 0, 255 );
  353. pRenderContext->ClearBuffers( true, true, true );
  354. pRenderContext.SafeRelease();
  355. g_pMaterialSystem->EndFrame();
  356. g_pMaterialSystem->SwapBuffers();
  357. // Pump system event queue
  358. XBX_ProcessEvents();
  359. XBX_DispatchEventsQueue();
  360. }
  361. // QUIT
  362. Warning( "[PS3 SYSTEM] REQUEST EXITGAME INITIATING QUIT @ %.3f\n", Plat_FloatTime() );
  363. Host_Quit_f();
  364. #else
  365. Assert( 0 );
  366. #error
  367. #endif
  368. }
  369. CON_COMMAND( quit_gameconsole, "" )
  370. {
  371. Quit_gameconsole_f(
  372. args.FindArg( "restart" ) != NULL,
  373. args.FindArg( "invite" ) != NULL );
  374. }
  375. #endif
  376. // store arbitrary launch arguments in KeyValues to avoid having to add code for every new
  377. // launch parameter (like edit mode, commentary mode, background, etc. do)
  378. void SetLaunchOptions( const CCommand &args )
  379. {
  380. if ( g_pLaunchOptions )
  381. {
  382. g_pLaunchOptions->deleteThis();
  383. }
  384. g_pLaunchOptions = new KeyValues( "LaunchOptions" );
  385. for ( int i = 0 ; i < args.ArgC() ; i++ )
  386. {
  387. g_pLaunchOptions->SetString( va("Arg%d", i), args[i] );
  388. }
  389. }
  390. /*
  391. ==================
  392. Host_Quit_f
  393. ==================
  394. */
  395. void Host_Quit_f (void)
  396. {
  397. #if !defined(DEDICATED)
  398. if ( !EngineTool_CheckQuitHandlers() )
  399. {
  400. return;
  401. }
  402. #endif
  403. HostState_Shutdown();
  404. }
  405. //-----------------------------------------------------------------------------
  406. // Purpose:
  407. //-----------------------------------------------------------------------------
  408. CON_COMMAND( _restart, "Shutdown and restart the engine." )
  409. {
  410. /*
  411. // FIXME: How to handle restarts?
  412. #ifndef DEDICATED
  413. if ( !EngineTool_CheckQuitHandlers() )
  414. {
  415. return;
  416. }
  417. #endif
  418. */
  419. HostState_Restart();
  420. }
  421. #ifndef DEDICATED
  422. //-----------------------------------------------------------------------------
  423. // A console command to spew out driver information
  424. //-----------------------------------------------------------------------------
  425. void Host_LightCrosshair (void);
  426. static ConCommand light_crosshair( "light_crosshair", Host_LightCrosshair, "Show texture color at crosshair", FCVAR_CHEAT );
  427. void Host_LightCrosshair (void)
  428. {
  429. Vector endPoint;
  430. Vector lightmapColor;
  431. // max_range * sqrt(3)
  432. VectorMA( MainViewOrigin(), COORD_EXTENT * 1.74f, MainViewForward(), endPoint );
  433. R_LightVec( MainViewOrigin(), endPoint, true, lightmapColor );
  434. int r = LinearToTexture( lightmapColor.x );
  435. int g = LinearToTexture( lightmapColor.y );
  436. int b = LinearToTexture( lightmapColor.z );
  437. ConMsg( "Luxel Value: %d %d %d\n", r, g, b );
  438. }
  439. #endif
  440. /*
  441. ==================
  442. Host_Status_PrintClient
  443. Print client info to console
  444. ==================
  445. */
  446. void Host_Status_PrintClient( IClient *client, bool bShowAddress, void (*print) (const char *fmt, ...) )
  447. {
  448. INetChannelInfo *nci = client->GetNetChannel();
  449. const char *state = "challenging";
  450. if ( client->IsActive() )
  451. state = "active";
  452. else if ( client->IsSpawned() )
  453. state = "spawning";
  454. else if ( client->IsConnected() )
  455. state = "connecting";
  456. if ( nci != NULL )
  457. {
  458. print( "# %2i %i \"%s\" %s %s %i %i %s %d",
  459. client->GetUserID(), client->GetPlayerSlot() + 1, client->GetClientName(), client->GetNetworkIDString(), COM_FormatSeconds( nci->GetTimeConnected() ),
  460. (int)(1000.0f*nci->GetAvgLatency( FLOW_OUTGOING )), (int)(100.0f*nci->GetAvgLoss(FLOW_INCOMING)), state, (int)nci->GetDataRate() );
  461. if ( bShowAddress )
  462. {
  463. print( " %s", nci->GetAddress() );
  464. }
  465. }
  466. else
  467. {
  468. print( "#%2i \"%s\" %s %s %.0f",
  469. client->GetUserID(), client->GetClientName(), client->GetNetworkIDString(), state, client->GetUpdateRate() );
  470. }
  471. print( "\n" );
  472. }
  473. typedef void ( *FnPrintf_t )(const char *fmt, ...);
  474. void Host_Client_Printf(const char *fmt, ...)
  475. {
  476. va_list argptr;
  477. char string[1024];
  478. va_start (argptr,fmt);
  479. Q_vsnprintf (string, sizeof( string ), fmt,argptr);
  480. va_end (argptr);
  481. host_client->ClientPrintf( "%s", string );
  482. }
  483. static void Host_Client_PrintfStub(const char *fmt, ...)
  484. {
  485. }
  486. void Host_PrintStatus( cmd_source_t commandSource, void ( *print )(const char *fmt, ...), bool bShort )
  487. {
  488. bool bWithAddresses = ( ( commandSource != kCommandSrcNetClient ) && ( commandSource != kCommandSrcNetServer ) && ( print == ConMsg ) ); // guarantee to never print for remote
  489. IClient *client;
  490. int j;
  491. if ( !print ) { return; }
  492. // ============================================================
  493. // Server status information.
  494. print( "hostname: %s\n", host_name.GetString() );
  495. const char *pchSecureReasonString = "";
  496. const char *pchUniverse = "";
  497. bool bGSSecure = Steam3Server().BSecure();
  498. if ( !bGSSecure && Steam3Server().BWantsSecure() )
  499. {
  500. if ( Steam3Server().BLoggedOn() )
  501. {
  502. pchSecureReasonString = "(secure mode enabled, connected to Steam3)";
  503. }
  504. else
  505. {
  506. pchSecureReasonString = "(secure mode enabled, disconnected from Steam3)";
  507. }
  508. }
  509. switch ( GetSteamUniverse() )
  510. {
  511. case k_EUniversePublic:
  512. pchUniverse = "";
  513. break;
  514. case k_EUniverseBeta:
  515. pchUniverse = "(beta)";
  516. break;
  517. case k_EUniverseInternal:
  518. pchUniverse = "(internal)";
  519. break;
  520. case k_EUniverseDev:
  521. pchUniverse = "(dev)";
  522. break;
  523. /* no such universe anymore
  524. case k_EUniverseRC:
  525. pchUniverse = "(rc)";
  526. break;
  527. */
  528. default:
  529. pchUniverse = "(unknown)";
  530. break;
  531. }
  532. if ( bWithAddresses )
  533. {
  534. print( "version : %s/%d %d/%d %s %s %s %s\n",
  535. Sys_GetVersionString(), GetHostVersion(),
  536. GetServerVersion(), build_number(),
  537. bGSSecure ? "secure" : "insecure", pchSecureReasonString,
  538. Steam3Server().GetGSSteamID().IsValid() ? Steam3Server().GetGSSteamID().Render() : "[INVALID_STEAMID]", pchUniverse );
  539. }
  540. else
  541. {
  542. print( "version : %s %s\n",
  543. Sys_GetVersionString(),
  544. bGSSecure ? "secure" : "insecure" );
  545. }
  546. if ( NET_IsMultiplayer() )
  547. {
  548. CUtlString sPublicIPInfo;
  549. if ( !Steam3Server().BLanOnly() )
  550. {
  551. uint32 unPublicIP = Steam3Server().GetPublicIP();
  552. if ( ( unPublicIP != 0 ) && bWithAddresses && sv.IsDedicated() )
  553. {
  554. netadr_t addr;
  555. addr.SetIP( unPublicIP );
  556. sPublicIPInfo.Format(" (public ip: %s)", addr.ToString( true ) );
  557. }
  558. }
  559. print( "udp/ip : %s:%i%s\n", net_local_adr.ToString(true), sv.GetUDPPort(), sPublicIPInfo.String() );
  560. static ConVarRef sv_steamdatagramtransport_port( "sv_steamdatagramtransport_port" );
  561. if ( bWithAddresses && sv_steamdatagramtransport_port.GetInt() > 0 )
  562. {
  563. print( "sdt : =%s on port %d\n", Steam3Server().GetGSSteamID().Render(), sv_steamdatagramtransport_port.GetInt() );
  564. }
  565. const char *osType =
  566. #if defined( WIN32 )
  567. "Windows";
  568. #elif defined( _LINUX )
  569. "Linux";
  570. #elif defined( PLATFORM_OSX )
  571. "OSX";
  572. #else
  573. "Unknown";
  574. #endif
  575. print( "os : %s\n", osType );
  576. char const *serverType = sv.IsHLTV() ? "hltv" : ( sv.IsDedicated() ? ( serverGameDLL->IsValveDS() ? "official dedicated" : "community dedicated" ) : "listen" );
  577. print( "type : %s\n", serverType );
  578. }
  579. #ifndef DEDICATED // no client on dedicated server
  580. if ( !sv.IsDedicated() && GetBaseLocalClient().IsConnected() )
  581. {
  582. print( "map : %s at: %d x, %d y, %d z\n", sv.GetMapName(), (int)MainViewOrigin()[0], (int)MainViewOrigin()[1], (int)MainViewOrigin()[2]);
  583. }
  584. #else
  585. {
  586. print( "map : %s\n", sv.GetMapName() );
  587. }
  588. #endif
  589. if ( CanShowHostTvStatus() )
  590. {
  591. for ( CActiveHltvServerIterator hltv; hltv; hltv.Next() )
  592. {
  593. print( "gotv[%i]: port %i, delay %.1fs, rate %.1f\n", hltv.GetIndex(), hltv->GetUDPPort(), hltv->GetDirector() ? hltv->GetDirector()->GetDelay() : 0.0f, hltv->GetSnapshotRate() );
  594. }
  595. }
  596. #if defined( REPLAY_ENABLED )
  597. if ( replay && replay->IsActive() )
  598. {
  599. print( "replay: port %i, delay %.1fs\n", replay->GetUDPPort(), replay->GetDirector()->GetDelay() );
  600. }
  601. #endif
  602. int nHumans;
  603. int nMaxHumans;
  604. int nBots;
  605. sv.GetMasterServerPlayerCounts( nHumans, nMaxHumans, nBots );
  606. print( "players : %i humans, %i bots (%i/%i max) (%s)\n\n",
  607. nHumans, nBots, nMaxHumans, sv.GetNumGameSlots(), sv.IsHibernating() ? "hibernating" : "not hibernating" );
  608. // ============================================================
  609. #if SUPPORT_NET_CONSOLE
  610. if ( g_pNetConsoleMgr && g_pNetConsoleMgr->IsActive() && bWithAddresses )
  611. {
  612. print( "netcon : %s:%i\n", net_local_adr.ToString( true), g_pNetConsoleMgr->GetAddress().GetPort() );
  613. }
  614. #endif
  615. // Early exit for this server.
  616. if ( bShort )
  617. {
  618. for ( j=0 ; j < sv.GetClientCount() ; j++ )
  619. {
  620. client = sv.GetClient( j );
  621. if ( !client->IsActive() )
  622. continue;
  623. if ( !bWithAddresses && !CanShowHostTvStatus() && client->IsHLTV() )
  624. continue;
  625. print( "#%i - %s\n" , j + 1, client->GetClientName() );
  626. }
  627. return;
  628. }
  629. // the header for the status rows
  630. print( "# userid name uniqueid connected ping loss state rate" );
  631. if ( bWithAddresses )
  632. {
  633. print( " adr" );
  634. }
  635. print( "\n" );
  636. for ( j=0 ; j < sv.GetClientCount() ; j++ )
  637. {
  638. client = sv.GetClient( j );
  639. if ( !client->IsConnected() )
  640. continue; // not connected yet, maybe challenging
  641. if ( !CanShowHostTvStatus() && client->IsHLTV() )
  642. continue;
  643. Host_Status_PrintClient( client, bWithAddresses, print );
  644. }
  645. print( "#end\n" );
  646. }
  647. //-----------------------------------------------------------------------------
  648. // Host_Status_f
  649. //-----------------------------------------------------------------------------
  650. CON_COMMAND( status, "Display map and connection status." )
  651. {
  652. void (*print) (const char *fmt, ...) = Host_Client_PrintfStub;
  653. if ( args.Source() != kCommandSrcNetClient )
  654. {
  655. if ( !sv.IsActive() )
  656. {
  657. Cmd_ForwardToServer( args );
  658. return;
  659. }
  660. #ifndef DBGFLAG_STRINGS_STRIP
  661. print = ConMsg;
  662. #endif
  663. }
  664. else
  665. {
  666. print = Host_Client_Printf;
  667. }
  668. bool bShort = false;
  669. if ( args.ArgC() == 2 )
  670. {
  671. if ( !Q_stricmp( args[1], "short" ) )
  672. {
  673. bShort = true;
  674. }
  675. }
  676. Host_PrintStatus( args.Source(), print, bShort );
  677. }
  678. CON_COMMAND( hltv_replay_status, "Show Killer Replay status and some statistics, works on listen or dedicated server." )
  679. {
  680. HltvReplayStats_t hltvStats;
  681. for ( int j = 0; j < sv.GetClientCount(); j++ )
  682. {
  683. IClient *client = sv.GetClient( j );
  684. if ( !client->IsConnected() )
  685. continue; // not connected yet, maybe challenging
  686. if ( !CanShowHostTvStatus() && client->IsHLTV() )
  687. continue;
  688. INetChannelInfo *nci = client->GetNetChannel();
  689. const char *state = "challenging";
  690. if ( client->IsActive() )
  691. state = "active";
  692. else if ( client->IsSpawned() )
  693. state = "spawning";
  694. else if ( client->IsConnected() )
  695. state = "connecting";
  696. if ( nci != NULL )
  697. {
  698. ConMsg( "# %2i %i \"%s\" %s %s %s %s",
  699. client->GetUserID(), client->GetPlayerSlot() + 1, client->GetClientName(), client->GetNetworkIDString(), COM_FormatSeconds( nci->GetTimeConnected() ),
  700. state, client->GetHltvReplayStatus() );
  701. if ( client->GetHltvReplayDelay() )
  702. ConMsg( ", in replay NOW" );
  703. }
  704. else
  705. {
  706. ConMsg( "#%2i \"%s\" %s %s %s",
  707. client->GetUserID(), client->GetClientName(), client->GetNetworkIDString(), state, client->GetHltvReplayStatus() );
  708. }
  709. if ( CGameClient *pClient = dynamic_cast< CGameClient * >( client ) )
  710. {
  711. if ( pClient->m_HltvReplayStats.nStartRequests )
  712. hltvStats += pClient->m_HltvReplayStats;
  713. if ( pClient->m_nForceWaitForTick > 0 )
  714. {
  715. ConMsg( ", force-waiting for tick %d - server tick %d, current frame %d", pClient->m_nForceWaitForTick, sv.GetTick(), pClient->m_pCurrentFrame ? pClient->m_pCurrentFrame->tick_count : 0 );
  716. }
  717. }
  718. ConMsg( "\n" );
  719. }
  720. extern HltvReplayStats_t m_DisconnectedClientsHltvReplayStats;
  721. if ( m_DisconnectedClientsHltvReplayStats.nClients > 1 )
  722. ConMsg( "%u disconnected clients: %s\n", m_DisconnectedClientsHltvReplayStats.nClients - 1, m_DisconnectedClientsHltvReplayStats.AsString() );
  723. if ( hltvStats.nClients > 0 )
  724. {
  725. ConMsg( "%u current clients: %s\n", hltvStats.nClients, hltvStats.AsString() );
  726. }
  727. }
  728. #if defined( _X360 )
  729. CON_COMMAND( vx_mapinfo, "" )
  730. {
  731. Vector org;
  732. QAngle ang;
  733. const char *pName;
  734. if ( GetBaseLocalClient().IsActive() )
  735. {
  736. pName = GetBaseLocalClient().m_szLevelNameShort;
  737. org = MainViewOrigin();
  738. VectorAngles( MainViewForward(), ang );
  739. IClientEntity *localPlayer = entitylist->GetClientEntity( GetBaseLocalClient().m_nPlayerSlot + 1 );
  740. if ( localPlayer )
  741. {
  742. org = localPlayer->GetAbsOrigin();
  743. }
  744. }
  745. else
  746. {
  747. pName = "";
  748. org.Init();
  749. ang.Init();
  750. }
  751. // HACK: This is only relevant for portal2.
  752. Msg( "BUG REPORT PORTAL POSITIONS:\n" );
  753. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "portal_report\n" );
  754. // send to vxconsole
  755. xMapInfo_t mapInfo;
  756. mapInfo.position[0] = org[0];
  757. mapInfo.position[1] = org[1];
  758. mapInfo.position[2] = org[2];
  759. mapInfo.angle[0] = ang[0];
  760. mapInfo.angle[1] = ang[1];
  761. mapInfo.angle[2] = ang[2];
  762. mapInfo.build = build_number();
  763. mapInfo.skill = skill.GetInt();
  764. // generate the qualified path where .sav files are expected to be written
  765. char savePath[MAX_PATH];
  766. V_snprintf( savePath, sizeof( savePath ), "%s", saverestore->GetSaveDir() );
  767. V_StripTrailingSlash( savePath );
  768. g_pFileSystem->RelativePathToFullPath( savePath, "MOD", mapInfo.savePath, sizeof( mapInfo.savePath ) );
  769. V_FixSlashes( mapInfo.savePath );
  770. if ( pName[0] )
  771. {
  772. // generate the qualified path from where the map was loaded
  773. char mapPath[MAX_PATH];
  774. V_snprintf( mapPath, sizeof( mapPath ), "maps/%s" PLATFORM_EXT ".bsp", pName );
  775. g_pFileSystem->GetLocalPath( mapPath, mapInfo.mapPath, sizeof( mapInfo.mapPath ) );
  776. V_FixSlashes( mapInfo.mapPath );
  777. }
  778. else
  779. {
  780. mapInfo.mapPath[0] = '\0';
  781. }
  782. mapInfo.details[0] = '\0';
  783. ConVarRef host_thread_mode( "host_thread_mode" );
  784. ConVarRef mat_queue_mode( "mat_queue_mode" );
  785. ConVarRef snd_surround_speakers( "snd_surround_speakers" );
  786. V_strncat(
  787. mapInfo.details,
  788. CFmtStr( "Build: %d\n", build_number() ),
  789. sizeof( mapInfo.details ) );
  790. XVIDEO_MODE videoMode;
  791. XGetVideoMode( &videoMode );
  792. V_strncat(
  793. mapInfo.details,
  794. CFmtStr( "Display: %dx%d (%s)\n", videoMode.dwDisplayWidth, videoMode.dwDisplayHeight, videoMode.fIsWideScreen ? "widescreen" : "normal" ),
  795. sizeof( mapInfo.details ) );
  796. int backbufferWidth, backbufferHeight;
  797. materials->GetBackBufferDimensions( backbufferWidth, backbufferHeight );
  798. V_strncat(
  799. mapInfo.details,
  800. CFmtStr( "BackBuffer: %dx%d\n", backbufferWidth, backbufferHeight ),
  801. sizeof( mapInfo.details ) );
  802. // audio info
  803. const char *pAudioInfo = "Unknown";
  804. switch ( snd_surround_speakers.GetInt() )
  805. {
  806. case 2:
  807. pAudioInfo = "Stereo";
  808. break;
  809. case 5:
  810. pAudioInfo = "5.1 Digital Surround";
  811. break;
  812. }
  813. V_strncat(
  814. mapInfo.details,
  815. CFmtStr( "Audio: %s\n", pAudioInfo ),
  816. sizeof( mapInfo.details ) );
  817. // ui language
  818. V_strncat(
  819. mapInfo.details,
  820. CFmtStr( "UI: %s\n", cl_language.GetString() ),
  821. sizeof( mapInfo.details ) );
  822. // cvars
  823. V_strncat(
  824. mapInfo.details,
  825. CFmtStr( "host_thread_mode: %d\n", host_thread_mode.GetInt() ),
  826. sizeof( mapInfo.details ) );
  827. V_strncat(
  828. mapInfo.details,
  829. CFmtStr( "mat_queue_mode: %d\n", mat_queue_mode.GetInt() ),
  830. sizeof( mapInfo.details ) );
  831. XBX_rMapInfo( &mapInfo );
  832. }
  833. #elif defined( _PS3 )
  834. #include "ps3/ps3_sn.h"
  835. CON_COMMAND( vx_mapinfo, "" )
  836. {
  837. Vector org;
  838. QAngle ang;
  839. const char *pName;
  840. if ( GetBaseLocalClient().IsActive() )
  841. {
  842. pName = GetBaseLocalClient().m_szLevelNameShort;
  843. org = MainViewOrigin();
  844. VectorAngles( MainViewForward(), ang );
  845. IClientEntity *localPlayer = entitylist->GetClientEntity( GetBaseLocalClient().m_nPlayerSlot + 1 );
  846. if ( localPlayer )
  847. {
  848. org = localPlayer->GetAbsOrigin();
  849. }
  850. }
  851. else
  852. {
  853. pName = "";
  854. org.Init();
  855. ang.Init();
  856. }
  857. // HACK: This is only relevant for portal2.
  858. Msg( "BUG REPORT PORTAL POSITIONS:\n" );
  859. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "portal_report\n" );
  860. // send to vxconsole
  861. xMapInfo_t mapInfo;
  862. mapInfo.position[0] = org[0];
  863. mapInfo.position[1] = org[1];
  864. mapInfo.position[2] = org[2];
  865. mapInfo.angle[0] = ang[0];
  866. mapInfo.angle[1] = ang[1];
  867. mapInfo.angle[2] = ang[2];
  868. mapInfo.build = build_number();
  869. mapInfo.skill = skill.GetInt();
  870. // generate the qualified path where .sav files are expected to be written
  871. char savePath[MAX_PATH];
  872. V_snprintf( savePath, sizeof( savePath ), "%s", saverestore->GetSaveDir() );
  873. V_StripTrailingSlash( savePath );
  874. g_pFileSystem->RelativePathToFullPath( savePath, "MOD", mapInfo.savePath, sizeof( mapInfo.savePath ) );
  875. V_FixSlashes( mapInfo.savePath );
  876. if ( pName[0] )
  877. {
  878. // generate the qualified path from where the map was loaded
  879. char mapPath[MAX_PATH];
  880. V_snprintf( mapPath, sizeof( mapPath ), "maps/%s" PLATFORM_EXT ".bsp", pName );
  881. g_pFileSystem->GetLocalPath( mapPath, mapInfo.mapPath, sizeof( mapInfo.mapPath ) );
  882. V_FixSlashes( mapInfo.mapPath );
  883. }
  884. else
  885. {
  886. mapInfo.mapPath[0] = '\0';
  887. }
  888. mapInfo.details[0] = '\0';
  889. ConVarRef host_thread_mode( "host_thread_mode" );
  890. ConVarRef mat_queue_mode( "mat_queue_mode" );
  891. ConVarRef snd_surround_speakers( "snd_surround_speakers" );
  892. V_strncat(
  893. mapInfo.details,
  894. CFmtStr( "Build: %d\n", build_number() ),
  895. sizeof( mapInfo.details ) );
  896. /*
  897. XVIDEO_MODE videoMode;
  898. XGetVideoMode( &videoMode );
  899. V_strncat(
  900. mapInfo.details,
  901. CFmtStr( "Display: %dx%d (%s)\n", videoMode.dwDisplayWidth, videoMode.dwDisplayHeight, videoMode.fIsWideScreen ? "widescreen" : "normal" ),
  902. sizeof( mapInfo.details ) );
  903. int backbufferWidth, backbufferHeight;
  904. materials->GetBackBufferDimensions( backbufferWidth, backbufferHeight );
  905. V_strncat(
  906. mapInfo.details,
  907. CFmtStr( "BackBuffer: %dx%d\n", backbufferWidth, backbufferHeight ),
  908. sizeof( mapInfo.details ) );
  909. */
  910. // audio info
  911. const char *pAudioInfo = "Unknown";
  912. switch ( snd_surround_speakers.GetInt() )
  913. {
  914. case 2:
  915. pAudioInfo = "Stereo";
  916. break;
  917. case 5:
  918. pAudioInfo = "5.1 Digital Surround";
  919. break;
  920. }
  921. V_strncat(
  922. mapInfo.details,
  923. CFmtStr( "Audio: %s\n", pAudioInfo ),
  924. sizeof( mapInfo.details ) );
  925. // ui language
  926. V_strncat(
  927. mapInfo.details,
  928. CFmtStr( "UI: %s\n", cl_language.GetString() ),
  929. sizeof( mapInfo.details ) );
  930. // cvars
  931. V_strncat(
  932. mapInfo.details,
  933. CFmtStr( "host_thread_mode: %d\n", host_thread_mode.GetInt() ),
  934. sizeof( mapInfo.details ) );
  935. V_strncat(
  936. mapInfo.details,
  937. CFmtStr( "mat_queue_mode: %d\n", mat_queue_mode.GetInt() ),
  938. sizeof( mapInfo.details ) );
  939. XBX_rMapInfo( &mapInfo );
  940. }
  941. CON_COMMAND( vx_screenshot, "" )
  942. {
  943. #if 1
  944. g_pMaterialSystem->TransmitScreenshotToVX( );
  945. #else
  946. // COMPILE_TIME_ASSERT( sizeof(g_pfnSwapBufferMarker) == 8);
  947. union FunctionPointerIsReallyADescriptor
  948. {
  949. void (*pFunc_t)();
  950. struct
  951. {
  952. uint32 funcaddress;
  953. int32 iToc;
  954. } fn8;
  955. };
  956. FunctionPointerIsReallyADescriptor *pBreakpoint = (FunctionPointerIsReallyADescriptor *)g_pfnSwapBufferMarker;
  957. // breakpoint.pFunc_t = g_pfnSwapBufferMarker;
  958. uint64 uBPAddress;
  959. /// Address of a pointer that points to the image in memory
  960. char * pFrameBuffer;
  961. /// Width of image
  962. uint32 uWidth;
  963. /// Height of image
  964. uint32 uHeight;
  965. /// Image pitch (as described in CellGCMSurface) - in bytes
  966. uint32 uPitch;
  967. /// Image colour settings (0 = X8R8G8B8, 1 = X8B8G8R8, 2 = R16G16B16X16)
  968. IMaterialSystem::VRAMScreenShotInfoColor_t colour ;
  969. // get one of the screen buffers. Since we breakpoint the game anyway I don't think
  970. // it really matters if we're two out of date. (For this test, anyway.)
  971. g_pMaterialSystem->GetVRAMScreenShotInfo( &pFrameBuffer, &uWidth, &uHeight, &uPitch, &colour );
  972. g_pValvePS3Console->VRAMDumpingInfo( (uint64)pBreakpoint->fn8.funcaddress,
  973. (uint64)pFrameBuffer, uWidth, uHeight, uPitch, colour );
  974. #endif
  975. }
  976. #endif
  977. //-----------------------------------------------------------------------------
  978. // Host_Ping_f
  979. //-----------------------------------------------------------------------------
  980. CON_COMMAND( ping, "Display ping to server." )
  981. {
  982. if ( args.Source() != kCommandSrcNetClient )
  983. {
  984. Cmd_ForwardToServer( args );
  985. return;
  986. }
  987. host_client->ClientPrintf( "Client ping times:\n" );
  988. for ( int i=0; i< sv.GetClientCount(); i++ )
  989. {
  990. IClient *client = sv.GetClient(i);
  991. if ( !client->IsConnected() || client->IsFakeClient() )
  992. continue;
  993. host_client->ClientPrintf ("%4.0f ms : %s\n",
  994. 1000.0f * client->GetNetChannel()->GetAvgLatency( FLOW_OUTGOING ), client->GetClientName() );
  995. }
  996. }
  997. //-----------------------------------------------------------------------------
  998. // Purpose:
  999. // Input : editmode -
  1000. //-----------------------------------------------------------------------------
  1001. extern void GetPlatformMapPath( const char *pMapPath, char *pPlatformMapPath, int maxLength );
  1002. bool CL_HL2Demo_MapCheck( const char *name )
  1003. {
  1004. if ( IsPC() && CL_IsHL2Demo() && !sv.IsDedicated() )
  1005. {
  1006. if ( !Q_stricmp( name, "d1_trainstation_01" ) ||
  1007. !Q_stricmp( name, "d1_trainstation_02" ) ||
  1008. !Q_stricmp( name, "d1_town_01" ) ||
  1009. !Q_stricmp( name, "d1_town_01a" ) ||
  1010. !Q_stricmp( name, "d1_town_02" ) ||
  1011. !Q_stricmp( name, "d1_town_03" ) ||
  1012. !Q_stricmp( name, "background01" ) ||
  1013. !Q_stricmp( name, "background03" )
  1014. )
  1015. {
  1016. return true;
  1017. }
  1018. return false;
  1019. }
  1020. return true;
  1021. }
  1022. bool CL_PortalDemo_MapCheck( const char *name )
  1023. {
  1024. if ( IsPC() && CL_IsPortalDemo() && !sv.IsDedicated() )
  1025. {
  1026. if ( !Q_stricmp( name, "testchmb_a_00" ) ||
  1027. !Q_stricmp( name, "testchmb_a_01" ) ||
  1028. !Q_stricmp( name, "testchmb_a_02" ) ||
  1029. !Q_stricmp( name, "testchmb_a_03" ) ||
  1030. !Q_stricmp( name, "testchmb_a_04" ) ||
  1031. !Q_stricmp( name, "testchmb_a_05" ) ||
  1032. !Q_stricmp( name, "testchmb_a_06" ) ||
  1033. !Q_stricmp( name, "background1" )
  1034. )
  1035. {
  1036. return true;
  1037. }
  1038. return false;
  1039. }
  1040. return true;
  1041. }
  1042. enum EMapFlags
  1043. {
  1044. EMAP_NONE = 0,
  1045. EMAP_EDIT_MODE = (1<<0),
  1046. EMAP_BACKGROUND = (1<<1),
  1047. EMAP_COMMENTARY = (1<<2),
  1048. EMAP_SPLITSCREEN = (1<<3)
  1049. };
  1050. int _Host_Map_f_CompletionFunc( char const *cmdname, char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] );
  1051. // Note, leaves name alone if no match possible
  1052. static bool Host_Map_Helper_FuzzyName( const CCommand &args, char *name, size_t bufsize )
  1053. {
  1054. char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ];
  1055. CUtlString argv0;
  1056. argv0 = args.Arg( 0 );
  1057. argv0 += " ";
  1058. if ( _Host_Map_f_CompletionFunc( argv0, args[1], commands ) > 0 )
  1059. {
  1060. Q_strncpy( name, &commands[ 0 ][ argv0.Length() ], bufsize );
  1061. return true;
  1062. }
  1063. return false;
  1064. }
  1065. void Host_Changelevel_f( const CCommand &args );
  1066. void Host_Map_Helper( const CCommand &args, EMapFlags flags )
  1067. {
  1068. char name[MAX_QPATH];
  1069. if (args.ArgC() < 2)
  1070. {
  1071. Warning("No map specified\n");
  1072. return;
  1073. }
  1074. if ( ( sv.IsActive() && !sv.IsSinglePlayerGame() && !sv.IsLevelMainMenuBackground() ) ||
  1075. ( sv.IsActive() && sv.IsDedicated() ) )
  1076. {
  1077. // Using the 'map' command while in a map disconnects all players.
  1078. // Ease the pain of this common error by forwarding to the correct command.
  1079. Host_Changelevel_f( args );
  1080. return;
  1081. }
  1082. bool bBackground = ( flags & EMAP_BACKGROUND ) != 0;
  1083. bool bSplitScreenConnect = ( flags & EMAP_SPLITSCREEN ) != 0;
  1084. char ppath[ MAX_QPATH ];
  1085. // If there is a .bsp on the end, strip it off!
  1086. Q_StripExtension( args[ 1 ], ppath, sizeof( ppath ) );
  1087. // Call with quiet flag for initial search
  1088. if ( !modelloader->Map_IsValid( ppath, true ) )
  1089. {
  1090. Host_Map_Helper_FuzzyName( args, ppath, sizeof( ppath ) );
  1091. if ( !modelloader->Map_IsValid( ppath ) )
  1092. {
  1093. Warning( "map load failed: %s not found or invalid\n", ppath );
  1094. return;
  1095. }
  1096. }
  1097. GetPlatformMapPath( ppath, name, sizeof( name ) );
  1098. // If I was in edit mode reload config file
  1099. // to overwrite WC edit key bindings
  1100. #if !defined(DEDICATED)
  1101. bool bCommentary = ( flags & EMAP_COMMENTARY ) != 0;
  1102. bool bEditmode = ( flags & EMAP_EDIT_MODE ) != 0;
  1103. if ( !bEditmode )
  1104. {
  1105. if ( g_bInEditMode )
  1106. {
  1107. // Re-read config from disk
  1108. Host_ReadConfiguration( -1, false );
  1109. g_bInEditMode = false;
  1110. }
  1111. }
  1112. else
  1113. {
  1114. g_bInEditMode = true;
  1115. }
  1116. g_bInCommentaryMode = bCommentary;
  1117. #endif
  1118. SetLaunchOptions( args );
  1119. if ( !CL_HL2Demo_MapCheck( name ) )
  1120. {
  1121. Warning( "map load failed: %s not found or invalid\n", name );
  1122. return;
  1123. }
  1124. if ( !CL_PortalDemo_MapCheck( name ) )
  1125. {
  1126. Warning( "map load failed: %s not found or invalid\n", name );
  1127. return;
  1128. }
  1129. #ifdef DEDICATED
  1130. if ( sv.IsDedicated() )
  1131. #else
  1132. // Stop demo loop
  1133. GetBaseLocalClient().demonum = -1;
  1134. if ( GetBaseLocalClient().m_nMaxClients == 0 || sv.IsDedicated() )
  1135. #endif
  1136. {
  1137. Host_Disconnect( false ); // stop old game
  1138. HostState_NewGame( name, false, bBackground, bSplitScreenConnect );
  1139. }
  1140. if (args.ArgC() == 10)
  1141. {
  1142. if (Q_stricmp(args[2], "setpos") == 0
  1143. && Q_stricmp(args[6], "setang") == 0)
  1144. {
  1145. Vector newpos;
  1146. newpos.x = atof( args[3] );
  1147. newpos.y = atof( args[4] );
  1148. newpos.z = atof( args[5] );
  1149. QAngle newangle;
  1150. newangle.x = atof( args[7] );
  1151. newangle.y = atof( args[8] );
  1152. newangle.z = atof( args[9] );
  1153. HostState_SetSpawnPoint(newpos, newangle);
  1154. }
  1155. }
  1156. }
  1157. // Handle a map command from the console. Active clients are kicked off.
  1158. void Host_Map_f( const CCommand &args )
  1159. {
  1160. Host_Map_Helper( args, (EMapFlags)0 );
  1161. }
  1162. // Handle a map group command from the console
  1163. void Host_MapGroup_f( const CCommand &args )
  1164. {
  1165. if ( args.ArgC() < 2 )
  1166. {
  1167. Warning( "Host_MapGroup_f: No mapgroup specified\n" );
  1168. return;
  1169. }
  1170. Msg( "Setting mapgroup to '%s'\n", args[1] );
  1171. HostState_SetMapGroupName( args[1] );
  1172. }
  1173. // Handle smap command to connect multiple splitscreen users at once
  1174. void Host_SplitScreen_Map_f( const CCommand &args )
  1175. {
  1176. #ifndef _DEMO
  1177. Host_Map_Helper( args, EMAP_SPLITSCREEN );
  1178. #endif
  1179. }
  1180. //-----------------------------------------------------------------------------
  1181. // handle a map_edit <servername> command from the console.
  1182. // Active clients are kicked off.
  1183. // UNDONE: protect this from use if not in dev. mode
  1184. //-----------------------------------------------------------------------------
  1185. #ifndef DEDICATED
  1186. CON_COMMAND( map_edit, "" )
  1187. {
  1188. Host_Map_Helper( args, EMAP_EDIT_MODE );
  1189. }
  1190. #endif
  1191. //-----------------------------------------------------------------------------
  1192. // Purpose: Runs a map as the background
  1193. //-----------------------------------------------------------------------------
  1194. void Host_Map_Background_f( const CCommand &args )
  1195. {
  1196. Host_Map_Helper( args, EMAP_BACKGROUND );
  1197. }
  1198. //-----------------------------------------------------------------------------
  1199. // Purpose: Runs a map in commentary mode
  1200. //-----------------------------------------------------------------------------
  1201. void Host_Map_Commentary_f( const CCommand &args )
  1202. {
  1203. Host_Map_Helper( args, EMAP_COMMENTARY );
  1204. }
  1205. //-----------------------------------------------------------------------------
  1206. // Restarts the current server for a dead player
  1207. //-----------------------------------------------------------------------------
  1208. CON_COMMAND( restart, "Restart the game on the same level (add setpos to jump to current view position on restart)." )
  1209. {
  1210. if (
  1211. #if !defined(DEDICATED)
  1212. demoplayer->IsPlayingBack() ||
  1213. #endif
  1214. !sv.IsActive() )
  1215. return;
  1216. if ( sv.IsMultiplayer() )
  1217. return;
  1218. bool bRememberLocation = ( args.ArgC() == 2 && !Q_stricmp( args[1], "setpos" ) );
  1219. bool bSplitScreenConnect = GET_NUM_SPLIT_SCREEN_PLAYERS() == 2 ;
  1220. Host_Disconnect(false); // stop old game
  1221. if ( !CL_HL2Demo_MapCheck( sv.GetMapName() ) )
  1222. {
  1223. Warning( "map load failed: %s not found or invalid\n", sv.GetMapName() );
  1224. return;
  1225. }
  1226. if ( !CL_PortalDemo_MapCheck( sv.GetMapName() ) )
  1227. {
  1228. Warning( "map load failed: %s not found or invalid\n", sv.GetMapName() );
  1229. return;
  1230. }
  1231. HostState_NewGame( sv.GetMapName(), bRememberLocation, false, bSplitScreenConnect );
  1232. }
  1233. //-----------------------------------------------------------------------------
  1234. // Restarts the current server for a dead player
  1235. //-----------------------------------------------------------------------------
  1236. CON_COMMAND( reload, "Reload the most recent saved game (add setpos to jump to current view position on reload).")
  1237. {
  1238. #ifndef DEDICATED
  1239. const char *pSaveName;
  1240. char name[MAX_OSPATH];
  1241. #endif
  1242. if (
  1243. #if !defined(DEDICATED)
  1244. demoplayer->IsPlayingBack() ||
  1245. #endif
  1246. !sv.IsActive() )
  1247. return;
  1248. if ( sv.IsMultiplayer() )
  1249. return;
  1250. if ( !serverGameDLL->SupportsSaveRestore() )
  1251. return;
  1252. bool remember_location = false;
  1253. if ( args.ArgC() == 2 &&
  1254. !Q_stricmp( args[1], "setpos" ) )
  1255. {
  1256. remember_location = true;
  1257. }
  1258. // See if there is a most recently saved game
  1259. // Restart that game if there is
  1260. // Otherwise, restart the starting game map
  1261. #ifndef DEDICATED
  1262. pSaveName = saverestore->FindRecentSave( name, sizeof( name ) );
  1263. // Put up loading plaque
  1264. SCR_BeginLoadingPlaque();
  1265. {
  1266. // Prepare the offline session for server reload
  1267. KeyValues *pEvent = new KeyValues( "OnEngineClientSignonStatePrepareChange" );
  1268. pEvent->SetString( "reason", "reload" );
  1269. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( pEvent );
  1270. }
  1271. Host_Disconnect( false ); // stop old game
  1272. if ( pSaveName && saverestore->SaveFileExists( pSaveName ) )
  1273. {
  1274. HostState_LoadGame( pSaveName, remember_location, false );
  1275. }
  1276. else
  1277. #endif
  1278. {
  1279. if ( !CL_HL2Demo_MapCheck( host_map.GetString() ) )
  1280. {
  1281. Warning( "map load failed: %s not found or invalid\n", host_map.GetString() );
  1282. return;
  1283. }
  1284. if ( !CL_PortalDemo_MapCheck( host_map.GetString() ) )
  1285. {
  1286. Warning( "map load failed: %s not found or invalid\n", host_map.GetString() );
  1287. return;
  1288. }
  1289. #if !defined( DEDICATED )
  1290. if ( pSaveName && pSaveName[0] )
  1291. {
  1292. Warning( "SAVERESTORE PROBLEM: %s not found! Starting new game in %s\n", pSaveName, host_map.GetString() );
  1293. }
  1294. #endif
  1295. HostState_NewGame( host_map.GetString(), remember_location, false, false );
  1296. }
  1297. }
  1298. //-----------------------------------------------------------------------------
  1299. // Purpose: Goes to a new map, taking all clients along
  1300. // Output : void Host_Changelevel_f
  1301. //-----------------------------------------------------------------------------
  1302. void Host_Changelevel_f( const CCommand &args )
  1303. {
  1304. if ( args.ArgC() < 2 )
  1305. {
  1306. ConMsg( "changelevel <levelname> : continue game on a new level\n" );
  1307. return;
  1308. }
  1309. if ( !sv.IsActive() )
  1310. {
  1311. ConMsg( "Can't changelevel, not running server\n" );
  1312. return;
  1313. }
  1314. char mapname[MAX_PATH];
  1315. Q_StripExtension( args[ 1 ], mapname, sizeof( mapname ) );
  1316. bool bMapMustExist = true;
  1317. static ConVarRef sv_workshop_allow_other_maps( "sv_workshop_allow_other_maps" );
  1318. if ( StringHasPrefix( mapname, "workshop" ) && ( ( mapname[8] == '/' ) || ( mapname[8] == '\\' ) ) &&
  1319. sv_workshop_allow_other_maps.GetBool() )
  1320. bMapMustExist = false;
  1321. if ( bMapMustExist && !modelloader->Map_IsValid( mapname, true ) )
  1322. {
  1323. Host_Map_Helper_FuzzyName( args, mapname, sizeof( mapname ) );
  1324. if ( !modelloader->Map_IsValid( mapname ) )
  1325. {
  1326. Warning( "changelevel failed: %s not found\n", mapname );
  1327. return;
  1328. }
  1329. }
  1330. if ( !CL_HL2Demo_MapCheck( mapname ) )
  1331. {
  1332. Warning( "changelevel failed: %s not found\n", mapname );
  1333. return;
  1334. }
  1335. if ( !CL_PortalDemo_MapCheck( mapname ) )
  1336. {
  1337. Warning( "changelevel failed: %s not found\n", mapname );
  1338. return;
  1339. }
  1340. SetLaunchOptions( args );
  1341. HostState_ChangeLevelMP( mapname, args[2] );
  1342. }
  1343. //-----------------------------------------------------------------------------
  1344. // Purpose: Changing levels within a unit, uses save/restore
  1345. //-----------------------------------------------------------------------------
  1346. void Host_Changelevel2_f( const CCommand &args )
  1347. {
  1348. if ( args.ArgC() < 2 )
  1349. {
  1350. ConMsg ("changelevel2 <levelname> : continue game on a new level in the unit\n");
  1351. return;
  1352. }
  1353. if ( !sv.IsActive() )
  1354. {
  1355. ConMsg( "Can't changelevel2, not in a map\n" );
  1356. return;
  1357. }
  1358. if ( !g_pVEngineServer->IsMapValid( args[1] ) )
  1359. {
  1360. if ( !CL_IsHL2Demo() || (CL_IsHL2Demo() && !(!Q_stricmp( args[1], "d1_trainstation_03" ) || !Q_stricmp( args[1], "d1_town_02a" ))) )
  1361. {
  1362. Warning( "changelevel2 failed: %s not found\n", args[1] );
  1363. return;
  1364. }
  1365. }
  1366. #if !defined(DEDICATED)
  1367. // needs to be before CL_HL2Demo_MapCheck() check as d1_trainstation_03 isn't a valid map
  1368. if ( IsPC() && CL_IsHL2Demo() && !sv.IsDedicated() && !Q_stricmp( args[1], "d1_trainstation_03" ) )
  1369. {
  1370. void CL_DemoTransitionFromTrainstation();
  1371. CL_DemoTransitionFromTrainstation();
  1372. return;
  1373. }
  1374. // needs to be before CL_HL2Demo_MapCheck() check as d1_trainstation_03 isn't a valid map
  1375. if ( IsPC() && CL_IsHL2Demo() && !sv.IsDedicated() && !Q_stricmp( args[1], "d1_town_02a" ) && !Q_stricmp( args[2], "d1_town_02_02a" ))
  1376. {
  1377. void CL_DemoTransitionFromRavenholm();
  1378. CL_DemoTransitionFromRavenholm();
  1379. return;
  1380. }
  1381. if ( IsPC() && CL_IsPortalDemo() && !sv.IsDedicated() && !Q_stricmp( args[1], "testchmb_a_07" ) )
  1382. {
  1383. void CL_DemoTransitionFromTestChmb();
  1384. CL_DemoTransitionFromTestChmb();
  1385. return;
  1386. }
  1387. #endif
  1388. // allow a level transition to d1_trainstation_03 so the Host_Changelevel() can act on it
  1389. if ( !CL_HL2Demo_MapCheck( args[1] ) )
  1390. {
  1391. Warning( "changelevel failed: %s not found\n", args[1] );
  1392. return;
  1393. }
  1394. SetLaunchOptions( args );
  1395. HostState_ChangeLevelSP( args[1], args[2] );
  1396. }
  1397. // On PS/3, due to Matchmaking framework event architecture, Host_Disconnect is called recursively on quit.
  1398. // Bad things happen. Since it's not really necessary to disconnect recursively, we'll track and prevent it on PS/3 during shutdown.
  1399. int g_nHostDisconnectReentrancyCounter = 0;
  1400. class CDisconnectReentrancyCounter
  1401. {
  1402. public:
  1403. CDisconnectReentrancyCounter() { g_nHostDisconnectReentrancyCounter++ ;}
  1404. ~CDisconnectReentrancyCounter() { g_nHostDisconnectReentrancyCounter-- ;}
  1405. };
  1406. //-----------------------------------------------------------------------------
  1407. // Purpose: Shut down client connection and any server
  1408. //-----------------------------------------------------------------------------
  1409. void Host_Disconnect( bool bShowMainMenu )
  1410. {
  1411. #ifdef _PS3
  1412. if ( GetTLSGlobals()->bNormalQuitRequested )
  1413. {
  1414. if ( g_nHostDisconnectReentrancyCounter != 0 )
  1415. {
  1416. return; // do not disconnect recursively on QUIT
  1417. }
  1418. }
  1419. #endif
  1420. IGameEvent *disconnectEvent = g_GameEventManager.CreateEvent( "cs_game_disconnected" );
  1421. if ( disconnectEvent )
  1422. g_GameEventManager.FireEventClientSide( disconnectEvent );
  1423. CDisconnectReentrancyCounter autoReentrancyCounter;
  1424. #if !defined( DEDICATED )
  1425. if ( bShowMainMenu )
  1426. {
  1427. // exiting game
  1428. // ensure commentary state gets cleared
  1429. g_bInCommentaryMode = false;
  1430. }
  1431. #endif
  1432. if ( IsGameConsole() )
  1433. {
  1434. g_pQueuedLoader->EndMapLoading( false );
  1435. }
  1436. // Switch to single-threaded rendering during shutdown to
  1437. // avoid synchronization issues between destructed objects
  1438. // and the renderer
  1439. Host_AllowQueuedMaterialSystem( false );
  1440. #ifndef DEDICATED
  1441. if ( !sv.IsDedicated() )
  1442. {
  1443. FOR_EACH_VALID_SPLITSCREEN_PLAYER( hh )
  1444. {
  1445. ACTIVE_SPLITSCREEN_PLAYER_GUARD( hh );
  1446. GetLocalClient().Disconnect( bShowMainMenu );
  1447. }
  1448. }
  1449. #endif
  1450. #if !defined( DEDICATED )
  1451. if ( g_ClientDLL && bShowMainMenu )
  1452. {
  1453. // forcefully stop any of the full screen video panels used for loading or whatever
  1454. // this is a safety precaution to ensure we don't orpan any of the hacky global video panels
  1455. g_ClientDLL->ShutdownMovies();
  1456. }
  1457. #endif
  1458. HostState_GameShutdown();
  1459. #ifndef DEDICATED
  1460. if ( !sv.IsDedicated() )
  1461. {
  1462. if ( bShowMainMenu && !engineClient->IsDrawingLoadingImage() && ( GetBaseLocalClient().demonum == -1 ) )
  1463. {
  1464. if ( IsGameConsole() )
  1465. {
  1466. // Reset larger configuration material system memory (for map) back down for ui work
  1467. // This must be BEFORE ui gets-rectivated below
  1468. materials->ResetTempHWMemory( true );
  1469. }
  1470. #ifdef _PS3
  1471. if ( GetTLSGlobals()->bNormalQuitRequested )
  1472. {
  1473. return; // do not disconnect recursively on QUIT
  1474. }
  1475. #endif
  1476. EngineVGui()->ActivateGameUI();
  1477. }
  1478. }
  1479. #endif
  1480. }
  1481. //-----------------------------------------------------------------------------
  1482. // Kill the client and any local server.
  1483. //-----------------------------------------------------------------------------
  1484. CON_COMMAND_F( disconnect, "Disconnect game from server.", FCVAR_SERVER_CAN_EXECUTE )
  1485. {
  1486. #ifndef DEDICATED
  1487. GetBaseLocalClient().demonum = -1;
  1488. #endif
  1489. if ( args.ArgC() > 1 )
  1490. {
  1491. COM_ExplainDisconnection( false, "%s", args[ 1 ] );
  1492. }
  1493. Host_Disconnect(true);
  1494. }
  1495. CON_COMMAND( version, "Print version info string." )
  1496. {
  1497. ConMsg( "Protocol version %i [%i/%i]\nExe version %s (%s)\n", GetHostVersion(), GetServerVersion(), GetClientVersion(), Sys_GetVersionString(), Sys_GetProductString() );
  1498. ConMsg( "Exe build: " __TIME__ " " __DATE__ " (%i) (%i)\n", build_number(), GetSteamAppID() );
  1499. }
  1500. //-----------------------------------------------------------------------------
  1501. // Purpose:
  1502. //-----------------------------------------------------------------------------
  1503. CON_COMMAND( pause, "Toggle the server pause state." )
  1504. {
  1505. #if !defined( CLIENT_DLL )
  1506. #ifndef DEDICATED
  1507. if ( !sv.IsDedicated() )
  1508. {
  1509. if ( !GetBaseLocalClient().m_szLevelName[ 0 ] )
  1510. return;
  1511. }
  1512. #endif
  1513. if ( !sv.IsPausable() )
  1514. return;
  1515. // toggle paused state
  1516. sv.SetPaused( !sv.IsPaused() );
  1517. // send text message who paused the game
  1518. if ( host_client )
  1519. sv.BroadcastPrintf( "%s %s the game\n", host_client->GetClientName(), sv.IsPaused() ? "paused" : "unpaused" );
  1520. #endif
  1521. }
  1522. //-----------------------------------------------------------------------------
  1523. // Purpose:
  1524. //-----------------------------------------------------------------------------
  1525. CON_COMMAND( setpause, "Set the pause state of the server." )
  1526. {
  1527. #if !defined( CLIENT_DLL )
  1528. #ifndef DEDICATED
  1529. if ( !sv.IsDedicated() )
  1530. {
  1531. if ( !GetBaseLocalClient().m_szLevelName[ 0 ] )
  1532. return;
  1533. }
  1534. #endif
  1535. if ( !sv.IsPausable() )
  1536. return;
  1537. sv.SetPaused( true );
  1538. if ( !args.FindArg( "nomsg" ) )
  1539. {
  1540. // send text message who paused the game
  1541. if ( host_client )
  1542. sv.BroadcastPrintf( "%s paused the game\n", host_client->GetClientName() );
  1543. }
  1544. #endif
  1545. }
  1546. //-----------------------------------------------------------------------------
  1547. // Purpose:
  1548. //-----------------------------------------------------------------------------
  1549. CON_COMMAND( unpause, "Unpause the game." )
  1550. {
  1551. #if !defined( CLIENT_DLL )
  1552. #ifndef DEDICATED
  1553. if ( !sv.IsDedicated() )
  1554. {
  1555. if ( !GetBaseLocalClient().m_szLevelName[ 0 ] )
  1556. return;
  1557. }
  1558. #endif
  1559. if ( !sv.IsPaused() )
  1560. return;
  1561. sv.SetPaused( false );
  1562. if ( !args.FindArg( "nomsg" ) )
  1563. {
  1564. // send text messaage who unpaused the game
  1565. if ( host_client )
  1566. sv.BroadcastPrintf( "%s unpaused the game\n", host_client->GetClientName() );
  1567. }
  1568. #endif
  1569. }
  1570. //-----------------------------------------------------------------------------
  1571. // Kicks a user off of the server using their userid or uniqueid
  1572. //-----------------------------------------------------------------------------
  1573. CON_COMMAND( kickid_ex, "Kick a player by userid or uniqueid, provide a force-the-kick flag and also assign a message." )
  1574. {
  1575. const char *pszArg1 = NULL, *pszMessage = NULL;
  1576. int iSearchIndex = -1;
  1577. char szSearchString[128];
  1578. int argsStartNum = 1;
  1579. bool bSteamID = false;
  1580. bool bForce = false;
  1581. if ( args.ArgC() <= 1 )
  1582. {
  1583. ConMsg( "Usage: kickid_ex < userid | uniqueid > < force ( 0 / 1 ) > { message }\n" );
  1584. return;
  1585. }
  1586. // get the first argument
  1587. pszArg1 = args[1];
  1588. // if the first letter is a charcter then
  1589. // we're searching for a uniqueid ( e.g. STEAM_ )
  1590. if ( *pszArg1 < '0' || *pszArg1 > '9' )
  1591. {
  1592. // SteamID (need to reassemble it)
  1593. if ( StringHasPrefix( pszArg1, STEAM_PREFIX ) && Q_strstr( args[2], ":" ) )
  1594. {
  1595. Q_snprintf( szSearchString, sizeof( szSearchString ), "%s:%s:%s", pszArg1, args[3], args[5] );
  1596. argsStartNum = 5;
  1597. bSteamID = true;
  1598. }
  1599. // some other ID (e.g. "UNKNOWN", "STEAM_ID_PENDING", "STEAM_ID_LAN")
  1600. // NOTE: assumed to be one argument
  1601. else
  1602. {
  1603. Q_snprintf( szSearchString, sizeof( szSearchString ), "%s", pszArg1 );
  1604. }
  1605. }
  1606. // this is a userid
  1607. else
  1608. {
  1609. iSearchIndex = Q_atoi( pszArg1 );
  1610. }
  1611. // check for game type and game mode
  1612. if ( args.ArgC() > argsStartNum )
  1613. {
  1614. if ( atoi( args[ argsStartNum + 1 ] ) == 1 )
  1615. {
  1616. bForce = true;
  1617. }
  1618. argsStartNum++;
  1619. }
  1620. // check for a message
  1621. if ( args.ArgC() > argsStartNum )
  1622. {
  1623. int j;
  1624. int dataLen = 0;
  1625. pszMessage = args.ArgS();
  1626. for ( j = 1; j <= argsStartNum; j++ )
  1627. {
  1628. dataLen += Q_strlen( args[j] ) + 1; // +1 for the space between args
  1629. }
  1630. if ( bSteamID )
  1631. {
  1632. dataLen -= 5; // SteamIDs don't have spaces between the args[) values
  1633. }
  1634. if ( dataLen > Q_strlen( pszMessage ) ) // saftey check
  1635. {
  1636. pszMessage = NULL;
  1637. }
  1638. else
  1639. {
  1640. pszMessage += dataLen;
  1641. }
  1642. }
  1643. PerformKick( args.Source(), iSearchIndex, szSearchString, bForce, pszMessage );
  1644. }
  1645. //-----------------------------------------------------------------------------
  1646. // Kicks a user off of the server using their userid or uniqueid
  1647. //-----------------------------------------------------------------------------
  1648. CON_COMMAND( kickid, "Kick a player by userid or uniqueid, with a message." )
  1649. {
  1650. const char *pszArg1 = NULL, *pszMessage = NULL;
  1651. int iSearchIndex = -1;
  1652. char szSearchString[128];
  1653. int argsStartNum = 1;
  1654. bool bSteamID = false;
  1655. if ( args.ArgC() <= 1 )
  1656. {
  1657. ConMsg( "Usage: kickid < userid | uniqueid > { message }\n" );
  1658. return;
  1659. }
  1660. // get the first argument
  1661. pszArg1 = args[1];
  1662. // if the first letter is a charcter then
  1663. // we're searching for a uniqueid ( e.g. STEAM_ )
  1664. if ( *pszArg1 < '0' || *pszArg1 > '9' )
  1665. {
  1666. // SteamID (need to reassemble it)
  1667. if ( StringHasPrefix( pszArg1, STEAM_PREFIX ) && Q_strstr( args[2], ":" ) )
  1668. {
  1669. Q_snprintf( szSearchString, sizeof( szSearchString ), "%s:%s:%s", pszArg1, args[3], args[5] );
  1670. argsStartNum = 5;
  1671. bSteamID = true;
  1672. }
  1673. // some other ID (e.g. "UNKNOWN", "STEAM_ID_PENDING", "STEAM_ID_LAN")
  1674. // NOTE: assumed to be one argument
  1675. else
  1676. {
  1677. Q_snprintf( szSearchString, sizeof( szSearchString ), "%s", pszArg1 );
  1678. }
  1679. }
  1680. // this is a userid
  1681. else
  1682. {
  1683. iSearchIndex = Q_atoi( pszArg1 );
  1684. }
  1685. // check for a message
  1686. if ( args.ArgC() > argsStartNum )
  1687. {
  1688. int j;
  1689. int dataLen = 0;
  1690. pszMessage = args.ArgS();
  1691. for ( j = 1; j <= argsStartNum; j++ )
  1692. {
  1693. dataLen += Q_strlen( args[j] ) + 1; // +1 for the space between args
  1694. }
  1695. if ( bSteamID )
  1696. {
  1697. dataLen -= 5; // SteamIDs don't have spaces between the args[) values
  1698. }
  1699. if ( dataLen > Q_strlen( pszMessage ) ) // saftey check
  1700. {
  1701. pszMessage = NULL;
  1702. }
  1703. else
  1704. {
  1705. pszMessage += dataLen;
  1706. }
  1707. }
  1708. PerformKick( args.Source(), iSearchIndex, szSearchString, false, pszMessage );
  1709. }
  1710. void PerformKick( cmd_source_t commandSource, int iSearchIndex, char* szSearchString, bool bForceKick, const char* pszMessage )
  1711. {
  1712. IClient *client = NULL;
  1713. char *who = "Console";
  1714. // find this client
  1715. int i;
  1716. for ( i = 0; i < sv.GetClientCount(); i++ )
  1717. {
  1718. client = sv.GetClient( i );
  1719. if ( !client->IsConnected() )
  1720. {
  1721. continue;
  1722. }
  1723. // searching by UserID
  1724. if ( iSearchIndex != -1 )
  1725. {
  1726. if ( client->GetUserID() == iSearchIndex )
  1727. {
  1728. // found!
  1729. break;
  1730. }
  1731. }
  1732. // searching by UniqueID
  1733. else
  1734. {
  1735. if ( Q_stricmp( client->GetNetworkIDString(), szSearchString ) == 0 )
  1736. {
  1737. // found!
  1738. break;
  1739. }
  1740. }
  1741. }
  1742. // now kick them
  1743. if ( i < sv.GetClientCount() )
  1744. {
  1745. if ( client->IsSplitScreenUser() && client->GetSplitScreenOwner() )
  1746. {
  1747. client = client->GetSplitScreenOwner();
  1748. }
  1749. if ( commandSource == kCommandSrcNetClient )
  1750. {
  1751. who = host_client->m_Name;
  1752. }
  1753. if ( host_client == client && !sv.IsDedicated() && !bForceKick )
  1754. {
  1755. // can't kick yourself!
  1756. return;
  1757. }
  1758. if ( iSearchIndex != -1 || !client->IsFakeClient() )
  1759. {
  1760. if ( pszMessage )
  1761. {
  1762. client->Disconnect( CFmtStr( "Kicked by %s : %s", who, pszMessage ) );
  1763. }
  1764. else
  1765. {
  1766. client->Disconnect( CFmtStr( "Kicked by %s", who ) );
  1767. }
  1768. }
  1769. }
  1770. else
  1771. {
  1772. if ( iSearchIndex != -1 )
  1773. {
  1774. ConMsg( "userid \"%d\" not found\n", iSearchIndex );
  1775. }
  1776. else
  1777. {
  1778. ConMsg( "uniqueid \"%s\" not found\n", szSearchString );
  1779. }
  1780. }
  1781. }
  1782. /*
  1783. ==================
  1784. Host_Kick_f
  1785. Kicks a user off of the server using their name
  1786. ==================
  1787. */
  1788. CON_COMMAND( kick, "Kick a player by name." )
  1789. {
  1790. char *who = "Console";
  1791. char *pszName = NULL;
  1792. IClient *client = NULL;
  1793. int i = 0;
  1794. char name[64];
  1795. if ( args.ArgC() <= 1 )
  1796. {
  1797. ConMsg( "Usage: kick < name >\n" );
  1798. return;
  1799. }
  1800. // copy the name to a local buffer
  1801. memset( name, 0, sizeof(name) );
  1802. Q_strncpy( name, args.ArgS(), sizeof(name) );
  1803. pszName = name;
  1804. // safety check
  1805. if ( pszName && pszName[0] != 0 )
  1806. {
  1807. //HACK-HACK
  1808. // check for the name surrounded by quotes (comes in this way from rcon)
  1809. int len = Q_strlen( pszName ) - 1; // (minus one since we start at 0)
  1810. if ( pszName[0] == '"' && pszName[len] == '"' )
  1811. {
  1812. // get rid of the quotes at the beginning and end
  1813. pszName[len] = 0;
  1814. pszName++;
  1815. }
  1816. for ( i = 0; i < sv.GetClientCount(); i++ )
  1817. {
  1818. client = sv.GetClient(i);
  1819. if ( !client->IsConnected() )
  1820. continue;
  1821. // found!
  1822. if ( Q_strcasecmp( client->GetClientName(), pszName ) == 0 )
  1823. break;
  1824. }
  1825. // now kick them
  1826. if ( i < sv.GetClientCount() )
  1827. {
  1828. if ( client->IsSplitScreenUser() && client->GetSplitScreenOwner() )
  1829. {
  1830. client = client->GetSplitScreenOwner();
  1831. }
  1832. if ( args.Source() == kCommandSrcNetClient )
  1833. {
  1834. who = host_client->m_Name;
  1835. }
  1836. // can't kick yourself!
  1837. if ( host_client == client && !sv.IsDedicated() )
  1838. return;
  1839. client->Disconnect( CFmtStr( "Kicked by %s", who ) );
  1840. }
  1841. else
  1842. {
  1843. ConMsg( "Can't kick \"%s\", name not found\n", pszName );
  1844. }
  1845. }
  1846. }
  1847. /*
  1848. ===============================================================================
  1849. DEBUGGING TOOLS
  1850. ===============================================================================
  1851. */
  1852. void Host_PrintMemoryStatus( const char *mapname )
  1853. {
  1854. const float MB = 1.0f / ( 1024*1024 );
  1855. Assert( mapname );
  1856. #ifdef PLATFORM_LINUX
  1857. struct mallinfo memstats = mallinfo( );
  1858. Msg( "[MEMORYSTATUS] [%s] Operating system reports sbrk size: %.2f MB, Used: %.2f MB, #mallocs = %d\n",
  1859. mapname, MB*memstats.arena, MB*memstats.uordblks, memstats.hblks );
  1860. #elif defined(PLATFORM_OSX)
  1861. struct mstats stats = mstats();
  1862. Msg( "[MEMORYSTATUS] [%s] Operating system reports Used: %.2f MB, Free: %.2f Total: %.2f\n",
  1863. mapname, MB*stats.bytes_used, MB*stats.bytes_free, MB*stats.bytes_total );
  1864. #elif defined( _PS3 )
  1865. // NOTE: for PS3 nFreeMemory can be negative (on a devkit, we can use more memory than a retail kit has)
  1866. int nUsedMemory, nFreeMemory, nAvailable;
  1867. g_pMemAlloc->GlobalMemoryStatus( (size_t *)&nUsedMemory, (size_t *)&nFreeMemory );
  1868. nAvailable = nUsedMemory + nFreeMemory;
  1869. Msg( "[MEMORYSTATUS] [%s] Operating system reports Available: %.2f MB, Used: %.2f MB, Free: %.2f MB\n",
  1870. mapname, MB*nAvailable, MB*nUsedMemory, MB*nFreeMemory );
  1871. #elif defined(PLATFORM_WINDOWS)
  1872. MEMORYSTATUSEX statex;
  1873. statex.dwLength = sizeof(statex);
  1874. GlobalMemoryStatusEx( &statex );
  1875. Msg( "[MEMORYSTATUSEX] [%s] Operating system reports Physical Available: %.2f MB, Physical Used: %.2f MB, Physical Free: %.2f MB\n Virtual Size: %.2f, Virtual Free: %.2f MB, PageFile Size: %.2f, PageFile Free: %.2f MB\n",
  1876. mapname, MB*statex.ullTotalPhys, MB*( statex.ullTotalPhys - statex.ullAvailPhys ), MB*statex.ullAvailPhys, MB*statex.ullTotalVirtual, MB*statex.ullAvailVirtual, MB*statex.ullTotalPageFile, MB*statex.ullAvailPageFile );
  1877. #endif
  1878. if ( IsPS3() )
  1879. {
  1880. // Include stats on GPU memory usage
  1881. GPUMemoryStats stats;
  1882. materials->GetGPUMemoryStats( stats );
  1883. g_pMemAlloc->SetStatsExtraInfo( mapname, CFmtStr( "%d %d %d %d %d %d %d",
  1884. stats.nGPUMemSize, stats.nGPUMemFree, stats.nTextureSize, stats.nRTSize, stats.nVBSize, stats.nIBSize, stats.nUnknown ) );
  1885. Msg( "[MEMORYSTATUS] [%s] RSX memory: total %.1fkb, free %.1fkb, textures %.1fkb, render targets %.1fkb, vertex buffers %.1fkb, index buffers %.1fkb, unknown %.1fkb\n",
  1886. mapname, stats.nGPUMemSize/1024.0f, stats.nGPUMemFree/1024.0f, stats.nTextureSize/1024.0f, stats.nRTSize/1024.0f, stats.nVBSize/1024.0f, stats.nIBSize/1024.0f, stats.nUnknown/1024.0f );
  1887. }
  1888. else
  1889. {
  1890. g_pMemAlloc->SetStatsExtraInfo( mapname, "" );
  1891. }
  1892. int nTotal = g_pMemAlloc->GetSize( 0 );
  1893. if (nTotal == -1)
  1894. {
  1895. Msg( "Internal heap corrupted!\n" );
  1896. }
  1897. else
  1898. {
  1899. Msg( "Internal heap reports: %5.2f MB (%d bytes)\n", nTotal/(1024.0f*1024.0f), nTotal );
  1900. }
  1901. Msg( "\nHunk Memory Used:\n" );
  1902. Hunk_Print();
  1903. Msg( "\nDatacache reports:\n" );
  1904. g_pDataCache->OutputReport( DC_SUMMARY_REPORT, NULL );
  1905. }
  1906. //-----------------------------------------------------------------------------
  1907. // Dump memory stats
  1908. //-----------------------------------------------------------------------------
  1909. CON_COMMAND( memory, "Print memory stats." )
  1910. {
  1911. ConMsg( "Heap Used:\n" );
  1912. int nTotal = g_pMemAlloc->GetSize( 0 );
  1913. if (nTotal == -1)
  1914. {
  1915. ConMsg( "Corrupted!\n" );
  1916. }
  1917. else
  1918. {
  1919. ConMsg( "%5.2f MB (%d bytes)\n", nTotal/(1024.0f*1024.0f), nTotal );
  1920. }
  1921. #ifdef VPROF_ENABLED
  1922. ConMsg("\nVideo Memory Used:\n");
  1923. CVProfile *pProf = &g_VProfCurrentProfile;
  1924. int prefixLen = V_strlen( "TexGroup_Global_" );
  1925. float total = 0.0f;
  1926. for ( int i=0; i < pProf->GetNumCounters(); i++ )
  1927. {
  1928. if ( pProf->GetCounterGroup( i ) == COUNTER_GROUP_TEXTURE_GLOBAL )
  1929. {
  1930. float value = pProf->GetCounterValue( i ) * (1.0f/(1024.0f*1024.0f) );
  1931. total += value;
  1932. const char *pName = pProf->GetCounterName( i );
  1933. if ( StringHasPrefix( pName, "TexGroup_Global_" ) )
  1934. {
  1935. pName += prefixLen;
  1936. }
  1937. ConMsg( "%5.2f MB: %s\n", value, pName );
  1938. }
  1939. }
  1940. ConMsg("------------------\n");
  1941. ConMsg( "%5.2f MB: total\n", total );
  1942. #endif
  1943. ConMsg( "\nHunk Memory Used:\n" );
  1944. Hunk_Print();
  1945. }
  1946. /*
  1947. ===============================================================================
  1948. DEMO LOOP CONTROL
  1949. ===============================================================================
  1950. */
  1951. #ifndef DEDICATED
  1952. //MOTODO move all demo commands to demoplayer
  1953. //-----------------------------------------------------------------------------
  1954. // Purpose: Gets number of valid demo names
  1955. // Output : int
  1956. //-----------------------------------------------------------------------------
  1957. int Host_GetNumDemos()
  1958. {
  1959. int c = 0;
  1960. #ifndef DEDICATED
  1961. for ( int i = 0; i < MAX_DEMOS; ++i )
  1962. {
  1963. const char *demoname = GetBaseLocalClient().demos[ i ];
  1964. if ( !demoname[ 0 ] )
  1965. break;
  1966. ++c;
  1967. }
  1968. #endif
  1969. return c;
  1970. }
  1971. //-----------------------------------------------------------------------------
  1972. // Purpose:
  1973. //-----------------------------------------------------------------------------
  1974. void Host_PrintDemoList()
  1975. {
  1976. int count = Host_GetNumDemos();
  1977. #ifndef DEDICATED
  1978. int next = GetBaseLocalClient().demonum;
  1979. if ( next >= count || next < 0 )
  1980. {
  1981. next = 0;
  1982. }
  1983. for ( int i = 0; i < MAX_DEMOS; ++i )
  1984. {
  1985. const char *demoname = GetBaseLocalClient().demos[ i ];
  1986. if ( !demoname[ 0 ] )
  1987. break;
  1988. bool isnextdemo = next == i ? true : false;
  1989. DevMsg( "%3s % 2i : %20s\n", isnextdemo ? "-->" : " ", i, GetBaseLocalClient().demos[ i ] );
  1990. }
  1991. #endif
  1992. if ( !count )
  1993. {
  1994. DevMsg( "No demos in list, use startdemos <demoname> <demoname2> to specify\n" );
  1995. }
  1996. }
  1997. #ifndef DEDICATED
  1998. //-----------------------------------------------------------------------------
  1999. //
  2000. // Con commands related to demos, not available on dedicated servers
  2001. //
  2002. //-----------------------------------------------------------------------------
  2003. //-----------------------------------------------------------------------------
  2004. // Purpose: Specify list of demos for the "demos" command
  2005. //-----------------------------------------------------------------------------
  2006. CON_COMMAND( startdemos, "Play demos in demo sequence." )
  2007. {
  2008. int c = args.ArgC() - 1;
  2009. if (c > MAX_DEMOS)
  2010. {
  2011. Msg ("Max %i demos in demoloop\n", MAX_DEMOS);
  2012. c = MAX_DEMOS;
  2013. }
  2014. Msg ("%i demo(s) in loop\n", c);
  2015. for ( int i=1 ; i<c+1 ; i++ )
  2016. {
  2017. Q_strncpy( GetBaseLocalClient().demos[i-1], args[i], sizeof(GetBaseLocalClient().demos[0]) );
  2018. }
  2019. GetBaseLocalClient().demonum = 0;
  2020. Host_PrintDemoList();
  2021. if ( !sv.IsActive() && !demoplayer->IsPlayingBack() )
  2022. {
  2023. CL_NextDemo ();
  2024. }
  2025. else
  2026. {
  2027. GetBaseLocalClient().demonum = -1;
  2028. }
  2029. }
  2030. //-----------------------------------------------------------------------------
  2031. // Purpose: Return to looping demos, optional resume demo index
  2032. //-----------------------------------------------------------------------------
  2033. CON_COMMAND( demos, "Demo demo file sequence." )
  2034. {
  2035. CClientState &cl = GetBaseLocalClient();
  2036. int oldn = cl.demonum;
  2037. cl.demonum = -1;
  2038. Host_Disconnect(false);
  2039. cl.demonum = oldn;
  2040. if (cl.demonum == -1)
  2041. cl.demonum = 0;
  2042. if ( args.ArgC() == 2 )
  2043. {
  2044. int numdemos = Host_GetNumDemos();
  2045. if ( numdemos >= 1 )
  2046. {
  2047. cl.demonum = clamp( Q_atoi( args[1] ), 0, numdemos - 1 );
  2048. DevMsg( "Jumping to %s\n", cl.demos[ cl.demonum ] );
  2049. }
  2050. }
  2051. Host_PrintDemoList();
  2052. CL_NextDemo ();
  2053. }
  2054. //-----------------------------------------------------------------------------
  2055. // Purpose: Stop current demo
  2056. //-----------------------------------------------------------------------------
  2057. CON_COMMAND_F( stopdemo, "Stop playing back a demo.", FCVAR_DONTRECORD )
  2058. {
  2059. if ( !demoplayer->IsPlayingBack() )
  2060. return;
  2061. Host_Disconnect (true);
  2062. }
  2063. //-----------------------------------------------------------------------------
  2064. // Purpose: Skip to next demo
  2065. //-----------------------------------------------------------------------------
  2066. CON_COMMAND( nextdemo, "Play next demo in sequence." )
  2067. {
  2068. if ( args.ArgC() == 2 )
  2069. {
  2070. int numdemos = Host_GetNumDemos();
  2071. if ( numdemos >= 1 )
  2072. {
  2073. GetBaseLocalClient().demonum = clamp( Q_atoi( args[1] ), 0, numdemos - 1 );
  2074. DevMsg( "Jumping to %s\n", GetBaseLocalClient().demos[ GetBaseLocalClient().demonum ] );
  2075. }
  2076. }
  2077. Host_EndGame( false, "Moving to next demo..." );
  2078. }
  2079. //-----------------------------------------------------------------------------
  2080. // Purpose: Print out the current demo play order
  2081. //-----------------------------------------------------------------------------
  2082. CON_COMMAND( demolist, "Print demo sequence list." )
  2083. {
  2084. Host_PrintDemoList();
  2085. }
  2086. //-----------------------------------------------------------------------------
  2087. // Purpose: Host_Soundfade_f
  2088. //-----------------------------------------------------------------------------
  2089. CON_COMMAND_F( soundfade, "Fade client volume.", FCVAR_SERVER_CAN_EXECUTE )
  2090. {
  2091. float percent;
  2092. float inTime, holdTime, outTime;
  2093. if (args.ArgC() != 3 && args.ArgC() != 5)
  2094. {
  2095. Msg("soundfade <percent> <hold> [<out> <int>]\n");
  2096. return;
  2097. }
  2098. percent = clamp( atof(args[1]), 0.0f, 100.0f );
  2099. holdTime = MAX( 0.0f, atof(args[2]) );
  2100. inTime = 0.0f;
  2101. outTime = 0.0f;
  2102. if (args.ArgC() == 5)
  2103. {
  2104. outTime = MAX( 0.0f, atof(args[3]) );
  2105. inTime = MAX( 0.0f, atof( args[4]) );
  2106. }
  2107. S_SoundFade( percent, holdTime, outTime, inTime );
  2108. }
  2109. #endif // !DEDICATED
  2110. #endif
  2111. //-----------------------------------------------------------------------------
  2112. // Shutdown the server
  2113. //-----------------------------------------------------------------------------
  2114. CON_COMMAND( killserver, "Shutdown the server." )
  2115. {
  2116. Host_Disconnect(true);
  2117. if ( !sv.IsDedicated() )
  2118. {
  2119. // close network sockets and reopen if multiplayer game
  2120. NET_SetMultiplayer( false );
  2121. NET_SetMultiplayer( !!( g_pMatchFramework->GetMatchTitle()->GetTitleSettingsFlags() & MATCHTITLE_SETTING_MULTIPLAYER ) );
  2122. }
  2123. }
  2124. // [hpe:jason] Enable ENGINE_VOICE for Cstrike 1.5, all platforms
  2125. #if defined( CSTRIKE15 )
  2126. ConVar voice_vox( "voice_vox", "false", FCVAR_DEVELOPMENTONLY ); // Controls open microphone (no push to talk) settings
  2127. #undef NO_ENGINE_VOICE
  2128. #else
  2129. #define NO_ENGINE_VOICE
  2130. #endif
  2131. #ifdef NO_ENGINE_VOICE
  2132. ConVar voice_ptt( "voice_ptt", "-1.0", FCVAR_DEVELOPMENTONLY ); // Time when ptt key was released, 0 means to keep transmitting voice
  2133. #endif
  2134. #if !defined(DEDICATED)
  2135. void Host_VoiceRecordStart_f(void)
  2136. {
  2137. #ifdef NO_ENGINE_VOICE
  2138. voice_ptt.SetValue( 0 );
  2139. #else
  2140. ConVarRef voice_vox( "voice_vox" );
  2141. if ( voice_vox.GetBool() == true )
  2142. return;
  2143. int iSsSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  2144. if ( GetLocalClient( iSsSlot ).IsActive() )
  2145. {
  2146. const char *pUncompressedFile = NULL;
  2147. const char *pDecompressedFile = NULL;
  2148. const char *pInputFile = NULL;
  2149. if (voice_recordtofile.GetInt())
  2150. {
  2151. pUncompressedFile = "voice_micdata.wav";
  2152. pDecompressedFile = "voice_decompressed.wav";
  2153. }
  2154. if (voice_inputfromfile.GetInt())
  2155. {
  2156. pInputFile = "voice_input.wav";
  2157. }
  2158. #if !defined( NO_VOICE )
  2159. if (Voice_RecordStart(pUncompressedFile, pDecompressedFile, pInputFile))
  2160. {
  2161. }
  2162. #endif
  2163. }
  2164. #endif // #ifndef NO_ENGINE_VOICE
  2165. }
  2166. void Host_VoiceRecordStop_f( const CCommand &args )
  2167. {
  2168. #ifdef NO_ENGINE_VOICE
  2169. voice_ptt.SetValue( (float) Plat_FloatTime() );
  2170. #else
  2171. ConVarRef voice_vox( "voice_vox" );
  2172. if ( voice_vox.GetBool() == true )
  2173. return;
  2174. int iSsSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  2175. if ( GetLocalClient( iSsSlot ).IsActive() )
  2176. {
  2177. #if !defined( NO_VOICE )
  2178. if (Voice_IsRecording())
  2179. {
  2180. CL_SendVoicePacket(true);
  2181. Voice_RecordStop();
  2182. }
  2183. if ( args.ArgC() == 2 && V_strcasecmp( args[1], "force" ) == 0 )
  2184. {
  2185. // do nothing
  2186. }
  2187. else
  2188. {
  2189. voice_vox.SetValue( 0 );
  2190. }
  2191. #endif
  2192. }
  2193. #endif // #ifndef NO_ENGINE_VOICE
  2194. }
  2195. #endif
  2196. // TERROR: adding a toggle for voice
  2197. void Host_VoiceToggle_f( const CCommand &args )
  2198. {
  2199. #ifdef NO_ENGINE_VOICE
  2200. voice_ptt.SetValue( (float) ( voice_ptt.GetFloat() ? 0.0f : Plat_FloatTime() ) );
  2201. #endif
  2202. #if !defined( DEDICATED ) && !defined( NO_ENGINE_VOICE )
  2203. #if !defined( NO_VOICE )
  2204. if ( GetBaseLocalClient().IsActive() )
  2205. {
  2206. bool bToggle = false;
  2207. if ( args.ArgC() == 2 && V_strcasecmp( args[1], "on" ) == 0 )
  2208. {
  2209. bToggle = true;
  2210. }
  2211. if ( Voice_IsRecording() && bToggle == false )
  2212. {
  2213. CL_SendVoicePacket(true);
  2214. Voice_RecordStop();
  2215. }
  2216. else if ( bToggle == true && Voice_IsRecording() == false )
  2217. {
  2218. const char *pUncompressedFile = NULL;
  2219. const char *pDecompressedFile = NULL;
  2220. const char *pInputFile = NULL;
  2221. if (voice_recordtofile.GetInt())
  2222. {
  2223. pUncompressedFile = "voice_micdata.wav";
  2224. pDecompressedFile = "voice_decompressed.wav";
  2225. }
  2226. if (voice_inputfromfile.GetInt())
  2227. {
  2228. pInputFile = "voice_input.wav";
  2229. }
  2230. Voice_RecordStart( pUncompressedFile, pDecompressedFile, pInputFile );
  2231. }
  2232. }
  2233. #endif
  2234. #endif
  2235. }
  2236. //-----------------------------------------------------------------------------
  2237. // Purpose: Wrapper for modelloader->Print() function call
  2238. //-----------------------------------------------------------------------------
  2239. CON_COMMAND( listmodels, "List loaded models." )
  2240. {
  2241. modelloader->Print();
  2242. }
  2243. /*
  2244. ==================
  2245. Host_IncrementCVar
  2246. ==================
  2247. */
  2248. CON_COMMAND_F( incrementvar, "Increment specified convar value.", FCVAR_DONTRECORD )
  2249. {
  2250. if( args.ArgC() != 5 )
  2251. {
  2252. Warning( "Usage: incrementvar varName minValue maxValue delta\n" );
  2253. return;
  2254. }
  2255. const char *varName = args[ 1 ];
  2256. if( !varName )
  2257. {
  2258. ConDMsg( "Host_IncrementCVar_f without a varname\n" );
  2259. return;
  2260. }
  2261. ConVar *var = ( ConVar * )g_pCVar->FindVar( varName );
  2262. if( !var )
  2263. {
  2264. ConDMsg( "cvar \"%s\" not found\n", varName );
  2265. return;
  2266. }
  2267. float currentValue = var->GetFloat();
  2268. float startValue = atof( args[ 2 ] );
  2269. float endValue = atof( args[ 3 ] );
  2270. float delta = atof( args[ 4 ] );
  2271. float newValue = currentValue + delta;
  2272. if( newValue > endValue )
  2273. {
  2274. newValue = startValue;
  2275. }
  2276. else if ( newValue < startValue )
  2277. {
  2278. newValue = endValue;
  2279. }
  2280. // Conver incrementvar command to direct sets to avoid any problems with state in a demo loop.
  2281. Cbuf_AddText( Cbuf_GetCurrentPlayer(), va("%s %f", varName, newValue) );
  2282. ConDMsg( "%s = %f\n", var->GetName(), newValue );
  2283. }
  2284. //-----------------------------------------------------------------------------
  2285. // Host_MultiplyCVar_f
  2286. //-----------------------------------------------------------------------------
  2287. CON_COMMAND_F( multvar, "Multiply specified convar value.", FCVAR_DONTRECORD )
  2288. {
  2289. if (( args.ArgC() != 5 ))
  2290. {
  2291. Warning( "Usage: multvar varName minValue maxValue factor\n" );
  2292. return;
  2293. }
  2294. const char *varName = args[ 1 ];
  2295. if( !varName )
  2296. {
  2297. ConDMsg( "multvar without a varname\n" );
  2298. return;
  2299. }
  2300. ConVar *var = ( ConVar * )g_pCVar->FindVar( varName );
  2301. if( !var )
  2302. {
  2303. ConDMsg( "cvar \"%s\" not found\n", varName );
  2304. return;
  2305. }
  2306. float currentValue = var->GetFloat();
  2307. float startValue = atof( args[ 2 ] );
  2308. float endValue = atof( args[ 3 ] );
  2309. float factor = atof( args[ 4 ] );
  2310. float newValue = currentValue * factor;
  2311. if( newValue > endValue )
  2312. {
  2313. newValue = endValue;
  2314. }
  2315. else if ( newValue < startValue )
  2316. {
  2317. newValue = startValue;
  2318. }
  2319. // Conver incrementvar command to direct sets to avoid any problems with state in a demo loop.
  2320. Cbuf_AddText( Cbuf_GetCurrentPlayer(), va("%s %f", varName, newValue) );
  2321. ConDMsg( "%s = %f\n", var->GetName(), newValue );
  2322. }
  2323. //-----------------------------------------------------------------------------
  2324. // Purpose:
  2325. //-----------------------------------------------------------------------------
  2326. CON_COMMAND( dumpstringtables, "Print string tables to console." )
  2327. {
  2328. SV_PrintStringTables();
  2329. #ifndef DEDICATED
  2330. CL_PrintStringTables();
  2331. #endif
  2332. }
  2333. CON_COMMAND( stringtabledictionary, "Create dictionary for current strings." )
  2334. {
  2335. if ( !sv.IsActive() )
  2336. {
  2337. Warning( "stringtabledictionary: only valid when running a map\n" );
  2338. return;
  2339. }
  2340. SV_CreateDictionary( sv.GetMapName() );
  2341. }
  2342. // Register shared commands
  2343. CON_COMMAND_F( quit, "Exit the engine.", FCVAR_NONE )
  2344. {
  2345. if ( args.ArgC() > 1 && V_strcmp( args[ 1 ], "prompt" ) == 0 )
  2346. {
  2347. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "quit_prompt" );
  2348. return;
  2349. }
  2350. Host_Quit_f();
  2351. }
  2352. static ConCommand cmd_exit("exit", Host_Quit_f, "Exit the engine.");
  2353. #ifndef DEDICATED
  2354. #ifdef VOICE_OVER_IP
  2355. static ConCommand startvoicerecord("+voicerecord", Host_VoiceRecordStart_f);
  2356. static ConCommand endvoicerecord("-voicerecord", Host_VoiceRecordStop_f);
  2357. static ConCommand togglevoicerecord("voicerecord_toggle", Host_VoiceToggle_f);
  2358. #endif // VOICE_OVER_IP
  2359. #endif
  2360. //-----------------------------------------------------------------------------
  2361. // Purpose: Force a null pointer crash. useful for testing minidumps
  2362. //-----------------------------------------------------------------------------
  2363. CON_COMMAND_F( crash, "Cause the engine to crash (Debug!!)", FCVAR_CHEAT )
  2364. {
  2365. Msg( "forcing crash\n" );
  2366. #if defined( _X360 )
  2367. DmCrashDump( FALSE );
  2368. #else
  2369. char *p = 0;
  2370. *p = 0;
  2371. #endif
  2372. }
  2373. CON_COMMAND_F( spincycle, "Cause the engine to spincycle (Debug!!)", FCVAR_CHEAT )
  2374. {
  2375. if ( args.ArgC() > 1 )
  2376. {
  2377. const char *pParam = args.Arg( 1 );
  2378. if ( pParam && *pParam && pParam[ V_strlen( pParam ) - 1 ] == 's' )
  2379. {
  2380. float flSeconds = V_atof( pParam );
  2381. if ( flSeconds > 0 )
  2382. {
  2383. Msg( "Sleeping for %.3f seconds\n", flSeconds );
  2384. ThreadSleep( flSeconds * 1000 );
  2385. return;
  2386. }
  2387. }
  2388. }
  2389. int numCycles = ( args.ArgC() > 1 ) ? Q_atoi( args.Arg(1) ) : 10;
  2390. Msg( "forcing spincycle for %d cycles\n", numCycles );
  2391. for( int k = 0; k < numCycles; ++ k )
  2392. {
  2393. ( void ) RandomInt( 0, numCycles );
  2394. }
  2395. }
  2396. #if POSIX
  2397. CON_COMMAND_F( forktest, "Cause the engine to fork and wait for child PID, parameter can be passed for requested exit code (Debug!!)", FCVAR_CHEAT )
  2398. {
  2399. EndWatchdogTimer(); // End the watchdog in case child takes too long
  2400. int nExitCodeRequested = ( args.ArgC() > 1 ) ? Q_atoi( args.Arg(1) ) : 0;
  2401. pid_t pID = fork();
  2402. Msg( "forktest: Forked, pID = %d\n", (int) pID );
  2403. if ( pID == 0 ) // are we the forked child?
  2404. {
  2405. //
  2406. // Enumerate all open file descriptors that are not #0 (stdin), #1 (stdout), #2 (stderr)
  2407. // and close them all.
  2408. // This will close all sockets and file handles that can result in process hanging
  2409. // when network events occur on the machine and make NFS handles go bad.
  2410. //
  2411. if ( !CommandLine()->FindParm( "-forkfdskeepall" ) )
  2412. {
  2413. FileFindHandle_t hFind = NULL;
  2414. CUtlVector< int > arrHandlesToClose;
  2415. for ( char const *szFileName = g_pFullFileSystem->FindFirst( "/proc/self/fd/*", &hFind );
  2416. szFileName && *szFileName; szFileName = g_pFullFileSystem->FindNext( hFind ) )
  2417. {
  2418. int iFdHandle = Q_atoi( szFileName );
  2419. if ( ( iFdHandle > 2 ) && ( arrHandlesToClose.Find( iFdHandle ) == arrHandlesToClose.InvalidIndex() ) )
  2420. arrHandlesToClose.AddToTail( iFdHandle );
  2421. }
  2422. g_pFullFileSystem->FindClose( hFind );
  2423. FOR_EACH_VEC( arrHandlesToClose, idxFd )
  2424. {
  2425. ::close( arrHandlesToClose[idxFd] );
  2426. }
  2427. if ( !CommandLine()->FindParm( "-forkfdskeepstd" ) )
  2428. {
  2429. // Explicitly close #0 (stdin), #1 (stdout), #2 (stderr) and reopen them to /dev/null to consume 0-1-2 FDs (Posix spec requires to return lowest FDs first)
  2430. ::close( 0 );
  2431. ::close( 1 );
  2432. ::close( 2 );
  2433. ::open("/dev/null", O_RDONLY);
  2434. ::open("/dev/null", O_RDWR);
  2435. ::open("/dev/null", O_RDWR);
  2436. }
  2437. }
  2438. Msg( "Child finished successfully!\n" );
  2439. syscall( SYS_exit, nExitCodeRequested ); // don't do a normal c++ exit, don't want to call destructors, etc.
  2440. Warning( "Forked child just called SYS_exit.\n" );
  2441. }
  2442. else
  2443. {
  2444. int nRet = -1;
  2445. int nWait = waitpid( pID, &nRet, 0 );
  2446. Msg( "Parent finished wait: %d, ret: %d, exit: %d, code: %d\n", nWait, nRet, WIFEXITED( nRet ), WEXITSTATUS( nRet ) );
  2447. }
  2448. }
  2449. #endif
  2450. CON_COMMAND_F( flush, "Flush unlocked cache memory.", FCVAR_CHEAT )
  2451. {
  2452. #if !defined( DEDICATED )
  2453. g_ClientDLL->InvalidateMdlCache();
  2454. #endif // DEDICATED
  2455. serverGameDLL->InvalidateMdlCache();
  2456. g_pDataCache->Flush( true );
  2457. #if !defined( DEDICATED )
  2458. wavedatacache->Flush();
  2459. #endif
  2460. }
  2461. CON_COMMAND_F( flush_locked, "Flush unlocked and locked cache memory.", FCVAR_CHEAT )
  2462. {
  2463. #if !defined( DEDICATED )
  2464. g_ClientDLL->InvalidateMdlCache();
  2465. #endif // DEDICATED
  2466. serverGameDLL->InvalidateMdlCache();
  2467. g_pDataCache->Flush( false );
  2468. #if !defined( DEDICATED )
  2469. wavedatacache->Flush();
  2470. #endif
  2471. }
  2472. CON_COMMAND( cache_print, "cache_print [section]\nPrint out contents of cache memory." )
  2473. {
  2474. const char *pszSection = NULL;
  2475. if ( args.ArgC() == 2 )
  2476. {
  2477. pszSection = args[ 1 ];
  2478. }
  2479. g_pDataCache->OutputReport( DC_DETAIL_REPORT, pszSection );
  2480. }
  2481. CON_COMMAND( cache_print_lru, "cache_print_lru [section]\nPrint out contents of cache memory." )
  2482. {
  2483. const char *pszSection = NULL;
  2484. if ( args.ArgC() == 2 )
  2485. {
  2486. pszSection = args[ 1 ];
  2487. }
  2488. g_pDataCache->OutputReport( DC_DETAIL_REPORT_LRU, pszSection );
  2489. }
  2490. CON_COMMAND( cache_print_summary, "cache_print_summary [section]\nPrint out a summary contents of cache memory." )
  2491. {
  2492. const char *pszSection = NULL;
  2493. if ( args.ArgC() == 2 )
  2494. {
  2495. pszSection = args[ 1 ];
  2496. }
  2497. g_pDataCache->OutputReport( DC_SUMMARY_REPORT, pszSection );
  2498. }
  2499. #if defined( _X360 )
  2500. CON_COMMAND( vx_datacache_list, "vx_datacache_list" )
  2501. {
  2502. g_pDataCache->OutputReport( DC_DETAIL_REPORT_VXCONSOLE, NULL );
  2503. }
  2504. #endif
  2505. #ifndef _DEMO
  2506. #ifndef DEDICATED
  2507. // NOTE: As of shipping the 360 version of L4D, this command will not work correctly. See changelist 612757 (terror src) for why.
  2508. CON_COMMAND_F( ss_connect, "If connected with available split screen slots, connects a split screen player to this machine.", FCVAR_DEVELOPMENTONLY )
  2509. {
  2510. if ( host_state.max_splitscreen_players == 1 )
  2511. {
  2512. if ( toolframework->InToolMode() )
  2513. {
  2514. Msg( "Can't ss_connect, split screen not supported when running -tools mode.\n" );
  2515. }
  2516. else
  2517. {
  2518. Msg( "Can't ss_connect, game does not support split screen.\n" );
  2519. }
  2520. return;
  2521. }
  2522. if ( !GetBaseLocalClient().IsConnected() )
  2523. {
  2524. Msg( "Can't ss_connect, not connected to game.\n" );
  2525. return;
  2526. }
  2527. int nSlot = 1;
  2528. #ifndef DEDICATED
  2529. while ( splitscreen->IsValidSplitScreenSlot( nSlot ) )
  2530. {
  2531. ++nSlot;
  2532. }
  2533. #endif
  2534. if ( nSlot >= host_state.max_splitscreen_players )
  2535. {
  2536. Msg( "Can't ss_connect, no more split screen player slots!\n" );
  2537. return;
  2538. }
  2539. // Grab convars for next available slot
  2540. CCLCMsg_SplitPlayerConnect_t msg;
  2541. Host_BuildUserInfoUpdateMessage( nSlot, msg.mutable_convars(), false );
  2542. GetBaseLocalClient().m_NetChannel->SendNetMsg( msg );
  2543. }
  2544. CON_COMMAND_F( ss_disconnect, "If connected with available split screen slots, connects a split screen player to this machine.", FCVAR_DEVELOPMENTONLY )
  2545. {
  2546. if ( args.Source() == kCommandSrcNetClient )
  2547. {
  2548. #ifndef DEDICATED
  2549. host_client->SplitScreenDisconnect( args );
  2550. #endif
  2551. return;
  2552. }
  2553. // Get the first valid slot
  2554. int nSlot = -1;
  2555. for ( int i = 1; i < host_state.max_splitscreen_players; ++i )
  2556. {
  2557. if ( IS_VALID_SPLIT_SCREEN_SLOT( i ) )
  2558. {
  2559. nSlot = i;
  2560. break;
  2561. }
  2562. }
  2563. if ( args.ArgC() > 1 )
  2564. {
  2565. int cmdslot = Q_atoi( args.Arg( 1 ) );
  2566. if ( IS_VALID_SPLIT_SCREEN_SLOT( cmdslot ) )
  2567. {
  2568. nSlot = cmdslot;
  2569. }
  2570. else
  2571. {
  2572. Msg( "Can't ss_disconnect, slot %d not active\n", cmdslot );
  2573. return;
  2574. }
  2575. }
  2576. if ( ! IS_VALID_SPLIT_SCREEN_SLOT( nSlot ) )
  2577. {
  2578. Msg( "Can't ss_disconnect, no split screen users active\n" );
  2579. return;
  2580. }
  2581. char buf[ 256 ];
  2582. Q_snprintf( buf, sizeof( buf ), "ss_disconnect %d\n", nSlot );
  2583. CCommand argsClient;
  2584. argsClient.Tokenize( buf, kCommandSrcCode );
  2585. Cmd_ForwardToServer( argsClient );
  2586. #ifndef DEDICATED
  2587. splitscreen->SetDisconnecting( nSlot, true );
  2588. #endif
  2589. }
  2590. #endif
  2591. #endif
  2592. #if 0
  2593. CON_COMMAND_F( infinite_loop, "Hang server with an infinite loop to test crash recovery.", FCVAR_CHEAT )
  2594. {
  2595. for(;;)
  2596. {
  2597. ThreadSleep( 500 );
  2598. }
  2599. }
  2600. CON_COMMAND_F( null_ptr_references, "Produce a null ptr reference.", FCVAR_CHEAT )
  2601. {
  2602. *((int *) 0 ) = 77;
  2603. }
  2604. #endif