From 8dc5d69ef37aafbed88d20a6c9bea8a773fb3363 Mon Sep 17 00:00:00 2001 From: Misa Date: Fri, 6 Aug 2021 20:57:34 -0700 Subject: [PATCH] Do not close game if custom level has assets issues It's quite rude to close the game entirely if there is trouble with assets. Instead, just unload the assets and gracefully return to the title screen. --- desktop_version/src/FileSystemUtils.cpp | 22 ++++++---- desktop_version/src/FileSystemUtils.h | 2 +- desktop_version/src/Game.cpp | 3 ++ desktop_version/src/Game.h | 1 + desktop_version/src/Graphics.cpp | 55 ++++++++++++++----------- desktop_version/src/Graphics.h | 13 +++--- desktop_version/src/Input.cpp | 5 +++ desktop_version/src/Render.cpp | 4 ++ desktop_version/src/Script.cpp | 20 ++++++++- desktop_version/src/UtilityClass.h | 9 ++++ desktop_version/src/editor.cpp | 16 ++++--- desktop_version/src/main.cpp | 14 ++++++- 12 files changed, 118 insertions(+), 46 deletions(-) diff --git a/desktop_version/src/FileSystemUtils.cpp b/desktop_version/src/FileSystemUtils.cpp index e5a3b970..fc6cfa92 100644 --- a/desktop_version/src/FileSystemUtils.cpp +++ b/desktop_version/src/FileSystemUtils.cpp @@ -473,7 +473,9 @@ void FILESYSTEM_loadZip(const char* filename) } } -void FILESYSTEM_mountAssets(const char* path) +void FILESYSTEM_unmountAssets(void); + +bool FILESYSTEM_mountAssets(const char* path) { char filename[MAX_PATH]; char zip_data[MAX_PATH]; @@ -504,10 +506,10 @@ void FILESYSTEM_mountAssets(const char* path) if (!FILESYSTEM_mountAssetsFrom(zip_data)) { - return; + return false; } - graphics.reloadresources(); + MAYBE_FAIL(graphics.reloadresources()); } else if (zip_normal != NULL && endsWith(zip_normal, ".zip")) { @@ -515,10 +517,10 @@ void FILESYSTEM_mountAssets(const char* path) if (!FILESYSTEM_mountAssetsFrom(zip_normal)) { - return; + return false; } - graphics.reloadresources(); + MAYBE_FAIL(graphics.reloadresources()); } else if (FILESYSTEM_exists(dir)) { @@ -526,15 +528,21 @@ void FILESYSTEM_mountAssets(const char* path) if (!FILESYSTEM_mountAssetsFrom(dir)) { - return; + return false; } - graphics.reloadresources(); + MAYBE_FAIL(graphics.reloadresources()); } else { puts("Custom asset directory does not exist"); } + + return true; + +fail: + FILESYSTEM_unmountAssets(); + return false; } void FILESYSTEM_unmountAssets(void) diff --git a/desktop_version/src/FileSystemUtils.h b/desktop_version/src/FileSystemUtils.h index 0074df30..6bb90fb3 100644 --- a/desktop_version/src/FileSystemUtils.h +++ b/desktop_version/src/FileSystemUtils.h @@ -19,7 +19,7 @@ bool FILESYSTEM_isFile(const char* filename); bool FILESYSTEM_isMounted(const char* filename); void FILESYSTEM_loadZip(const char* filename); -void FILESYSTEM_mountAssets(const char *path); +bool FILESYSTEM_mountAssets(const char *path); void FILESYSTEM_unmountAssets(void); bool FILESYSTEM_isAssetMounted(const char* filename); diff --git a/desktop_version/src/Game.cpp b/desktop_version/src/Game.cpp index 506a3591..645f4d0d 100644 --- a/desktop_version/src/Game.cpp +++ b/desktop_version/src/Game.cpp @@ -6477,6 +6477,9 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) option("silence"); menuyoff = 10; break; + case Menu::errorloadinglevel: + option("ok"); + break; } // Automatically center the menu. We must check the width of the menu with the initial horizontal spacing. diff --git a/desktop_version/src/Game.h b/desktop_version/src/Game.h index e1aa4ed2..7f7df630 100644 --- a/desktop_version/src/Game.h +++ b/desktop_version/src/Game.h @@ -35,6 +35,7 @@ namespace Menu youwannaquit, errornostart, errorsavingsettings, + errorloadinglevel, graphicoptions, ed_settings, ed_desc, diff --git a/desktop_version/src/Graphics.cpp b/desktop_version/src/Graphics.cpp index 63927fe1..5cfc25f9 100644 --- a/desktop_version/src/Graphics.cpp +++ b/desktop_version/src/Graphics.cpp @@ -151,6 +151,9 @@ void Graphics::init(void) tiles2_mounted = false; minimap_mounted = false; #endif + + SDL_zeroa(error); + SDL_zeroa(error_title); } void Graphics::destroy(void) @@ -314,24 +317,15 @@ void Graphics::updatetitlecolours(void) else if (grphx.im_##tilesheet->w % tile_square != 0 \ || grphx.im_##tilesheet->h % tile_square != 0) \ { \ - const char* error = "Error: %s.png dimensions not exact multiples of %i!"; \ - char message[128]; \ - const char* error_title = "Error with %s.png"; \ - char message_title[128]; \ + static const char error_fmt[] = "%s.png dimensions not exact multiples of %i!"; \ + static const char error_title_fmt[] = "Error with %s.png"; \ \ - SDL_snprintf(message, sizeof(message), error, #tilesheet, tile_square); \ - SDL_snprintf(message_title, sizeof(message_title), error_title, #tilesheet); \ + SDL_snprintf(error, sizeof(error), error_fmt, #tilesheet, tile_square); \ + SDL_snprintf(error_title, sizeof(error_title), error_title_fmt, #tilesheet); \ \ - puts(message); \ + puts(error); \ \ - SDL_ShowSimpleMessageBox( \ - SDL_MESSAGEBOX_ERROR, \ - message_title, \ - message, \ - NULL \ - ); \ - \ - VVV_exit(1); \ + return false; \ } #define PROCESS_TILESHEET_RENAME(tilesheet, vector, tile_square, extra_code) \ @@ -363,7 +357,7 @@ void Graphics::updatetitlecolours(void) #define PROCESS_TILESHEET(tilesheet, tile_square, extra_code) \ PROCESS_TILESHEET_RENAME(tilesheet, tilesheet, tile_square, extra_code) -void Graphics::Makebfont(void) +bool Graphics::Makebfont(void) { PROCESS_TILESHEET(bfont, 8, { @@ -391,6 +385,8 @@ void Graphics::Makebfont(void) { font_positions.clear(); } + + return true; } int Graphics::bfontlen(uint32_t ch) @@ -405,23 +401,29 @@ int Graphics::bfontlen(uint32_t ch) } } -void Graphics::MakeTileArray(void) +bool Graphics::MakeTileArray(void) { PROCESS_TILESHEET(tiles, 8, {}) PROCESS_TILESHEET(tiles2, 8, {}) PROCESS_TILESHEET(tiles3, 8, {}) PROCESS_TILESHEET(entcolours, 8, {}) + + return true; } -void Graphics::maketelearray(void) +bool Graphics::maketelearray(void) { PROCESS_TILESHEET_RENAME(teleporter, tele, 96, {}) + + return true; } -void Graphics::MakeSpriteArray(void) +bool Graphics::MakeSpriteArray(void) { PROCESS_TILESHEET(sprites, 32, {}) PROCESS_TILESHEET(flipsprites, 32, {}) + + return true; } #undef PROCESS_TILESHEET @@ -3486,17 +3488,17 @@ bool Graphics::onscreen(int t) return (t >= -40 && t <= 280); } -void Graphics::reloadresources(void) +bool Graphics::reloadresources(void) { grphx.destroy(); grphx.init(); destroy(); - MakeTileArray(); - MakeSpriteArray(); - maketelearray(); - Makebfont(); + MAYBE_FAIL(MakeTileArray()); + MAYBE_FAIL(MakeSpriteArray()); + MAYBE_FAIL(maketelearray()); + MAYBE_FAIL(Makebfont()); images.clear(); @@ -3528,6 +3530,11 @@ void Graphics::reloadresources(void) tiles2_mounted = FILESYSTEM_isAssetMounted("graphics/tiles2.png"); minimap_mounted = FILESYSTEM_isAssetMounted("graphics/minimap.png"); #endif + + return true; + +fail: + return false; } Uint32 Graphics::crewcolourreal(int t) diff --git a/desktop_version/src/Graphics.h b/desktop_version/src/Graphics.h index 6e64e5d0..1ec6818d 100644 --- a/desktop_version/src/Graphics.h +++ b/desktop_version/src/Graphics.h @@ -26,7 +26,7 @@ public: int bfontlen(uint32_t ch); int font_idx(uint32_t ch); - void Makebfont(void); + bool Makebfont(void); void drawhuetile(int x, int y, int t); void huetilesetcol(int t); @@ -34,11 +34,11 @@ public: void drawgravityline(int t); - void MakeTileArray(void); + bool MakeTileArray(void); - void MakeSpriteArray(void); + bool MakeSpriteArray(void); - void maketelearray(void); + bool maketelearray(void); void drawcoloredtile(int x, int y, int t, int r, int g, int b); @@ -222,7 +222,7 @@ public: bool onscreen(int t); - void reloadresources(void); + bool reloadresources(void); #ifndef NO_CUSTOM_LEVELS bool tiles1_mounted; bool tiles2_mounted; @@ -357,6 +357,9 @@ public: bool kludgeswnlinewidth; Uint32 crewcolourreal(int t); + + char error[128]; + char error_title[128]; /* for SDL_ShowSimpleMessageBox */ }; #ifndef GRAPHICS_DEFINITION diff --git a/desktop_version/src/Input.cpp b/desktop_version/src/Input.cpp index d61e0fb2..db850484 100644 --- a/desktop_version/src/Input.cpp +++ b/desktop_version/src/Input.cpp @@ -1727,6 +1727,11 @@ static void menuactionpress(void) game.returnmenu(); map.nexttowercolour(); break; + case Menu::errorloadinglevel: + music.playef(11); + game.returnmenu(); + map.nexttowercolour(); + break; default: break; } diff --git a/desktop_version/src/Render.cpp b/desktop_version/src/Render.cpp index d94e4c8d..b5267606 100644 --- a/desktop_version/src/Render.cpp +++ b/desktop_version/src/Render.cpp @@ -1387,6 +1387,10 @@ static void menurender(void) case Menu::errorsavingsettings: graphics.Print( -1, 95, "ERROR: Could not save settings file!", tr, tg, tb, true); break; + case Menu::errorloadinglevel: + graphics.bigprint(-1, 45, "ERROR", tr, tg, tb, true); + graphics.PrintWrap(-1, 65, graphics.error, tr, tg, tb, true, 10, 304); + break; default: break; } diff --git a/desktop_version/src/Script.cpp b/desktop_version/src/Script.cpp index 36c72d18..85419341 100644 --- a/desktop_version/src/Script.cpp +++ b/desktop_version/src/Script.cpp @@ -2634,6 +2634,14 @@ void scriptclass::resetgametomenu(void) game.createmenu(Menu::gameover); } +static void gotoerrorloadinglevel(void) +{ + game.createmenu(Menu::errorloadinglevel); + graphics.fademode = 4; /* start fade in */ + music.currentsong = -1; /* otherwise music.play won't work */ + music.play(6); /* title screen music */ +} + void scriptclass::startgamemode( int t ) { switch(t) @@ -3152,7 +3160,11 @@ void scriptclass::startgamemode( int t ) //Initilise the level //First up, find the start point std::string filename = std::string(ed.ListOfMetaData[game.playcustomlevel].filename); - ed.load(filename); + if (!ed.load(filename)) + { + gotoerrorloadinglevel(); + break; + } ed.findstartpoint(); game.gamestate = GAMEMODE; @@ -3190,7 +3202,11 @@ void scriptclass::startgamemode( int t ) //Initilise the level //First up, find the start point std::string filename = std::string(ed.ListOfMetaData[game.playcustomlevel].filename); - ed.load(filename); + if (!ed.load(filename)) + { + gotoerrorloadinglevel(); + break; + } ed.findstartpoint(); game.gamestate = GAMEMODE; diff --git a/desktop_version/src/UtilityClass.h b/desktop_version/src/UtilityClass.h index 01e8cd3c..b3b6af65 100644 --- a/desktop_version/src/UtilityClass.h +++ b/desktop_version/src/UtilityClass.h @@ -78,6 +78,15 @@ void _VVV_between( # define VVV_fallthrough do { } while (false) /* fallthrough */ #endif +#define MAYBE_FAIL(expr) \ + do \ + { \ + if (!expr) \ + { \ + goto fail; \ + } \ + } \ + while (false) //helperClass class UtilityClass diff --git a/desktop_version/src/editor.cpp b/desktop_version/src/editor.cpp index 03179b82..d26f6357 100644 --- a/desktop_version/src/editor.cpp +++ b/desktop_version/src/editor.cpp @@ -1748,6 +1748,11 @@ void editorclass::switch_enemy(const bool reversed /*= false*/) bool editorclass::load(std::string& _path) { + tinyxml2::XMLDocument doc; + tinyxml2::XMLHandle hDoc(&doc); + tinyxml2::XMLElement* pElem; + tinyxml2::XMLHandle hRoot(NULL); + reset(); static const char *levelDir = "levels/"; @@ -1759,14 +1764,13 @@ bool editorclass::load(std::string& _path) FILESYSTEM_unmountAssets(); if (game.cliplaytest && game.playassets != "") { - FILESYSTEM_mountAssets(game.playassets.c_str()); + MAYBE_FAIL(FILESYSTEM_mountAssets(game.playassets.c_str())); } else { - FILESYSTEM_mountAssets(_path.c_str()); + MAYBE_FAIL(FILESYSTEM_mountAssets(_path.c_str())); } - tinyxml2::XMLDocument doc; if (!FILESYSTEM_loadTiXml2Document(_path.c_str(), doc)) { printf("No level %s to load :(\n", _path.c_str()); @@ -1775,9 +1779,6 @@ bool editorclass::load(std::string& _path) loaded_filepath = _path; - tinyxml2::XMLHandle hDoc(&doc); - tinyxml2::XMLElement* pElem; - tinyxml2::XMLHandle hRoot(NULL); version = 0; { @@ -2040,6 +2041,9 @@ next: version=2; return true; + +fail: + return false; } bool editorclass::save(std::string& _path) diff --git a/desktop_version/src/main.cpp b/desktop_version/src/main.cpp index af7af8c6..a384d534 100644 --- a/desktop_version/src/main.cpp +++ b/desktop_version/src/main.cpp @@ -483,7 +483,19 @@ int main(int argc, char *argv[]) game.init(); // This loads music too... - graphics.reloadresources(); + if (!graphics.reloadresources()) + { + /* Something wrong with the default assets? We can't use them to + * display the error message, and we have to bail. */ + SDL_ShowSimpleMessageBox( + SDL_MESSAGEBOX_ERROR, + graphics.error_title, + graphics.error, + NULL + ); + + VVV_exit(1); + } game.gamestate = PRELOADER;