2017-01-19 16:23:59 -05:00
# include "STDInclude.hpp"
namespace Components
{
std : : mutex Logger : : MessageMutex ;
std : : vector < std : : string > Logger : : MessageQueue ;
std : : vector < Network : : Address > Logger : : LoggingAddresses [ 2 ] ;
void ( * Logger : : PipeCallback ) ( std : : string ) = nullptr ;
bool Logger : : IsConsoleReady ( )
{
2017-02-10 03:50:08 -05:00
return ( IsWindow ( Console : : GetWindow ( ) ) ! = FALSE | | ( Dedicated : : IsEnabled ( ) & & ! Flags : : HasFlag ( " console " ) ) ) ;
2017-01-19 16:23:59 -05:00
}
void Logger : : PrintStub ( int channel , const char * message , . . . )
{
return Logger : : MessagePrint ( channel , Logger : : Format ( & message ) ) ;
}
void Logger : : Print ( const char * message , . . . )
{
return Logger : : MessagePrint ( 0 , Logger : : Format ( & message ) ) ;
}
void Logger : : Print ( int channel , const char * message , . . . )
{
return Logger : : MessagePrint ( channel , Logger : : Format ( & message ) ) ;
}
void Logger : : MessagePrint ( int channel , std : : string message )
{
2017-07-03 09:40:32 -04:00
if ( Flags : : HasFlag ( " stdout " ) | | Loader : : IsPerformingUnitTests ( ) )
2017-01-19 16:23:59 -05:00
{
printf ( " %s " , message . data ( ) ) ;
fflush ( stdout ) ;
return ;
}
if ( ! Logger : : IsConsoleReady ( ) )
{
OutputDebugStringA ( message . data ( ) ) ;
}
if ( ! Game : : Sys_IsMainThread ( ) )
{
Logger : : EnqueueMessage ( message ) ;
}
else
{
Game : : Com_PrintMessage ( channel , message . data ( ) , 0 ) ;
}
}
void Logger : : ErrorPrint ( int error , std : : string message )
{
2017-03-18 10:19:31 -04:00
# ifdef DEBUG
if ( IsDebuggerPresent ( ) ) __debugbreak ( ) ;
# endif
2017-01-19 16:23:59 -05:00
return Game : : Com_Error ( error , " %s " , message . data ( ) ) ;
}
void Logger : : Error ( int error , const char * message , . . . )
{
return Logger : : ErrorPrint ( error , Logger : : Format ( & message ) ) ;
}
void Logger : : Error ( const char * message , . . . )
{
return Logger : : ErrorPrint ( 0 , Logger : : Format ( & message ) ) ;
}
void Logger : : SoftError ( const char * message , . . . )
{
return Logger : : ErrorPrint ( 2 , Logger : : Format ( & message ) ) ;
}
std : : string Logger : : Format ( const char * * message )
{
2017-04-21 14:48:31 -04:00
const size_t bufferSize = 0x10000 ;
Utils : : Memory : : Allocator allocator ;
char * buffer = allocator . allocateArray < char > ( bufferSize ) ;
2017-01-19 16:23:59 -05:00
va_list ap = reinterpret_cast < char * > ( const_cast < char * * > ( & message [ 1 ] ) ) ;
//va_start(ap, *message);
2017-04-21 14:48:31 -04:00
_vsnprintf_s ( buffer , bufferSize , bufferSize , * message , ap ) ;
2017-01-19 16:23:59 -05:00
va_end ( ap ) ;
return buffer ;
}
void Logger : : Flush ( )
{
// if (!Game::Sys_IsMainThread())
// {
// while (!Logger::MessageQueue.empty())
// {
// std::this_thread::sleep_for(10ms);
// }
// }
// else
{
Logger : : Frame ( ) ;
}
}
void Logger : : Frame ( )
{
std : : lock_guard < std : : mutex > _ ( Logger : : MessageMutex ) ;
for ( unsigned int i = 0 ; i < Logger : : MessageQueue . size ( ) ; + + i )
{
Game : : Com_PrintMessage ( 0 , Logger : : MessageQueue [ i ] . data ( ) , 0 ) ;
if ( ! Logger : : IsConsoleReady ( ) )
{
OutputDebugStringA ( Logger : : MessageQueue [ i ] . data ( ) ) ;
}
}
Logger : : MessageQueue . clear ( ) ;
}
void Logger : : PipeOutput ( void ( * callback ) ( std : : string ) )
{
Logger : : PipeCallback = callback ;
}
void Logger : : PrintMessagePipe ( const char * data )
{
if ( Logger : : PipeCallback )
{
Logger : : PipeCallback ( data ) ;
}
}
void Logger : : NetworkLog ( const char * data , bool gLog )
{
if ( ! data ) return ;
std : : string buffer ( data ) ;
for ( auto & addr : Logger : : LoggingAddresses [ gLog & 1 ] )
{
Network : : SendCommand ( addr , " print " , buffer ) ;
}
}
__declspec ( naked ) void Logger : : GameLogStub ( )
{
__asm
{
2017-02-01 07:44:25 -05:00
pushad
2017-01-19 16:23:59 -05:00
push 1
2017-02-01 07:44:25 -05:00
push [ esp + 28 h ]
2017-01-19 16:23:59 -05:00
call Logger : : NetworkLog
add esp , 8 h
2017-02-01 07:44:25 -05:00
popad
push 4576 C0h
retn
2017-01-19 16:23:59 -05:00
}
}
__declspec ( naked ) void Logger : : PrintMessageStub ( )
{
__asm
{
mov eax , Logger : : PipeCallback
test eax , eax
jz returnPrint
2017-02-01 07:44:25 -05:00
pushad
push [ esp + 28 h ]
2017-01-19 16:23:59 -05:00
call Logger : : PrintMessagePipe
add esp , 4 h
2017-02-01 07:44:25 -05:00
popad
2017-01-19 16:23:59 -05:00
retn
returnPrint :
2017-02-01 07:44:25 -05:00
pushad
2017-01-19 16:23:59 -05:00
push 0
2017-02-01 07:44:25 -05:00
push [ esp + 2 Ch ]
2017-01-19 16:23:59 -05:00
call Logger : : NetworkLog
add esp , 8 h
2017-02-01 07:44:25 -05:00
popad
2017-01-19 16:23:59 -05:00
push esi
mov esi , [ esp + 0 Ch ]
2017-02-01 07:44:25 -05:00
push 4 AA835h
retn
2017-01-19 16:23:59 -05:00
}
}
void Logger : : EnqueueMessage ( std : : string message )
{
Logger : : MessageMutex . lock ( ) ;
Logger : : MessageQueue . push_back ( message ) ;
Logger : : MessageMutex . unlock ( ) ;
}
2017-02-24 19:17:11 -05:00
void Logger : : RedirectOSPath ( const char * file , char * folder )
{
if ( Dvar : : Var ( " g_log " ) . get < std : : string > ( ) = = file )
{
if ( folder ! = " userraw " s )
{
2017-03-18 12:26:35 -04:00
if ( Dvar : : Var ( " iw4x_onelog " ) . get < bool > ( ) )
2017-02-24 19:17:11 -05:00
{
strcpy_s ( folder , 256 , " userraw " ) ;
}
}
}
}
__declspec ( naked ) void Logger : : BuildOSPathStub ( )
{
__asm
{
pushad
push [ esp + 28 h ]
push [ esp + 30 h ]
call Logger : : RedirectOSPath
add esp , 8 h
popad
mov eax , [ esp + 8 h ]
push ebp
push esi
mov esi , [ esp + 0 Ch ]
push 64213F h
retn
}
}
2017-01-19 16:23:59 -05:00
Logger : : Logger ( )
{
2017-02-24 19:17:11 -05:00
Dvar : : Register < bool > ( " iw4x_onelog " , false , Game : : dvar_flag : : DVAR_FLAG_LATCHED | Game : : dvar_flag : : DVAR_FLAG_SAVED , " Only write the game log to the 'userraw' OS folder " ) ;
Utils : : Hook ( 0x642139 , Logger : : BuildOSPathStub , HOOK_JUMP ) . install ( ) - > quick ( ) ;
2017-01-19 16:23:59 -05:00
Logger : : PipeOutput ( nullptr ) ;
2017-05-31 09:45:12 -04:00
Scheduler : : OnFrame ( Logger : : Frame ) ;
2017-01-19 16:23:59 -05:00
Utils : : Hook ( 0x4B0218 , Logger : : GameLogStub , HOOK_CALL ) . install ( ) - > quick ( ) ;
Utils : : Hook ( Game : : Com_PrintMessage , Logger : : PrintMessageStub , HOOK_JUMP ) . install ( ) - > quick ( ) ;
2017-07-03 09:40:32 -04:00
if ( Loader : : IsPerformingUnitTests ( ) )
2017-01-19 16:23:59 -05:00
{
Utils : : Hook ( Game : : Com_Printf , Logger : : PrintStub , HOOK_JUMP ) . install ( ) - > quick ( ) ;
}
2017-06-14 06:06:04 -04:00
Dvar : : OnInit ( [ ] ( )
2017-01-19 16:23:59 -05:00
{
2017-06-14 06:06:04 -04:00
Command : : AddSV ( " log_add " , [ ] ( Command : : Params * params )
2017-01-19 16:23:59 -05:00
{
if ( params - > length ( ) < 2 ) return ;
Network : : Address addr ( params - > get ( 1 ) ) ;
if ( std : : find ( Logger : : LoggingAddresses [ 0 ] . begin ( ) , Logger : : LoggingAddresses [ 0 ] . end ( ) , addr ) = = Logger : : LoggingAddresses [ 0 ] . end ( ) )
{
Logger : : LoggingAddresses [ 0 ] . push_back ( addr ) ;
}
} ) ;
2017-06-14 06:06:04 -04:00
Command : : AddSV ( " log_del " , [ ] ( Command : : Params * params )
2017-01-19 16:23:59 -05:00
{
if ( params - > length ( ) < 2 ) return ;
int num = atoi ( params - > get ( 1 ) ) ;
if ( Utils : : String : : VA ( " %i " , num ) = = std : : string ( params - > get ( 1 ) ) & & static_cast < unsigned int > ( num ) < Logger : : LoggingAddresses [ 0 ] . size ( ) )
{
auto addr = Logger : : LoggingAddresses [ 0 ] . begin ( ) + num ;
Logger : : Print ( " Address %s removed \n " , addr - > getCString ( ) ) ;
Logger : : LoggingAddresses [ 0 ] . erase ( addr ) ;
}
else
{
Network : : Address addr ( params - > get ( 1 ) ) ;
auto i = std : : find ( Logger : : LoggingAddresses [ 0 ] . begin ( ) , Logger : : LoggingAddresses [ 0 ] . end ( ) , addr ) ;
if ( i ! = Logger : : LoggingAddresses [ 0 ] . end ( ) )
{
Logger : : LoggingAddresses [ 0 ] . erase ( i ) ;
Logger : : Print ( " Address %s removed \n " , addr . getCString ( ) ) ;
}
else
{
Logger : : Print ( " Address %s not found! \n " , addr . getCString ( ) ) ;
}
}
} ) ;
2017-06-14 06:06:04 -04:00
Command : : AddSV ( " log_list " , [ ] ( Command : : Params * )
2017-01-19 16:23:59 -05:00
{
Logger : : Print ( " # ID: Address \n " ) ;
Logger : : Print ( " ------------- \n " ) ;
for ( unsigned int i = 0 ; i < Logger : : LoggingAddresses [ 0 ] . size ( ) ; + + i )
{
Logger : : Print ( " #%03d: %5s \n " , i , Logger : : LoggingAddresses [ 0 ] [ i ] . getCString ( ) ) ;
}
} ) ;
2017-06-14 06:06:04 -04:00
Command : : AddSV ( " g_log_add " , [ ] ( Command : : Params * params )
2017-01-19 16:23:59 -05:00
{
if ( params - > length ( ) < 2 ) return ;
Network : : Address addr ( params - > get ( 1 ) ) ;
if ( std : : find ( Logger : : LoggingAddresses [ 1 ] . begin ( ) , Logger : : LoggingAddresses [ 1 ] . end ( ) , addr ) = = Logger : : LoggingAddresses [ 1 ] . end ( ) )
{
Logger : : LoggingAddresses [ 1 ] . push_back ( addr ) ;
}
} ) ;
2017-06-14 06:06:04 -04:00
Command : : AddSV ( " g_log_del " , [ ] ( Command : : Params * params )
2017-01-19 16:23:59 -05:00
{
if ( params - > length ( ) < 2 ) return ;
int num = atoi ( params - > get ( 1 ) ) ;
if ( Utils : : String : : VA ( " %i " , num ) = = std : : string ( params - > get ( 1 ) ) & & static_cast < unsigned int > ( num ) < Logger : : LoggingAddresses [ 1 ] . size ( ) )
{
auto addr = Logger : : LoggingAddresses [ 1 ] . begin ( ) + num ;
Logger : : Print ( " Address %s removed \n " , addr - > getCString ( ) ) ;
Logger : : LoggingAddresses [ 1 ] . erase ( addr ) ;
}
else
{
Network : : Address addr ( params - > get ( 1 ) ) ;
auto i = std : : find ( Logger : : LoggingAddresses [ 1 ] . begin ( ) , Logger : : LoggingAddresses [ 1 ] . end ( ) , addr ) ;
if ( i ! = Logger : : LoggingAddresses [ 1 ] . end ( ) )
{
Logger : : LoggingAddresses [ 1 ] . erase ( i ) ;
Logger : : Print ( " Address %s removed \n " , addr . getCString ( ) ) ;
}
else
{
Logger : : Print ( " Address %s not found! \n " , addr . getCString ( ) ) ;
}
}
} ) ;
2017-06-14 06:06:04 -04:00
Command : : AddSV ( " g_log_list " , [ ] ( Command : : Params * )
2017-01-19 16:23:59 -05:00
{
Logger : : Print ( " # ID: Address \n " ) ;
Logger : : Print ( " ------------- \n " ) ;
for ( unsigned int i = 0 ; i < Logger : : LoggingAddresses [ 1 ] . size ( ) ; + + i )
{
Logger : : Print ( " #%03d: %5s \n " , i , Logger : : LoggingAddresses [ 1 ] [ i ] . getCString ( ) ) ;
}
} ) ;
} ) ;
}
Logger : : ~ Logger ( )
{
Logger : : LoggingAddresses [ 0 ] . clear ( ) ;
Logger : : LoggingAddresses [ 1 ] . clear ( ) ;
Logger : : MessageMutex . lock ( ) ;
Logger : : MessageQueue . clear ( ) ;
Logger : : MessageMutex . unlock ( ) ;
// Flush the console log
if ( int fh = * reinterpret_cast < int * > ( 0x1AD8F28 ) )
{
Game : : FS_FCloseFile ( fh ) ;
}
}
}