Team Fortress 2 Source Code as on 22/4/2020
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.

2411 lines
59 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "tier0/vprof.h"
  7. #include "server.h"
  8. #include "host_cmd.h"
  9. #include "keys.h"
  10. #include "screen.h"
  11. #include "vengineserver_impl.h"
  12. #include "host_saverestore.h"
  13. #include "sv_filter.h"
  14. #include "gl_matsysiface.h"
  15. #include "pr_edict.h"
  16. #include "world.h"
  17. #include "checksum_engine.h"
  18. #include "const.h"
  19. #include "sv_main.h"
  20. #include "host.h"
  21. #include "demo.h"
  22. #include "cdll_int.h"
  23. #include "networkstringtableserver.h"
  24. #include "networkstringtableclient.h"
  25. #include "host_state.h"
  26. #include "string_t.h"
  27. #include "tier0/dbg.h"
  28. #include "testscriptmgr.h"
  29. #include "r_local.h"
  30. #include "PlayerState.h"
  31. #include "enginesingleuserfilter.h"
  32. #include "profile.h"
  33. #include "proto_version.h"
  34. #include "protocol.h"
  35. #include "cl_main.h"
  36. #include "sv_steamauth.h"
  37. #include "zone.h"
  38. #include "datacache/idatacache.h"
  39. #include "sys_dll.h"
  40. #include "cmd.h"
  41. #include "tier0/icommandline.h"
  42. #include "filesystem.h"
  43. #include "filesystem_engine.h"
  44. #include "icliententitylist.h"
  45. #include "icliententity.h"
  46. #include "GameEventManager.h"
  47. #include "hltvserver.h"
  48. #if defined( REPLAY_ENABLED )
  49. #include "replay_internal.h"
  50. #include "replayserver.h"
  51. #endif
  52. #include "cdll_engine_int.h"
  53. #include "cl_steamauth.h"
  54. #ifndef SWDS
  55. #include "vgui_baseui_interface.h"
  56. #endif
  57. #include "sound.h"
  58. #include "voice.h"
  59. #include "sv_rcon.h"
  60. #if defined( _X360 )
  61. #include "xbox/xbox_console.h"
  62. #include "xbox/xbox_launch.h"
  63. #endif
  64. #include "filesystem/IQueuedLoader.h"
  65. #include "sys.h"
  66. #include "ixboxsystem.h"
  67. extern IXboxSystem *g_pXboxSystem;
  68. #include <sys/stat.h>
  69. #include <stdio.h>
  70. #ifdef POSIX
  71. // sigh, microsoft put _ in front of its type defines for stat
  72. #define _stat stat
  73. #endif
  74. // memdbgon must be the last include file in a .cpp file!!!
  75. #include "tier0/memdbgon.h"
  76. #define STEAM_PREFIX "STEAM_"
  77. #define STATUS_COLUMN_LENGTH_LINEPREFIX 1
  78. #define STATUS_COLUMN_LENGTH_USERID 6
  79. #define STATUS_COLUMN_LENGTH_USERID_STR "6"
  80. #define STATUS_COLUMN_LENGTH_NAME 19
  81. #define STATUS_COLUMN_LENGTH_STEAMID 19
  82. #define STATUS_COLUMN_LENGTH_TIME 9
  83. #define STATUS_COLUMN_LENGTH_PING 4
  84. #define STATUS_COLUMN_LENGTH_PING_STR "4"
  85. #define STATUS_COLUMN_LENGTH_LOSS 4
  86. #define STATUS_COLUMN_LENGTH_LOSS_STR "4"
  87. #define STATUS_COLUMN_LENGTH_STATE 6
  88. #define STATUS_COLUMN_LENGTH_ADDR 21
  89. #define KICKED_BY_CONSOLE "Kicked from server"
  90. #ifndef SWDS
  91. bool g_bInEditMode = false;
  92. bool g_bInCommentaryMode = false;
  93. #endif
  94. static void host_name_changed_f( IConVar *var, const char *pOldValue, float flOldValue )
  95. {
  96. Steam3Server().NotifyOfServerNameChange();
  97. }
  98. ConVar host_name( "hostname", "", 0, "Hostname for server.", host_name_changed_f );
  99. ConVar host_map( "host_map", "", 0, "Current map name." );
  100. void Host_VoiceRecordStop_f(void);
  101. static void voiceconvar_file_changed_f( IConVar *pConVar, const char *pOldValue, float flOldValue )
  102. {
  103. #ifndef SWDS
  104. ConVarRef var( pConVar );
  105. if ( var.GetInt() == 0 )
  106. {
  107. // Force voice recording to stop if they turn off voice_inputfromfile or if sv_allow_voice_from_file is set to 0.
  108. // Prevents an exploit where clients turn it on, start voice sending a long file, and then turn it off immediately.
  109. Host_VoiceRecordStop_f();
  110. }
  111. #endif
  112. }
  113. ConVar voice_recordtofile("voice_recordtofile", "0", 0, "Record mic data and decompressed voice data into 'voice_micdata.wav' and 'voice_decompressed.wav'");
  114. ConVar voice_inputfromfile("voice_inputfromfile", "0", 0, "Get voice input from 'voice_input.wav' rather than from the microphone.", &voiceconvar_file_changed_f );
  115. ConVar sv_allow_voice_from_file( "sv_allow_voice_from_file", "1", FCVAR_REPLICATED, "Allow or disallow clients from using voice_inputfromfile on this server.", &voiceconvar_file_changed_f );
  116. class CStatusLineBuilder
  117. {
  118. public:
  119. CStatusLineBuilder() { Reset(); }
  120. void Reset() { m_curPosition = 0; m_szLine[0] = '\0'; }
  121. void AddColumnText( const char *pszText, unsigned int columnWidth )
  122. {
  123. size_t len = strlen( m_szLine );
  124. if ( m_curPosition > len )
  125. {
  126. for ( size_t i = len; i < m_curPosition; i++ )
  127. {
  128. m_szLine[i] = ' ';
  129. }
  130. m_szLine[m_curPosition] = '\0';
  131. }
  132. else if ( len != 0 )
  133. {
  134. // There is always at least one space between columns.
  135. m_szLine[len] = ' ';
  136. m_szLine[len+1] = '\0';
  137. }
  138. V_strncat( m_szLine, pszText, sizeof( m_szLine ) );
  139. m_curPosition += columnWidth + 1;
  140. }
  141. void InsertEmptyColumn( unsigned int columnWidth )
  142. {
  143. m_curPosition += columnWidth + 1;
  144. }
  145. const char *GetLine() { return m_szLine; }
  146. private:
  147. size_t m_curPosition;
  148. char m_szLine[512];
  149. };
  150. uint GetSteamAppID()
  151. {
  152. static uint sunAppID = 0;
  153. static bool bHaveValidSteamInterface = false;
  154. if ( !bHaveValidSteamInterface )
  155. {
  156. #ifndef SWDS
  157. if ( Steam3Client().SteamUtils() )
  158. {
  159. bHaveValidSteamInterface = true;
  160. sunAppID = Steam3Client().SteamUtils()->GetAppID();
  161. }
  162. #endif
  163. if ( Steam3Server().SteamGameServerUtils() )
  164. {
  165. bHaveValidSteamInterface = true;
  166. sunAppID = Steam3Server().SteamGameServerUtils()->GetAppID();
  167. }
  168. if ( !sunAppID )
  169. sunAppID = 215; // defaults to Source SDK Base (215) if no steam.inf can be found.
  170. }
  171. return sunAppID;
  172. }
  173. EUniverse GetSteamUniverse()
  174. {
  175. #ifndef SWDS
  176. if ( Steam3Client().SteamUtils() )
  177. return Steam3Client().SteamUtils()->GetConnectedUniverse();
  178. #endif
  179. if ( Steam3Server().SteamGameServerUtils() )
  180. return Steam3Server().SteamGameServerUtils()->GetConnectedUniverse();
  181. return k_EUniverseInvalid;
  182. }
  183. // Globals
  184. int gHostSpawnCount = 0;
  185. // If any quit handlers balk, then aborts quit sequence
  186. bool EngineTool_CheckQuitHandlers();
  187. #if defined( _X360 )
  188. CON_COMMAND( quit_x360, "" )
  189. {
  190. int launchFlags = LF_EXITFROMGAME;
  191. // allocate the full payload
  192. int nPayloadSize = XboxLaunch()->MaxPayloadSize();
  193. byte *pPayload = (byte *)stackalloc( nPayloadSize );
  194. V_memset( pPayload, 0, sizeof( nPayloadSize ) );
  195. // payload is at least the command line
  196. // any user data needed must be placed AFTER the command line
  197. const char *pCmdLine = CommandLine()->GetCmdLine();
  198. int nCmdLineLength = (int)strlen( pCmdLine ) + 1;
  199. V_memcpy( pPayload, pCmdLine, min( nPayloadSize, nCmdLineLength ) );
  200. // add any other data here to payload, after the command line
  201. // ...
  202. // storage device may have changed since previous launch
  203. XboxLaunch()->SetStorageID( XBX_GetStorageDeviceId() );
  204. // Close the storage devices
  205. g_pXboxSystem->CloseContainers();
  206. // persist the user id
  207. bool bInviteRestart = args.FindArg( "invite" );
  208. DWORD nUserID = ( bInviteRestart ) ? XBX_GetInvitedUserId() : XBX_GetPrimaryUserId();
  209. XboxLaunch()->SetUserID( nUserID );
  210. if ( args.FindArg( "restart" ) )
  211. {
  212. launchFlags |= LF_GAMERESTART;
  213. }
  214. // If we're relaunching due to invite
  215. if ( bInviteRestart )
  216. {
  217. launchFlags |= LF_INVITERESTART;
  218. XNKID nSessionID = XBX_GetInviteSessionId();
  219. XboxLaunch()->SetInviteSessionID( &nSessionID );
  220. }
  221. bool bLaunch = XboxLaunch()->SetLaunchData( pPayload, nPayloadSize, launchFlags );
  222. if ( bLaunch )
  223. {
  224. COM_TimestampedLog( "Launching: \"%s\" Flags: 0x%8.8x", pCmdLine, XboxLaunch()->GetLaunchFlags() );
  225. g_pMaterialSystem->PersistDisplay();
  226. XBX_DisconnectConsoleMonitor();
  227. XboxLaunch()->Launch();
  228. }
  229. }
  230. #endif
  231. /*
  232. ==================
  233. Host_Quit_f
  234. ==================
  235. */
  236. void Host_Quit_f( const CCommand &args )
  237. {
  238. #if !defined(SWDS)
  239. if ( args.FindArg( "prompt" ) )
  240. {
  241. // confirm they want to quit
  242. EngineVGui()->ConfirmQuit();
  243. return;
  244. }
  245. if ( !EngineTool_CheckQuitHandlers() )
  246. {
  247. return;
  248. }
  249. #endif
  250. IGameEvent *event = g_GameEventManager.CreateEvent( "host_quit" );
  251. if ( event )
  252. {
  253. g_GameEventManager.FireEventClientSide( event );
  254. }
  255. HostState_Shutdown();
  256. }
  257. //-----------------------------------------------------------------------------
  258. // Purpose:
  259. //-----------------------------------------------------------------------------
  260. CON_COMMAND( _restart, "Shutdown and restart the engine." )
  261. {
  262. /*
  263. // FIXME: How to handle restarts?
  264. #ifndef SWDS
  265. if ( !EngineTool_CheckQuitHandlers() )
  266. {
  267. return;
  268. }
  269. #endif
  270. */
  271. HostState_Restart();
  272. }
  273. #ifndef SWDS
  274. //-----------------------------------------------------------------------------
  275. // A console command to spew out driver information
  276. //-----------------------------------------------------------------------------
  277. void Host_LightCrosshair (void);
  278. static ConCommand light_crosshair( "light_crosshair", Host_LightCrosshair, "Show texture color at crosshair", FCVAR_CHEAT );
  279. void Host_LightCrosshair (void)
  280. {
  281. Vector endPoint;
  282. Vector lightmapColor;
  283. // max_range * sqrt(3)
  284. VectorMA( MainViewOrigin(), COORD_EXTENT * 1.74f, MainViewForward(), endPoint );
  285. R_LightVec( MainViewOrigin(), endPoint, true, lightmapColor );
  286. int r = LinearToTexture( lightmapColor.x );
  287. int g = LinearToTexture( lightmapColor.y );
  288. int b = LinearToTexture( lightmapColor.z );
  289. ConMsg( "Luxel Value: %d %d %d\n", r, g, b );
  290. }
  291. #endif
  292. /*
  293. ==================
  294. Host_Status_PrintClient
  295. Print client info to console
  296. ==================
  297. */
  298. void Host_Status_PrintClient( IClient *client, bool bShowAddress, void (*print) (const char *fmt, ...) )
  299. {
  300. INetChannelInfo *nci = client->GetNetChannel();
  301. const char *state = "challenging";
  302. if ( client->IsActive() )
  303. state = "active";
  304. else if ( client->IsSpawned() )
  305. state = "spawning";
  306. else if ( client->IsConnected() )
  307. state = "connecting";
  308. CStatusLineBuilder builder;
  309. builder.AddColumnText( "#", STATUS_COLUMN_LENGTH_LINEPREFIX );
  310. builder.AddColumnText( va( "%" STATUS_COLUMN_LENGTH_USERID_STR "i", client->GetUserID() ), STATUS_COLUMN_LENGTH_USERID );
  311. builder.AddColumnText( va( "\"%s\"", client->GetClientName() ), STATUS_COLUMN_LENGTH_NAME );
  312. builder.AddColumnText( client->GetNetworkIDString(), STATUS_COLUMN_LENGTH_STEAMID );
  313. if ( nci != NULL )
  314. {
  315. builder.AddColumnText( COM_FormatSeconds( nci->GetTimeConnected() ), STATUS_COLUMN_LENGTH_TIME );
  316. builder.AddColumnText( va( "%" STATUS_COLUMN_LENGTH_PING_STR "i", (int)(1000.0f*nci->GetAvgLatency( FLOW_OUTGOING )) ), STATUS_COLUMN_LENGTH_PING );
  317. builder.AddColumnText( va( "%" STATUS_COLUMN_LENGTH_LOSS_STR "i", (int)(100.0f*nci->GetAvgLoss(FLOW_INCOMING)) ), STATUS_COLUMN_LENGTH_LOSS );
  318. builder.AddColumnText( state, STATUS_COLUMN_LENGTH_STATE );
  319. if ( bShowAddress )
  320. builder.AddColumnText( nci->GetAddress(), STATUS_COLUMN_LENGTH_ADDR );
  321. }
  322. else
  323. {
  324. builder.InsertEmptyColumn( STATUS_COLUMN_LENGTH_TIME );
  325. builder.InsertEmptyColumn( STATUS_COLUMN_LENGTH_PING );
  326. builder.InsertEmptyColumn( STATUS_COLUMN_LENGTH_LOSS );
  327. builder.AddColumnText( state, STATUS_COLUMN_LENGTH_STATE );
  328. }
  329. print( "%s\n", builder.GetLine() );
  330. }
  331. void Host_Client_Printf(const char *fmt, ...)
  332. {
  333. va_list argptr;
  334. char string[1024];
  335. va_start (argptr,fmt);
  336. Q_vsnprintf (string, sizeof( string ), fmt,argptr);
  337. va_end (argptr);
  338. host_client->ClientPrintf( "%s", string );
  339. }
  340. #define LIMIT_PER_CLIENT_COMMAND_EXECUTION_ONCE_PER_INTERVAL(seconds) \
  341. { \
  342. static float g_flLastTime__Limit[ABSOLUTE_PLAYER_LIMIT] = { 0.0f }; /* we don't have access to any of the three MAX_PLAYERS #define's here unfortunately */ \
  343. int playerindex = cmd_clientslot; \
  344. if ( playerindex >= 0 && playerindex < (ARRAYSIZE(g_flLastTime__Limit)) && realtime - g_flLastTime__Limit[playerindex] > (seconds) ) \
  345. { \
  346. g_flLastTime__Limit[playerindex] = realtime; \
  347. } \
  348. else \
  349. { \
  350. return; \
  351. } \
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Host_Status_f
  355. //-----------------------------------------------------------------------------
  356. CON_COMMAND( status, "Display map and connection status." )
  357. {
  358. IClient *client;
  359. int j;
  360. void (*print) (const char *fmt, ...);
  361. #if defined( _X360 )
  362. Vector org;
  363. QAngle ang;
  364. const char *pName;
  365. if ( cl.IsActive() )
  366. {
  367. pName = cl.m_szLevelNameShort;
  368. org = MainViewOrigin();
  369. VectorAngles( MainViewForward(), ang );
  370. IClientEntity *localPlayer = entitylist->GetClientEntity( cl.m_nPlayerSlot + 1 );
  371. if ( localPlayer )
  372. {
  373. org = localPlayer->GetAbsOrigin();
  374. }
  375. }
  376. else
  377. {
  378. pName = "";
  379. org.Init();
  380. ang.Init();
  381. }
  382. // send to vxconsole
  383. xMapInfo_t mapInfo;
  384. mapInfo.position[0] = org[0];
  385. mapInfo.position[1] = org[1];
  386. mapInfo.position[2] = org[2];
  387. mapInfo.angle[0] = ang[0];
  388. mapInfo.angle[1] = ang[1];
  389. mapInfo.angle[2] = ang[2];
  390. mapInfo.build = build_number();
  391. mapInfo.skill = skill.GetInt();
  392. // generate the qualified path where .sav files are expected to be written
  393. char savePath[MAX_PATH];
  394. V_snprintf( savePath, sizeof( savePath ), "%s", saverestore->GetSaveDir() );
  395. V_StripTrailingSlash( savePath );
  396. g_pFileSystem->RelativePathToFullPath( savePath, "MOD", mapInfo.savePath, sizeof( mapInfo.savePath ) );
  397. V_FixSlashes( mapInfo.savePath );
  398. if ( pName[0] )
  399. {
  400. // generate the qualified path from where the map was loaded
  401. char mapPath[MAX_PATH];
  402. Q_snprintf( mapPath, sizeof( mapPath ), "maps/%s.360.bsp", pName );
  403. g_pFileSystem->GetLocalPath( mapPath, mapInfo.mapPath, sizeof( mapInfo.mapPath ) );
  404. Q_FixSlashes( mapInfo.mapPath );
  405. }
  406. else
  407. {
  408. mapInfo.mapPath[0] = '\0';
  409. }
  410. XBX_rMapInfo( &mapInfo );
  411. #endif
  412. if ( cmd_source == src_command )
  413. {
  414. if ( !sv.IsActive() )
  415. {
  416. Cmd_ForwardToServer( args );
  417. return;
  418. }
  419. print = ConMsg;
  420. }
  421. else
  422. {
  423. print = Host_Client_Printf;
  424. // limit this to once per 5 seconds
  425. LIMIT_PER_CLIENT_COMMAND_EXECUTION_ONCE_PER_INTERVAL(5.0);
  426. }
  427. // ============================================================
  428. // Server status information.
  429. print( "hostname: %s\n", host_name.GetString() );
  430. const char *pchSecureReasonString = "";
  431. const char *pchUniverse = "";
  432. bool bGSSecure = Steam3Server().BSecure();
  433. if ( !bGSSecure && Steam3Server().BWantsSecure() )
  434. {
  435. if ( Steam3Server().BLoggedOn() )
  436. {
  437. pchSecureReasonString = " (secure mode enabled, connected to Steam3)";
  438. }
  439. else
  440. {
  441. pchSecureReasonString = " (secure mode enabled, disconnected from Steam3)";
  442. }
  443. }
  444. switch ( GetSteamUniverse() )
  445. {
  446. case k_EUniversePublic:
  447. pchUniverse = "";
  448. break;
  449. case k_EUniverseBeta:
  450. pchUniverse = " (beta)";
  451. break;
  452. case k_EUniverseInternal:
  453. pchUniverse = " (internal)";
  454. break;
  455. case k_EUniverseDev:
  456. pchUniverse = " (dev)";
  457. break;
  458. default:
  459. pchUniverse = " (unknown)";
  460. break;
  461. }
  462. print( "version : %s/%d %d %s%s%s\n", GetSteamInfIDVersionInfo().szVersionString,
  463. PROTOCOL_VERSION, build_number(), bGSSecure ? "secure" : "insecure", pchSecureReasonString, pchUniverse );
  464. if ( NET_IsMultiplayer() )
  465. {
  466. CUtlString sPublicIPInfo;
  467. if ( !Steam3Server().BLanOnly() )
  468. {
  469. uint32 unPublicIP = Steam3Server().GetPublicIP();
  470. if ( unPublicIP != 0 )
  471. {
  472. netadr_t addr;
  473. addr.SetIP( unPublicIP );
  474. sPublicIPInfo.Format(" (public ip: %s)", addr.ToString( true ) );
  475. }
  476. }
  477. print( "udp/ip : %s:%i%s\n", net_local_adr.ToString(true), sv.GetUDPPort(), sPublicIPInfo.String() );
  478. if ( !Steam3Server().BLanOnly() )
  479. {
  480. if ( Steam3Server().BLoggedOn() )
  481. print( "steamid : %s (%llu)\n", Steam3Server().SteamGameServer()->GetSteamID().Render(), Steam3Server().SteamGameServer()->GetSteamID().ConvertToUint64() );
  482. else
  483. print( "steamid : not logged in\n" );
  484. }
  485. }
  486. // Check if this game uses server registration, then output status
  487. ConVarRef sv_registration_successful( "sv_registration_successful", true );
  488. if ( sv_registration_successful.IsValid() )
  489. {
  490. CUtlString sExtraInfo;
  491. ConVarRef sv_registration_message( "sv_registration_message", true );
  492. if ( sv_registration_message.IsValid() )
  493. {
  494. const char *msg = sv_registration_message.GetString();
  495. if ( msg && *msg )
  496. {
  497. sExtraInfo.Format(" (%s)", msg );
  498. }
  499. }
  500. if ( sv_registration_successful.GetBool() )
  501. {
  502. print( "account : logged in%s\n", sExtraInfo.String() );
  503. }
  504. else
  505. {
  506. print( "account : not logged in%s\n", sExtraInfo.String() );
  507. }
  508. }
  509. print( "map : %s at: %d x, %d y, %d z\n", sv.GetMapName(), (int)MainViewOrigin()[0], (int)MainViewOrigin()[1], (int)MainViewOrigin()[2]);
  510. static ConVarRef sv_tags( "sv_tags" );
  511. print( "tags : %s\n", sv_tags.GetString() );
  512. if ( hltv && hltv->IsActive() )
  513. {
  514. print( "sourcetv: port %i, delay %.1fs\n", hltv->GetUDPPort(), hltv->GetDirector()->GetDelay() );
  515. }
  516. #if defined( REPLAY_ENABLED )
  517. if ( replay && replay->IsActive() )
  518. {
  519. print( "replay : %s\n", replay->IsRecording() ? "recording" : "not recording" );
  520. }
  521. #endif
  522. int players = sv.GetNumClients();
  523. int nBots = sv.GetNumFakeClients();
  524. int nHumans = players - nBots;
  525. print( "players : %i humans, %i bots (%i max)\n", nHumans, nBots, sv.GetMaxClients() );
  526. // ============================================================
  527. print( "edicts : %d used of %d max\n", sv.num_edicts - sv.free_edicts, sv.max_edicts );
  528. if ( ( g_iServerGameDLLVersion >= 10 ) && serverGameDLL )
  529. {
  530. serverGameDLL->Status( print );
  531. }
  532. // Early exit for this server.
  533. if ( args.ArgC() == 2 )
  534. {
  535. if ( !Q_stricmp( args[1], "short" ) )
  536. {
  537. for ( j=0 ; j < sv.GetClientCount() ; j++ )
  538. {
  539. client = sv.GetClient( j );
  540. if ( !client->IsActive() )
  541. continue;
  542. print( "#%i - %s\n" , j + 1, client->GetClientName() );
  543. }
  544. return;
  545. }
  546. }
  547. // the header for the status rows
  548. // print( "# userid %-19s %-19s connected ping loss state%s\n", "name", "uniqueid", cmd_source == src_command ? " adr" : "" );
  549. CStatusLineBuilder header;
  550. header.AddColumnText( "#", STATUS_COLUMN_LENGTH_LINEPREFIX );
  551. header.AddColumnText( "userid", STATUS_COLUMN_LENGTH_USERID );
  552. header.AddColumnText( "name", STATUS_COLUMN_LENGTH_NAME );
  553. header.AddColumnText( "uniqueid", STATUS_COLUMN_LENGTH_STEAMID );
  554. header.AddColumnText( "connected", STATUS_COLUMN_LENGTH_TIME );
  555. header.AddColumnText( "ping", STATUS_COLUMN_LENGTH_PING );
  556. header.AddColumnText( "loss", STATUS_COLUMN_LENGTH_LOSS );
  557. header.AddColumnText( "state", STATUS_COLUMN_LENGTH_STATE );
  558. if ( cmd_source == src_command )
  559. {
  560. header.AddColumnText( "adr", STATUS_COLUMN_LENGTH_ADDR );
  561. }
  562. print( "%s\n", header.GetLine() );
  563. for ( j=0 ; j < sv.GetClientCount() ; j++ )
  564. {
  565. client = sv.GetClient( j );
  566. if ( !client->IsConnected() )
  567. continue; // not connected yet, maybe challenging
  568. Host_Status_PrintClient( client, (cmd_source == src_command), print );
  569. }
  570. }
  571. //-----------------------------------------------------------------------------
  572. // Host_Ping_f
  573. //-----------------------------------------------------------------------------
  574. CON_COMMAND( ping, "Display ping to server." )
  575. {
  576. if ( cmd_source == src_command )
  577. {
  578. Cmd_ForwardToServer( args );
  579. return;
  580. }
  581. // limit this to once per 5 seconds
  582. LIMIT_PER_CLIENT_COMMAND_EXECUTION_ONCE_PER_INTERVAL(5.0);
  583. host_client->ClientPrintf( "Client ping times:\n" );
  584. for ( int i=0; i< sv.GetClientCount(); i++ )
  585. {
  586. IClient *client = sv.GetClient(i);
  587. if ( !client->IsConnected() || client->IsFakeClient() )
  588. continue;
  589. host_client->ClientPrintf ("%4.0f ms : %s\n",
  590. 1000.0f * client->GetNetChannel()->GetAvgLatency( FLOW_OUTGOING ), client->GetClientName() );
  591. }
  592. }
  593. bool CL_HL2Demo_MapCheck( const char *name )
  594. {
  595. if ( IsPC() && CL_IsHL2Demo() && !sv.IsDedicated() )
  596. {
  597. if ( !Q_stricmp( name, "d1_trainstation_01" ) ||
  598. !Q_stricmp( name, "d1_trainstation_02" ) ||
  599. !Q_stricmp( name, "d1_town_01" ) ||
  600. !Q_stricmp( name, "d1_town_01a" ) ||
  601. !Q_stricmp( name, "d1_town_02" ) ||
  602. !Q_stricmp( name, "d1_town_03" ) ||
  603. !Q_stricmp( name, "background01" ) ||
  604. !Q_stricmp( name, "background03" )
  605. )
  606. {
  607. return true;
  608. }
  609. return false;
  610. }
  611. return true;
  612. }
  613. bool CL_PortalDemo_MapCheck( const char *name )
  614. {
  615. if ( IsPC() && CL_IsPortalDemo() && !sv.IsDedicated() )
  616. {
  617. if ( !Q_stricmp( name, "testchmb_a_00" ) ||
  618. !Q_stricmp( name, "testchmb_a_01" ) ||
  619. !Q_stricmp( name, "testchmb_a_02" ) ||
  620. !Q_stricmp( name, "testchmb_a_03" ) ||
  621. !Q_stricmp( name, "testchmb_a_04" ) ||
  622. !Q_stricmp( name, "testchmb_a_05" ) ||
  623. !Q_stricmp( name, "testchmb_a_06" ) ||
  624. !Q_stricmp( name, "background1" )
  625. )
  626. {
  627. return true;
  628. }
  629. return false;
  630. }
  631. return true;
  632. }
  633. int _Host_Map_f_CompletionFunc( char const *cmdname, char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] );
  634. // Note, leaves name alone if no match possible
  635. static bool Host_Map_Helper_FuzzyName( const CCommand &args, char *name, size_t bufsize )
  636. {
  637. char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ];
  638. CUtlString argv0;
  639. argv0 = args.Arg( 0 );
  640. argv0 += " ";
  641. if ( _Host_Map_f_CompletionFunc( argv0, args.ArgS(), commands ) > 0 )
  642. {
  643. Q_strncpy( name, &commands[ 0 ][ argv0.Length() ], bufsize );
  644. return true;
  645. }
  646. return false;
  647. }
  648. void Host_Map_Helper( const CCommand &args, bool bEditmode, bool bBackground, bool bCommentary )
  649. {
  650. if ( cmd_source != src_command )
  651. return;
  652. if (args.ArgC() < 2)
  653. {
  654. Warning("No map specified\n");
  655. return;
  656. }
  657. const char *pszReason = NULL;
  658. if ( ( g_iServerGameDLLVersion >= 10 ) && !serverGameDLL->IsManualMapChangeOkay( &pszReason ) )
  659. {
  660. if ( pszReason && pszReason[0] )
  661. {
  662. Warning( "%s\n", pszReason );
  663. }
  664. return;
  665. }
  666. char szMapName[ MAX_QPATH ] = { 0 };
  667. V_strncpy( szMapName, args[ 1 ], sizeof( szMapName ) );
  668. // Call find map, proceed for any value besides NotFound
  669. IVEngineServer::eFindMapResult eResult = g_pVEngineServer->FindMap( szMapName, sizeof( szMapName ) );
  670. if ( eResult == IVEngineServer::eFindMap_NotFound )
  671. {
  672. Warning( "map load failed: %s not found or invalid\n", args[ 1 ] );
  673. return;
  674. }
  675. COM_TimestampedLog( "*** Map Load: %s", szMapName );
  676. // There is a precision issue here, as described Bruce Dawson's blog.
  677. // In our case, we don't care because we're looking for anything on the order of second precision, which
  678. // covers runtime up to around 4 months.
  679. static ConVarRef dev_loadtime_map_start( "dev_loadtime_map_start" );
  680. dev_loadtime_map_start.SetValue( (float)Plat_FloatTime() );
  681. // If I was in edit mode reload config file
  682. // to overwrite WC edit key bindings
  683. #if !defined(SWDS)
  684. if ( !bEditmode )
  685. {
  686. if ( g_bInEditMode )
  687. {
  688. // Re-read config from disk
  689. Host_ReadConfiguration();
  690. g_bInEditMode = false;
  691. }
  692. }
  693. else
  694. {
  695. g_bInEditMode = true;
  696. }
  697. g_bInCommentaryMode = bCommentary;
  698. #endif
  699. if ( !CL_HL2Demo_MapCheck( szMapName ) )
  700. {
  701. Warning( "map load failed: %s not found or invalid\n", szMapName );
  702. return;
  703. }
  704. if ( !CL_PortalDemo_MapCheck( szMapName ) )
  705. {
  706. Warning( "map load failed: %s not found or invalid\n", szMapName );
  707. return;
  708. }
  709. #if defined( REPLAY_ENABLED )
  710. // If we're recording the game, finalize the replay so players can download it.
  711. if ( g_pReplay && g_pReplay->IsRecording() )
  712. {
  713. g_pReplay->SV_EndRecordingSession();
  714. }
  715. #endif
  716. // Stop demo loop
  717. cl.demonum = -1;
  718. Host_Disconnect( false ); // stop old game
  719. HostState_NewGame( szMapName, false, bBackground );
  720. if (args.ArgC() == 10)
  721. {
  722. if (Q_stricmp(args[2], "setpos") == 0
  723. && Q_stricmp(args[6], "setang") == 0)
  724. {
  725. Vector newpos;
  726. newpos.x = atof( args[3] );
  727. newpos.y = atof( args[4] );
  728. newpos.z = atof( args[5] );
  729. QAngle newangle;
  730. newangle.x = atof( args[7] );
  731. newangle.y = atof( args[8] );
  732. newangle.z = atof( args[9] );
  733. HostState_SetSpawnPoint(newpos, newangle);
  734. }
  735. }
  736. }
  737. /*
  738. ======================
  739. Host_Map_f
  740. handle a
  741. map <servername>
  742. command from the console. Active clients are kicked off.
  743. ======================
  744. */
  745. void Host_Map_f( const CCommand &args )
  746. {
  747. Host_Map_Helper( args, false, false, false );
  748. }
  749. //-----------------------------------------------------------------------------
  750. // handle a map_edit <servername> command from the console.
  751. // Active clients are kicked off.
  752. // UNDONE: protect this from use if not in dev. mode
  753. //-----------------------------------------------------------------------------
  754. #ifndef SWDS
  755. CON_COMMAND( map_edit, "" )
  756. {
  757. Host_Map_Helper( args, true, false, false );
  758. }
  759. #endif
  760. //-----------------------------------------------------------------------------
  761. // Purpose: Runs a map as the background
  762. //-----------------------------------------------------------------------------
  763. void Host_Map_Background_f( const CCommand &args )
  764. {
  765. Host_Map_Helper( args, false, true, false );
  766. }
  767. //-----------------------------------------------------------------------------
  768. // Purpose: Runs a map in commentary mode
  769. //-----------------------------------------------------------------------------
  770. void Host_Map_Commentary_f( const CCommand &args )
  771. {
  772. Host_Map_Helper( args, false, false, true );
  773. }
  774. //-----------------------------------------------------------------------------
  775. // Restarts the current server for a dead player
  776. //-----------------------------------------------------------------------------
  777. CON_COMMAND( restart, "Restart the game on the same level (add setpos to jump to current view position on restart)." )
  778. {
  779. if (
  780. #if !defined(SWDS)
  781. demoplayer->IsPlayingBack() ||
  782. #endif
  783. !sv.IsActive() )
  784. return;
  785. if ( sv.IsMultiplayer() )
  786. return;
  787. if ( cmd_source != src_command )
  788. return;
  789. bool bRememberLocation = ( args.ArgC() == 2 && !Q_stricmp( args[1], "setpos" ) );
  790. Host_Disconnect(false); // stop old game
  791. if ( !CL_HL2Demo_MapCheck( sv.GetMapName() ) )
  792. {
  793. Warning( "map load failed: %s not found or invalid\n", sv.GetMapName() );
  794. return;
  795. }
  796. if ( !CL_PortalDemo_MapCheck( sv.GetMapName() ) )
  797. {
  798. Warning( "map load failed: %s not found or invalid\n", sv.GetMapName() );
  799. return;
  800. }
  801. HostState_NewGame( sv.GetMapName(), bRememberLocation, false );
  802. }
  803. //-----------------------------------------------------------------------------
  804. // Restarts the current server for a dead player
  805. //-----------------------------------------------------------------------------
  806. CON_COMMAND( reload, "Reload the most recent saved game (add setpos to jump to current view position on reload).")
  807. {
  808. #ifndef SWDS
  809. const char *pSaveName;
  810. char name[MAX_OSPATH];
  811. #endif
  812. if (
  813. #if !defined(SWDS)
  814. demoplayer->IsPlayingBack() ||
  815. #endif
  816. !sv.IsActive() )
  817. return;
  818. if ( sv.IsMultiplayer() )
  819. return;
  820. if (cmd_source != src_command)
  821. return;
  822. bool remember_location = false;
  823. if ( args.ArgC() == 2 &&
  824. !Q_stricmp( args[1], "setpos" ) )
  825. {
  826. remember_location = true;
  827. }
  828. // See if there is a most recently saved game
  829. // Restart that game if there is
  830. // Otherwise, restart the starting game map
  831. #ifndef SWDS
  832. pSaveName = saverestore->FindRecentSave( name, sizeof( name ) );
  833. // Put up loading plaque
  834. SCR_BeginLoadingPlaque();
  835. Host_Disconnect( false ); // stop old game
  836. if ( pSaveName && saverestore->SaveFileExists( pSaveName ) )
  837. {
  838. HostState_LoadGame( pSaveName, remember_location );
  839. }
  840. else
  841. #endif
  842. {
  843. if ( !CL_HL2Demo_MapCheck( host_map.GetString() ) )
  844. {
  845. Warning( "map load failed: %s not found or invalid\n", host_map.GetString() );
  846. return;
  847. }
  848. if ( !CL_PortalDemo_MapCheck( host_map.GetString() ) )
  849. {
  850. Warning( "map load failed: %s not found or invalid\n", host_map.GetString() );
  851. return;
  852. }
  853. HostState_NewGame( host_map.GetString(), remember_location, false );
  854. }
  855. }
  856. //-----------------------------------------------------------------------------
  857. // Purpose: Goes to a new map, taking all clients along
  858. // Output : void Host_Changelevel_f
  859. //-----------------------------------------------------------------------------
  860. void Host_Changelevel_f( const CCommand &args )
  861. {
  862. if ( args.ArgC() < 2 )
  863. {
  864. ConMsg( "changelevel <levelname> : continue game on a new level\n" );
  865. return;
  866. }
  867. if ( !sv.IsActive() )
  868. {
  869. ConMsg( "Can't changelevel, not running server\n" );
  870. return;
  871. }
  872. char szName[MAX_PATH] = { 0 };
  873. V_strncpy( szName, args[1], sizeof( szName ) );
  874. // Call find map to attempt to resolve fuzzy/non-canonical map names
  875. IVEngineServer::eFindMapResult eResult = g_pVEngineServer->FindMap( szName, sizeof( szName ) );
  876. if ( eResult == IVEngineServer::eFindMap_NotFound )
  877. {
  878. // Warn, but but proceed even if the map is not found, such that we hit the proper server_levelchange_failed
  879. // codepath and event later on.
  880. Warning( "Failed to find map %s\n", args[ 1 ] );
  881. }
  882. if ( !CL_HL2Demo_MapCheck(szName) )
  883. {
  884. Warning( "changelevel failed: %s not found\n", szName );
  885. return;
  886. }
  887. if ( !CL_PortalDemo_MapCheck(szName) )
  888. {
  889. Warning( "changelevel failed: %s not found\n", szName );
  890. return;
  891. }
  892. const char *pszReason = NULL;
  893. if ( ( g_iServerGameDLLVersion >= 10 ) && !serverGameDLL->IsManualMapChangeOkay( &pszReason ) )
  894. {
  895. if ( pszReason && pszReason[0] )
  896. {
  897. Warning( "%s", pszReason );
  898. }
  899. return;
  900. }
  901. HostState_ChangeLevelMP( szName, args[2] );
  902. }
  903. //-----------------------------------------------------------------------------
  904. // Purpose: Changing levels within a unit, uses save/restore
  905. //-----------------------------------------------------------------------------
  906. void Host_Changelevel2_f( const CCommand &args )
  907. {
  908. if ( args.ArgC() < 2 )
  909. {
  910. ConMsg ("changelevel2 <levelname> : continue game on a new level in the unit\n");
  911. return;
  912. }
  913. if ( !sv.IsActive() || sv.IsMultiplayer() )
  914. {
  915. ConMsg( "Can't changelevel2, not in a single-player map\n" );
  916. return;
  917. }
  918. char szName[MAX_PATH] = { 0 };
  919. V_strncpy( szName, args[1], sizeof( szName ) );
  920. IVEngineServer::eFindMapResult eResult = g_pVEngineServer->FindMap( szName, sizeof( szName ) );
  921. if ( eResult == IVEngineServer::eFindMap_NotFound )
  922. {
  923. if ( !CL_IsHL2Demo() || (CL_IsHL2Demo() && !(!Q_stricmp( szName, "d1_trainstation_03" ) || !Q_stricmp( szName, "d1_town_02a" ))) )
  924. {
  925. Warning( "changelevel2 failed: %s not found\n", szName );
  926. return;
  927. }
  928. }
  929. #if !defined(SWDS)
  930. // needs to be before CL_HL2Demo_MapCheck() check as d1_trainstation_03 isn't a valid map
  931. if ( IsPC() && CL_IsHL2Demo() && !sv.IsDedicated() && !Q_stricmp( szName, "d1_trainstation_03" ) )
  932. {
  933. void CL_DemoTransitionFromTrainstation();
  934. CL_DemoTransitionFromTrainstation();
  935. return;
  936. }
  937. // needs to be before CL_HL2Demo_MapCheck() check as d1_trainstation_03 isn't a valid map
  938. if ( IsPC() && CL_IsHL2Demo() && !sv.IsDedicated() && !Q_stricmp( szName, "d1_town_02a" ) && !Q_stricmp( args[2], "d1_town_02_02a" ))
  939. {
  940. void CL_DemoTransitionFromRavenholm();
  941. CL_DemoTransitionFromRavenholm();
  942. return;
  943. }
  944. if ( IsPC() && CL_IsPortalDemo() && !sv.IsDedicated() && !Q_stricmp( szName, "testchmb_a_07" ) )
  945. {
  946. void CL_DemoTransitionFromTestChmb();
  947. CL_DemoTransitionFromTestChmb();
  948. return;
  949. }
  950. #endif
  951. // allow a level transition to d1_trainstation_03 so the Host_Changelevel() can act on it
  952. if ( !CL_HL2Demo_MapCheck( szName ) )
  953. {
  954. Warning( "changelevel failed: %s not found\n", szName );
  955. return;
  956. }
  957. HostState_ChangeLevelSP( szName, args[2] );
  958. }
  959. //-----------------------------------------------------------------------------
  960. // Purpose: Shut down client connection and any server
  961. //-----------------------------------------------------------------------------
  962. void Host_Disconnect( bool bShowMainMenu, const char *pszReason )
  963. {
  964. if ( IsX360() )
  965. {
  966. g_pQueuedLoader->EndMapLoading( false );
  967. }
  968. #ifndef SWDS
  969. if ( !sv.IsDedicated() )
  970. {
  971. cl.Disconnect( pszReason, bShowMainMenu );
  972. }
  973. #endif
  974. Host_AllowQueuedMaterialSystem( false );
  975. HostState_GameShutdown();
  976. }
  977. void Disconnect()
  978. {
  979. cl.demonum = -1;
  980. Host_Disconnect(true);
  981. #if defined( REPLAY_ENABLED )
  982. // Finalize the recording replay on the server, if is recording.
  983. // NOTE: We don't want this in Host_Disconnect() as that would be called more
  984. // than necessary.
  985. if ( g_pReplay && g_pReplay->IsReplayEnabled() && sv.IsDedicated() )
  986. {
  987. g_pReplay->SV_EndRecordingSession();
  988. }
  989. #endif
  990. }
  991. //-----------------------------------------------------------------------------
  992. // Kill the client and any local server.
  993. //-----------------------------------------------------------------------------
  994. CON_COMMAND( disconnect, "Disconnect game from server." )
  995. {
  996. #if !defined( SWDS )
  997. // Just run the regular Disconnect function if we're not the client or the client didn't handle it for us
  998. if( !g_ClientDLL || !g_ClientDLL->DisconnectAttempt() )
  999. {
  1000. Disconnect();
  1001. }
  1002. #else
  1003. Disconnect();
  1004. #endif
  1005. }
  1006. #ifdef _WIN32
  1007. // manually pull in the GetEnvironmentVariableA defn so we don't need to include windows.h
  1008. extern "C"
  1009. {
  1010. DWORD __declspec(dllimport) __stdcall GetEnvironmentVariableA( const char *, char *, DWORD );
  1011. }
  1012. #endif // _WIN32
  1013. CON_COMMAND( version, "Print version info string." )
  1014. {
  1015. ConMsg( "Build Label: %8d # Uniquely identifies each build\n", GetSteamInfIDVersionInfo().ServerVersion );
  1016. ConMsg( "Network PatchVersion: %8s # Determines client and server compatibility\n", GetSteamInfIDVersionInfo().szVersionString );
  1017. ConMsg( "Protocol version: %8d # High level network protocol version\n", PROTOCOL_VERSION );
  1018. if ( sv.IsDedicated() || serverGameDLL )
  1019. {
  1020. ConMsg( "Server version: %8i\n", GetSteamInfIDVersionInfo().ServerVersion );
  1021. ConMsg( "Server AppID: %8i\n", GetSteamInfIDVersionInfo().ServerAppID );
  1022. }
  1023. if ( !sv.IsDedicated() )
  1024. {
  1025. ConMsg( "Client version: %8i\n", GetSteamInfIDVersionInfo().ClientVersion );
  1026. ConMsg( "Client AppID: %8i\n", GetSteamInfIDVersionInfo().AppID );
  1027. }
  1028. }
  1029. //-----------------------------------------------------------------------------
  1030. // Purpose:
  1031. //-----------------------------------------------------------------------------
  1032. CON_COMMAND( pause, "Toggle the server pause state." )
  1033. {
  1034. #ifndef SWDS
  1035. if ( !sv.IsDedicated() )
  1036. {
  1037. if ( !cl.m_szLevelFileName[ 0 ] )
  1038. return;
  1039. }
  1040. #endif
  1041. if ( cmd_source == src_command )
  1042. {
  1043. Cmd_ForwardToServer( args );
  1044. return;
  1045. }
  1046. if ( !sv.IsPausable() )
  1047. return;
  1048. // toggle paused state
  1049. sv.SetPaused( !sv.IsPaused() );
  1050. // send text messaage who paused the game
  1051. sv.BroadcastPrintf( "%s %s the game\n", host_client->GetClientName(), sv.IsPaused() ? "paused" : "unpaused" );
  1052. }
  1053. //-----------------------------------------------------------------------------
  1054. // Purpose:
  1055. //-----------------------------------------------------------------------------
  1056. CON_COMMAND( setpause, "Set the pause state of the server." )
  1057. {
  1058. #ifndef SWDS
  1059. if ( !cl.m_szLevelFileName[ 0 ] )
  1060. return;
  1061. #endif
  1062. if ( cmd_source == src_command )
  1063. {
  1064. Cmd_ForwardToServer( args );
  1065. return;
  1066. }
  1067. sv.SetPaused( true );
  1068. }
  1069. //-----------------------------------------------------------------------------
  1070. // Purpose:
  1071. //-----------------------------------------------------------------------------
  1072. CON_COMMAND( unpause, "Unpause the game." )
  1073. {
  1074. #ifndef SWDS
  1075. if ( !cl.m_szLevelFileName[ 0 ] )
  1076. return;
  1077. #endif
  1078. if ( cmd_source == src_command )
  1079. {
  1080. Cmd_ForwardToServer( args );
  1081. return;
  1082. }
  1083. sv.SetPaused( false );
  1084. }
  1085. // No non-testing use for this at the moment, though server mods in public will expose similar functionality
  1086. #if defined( STAGING_ONLY ) || defined( _DEBUG )
  1087. //-----------------------------------------------------------------------------
  1088. // Purpose: Send a string command to a client by userid
  1089. //-----------------------------------------------------------------------------
  1090. CON_COMMAND( clientcmd, "Send a clientside command to a player by userid" )
  1091. {
  1092. if ( args.ArgC() <= 2 )
  1093. {
  1094. ConMsg( "Usage: clientcmd < userid > { command string }\n" );
  1095. return;
  1096. }
  1097. // Args
  1098. int userid = Q_atoi( args[1] );
  1099. int messageArgStart = 2;
  1100. // Concatenate other arguments into string
  1101. CUtlString commandString;
  1102. commandString.SetLength( Q_strlen( args.ArgS() ) );
  1103. commandString.Set( args[ messageArgStart ] );
  1104. for ( int i = messageArgStart + 1; i < args.ArgC(); i++ )
  1105. {
  1106. commandString.Append( " " );
  1107. commandString.Append( args[i] );
  1108. }
  1109. // find client
  1110. IClient *client = NULL;
  1111. for ( int i = 0; i < sv.GetClientCount(); i++ )
  1112. {
  1113. IClient *searchclient = sv.GetClient( i );
  1114. if ( !searchclient->IsConnected() )
  1115. continue;
  1116. if ( userid != -1 && searchclient->GetUserID() == userid )
  1117. {
  1118. client = searchclient;
  1119. break;
  1120. }
  1121. }
  1122. if ( !client )
  1123. {
  1124. ConMsg( "userid \"%d\" not found\n", userid );
  1125. return;
  1126. }
  1127. NET_StringCmd cmdMsg( commandString ) ;
  1128. client->SendNetMsg( cmdMsg, true );
  1129. }
  1130. #endif // defined( STAGING_ONLY ) || defined( _DEBUG )
  1131. //-----------------------------------------------------------------------------
  1132. // Kicks a user off of the server using their userid or uniqueid
  1133. //-----------------------------------------------------------------------------
  1134. CON_COMMAND( kickid, "Kick a player by userid or uniqueid, with a message." )
  1135. {
  1136. char *who = NULL;
  1137. const char *pszArg1 = NULL, *pszMessage = NULL;
  1138. IClient *client = NULL;
  1139. int iSearchIndex = -1;
  1140. char szSearchString[128];
  1141. int argsStartNum = 1;
  1142. bool bSteamID = false;
  1143. int i = 0;
  1144. if ( args.ArgC() <= 1 )
  1145. {
  1146. ConMsg( "Usage: kickid < userid | uniqueid > { message }\n" );
  1147. return;
  1148. }
  1149. // get the first argument
  1150. pszArg1 = args[1];
  1151. // if the first letter is a character then
  1152. // we're searching for a uniqueid ( e.g. STEAM_ )
  1153. if ( *pszArg1 < '0' || *pszArg1 > '9' )
  1154. {
  1155. // SteamID (need to reassemble it)
  1156. if ( !Q_strnicmp( pszArg1, STEAM_PREFIX, strlen( STEAM_PREFIX ) ) && Q_strstr( args[2], ":" ) )
  1157. {
  1158. Q_snprintf( szSearchString, sizeof( szSearchString ), "%s:%s:%s", pszArg1, args[3], args[5] );
  1159. argsStartNum = 5;
  1160. bSteamID = true;
  1161. }
  1162. // some other ID (e.g. "UNKNOWN", "STEAM_ID_PENDING", "STEAM_ID_LAN")
  1163. // NOTE: assumed to be one argument
  1164. else
  1165. {
  1166. Q_snprintf( szSearchString, sizeof( szSearchString ), "%s", pszArg1 );
  1167. }
  1168. }
  1169. // this is a userid
  1170. else
  1171. {
  1172. iSearchIndex = Q_atoi( pszArg1 );
  1173. }
  1174. // check for a message
  1175. if ( args.ArgC() > argsStartNum )
  1176. {
  1177. int j;
  1178. int dataLen = 0;
  1179. pszMessage = args.ArgS();
  1180. for ( j = 1; j <= argsStartNum; j++ )
  1181. {
  1182. dataLen += Q_strlen( args[j] ) + 1; // +1 for the space between args
  1183. }
  1184. if ( bSteamID )
  1185. {
  1186. dataLen -= 5; // SteamIDs don't have spaces between the args[) values
  1187. }
  1188. if ( dataLen > Q_strlen( pszMessage ) ) // saftey check
  1189. {
  1190. pszMessage = NULL;
  1191. }
  1192. else
  1193. {
  1194. pszMessage += dataLen;
  1195. }
  1196. }
  1197. // find this client
  1198. for ( i = 0; i < sv.GetClientCount(); i++ )
  1199. {
  1200. client = sv.GetClient( i );
  1201. if ( !client->IsConnected() )
  1202. continue;
  1203. #if defined( REPLAY_ENABLED )
  1204. if ( client->IsReplay() )
  1205. continue;
  1206. #endif
  1207. if ( client->IsHLTV() )
  1208. continue;
  1209. // searching by UserID
  1210. if ( iSearchIndex != -1 )
  1211. {
  1212. if ( client->GetUserID() == iSearchIndex )
  1213. {
  1214. // found!
  1215. break;
  1216. }
  1217. }
  1218. // searching by UniqueID
  1219. else
  1220. {
  1221. if ( Q_stricmp( client->GetNetworkIDString(), szSearchString ) == 0 )
  1222. {
  1223. // found!
  1224. break;
  1225. }
  1226. }
  1227. }
  1228. // now kick them
  1229. if ( i < sv.GetClientCount() )
  1230. {
  1231. if ( cmd_source != src_command )
  1232. {
  1233. who = host_client->m_Name;
  1234. }
  1235. // can't kick yourself!
  1236. if ( cmd_source != src_command && host_client == client && !sv.IsDedicated() )
  1237. {
  1238. return;
  1239. }
  1240. if ( iSearchIndex != -1 || !client->IsFakeClient() )
  1241. {
  1242. if ( who == NULL )
  1243. {
  1244. if ( pszMessage )
  1245. {
  1246. client->Disconnect( "%s", pszMessage );
  1247. }
  1248. else
  1249. {
  1250. client->Disconnect( KICKED_BY_CONSOLE );
  1251. }
  1252. }
  1253. else
  1254. {
  1255. if ( pszMessage )
  1256. {
  1257. client->Disconnect( "Kicked by %s : %s", who, pszMessage );
  1258. }
  1259. else
  1260. {
  1261. client->Disconnect( "Kicked by %s", who );
  1262. }
  1263. }
  1264. }
  1265. }
  1266. else
  1267. {
  1268. if ( iSearchIndex != -1 )
  1269. {
  1270. ConMsg( "userid \"%d\" not found\n", iSearchIndex );
  1271. }
  1272. else
  1273. {
  1274. ConMsg( "uniqueid \"%s\" not found\n", szSearchString );
  1275. }
  1276. }
  1277. }
  1278. /*
  1279. ==================
  1280. Host_Kick_f
  1281. Kicks a user off of the server using their name
  1282. ==================
  1283. */
  1284. CON_COMMAND( kick, "Kick a player by name." )
  1285. {
  1286. char *who = NULL;
  1287. char *pszName = NULL;
  1288. IClient *client = NULL;
  1289. int i = 0;
  1290. char name[64];
  1291. if ( args.ArgC() <= 1 )
  1292. {
  1293. ConMsg( "Usage: kick < name >\n" );
  1294. return;
  1295. }
  1296. // copy the name to a local buffer
  1297. memset( name, 0, sizeof(name) );
  1298. Q_strncpy( name, args.ArgS(), sizeof(name) );
  1299. pszName = name;
  1300. // safety check
  1301. if ( pszName && pszName[0] != 0 )
  1302. {
  1303. //HACK-HACK
  1304. // check for the name surrounded by quotes (comes in this way from rcon)
  1305. int len = Q_strlen( pszName ) - 1; // (minus one since we start at 0)
  1306. if ( pszName[0] == '"' && pszName[len] == '"' )
  1307. {
  1308. // get rid of the quotes at the beginning and end
  1309. pszName[len] = 0;
  1310. pszName++;
  1311. }
  1312. for ( i = 0; i < sv.GetClientCount(); i++ )
  1313. {
  1314. client = sv.GetClient(i);
  1315. if ( !client->IsConnected() )
  1316. continue;
  1317. #if defined( REPLAY_ENABLED )
  1318. if ( client->IsReplay() )
  1319. continue;
  1320. #endif
  1321. if ( client->IsHLTV() )
  1322. continue;
  1323. // found!
  1324. if ( Q_strcasecmp( client->GetClientName(), pszName ) == 0 )
  1325. break;
  1326. }
  1327. // now kick them
  1328. if ( i < sv.GetClientCount() )
  1329. {
  1330. if ( cmd_source != src_command )
  1331. {
  1332. who = host_client->m_Name;
  1333. }
  1334. // can't kick yourself!
  1335. if ( cmd_source != src_command && host_client == client && !sv.IsDedicated() )
  1336. return;
  1337. if ( who )
  1338. {
  1339. client->Disconnect( "Kicked by %s", who );
  1340. }
  1341. else
  1342. {
  1343. client->Disconnect( KICKED_BY_CONSOLE );
  1344. }
  1345. }
  1346. else
  1347. {
  1348. ConMsg( "name \"%s\" not found\n", pszName );
  1349. }
  1350. }
  1351. }
  1352. //-----------------------------------------------------------------------------
  1353. // Kicks all users off of the server
  1354. //-----------------------------------------------------------------------------
  1355. CON_COMMAND( kickall, "Kicks everybody connected with a message." )
  1356. {
  1357. char *who = NULL;
  1358. IClient *client = NULL;
  1359. int i = 0;
  1360. char szMessage[128];
  1361. // copy the message to a local buffer
  1362. memset( szMessage, 0, sizeof(szMessage) );
  1363. V_strcpy_safe( szMessage, args.ArgS() );
  1364. if ( cmd_source != src_command )
  1365. {
  1366. who = host_client->m_Name;
  1367. }
  1368. for ( i = 0; i < sv.GetClientCount(); i++ )
  1369. {
  1370. client = sv.GetClient(i);
  1371. if ( !client->IsConnected() )
  1372. continue;
  1373. // can't kick yourself!
  1374. if ( cmd_source != src_command && host_client == client && !sv.IsDedicated() )
  1375. continue;
  1376. #if defined( REPLAY_ENABLED )
  1377. if ( client->IsReplay() )
  1378. continue;
  1379. #endif
  1380. if ( client->IsHLTV() )
  1381. continue;
  1382. if ( who )
  1383. {
  1384. if ( szMessage[0] )
  1385. {
  1386. client->Disconnect( "Kicked by %s : %s", who, szMessage );
  1387. }
  1388. else
  1389. {
  1390. client->Disconnect( "Kicked by %s", who );
  1391. }
  1392. }
  1393. else
  1394. {
  1395. if ( szMessage[0] )
  1396. {
  1397. client->Disconnect( "%s", szMessage );
  1398. }
  1399. else
  1400. {
  1401. client->Disconnect( KICKED_BY_CONSOLE );
  1402. }
  1403. }
  1404. }
  1405. }
  1406. /*
  1407. ===============================================================================
  1408. DEBUGGING TOOLS
  1409. ===============================================================================
  1410. */
  1411. //-----------------------------------------------------------------------------
  1412. // Dump memory stats
  1413. //-----------------------------------------------------------------------------
  1414. CON_COMMAND( memory, "Print memory stats." )
  1415. {
  1416. #if !defined(NO_MALLOC_OVERRIDE)
  1417. ConMsg( "Heap Used:\n" );
  1418. int nTotal = MemAlloc_GetSize( 0 );
  1419. if (nTotal == -1)
  1420. {
  1421. ConMsg( "Corrupted!\n" );
  1422. }
  1423. else
  1424. {
  1425. ConMsg( "%5.2f MB (%d bytes)\n", nTotal/(1024.0f*1024.0f), nTotal );
  1426. }
  1427. #endif
  1428. #ifdef VPROF_ENABLED
  1429. ConMsg("\nVideo Memory Used:\n");
  1430. CVProfile *pProf = &g_VProfCurrentProfile;
  1431. int prefixLen = strlen( "TexGroup_Global_" );
  1432. float total = 0.0f;
  1433. for ( int i=0; i < pProf->GetNumCounters(); i++ )
  1434. {
  1435. if ( pProf->GetCounterGroup( i ) == COUNTER_GROUP_TEXTURE_GLOBAL )
  1436. {
  1437. float value = pProf->GetCounterValue( i ) * (1.0f/(1024.0f*1024.0f) );
  1438. total += value;
  1439. const char *pName = pProf->GetCounterName( i );
  1440. if ( !Q_strnicmp( pName, "TexGroup_Global_", prefixLen ) )
  1441. {
  1442. pName += prefixLen;
  1443. }
  1444. ConMsg( "%5.2f MB: %s\n", value, pName );
  1445. }
  1446. }
  1447. ConMsg("------------------\n");
  1448. ConMsg( "%5.2f MB: total\n", total );
  1449. #endif
  1450. ConMsg( "\nHunk Memory Used:\n" );
  1451. Hunk_Print();
  1452. }
  1453. /*
  1454. ===============================================================================
  1455. DEMO LOOP CONTROL
  1456. ===============================================================================
  1457. */
  1458. #ifndef SWDS
  1459. //MOTODO move all demo commands to demoplayer
  1460. //-----------------------------------------------------------------------------
  1461. // Purpose: Gets number of valid demo names
  1462. // Output : int
  1463. //-----------------------------------------------------------------------------
  1464. int Host_GetNumDemos()
  1465. {
  1466. int c = 0;
  1467. #ifndef SWDS
  1468. for ( int i = 0; i < MAX_DEMOS; ++i )
  1469. {
  1470. const char *demoname = cl.demos[ i ].Get();
  1471. if ( !demoname[ 0 ] )
  1472. break;
  1473. ++c;
  1474. }
  1475. #endif
  1476. return c;
  1477. }
  1478. //-----------------------------------------------------------------------------
  1479. // Purpose:
  1480. //-----------------------------------------------------------------------------
  1481. void Host_PrintDemoList()
  1482. {
  1483. int count = Host_GetNumDemos();
  1484. int next = cl.demonum;
  1485. if ( next >= count || next < 0 )
  1486. {
  1487. next = 0;
  1488. }
  1489. #ifndef SWDS
  1490. for ( int i = 0; i < MAX_DEMOS; ++i )
  1491. {
  1492. const char *demoname = cl.demos[ i ].Get();
  1493. if ( !demoname[ 0 ] )
  1494. break;
  1495. bool isnextdemo = next == i ? true : false;
  1496. DevMsg( "%3s % 2i : %20s\n", isnextdemo ? "-->" : " ", i, cl.demos[ i ].Get() );
  1497. }
  1498. #endif
  1499. if ( !count )
  1500. {
  1501. DevMsg( "No demos in list, use startdemos <demoname> <demoname2> to specify\n" );
  1502. }
  1503. }
  1504. #ifndef SWDS
  1505. //-----------------------------------------------------------------------------
  1506. //
  1507. // Con commands related to demos, not available on dedicated servers
  1508. //
  1509. //-----------------------------------------------------------------------------
  1510. //-----------------------------------------------------------------------------
  1511. // Purpose: Specify list of demos for the "demos" command
  1512. //-----------------------------------------------------------------------------
  1513. CON_COMMAND( startdemos, "Play demos in demo sequence." )
  1514. {
  1515. int c = args.ArgC() - 1;
  1516. if (c > MAX_DEMOS)
  1517. {
  1518. Msg ("Max %i demos in demoloop\n", MAX_DEMOS);
  1519. c = MAX_DEMOS;
  1520. }
  1521. Msg ("%i demo(s) in loop\n", c);
  1522. for ( int i=1 ; i<c+1 ; i++ )
  1523. {
  1524. cl.demos[i-1] = args[i];
  1525. }
  1526. cl.demonum = 0;
  1527. Host_PrintDemoList();
  1528. if ( !sv.IsActive() && !demoplayer->IsPlayingBack() )
  1529. {
  1530. CL_NextDemo ();
  1531. }
  1532. else
  1533. {
  1534. cl.demonum = -1;
  1535. }
  1536. }
  1537. //-----------------------------------------------------------------------------
  1538. // Purpose: Return to looping demos, optional resume demo index
  1539. //-----------------------------------------------------------------------------
  1540. CON_COMMAND( demos, "Demo demo file sequence." )
  1541. {
  1542. int oldn = cl.demonum;
  1543. cl.demonum = -1;
  1544. Host_Disconnect(false);
  1545. cl.demonum = oldn;
  1546. if (cl.demonum == -1)
  1547. cl.demonum = 0;
  1548. if ( args.ArgC() == 2 )
  1549. {
  1550. int numdemos = Host_GetNumDemos();
  1551. if ( numdemos >= 1 )
  1552. {
  1553. cl.demonum = clamp( Q_atoi( args[1] ), 0, numdemos - 1 );
  1554. DevMsg( "Jumping to %s\n", cl.demos[ cl.demonum ].Get() );
  1555. }
  1556. }
  1557. Host_PrintDemoList();
  1558. CL_NextDemo ();
  1559. }
  1560. //-----------------------------------------------------------------------------
  1561. // Purpose: Stop current demo
  1562. //-----------------------------------------------------------------------------
  1563. CON_COMMAND_F( stopdemo, "Stop playing back a demo.", FCVAR_DONTRECORD )
  1564. {
  1565. if ( !demoplayer->IsPlayingBack() )
  1566. return;
  1567. Host_Disconnect (true);
  1568. }
  1569. //-----------------------------------------------------------------------------
  1570. // Purpose: Skip to next demo
  1571. //-----------------------------------------------------------------------------
  1572. CON_COMMAND( nextdemo, "Play next demo in sequence." )
  1573. {
  1574. if ( args.ArgC() == 2 )
  1575. {
  1576. int numdemos = Host_GetNumDemos();
  1577. if ( numdemos >= 1 )
  1578. {
  1579. cl.demonum = clamp( Q_atoi( args[1] ), 0, numdemos - 1 );
  1580. DevMsg( "Jumping to %s\n", cl.demos[ cl.demonum ].Get() );
  1581. }
  1582. }
  1583. Host_EndGame( false, "Moving to next demo..." );
  1584. }
  1585. //-----------------------------------------------------------------------------
  1586. // Purpose: Print out the current demo play order
  1587. //-----------------------------------------------------------------------------
  1588. CON_COMMAND( demolist, "Print demo sequence list." )
  1589. {
  1590. Host_PrintDemoList();
  1591. }
  1592. //-----------------------------------------------------------------------------
  1593. // Purpose: Host_Soundfade_f
  1594. //-----------------------------------------------------------------------------
  1595. CON_COMMAND_F( soundfade, "Fade client volume.", FCVAR_SERVER_CAN_EXECUTE )
  1596. {
  1597. float percent;
  1598. float inTime, holdTime, outTime;
  1599. if (args.ArgC() != 3 && args.ArgC() != 5)
  1600. {
  1601. Msg("soundfade <percent> <hold> [<out> <int>]\n");
  1602. return;
  1603. }
  1604. percent = clamp( (float) atof(args[1]), 0.0f, 100.0f );
  1605. holdTime = max( 0., atof(args[2]) );
  1606. inTime = 0.0f;
  1607. outTime = 0.0f;
  1608. if (args.ArgC() == 5)
  1609. {
  1610. outTime = max( 0., atof(args[3]) );
  1611. inTime = max( 0., atof( args[4]) );
  1612. }
  1613. S_SoundFade( percent, holdTime, outTime, inTime );
  1614. }
  1615. #endif // !SWDS
  1616. #endif
  1617. //-----------------------------------------------------------------------------
  1618. // Shutdown the server
  1619. //-----------------------------------------------------------------------------
  1620. CON_COMMAND( killserver, "Shutdown the server." )
  1621. {
  1622. Host_Disconnect(true);
  1623. if ( !sv.IsDedicated() )
  1624. {
  1625. // close network sockets
  1626. NET_SetMutiplayer( false );
  1627. }
  1628. }
  1629. #if !defined(SWDS)
  1630. void Host_VoiceRecordStart_f(void)
  1631. {
  1632. #ifdef VOICE_VOX_ENABLE
  1633. ConVarRef voice_vox( "voice_vox" );
  1634. if ( voice_vox.IsValid() && voice_vox.GetBool() )
  1635. return;
  1636. #endif // VOICE_VOX_ENABLE
  1637. if ( cl.IsActive() )
  1638. {
  1639. const char *pUncompressedFile = NULL;
  1640. const char *pDecompressedFile = NULL;
  1641. const char *pInputFile = NULL;
  1642. if (voice_recordtofile.GetInt())
  1643. {
  1644. pUncompressedFile = "voice_micdata.wav";
  1645. pDecompressedFile = "voice_decompressed.wav";
  1646. }
  1647. if (voice_inputfromfile.GetInt())
  1648. {
  1649. pInputFile = "voice_input.wav";
  1650. }
  1651. if ( !sv_allow_voice_from_file.GetBool() )
  1652. {
  1653. pInputFile = NULL;
  1654. }
  1655. #if !defined( NO_VOICE )
  1656. if (Voice_RecordStart(pUncompressedFile, pDecompressedFile, pInputFile))
  1657. {
  1658. }
  1659. #endif
  1660. }
  1661. }
  1662. void Host_VoiceRecordStop_f(void)
  1663. {
  1664. #ifdef VOICE_VOX_ENABLE
  1665. ConVarRef voice_vox( "voice_vox" );
  1666. if ( voice_vox.IsValid() && voice_vox.GetBool() )
  1667. return;
  1668. #endif // VOICE_VOX_ENABLE
  1669. if ( cl.IsActive() )
  1670. {
  1671. #if !defined( NO_VOICE )
  1672. if (Voice_IsRecording())
  1673. {
  1674. CL_SendVoicePacket( g_bUsingSteamVoice ? false : true );
  1675. Voice_UserDesiresStop();
  1676. }
  1677. #endif
  1678. }
  1679. }
  1680. #ifdef VOICE_VOX_ENABLE
  1681. void Host_VoiceToggle_f( const CCommand &args )
  1682. {
  1683. if ( cl.IsActive() )
  1684. {
  1685. #if !defined( NO_VOICE )
  1686. bool bToggle = false;
  1687. if ( args.ArgC() == 2 && V_strcasecmp( args[1], "on" ) == 0 )
  1688. {
  1689. bToggle = true;
  1690. }
  1691. if ( Voice_IsRecording() && bToggle == false )
  1692. {
  1693. CL_SendVoicePacket( g_bUsingSteamVoice ? false : true );
  1694. Voice_UserDesiresStop();
  1695. }
  1696. else if ( !Voice_IsRecording() && bToggle == true )
  1697. {
  1698. const char *pUncompressedFile = NULL;
  1699. const char *pDecompressedFile = NULL;
  1700. const char *pInputFile = NULL;
  1701. if (voice_recordtofile.GetInt())
  1702. {
  1703. pUncompressedFile = "voice_micdata.wav";
  1704. pDecompressedFile = "voice_decompressed.wav";
  1705. }
  1706. if (voice_inputfromfile.GetInt())
  1707. {
  1708. pInputFile = "voice_input.wav";
  1709. }
  1710. if ( !sv_allow_voice_from_file.GetBool() )
  1711. {
  1712. pInputFile = NULL;
  1713. }
  1714. Voice_RecordStart( pUncompressedFile, pDecompressedFile, pInputFile );
  1715. }
  1716. #endif // NO_VOICE
  1717. }
  1718. }
  1719. #endif // VOICE_VOX_ENABLE
  1720. #endif // SWDS
  1721. //-----------------------------------------------------------------------------
  1722. // Purpose: Wrapper for modelloader->Print() function call
  1723. //-----------------------------------------------------------------------------
  1724. CON_COMMAND( listmodels, "List loaded models." )
  1725. {
  1726. modelloader->Print();
  1727. }
  1728. /*
  1729. ==================
  1730. Host_IncrementCVar
  1731. ==================
  1732. */
  1733. CON_COMMAND_F( incrementvar, "Increment specified convar value.", FCVAR_DONTRECORD )
  1734. {
  1735. if( args.ArgC() != 5 )
  1736. {
  1737. Warning( "Usage: incrementvar varName minValue maxValue delta\n" );
  1738. return;
  1739. }
  1740. const char *varName = args[ 1 ];
  1741. if( !varName )
  1742. {
  1743. ConDMsg( "Host_IncrementCVar_f without a varname\n" );
  1744. return;
  1745. }
  1746. ConVar *var = ( ConVar * )g_pCVar->FindVar( varName );
  1747. if( !var )
  1748. {
  1749. ConDMsg( "cvar \"%s\" not found\n", varName );
  1750. return;
  1751. }
  1752. float currentValue = var->GetFloat();
  1753. float startValue = atof( args[ 2 ] );
  1754. float endValue = atof( args[ 3 ] );
  1755. float delta = atof( args[ 4 ] );
  1756. float newValue = currentValue + delta;
  1757. if( newValue > endValue )
  1758. {
  1759. newValue = startValue;
  1760. }
  1761. else if ( newValue < startValue )
  1762. {
  1763. newValue = endValue;
  1764. }
  1765. // Conver incrementvar command to direct sets to avoid any problems with state in a demo loop.
  1766. Cbuf_AddText( va("%s %f", varName, newValue) );
  1767. ConDMsg( "%s = %f\n", var->GetName(), newValue );
  1768. }
  1769. //-----------------------------------------------------------------------------
  1770. // Host_MultiplyCVar_f
  1771. //-----------------------------------------------------------------------------
  1772. CON_COMMAND_F( multvar, "Multiply specified convar value.", FCVAR_DONTRECORD )
  1773. {
  1774. if (( args.ArgC() != 5 ))
  1775. {
  1776. Warning( "Usage: multvar varName minValue maxValue factor\n" );
  1777. return;
  1778. }
  1779. const char *varName = args[ 1 ];
  1780. if( !varName )
  1781. {
  1782. ConDMsg( "multvar without a varname\n" );
  1783. return;
  1784. }
  1785. ConVar *var = ( ConVar * )g_pCVar->FindVar( varName );
  1786. if( !var )
  1787. {
  1788. ConDMsg( "cvar \"%s\" not found\n", varName );
  1789. return;
  1790. }
  1791. float currentValue = var->GetFloat();
  1792. float startValue = atof( args[ 2 ] );
  1793. float endValue = atof( args[ 3 ] );
  1794. float factor = atof( args[ 4 ] );
  1795. float newValue = currentValue * factor;
  1796. if( newValue > endValue )
  1797. {
  1798. newValue = endValue;
  1799. }
  1800. else if ( newValue < startValue )
  1801. {
  1802. newValue = startValue;
  1803. }
  1804. // Conver incrementvar command to direct sets to avoid any problems with state in a demo loop.
  1805. Cbuf_AddText( va("%s %f", varName, newValue) );
  1806. ConDMsg( "%s = %f\n", var->GetName(), newValue );
  1807. }
  1808. //-----------------------------------------------------------------------------
  1809. // Purpose:
  1810. //-----------------------------------------------------------------------------
  1811. CON_COMMAND( dumpstringtables, "Print string tables to console." )
  1812. {
  1813. SV_PrintStringTables();
  1814. #ifndef SWDS
  1815. CL_PrintStringTables();
  1816. #endif
  1817. }
  1818. // Register shared commands
  1819. ConCommand quit("quit", Host_Quit_f, "Exit the engine.");
  1820. static ConCommand cmd_exit("exit", Host_Quit_f, "Exit the engine.");
  1821. #ifndef SWDS
  1822. #ifdef VOICE_OVER_IP
  1823. static ConCommand startvoicerecord("+voicerecord", Host_VoiceRecordStart_f);
  1824. static ConCommand endvoicerecord("-voicerecord", Host_VoiceRecordStop_f);
  1825. #ifdef VOICE_VOX_ENABLE
  1826. static ConCommand togglevoicerecord("voicerecord_toggle", Host_VoiceToggle_f);
  1827. #endif // VOICE_VOX_ENABLE
  1828. #endif // VOICE_OVER_IP
  1829. #endif // SWDS
  1830. #if defined( STAGING_ONLY )
  1831. // From Kyle: For the GC we added this so we could call it over and
  1832. // over until we got the crash reporter fixed.
  1833. // Visual studio optimizes this away unless we disable optimizations.
  1834. #pragma optimize( "", off )
  1835. class PureCallBase
  1836. {
  1837. public:
  1838. virtual void PureFunction() = 0;
  1839. PureCallBase()
  1840. {
  1841. NonPureFunction();
  1842. }
  1843. void NonPureFunction()
  1844. {
  1845. PureFunction();
  1846. }
  1847. };
  1848. class PureCallDerived : public PureCallBase
  1849. {
  1850. public:
  1851. void PureFunction() OVERRIDE
  1852. {
  1853. }
  1854. };
  1855. //-----------------------------------------------------------------------------
  1856. // Purpose: Force various crashes. useful for testing minidumps.
  1857. // crash : Write 0 to address 0.
  1858. // crash sys_error : Call Sys_Error().
  1859. // crash hang : Hang.
  1860. // crash purecall : Call virtual function in ctor.
  1861. //-----------------------------------------------------------------------------
  1862. CON_COMMAND( crash, "[ sys_error | hang | purecall | segfault | minidump ]: Cause the engine to crash." )
  1863. {
  1864. if ( cmd_source != src_command )
  1865. return;
  1866. CUtlString cmd( ( args.ArgC() > 1 ) ? args[ 1 ] : "" );
  1867. if ( cmd == "hang" )
  1868. {
  1869. // Hang. Useful to test watchdog code.
  1870. Msg( "Hanging... Watchdog time: %d.\n ", Plat_GetWatchdogTime() );
  1871. for ( ;; )
  1872. {
  1873. Msg( "%d ", Plat_MSTime() );
  1874. ThreadSleep( 5000 );
  1875. }
  1876. }
  1877. else if ( cmd == "purecall" )
  1878. {
  1879. Msg( "Instantiating PureCallDerived_derived...\n" );
  1880. PureCallDerived derived;
  1881. }
  1882. else if ( cmd == "sys_error" )
  1883. {
  1884. Msg( "Calling Sys_Error...\n" );
  1885. Sys_Error( "%s: Sys_Error()!!!", __FUNCTION__ );
  1886. }
  1887. else if ( cmd == "minidump" )
  1888. {
  1889. Msg( "Forcing minidump. build_number: %d.\n", build_number() );
  1890. SteamAPI_WriteMiniDump( 0, NULL, build_number() );
  1891. }
  1892. else
  1893. {
  1894. Msg( "Segfault...\n" );
  1895. char *p = 0;
  1896. *p = 0;
  1897. }
  1898. }
  1899. #pragma optimize( "", on )
  1900. #endif // STAGING_ONLY
  1901. CON_COMMAND_F( flush, "Flush unlocked cache memory.", FCVAR_CHEAT )
  1902. {
  1903. #if !defined( SWDS )
  1904. g_ClientDLL->InvalidateMdlCache();
  1905. #endif // SWDS
  1906. serverGameDLL->InvalidateMdlCache();
  1907. g_pDataCache->Flush( true );
  1908. }
  1909. CON_COMMAND_F( flush_locked, "Flush unlocked and locked cache memory.", FCVAR_CHEAT )
  1910. {
  1911. #if !defined( SWDS )
  1912. g_ClientDLL->InvalidateMdlCache();
  1913. #endif // SWDS
  1914. serverGameDLL->InvalidateMdlCache();
  1915. g_pDataCache->Flush( false );
  1916. }
  1917. CON_COMMAND( cache_print, "cache_print [section]\nPrint out contents of cache memory." )
  1918. {
  1919. const char *pszSection = NULL;
  1920. if ( args.ArgC() == 2 )
  1921. {
  1922. pszSection = args[ 1 ];
  1923. }
  1924. g_pDataCache->OutputReport( DC_DETAIL_REPORT, pszSection );
  1925. }
  1926. CON_COMMAND( cache_print_lru, "cache_print_lru [section]\nPrint out contents of cache memory." )
  1927. {
  1928. const char *pszSection = NULL;
  1929. if ( args.ArgC() == 2 )
  1930. {
  1931. pszSection = args[ 1 ];
  1932. }
  1933. g_pDataCache->OutputReport( DC_DETAIL_REPORT_LRU, pszSection );
  1934. }
  1935. CON_COMMAND( cache_print_summary, "cache_print_summary [section]\nPrint out a summary contents of cache memory." )
  1936. {
  1937. const char *pszSection = NULL;
  1938. if ( args.ArgC() == 2 )
  1939. {
  1940. pszSection = args[ 1 ];
  1941. }
  1942. g_pDataCache->OutputReport( DC_SUMMARY_REPORT, pszSection );
  1943. }
  1944. CON_COMMAND( sv_dump_edicts, "Display a list of edicts allocated on the server." )
  1945. {
  1946. if ( !sv.IsActive() )
  1947. return;
  1948. CUtlMap<CUtlString, int> classNameCountMap;
  1949. classNameCountMap.SetLessFunc( UtlStringLessFunc );
  1950. Msg( "\nCurrent server edicts:\n");
  1951. for ( int i = 0; i < sv.num_edicts; ++i )
  1952. {
  1953. CUtlMap<CUtlString, int>::IndexType_t index = classNameCountMap.Find( sv.edicts[ i ].GetClassName() );
  1954. if ( index == classNameCountMap.InvalidIndex() )
  1955. {
  1956. index = classNameCountMap.Insert( sv.edicts[ i ].GetClassName(), 0 );
  1957. }
  1958. classNameCountMap[ index ]++;
  1959. }
  1960. Msg( "Count Classname\n");
  1961. FOR_EACH_MAP( classNameCountMap, i )
  1962. {
  1963. Msg("%5d %s\n", classNameCountMap[ i ], classNameCountMap.Key(i).String() );
  1964. }
  1965. Msg( "NumEdicts: %d\n", sv.num_edicts );
  1966. Msg( "FreeEdicts: %d\n\n", sv.free_edicts );
  1967. }
  1968. // make valve_ds only?
  1969. CON_COMMAND_F( memory_list, "dump memory list (linux only)", FCVAR_CHEAT )
  1970. {
  1971. DumpMemoryLog( 128 * 1024 );
  1972. }
  1973. // make valve_ds only?
  1974. CON_COMMAND_F( memory_status, "show memory stats (linux only)", FCVAR_CHEAT )
  1975. {
  1976. DumpMemorySummary();
  1977. }
  1978. // make valve_ds only?
  1979. CON_COMMAND_F( memory_mark, "snapshot current allocation status", FCVAR_CHEAT )
  1980. {
  1981. SetMemoryMark();
  1982. }
  1983. // make valve_ds only?
  1984. CON_COMMAND_F( memory_diff, "show memory stats relative to snapshot", FCVAR_CHEAT )
  1985. {
  1986. DumpChangedMemory( 64 * 1024 );
  1987. }
  1988. //-----------------------------------------------------------------------------
  1989. //
  1990. //-----------------------------------------------------------------------------
  1991. CON_COMMAND( namelockid, "Prevent name changes for this userID." )
  1992. {
  1993. if ( args.ArgC() <= 2 )
  1994. {
  1995. ConMsg( "Usage: namelockid < userid > < 0 | 1 >\n" );
  1996. return;
  1997. }
  1998. CBaseClient *pClient = NULL;
  1999. int iIndex = Q_atoi( args[1] );
  2000. if ( iIndex > 0 )
  2001. {
  2002. for ( int i = 0; i < sv.GetClientCount(); i++ )
  2003. {
  2004. pClient = static_cast< CBaseClient* >( sv.GetClient( i ) );
  2005. if ( !pClient->IsConnected() )
  2006. continue;
  2007. #if defined( REPLAY_ENABLED )
  2008. if ( pClient->IsReplay() )
  2009. continue;
  2010. #endif
  2011. if ( pClient->IsHLTV() )
  2012. continue;
  2013. if ( pClient->GetUserID() == iIndex )
  2014. break;
  2015. pClient = NULL;
  2016. }
  2017. }
  2018. if ( pClient )
  2019. {
  2020. pClient->SetPlayerNameLocked( ( Q_atoi( args[2] ) == 0 ) ? false : true );
  2021. }
  2022. else
  2023. {
  2024. ConMsg( "Player id \"%d\" not found.\n", iIndex );
  2025. }
  2026. }
  2027. #if defined( STAGING_ONLY ) || defined( _DEBUG )
  2028. CON_COMMAND( fs_find, "Run virtual filesystem find" )
  2029. {
  2030. if ( args.ArgC() != 3 )
  2031. {
  2032. ConMsg( "Usage: fs_find wildcard pathid\n" );
  2033. return;
  2034. }
  2035. const char *pWildcard = args.Arg(1);
  2036. const char *pPathID = args.Arg(2);
  2037. FileFindHandle_t findhandle;
  2038. const char *pFile = NULL;
  2039. size_t matches = 0;
  2040. for ( pFile = g_pFullFileSystem->FindFirstEx( pWildcard, pPathID, &findhandle );
  2041. pFile;
  2042. pFile = g_pFullFileSystem->FindNext( findhandle ) )
  2043. {
  2044. ConMsg( "%s\n", pFile );
  2045. matches++;
  2046. }
  2047. ConMsg( " %u matching files/directories\n", matches );
  2048. }
  2049. #endif // defined( STAGING_ONLY ) || defined( _DEBUG )