diff --git a/engine/common/com_strings.h b/engine/common/com_strings.h index 1817fb8a..cb37bb3e 100644 --- a/engine/common/com_strings.h +++ b/engine/common/com_strings.h @@ -57,4 +57,6 @@ GNU General Public License for more details. #define DEFAULT_BSP_BUILD_ERROR "%s can't be loaded in this build. Please rebuild engine with enabled SUPPORT_BSP2_FORMAT\n" -#endif//COM_STRINGS_H \ No newline at end of file +#define DEFAULT_UPDATE_PAGE "https://github.com/FWGS/xash3d-fwgs/releases/latest" + +#endif//COM_STRINGS_H diff --git a/engine/common/common.h b/engine/common/common.h index 23a3c717..bed04368 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -186,8 +186,6 @@ typedef enum #define CIN_MAIN 0 #define CIN_LOGO 1 -#define MAX_NUM_ARGVS 128 - // config strings are a general means of communication from // the server to all connected clients. // each config string can be at most CS_SIZE characters. @@ -426,7 +424,7 @@ typedef struct host_parm_s // command line parms int argc; - const char *argv[MAX_NUM_ARGVS]; + const char **argv; double realtime; // host.curtime double frametime; // time between engine frames @@ -916,6 +914,8 @@ void Key_SetKeyDest( int key_dest ); #include "avi/avi.h" // shared calls +typedef struct sv_client_s sv_client_t; +typedef struct sizebuf_s sizebuf_t; qboolean CL_IsInGame( void ); qboolean CL_IsInMenu( void ); qboolean CL_IsInConsole( void ); @@ -934,12 +934,12 @@ int COM_ExpandFilename( const char *fileName, char *nameOutBuffer, int nameOutBu struct pmtrace_s *PM_TraceLine( float *start, float *end, int flags, int usehull, int ignore_pe ); void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch ); void SV_StartMusic( const char *curtrack, const char *looptrack, long position ); -void SV_CreateDecal( struct sizebuf_s *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale ); +void SV_CreateDecal( sizebuf_t *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale ); void Log_Printf( const char *fmt, ... ); struct sizebuf_s *SV_GetReliableDatagram( void ); void SV_BroadcastCommand( const char *fmt, ... ); qboolean SV_RestoreCustomDecal( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent ); -void SV_BroadcastPrintf( struct sv_client_s *ignore, char *fmt, ... ); +void SV_BroadcastPrintf( sv_client_t *ignore, char *fmt, ... ); int R_CreateDecalList( struct decallist_s *pList ); void R_DecalRemoveAll( int texture ); void R_ClearAllDecals( void ); diff --git a/engine/common/host.c b/engine/common/host.c index f63167f1..d324da3a 100644 --- a/engine/common/host.c +++ b/engine/common/host.c @@ -393,12 +393,11 @@ void Host_GetCommands( void ) { char *cmd; - if( host.type != HOST_DEDICATED ) - return; - - cmd = Con_Input(); - if( cmd ) Cbuf_AddText( cmd ); - Cbuf_Execute (); + while( ( cmd = Sys_Input() ) ) + { + Cbuf_AddText( cmd ); + Cbuf_Execute(); + } } /* @@ -786,7 +785,9 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha // member console allowing host.allow_console_init = host.allow_console; - Con_CreateConsole(); // system console used by dedicated server or show fatal errors +#ifdef _WIN32 + Wcon_CreateConsole(); // system console used by dedicated server or show fatal errors +#endif // NOTE: this message couldn't be passed into game console but it doesn't matter MsgDev( D_NOTE, "Sys_LoadLibrary: Loading xash.dll - ok\n" ); @@ -889,7 +890,9 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa if( host.type == HOST_DEDICATED ) { - Con_InitConsoleCommands (); +#ifdef _WIN32 + Wcon_InitConsoleCommands (); +#endif Cmd_AddCommand( "quit", Sys_Quit, "quit the game" ); Cmd_AddCommand( "exit", Sys_Quit, "quit the game" ); @@ -902,7 +905,9 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa switch( host.type ) { case HOST_NORMAL: - Con_ShowConsole( false ); // hide console +#ifdef _WIN32 + Wcon_ShowConsole( false ); // hide console +#endif // execute startup config and cmdline Cbuf_AddText( va( "exec %s.rc\n", SI.rcName )); Cbuf_Execute(); @@ -963,7 +968,9 @@ void EXPORT Host_Shutdown( void ) Mod_Shutdown(); NET_Shutdown(); Host_FreeCommon(); - Con_DestroyConsole(); +#ifdef _WIN32 + Wcon_DestroyConsole(); +#endif // must be last, console uses this Mem_FreePool( &host.mempool ); diff --git a/engine/common/sys_con.c b/engine/common/sys_con.c new file mode 100644 index 00000000..fcc356a8 --- /dev/null +++ b/engine/common/sys_con.c @@ -0,0 +1,223 @@ +/* +sys_con.c - stdout and log +Copyright (C) 2007 Uncle Mike + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "common.h" +#ifdef __ANDROID__ +#include +#endif + +#if !defined( _WIN32 ) && !defined( XASH_MOBILE_PLATFORM ) +#define COLORIZE_CONSOLE +#define USE_SELECT +#endif + +#ifdef USE_SELECT +// non-blocking console input +#include +#endif + +typedef struct { + char title[64]; + qboolean log_active; + char log_path[MAX_SYSPATH]; + FILE *logfile; + int logfileno; +} LogData; + +static LogData s_ld; + +char *Sys_Input( void ) +{ +#ifdef USE_SELECT + { + fd_set rfds; + static char line[1024]; + static int len; + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + FD_ZERO(&rfds); + FD_SET(0, &rfds); // stdin + while( select(1, &rfds, NULL, NULL, &tv ) > 0 ) + { + if( read( 0, &line[len], 1 ) != 1 ) + break; + if( line[len] == '\n' || len > 1022 ) + { + line[ ++len ] = 0; + len = 0; + return line; + } + len++; + tv.tv_sec = 0; + tv.tv_usec = 0; + } + } +#endif +#ifdef _WIN32 + return Wcon_Input(); +#endif + return NULL; +} + +void Sys_DestroyConsole( void ) +{ + // last text message into console or log + MsgDev( D_NOTE, "Sys_DestroyConsole: Exiting!\n" ); +#ifdef _WIN32 + Wcon_DestroyConsole(); +#endif +} + +/* +=============================================================================== + +SYSTEM LOG + +=============================================================================== +*/ +void Sys_InitLog( void ) +{ + const char *mode; + + if( host.change_game && host.type != HOST_DEDICATED ) + mode = "a"; + else mode = "w"; + + // create log if needed + if( s_ld.log_active ) + { + s_ld.logfile = fopen( s_ld.log_path, mode ); + if( !s_ld.logfile ) MsgDev( D_ERROR, "Sys_InitLog: can't create log file %s\n", s_ld.log_path ); + + fprintf( s_ld.logfile, "=================================================================================\n" ); + fprintf( s_ld.logfile, "\t%s (build %i) started at %s\n", s_ld.title, Q_buildnum(), Q_timestamp( TIME_FULL )); + fprintf( s_ld.logfile, "=================================================================================\n" ); + } +} + +void Sys_CloseLog( void ) +{ + char event_name[64]; + + // continue logged + switch( host.status ) + { + case HOST_CRASHED: + Q_strncpy( event_name, "crashed", sizeof( event_name )); + break; + case HOST_ERR_FATAL: + Q_strncpy( event_name, "stopped with error", sizeof( event_name )); + break; + default: + if( !host.change_game ) Q_strncpy( event_name, "stopped", sizeof( event_name )); + else Q_strncpy( event_name, host.finalmsg, sizeof( event_name )); + break; + } + + if( s_ld.logfile ) + { + fprintf( s_ld.logfile, "\n"); + fprintf( s_ld.logfile, "================================================================================="); + if( host.change_game ) fprintf( s_ld.logfile, "\n\t%s (build %i) %s\n", s_ld.title, Q_buildnum(), event_name ); + else fprintf( s_ld.logfile, "\n\t%s (build %i) %s at %s\n", s_ld.title, Q_buildnum(), event_name, Q_timestamp( TIME_FULL )); + fprintf( s_ld.logfile, "================================================================================="); + if( host.change_game ) fprintf( s_ld.logfile, "\n" ); // just for tabulate + + fclose( s_ld.logfile ); + s_ld.logfile = NULL; + } +} + +void Sys_PrintLog( const char *pMsg ) +{ + time_t crt_time; + const struct tm *crt_tm; + char logtime[32] = ""; + static char lastchar; + + time( &crt_time ); + crt_tm = localtime( &crt_time ); +#ifdef __ANDROID__ + __android_log_print( ANDROID_LOG_DEBUG, "Xash", "%s", pMsg ); +#endif + +#if TARGET_OS_IOS + void IOS_Log(const char*); + IOS_Log(pMsg); +#endif + + + if( !lastchar || lastchar == '\n') + strftime( logtime, sizeof( logtime ), "[%H:%M:%S] ", crt_tm ); //short time + +#ifdef COLORIZE_CONSOLE + { + char colored[4096]; + const char *msg = pMsg; + int len = 0; + while( *msg && ( len < 4090 ) ) + { + static char q3ToAnsi[ 8 ] = + { + '0', // COLOR_BLACK + '1', // COLOR_RED + '2', // COLOR_GREEN + '3', // COLOR_YELLOW + '4', // COLOR_BLUE + '6', // COLOR_CYAN + '5', // COLOR_MAGENTA + 0 // COLOR_WHITE + }; + + if( IsColorString( msg ) ) + { + int color; + + msg++; + color = q3ToAnsi[ *msg++ % 8 ]; + colored[len++] = '\033'; + colored[len++] = '['; + if( color ) + { + colored[len++] = '3'; + colored[len++] = color; + } + else + colored[len++] = '0'; + colored[len++] = 'm'; + } + else + colored[len++] = *msg++; + } + colored[len] = 0; + printf( "\033[34m%s\033[0m%s\033[0m", logtime, colored ); + } +#else +#if !defined __ANDROID__ || defined XASH_DEDICATED + printf( "%s %s", logtime, pMsg ); + fflush( stdout ); +#endif +#endif + lastchar = pMsg[strlen(pMsg)-1]; + if( !s_ld.logfile ) + return; + + if( !lastchar || lastchar == '\n') + strftime( logtime, sizeof( logtime ), "[%Y:%m:%d|%H:%M:%S]", crt_tm ); //full time + + fprintf( s_ld.logfile, "%s %s", logtime, pMsg ); + fflush( s_ld.logfile ); +} diff --git a/engine/common/sys_win.c b/engine/common/system.c similarity index 55% rename from engine/common/sys_win.c rename to engine/common/system.c index 130e71f6..6ce02d3e 100644 --- a/engine/common/sys_win.c +++ b/engine/common/system.c @@ -15,16 +15,40 @@ GNU General Public License for more details. #include "common.h" #include "mathlib.h" +#include +#include + +#ifdef XASH_SDL +#include +#endif + +#ifndef _WIN32 +#include +#include +#include + +#ifndef __ANDROID__ +extern char **environ; +#include +#endif +#endif + +#include "menu_int.h" // _UPDATE_PAGE macro qboolean error_on_exit = false; // arg for exit(); +#define DEBUG_BREAK +#if defined _WIN32 && !defined XASH_SDL +#include +#endif /* ================ Sys_DoubleTime ================ */ -double Sys_DoubleTime( void ) +double GAME_EXPORT Sys_DoubleTime( void ) { +#if XASH_TIMER == TIMER_WIN32 static LARGE_INTEGER g_PerformanceFrequency; static LARGE_INTEGER g_ClockStart; LARGE_INTEGER CurrentTime; @@ -37,8 +61,92 @@ double Sys_DoubleTime( void ) QueryPerformanceCounter( &CurrentTime ); return (double)( CurrentTime.QuadPart - g_ClockStart.QuadPart ) / (double)( g_PerformanceFrequency.QuadPart ); +#elif XASH_TIMER == TIMER_SDL + static longtime_t g_PerformanceFrequency; + static longtime_t g_ClockStart; + longtime_t CurrentTime; + + if( !g_PerformanceFrequency ) + { + g_PerformanceFrequency = SDL_GetPerformanceFrequency(); + g_ClockStart = SDL_GetPerformanceCounter(); + } + CurrentTime = SDL_GetPerformanceCounter(); + return (double)( CurrentTime - g_ClockStart ) / (double)( g_PerformanceFrequency ); +#elif XASH_TIMER == TIMER_LINUX + static longtime_t g_PerformanceFrequency; + static longtime_t g_ClockStart; + longtime_t CurrentTime; + struct timespec ts; + + if( !g_PerformanceFrequency ) + { + struct timespec res; + if( !clock_getres(CLOCK_MONOTONIC, &res) ) + g_PerformanceFrequency = 1000000000LL/res.tv_nsec; + } + clock_gettime(CLOCK_MONOTONIC, &ts); + return (double) ts.tv_sec + (double) ts.tv_nsec/1000000000.0; +#endif +} + +#ifdef GDB_BREAK +#include +qboolean Sys_DebuggerPresent( void ) +{ + char buf[1024]; + + int status_fd = open( "/proc/self/status", O_RDONLY ); + if ( status_fd == -1 ) + return 0; + + ssize_t num_read = read( status_fd, buf, sizeof( buf ) ); + + if ( num_read > 0 ) + { + static const char TracerPid[] = "TracerPid:"; + const byte *tracer_pid; + + buf[num_read] = 0; + tracer_pid = (const byte*)Q_strstr( buf, TracerPid ); + if( !tracer_pid ) + return false; + //printf( "%s\n", tracer_pid ); + while( *tracer_pid < '0' || *tracer_pid > '9' ) + if( *tracer_pid++ == '\n' ) + return false; + //printf( "%s\n", tracer_pid ); + return !!Q_atoi( (const char*)tracer_pid ); + } + + return false; } +#undef DEBUG_BREAK +#ifdef __i386__ +#define DEBUG_BREAK \ + if( Sys_DebuggerPresent() ) \ + asm volatile("int $3;") +#else +#define DEBUG_BREAK \ + if( Sys_DebuggerPresent() ) \ + raise( SIGINT ) +#endif +#endif + +#if defined _WIN32 && !defined XASH_64BIT +#ifdef _MSC_VER + + +BOOL WINAPI IsDebuggerPresent(void); +#define DEBUG_BREAK if( IsDebuggerPresent() ) \ + _asm{ int 3 } +#else +#define DEBUG_BREAK if( IsDebuggerPresent() ) \ + asm volatile("int $3;") +#endif +#endif + /* ================ Sys_GetClipboardData @@ -48,31 +156,19 @@ create buffer, that contain clipboard */ char *Sys_GetClipboardData( void ) { - static char *data = NULL; + static char data[1024]; char *cliptext; - if( data ) - { - // release previous cbd - Z_Free( data ); - data = NULL; - } + data[0] = '\0'; - if( OpenClipboard( NULL ) != 0 ) +#ifdef XASH_SDL + cliptext = SDL_GetClipboardText(); + if( cliptext ) { - HANDLE hClipboardData; - - if(( hClipboardData = GetClipboardData( CF_TEXT )) != 0 ) - { - if(( cliptext = GlobalLock( hClipboardData )) != 0 ) - { - data = Z_Malloc( GlobalSize( hClipboardData ) + 1 ); - Q_strcpy( data, cliptext ); - GlobalUnlock( hClipboardData ); - } - } - CloseClipboard(); + Q_strncpy( data, cliptext, sizeof( data ) ); + SDL_free( cliptext ); } +#endif // XASH_SDL return data; } @@ -86,23 +182,9 @@ write screenshot into clipboard */ void Sys_SetClipboardData( const byte *buffer, size_t size ) { - EmptyClipboard(); - - if( OpenClipboard( NULL ) != 0 ) - { - HGLOBAL hResult = GlobalAlloc( GMEM_MOVEABLE, size ); - byte *bufferCopy = (byte *)GlobalLock( hResult ); - - memcpy( bufferCopy, buffer, size ); - GlobalUnlock( hResult ); - - if( SetClipboardData( CF_DIB, hResult ) == NULL ) - { - MsgDev( D_ERROR, "unable to write screenshot\n" ); - GlobalFree( hResult ); - } - CloseClipboard(); - } +#ifdef XASH_SDL + SDL_SetClipboardText((char *)buffer); +#endif } /* @@ -114,8 +196,17 @@ freeze application for some time */ void Sys_Sleep( int msec ) { - msec = bound( 1, msec, 1000 ); + if( !msec ) + return; + + msec = min( msec, 1000 ); +#if XASH_TIMER == TIMER_WIN32 Sleep( msec ); +#elif XASH_TIMER == TIMER_SDL + SDL_Delay( msec ); +#elif XASH_TIEMR == TIMER_LINUX + usleep( msec * 1000 ); +#endif } /* @@ -127,63 +218,106 @@ returns username for current profile */ char *Sys_GetCurrentUser( void ) { - static string sys_user_name; - dword size = sizeof( sys_user_name ); - - if( !sys_user_name[0] ) - { - HINSTANCE advapi32_dll = LoadLibrary( "advapi32.dll" ); - BOOL (_stdcall *pGetUserNameA)( LPSTR lpBuffer, LPDWORD nSize ) = NULL; - if( advapi32_dll ) pGetUserNameA = (void *)GetProcAddress( advapi32_dll, "GetUserNameA" ); - if( pGetUserNameA) pGetUserNameA( sys_user_name, &size ); - if( advapi32_dll ) FreeLibrary( advapi32_dll ); // no need anymore... - if( !sys_user_name[0] ) Q_strcpy( sys_user_name, "player" ); - } - - return sys_user_name; +#if defined(_WIN32) + static string s_userName; + unsigned long size = sizeof( s_userName ); + + if( GetUserName( s_userName, &size )) + return s_userName; +#elif !defined(__ANDROID__) + uid_t uid = geteuid(); + struct passwd *pw = getpwuid( uid ); + + if( pw ) + return pw->pw_name; +#endif + return "Player"; } -/* -================= -Sys_GetMachineKey -================= -*/ -const char *Sys_GetMachineKey( int *nLength ) +#if (defined(__linux__) && !defined(__ANDROID__)) || defined (__FreeBSD__) || defined (__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) +static qboolean Sys_FindExecutable( const char *baseName, char *buf, size_t size ) { - HINSTANCE rpcrt4_dll = LoadLibrary( "rpcrt4.dll" ); - RPC_STATUS (_stdcall *pUuidCreateSequential)( UUID __RPC_FAR *Uuid ) = NULL; - static byte key[32]; - byte mac[8]; - UUID uuid; - int i; + char *envPath; + char *part; + size_t length; + size_t baseNameLength; + size_t needTrailingSlash; - if( rpcrt4_dll ) pUuidCreateSequential = (void *)GetProcAddress( rpcrt4_dll, "UuidCreateSequential" ); - if( pUuidCreateSequential ) pUuidCreateSequential( &uuid ); // ask OS to create UUID - if( rpcrt4_dll ) FreeLibrary( rpcrt4_dll ); // no need anymore... + if( !baseName || !baseName[0] ) + return false; + + envPath = getenv( "PATH" ); + if( !envPath ) + return false; - for( i = 2; i < 8; i++ ) // bytes 2 through 7 inclusive are MAC address - mac[i-2] = uuid.Data4[i]; + baseNameLength = Q_strlen( baseName ); + while( *envPath ) + { + part = Q_strchr( envPath, ':' ); + if( part ) + length = part - envPath; + else + length = Q_strlen( envPath ); - Q_snprintf( key, sizeof( key ), "%02X-%02X-%02X-%02X-%02X-%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ); + if( length > 0 ) + { + needTrailingSlash = ( envPath[length - 1] == '/' ) ? 0 : 1; + if( length + baseNameLength + needTrailingSlash < size ) + { + Q_strncpy( buf, envPath, length + 1 ); + if( needTrailingSlash ) + Q_strcpy( buf + length, "/" ); + Q_strcpy( buf + length + needTrailingSlash, baseName ); + buf[length + needTrailingSlash + baseNameLength] = '\0'; + if( access( buf, X_OK ) == 0 ) + return true; + } + } - if( nLength ) *nLength = Q_strlen( key ); - return key; + envPath += length; + if( *envPath == ':' ) + envPath++; + } + return false; } +#endif /* ================= Sys_ShellExecute ================= */ -void Sys_ShellExecute( const char *path, const char *parms, qboolean exit ) +void Sys_ShellExecute( const char *path, const char *parms, qboolean shouldExit ) { - HINSTANCE shell32_dll = LoadLibrary( "shell32.dll" ); - HINSTANCE (_stdcall *pShellExecuteA)( HWND hwnd, LPCSTR lpOp, LPCSTR lpFile, LPCSTR lpParam, LPCSTR lpDir, INT nShowCmd ) = NULL; - if( shell32_dll ) pShellExecuteA = (void *)GetProcAddress( shell32_dll, "ShellExecuteA" ); - if( pShellExecuteA ) pShellExecuteA( NULL, "open", path, parms, NULL, SW_SHOW ); - if( shell32_dll ) FreeLibrary( shell32_dll ); // no need anymore... +#ifdef _WIN32 + if( !Q_strcmp( path, GENERIC_UPDATE_PAGE ) || !Q_strcmp( path, PLATFORM_UPDATE_PAGE )) + path = DEFAULT_UPDATE_PAGE; + + ShellExecute( NULL, "open", path, parms, NULL, SW_SHOW ); +#elif (defined(__linux__) && !defined (__ANDROID__)) || defined (__FreeBSD__) || defined (__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) + + if( !Q_strcmp( path, GENERIC_UPDATE_PAGE ) || !Q_strcmp( path, PLATFORM_UPDATE_PAGE )) + path = DEFAULT_UPDATE_PAGE; + + char xdgOpen[128]; + if( Sys_FindExecutable( OPEN_COMMAND, xdgOpen, sizeof( xdgOpen ) ) ) + { + const char *argv[] = {xdgOpen, path, NULL}; + pid_t id = fork( ); + if( id == 0 ) + { + execve( xdgOpen, (char **)argv, environ ); + fprintf( stderr, "error opening %s %s", xdgOpen, path ); + _exit( 1 ); + } + } + else MsgDev( D_WARN, "Could not find "OPEN_COMMAND" utility\n" ); +#elif defined(__ANDROID__) && !defined(XASH_DEDICATED) + Android_ShellExecute( path, parms ); +#endif - if( exit ) Sys_Quit(); + if( shouldExit ) + Sys_Quit(); } /* @@ -223,7 +357,7 @@ Sys_MergeCommandLine ================== */ -void Sys_MergeCommandLine( ) +void Sys_MergeCommandLine( void ) { const char *blank = "censored"; int i; @@ -280,6 +414,7 @@ qboolean _Sys_GetParmFromCmdLine( char *parm, char *out, size_t size ) void Sys_SendKeyEvents( void ) { +#ifdef _WIN32 MSG msg; while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE )) @@ -290,6 +425,7 @@ void Sys_SendKeyEvents( void ) TranslateMessage( &msg ); DispatchMessage( &msg ); } +#endif } //======================================================================= @@ -383,6 +519,7 @@ wait for 'Esc' key will be hit */ void Sys_WaitForQuit( void ) { +#ifdef _WIN32 MSG msg; Con_RegisterHotkeys(); @@ -399,37 +536,7 @@ void Sys_WaitForQuit( void ) } else Sys_Sleep( 20 ); } -} - -long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo ) -{ - // save config - if( host.status != HOST_CRASHED ) - { - // check to avoid recursive call - error_on_exit = true; - host.crashed = true; - - if( host.type == HOST_NORMAL ) - CL_Crashed(); // tell client about crash - else host.status = HOST_CRASHED; - - Con_Printf( "unhandled exception: %p at address %p\n", pInfo->ExceptionRecord->ExceptionAddress, pInfo->ExceptionRecord->ExceptionCode ); - - if( !host_developer.value ) - { - // for non-development mode - Sys_Quit(); - return EXCEPTION_CONTINUE_EXECUTION; - } - - // all other states keep unchanged to let debugger find bug - Con_DestroyConsole(); - } - - if( host.oldFilter ) - return host.oldFilter( pInfo ); - return EXCEPTION_CONTINUE_EXECUTION; +#endif } /* @@ -466,7 +573,9 @@ void Sys_Error( const char *error, ... ) { va_list argptr; char text[MAX_SYSPATH]; - + + DEBUG_BREAK; + if( host.status == HOST_ERR_FATAL ) return; // don't multiple executes @@ -481,27 +590,48 @@ void Sys_Error( const char *error, ... ) SV_SysError( text ); - if( host.type == HOST_NORMAL ) + if( !Host_IsDedicated() ) { - if( host.hWnd ) ShowWindow( host.hWnd, SW_HIDE ); +#ifdef XASH_SDL + if( host.hWnd ) SDL_HideWindow( host.hWnd ); +#endif } if( host_developer.value ) { +#ifdef _WIN32 Con_ShowConsole( true ); Con_DisableInput(); // disable input line for dedicated server +#endif Sys_Print( text ); // print error message Sys_WaitForQuit(); } else { +#ifdef _WIN32 Con_ShowConsole( false ); +#endif MSGBOX( text ); } Sys_Quit(); } +#ifdef __EMSCRIPTEN__ +/* strange glitchy bug on emscripten +_exit->_Exit->asm._exit->_exit +As we do not need atexit(), just throw hidden exception +*/ +#include +#define exit my_exit +void my_exit(int ret) +{ + emscripten_cancel_main_loop(); + printf("exit(%d)\n", ret); + EM_ASM(if(showElement)showElement('reload', true);throw 'SimulateInfiniteLoop'); +} +#endif + /* ================ Sys_Quit @@ -522,65 +652,75 @@ print into window console */ void Sys_Print( const char *pMsg ) { - const char *msg; - static char buffer[MAX_PRINT_MSG]; - static char logbuf[MAX_PRINT_MSG]; - char *b = buffer; - char *c = logbuf; - int i = 0; - - if( host.type == HOST_NORMAL ) + if( !Host_IsDedicated() ) Con_Print( pMsg ); - // if the message is REALLY long, use just the last portion of it - if( Q_strlen( pMsg ) > sizeof( buffer ) - 1 ) - msg = pMsg + Q_strlen( pMsg ) - sizeof( buffer ) + 1; - else msg = pMsg; - - // copy into an intermediate buffer - while( msg[i] && (( b - buffer ) < sizeof( buffer ) - 1 )) +#ifdef _WIN32 { - if( msg[i] == '\n' && msg[i+1] == '\r' ) - { - b[0] = '\r'; - b[1] = c[0] = '\n'; - b += 2, c++; - i++; - } - else if( msg[i] == '\r' ) - { - b[0] = c[0] = '\r'; - b[1] = '\n'; - b += 2, c++; - } - else if( msg[i] == '\n' ) - { - b[0] = '\r'; - b[1] = c[0] = '\n'; - b += 2, c++; - } - else if( msg[i] == '\35' || msg[i] == '\36' || msg[i] == '\37' ) - { - i++; // skip console pseudo graph - } - else if( IsColorString( &msg[i] )) - { - i++; // skip color prefix - } - else + const char *msg; + static char buffer[MAX_PRINT_MSG]; + static char logbuf[MAX_PRINT_MSG]; + char *b = buffer; + char *c = logbuf; + int i = 0; + + if( host.type == HOST_NORMAL ) + Con_Print( pMsg ); + + // if the message is REALLY long, use just the last portion of it + if( Q_strlen( pMsg ) > sizeof( buffer ) - 1 ) + msg = pMsg + Q_strlen( pMsg ) - sizeof( buffer ) + 1; + else msg = pMsg; + + // copy into an intermediate buffer + while( msg[i] && (( b - buffer ) < sizeof( buffer ) - 1 )) { - if( msg[i] == '\1' || msg[i] == '\2' ) + if( msg[i] == '\n' && msg[i+1] == '\r' ) + { + b[0] = '\r'; + b[1] = c[0] = '\n'; + b += 2, c++; i++; - *b = *c = msg[i]; - b++, c++; + } + else if( msg[i] == '\r' ) + { + b[0] = c[0] = '\r'; + b[1] = '\n'; + b += 2, c++; + } + else if( msg[i] == '\n' ) + { + b[0] = '\r'; + b[1] = c[0] = '\n'; + b += 2, c++; + } + else if( msg[i] == '\35' || msg[i] == '\36' || msg[i] == '\37' ) + { + i++; // skip console pseudo graph + } + else if( IsColorString( &msg[i] )) + { + i++; // skip color prefix + } + else + { + if( msg[i] == '\1' || msg[i] == '\2' ) + i++; + *b = *c = msg[i]; + b++, c++; + } + i++; } - i++; + + *b = *c = 0; // terminator + + Con_WinPrint( buffer ); } +#endif - *b = *c = 0; // terminator + Sys_PrintLog( pMsg ); - Sys_PrintLog( logbuf ); - Con_WinPrint( buffer ); + // Rcon_Print( pMsg ); } /* @@ -617,70 +757,3 @@ void MsgDev( int type, const char *pMsg, ... ) break; } } - -/* -=============================================================================== - -SYSTEM LOG - -=============================================================================== -*/ -void Sys_InitLog( void ) -{ - const char *mode; - - if( host.change_game && host.type != HOST_DEDICATED ) - mode = "a"; - else mode = "w"; - - // create log if needed - if( s_wcd.log_active ) - { - s_wcd.logfile = fopen( s_wcd.log_path, mode ); - if( !s_wcd.logfile ) MsgDev( D_ERROR, "Sys_InitLog: can't create log file %s\n", s_wcd.log_path ); - - fprintf( s_wcd.logfile, "=================================================================================\n" ); - fprintf( s_wcd.logfile, "\t%s (build %i) started at %s\n", s_wcd.title, Q_buildnum(), Q_timestamp( TIME_FULL )); - fprintf( s_wcd.logfile, "=================================================================================\n" ); - } -} - -void Sys_CloseLog( void ) -{ - char event_name[64]; - - // continue logged - switch( host.status ) - { - case HOST_CRASHED: - Q_strncpy( event_name, "crashed", sizeof( event_name )); - break; - case HOST_ERR_FATAL: - Q_strncpy( event_name, "stopped with error", sizeof( event_name )); - break; - default: - if( !host.change_game ) Q_strncpy( event_name, "stopped", sizeof( event_name )); - else Q_strncpy( event_name, host.finalmsg, sizeof( event_name )); - break; - } - - if( s_wcd.logfile ) - { - fprintf( s_wcd.logfile, "\n"); - fprintf( s_wcd.logfile, "================================================================================="); - if( host.change_game ) fprintf( s_wcd.logfile, "\n\t%s (build %i) %s\n", s_wcd.title, Q_buildnum(), event_name ); - else fprintf( s_wcd.logfile, "\n\t%s (build %i) %s at %s\n", s_wcd.title, Q_buildnum(), event_name, Q_timestamp( TIME_FULL )); - fprintf( s_wcd.logfile, "================================================================================="); - if( host.change_game ) fprintf( s_wcd.logfile, "\n" ); // just for tabulate - - fclose( s_wcd.logfile ); - s_wcd.logfile = NULL; - } -} - -void Sys_PrintLog( const char *pMsg ) -{ - if( !s_wcd.logfile ) return; - fprintf( s_wcd.logfile, pMsg ); - fflush( s_wcd.logfile ); -} diff --git a/engine/common/system.h b/engine/common/system.h index 3c4b58cc..c59b3f87 100644 --- a/engine/common/system.h +++ b/engine/common/system.h @@ -86,7 +86,7 @@ void Sys_Error( const char *error, ... ); qboolean Sys_LoadLibrary( dll_info_t *dll ); void* Sys_GetProcAddress( dll_info_t *dll, const char* name ); qboolean Sys_FreeLibrary( dll_info_t *dll ); -void Sys_ParseCommandLine( int argc, char **argv ); +void Sys_ParseCommandLine( int argc, const char **argv ); void Sys_MergeCommandLine( void ); void Sys_SetupCrashHandler( void ); void Sys_RestoreCrashHandler( void ); @@ -94,7 +94,6 @@ void Sys_SetClipboardData( const byte *buffer, size_t size ); #define Sys_GetParmFromCmdLine( parm, out ) _Sys_GetParmFromCmdLine( parm, out, sizeof( out )) qboolean _Sys_GetParmFromCmdLine( char *parm, char *out, size_t size ); void Sys_ShellExecute( const char *path, const char *parms, qboolean exit ); -const char *Sys_GetMachineKey( int *nLength ); void Sys_SendKeyEvents( void ); void Sys_Print( const char *pMsg ); void Sys_PrintLog( const char *pMsg ); @@ -105,14 +104,26 @@ void Sys_Quit( void ); // // sys_con.c // -void Con_ShowConsole( qboolean show ); -void Con_WinPrint( const char *pMsg ); -void Con_InitConsoleCommands( void ); -void Con_CreateConsole( void ); -void Con_DestroyConsole( void ); -void Con_RegisterHotkeys( void ); -void Con_DisableInput( void ); -char *Con_Input( void ); +char *Sys_Input( void ); +void Sys_DestroyConsole( void ); +void Sys_CloseLog( void ); +void Sys_InitLog( void ); +void Sys_PrintLog( const char *pMsg ); +int Sys_LogFileNo( void ); + +// +// con_win.c +// +#ifdef _WIN32 +void Wcon_ShowConsole( qboolean show ); +void Wcon_Print( const char *pMsg ); +void Wcon_Init( void ); +void Wcon_CreateConsole( void ); +void Wcon_DestroyConsole( void ); +void Wcon_DisableInput( void ); +void Wcon_Clear( void ); +char *Wcon_Input( void ); +#endif // text messages #define Msg Con_Printf diff --git a/engine/menu_int.h b/engine/menu_int.h index bbc93ab0..f0f1103d 100644 --- a/engine/menu_int.h +++ b/engine/menu_int.h @@ -164,6 +164,13 @@ typedef struct ui_enginefuncs_s const char *(*pfnGetModeString)( int vid_mode ); } ui_enginefuncs_t; +typedef struct ui_textfuncs_s { + void (*pfnEnableTextInput)( int enable ); + int (*pfnUtfProcessChar) ( int ch ); + int (*pfnUtfMoveLeft) ( char *str, int pos ); + int (*pfnUtfMoveRight) ( char *str, int pos, int length ); +} ui_textfuncs_t; + typedef struct { int (*pfnVidInit)( void ); @@ -186,4 +193,11 @@ typedef struct typedef int (*MENUAPI)( UI_FUNCTIONS *pFunctionTable, ui_enginefuncs_t* engfuncs, ui_globalvars_t *pGlobals ); -#endif//MENU_INT_H \ No newline at end of file +typedef int (*UITEXTAPI)( ui_textfuncs_t* engfuncs ); + +typedef void (*ADDTOUCHBUTTONTOLIST)( const char *name, const char *texture, const char *command, unsigned char *color, int flags ); + +#define PLATFORM_UPDATE_PAGE "PlatformUpdatePage" +#define GENERIC_UPDATE_PAGE "GenericUpdatePage" + +#endif//MENU_INT_H diff --git a/engine/platform/win32/win_con.c b/engine/platform/win32/win_con.c index 7acba919..92b982b5 100644 --- a/engine/platform/win32/win_con.c +++ b/engine/platform/win32/win_con.c @@ -56,12 +56,11 @@ typedef struct // log stuff qboolean log_active; char log_path[MAX_SYSPATH]; - FILE *logfile; } WinConData; static WinConData s_wcd; -void Con_ShowConsole( qboolean show ) +void Wcon_ShowConsole( qboolean show ) { if( !s_wcd.hWnd || show == s_wcd.status ) return; @@ -75,21 +74,21 @@ void Con_ShowConsole( qboolean show ) else ShowWindow( s_wcd.hWnd, SW_HIDE ); } -void Con_DisableInput( void ) +void Wcon_DisableInput( void ) { if( host.type != HOST_DEDICATED ) return; SendMessage( s_wcd.hwndButtonSubmit, WM_ENABLE, 0, 0 ); SendMessage( s_wcd.hwndInputLine, WM_ENABLE, 0, 0 ); } -void Con_SetInputText( const char *inputText ) +void Wcon_SetInputText( const char *inputText ) { if( host.type != HOST_DEDICATED ) return; SetWindowText( s_wcd.hwndInputLine, inputText ); SendMessage( s_wcd.hwndInputLine, EM_SETSEL, Q_strlen( inputText ), -1 ); } -static void Con_Clear_f( void ) +static void Wcon_Clear_f( void ) { if( host.type != HOST_DEDICATED ) return; SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 ); @@ -97,7 +96,7 @@ static void Con_Clear_f( void ) UpdateWindow( s_wcd.hwndBuffer ); } -static int Con_KeyEvent( int key, qboolean down ) +static int Wcon_KeyEvent( int key, qboolean down ) { char inputBuffer[1024]; @@ -109,24 +108,24 @@ static int Con_KeyEvent( int key, qboolean down ) case VK_TAB: GetWindowText( s_wcd.hwndInputLine, inputBuffer, sizeof( inputBuffer )); Cmd_AutoComplete( inputBuffer ); - Con_SetInputText( inputBuffer ); + Wcon_SetInputText( inputBuffer ); return 1; case VK_DOWN: if( s_wcd.historyLine == s_wcd.nextHistoryLine ) return 0; s_wcd.historyLine++; - Con_SetInputText( s_wcd.historyLines[s_wcd.historyLine % COMMAND_HISTORY] ); + Wcon_SetInputText( s_wcd.historyLines[s_wcd.historyLine % COMMAND_HISTORY] ); return 1; case VK_UP: if( s_wcd.nextHistoryLine - s_wcd.historyLine < COMMAND_HISTORY && s_wcd.historyLine > 0 ) s_wcd.historyLine--; - Con_SetInputText( s_wcd.historyLines[s_wcd.historyLine % COMMAND_HISTORY] ); + Wcon_SetInputText( s_wcd.historyLines[s_wcd.historyLine % COMMAND_HISTORY] ); return 1; } return 0; } -static long _stdcall Con_WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +static long _stdcall Wcon_WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch( uMsg ) { @@ -172,7 +171,7 @@ static long _stdcall Con_WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lP return DefWindowProc( hWnd, uMsg, wParam, lParam ); } -long _stdcall Con_InputLineProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +long _stdcall Wcon_InputLineProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { char inputBuffer[1024]; @@ -187,16 +186,16 @@ long _stdcall Con_InputLineProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa break; case WM_SYSKEYDOWN: case WM_KEYDOWN: - if( Con_KeyEvent( LOWORD( wParam ), true )) + if( Wcon_KeyEvent( LOWORD( wParam ), true )) return 0; break; case WM_SYSKEYUP: case WM_KEYUP: - if( Con_KeyEvent( LOWORD( wParam ), false )) + if( Wcon_KeyEvent( LOWORD( wParam ), false )) return 0; break; case WM_CHAR: - if( Con_KeyEvent( wParam, true )) + if( Wcon_KeyEvent( wParam, true )) return 0; if( wParam == 13 && host.status != HOST_ERR_FATAL ) { @@ -232,7 +231,7 @@ Con_WinPrint print into window console ================ */ -void Con_WinPrint( const char *pMsg ) +void Wcon_WinPrint( const char *pMsg ) { size_t len = Q_strlen( pMsg ); @@ -259,7 +258,7 @@ Con_CreateConsole create win32 console ================ */ -void Con_CreateConsole( void ) +void Wcon_CreateConsole( void ) { HDC hDC; WNDCLASS wc; @@ -345,7 +344,7 @@ void Con_CreateConsole( void ) s_wcd.hwndButtonSubmit = CreateWindow( "button", NULL, BS_PUSHBUTTON|WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON, 552, 367, 87, 25, s_wcd.hWnd, (HMENU)SUBMIT_ID, host.hInst, NULL ); SendMessage( s_wcd.hwndButtonSubmit, WM_SETTEXT, 0, ( LPARAM ) "submit" ); - } + } // create the scrollbuffer GetClientRect( s_wcd.hWnd, &rect ); @@ -355,7 +354,7 @@ void Con_CreateConsole( void ) if( host.type == HOST_DEDICATED ) { - s_wcd.SysInputLineWndProc = (WNDPROC)SetWindowLong( s_wcd.hwndInputLine, GWL_WNDPROC, (long)Con_InputLineProc ); + s_wcd.SysInputLineWndProc = (WNDPROC)SetWindowLong( s_wcd.hwndInputLine, GWL_WNDPROC, (long)Wcon_InputLineProc ); SendMessage( s_wcd.hwndInputLine, WM_SETFONT, ( WPARAM )s_wcd.hfBufferFont, 0 ); } @@ -382,7 +381,7 @@ Con_InitConsoleCommands register console commands (dedicated only) ================ */ -void Con_InitConsoleCommands( void ) +void Wcon_InitConsoleCommands( void ) { if( host.type != HOST_DEDICATED ) return; Cmd_AddCommand( "clear", Con_Clear_f, "clear console history" ); @@ -395,7 +394,7 @@ Con_DestroyConsole destroy win32 console ================ */ -void Con_DestroyConsole( void ) +void Wcon_DestroyConsole( void ) { // last text message into console or log MsgDev( D_NOTE, "Sys_FreeLibrary: Unloading xash.dll\n" ); @@ -440,7 +439,7 @@ Con_Input returned input text ================ */ -char *Con_Input( void ) +char *Wcon_Input( void ) { if( s_wcd.consoleText[0] == 0 ) return NULL; @@ -458,7 +457,7 @@ Con_SetFocus change focus to console hwnd ================ */ -void Con_RegisterHotkeys( void ) +void Wcon_RegisterHotkeys( void ) { SetFocus( s_wcd.hWnd );