From e6a2c207de9ca2f2e21dbede197029c0b02d4896 Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Mon, 13 Jun 2022 03:42:20 +0300 Subject: [PATCH] engine: implement change game with execv in-engine. For now it enabled for all platforms, will probably disabled selectively --- engine/common/host.c | 6 ++-- engine/common/system.c | 69 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/engine/common/host.c b/engine/common/host.c index d3ca35b8..fcac92dd 100644 --- a/engine/common/host.c +++ b/engine/common/host.c @@ -305,7 +305,9 @@ void Host_NewInstance( const char *name, const char *finalmsg ) host.change_game = true; Q_strncpy( host.finalmsg, finalmsg, sizeof( host.finalmsg )); - pChangeGame( name ); // call from hl.exe + + if( !Platform_ChangeGame( name )) + pChangeGame( name ); // call from hl.exe } /* @@ -868,7 +870,7 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha host.enabledll = !Sys_CheckParm( "-nodll" ); - host.change_game = bChangeGame; + host.change_game = bChangeGame || Sys_CheckParm( "-changegame" ); host.config_executed = false; host.status = HOST_INIT; // initialzation started diff --git a/engine/common/system.c b/engine/common/system.c index c41854e8..f154f7ee 100644 --- a/engine/common/system.c +++ b/engine/common/system.c @@ -32,9 +32,14 @@ GNU General Public License for more details. #endif #endif +#if XASH_WIN32 +#include +#endif + #include "menu_int.h" // _UPDATE_PAGE macro #include "library.h" +#include "whereami.h" qboolean error_on_exit = false; // arg for exit(); #define DEBUG_BREAK @@ -539,3 +544,67 @@ void Sys_Print( const char *pMsg ) Rcon_Print( pMsg ); } + +/* +================== +Sys_ChangeGame + +This is a special function + +Here we restart engine with new -game parameter +but since engine will be unloaded during this call +it explicitly doesn't use internal allocation or string copy utils +================== +*/ +qboolean Sys_ChangeGame( const char *gamedir ) +{ + int i = 0; + qboolean replacedArg = false; + size_t exelen; + char *exe, **newargs; + + // don't use engine allocation utils here + // they will be freed after Host_Shutdown + newargs = calloc( host.argc + 4, sizeof( *newargs )); + while( i < host.argc ) + { + newargs[i] = strdup( host.argv[i] ); + + // replace existing -game argument + if( !Q_stricmp( newargs[i], "-game" )) + { + newargs[i + 1] = strdup( gamedir ); + replacedArg = true; + i += 2; + } + else i++; + } + + if( !replacedArg ) + { + newargs[i++] = strdup( "-game" ); + newargs[i++] = strdup( gamedir ); + } + + newargs[i++] = strdup( "-changegame" ); + newargs[i] = NULL; + + exelen = wai_getExecutablePath( NULL, 0, NULL ); + exe = malloc( exelen + 1 ); + wai_getExecutablePath( exe, exelen, NULL ); + exe[exelen] = 0; + + Host_Shutdown(); + + execv( exe, newargs ); + + // if execv returned, it's probably an error + printf( "execv failed: %s", strerror( errno )); + + for( ; i >= 0; i-- ) + free( newargs[i] ); + free( newargs ); + free( exe ); + + return false; +}