2022-02-27 07:53:44 -05:00
# include <STDInclude.hpp>
2017-01-19 16:23:59 -05:00
namespace Components
{
std : : mutex Logger : : MessageMutex ;
std : : vector < std : : string > Logger : : MessageQueue ;
std : : vector < Network : : Address > Logger : : LoggingAddresses [ 2 ] ;
2018-12-17 08:29:18 -05:00
void ( * Logger : : PipeCallback ) ( const std : : string & ) = nullptr ;
2017-01-19 16:23:59 -05:00
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
}
2022-06-12 17:07:53 -04:00
void Logger : : PrintStub ( const int channel , const char * message , . . . )
2017-01-19 16:23:59 -05:00
{
2022-06-12 17:07:53 -04:00
char buf [ 4096 ] = { 0 } ;
2017-01-19 16:23:59 -05:00
2022-06-12 17:07:53 -04:00
va_list va ;
va_start ( va , message ) ;
_vsnprintf_s ( buf , _TRUNCATE , message , va ) ;
va_end ( va ) ;
2017-01-19 16:23:59 -05:00
2022-06-12 17:07:53 -04:00
Logger : : MessagePrint ( channel , { buf } ) ;
2017-01-19 16:23:59 -05:00
}
2022-06-12 17:07:53 -04:00
void Logger : : MessagePrint ( const int channel , const std : : string & msg )
2017-01-19 16:23:59 -05:00
{
2017-07-03 09:40:32 -04:00
if ( Flags : : HasFlag ( " stdout " ) | | Loader : : IsPerformingUnitTests ( ) )
2017-01-19 16:23:59 -05:00
{
2022-06-12 17:07:53 -04:00
printf ( " %s " , msg . data ( ) ) ;
2017-01-19 16:23:59 -05:00
fflush ( stdout ) ;
return ;
}
if ( ! Logger : : IsConsoleReady ( ) )
{
2022-06-12 17:07:53 -04:00
OutputDebugStringA ( msg . data ( ) ) ;
2017-01-19 16:23:59 -05:00
}
if ( ! Game : : Sys_IsMainThread ( ) )
{
2022-06-12 17:07:53 -04:00
Logger : : EnqueueMessage ( msg ) ;
2017-01-19 16:23:59 -05:00
}
else
{
2022-06-12 17:07:53 -04:00
Game : : Com_PrintMessage ( channel , msg . data ( ) , 0 ) ;
2017-01-19 16:23:59 -05:00
}
}
2022-06-22 04:58:51 -04:00
void Logger : : DebugInternal ( std : : string_view fmt , std : : format_args & & args , [[maybe_unused]] const std : : source_location & loc )
2017-01-19 16:23:59 -05:00
{
2022-06-12 17:07:53 -04:00
const auto msg = std : : vformat ( fmt , args ) ;
2022-06-22 04:58:51 -04:00
# ifdef LOGGER_TRACE
const auto out = std : : format ( " Debug: \n {} \n File: {} \n Line: {} \n " , msg , loc . file_name ( ) , loc . line ( ) ) ;
# else
const auto out = std : : format ( " Debug: \n {} \n " , msg ) ;
# endif
2017-01-19 16:23:59 -05:00
2022-06-12 17:07:53 -04:00
Logger : : MessagePrint ( Game : : CON_CHANNEL_DONT_FILTER , out ) ;
2017-01-19 16:23:59 -05:00
}
2022-06-12 17:07:53 -04:00
void Logger : : PrintInternal ( int channel , std : : string_view fmt , std : : format_args & & args )
2017-01-19 16:23:59 -05:00
{
2022-06-12 17:07:53 -04:00
const auto msg = std : : vformat ( fmt , args ) ;
Logger : : MessagePrint ( channel , msg ) ;
2017-01-19 16:23:59 -05:00
}
2022-06-12 17:07:53 -04:00
void Logger : : ErrorInternal ( const Game : : errorParm_t error , const std : : string_view fmt , std : : format_args & & args )
2017-01-19 16:23:59 -05:00
{
2022-06-12 17:07:53 -04:00
# ifdef _DEBUG
if ( IsDebuggerPresent ( ) ) __debugbreak ( ) ;
# endif
const auto msg = std : : vformat ( fmt , args ) ;
Game : : Com_Error ( error , " %s " , msg . data ( ) ) ;
2017-01-19 16:23:59 -05:00
}
2022-06-12 17:07:53 -04:00
void Logger : : PrintErrorInternal ( int channel , std : : string_view fmt , std : : format_args & & args )
2017-01-19 16:23:59 -05:00
{
2022-06-12 17:07:53 -04:00
const auto msg = " ^1Error: " + std : : vformat ( fmt , args ) ;
+ + ( * Game : : com_errorPrintsCount ) ;
Logger : : MessagePrint ( channel , msg ) ;
2017-01-19 16:23:59 -05:00
2022-06-12 17:07:53 -04:00
if ( * Game : : cls_uiStarted ! = 0 & & ( * Game : : com_fixedConsolePosition = = 0 ) )
{
Game : : CL_ConsoleFixPosition ( ) ;
}
}
2022-04-16 04:01:25 -04:00
2022-06-12 17:07:53 -04:00
void Logger : : WarningInternal ( int channel , std : : string_view fmt , std : : format_args & & args )
{
const auto msg = " ^3 " + std : : vformat ( fmt , args ) ;
2017-01-19 16:23:59 -05:00
2022-06-12 17:07:53 -04:00
Logger : : MessagePrint ( channel , msg ) ;
2017-01-19 16:23:59 -05:00
}
void Logger : : Flush ( )
{
// if (!Game::Sys_IsMainThread())
// {
// while (!Logger::MessageQueue.empty())
// {
// std::this_thread::sleep_for(10ms);
// }
// }
// else
{
Logger : : Frame ( ) ;
}
}
void Logger : : Frame ( )
{
2022-06-13 11:32:45 -04:00
std : : unique_lock _ ( Logger : : MessageMutex ) ;
2017-01-19 16:23:59 -05:00
2022-06-13 11:32:45 -04:00
for ( auto i = Logger : : MessageQueue . begin ( ) ; i ! = Logger : : MessageQueue . end ( ) ; )
2017-01-19 16:23:59 -05:00
{
2022-06-13 11:32:45 -04:00
Game : : Com_PrintMessage ( Game : : CON_CHANNEL_DONT_FILTER , i - > data ( ) , 0 ) ;
2017-01-19 16:23:59 -05:00
if ( ! Logger : : IsConsoleReady ( ) )
{
2022-06-13 11:32:45 -04:00
OutputDebugStringA ( i - > data ( ) ) ;
2017-01-19 16:23:59 -05:00
}
2022-06-13 11:32:45 -04:00
i = Logger : : MessageQueue . erase ( i ) ;
}
2017-01-19 16:23:59 -05:00
}
2018-12-17 08:29:18 -05:00
void Logger : : PipeOutput ( void ( * callback ) ( const std : : string & ) )
2017-01-19 16:23:59 -05:00
{
Logger : : PipeCallback = callback ;
}
void Logger : : PrintMessagePipe ( const char * data )
{
if ( Logger : : PipeCallback )
{
Logger : : PipeCallback ( data ) ;
}
}
void Logger : : NetworkLog ( const char * data , bool gLog )
{
2022-06-26 16:01:11 -04:00
if ( data = = nullptr )
{
return ;
}
2017-01-19 16:23:59 -05:00
2022-04-16 04:01:25 -04:00
for ( const auto & addr : Logger : : LoggingAddresses [ gLog & 1 ] )
2017-01-19 16:23:59 -05:00
{
2022-06-26 16:01:11 -04:00
Network : : SendCommand ( addr , " print " , data ) ;
2017-01-19 16:23:59 -05:00
}
}
2022-06-26 15:36:23 -04:00
void Logger : : G_LogPrintfStub ( const char * fmt , . . . )
2017-01-19 16:23:59 -05:00
{
2022-06-26 15:36:23 -04:00
char string [ 1024 ] ;
char string2 [ 1024 ] ;
2017-02-01 07:44:25 -05:00
2022-06-26 15:36:23 -04:00
va_list ap ;
va_start ( ap , fmt ) ;
vsnprintf_s ( string2 , _TRUNCATE , fmt , ap ) ;
va_end ( ap ) ;
2017-01-19 16:23:59 -05:00
2022-06-26 15:36:23 -04:00
const auto min = Game : : level - > time / 1000 / 60 ;
const auto tens = Game : : level - > time / 1000 % 60 / 10 ;
const auto sec = Game : : level - > time / 1000 % 60 % 10 ;
2017-02-01 07:44:25 -05:00
2022-06-26 16:01:11 -04:00
const auto len = _snprintf_s ( string , _TRUNCATE , " %3i:%i%i %s " ,
2022-06-26 15:36:23 -04:00
min , tens , sec , string2 ) ;
if ( Game : : level - > logFile ! = nullptr )
{
2022-06-26 16:01:11 -04:00
Game : : FS_Write ( string , len , reinterpret_cast < int > ( Game : : level - > logFile ) ) ;
2017-01-19 16:23:59 -05:00
}
2022-06-26 15:36:23 -04:00
// Allow the network log to run even if logFile was not opened
Logger : : NetworkLog ( string , true ) ;
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
}
}
2018-12-17 08:29:18 -05:00
void Logger : : EnqueueMessage ( const std : : string & message )
2017-01-19 16:23:59 -05:00
{
2022-06-13 11:32:45 -04:00
std : : unique_lock _ ( Logger : : MessageMutex ) ;
2017-01-19 16:23:59 -05:00
Logger : : MessageQueue . push_back ( message ) ;
}
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
}
}
2022-06-16 10:15:26 -04:00
void Logger : : AddServerCommands ( )
2017-01-19 16:23:59 -05:00
{
2022-06-16 10:15:26 -04:00
Command : : AddSV ( " log_add " , [ ] ( Command : : Params * params )
{
if ( params - > size ( ) < 2 ) return ;
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
Network : : Address addr ( params - > get ( 1 ) ) ;
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
if ( std : : find ( Logger : : LoggingAddresses [ 0 ] . begin ( ) , Logger : : LoggingAddresses [ 0 ] . end ( ) , addr ) = = Logger : : LoggingAddresses [ 0 ] . end ( ) )
{
Logger : : LoggingAddresses [ 0 ] . push_back ( addr ) ;
}
} ) ;
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
Command : : AddSV ( " log_del " , [ ] ( Command : : Params * params )
2017-01-19 16:23:59 -05:00
{
2022-06-16 10:15:26 -04:00
if ( params - > size ( ) < 2 ) return ;
2017-01-19 16:23:59 -05:00
2022-06-26 14:20:11 -04:00
const auto num = atoi ( params - > get ( 1 ) ) ;
2022-06-16 10:15:26 -04:00
if ( Utils : : String : : VA ( " %i " , num ) = = std : : string ( params - > get ( 1 ) ) & & static_cast < unsigned int > ( num ) < Logger : : LoggingAddresses [ 0 ] . size ( ) )
2017-01-19 16:23:59 -05:00
{
2022-06-16 10:15:26 -04:00
auto addr = Logger : : LoggingAddresses [ 0 ] . begin ( ) + num ;
Logger : : Print ( " Address {} removed \n " , addr - > getCString ( ) ) ;
Logger : : LoggingAddresses [ 0 ] . erase ( addr ) ;
}
else
2017-01-19 16:23:59 -05:00
{
2022-06-16 10:15:26 -04:00
Network : : Address addr ( params - > get ( 1 ) ) ;
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
const auto i = std : : find ( Logger : : LoggingAddresses [ 0 ] . begin ( ) , Logger : : LoggingAddresses [ 0 ] . end ( ) , addr ) ;
if ( i ! = Logger : : LoggingAddresses [ 0 ] . end ( ) )
2017-01-19 16:23:59 -05:00
{
2022-06-16 10:15:26 -04:00
Logger : : LoggingAddresses [ 0 ] . erase ( i ) ;
Logger : : Print ( " Address {} removed \n " , addr . getCString ( ) ) ;
2017-01-19 16:23:59 -05:00
}
else
{
2022-06-16 10:15:26 -04:00
Logger : : Print ( " Address {} not found! \n " , addr . getCString ( ) ) ;
2017-01-19 16:23:59 -05:00
}
2022-06-16 10:15:26 -04:00
}
} ) ;
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
Command : : AddSV ( " log_list " , [ ] ( Command : : Params * )
{
Logger : : Print ( " # ID: Address \n " ) ;
Logger : : Print ( " ------------- \n " ) ;
for ( unsigned int i = 0 ; i < Logger : : LoggingAddresses [ 0 ] . size ( ) ; + + i )
2017-01-19 16:23:59 -05:00
{
2022-06-26 14:20:11 -04:00
Logger : : Print ( " #{:03d}: {} \n " , i , Logger : : LoggingAddresses [ 0 ] [ i ] . getCString ( ) ) ;
2022-06-16 10:15:26 -04:00
}
} ) ;
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
Command : : AddSV ( " g_log_add " , [ ] ( Command : : Params * params )
{
if ( params - > size ( ) < 2 ) return ;
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
const Network : : Address addr ( params - > get ( 1 ) ) ;
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
if ( std : : find ( Logger : : LoggingAddresses [ 1 ] . begin ( ) , Logger : : LoggingAddresses [ 1 ] . end ( ) , addr ) = = Logger : : LoggingAddresses [ 1 ] . end ( ) )
{
Logger : : LoggingAddresses [ 1 ] . push_back ( addr ) ;
}
} ) ;
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
Command : : AddSV ( " g_log_del " , [ ] ( Command : : Params * params )
{
if ( params - > size ( ) < 2 ) return ;
2017-01-19 16:23:59 -05:00
2022-06-26 14:20:11 -04:00
const auto num = std : : atoi ( params - > get ( 1 ) ) ;
2022-06-16 10:15:26 -04:00
if ( Utils : : String : : VA ( " %i " , num ) = = std : : string ( params - > get ( 1 ) ) & & static_cast < unsigned int > ( num ) < Logger : : LoggingAddresses [ 1 ] . size ( ) )
{
const auto addr = Logger : : LoggingAddresses [ 1 ] . begin ( ) + num ;
Logger : : Print ( " Address {} removed \n " , addr - > getCString ( ) ) ;
Logger : : LoggingAddresses [ 1 ] . erase ( addr ) ;
}
else
2017-01-19 16:23:59 -05:00
{
2022-06-16 10:15:26 -04:00
const Network : : Address addr ( params - > get ( 1 ) ) ;
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
const auto i = std : : find ( Logger : : LoggingAddresses [ 1 ] . begin ( ) , Logger : : LoggingAddresses [ 1 ] . end ( ) , addr ) ;
if ( i ! = Logger : : LoggingAddresses [ 1 ] . end ( ) )
2017-01-19 16:23:59 -05:00
{
2022-06-16 10:15:26 -04:00
Logger : : LoggingAddresses [ 1 ] . erase ( i ) ;
Logger : : Print ( " Address {} removed \n " , addr . getCString ( ) ) ;
2017-01-19 16:23:59 -05:00
}
else
{
2022-06-16 10:15:26 -04:00
Logger : : Print ( " Address {} not found! \n " , addr . getCString ( ) ) ;
2017-01-19 16:23:59 -05:00
}
2022-06-16 10:15:26 -04:00
}
} ) ;
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
Command : : AddSV ( " g_log_list " , [ ] ( Command : : Params * )
{
Logger : : Print ( " # ID: Address \n " ) ;
Logger : : Print ( " ------------- \n " ) ;
for ( std : : size_t i = 0 ; i < Logger : : LoggingAddresses [ 1 ] . size ( ) ; + + i )
2017-01-19 16:23:59 -05:00
{
2022-06-26 14:20:11 -04:00
Logger : : Print ( " #{:03d}: {} \n " , i , Logger : : LoggingAddresses [ 1 ] [ i ] . getCString ( ) ) ;
2022-06-16 10:15:26 -04:00
}
} ) ;
}
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
Logger : : Logger ( )
{
Dvar : : Register < bool > ( " iw4x_onelog " , false , Game : : dvar_flag : : DVAR_LATCH | Game : : dvar_flag : : DVAR_ARCHIVE , " Only write the game log to the 'userraw' OS folder " ) ;
Utils : : Hook ( 0x642139 , Logger : : BuildOSPathStub , HOOK_JUMP ) . install ( ) - > quick ( ) ;
Logger : : PipeOutput ( nullptr ) ;
Scheduler : : Loop ( Logger : : Frame , Scheduler : : Pipeline : : SERVER ) ;
2022-06-26 15:36:23 -04:00
Utils : : Hook ( Game : : G_LogPrintf , Logger : : G_LogPrintfStub , HOOK_JUMP ) . install ( ) - > quick ( ) ;
2022-06-16 10:15:26 -04:00
Utils : : Hook ( Game : : Com_PrintMessage , Logger : : PrintMessageStub , HOOK_JUMP ) . install ( ) - > quick ( ) ;
if ( Loader : : IsPerformingUnitTests ( ) )
{
Utils : : Hook ( Game : : Com_Printf , Logger : : PrintStub , HOOK_JUMP ) . install ( ) - > quick ( ) ;
}
2022-06-28 14:57:58 -04:00
Events : : OnSVInit ( Logger : : AddServerCommands ) ;
2017-01-19 16:23:59 -05:00
}
Logger : : ~ Logger ( )
{
Logger : : LoggingAddresses [ 0 ] . clear ( ) ;
Logger : : LoggingAddresses [ 1 ] . clear ( ) ;
2022-06-13 11:32:45 -04:00
std : : unique_lock lock ( Logger : : MessageMutex ) ;
2017-01-19 16:23:59 -05:00
Logger : : MessageQueue . clear ( ) ;
2022-06-13 11:32:45 -04:00
lock . unlock ( ) ;
2017-01-19 16:23:59 -05:00
// Flush the console log
2022-04-16 04:01:25 -04:00
if ( const auto logfile = * reinterpret_cast < int * > ( 0x1AD8F28 ) )
2017-01-19 16:23:59 -05:00
{
2022-04-16 04:01:25 -04:00
Game : : FS_FCloseFile ( logfile ) ;
2017-01-19 16:23:59 -05:00
}
}
}