Offer post-crash safe settings on a per-mod basis

Offer to restore settings when loading a mod that crashed, not the first
mod that gets loaded after a crash. Before the first mod loaded (usually
baseq3) would get the option even if missionpack or some other mod crashed.

- Make pid files separate for each fs_game.
- Remove/write pid every time switching fs_game.
- Create path before writing pid file otherwise it fails on first run.
- Show mod description.txt or fs_game instead of engine name in abnormal
  exit message.
- Check com_fullyInitialized in Com_Error before removing PID,
  otherwise "ioquake3 --version" segfaults when accessing fs_gamevar->string
  (plus not fully initialized isn't really a normal shutdown).
This commit is contained in:
Zack Middleton 2016-10-09 16:55:36 -05:00
parent 1246d16834
commit 755b2f38f0
4 changed files with 87 additions and 41 deletions

View File

@ -2776,17 +2776,7 @@ void Com_Init( char *commandLine ) {
Sys_Init(); Sys_Init();
if( Sys_WritePIDFile( ) ) { Sys_InitPIDFile( FS_GetCurrentGameDir() );
#ifndef DEDICATED
const char *message = "The last time " CLIENT_WINDOW_TITLE " ran, "
"it didn't exit properly. This may be due to inappropriate video "
"settings. Would you like to start with \"safe\" video settings?";
if( Sys_Dialog( DT_YES_NO, message, "Abnormal Exit" ) == DR_YES ) {
Cvar_Set( "com_abnormalExit", "1" );
}
#endif
}
// Pick a random port value // Pick a random port value
Com_RandomBytes( (byte*)&qport, sizeof(int) ); Com_RandomBytes( (byte*)&qport, sizeof(int) );

View File

@ -2482,6 +2482,33 @@ static char** Sys_ConcatenateFileLists( char **list0, char **list1 )
return cat; return cat;
} }
/*
================
FS_GetModDescription
================
*/
void FS_GetModDescription( const char *modDir, char *description, int descriptionLen ) {
fileHandle_t descHandle;
char descPath[MAX_QPATH];
int nDescLen;
FILE *file;
Com_sprintf( descPath, sizeof ( descPath ), "%s/description.txt", modDir );
nDescLen = FS_SV_FOpenFileRead( descPath, &descHandle );
if ( nDescLen > 0 && descHandle ) {
file = FS_FileForHandle(descHandle);
Com_Memset( description, 0, descriptionLen );
nDescLen = fread(description, 1, descriptionLen, file);
if (nDescLen >= 0) {
description[nDescLen] = '\0';
}
FS_FCloseFile(descHandle);
} else {
Q_strncpyz( description, modDir, descriptionLen );
}
}
/* /*
================ ================
FS_GetModList FS_GetModList
@ -2496,8 +2523,7 @@ int FS_GetModList( char *listbuf, int bufsize ) {
char **pFiles = NULL; char **pFiles = NULL;
char **pPaks = NULL; char **pPaks = NULL;
char *name, *path; char *name, *path;
char descPath[MAX_OSPATH]; char description[MAX_OSPATH];
fileHandle_t descHandle;
int dummy; int dummy;
char **pFiles0 = NULL; char **pFiles0 = NULL;
@ -2571,28 +2597,13 @@ int FS_GetModList( char *listbuf, int bufsize ) {
nLen = strlen(name) + 1; nLen = strlen(name) + 1;
// nLen is the length of the mod path // nLen is the length of the mod path
// we need to see if there is a description available // we need to see if there is a description available
descPath[0] = '\0'; FS_GetModDescription( name, description, sizeof( description ) );
strcpy(descPath, name); nDescLen = strlen(description) + 1;
strcat(descPath, "/description.txt");
nDescLen = FS_SV_FOpenFileRead( descPath, &descHandle );
if ( nDescLen > 0 && descHandle) {
FILE *file;
file = FS_FileForHandle(descHandle);
Com_Memset( descPath, 0, sizeof( descPath ) );
nDescLen = fread(descPath, 1, 48, file);
if (nDescLen >= 0) {
descPath[nDescLen] = '\0';
}
FS_FCloseFile(descHandle);
} else {
strcpy(descPath, name);
}
nDescLen = strlen(descPath) + 1;
if (nTotal + nLen + 1 + nDescLen + 1 < bufsize) { if (nTotal + nLen + 1 + nDescLen + 1 < bufsize) {
strcpy(listbuf, name); strcpy(listbuf, name);
listbuf += nLen; listbuf += nLen;
strcpy(listbuf, descPath); strcpy(listbuf, description);
listbuf += nDescLen; listbuf += nDescLen;
nTotal += nLen + nDescLen; nTotal += nLen + nDescLen;
nMods++; nMods++;
@ -3999,6 +4010,9 @@ void FS_Restart( int checksumFeed ) {
} }
if ( Q_stricmp(fs_gamedirvar->string, lastValidGame) ) { if ( Q_stricmp(fs_gamedirvar->string, lastValidGame) ) {
Sys_RemovePIDFile( lastValidGame );
Sys_InitPIDFile( fs_gamedirvar->string );
// skip the q3config.cfg if "safe" is on the command line // skip the q3config.cfg if "safe" is on the command line
if ( !Com_SafeMode() ) { if ( !Com_SafeMode() ) {
Cbuf_AddText ("exec " Q3CONFIG_CFG "\n"); Cbuf_AddText ("exec " Q3CONFIG_CFG "\n");

View File

@ -637,6 +637,8 @@ int FS_LoadStack( void );
int FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize ); int FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
int FS_GetModList( char *listbuf, int bufsize ); int FS_GetModList( char *listbuf, int bufsize );
void FS_GetModDescription( const char *modDir, char *description, int descriptionLen );
fileHandle_t FS_FOpenFileWrite( const char *qpath ); fileHandle_t FS_FOpenFileWrite( const char *qpath );
fileHandle_t FS_FOpenFileAppend( const char *filename ); fileHandle_t FS_FOpenFileAppend( const char *filename );
fileHandle_t FS_FCreateOpenPipeFile( const char *filename ); fileHandle_t FS_FCreateOpenPipeFile( const char *filename );
@ -1145,7 +1147,8 @@ typedef enum
dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *title ); dialogResult_t Sys_Dialog( dialogType_t type, const char *message, const char *title );
qboolean Sys_WritePIDFile( void ); void Sys_RemovePIDFile( const char *gamedir );
void Sys_InitPIDFile( const char *gamedir );
/* This is based on the Adaptive Huffman algorithm described in Sayood's Data /* This is based on the Adaptive Huffman algorithm described in Sayood's Data
* Compression book. The ranks are not actually stored, but implicitly defined * Compression book. The ranks are not actually stored, but implicitly defined

View File

@ -167,16 +167,29 @@ char *Sys_GetClipboardData(void)
Sys_PIDFileName Sys_PIDFileName
================= =================
*/ */
static char *Sys_PIDFileName( void ) static char *Sys_PIDFileName( const char *gamedir )
{ {
const char *homePath = Cvar_VariableString( "fs_homepath" ); const char *homePath = Cvar_VariableString( "fs_homepath" );
if( *homePath != '\0' ) if( *homePath != '\0' )
return va( "%s/%s", homePath, PID_FILENAME ); return va( "%s/%s/%s", homePath, gamedir, PID_FILENAME );
return NULL; return NULL;
} }
/*
=================
Sys_RemovePIDFile
=================
*/
void Sys_RemovePIDFile( const char *gamedir )
{
char *pidFile = Sys_PIDFileName( gamedir );
if( pidFile != NULL )
remove( pidFile );
}
/* /*
================= =================
Sys_WritePIDFile Sys_WritePIDFile
@ -184,9 +197,9 @@ Sys_WritePIDFile
Return qtrue if there is an existing stale PID file Return qtrue if there is an existing stale PID file
================= =================
*/ */
qboolean Sys_WritePIDFile( void ) static qboolean Sys_WritePIDFile( const char *gamedir )
{ {
char *pidFile = Sys_PIDFileName( ); char *pidFile = Sys_PIDFileName( gamedir );
FILE *f; FILE *f;
qboolean stale = qfalse; qboolean stale = qfalse;
@ -212,6 +225,10 @@ qboolean Sys_WritePIDFile( void )
stale = qtrue; stale = qtrue;
} }
if( FS_CreatePath( pidFile ) ) {
return 0;
}
if( ( f = fopen( pidFile, "w" ) ) != NULL ) if( ( f = fopen( pidFile, "w" ) ) != NULL )
{ {
fprintf( f, "%d", Sys_PID( ) ); fprintf( f, "%d", Sys_PID( ) );
@ -223,6 +240,31 @@ qboolean Sys_WritePIDFile( void )
return stale; return stale;
} }
/*
=================
Sys_InitPIDFile
=================
*/
void Sys_InitPIDFile( const char *gamedir ) {
if( Sys_WritePIDFile( gamedir ) ) {
#ifndef DEDICATED
char message[1024];
char modName[MAX_OSPATH];
FS_GetModDescription( gamedir, modName, sizeof ( modName ) );
Q_CleanStr( modName );
Com_sprintf( message, sizeof (message), "The last time %s ran, "
"it didn't exit properly. This may be due to inappropriate video "
"settings. Would you like to start with \"safe\" video settings?", modName );
if( Sys_Dialog( DT_YES_NO, message, "Abnormal Exit" ) == DR_YES ) {
Cvar_Set( "com_abnormalExit", "1" );
}
#endif
}
}
/* /*
================= =================
Sys_Exit Sys_Exit
@ -238,13 +280,10 @@ static __attribute__ ((noreturn)) void Sys_Exit( int exitCode )
SDL_Quit( ); SDL_Quit( );
#endif #endif
if( exitCode < 2 ) if( exitCode < 2 && com_fullyInitialized )
{ {
// Normal exit // Normal exit
char *pidFile = Sys_PIDFileName( ); Sys_RemovePIDFile( FS_GetCurrentGameDir() );
if( pidFile != NULL )
remove( pidFile );
} }
NET_Shutdown( ); NET_Shutdown( );