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.

484 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // REMOTE_CMDS.CPP
  4. //
  5. // Remote commands received by an external application and dispatched.
  6. //=====================================================================================//
  7. #include "vxconsole.h"
  8. remoteCommand_t *g_remoteCommands[MAX_RCMDS];
  9. int g_numRemoteCommands;
  10. //-----------------------------------------------------------------------------
  11. // MatchRemoteCommands
  12. //
  13. //-----------------------------------------------------------------------------
  14. int MatchRemoteCommands( char *pCmdStr, const char *cmdList[], int maxCmds )
  15. {
  16. int numCommands = 0;
  17. // look in local
  18. int matchLen = strlen( pCmdStr );
  19. for ( int i=0; i<g_numRemoteCommands; i++ )
  20. {
  21. if ( !strnicmp( pCmdStr, g_remoteCommands[i]->strCommand, matchLen ) )
  22. {
  23. cmdList[numCommands++] = g_remoteCommands[i]->strCommand;
  24. if ( numCommands >= maxCmds )
  25. break;
  26. }
  27. }
  28. return ( numCommands );
  29. }
  30. //-----------------------------------------------------------------------------
  31. // GetToken
  32. //
  33. //-----------------------------------------------------------------------------
  34. char *GetToken( char **ppTokenStream )
  35. {
  36. static char token[MAX_TOKENCHARS];
  37. int len;
  38. char c;
  39. char *pData;
  40. len = 0;
  41. token[0] = 0;
  42. if ( !ppTokenStream )
  43. return NULL;
  44. pData = *ppTokenStream;
  45. // skip whitespace
  46. skipwhite:
  47. while ( ( c = *pData ) <= ' ' )
  48. {
  49. if ( !c )
  50. goto cleanup;
  51. pData++;
  52. }
  53. // skip // comments
  54. if ( c=='/' && pData[1] == '/' )
  55. {
  56. while ( *pData && *pData != '\n' )
  57. pData++;
  58. goto skipwhite;
  59. }
  60. // handle quoted strings specially
  61. if ( c == '\"' )
  62. {
  63. pData++;
  64. while ( 1 )
  65. {
  66. c = *pData++;
  67. if ( c=='\"' || !c )
  68. goto cleanup;
  69. token[len] = c;
  70. len++;
  71. if ( len > MAX_TOKENCHARS-1 )
  72. goto cleanup;
  73. }
  74. }
  75. // parse a regular word
  76. do
  77. {
  78. token[len] = c;
  79. pData++;
  80. len++;
  81. if ( len > MAX_TOKENCHARS-1 )
  82. break;
  83. c = *pData;
  84. }
  85. while ( c > ' ' && c <= '~' );
  86. cleanup:
  87. token[len] = 0;
  88. *ppTokenStream = pData;
  89. return ( token );
  90. }
  91. //-----------------------------------------------------------------------------
  92. // CommandCompleted
  93. //
  94. //-----------------------------------------------------------------------------
  95. void CommandCompleted( int errCode )
  96. {
  97. char cmdString[MAX_PATH];
  98. // send command complete
  99. sprintf( cmdString, "%s!__complete__%d", VXCONSOLE_COMMAND_PREFIX, errCode );
  100. DmAPI_SendCommand( cmdString, true );
  101. }
  102. //-----------------------------------------------------------------------------
  103. // DebugCommand
  104. //-----------------------------------------------------------------------------
  105. void DebugCommand( const char *pStrFormat, ... )
  106. {
  107. char buffer[MAX_QUEUEDSTRINGLEN];
  108. va_list arglist;
  109. if ( !g_debugCommands )
  110. return;
  111. va_start( arglist, pStrFormat );
  112. _vsnprintf( buffer, MAX_QUEUEDSTRINGLEN, pStrFormat, arglist );
  113. va_end( arglist );
  114. PrintToQueue( RGB( 0,128,0 ), "[CMD]: %s", buffer );
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Remote_NotifyPrintFunc
  118. //
  119. //-----------------------------------------------------------------------------
  120. DWORD __stdcall Remote_NotifyPrintFunc( const CHAR *pStrNotification )
  121. {
  122. int color;
  123. if ( !strnicmp( pStrNotification, VXCONSOLE_PRINT_PREFIX, strlen( VXCONSOLE_PRINT_PREFIX ) ) )
  124. {
  125. // skip past prefix!
  126. pStrNotification += strlen( VXCONSOLE_PRINT_PREFIX )+1;
  127. }
  128. color = XBX_CLR_DEFAULT;
  129. if ( !strnicmp( pStrNotification, VXCONSOLE_COLOR_PREFIX, strlen( VXCONSOLE_COLOR_PREFIX ) ) )
  130. {
  131. // skip past prefix[12345678]
  132. char buff[16];
  133. pStrNotification += strlen( VXCONSOLE_COLOR_PREFIX );
  134. memcpy( buff, pStrNotification, 10 );
  135. if ( buff[0] == '[' && buff[9] == ']' )
  136. {
  137. buff[0] = ' ';
  138. buff[9] = ' ';
  139. buff[10] = '\0';
  140. sscanf( buff, "%x", &color );
  141. pStrNotification += 10;
  142. }
  143. }
  144. PrintToQueue( color, "%s\n", pStrNotification );
  145. return S_OK;
  146. }
  147. //-----------------------------------------------------------------------------
  148. // Remote_NotifyDebugString
  149. //
  150. // Print as [DBG]:xxxx
  151. //-----------------------------------------------------------------------------
  152. DWORD __stdcall Remote_NotifyDebugString( ULONG dwNotification, DWORD dwParam )
  153. {
  154. if ( g_captureDebugSpew )
  155. {
  156. PDMN_DEBUGSTR p = ( PDMN_DEBUGSTR )dwParam;
  157. int len;
  158. // strip all terminating cr
  159. len = p->Length-1;
  160. while ( len > 0 )
  161. {
  162. if ( p->String[len] != '\n' )
  163. {
  164. len++;
  165. break;
  166. }
  167. len--;
  168. }
  169. // for safety, terminate
  170. CHAR* strTemp = new CHAR[len+1];
  171. memcpy( strTemp, p->String, len*sizeof( CHAR ) );
  172. strTemp[len] = '\0';
  173. PrintToQueue( RGB( 0,0,255 ), "[DBG]: %s\n", strTemp );
  174. delete[] strTemp;
  175. }
  176. // Don't let the compiler complain about unused parameters
  177. ( VOID )dwNotification;
  178. return 0;
  179. }
  180. //-----------------------------------------------------------------------------
  181. // Remote_CompareCommands
  182. //
  183. //-----------------------------------------------------------------------------
  184. int Remote_CompareCommands( const void *pElem1, const void *pElem2 )
  185. {
  186. remoteCommand_t *pCmd1;
  187. remoteCommand_t *pCmd2;
  188. pCmd1 = *( remoteCommand_t** )( pElem1 );
  189. pCmd2 = *( remoteCommand_t** )( pElem2 );
  190. return ( strcmp( pCmd1->strCommand, pCmd2->strCommand ) );
  191. }
  192. //-----------------------------------------------------------------------------
  193. // Remote_DeleteCommands
  194. //
  195. //-----------------------------------------------------------------------------
  196. void Remote_DeleteCommands()
  197. {
  198. if ( !g_numRemoteCommands )
  199. return;
  200. for ( int i=0; i<g_numRemoteCommands; i++ )
  201. {
  202. delete [] g_remoteCommands[i]->strCommand;
  203. delete [] g_remoteCommands[i]->strHelp;
  204. delete g_remoteCommands[i];
  205. g_remoteCommands[i] = NULL;
  206. }
  207. g_numRemoteCommands = 0;
  208. }
  209. //-----------------------------------------------------------------------------
  210. // Remote_AddCommand
  211. //
  212. //-----------------------------------------------------------------------------
  213. bool Remote_AddCommand( char *command, char *helptext )
  214. {
  215. if ( g_numRemoteCommands == MAX_RCMDS )
  216. {
  217. // full
  218. return false;
  219. }
  220. // look for duplicate
  221. int i;
  222. for ( i = 0; i < g_numRemoteCommands; i++ )
  223. {
  224. if ( !stricmp( command, g_remoteCommands[i]->strCommand ) )
  225. break;
  226. }
  227. if ( i < g_numRemoteCommands )
  228. {
  229. // already in list, skip - not an error
  230. return true;
  231. }
  232. // add new command to list
  233. g_remoteCommands[g_numRemoteCommands] = new remoteCommand_t;
  234. g_remoteCommands[g_numRemoteCommands]->strCommand = new char[strlen( command )+1];
  235. strcpy( g_remoteCommands[g_numRemoteCommands]->strCommand, command );
  236. g_remoteCommands[g_numRemoteCommands]->strHelp = new char[strlen( helptext )+1];
  237. strcpy( g_remoteCommands[g_numRemoteCommands]->strHelp, helptext );
  238. g_numRemoteCommands++;
  239. // success
  240. return true;
  241. }
  242. //-----------------------------------------------------------------------------
  243. // rc_AddCommands
  244. //
  245. // Exposes an app's list of remote commands
  246. //-----------------------------------------------------------------------------
  247. int rc_AddCommands( char *commandPtr )
  248. {
  249. char* cmdToken;
  250. int numCommands;
  251. int cmdList;
  252. int retAddr;
  253. int retVal;
  254. int errCode;
  255. xrCommand_t* locallist;
  256. errCode = -1;
  257. // pacifier for lengthy operation
  258. ConsoleWindowPrintf( RGB( 0, 0, 0 ), "Receiving Console Commands From Game..." );
  259. // get number of commands
  260. cmdToken = GetToken( &commandPtr );
  261. if ( !cmdToken[0] )
  262. goto cleanUp;
  263. sscanf( cmdToken, "%x", &numCommands );
  264. // get command list
  265. cmdToken = GetToken( &commandPtr );
  266. if ( !cmdToken[0] )
  267. goto cleanUp;
  268. sscanf( cmdToken, "%x", &cmdList );
  269. // get retAddr
  270. cmdToken = GetToken( &commandPtr );
  271. if ( !cmdToken[0] )
  272. goto cleanUp;
  273. sscanf( cmdToken, "%x", &retAddr );
  274. locallist = new xrCommand_t[numCommands];
  275. memset( locallist, 0, numCommands*sizeof( xrCommand_t ) );
  276. // get the caller's command list
  277. DmGetMemory( ( void* )cmdList, numCommands*sizeof( xrCommand_t ), locallist, NULL );
  278. int numAdded = 0;
  279. for ( int i=0; i<numCommands; i++ )
  280. {
  281. if ( Remote_AddCommand( locallist[i].nameString, locallist[i].helpString ) )
  282. numAdded++;
  283. }
  284. // sort the list
  285. qsort( g_remoteCommands, g_numRemoteCommands, sizeof( remoteCommand_t* ), Remote_CompareCommands );
  286. ConsoleWindowPrintf( RGB( 0, 0, 0 ), "Completed.\n" );
  287. // return the result
  288. retVal = numAdded;
  289. int xboxRetVal = BigDWord( retVal );
  290. DmSetMemory( ( void* )retAddr, sizeof( int ), &xboxRetVal, NULL );
  291. DebugCommand( "0x%8.8x = AddCommands( 0x%8.8x, 0x%8.8x )\n", retVal, numCommands, cmdList );
  292. delete [] locallist;
  293. // success
  294. errCode = 0;
  295. if ( g_bPlayTestMode )
  296. {
  297. if ( g_connectedToApp )
  298. {
  299. // send the developer command
  300. ProcessCommand( "developer 1" );
  301. }
  302. }
  303. cleanUp:
  304. return ( errCode );
  305. }
  306. //-----------------------------------------------------------------------------
  307. // Remote_NotifyCommandFunc
  308. //
  309. //-----------------------------------------------------------------------------
  310. DWORD __stdcall Remote_NotifyCommandFunc( const CHAR *strNotification )
  311. {
  312. CHAR* commandPtr;
  313. CHAR* cmdToken;
  314. int errCode;
  315. bool async;
  316. // skip over the command prefix and the exclamation mark
  317. strNotification += strlen( VXCONSOLE_COMMAND_PREFIX ) + 1;
  318. commandPtr = ( CHAR* )strNotification;
  319. // failure until otherwise
  320. errCode = -1;
  321. // default synchronous
  322. async = false;
  323. cmdToken = GetToken( &commandPtr );
  324. if ( cmdToken && !stricmp( cmdToken, "AddCommands()" ) )
  325. {
  326. errCode = rc_AddCommands( commandPtr );
  327. goto cleanUp;
  328. }
  329. else if ( cmdToken && !stricmp( cmdToken, "SetProfile()" ) )
  330. {
  331. // first arg dictates routing
  332. cmdToken = GetToken( &commandPtr );
  333. if ( cmdToken && !stricmp( cmdToken, "cpu" ) )
  334. errCode = rc_SetCpuProfile( commandPtr );
  335. else if ( cmdToken && !stricmp( cmdToken, "texture" ) )
  336. errCode = rc_SetTexProfile( commandPtr );
  337. goto cleanUp;
  338. }
  339. else if ( cmdToken && !stricmp( cmdToken, "SetProfileData()" ) )
  340. {
  341. // first arg dictates routing
  342. cmdToken = GetToken( &commandPtr );
  343. if ( cmdToken && !stricmp( cmdToken, "cpu" ) )
  344. errCode = rc_SetCpuProfileData( commandPtr );
  345. else if ( cmdToken && !stricmp( cmdToken, "texture" ) )
  346. errCode = rc_SetTexProfileData( commandPtr );
  347. async = true;
  348. goto cleanUp;
  349. }
  350. else if ( cmdToken && !stricmp( cmdToken, "TextureList()" ) )
  351. {
  352. errCode = rc_TextureList( commandPtr );
  353. goto cleanUp;
  354. }
  355. else if ( cmdToken && !stricmp( cmdToken, "MaterialList()" ) )
  356. {
  357. errCode = rc_MaterialList( commandPtr );
  358. goto cleanUp;
  359. }
  360. else if ( cmdToken && !stricmp( cmdToken, "SoundList()" ) )
  361. {
  362. errCode = rc_SoundList( commandPtr );
  363. goto cleanUp;
  364. }
  365. else if ( cmdToken && !stricmp( cmdToken, "TimeStampLog()" ) )
  366. {
  367. errCode = rc_TimeStampLog( commandPtr );
  368. goto cleanUp;
  369. }
  370. else if ( cmdToken && !stricmp( cmdToken, "MemDump()" ) )
  371. {
  372. errCode = rc_MemDump( commandPtr );
  373. async = true;
  374. goto cleanUp;
  375. }
  376. else if ( cmdToken && !stricmp( cmdToken, "MapInfo()" ) )
  377. {
  378. errCode = rc_MapInfo( commandPtr );
  379. goto cleanUp;
  380. }
  381. else if ( cmdToken && !stricmp( cmdToken, "Assert()" ) )
  382. {
  383. errCode = rc_Assert( commandPtr );
  384. goto cleanUp;
  385. }
  386. else if ( cmdToken && !stricmp( cmdToken, "FreeMemory()" ) )
  387. {
  388. errCode = rc_FreeMemory( commandPtr );
  389. async = true;
  390. goto cleanUp;
  391. }
  392. else if ( cmdToken && !stricmp( cmdToken, "Disconnect()" ) )
  393. {
  394. // disconnect requires specialized processing
  395. // send command status first while connection valid, then do actual disconnect
  396. // disconnect is always assumed to be valid, can't be denied
  397. CommandCompleted( 0 );
  398. DoDisconnect( TRUE );
  399. return S_OK;
  400. }
  401. else
  402. {
  403. // unknown command
  404. PrintToQueue( RGB( 255,0,0 ), "Unknown Command: %s\n", strNotification );
  405. goto cleanUp;
  406. }
  407. cleanUp:
  408. if ( !async )
  409. CommandCompleted( errCode );
  410. return ( S_OK );
  411. }