2010-11-20 10:37:14 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
2010-08-07 18:22:25 +00:00
# include <new>
2010-05-29 07:25:38 +00:00
# include <base/system.h>
# include <engine/shared/protocol.h>
# include <engine/storage.h>
# include "console.h"
# include "config.h"
# include "linereader.h"
2011-04-09 06:41:31 +00:00
# include <base/math.h>
2010-05-29 07:25:38 +00:00
const char * CConsole : : CResult : : GetString ( unsigned Index )
{
if ( Index < 0 | | Index > = m_NumArgs )
return " " ;
return m_apArgs [ Index ] ;
}
int CConsole : : CResult : : GetInteger ( unsigned Index )
{
if ( Index < 0 | | Index > = m_NumArgs )
return 0 ;
return str_toint ( m_apArgs [ Index ] ) ;
}
float CConsole : : CResult : : GetFloat ( unsigned Index )
{
if ( Index < 0 | | Index > = m_NumArgs )
return 0.0f ;
return str_tofloat ( m_apArgs [ Index ] ) ;
}
// the maximum number of tokens occurs in a string of length CONSOLE_MAX_STR_LENGTH with tokens size 1 separated by single spaces
int CConsole : : ParseStart ( CResult * pResult , const char * pString , int Length )
{
char * pStr ;
int Len = sizeof ( pResult - > m_aStringStorage ) ;
if ( Length < Len )
Len = Length ;
str_copy ( pResult - > m_aStringStorage , pString , Length ) ;
pStr = pResult - > m_aStringStorage ;
// get command
2010-08-12 13:44:11 +00:00
pStr = str_skip_whitespaces ( pStr ) ;
2010-05-29 07:25:38 +00:00
pResult - > m_pCommand = pStr ;
2010-10-25 16:41:15 +00:00
pStr = str_skip_to_whitespace ( pStr ) ;
2010-05-29 07:25:38 +00:00
if ( * pStr )
{
pStr [ 0 ] = 0 ;
pStr + + ;
}
pResult - > m_pArgsStart = pStr ;
return 0 ;
}
int CConsole : : ParseArgs ( CResult * pResult , const char * pFormat )
{
char Command ;
char * pStr ;
int Optional = 0 ;
int Error = 0 ;
2010-11-07 15:29:55 +00:00
pResult - > ResetVictim ( ) ;
2010-05-29 07:25:38 +00:00
pStr = pResult - > m_pArgsStart ;
while ( 1 )
{
// fetch command
Command = * pFormat ;
pFormat + + ;
if ( ! Command )
break ;
if ( Command = = ' ? ' )
Optional = 1 ;
else
{
2010-08-12 13:44:11 +00:00
pStr = str_skip_whitespaces ( pStr ) ;
2010-05-29 07:25:38 +00:00
if ( ! ( * pStr ) ) // error, non optional command needs value
{
if ( ! Optional )
2011-02-25 22:09:19 +00:00
{
2010-05-29 07:25:38 +00:00
Error = 1 ;
2011-02-25 22:09:19 +00:00
break ;
}
2011-04-09 06:41:31 +00:00
2011-02-25 22:09:19 +00:00
while ( * ( pFormat - 1 ) )
{
if ( * ( pFormat - 1 ) = = ' v ' )
{
pResult - > SetVictim ( CResult : : VICTIM_ME ) ;
break ;
}
pFormat + + ;
}
2010-05-29 07:25:38 +00:00
break ;
}
// add token
if ( * pStr = = ' " ' )
{
char * pDst ;
pStr + + ;
pResult - > AddArgument ( pStr ) ;
pDst = pStr ; // we might have to process escape data
while ( 1 )
{
if ( pStr [ 0 ] = = ' " ' )
break ;
else if ( pStr [ 0 ] = = ' \\ ' )
{
if ( pStr [ 1 ] = = ' \\ ' )
pStr + + ; // skip due to escape
else if ( pStr [ 1 ] = = ' " ' )
pStr + + ; // skip due to escape
}
else if ( pStr [ 0 ] = = 0 )
return 1 ; // return error
* pDst = * pStr ;
pDst + + ;
pStr + + ;
}
// write null termination
* pDst = 0 ;
pStr + + ;
}
else
{
2010-11-15 17:58:44 +00:00
char * pVictim = 0 ;
2010-11-07 15:29:55 +00:00
if ( Command ! = ' v ' )
pResult - > AddArgument ( pStr ) ;
else
2010-11-15 17:58:44 +00:00
pVictim = pStr ;
2010-05-29 07:25:38 +00:00
if ( Command = = ' r ' ) // rest of the string
break ;
2010-11-07 15:29:55 +00:00
else if ( Command = = ' v ' )
pStr = str_skip_to_whitespace ( pStr ) ;
2010-05-29 07:25:38 +00:00
else if ( Command = = ' i ' ) // validate int
2010-10-25 16:41:15 +00:00
pStr = str_skip_to_whitespace ( pStr ) ;
2010-05-29 07:25:38 +00:00
else if ( Command = = ' f ' ) // validate float
2010-10-25 16:41:15 +00:00
pStr = str_skip_to_whitespace ( pStr ) ;
2010-05-29 07:25:38 +00:00
else if ( Command = = ' s ' ) // validate string
2010-10-25 16:41:15 +00:00
pStr = str_skip_to_whitespace ( pStr ) ;
2010-05-29 07:25:38 +00:00
if ( pStr [ 0 ] ! = 0 ) // check for end of string
{
pStr [ 0 ] = 0 ;
pStr + + ;
}
2011-04-09 06:41:31 +00:00
2010-11-15 17:58:44 +00:00
if ( pVictim )
pResult - > SetVictim ( pVictim ) ;
2010-05-29 07:25:38 +00:00
}
}
}
return Error ;
}
void CConsole : : RegisterPrintCallback ( FPrintCallback pfnPrintCallback , void * pUserData )
{
m_pfnPrintCallback = pfnPrintCallback ;
m_pPrintCallbackUserdata = pUserData ;
}
2010-08-17 22:06:00 +00:00
void CConsole : : Print ( int Level , const char * pFrom , const char * pStr )
2010-05-29 07:25:38 +00:00
{
2010-08-17 22:06:00 +00:00
dbg_msg ( pFrom , " %s " , pStr ) ;
2010-10-25 16:30:35 +00:00
if ( Level < = g_Config . m_ConsoleOutputLevel & & m_pfnPrintCallback )
2010-08-17 22:06:00 +00:00
{
char aBuf [ 1024 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " [%s]: %s " , pFrom , pStr ) ;
2010-10-10 22:40:07 +00:00
if ( ! m_pfnAlternativePrintCallback | | m_PrintUsed = = 0 )
2011-02-13 05:35:13 +00:00
m_pfnPrintCallback ( aBuf , m_pPrintCallbackUserdata ) ;
else
m_pfnAlternativePrintCallback ( aBuf , m_pAlternativePrintCallbackUserdata ) ;
2010-10-10 22:40:07 +00:00
}
}
2010-10-25 16:30:35 +00:00
bool CConsole : : LineIsValid ( const char * pStr )
{
if ( ! pStr | | * pStr = = 0 )
return false ;
do
{
CResult Result ;
const char * pEnd = pStr ;
const char * pNextPart = 0 ;
int InString = 0 ;
while ( * pEnd )
{
if ( * pEnd = = ' " ' )
InString ^ = 1 ;
else if ( * pEnd = = ' \\ ' ) // escape sequences
{
if ( pEnd [ 1 ] = = ' " ' )
pEnd + + ;
}
else if ( ! InString )
{
if ( * pEnd = = ' ; ' ) // command separator
{
pNextPart = pEnd + 1 ;
break ;
}
else if ( * pEnd = = ' # ' ) // comment, no need to do anything more
break ;
}
pEnd + + ;
}
if ( ParseStart ( & Result , pStr , ( pEnd - pStr ) + 1 ) ! = 0 )
return false ;
CCommand * pCommand = FindCommand ( Result . m_pCommand , m_FlagMask ) ;
if ( ! pCommand | | ParseArgs ( & Result , pCommand - > m_pParams ) )
return false ;
pStr = pNextPart ;
}
while ( pStr & & * pStr ) ;
return true ;
}
2011-02-13 05:35:13 +00:00
void CConsole : : ExecuteLineStroked ( int Stroke , const char * pStr , const int ClientLevel , const int ClientID , FPrintCallback pfnAlternativePrintCallback , void * pUserData , FPrintCallback pfnAlternativePrintResponseCallback , void * pResponseUserData )
2010-10-14 00:06:57 +00:00
{
2010-05-29 07:25:38 +00:00
while ( pStr & & * pStr )
{
2011-01-07 18:33:29 +00:00
CResult Result ;
2010-05-29 07:25:38 +00:00
const char * pEnd = pStr ;
const char * pNextPart = 0 ;
int InString = 0 ;
while ( * pEnd )
{
if ( * pEnd = = ' " ' )
InString ^ = 1 ;
else if ( * pEnd = = ' \\ ' ) // escape sequences
{
if ( pEnd [ 1 ] = = ' " ' )
pEnd + + ;
}
else if ( ! InString )
{
if ( * pEnd = = ' ; ' ) // command separator
{
pNextPart = pEnd + 1 ;
break ;
}
else if ( * pEnd = = ' # ' ) // comment, no need to do anything more
break ;
}
pEnd + + ;
}
2011-01-07 18:33:29 +00:00
if ( ParseStart ( & Result , pStr , ( pEnd - pStr ) + 1 ) ! = 0 )
2010-05-29 07:25:38 +00:00
return ;
2011-01-07 18:33:29 +00:00
CCommand * pCommand = FindCommand ( Result . m_pCommand , m_FlagMask ) ;
2010-05-29 07:25:38 +00:00
if ( pCommand )
{
int IsStrokeCommand = 0 ;
2011-01-07 18:33:29 +00:00
if ( Result . m_pCommand [ 0 ] = = ' + ' )
2010-05-29 07:25:38 +00:00
{
// insert the stroke direction token
2011-01-07 18:33:29 +00:00
Result . AddArgument ( m_paStrokeStr [ Stroke ] ) ;
2010-05-29 07:25:38 +00:00
IsStrokeCommand = 1 ;
}
if ( Stroke | | IsStrokeCommand )
{
2011-01-07 18:33:29 +00:00
if ( ParseArgs ( & Result , pCommand - > m_pParams ) )
2010-05-29 07:25:38 +00:00
{
2010-10-16 19:42:39 +00:00
RegisterAlternativePrintResponseCallback ( pfnAlternativePrintResponseCallback , pResponseUserData ) ;
2010-05-29 07:25:38 +00:00
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " Invalid arguments... Usage: %s %s " , pCommand - > m_pName , pCommand - > m_pParams ) ;
2010-10-10 22:40:07 +00:00
PrintResponse ( OUTPUT_LEVEL_STANDARD , " Console " , aBuf ) ;
2010-10-16 19:42:39 +00:00
ReleaseAlternativePrintResponseCallback ( ) ;
2010-05-29 07:25:38 +00:00
}
2010-09-06 03:22:00 +00:00
else if ( m_StoreCommands & & pCommand - > m_Flags & CFGFLAG_STORE )
{
2011-01-07 18:33:29 +00:00
m_ExecutionQueue . AddEntry ( ) ;
2010-09-06 03:22:00 +00:00
m_ExecutionQueue . m_pLast - > m_pfnCommandCallback = pCommand - > m_pfnCallback ;
m_ExecutionQueue . m_pLast - > m_pCommandUserData = pCommand - > m_pUserData ;
2011-01-07 18:33:29 +00:00
m_ExecutionQueue . m_pLast - > m_Result = Result ;
2010-09-06 03:22:00 +00:00
}
2010-05-29 07:25:38 +00:00
else
2010-09-06 03:22:00 +00:00
{
2011-01-12 09:08:17 +00:00
if ( Result . GetVictim ( ) = = CResult : : VICTIM_ME )
2011-02-13 05:35:13 +00:00
Result . SetVictim ( ClientID ) ;
2011-04-09 06:41:31 +00:00
2010-11-07 16:35:11 +00:00
if ( ( ClientLevel < pCommand - > m_Level & & ! ( pCommand - > m_Flags & CMDFLAG_HELPERCMD ) ) | | ( ClientLevel < 1 & & ( pCommand - > m_Flags & CMDFLAG_HELPERCMD ) ) )
2010-11-07 15:29:55 +00:00
{
RegisterAlternativePrintResponseCallback ( pfnAlternativePrintResponseCallback , pResponseUserData ) ;
char aBuf [ 256 ] ;
if ( pCommand - > m_Level = = 100 & & ClientLevel < 100 )
{
str_format ( aBuf , sizeof ( aBuf ) , " You can't use this command: %s " , pCommand - > m_pName ) ;
}
else
{
str_format ( aBuf , sizeof ( aBuf ) , " You have too low level to use command: %s. Your level: %d. Need level: %d " , pCommand - > m_pName , ClientLevel , pCommand - > m_Level ) ;
2011-02-13 05:35:13 +00:00
dbg_msg ( " server " , " client tried rcon command ('%s') without permisson. ClientID=%d " , pCommand - > m_pName , ClientID ) ;
2010-11-07 15:29:55 +00:00
}
PrintResponse ( OUTPUT_LEVEL_STANDARD , " Console " , aBuf ) ;
ReleaseAlternativePrintResponseCallback ( ) ;
2011-04-09 06:41:31 +00:00
}
2011-02-13 05:35:13 +00:00
else if ( ClientLevel = = 1 & & ( pCommand - > m_Flags & CMDFLAG_HELPERCMD ) & & Result . GetVictim ( ) ! = ClientID )
2010-11-07 15:29:55 +00:00
{
RegisterAlternativePrintResponseCallback ( pfnAlternativePrintResponseCallback , pResponseUserData ) ;
PrintResponse ( OUTPUT_LEVEL_STANDARD , " Console " , " As a helper you can't use commands on others. " ) ;
2011-02-13 05:35:13 +00:00
dbg_msg ( " server " , " helper tried rcon command ('%s') on others without permission. ClientID=%d " , pCommand - > m_pName , ClientID ) ;
2010-11-07 15:29:55 +00:00
ReleaseAlternativePrintResponseCallback ( ) ;
}
2011-03-17 22:07:43 +00:00
else if ( ( ! g_Config . m_SvCheats | | g_Config . m_SvRegister | | ! g_Config . m_Password [ 0 ] ) & & ( pCommand - > m_Flags & CMDFLAG_CHEAT ) )
2010-11-07 15:29:55 +00:00
{
RegisterAlternativePrintResponseCallback ( pfnAlternativePrintResponseCallback , pResponseUserData ) ;
2011-03-17 22:07:43 +00:00
PrintResponse ( OUTPUT_LEVEL_STANDARD , " Console " , " Cheats are not allowed on registered or un-passworded servers " ) ;
2011-02-13 05:35:13 +00:00
dbg_msg ( " server " , " client tried rcon cheat ('%s') with cheats off. ClientID=%d " , pCommand - > m_pName , ClientID ) ;
2010-11-07 15:29:55 +00:00
ReleaseAlternativePrintResponseCallback ( ) ;
}
2010-10-10 22:40:07 +00:00
else
{
2011-03-16 13:41:26 +00:00
if ( pCommand - > m_Flags & CMDFLAG_CHEAT )
m_Cheated = true ;
2011-01-12 09:08:17 +00:00
if ( Result . HasVictim ( ) )
2010-11-07 15:29:55 +00:00
{
2011-01-12 09:08:17 +00:00
if ( Result . GetVictim ( ) = = CResult : : VICTIM_ALL )
2010-11-07 15:29:55 +00:00
{
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( ClientOnline ( i ) & & CompareClients ( ClientLevel , i ) )
{
2011-01-12 09:08:17 +00:00
Result . SetVictim ( i ) ;
2010-11-07 15:29:55 +00:00
RegisterAlternativePrintCallback ( pfnAlternativePrintCallback , pUserData ) ;
RegisterAlternativePrintResponseCallback ( pfnAlternativePrintResponseCallback , pResponseUserData ) ;
2011-02-13 05:35:13 +00:00
pCommand - > m_pfnCallback ( & Result , pCommand - > m_pUserData , ClientID ) ;
2010-11-07 15:29:55 +00:00
ReleaseAlternativePrintResponseCallback ( ) ;
ReleaseAlternativePrintCallback ( ) ;
}
}
}
else
{
2011-01-12 09:08:17 +00:00
if ( ! ClientOnline ( Result . GetVictim ( ) ) )
2010-11-07 15:29:55 +00:00
{
RegisterAlternativePrintResponseCallback ( pfnAlternativePrintResponseCallback , pResponseUserData ) ;
PrintResponse ( OUTPUT_LEVEL_STANDARD , " Console " , " client is offline " ) ;
ReleaseAlternativePrintResponseCallback ( ) ;
}
2011-02-13 05:35:13 +00:00
else if ( ! CompareClients ( ClientLevel , Result . GetVictim ( ) ) & & ClientID ! = Result . GetVictim ( ) )
2010-11-07 15:29:55 +00:00
{
RegisterAlternativePrintResponseCallback ( pfnAlternativePrintResponseCallback , pResponseUserData ) ;
PrintResponse ( OUTPUT_LEVEL_STANDARD , " Console " , " you can not use commands on players with the same or higher level than you " ) ;
ReleaseAlternativePrintResponseCallback ( ) ;
}
else
{
RegisterAlternativePrintCallback ( pfnAlternativePrintCallback , pUserData ) ;
RegisterAlternativePrintResponseCallback ( pfnAlternativePrintResponseCallback , pResponseUserData ) ;
2011-02-13 05:35:13 +00:00
pCommand - > m_pfnCallback ( & Result , pCommand - > m_pUserData , ClientID ) ;
2010-11-07 15:29:55 +00:00
ReleaseAlternativePrintResponseCallback ( ) ;
ReleaseAlternativePrintCallback ( ) ;
}
}
}
else
{
RegisterAlternativePrintCallback ( pfnAlternativePrintCallback , pUserData ) ;
RegisterAlternativePrintResponseCallback ( pfnAlternativePrintResponseCallback , pResponseUserData ) ;
2011-02-13 05:35:13 +00:00
pCommand - > m_pfnCallback ( & Result , pCommand - > m_pUserData , ClientID ) ;
2010-11-07 15:29:55 +00:00
ReleaseAlternativePrintResponseCallback ( ) ;
ReleaseAlternativePrintCallback ( ) ;
}
2010-07-29 05:21:18 +00:00
}
}
2010-05-29 07:25:38 +00:00
}
}
2010-06-18 18:32:52 +00:00
else if ( Stroke )
2010-05-29 07:25:38 +00:00
{
2010-10-16 19:42:39 +00:00
RegisterAlternativePrintResponseCallback ( pfnAlternativePrintResponseCallback , pResponseUserData ) ;
2010-05-29 07:25:38 +00:00
char aBuf [ 256 ] ;
2011-01-07 18:33:29 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " No such command: %s. " , Result . m_pCommand ) ;
2010-10-10 22:40:07 +00:00
PrintResponse ( OUTPUT_LEVEL_STANDARD , " Console " , aBuf ) ;
2010-10-16 19:42:39 +00:00
ReleaseAlternativePrintResponseCallback ( ) ;
2010-05-29 07:25:38 +00:00
}
pStr = pNextPart ;
}
}
void CConsole : : PossibleCommands ( const char * pStr , int FlagMask , FPossibleCallback pfnCallback , void * pUser )
{
CCommand * pCommand ;
for ( pCommand = m_pFirstCommand ; pCommand ; pCommand = pCommand - > m_pNext )
{
if ( pCommand - > m_Flags & FlagMask )
{
if ( str_find_nocase ( pCommand - > m_pName , pStr ) )
pfnCallback ( pCommand - > m_pName , pUser ) ;
}
}
}
2010-06-18 18:32:52 +00:00
CConsole : : CCommand * CConsole : : FindCommand ( const char * pName , int FlagMask )
2010-05-29 07:25:38 +00:00
{
CCommand * pCommand ;
for ( pCommand = m_pFirstCommand ; pCommand ; pCommand = pCommand - > m_pNext )
{
2010-06-18 18:32:52 +00:00
if ( pCommand - > m_Flags & FlagMask )
{
if ( str_comp_nocase ( pCommand - > m_pName , pName ) = = 0 )
return pCommand ;
}
2010-05-29 07:25:38 +00:00
}
return 0x0 ;
}
2011-02-13 05:35:13 +00:00
void CConsole : : ExecuteLine ( const char * pStr , const int ClientLevel , const int ClientID , FPrintCallback pfnAlternativePrintCallback , void * pUserData , FPrintCallback pfnAlternativePrintResponseCallback , void * pResponseUserData )
2010-05-29 07:25:38 +00:00
{
2011-02-13 05:35:13 +00:00
CConsole : : ExecuteLineStroked ( 1 , pStr , ClientLevel , ClientID , pfnAlternativePrintCallback , pUserData , pfnAlternativePrintResponseCallback , pResponseUserData ) ; // press it
CConsole : : ExecuteLineStroked ( 0 , pStr , ClientLevel , ClientID , pfnAlternativePrintCallback , pUserData , pfnAlternativePrintResponseCallback , pResponseUserData ) ; // then release it
2010-05-29 07:25:38 +00:00
}
2010-11-22 08:27:13 +00:00
void CConsole : : ExecuteFile ( const char * pFilename , FPrintCallback pfnAlternativePrintCallback , void * pUserData , FPrintCallback pfnAlternativePrintResponseCallback , void * pResponseUserData , int Level )
2010-05-29 07:25:38 +00:00
{
// make sure that this isn't being executed already
for ( CExecFile * pCur = m_pFirstExec ; pCur ; pCur = pCur - > m_pPrev )
if ( str_comp ( pFilename , pCur - > m_pFilename ) = = 0 )
return ;
if ( ! m_pStorage )
m_pStorage = Kernel ( ) - > RequestInterface < IStorage > ( ) ;
if ( ! m_pStorage )
return ;
// push this one to the stack
CExecFile ThisFile ;
CExecFile * pPrev = m_pFirstExec ;
ThisFile . m_pFilename = pFilename ;
ThisFile . m_pPrev = m_pFirstExec ;
m_pFirstExec = & ThisFile ;
// exec the file
2010-10-06 21:07:35 +00:00
IOHANDLE File = m_pStorage - > OpenFile ( pFilename , IOFLAG_READ , IStorage : : TYPE_ALL ) ;
2010-05-29 07:25:38 +00:00
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
2010-05-29 07:25:38 +00:00
if ( File )
{
char * pLine ;
CLineReader lr ;
2010-10-10 22:40:07 +00:00
RegisterAlternativePrintCallback ( pfnAlternativePrintCallback , pUserData ) ;
2010-08-17 22:06:00 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " executing '%s' " , pFilename ) ;
2010-10-11 20:52:18 +00:00
PrintResponse ( IConsole : : OUTPUT_LEVEL_STANDARD , " console " , aBuf ) ;
2010-05-29 07:25:38 +00:00
lr . Init ( File ) ;
2010-10-10 22:40:07 +00:00
ReleaseAlternativePrintCallback ( ) ;
2010-05-29 07:25:38 +00:00
while ( ( pLine = lr . Get ( ) ) )
2010-11-22 08:27:13 +00:00
ExecuteLine ( pLine , Level , - 1 , pfnAlternativePrintCallback , pUserData , pfnAlternativePrintResponseCallback , pResponseUserData ) ;
2010-05-29 07:25:38 +00:00
io_close ( File ) ;
}
else
2010-08-17 22:06:00 +00:00
{
2010-10-10 22:40:07 +00:00
RegisterAlternativePrintCallback ( pfnAlternativePrintCallback , pUserData ) ;
2010-08-17 22:06:00 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " failed to open '%s' " , pFilename ) ;
2010-10-11 20:52:18 +00:00
PrintResponse ( IConsole : : OUTPUT_LEVEL_STANDARD , " console " , aBuf ) ;
2010-10-10 22:40:07 +00:00
ReleaseAlternativePrintCallback ( ) ;
2010-08-17 22:06:00 +00:00
}
2010-05-29 07:25:38 +00:00
m_pFirstExec = pPrev ;
}
2011-02-13 05:35:13 +00:00
void CConsole : : Con_Echo ( IResult * pResult , void * pUserData , int ClientID )
2010-05-29 07:25:38 +00:00
{
2011-04-09 06:41:31 +00:00
( ( CConsole * ) pUserData ) - > PrintResponse ( IConsole : : OUTPUT_LEVEL_STANDARD , " Console " , pResult - > GetString ( 0 ) ) ;
2010-05-29 07:25:38 +00:00
}
2011-02-13 05:35:13 +00:00
void CConsole : : Con_Exec ( IResult * pResult , void * pUserData , int ClientID )
2010-05-29 07:25:38 +00:00
{
2010-10-11 20:52:18 +00:00
CConsole * pSelf = ( CConsole * ) pUserData ;
2010-10-16 19:42:39 +00:00
pSelf - > ExecuteFile ( pResult - > GetString ( 0 ) , pSelf - > m_pfnAlternativePrintCallback , pSelf - > m_pAlternativePrintCallbackUserdata , pSelf - > m_pfnAlternativePrintResponseCallback , pSelf - > m_pAlternativePrintResponseCallbackUserdata ) ;
2010-05-29 07:25:38 +00:00
}
struct CIntVariableData
{
IConsole * m_pConsole ;
2010-12-07 18:27:04 +00:00
const char * m_Name ;
2010-05-29 07:25:38 +00:00
int * m_pVariable ;
int m_Min ;
int m_Max ;
} ;
struct CStrVariableData
{
IConsole * m_pConsole ;
2010-12-07 18:27:04 +00:00
const char * m_Name ;
2010-05-29 07:25:38 +00:00
char * m_pStr ;
int m_MaxSize ;
} ;
2011-02-13 05:35:13 +00:00
static void IntVariableCommand ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2010-05-29 07:25:38 +00:00
{
CIntVariableData * pData = ( CIntVariableData * ) pUserData ;
if ( pResult - > NumArguments ( ) )
{
int Val = pResult - > GetInteger ( 0 ) ;
// do clamping
if ( pData - > m_Min ! = pData - > m_Max )
{
if ( Val < pData - > m_Min )
Val = pData - > m_Min ;
if ( pData - > m_Max ! = 0 & & Val > pData - > m_Max )
Val = pData - > m_Max ;
}
* ( pData - > m_pVariable ) = Val ;
2010-10-11 21:05:52 +00:00
char aBuf [ 1024 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " %s changed to %d " , pData - > m_Name , * ( pData - > m_pVariable ) ) ;
pData - > m_pConsole - > PrintResponse ( IConsole : : OUTPUT_LEVEL_STANDARD , " Console " , aBuf ) ;
2010-05-29 07:25:38 +00:00
}
else
{
char aBuf [ 1024 ] ;
2010-10-11 21:05:52 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %s is %d " , pData - > m_Name , * ( pData - > m_pVariable ) ) ;
2010-10-10 22:40:07 +00:00
pData - > m_pConsole - > PrintResponse ( IConsole : : OUTPUT_LEVEL_STANDARD , " Console " , aBuf ) ;
2010-05-29 07:25:38 +00:00
}
}
2011-02-13 05:35:13 +00:00
static void StrVariableCommand ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2010-05-29 07:25:38 +00:00
{
CStrVariableData * pData = ( CStrVariableData * ) pUserData ;
if ( pResult - > NumArguments ( ) )
2010-09-30 22:55:16 +00:00
{
const char * pString = pResult - > GetString ( 0 ) ;
if ( ! str_utf8_check ( pString ) )
{
char Temp [ 4 ] ;
int Length = 0 ;
while ( * pString )
{
int Size = str_utf8_encode ( Temp , static_cast < const unsigned char > ( * pString + + ) ) ;
if ( Length + Size < pData - > m_MaxSize )
{
mem_copy ( pData - > m_pStr + Length , & Temp , Size ) ;
Length + = Size ;
}
else
break ;
}
pData - > m_pStr [ Length ] = 0 ;
}
else
str_copy ( pData - > m_pStr , pString , pData - > m_MaxSize ) ;
}
2010-05-29 07:25:38 +00:00
else
{
char aBuf [ 1024 ] ;
2010-10-11 21:05:52 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %s is '%s' " , pData - > m_Name , pData - > m_pStr ) ;
2010-10-10 22:40:07 +00:00
pData - > m_pConsole - > PrintResponse ( IConsole : : OUTPUT_LEVEL_STANDARD , " Console " , aBuf ) ;
2010-05-29 07:25:38 +00:00
}
}
2010-06-18 18:32:52 +00:00
CConsole : : CConsole ( int FlagMask )
2010-05-29 07:25:38 +00:00
{
2010-06-18 18:32:52 +00:00
m_FlagMask = FlagMask ;
2010-08-07 18:22:25 +00:00
m_StoreCommands = true ;
m_paStrokeStr [ 0 ] = " 0 " ;
m_paStrokeStr [ 1 ] = " 1 " ;
m_ExecutionQueue . Reset ( ) ;
2010-05-29 07:25:38 +00:00
m_pFirstCommand = 0 ;
m_pFirstExec = 0 ;
2010-11-22 07:55:19 +00:00
for ( int i = 0 ; i < 5 ; + + i )
{
m_aCommandCount [ i ] = 0 ;
}
2010-05-29 07:25:38 +00:00
m_pPrintCallbackUserdata = 0 ;
m_pfnPrintCallback = 0 ;
2010-10-10 22:40:07 +00:00
m_pAlternativePrintCallbackUserdata = 0 ;
m_pfnAlternativePrintCallback = 0 ;
m_PrintUsed = 0 ;
m_pPrintResponseCallbackUserdata = 0 ;
m_pfnPrintResponseCallback = 0 ;
m_pAlternativePrintResponseCallbackUserdata = 0 ;
m_pfnAlternativePrintResponseCallback = 0 ;
m_PrintResponseUsed = 0 ;
2011-02-13 05:35:13 +00:00
2010-11-07 15:29:55 +00:00
m_pfnClientOnlineCallback = 0 ;
m_pfnCompareClientsCallback = 0 ;
m_pClientOnlineUserdata = 0 ;
m_pCompareClientsUserdata = 0 ;
2010-05-29 07:25:38 +00:00
m_pStorage = 0 ;
// register some basic commands
2011-04-09 06:41:31 +00:00
Register ( " echo " , " r " , CFGFLAG_SERVER | CFGFLAG_CLIENT , Con_Echo , this , " Echo the text " , IConsole : : CONSOLELEVEL_ADMIN ) ;
Register ( " exec " , " r " , CFGFLAG_SERVER | CFGFLAG_CLIENT , Con_Exec , this , " Execute the specified file " , IConsole : : CONSOLELEVEL_ADMIN ) ;
2010-05-29 07:25:38 +00:00
// TODO: this should disappear
2010-08-30 23:45:30 +00:00
# define MACRO_CONFIG_INT(Name,ScriptName,Def,Min,Max,Flags,Desc,Level) \
2010-05-29 07:25:38 +00:00
{ \
2010-10-11 21:05:52 +00:00
static CIntVariableData Data = { this , # ScriptName , & g_Config . m_ # # Name , Min , Max } ; \
2010-08-30 23:45:30 +00:00
Register ( # ScriptName , " ?i " , Flags , IntVariableCommand , & Data , Desc , Level ) ; \
2010-05-29 07:25:38 +00:00
}
2010-08-30 23:45:30 +00:00
# define MACRO_CONFIG_STR(Name,ScriptName,Len,Def,Flags,Desc,Level) \
2010-05-29 07:25:38 +00:00
{ \
2010-10-11 21:05:52 +00:00
static CStrVariableData Data = { this , # ScriptName , g_Config . m_ # # Name , Len } ; \
2010-08-30 23:45:30 +00:00
Register ( # ScriptName , " ?r " , Flags , StrVariableCommand , & Data , Desc , Level ) ; \
2010-05-29 07:25:38 +00:00
}
# include "config_variables.h"
# undef MACRO_CONFIG_INT
# undef MACRO_CONFIG_STR
2011-04-09 06:41:31 +00:00
2011-03-16 13:41:26 +00:00
m_Cheated = false ;
2010-05-29 07:25:38 +00:00
}
void CConsole : : ParseArguments ( int NumArgs , const char * * ppArguments )
{
for ( int i = 0 ; i < NumArgs ; i + + )
{
// check for scripts to execute
2010-10-31 16:53:00 +00:00
if ( ppArguments [ i ] [ 0 ] = = ' - ' & & ppArguments [ i ] [ 1 ] = = ' f ' & & ppArguments [ i ] [ 2 ] = = 0 )
2010-05-29 07:25:38 +00:00
{
2010-10-31 16:53:00 +00:00
if ( NumArgs - i > 1 )
2011-04-09 06:41:31 +00:00
ExecuteFile ( ppArguments [ i + 1 ] , 0 , 0 , 0 , 0 , IConsole : : CONSOLELEVEL_CONFIG ) ;
2010-05-29 07:25:38 +00:00
i + + ;
}
2010-10-31 16:53:00 +00:00
else if ( ! str_comp ( " -s " , ppArguments [ i ] ) | | ! str_comp ( " --silent " , ppArguments [ i ] ) )
{
// skip silent param
continue ;
}
2010-05-29 07:25:38 +00:00
else
{
// search arguments for overrides
2011-04-09 06:41:31 +00:00
ExecuteLine ( ppArguments [ i ] , IConsole : : CONSOLELEVEL_CONFIG , - 1 ) ;
2010-05-29 07:25:38 +00:00
}
}
}
void CConsole : : Register ( const char * pName , const char * pParams ,
2010-07-29 05:21:18 +00:00
int Flags , FCommandCallback pfnFunc , void * pUser , const char * pHelp , const int Level )
2010-05-29 07:25:38 +00:00
{
CCommand * pCommand = ( CCommand * ) mem_alloc ( sizeof ( CCommand ) , sizeof ( void * ) ) ;
pCommand - > m_pfnCallback = pfnFunc ;
pCommand - > m_pUserData = pUser ;
pCommand - > m_pHelp = pHelp ;
pCommand - > m_pName = pName ;
pCommand - > m_pParams = pParams ;
pCommand - > m_Flags = Flags ;
2010-07-29 05:21:18 +00:00
pCommand - > m_Level = Level ;
2010-05-29 07:25:38 +00:00
2011-01-06 03:46:10 +00:00
2010-05-29 07:25:38 +00:00
pCommand - > m_pNext = m_pFirstCommand ;
m_pFirstCommand = pCommand ;
2010-11-22 07:55:19 +00:00
m_aCommandCount [ pCommand - > m_Level ] + + ;
2010-05-29 07:25:38 +00:00
}
2011-02-13 05:35:13 +00:00
void CConsole : : Con_Chain ( IResult * pResult , void * pUserData , int ClientID )
2010-05-29 07:25:38 +00:00
{
CChain * pInfo = ( CChain * ) pUserData ;
pInfo - > m_pfnChainCallback ( pResult , pInfo - > m_pUserData , pInfo - > m_pfnCallback , pInfo - > m_pCallbackUserData ) ;
}
void CConsole : : Chain ( const char * pName , FChainCommandCallback pfnChainFunc , void * pUser )
{
2010-06-18 18:32:52 +00:00
CCommand * pCommand = FindCommand ( pName , m_FlagMask ) ;
2010-05-29 07:25:38 +00:00
if ( ! pCommand )
{
2010-10-10 22:40:07 +00:00
RegisterAlternativePrintCallback ( 0 , 0 ) ;
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " failed to chain '%s' " , pName ) ;
Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " console " , aBuf ) ;
2010-10-10 22:40:07 +00:00
ReleaseAlternativePrintCallback ( ) ;
2010-05-29 07:25:38 +00:00
return ;
}
CChain * pChainInfo = ( CChain * ) mem_alloc ( sizeof ( CChain ) , sizeof ( void * ) ) ;
// store info
pChainInfo - > m_pfnChainCallback = pfnChainFunc ;
pChainInfo - > m_pUserData = pUser ;
pChainInfo - > m_pfnCallback = pCommand - > m_pfnCallback ;
pChainInfo - > m_pCallbackUserData = pCommand - > m_pUserData ;
// chain
pCommand - > m_pfnCallback = Con_Chain ;
pCommand - > m_pUserData = pChainInfo ;
}
2011-02-13 05:35:13 +00:00
void CConsole : : StoreCommands ( bool Store , int ClientID )
2010-08-07 18:22:25 +00:00
{
if ( ! Store )
{
2011-01-07 18:33:29 +00:00
for ( CExecutionQueue : : CQueueEntry * pEntry = m_ExecutionQueue . m_pFirst ; pEntry ; pEntry = pEntry - > m_pNext )
2011-02-13 05:35:13 +00:00
pEntry - > m_pfnCommandCallback ( & pEntry - > m_Result , pEntry - > m_pCommandUserData , ClientID ) ;
2010-08-07 18:22:25 +00:00
m_ExecutionQueue . Reset ( ) ;
}
m_StoreCommands = Store ;
}
2010-05-29 07:25:38 +00:00
2010-06-18 18:32:52 +00:00
IConsole : : CCommandInfo * CConsole : : GetCommandInfo ( const char * pName , int FlagMask )
2010-05-29 07:25:38 +00:00
{
2010-06-18 18:32:52 +00:00
return FindCommand ( pName , FlagMask ) ;
2010-05-29 07:25:38 +00:00
}
2010-06-18 18:32:52 +00:00
extern IConsole * CreateConsole ( int FlagMask ) { return new CConsole ( FlagMask ) ; }
2011-01-06 03:46:10 +00:00
2011-04-09 06:41:31 +00:00
// DDRace
2011-01-06 03:46:10 +00:00
void CConsole : : RegisterAlternativePrintCallback ( FPrintCallback pfnAlternativePrintCallback , void * pAlternativeUserData )
{
2011-04-09 06:41:31 +00:00
while ( m_pfnAlternativePrintCallback ! = pfnAlternativePrintCallback & & m_PrintUsed )
; // wait for other threads to finish their commands
// TODO:DDRace:heinrich5991: implement this with LOCK
2011-01-06 03:46:10 +00:00
m_pfnAlternativePrintCallback = pfnAlternativePrintCallback ;
m_pAlternativePrintCallbackUserdata = pAlternativeUserData ;
2011-04-09 06:41:31 +00:00
m_PrintUsed + + ;
2011-01-06 03:46:10 +00:00
}
void CConsole : : ReleaseAlternativePrintCallback ( )
{
2011-04-09 06:41:31 +00:00
m_PrintUsed - - ;
2011-01-06 03:46:10 +00:00
}
void CConsole : : RegisterClientOnlineCallback ( FClientOnlineCallback pfnCallback , void * pUserData )
{
m_pfnClientOnlineCallback = pfnCallback ;
m_pClientOnlineUserdata = pUserData ;
}
void CConsole : : RegisterCompareClientsCallback ( FCompareClientsCallback pfnCallback , void * pUserData )
{
m_pfnCompareClientsCallback = pfnCallback ;
m_pCompareClientsUserdata = pUserData ;
}
2011-02-13 05:35:13 +00:00
bool CConsole : : ClientOnline ( int ClientID )
2011-01-06 03:46:10 +00:00
{
if ( ! m_pfnClientOnlineCallback )
return true ;
2011-04-09 06:41:31 +00:00
2011-02-13 05:35:13 +00:00
return m_pfnClientOnlineCallback ( ClientID , m_pClientOnlineUserdata ) ;
2011-01-06 03:46:10 +00:00
}
2011-02-13 05:35:13 +00:00
bool CConsole : : CompareClients ( int ClientID , int Victim )
2011-01-06 03:46:10 +00:00
{
if ( ! m_pfnCompareClientsCallback )
return true ;
2011-04-09 06:41:31 +00:00
return m_pfnCompareClientsCallback ( ClientID , Victim , m_pCompareClientsUserdata ) ;
2011-01-06 03:46:10 +00:00
}
void CConsole : : RegisterPrintResponseCallback ( FPrintCallback pfnPrintResponseCallback , void * pUserData )
{
m_pfnPrintResponseCallback = pfnPrintResponseCallback ;
m_pPrintResponseCallbackUserdata = pUserData ;
}
void CConsole : : RegisterAlternativePrintResponseCallback ( FPrintCallback pfnAlternativePrintResponseCallback , void * pAlternativeUserData )
{
2011-04-09 06:41:31 +00:00
while ( m_pfnAlternativePrintResponseCallback ! = pfnAlternativePrintResponseCallback & & m_PrintResponseUsed )
; // wait for other threads to finish their commands
// TODO:DDRace:heinrich5991: implement this with LOCK
2011-01-06 03:46:10 +00:00
m_pfnAlternativePrintResponseCallback = pfnAlternativePrintResponseCallback ;
m_pAlternativePrintResponseCallbackUserdata = pAlternativeUserData ;
2011-04-09 06:41:31 +00:00
m_PrintResponseUsed + + ;
2011-01-06 03:46:10 +00:00
}
void CConsole : : ReleaseAlternativePrintResponseCallback ( )
{
m_PrintResponseUsed - - ;
}
void CConsole : : PrintResponse ( int Level , const char * pFrom , const char * pStr )
{
dbg_msg ( pFrom , " %s " , pStr ) ;
if ( Level < = g_Config . m_ConsoleOutputLevel & & m_pfnPrintResponseCallback )
{
char aBuf [ 1024 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " [%s]: %s " , pFrom , pStr ) ;
if ( ! m_pfnAlternativePrintResponseCallback | | m_PrintResponseUsed = = 0 )
2011-04-09 06:41:31 +00:00
m_pfnPrintResponseCallback ( aBuf , m_pPrintResponseCallbackUserdata ) ;
2011-01-06 03:46:10 +00:00
else
2011-04-09 06:41:31 +00:00
m_pfnAlternativePrintResponseCallback ( aBuf , m_pAlternativePrintResponseCallbackUserdata ) ;
2011-01-06 03:46:10 +00:00
}
}
2011-01-09 14:38:26 +00:00
void CConsole : : List ( int Level , int Flags )
2011-01-06 03:46:10 +00:00
{
2011-01-09 14:38:26 +00:00
if ( Level < 0 )
Level = 0 ;
if ( Level > 4 )
Level = 4 ;
2011-01-06 03:46:10 +00:00
switch ( Level )
{
case 4 : PrintResponse ( IConsole : : OUTPUT_LEVEL_STANDARD , " console " , " command cmdlist is not allowed for config files " ) ; return ;
case 3 : PrintResponse ( IConsole : : OUTPUT_LEVEL_STANDARD , " console " , " === cmdlist for admins === " ) ; break ;
case 2 : PrintResponse ( IConsole : : OUTPUT_LEVEL_STANDARD , " console " , " === cmdlist for mods === " ) ; break ;
case 1 : PrintResponse ( IConsole : : OUTPUT_LEVEL_STANDARD , " console " , " === cmdlist for helpers === " ) ; break ;
default : PrintResponse ( IConsole : : OUTPUT_LEVEL_STANDARD , " console " , " === cmdlist === " ) ; break ;
}
2011-04-09 06:41:31 +00:00
2011-01-06 03:46:10 +00:00
char aBuf [ 50 + 1 ] = { 0 } ;
CCommand * pCommand = m_pFirstCommand ;
unsigned Length = 0 ;
2011-04-09 06:41:31 +00:00
2011-01-06 03:46:10 +00:00
while ( pCommand )
{
if ( str_comp_num ( pCommand - > m_pName , " sv_ " , 3 ) & & str_comp_num ( pCommand - > m_pName , " dbg_ " , 4 ) ) // ignore configs and debug commands
{
if ( ( pCommand - > m_Flags & Flags ) = = Flags & & ( pCommand - > m_Level = = Level | | ( Level = = 1 & & ( pCommand - > m_Flags & CMDFLAG_HELPERCMD ) ) ) )
{
unsigned CommandLength = str_length ( pCommand - > m_pName ) ;
if ( Length + CommandLength + 2 > = sizeof ( aBuf ) | | aBuf [ 0 ] = = 0 )
{
if ( aBuf [ 0 ] )
PrintResponse ( IConsole : : OUTPUT_LEVEL_STANDARD , " console " , aBuf ) ;
aBuf [ 0 ] = 0 ;
Length = CommandLength ;
str_copy ( aBuf , pCommand - > m_pName , sizeof ( aBuf ) ) ;
}
else
{
2011-01-09 14:38:26 +00:00
str_append ( aBuf , " , " , sizeof ( aBuf ) ) ;
str_append ( aBuf , pCommand - > m_pName , sizeof ( aBuf ) ) ;
2011-01-06 03:46:10 +00:00
Length + = CommandLength + 2 ;
}
}
}
pCommand = pCommand - > m_pNext ;
}
2011-04-09 06:41:31 +00:00
2011-01-06 03:46:10 +00:00
if ( aBuf [ 0 ] )
PrintResponse ( IConsole : : OUTPUT_LEVEL_STANDARD , " Console " , aBuf ) ;
switch ( Level )
{
case 3 : PrintResponse ( IConsole : : OUTPUT_LEVEL_STANDARD , " console " , " see 'cmdlist 0,1,2' for more commands, which don't require admin rights " ) ; break ;
case 2 : PrintResponse ( IConsole : : OUTPUT_LEVEL_STANDARD , " console " , " see 'cmdlist 0,1' for more commands, which don't require mod rights " ) ; break ;
case 1 : PrintResponse ( IConsole : : OUTPUT_LEVEL_STANDARD , " console " , " see 'cmdlist 0' for more commands, which don't require helper rights " ) ; break ;
default : break ;
}
}
2011-02-13 05:35:13 +00:00
int CConsole : : CResult : : GetVictim ( )
{
return m_Victim ;
}
void CConsole : : CResult : : ResetVictim ( )
{
m_Victim = VICTIM_NONE ;
}
bool CConsole : : CResult : : HasVictim ( )
{
return m_Victim ! = VICTIM_NONE ;
}
void CConsole : : CResult : : SetVictim ( int Victim )
{
2011-02-25 22:09:19 +00:00
m_Victim = clamp < int > ( Victim , VICTIM_NONE , MAX_CLIENTS - 1 ) ;
2011-02-13 05:35:13 +00:00
}
void CConsole : : CResult : : SetVictim ( const char * pVictim )
{
if ( ! str_comp ( pVictim , " me " ) )
m_Victim = VICTIM_ME ;
else if ( ! str_comp ( pVictim , " all " ) )
m_Victim = VICTIM_ALL ;
else
m_Victim = clamp < int > ( str_toint ( pVictim ) , 0 , MAX_CLIENTS - 1 ) ;
}