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
484 lines
12 KiB
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// REMOTE_CMDS.CPP
|
|
//
|
|
// Remote commands received by an external application and dispatched.
|
|
//=====================================================================================//
|
|
#include "vxconsole.h"
|
|
|
|
remoteCommand_t *g_remoteCommands[MAX_RCMDS];
|
|
int g_numRemoteCommands;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// MatchRemoteCommands
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
int MatchRemoteCommands( char *pCmdStr, const char *cmdList[], int maxCmds )
|
|
{
|
|
int numCommands = 0;
|
|
|
|
// look in local
|
|
int matchLen = strlen( pCmdStr );
|
|
for ( int i=0; i<g_numRemoteCommands; i++ )
|
|
{
|
|
if ( !strnicmp( pCmdStr, g_remoteCommands[i]->strCommand, matchLen ) )
|
|
{
|
|
cmdList[numCommands++] = g_remoteCommands[i]->strCommand;
|
|
if ( numCommands >= maxCmds )
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ( numCommands );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// GetToken
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
char *GetToken( char **ppTokenStream )
|
|
{
|
|
static char token[MAX_TOKENCHARS];
|
|
int len;
|
|
char c;
|
|
char *pData;
|
|
|
|
len = 0;
|
|
token[0] = 0;
|
|
|
|
if ( !ppTokenStream )
|
|
return NULL;
|
|
|
|
pData = *ppTokenStream;
|
|
|
|
// skip whitespace
|
|
skipwhite:
|
|
while ( ( c = *pData ) <= ' ' )
|
|
{
|
|
if ( !c )
|
|
goto cleanup;
|
|
pData++;
|
|
}
|
|
|
|
// skip // comments
|
|
if ( c=='/' && pData[1] == '/' )
|
|
{
|
|
while ( *pData && *pData != '\n' )
|
|
pData++;
|
|
goto skipwhite;
|
|
}
|
|
|
|
// handle quoted strings specially
|
|
if ( c == '\"' )
|
|
{
|
|
pData++;
|
|
while ( 1 )
|
|
{
|
|
c = *pData++;
|
|
if ( c=='\"' || !c )
|
|
goto cleanup;
|
|
|
|
token[len] = c;
|
|
len++;
|
|
if ( len > MAX_TOKENCHARS-1 )
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
// parse a regular word
|
|
do
|
|
{
|
|
token[len] = c;
|
|
pData++;
|
|
len++;
|
|
if ( len > MAX_TOKENCHARS-1 )
|
|
break;
|
|
c = *pData;
|
|
}
|
|
while ( c > ' ' && c <= '~' );
|
|
|
|
cleanup:
|
|
token[len] = 0;
|
|
*ppTokenStream = pData;
|
|
return ( token );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CommandCompleted
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void CommandCompleted( int errCode )
|
|
{
|
|
char cmdString[MAX_PATH];
|
|
|
|
// send command complete
|
|
sprintf( cmdString, "%s!__complete__%d", VXCONSOLE_COMMAND_PREFIX, errCode );
|
|
DmAPI_SendCommand( cmdString, true );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// DebugCommand
|
|
//-----------------------------------------------------------------------------
|
|
void DebugCommand( const char *pStrFormat, ... )
|
|
{
|
|
char buffer[MAX_QUEUEDSTRINGLEN];
|
|
va_list arglist;
|
|
|
|
if ( !g_debugCommands )
|
|
return;
|
|
|
|
va_start( arglist, pStrFormat );
|
|
_vsnprintf( buffer, MAX_QUEUEDSTRINGLEN, pStrFormat, arglist );
|
|
va_end( arglist );
|
|
|
|
PrintToQueue( RGB( 0,128,0 ), "[CMD]: %s", buffer );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Remote_NotifyPrintFunc
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD __stdcall Remote_NotifyPrintFunc( const CHAR *pStrNotification )
|
|
{
|
|
int color;
|
|
|
|
if ( !strnicmp( pStrNotification, VXCONSOLE_PRINT_PREFIX, strlen( VXCONSOLE_PRINT_PREFIX ) ) )
|
|
{
|
|
// skip past prefix!
|
|
pStrNotification += strlen( VXCONSOLE_PRINT_PREFIX )+1;
|
|
}
|
|
|
|
color = XBX_CLR_DEFAULT;
|
|
|
|
if ( !strnicmp( pStrNotification, VXCONSOLE_COLOR_PREFIX, strlen( VXCONSOLE_COLOR_PREFIX ) ) )
|
|
{
|
|
// skip past prefix[12345678]
|
|
char buff[16];
|
|
pStrNotification += strlen( VXCONSOLE_COLOR_PREFIX );
|
|
memcpy( buff, pStrNotification, 10 );
|
|
if ( buff[0] == '[' && buff[9] == ']' )
|
|
{
|
|
buff[0] = ' ';
|
|
buff[9] = ' ';
|
|
buff[10] = '\0';
|
|
|
|
sscanf( buff, "%x", &color );
|
|
pStrNotification += 10;
|
|
}
|
|
}
|
|
|
|
PrintToQueue( color, "%s\n", pStrNotification );
|
|
return S_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Remote_NotifyDebugString
|
|
//
|
|
// Print as [DBG]:xxxx
|
|
//-----------------------------------------------------------------------------
|
|
DWORD __stdcall Remote_NotifyDebugString( ULONG dwNotification, DWORD dwParam )
|
|
{
|
|
if ( g_captureDebugSpew )
|
|
{
|
|
PDMN_DEBUGSTR p = ( PDMN_DEBUGSTR )dwParam;
|
|
int len;
|
|
|
|
// strip all terminating cr
|
|
len = p->Length-1;
|
|
while ( len > 0 )
|
|
{
|
|
if ( p->String[len] != '\n' )
|
|
{
|
|
len++;
|
|
break;
|
|
}
|
|
len--;
|
|
}
|
|
|
|
// for safety, terminate
|
|
CHAR* strTemp = new CHAR[len+1];
|
|
memcpy( strTemp, p->String, len*sizeof( CHAR ) );
|
|
strTemp[len] = '\0';
|
|
|
|
PrintToQueue( RGB( 0,0,255 ), "[DBG]: %s\n", strTemp );
|
|
|
|
delete[] strTemp;
|
|
}
|
|
|
|
// Don't let the compiler complain about unused parameters
|
|
( VOID )dwNotification;
|
|
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Remote_CompareCommands
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
int Remote_CompareCommands( const void *pElem1, const void *pElem2 )
|
|
{
|
|
remoteCommand_t *pCmd1;
|
|
remoteCommand_t *pCmd2;
|
|
|
|
pCmd1 = *( remoteCommand_t** )( pElem1 );
|
|
pCmd2 = *( remoteCommand_t** )( pElem2 );
|
|
|
|
return ( strcmp( pCmd1->strCommand, pCmd2->strCommand ) );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Remote_DeleteCommands
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void Remote_DeleteCommands()
|
|
{
|
|
if ( !g_numRemoteCommands )
|
|
return;
|
|
|
|
for ( int i=0; i<g_numRemoteCommands; i++ )
|
|
{
|
|
delete [] g_remoteCommands[i]->strCommand;
|
|
delete [] g_remoteCommands[i]->strHelp;
|
|
delete g_remoteCommands[i];
|
|
|
|
g_remoteCommands[i] = NULL;
|
|
}
|
|
|
|
g_numRemoteCommands = 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Remote_AddCommand
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
bool Remote_AddCommand( char *command, char *helptext )
|
|
{
|
|
if ( g_numRemoteCommands == MAX_RCMDS )
|
|
{
|
|
// full
|
|
return false;
|
|
}
|
|
|
|
// look for duplicate
|
|
int i;
|
|
for ( i = 0; i < g_numRemoteCommands; i++ )
|
|
{
|
|
if ( !stricmp( command, g_remoteCommands[i]->strCommand ) )
|
|
break;
|
|
}
|
|
if ( i < g_numRemoteCommands )
|
|
{
|
|
// already in list, skip - not an error
|
|
return true;
|
|
}
|
|
|
|
// add new command to list
|
|
g_remoteCommands[g_numRemoteCommands] = new remoteCommand_t;
|
|
g_remoteCommands[g_numRemoteCommands]->strCommand = new char[strlen( command )+1];
|
|
strcpy( g_remoteCommands[g_numRemoteCommands]->strCommand, command );
|
|
|
|
g_remoteCommands[g_numRemoteCommands]->strHelp = new char[strlen( helptext )+1];
|
|
strcpy( g_remoteCommands[g_numRemoteCommands]->strHelp, helptext );
|
|
|
|
g_numRemoteCommands++;
|
|
|
|
// success
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// rc_AddCommands
|
|
//
|
|
// Exposes an app's list of remote commands
|
|
//-----------------------------------------------------------------------------
|
|
int rc_AddCommands( char *commandPtr )
|
|
{
|
|
char* cmdToken;
|
|
int numCommands;
|
|
int cmdList;
|
|
int retAddr;
|
|
int retVal;
|
|
int errCode;
|
|
xrCommand_t* locallist;
|
|
|
|
errCode = -1;
|
|
|
|
// pacifier for lengthy operation
|
|
ConsoleWindowPrintf( RGB( 0, 0, 0 ), "Receiving Console Commands From Game..." );
|
|
|
|
// get number of commands
|
|
cmdToken = GetToken( &commandPtr );
|
|
if ( !cmdToken[0] )
|
|
goto cleanUp;
|
|
sscanf( cmdToken, "%x", &numCommands );
|
|
|
|
// get command list
|
|
cmdToken = GetToken( &commandPtr );
|
|
if ( !cmdToken[0] )
|
|
goto cleanUp;
|
|
sscanf( cmdToken, "%x", &cmdList );
|
|
|
|
// get retAddr
|
|
cmdToken = GetToken( &commandPtr );
|
|
if ( !cmdToken[0] )
|
|
goto cleanUp;
|
|
sscanf( cmdToken, "%x", &retAddr );
|
|
|
|
locallist = new xrCommand_t[numCommands];
|
|
memset( locallist, 0, numCommands*sizeof( xrCommand_t ) );
|
|
|
|
// get the caller's command list
|
|
DmGetMemory( ( void* )cmdList, numCommands*sizeof( xrCommand_t ), locallist, NULL );
|
|
|
|
int numAdded = 0;
|
|
for ( int i=0; i<numCommands; i++ )
|
|
{
|
|
if ( Remote_AddCommand( locallist[i].nameString, locallist[i].helpString ) )
|
|
numAdded++;
|
|
}
|
|
|
|
// sort the list
|
|
qsort( g_remoteCommands, g_numRemoteCommands, sizeof( remoteCommand_t* ), Remote_CompareCommands );
|
|
|
|
ConsoleWindowPrintf( RGB( 0, 0, 0 ), "Completed.\n" );
|
|
|
|
// return the result
|
|
retVal = numAdded;
|
|
int xboxRetVal = BigDWord( retVal );
|
|
DmSetMemory( ( void* )retAddr, sizeof( int ), &xboxRetVal, NULL );
|
|
|
|
DebugCommand( "0x%8.8x = AddCommands( 0x%8.8x, 0x%8.8x )\n", retVal, numCommands, cmdList );
|
|
|
|
delete [] locallist;
|
|
|
|
// success
|
|
errCode = 0;
|
|
|
|
if ( g_bPlayTestMode )
|
|
{
|
|
if ( g_connectedToApp )
|
|
{
|
|
// send the developer command
|
|
ProcessCommand( "developer 1" );
|
|
}
|
|
}
|
|
|
|
cleanUp:
|
|
return ( errCode );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Remote_NotifyCommandFunc
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD __stdcall Remote_NotifyCommandFunc( const CHAR *strNotification )
|
|
{
|
|
CHAR* commandPtr;
|
|
CHAR* cmdToken;
|
|
int errCode;
|
|
bool async;
|
|
|
|
// skip over the command prefix and the exclamation mark
|
|
strNotification += strlen( VXCONSOLE_COMMAND_PREFIX ) + 1;
|
|
commandPtr = ( CHAR* )strNotification;
|
|
|
|
// failure until otherwise
|
|
errCode = -1;
|
|
|
|
// default synchronous
|
|
async = false;
|
|
|
|
cmdToken = GetToken( &commandPtr );
|
|
|
|
if ( cmdToken && !stricmp( cmdToken, "AddCommands()" ) )
|
|
{
|
|
errCode = rc_AddCommands( commandPtr );
|
|
goto cleanUp;
|
|
}
|
|
else if ( cmdToken && !stricmp( cmdToken, "SetProfile()" ) )
|
|
{
|
|
// first arg dictates routing
|
|
cmdToken = GetToken( &commandPtr );
|
|
if ( cmdToken && !stricmp( cmdToken, "cpu" ) )
|
|
errCode = rc_SetCpuProfile( commandPtr );
|
|
else if ( cmdToken && !stricmp( cmdToken, "texture" ) )
|
|
errCode = rc_SetTexProfile( commandPtr );
|
|
|
|
goto cleanUp;
|
|
}
|
|
else if ( cmdToken && !stricmp( cmdToken, "SetProfileData()" ) )
|
|
{
|
|
// first arg dictates routing
|
|
cmdToken = GetToken( &commandPtr );
|
|
if ( cmdToken && !stricmp( cmdToken, "cpu" ) )
|
|
errCode = rc_SetCpuProfileData( commandPtr );
|
|
else if ( cmdToken && !stricmp( cmdToken, "texture" ) )
|
|
errCode = rc_SetTexProfileData( commandPtr );
|
|
|
|
async = true;
|
|
goto cleanUp;
|
|
}
|
|
else if ( cmdToken && !stricmp( cmdToken, "TextureList()" ) )
|
|
{
|
|
errCode = rc_TextureList( commandPtr );
|
|
goto cleanUp;
|
|
}
|
|
else if ( cmdToken && !stricmp( cmdToken, "MaterialList()" ) )
|
|
{
|
|
errCode = rc_MaterialList( commandPtr );
|
|
goto cleanUp;
|
|
}
|
|
else if ( cmdToken && !stricmp( cmdToken, "SoundList()" ) )
|
|
{
|
|
errCode = rc_SoundList( commandPtr );
|
|
goto cleanUp;
|
|
}
|
|
else if ( cmdToken && !stricmp( cmdToken, "TimeStampLog()" ) )
|
|
{
|
|
errCode = rc_TimeStampLog( commandPtr );
|
|
goto cleanUp;
|
|
}
|
|
else if ( cmdToken && !stricmp( cmdToken, "MemDump()" ) )
|
|
{
|
|
errCode = rc_MemDump( commandPtr );
|
|
async = true;
|
|
goto cleanUp;
|
|
}
|
|
else if ( cmdToken && !stricmp( cmdToken, "MapInfo()" ) )
|
|
{
|
|
errCode = rc_MapInfo( commandPtr );
|
|
goto cleanUp;
|
|
}
|
|
else if ( cmdToken && !stricmp( cmdToken, "Assert()" ) )
|
|
{
|
|
errCode = rc_Assert( commandPtr );
|
|
goto cleanUp;
|
|
}
|
|
else if ( cmdToken && !stricmp( cmdToken, "FreeMemory()" ) )
|
|
{
|
|
errCode = rc_FreeMemory( commandPtr );
|
|
async = true;
|
|
goto cleanUp;
|
|
}
|
|
else if ( cmdToken && !stricmp( cmdToken, "Disconnect()" ) )
|
|
{
|
|
// disconnect requires specialized processing
|
|
// send command status first while connection valid, then do actual disconnect
|
|
// disconnect is always assumed to be valid, can't be denied
|
|
CommandCompleted( 0 );
|
|
DoDisconnect( TRUE );
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
// unknown command
|
|
PrintToQueue( RGB( 255,0,0 ), "Unknown Command: %s\n", strNotification );
|
|
goto cleanUp;
|
|
}
|
|
|
|
cleanUp:
|
|
if ( !async )
|
|
CommandCompleted( errCode );
|
|
|
|
return ( S_OK );
|
|
}
|