diff --git a/src/openttd.cpp b/src/openttd.cpp index cf4709c5d2..a8f08bb9c4 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -84,6 +84,7 @@ #include "water.h" #include +#include #include "table/strings.h" @@ -1309,8 +1310,51 @@ static bool InitializeWindowsAndCaches() return true; } +/** + * Signal handler used to give a user a more useful report for crashes during + * the savegame loading process; especially when there's problems with the + * NewGRFs that are required by the savegame. + * @param unused well... unused + */ +void CDECL HandleSavegameLoadCrash(int unused) +{ + char buffer[8192]; + char *p = buffer; + p += seprintf(p, lastof(buffer), + "Loading your savegame caused OpenTTD to crash.\n" + "This is most likely caused by a missing NewGRF or a NewGRF that has been\n" + "loaded as replacement for a missing NewGRF. OpenTTD cannot easily\n" + "determine whether a replacement NewGRF is of a newer or older version.\n" + "It will load a NewGRF with the same GRF ID as the missing NewGRF. This\n" + "means that if the author makes incompatible NewGRFs with the same GRF ID\n" + "OpenTTD cannot magically do the right thing. In most cases OpenTTD will\n" + "load the savegame and not crash, but this is an exception.\n" + "Please load the savegame with the appropriate NewGRFs. When loading a\n" + "savegame still crashes when all NewGRFs are found you should file a\n" + "bug report. The missing NewGRFs are:\n"); + + for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { + if (HasBit(c->flags, GCF_COMPATIBLE)) { + char buf[40]; + md5sumToString(buf, lastof(buf), c->md5sum); + p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s. Tried another NewGRF with same GRF ID\n", BSWAP32(c->grfid), c->filename, buf); + } + if (c->status == GCS_NOT_FOUND) { + char buf[40]; + md5sumToString(buf, lastof(buf), c->md5sum); + p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s\n", BSWAP32(c->grfid), c->filename, buf); + } + } + + ShowInfo(buffer); +} + bool AfterLoadGame() { + typedef void (CDECL *SignalHandlerPointer)(int); + SignalHandlerPointer prev_segfault = signal(SIGSEGV, HandleSavegameLoadCrash); + SignalHandlerPointer prev_abort = signal(SIGABRT, HandleSavegameLoadCrash); + TileIndex map_size = MapSize(); Company *c; @@ -1421,6 +1465,9 @@ bool AfterLoadGame() GRFListCompatibility gcf_res = IsGoodGRFConfigList(); if (_networking && gcf_res != GLC_ALL_GOOD) { SetSaveLoadError(STR_NETWORK_ERR_CLIENT_NEWGRF_MISMATCH); + /* Restore the signals */ + signal(SIGSEGV, prev_segfault); + signal(SIGABRT, prev_abort); return false; } @@ -1468,6 +1515,9 @@ bool AfterLoadGame() /* make sure there is a town in the game */ if (_game_mode == GM_NORMAL && !ClosestTownFromTile(0, UINT_MAX)) { SetSaveLoadError(STR_NO_TOWN_IN_SCENARIO); + /* Restore the signals */ + signal(SIGSEGV, prev_segfault); + signal(SIGABRT, prev_abort); return false; } @@ -1529,6 +1579,9 @@ bool AfterLoadGame() st = STATION_BUS; SetStationGfx(t, gfx - 170 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET); } else { + /* Restore the signals */ + signal(SIGSEGV, prev_segfault); + signal(SIGABRT, prev_abort); return false; } SB(_m[t].m6, 3, 3, st); @@ -2647,7 +2700,11 @@ bool AfterLoadGame() GamelogPrintDebug(1); - return InitializeWindowsAndCaches(); + bool ret = InitializeWindowsAndCaches(); + /* Restore the signals */ + signal(SIGSEGV, prev_segfault); + signal(SIGABRT, prev_abort); + return ret; } /** Reload all NewGRF files during a running game. This is a cut-down diff --git a/src/win32.cpp b/src/win32.cpp index 27be2d8a1e..98d6260943 100644 --- a/src/win32.cpp +++ b/src/win32.cpp @@ -934,9 +934,9 @@ void ShowInfo(const char *str) } else { bool old; #if defined(UNICODE) - /* We need to put the text in a seperate buffer because the default - * buffer in MB_TO_WIDE might not be large enough (512 chars) */ - wchar_t help_msgW[4096]; + /* We need to put the text in a seperate buffer because the default + * buffer in MB_TO_WIDE might not be large enough (512 chars) */ + wchar_t help_msgW[8192]; #endif ReleaseCapture(); _left_button_clicked =_left_button_down = false;