From b940a62f02dcf9a9fe5fb7ddfcc134fcfe48feea Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Fri, 13 Apr 2018 21:28:46 +0300 Subject: [PATCH] host.c port --- engine/common/common.h | 9 ++ engine/common/host.c | 240 +++++++++++++++++++++++++--------------- engine/common/sys_con.c | 4 +- engine/common/sys_win.c | 100 ++++------------- engine/common/system.h | 6 +- 5 files changed, 185 insertions(+), 174 deletions(-) diff --git a/engine/common/common.h b/engine/common/common.h index d554928a..77b92ee8 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -148,6 +148,12 @@ typedef enum HOST_DEDICATED, } instance_t; +#ifdef XASH_DEDICATED +#define Host_IsDedicated() ( true ) +#else +#define Host_IsDedicated() ( host.type == HOST_DEDICATED ) +#endif + #include "system.h" #include "com_model.h" #include "com_strings.h" @@ -446,6 +452,9 @@ typedef struct host_parm_s qboolean config_executed; // a bit who indicated was config.cfg already executed e.g. from valve.rc int sv_cvars_restored; // count of restored server cvars qboolean crashed; // set to true if crashed + qboolean daemonized; + qboolean enabledll; + qboolean textmode; // some settings were changed and needs to global update qboolean userinfo_changed; diff --git a/engine/common/host.c b/engine/common/host.c index b32ad437..f63167f1 100644 --- a/engine/common/host.c +++ b/engine/common/host.c @@ -13,6 +13,22 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ +#ifdef XASH_SDL +#include +#endif // XASH_SDL +#include // va_args +#include // errno +#include // strerror +#ifndef _WIN32 +#include // fork +#include +#include +#include +#endif +#ifdef __EMSCRIPTEN__ +#include +#endif +#include #include "common.h" #include "netchan.h" #include "protocol.h" @@ -22,11 +38,11 @@ GNU General Public License for more details. #include "enginefeatures.h" #include "render_api.h" // decallist_t + typedef void (*pfnChangeGame)( const char *progname ); pfnChangeGame pChangeGame = NULL; -HINSTANCE hCurrent; // hinstance of current .dll -host_parm_t host; // host parms +host_parm_t host; // host parms sysinfo_t SI; CVAR_DEFINE( host_developer, "developer", "0", 0, "engine is in development-mode" ); @@ -275,7 +291,9 @@ void Host_MemStats_f( void ) void Host_Minimize_f( void ) { - if( host.hWnd ) ShowWindow( host.hWnd, SW_MINIMIZE ); +#ifdef XASH_SDL + if( host.hWnd ) SDL_MinimizeWindow( host.hWnd ); +#endif } /* @@ -495,7 +513,9 @@ void Host_Error( const char *error, ... ) if( host.mouse_visible && !CL_IsInMenu( )) { // hide VGUI mouse - while( ShowCursor( false ) >= 0 ); +#ifdef XASH_SDL + SDL_ShowCursor( 0 ); +#endif host.mouse_visible = false; } @@ -588,61 +608,107 @@ static void Host_Crash_f( void ) Host_InitCommon ================= */ -void Host_InitCommon( const char *hostname, qboolean bChangeGame ) +void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bChangeGame ) { - MEMORYSTATUS lpBuffer; char dev_level[4]; - char progname[128]; - char cmdline[128]; - qboolean parse_cmdline = false; - char szTemp[MAX_SYSPATH]; int developer = 0; - string szRootPath; - char *in, *out; + const char *baseDir; - lpBuffer.dwLength = sizeof( MEMORYSTATUS ); - GlobalMemoryStatus( &lpBuffer ); + // some commands may turn engine into infinite loop, + // e.g. xash.exe +game xash -game xash + // so we clear all cmd_args, but leave dbg states as well + Sys_ParseCommandLine( argc, argv ); - if( !GetCurrentDirectory( sizeof( host.rootdir ), host.rootdir )) - Sys_Error( "couldn't determine current directory\n" ); + if( !Sys_CheckParm( "-noch" ) ) + Sys_SetupCrashHandler(); + + // to be accessed later + if( ( host.daemonized = Sys_CheckParm( "-daemonize" ) ) ) + { +#if defined(_POSIX_VERSION) && !defined(XASH_MOBILE_PLATFORM) + pid_t daemon; + + daemon = fork(); + + if( daemon < 0 ) + { + Host_Error( "fork() failed: %s\n", strerror( errno ) ); + } + + if( daemon > 0 ) + { + // parent + MsgDev( D_INFO, "Child pid: %i\n", daemon ); + exit( 0 ); + } + else + { + // don't be closed by parent + if( setsid() < 0 ) + { + Host_Error( "setsid() failed: %s\n", strerror( errno ) ); + } + + // set permissions + umask( 0 ); + + // engine will still use stdin/stdout, + // so just redirect them to /dev/null + close( STDIN_FILENO ); + close( STDOUT_FILENO ); + close( STDERR_FILENO ); + open("/dev/null", O_RDONLY); // becomes stdin + open("/dev/null", O_RDWR); // stdout + open("/dev/null", O_RDWR); // stderr + + // fallthrough + } +#elif defined(XASH_MOBILE_PLATFORM) + Sys_Error( "Can't run in background on mobile platforms!" ); +#else + Sys_Error( "Daemonize not supported on this platform!" ); +#endif + } + + if( ( baseDir = getenv( "XASH3D_BASEDIR" ) ) ) + { + Q_strncpy( host.rootdir, baseDir, sizeof(host.rootdir) ); + } + else + { +#if TARGET_OS_IOS + const char *IOS_GetDocsDir(); + Q_strncpy( host.rootdir, IOS_GetDocsDir(), sizeof(host.rootdir) ); +#elif defined(XASH_SDL) + if( !( baseDir = SDL_GetBasePath() ) ) + Sys_Error( "couldn't determine current directory: %s", SDL_GetError() ); + Q_strncpy( host.rootdir, baseDir, sizeof( host.rootdir ) ); + SDL_free( baseDir ); +#else + if( !getcwd( host.rootdir, sizeof(host.rootdir) ) ) + { + Sys_Error( "couldn't determine current directory: %s", strerror( errno ) ); + host.rootdir[0] = 0; + } +#endif + } if( host.rootdir[Q_strlen( host.rootdir ) - 1] == '/' ) host.rootdir[Q_strlen( host.rootdir ) - 1] = 0; - host.oldFilter = SetUnhandledExceptionFilter( Sys_Crash ); - host.hInst = GetModuleHandle( NULL ); + host.enabledll = !Sys_CheckParm( "-nodll" ); + +#ifdef DLL_LOADER + if( host.enabledll ) + Setup_LDT_Keeper( ); // Must call before creating any thread +#endif + host.change_game = bChangeGame; host.config_executed = false; host.status = HOST_INIT; // initialzation started Memory_Init(); // init memory subsystem - progname[0] = cmdline[0] = '\0'; - in = (char *)hostname; - out = progname; - - while( *in != '\0' ) - { - if( parse_cmdline ) - { - *out++ = *in++; - } - else - { - if( *in == ' ' ) - { - parse_cmdline = true; - *out++ = '\0'; - out = cmdline; - } - else *out++ = *in++; - } - } - *out = '\0'; // write terminator - - Sys_ParseCommandLine( GetCommandLine( ), false ); - SetErrorMode( SEM_FAILCRITICALERRORS ); // no abort/retry/fail errors - host.mempool = Mem_AllocPool( "Zone Engine" ); if( Sys_CheckParm( "-console" )) @@ -663,46 +729,51 @@ void Host_InitCommon( const char *hostname, qboolean bChangeGame ) host.type = HOST_NORMAL; // predict state host.con_showalways = true; - // we can specified custom name, from Sys_NewInstance - if( GetModuleFileName( NULL, szTemp, sizeof( szTemp )) && !host.change_game ) - COM_FileBase( szTemp, SI.exeName ); - - COM_ExtractFilePath( szTemp, szRootPath ); - if( Q_stricmp( host.rootdir, szRootPath )) +#ifdef XASH_DEDICATED + host.type = HOST_DEDICATED; // predict state +#else + if( Sys_CheckParm("-dedicated") || progname[0] == '#' ) { - Q_strncpy( host.rootdir, szRootPath, sizeof( host.rootdir )); - SetCurrentDirectory( host.rootdir ); + host.type = HOST_DEDICATED; } + else + { + host.type = HOST_NORMAL; + } +#endif - if( SI.exeName[0] == '#' ) host.type = HOST_DEDICATED; +#ifdef XASH_SDL + // should work even if it failed + SDL_Init( SDL_INIT_TIMER ); - // determine host type + if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_EVENTS ) ) + { + Sys_Warn( "SDL_Init failed: %s", SDL_GetError() ); + host.type = HOST_DEDICATED; + } + SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0"); +#if defined XASH_GLES && !defined __EMSCRIPTEN__ && !TARGET_OS_IOS + SDL_SetHint( SDL_HINT_OPENGL_ES_DRIVER, "1" ); +#endif +#endif + + if ( !host.rootdir[0] || SetCurrentDirectory( host.rootdir ) != 0) + MsgDev( D_INFO, "%s is working directory now\n", host.rootdir ); + else + Sys_Error( "Changing working directory to %s failed.\n", host.rootdir ); + + Sys_InitLog(); + + // set default gamedir if( progname[0] == '#' ) + progname++; + + Q_strncpy( SI.exeName, progname, sizeof( SI.exeName )); + + if( Host_IsDedicated() ) { - Q_strncpy( SI.basedirName, progname + 1, sizeof( SI.basedirName )); - host.type = HOST_DEDICATED; - } - else Q_strncpy( SI.basedirName, progname, sizeof( SI.basedirName )); + Sys_MergeCommandLine( ); - if( Sys_CheckParm( "-dedicated" )) - host.type = HOST_DEDICATED; - - if( host.type == HOST_DEDICATED ) - { - // check for duplicate dedicated server - host.hMutex = CreateMutex( NULL, 0, "Xash Dedicated Server" ); - - if( !host.hMutex ) - { - MSGBOX( "Dedicated server already running" ); - Sys_Quit(); - return; - } - - Sys_MergeCommandLine( cmdline ); - - CloseHandle( host.hMutex ); - host.hMutex = CreateSemaphore( NULL, 0, 1, "Xash Dedicated Server" ); host.allow_console = true; } else @@ -773,13 +844,13 @@ void Host_FreeCommon( void ) Host_Main ================= */ -int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func ) +int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGame, pfnChangeGame func ) { static double oldtime, newtime; pChangeGame = func; // may be NULL - Host_InitCommon( progname, bChangeGame ); + Host_InitCommon( argc, argv, progname, bChangeGame ); // init commands and vars if( host_developer.value >= DEV_EXTENDED ) @@ -897,13 +968,6 @@ void EXPORT Host_Shutdown( void ) // must be last, console uses this Mem_FreePool( &host.mempool ); - // restore filter - if( host.oldFilter ) SetUnhandledExceptionFilter( host.oldFilter ); + // restore filter + Sys_RestoreCrashHandler(); } - -// main DLL entry point -BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) -{ - hCurrent = hinstDLL; - return TRUE; -} \ No newline at end of file diff --git a/engine/common/sys_con.c b/engine/common/sys_con.c index 8488f97a..b2599e32 100644 --- a/engine/common/sys_con.c +++ b/engine/common/sys_con.c @@ -307,8 +307,6 @@ void Con_CreateConsole( void ) fontsize = 14; } - Sys_InitLog(); - if( !RegisterClass( &wc )) { // print into log @@ -532,4 +530,4 @@ void Sys_PrintLog( const char *pMsg ) if( !s_wcd.logfile ) return; fprintf( s_wcd.logfile, pMsg ); fflush( s_wcd.logfile ); -} \ No newline at end of file +} diff --git a/engine/common/sys_win.c b/engine/common/sys_win.c index ecfeecf0..d9803013 100644 --- a/engine/common/sys_win.c +++ b/engine/common/sys_win.c @@ -192,64 +192,28 @@ Sys_ParseCommandLine ================== */ -void Sys_ParseCommandLine( LPSTR lpCmdLine, qboolean uncensored ) +void Sys_ParseCommandLine( int argc, const char** argv ) { const char *blank = "censored"; - static char commandline[MAX_SYSPATH]; int i; - host.argc = 1; - host.argv[0] = "exe"; + host.argc = argc; + host.argv = argv; - Q_strncpy( commandline, lpCmdLine, Q_strlen( lpCmdLine ) + 1 ); - lpCmdLine = commandline; // to prevent modify original commandline - - while( *lpCmdLine && ( host.argc < MAX_NUM_ARGVS )) - { - while( *lpCmdLine && *lpCmdLine <= ' ' ) - lpCmdLine++; - if( !*lpCmdLine ) break; - - if( *lpCmdLine == '\"' ) - { - // quoted string - lpCmdLine++; - host.argv[host.argc] = lpCmdLine; - host.argc++; - while( *lpCmdLine && ( *lpCmdLine != '\"' )) - lpCmdLine++; - } - else - { - // unquoted word - host.argv[host.argc] = lpCmdLine; - host.argc++; - while( *lpCmdLine && *lpCmdLine > ' ') - lpCmdLine++; - } - - if( *lpCmdLine ) - { - *lpCmdLine = 0; - lpCmdLine++; - } - } - - if( uncensored || !host.change_game ) - return; + if( !host.change_game ) return; for( i = 0; i < host.argc; i++ ) { - // we wan't return to first game - if( !Q_stricmp( "-game", host.argv[i] )) host.argv[i] = (char *)blank; + // we don't want to return to first game + if( !Q_stricmp( "-game", host.argv[i] )) host.argv[i] = (char *)blank; // probably it's timewaster, because engine rejected second change - if( !Q_stricmp( "+game", host.argv[i] )) host.argv[i] = (char *)blank; - // you sure what is map exists in new game? - if( !Q_stricmp( "+map", host.argv[i] )) host.argv[i] = (char *)blank; + else if( !Q_stricmp( "+game", host.argv[i] )) host.argv[i] = (char *)blank; + // you sure that map exists in new game? + else if( !Q_stricmp( "+map", host.argv[i] )) host.argv[i] = (char *)blank; // just stupid action - if( !Q_stricmp( "+load", host.argv[i] )) host.argv[i] = (char *)blank; + else if( !Q_stricmp( "+load", host.argv[i] )) host.argv[i] = (char *)blank; // changelevel beetwen games? wow it's great idea! - if( !Q_stricmp( "+changelevel", host.argv[i] )) host.argv[i] = (char *)blank; + else if( !Q_stricmp( "+changelevel", host.argv[i] )) host.argv[i] = (char *)blank; } } @@ -259,44 +223,18 @@ Sys_MergeCommandLine ================== */ -void Sys_MergeCommandLine( LPSTR lpCmdLine ) +void Sys_MergeCommandLine( ) { - static char commandline[MAX_SYSPATH]; + const char *blank = "censored"; + int i; if( !host.change_game ) return; - Q_strncpy( commandline, lpCmdLine, Q_strlen( lpCmdLine ) + 1 ); - lpCmdLine = commandline; // to prevent modify original commandline - - while( *lpCmdLine && ( host.argc < MAX_NUM_ARGVS )) + for( i = 0; i < host.argc; i++ ) { - while( *lpCmdLine && *lpCmdLine <= ' ' ) - lpCmdLine++; - if( !*lpCmdLine ) break; - - if( *lpCmdLine == '\"' ) - { - // quoted string - lpCmdLine++; - host.argv[host.argc] = lpCmdLine; - host.argc++; - while( *lpCmdLine && ( *lpCmdLine != '\"' )) - lpCmdLine++; - } - else - { - // unquoted word - host.argv[host.argc] = lpCmdLine; - host.argc++; - while( *lpCmdLine && *lpCmdLine > ' ') - lpCmdLine++; - } - - if( *lpCmdLine ) - { - *lpCmdLine = 0; - lpCmdLine++; - } + // second call + if( Host_IsDedicated() && !Q_strnicmp( "+menu_", host.argv[i], 6 )) + host.argv[i] = (char *)blank; } } @@ -656,4 +594,4 @@ void MsgDev( int type, const char *pMsg, ... ) Sys_Print( text ); break; } -} \ No newline at end of file +} diff --git a/engine/common/system.h b/engine/common/system.h index 36561c91..f5cc4d3f 100644 --- a/engine/common/system.h +++ b/engine/common/system.h @@ -85,8 +85,10 @@ 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( LPSTR lpCmdLine, qboolean uncensored ); -void Sys_MergeCommandLine( LPSTR lpCmdLine ); +void Sys_ParseCommandLine( int argc, char **argv ); +void Sys_MergeCommandLine( void ); +void Sys_SetupCrashHandler( void ); +void Sys_RestoreCrashHandler( void ); 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 );