From 0fb5083cbb78ae8752981c86fb7d11621b97b443 Mon Sep 17 00:00:00 2001 From: Carsten Teibes Date: Sun, 26 May 2024 01:10:14 +0200 Subject: [PATCH] Add custom error display for platforms Implemented currently for 3DS and SDL2. Switch and Vita are possible, however an Error report might be generated on Switch (bad, could get send to big N) and for Vita one would need to match framebuffer format and such when dealing with GXM for dialog display. This is not worth currently, since we likely migrate away from vita2d library in the future. Go through platform teardown code. While this may not work for every case (e.g. out of memory on Wii), this should be cleaner. --- src/baseui.h | 8 ++++++++ src/output.cpp | 27 +++++++++++------------- src/platform/3ds/main.cpp | 24 ++++++++++++++-------- src/platform/3ds/ui.cpp | 12 +++++++++++ src/platform/3ds/ui.h | 1 + src/platform/emscripten/main.cpp | 3 ++- src/platform/psvita/main.cpp | 10 +++++++-- src/platform/sdl/main.cpp | 3 ++- src/platform/sdl/sdl2_ui.cpp | 18 ++++++++++++++++ src/platform/sdl/sdl2_ui.h | 1 + src/platform/switch/main.cpp | 35 +++++++++++++++++++------------- src/platform/wii/main.cpp | 3 ++- src/player.cpp | 6 +++--- src/player.h | 3 +++ 14 files changed, 108 insertions(+), 46 deletions(-) diff --git a/src/baseui.h b/src/baseui.h index 266c3ee4ad..e78775993d 100644 --- a/src/baseui.h +++ b/src/baseui.h @@ -103,6 +103,14 @@ class BaseUi { */ virtual bool ShowCursor(bool /* flag */) { return true; }; + /** + * Outputs the error message in a custom way depending on platform + * + * @param message message string. + * @return wether error has been handled + */ + virtual bool HandleErrorOutput(const std::string & /* message */) { return false; } + /** * Gets if fullscreen mode is active. * diff --git a/src/output.cpp b/src/output.cpp index a12335fe8f..23129d9a1d 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -28,8 +28,6 @@ #include #ifdef EMSCRIPTEN # include "platform/emscripten/interface.h" -#elif defined(__vita__) -# include #endif #include "output.h" @@ -203,10 +201,7 @@ static void HandleErrorOutput(const std::string& err) { BitmapRef surface = DisplayUi->GetDisplaySurface(); surface->FillRect(surface->GetRect(), Color(255, 0, 0, 128)); - std::string error = "Error:\n"; - error += err; - - error += "\n\nEasyRPG Player will close now.\nPress [ENTER] key to exit..."; + std::string error = err + "\nPress [ENTER] key to exit..."; Text::Draw(*surface, 11, 11, *Font::DefaultBitmapFont(), Color(0, 0, 0, 255), error); Text::Draw(*surface, 10, 10, *Font::DefaultBitmapFont(), Color(255, 255, 255, 255), error); @@ -294,16 +289,19 @@ void Output::ToggleLog() { void Output::ErrorStr(std::string const& err) { WriteLog(LogLevel::Error, err); + std::string error = "Error:\n" + err + "\n\nEasyRPG Player will close now."; + static bool recursive_call = false; if (!recursive_call && DisplayUi) { recursive_call = true; - HandleErrorOutput(err); + // Try platform handler first, then global one + if (!DisplayUi->HandleErrorOutput(error)) { + HandleErrorOutput(error); + } DisplayUi.reset(); } else { // Fallback to Console if the display is not ready yet - std::cout << err << std::endl; - std::cout << std::endl; - std::cout << "EasyRPG Player will close now."; + std::cout << error << std::endl; #if defined (PLAYER_NINTENDO) || defined(__vita__) // stdin is non-blocking Game_Clock::SleepFor(5s); @@ -316,11 +314,10 @@ void Output::ErrorStr(std::string const& err) { #endif } - // FIXME: This does not go through platform teardown code -#ifdef __vita__ - sceKernelExitProcess(EXIT_FAILURE); -#endif - exit(EXIT_FAILURE); + Player::exit_code = EXIT_FAILURE; + + // FIXME: No idea how to indicate error from core in libretro + exit(Player::exit_code); } void Output::WarningStr(std::string const& warn) { diff --git a/src/platform/3ds/main.cpp b/src/platform/3ds/main.cpp index 61668fdafd..34e934541e 100644 --- a/src/platform/3ds/main.cpp +++ b/src/platform/3ds/main.cpp @@ -104,6 +104,16 @@ static void LogCallback(LogLevel lvl, std::string const& msg, LogCallbackUserDat } } +void n3dsExit() { + romfsExit(); + stop3DSLink(); + gfxExit(); + + if (old_time_limit != UINT32_MAX) { + APT_SetAppCpuTimeLimit(old_time_limit); + } +} + int main(int argc, char* argv[]) { std::vector args(argv, argv + argc); @@ -174,17 +184,13 @@ int main(int argc, char* argv[]) { args.push_back(ctr_dir); } + // Setup teardown code + atexit(n3dsExit); + // Run Player Player::Init(std::move(args)); Player::Run(); - romfsExit(); - stop3DSLink(); - gfxExit(); - - if (old_time_limit != UINT32_MAX) { - APT_SetAppCpuTimeLimit(old_time_limit); - } - - return EXIT_SUCCESS; + // Close + return Player::exit_code; } diff --git a/src/platform/3ds/ui.cpp b/src/platform/3ds/ui.cpp index ffb8f838d6..ea4472e36e 100644 --- a/src/platform/3ds/ui.cpp +++ b/src/platform/3ds/ui.cpp @@ -452,3 +452,15 @@ void CtrUi::vGetConfig(Game_ConfigVideo& cfg) const { cfg.touch_ui.SetDescription("Toggle the backlight of the bottom screen"); cfg.touch_ui.Set(bottom_state != screen_state::off); } + +bool CtrUi::HandleErrorOutput(const std::string &message) { + errorConf errCnf; + std::string error = Player::GetFullVersionString(); + error += "\n\n" + message; + + errorInit(&errCnf, ERROR_TEXT_WORD_WRAP, CFG_LANGUAGE_EN); + errorText(&errCnf, error.c_str()); + errorDisp(&errCnf); + + return true; +} diff --git a/src/platform/3ds/ui.h b/src/platform/3ds/ui.h index 02cc60cdab..9dc42b7122 100644 --- a/src/platform/3ds/ui.h +++ b/src/platform/3ds/ui.h @@ -54,6 +54,7 @@ class CtrUi final : public BaseUi { void ToggleStretch() override; void ToggleTouchUi() override; void vGetConfig(Game_ConfigVideo& cfg) const override; + bool HandleErrorOutput(const std::string &message) override; #ifdef SUPPORT_AUDIO AudioInterface& GetAudio(); diff --git a/src/platform/emscripten/main.cpp b/src/platform/emscripten/main.cpp index 50f3413839..b20b8f80f5 100644 --- a/src/platform/emscripten/main.cpp +++ b/src/platform/emscripten/main.cpp @@ -87,5 +87,6 @@ extern "C" int main(int argc, char* argv[]) { emscripten_set_main_loop(main_loop, 0, 0); - return EXIT_SUCCESS; + // Close + return Player::exit_code; } diff --git a/src/platform/psvita/main.cpp b/src/platform/psvita/main.cpp index 0c797eae6c..cbe48236ec 100644 --- a/src/platform/psvita/main.cpp +++ b/src/platform/psvita/main.cpp @@ -34,6 +34,10 @@ static void LogCallback(LogLevel lvl, std::string const& msg, LogCallbackUserDat sceClibPrintf("[%s] %s: %s\n", GAME_TITLE, prefix.c_str(), msg.c_str()); } +void VitaExit() { + sceKernelExitProcess(Player::exit_code); +} + int main(int argc, char* argv[]) { std::vector args(argv, argv + argc); @@ -102,11 +106,13 @@ int main(int argc, char* argv[]) { args.push_back(psp2_dir); } + // Setup teardown code + atexit(VitaExit); + // Run Player Player::Init(std::move(args)); Player::Run(); // Close - sceKernelExitProcess(EXIT_SUCCESS); - return EXIT_SUCCESS; + return Player::exit_code; } diff --git a/src/platform/sdl/main.cpp b/src/platform/sdl/main.cpp index 031a542f8e..2183c87c9f 100644 --- a/src/platform/sdl/main.cpp +++ b/src/platform/sdl/main.cpp @@ -86,5 +86,6 @@ extern "C" int main(int argc, char* argv[]) { Player::Init(std::move(args)); Player::Run(); - return EXIT_SUCCESS; + // Close + return Player::exit_code; } diff --git a/src/platform/sdl/sdl2_ui.cpp b/src/platform/sdl/sdl2_ui.cpp index 6e5255166d..2e691332a0 100644 --- a/src/platform/sdl/sdl2_ui.cpp +++ b/src/platform/sdl/sdl2_ui.cpp @@ -674,6 +674,24 @@ bool Sdl2Ui::ShowCursor(bool flag) { return temp_flag; } +bool Sdl2Ui::HandleErrorOutput(const std::string &message) { + std::string title = Player::GetFullVersionString(); + + // Manually Restore window from fullscreen, since message would not be visible otherwise + if ((current_display_mode.flags & SDL_WINDOW_FULLSCREEN_DESKTOP) + == SDL_WINDOW_FULLSCREEN_DESKTOP) { + SDL_SetWindowFullscreen(sdl_window, 0); + SDL_SetWindowSize(sdl_window, 0, 0); + } + + if(SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title.c_str(), + message.c_str(), sdl_window) != 0) { + return false; + } + + return true; +} + void Sdl2Ui::ProcessEvent(SDL_Event &evnt) { switch (evnt.type) { case SDL_WINDOWEVENT: diff --git a/src/platform/sdl/sdl2_ui.h b/src/platform/sdl/sdl2_ui.h index c9543f2aa9..3b8203e9c4 100644 --- a/src/platform/sdl/sdl2_ui.h +++ b/src/platform/sdl/sdl2_ui.h @@ -71,6 +71,7 @@ class Sdl2Ui final : public BaseUi { void ToggleVsync() override; void vGetConfig(Game_ConfigVideo& cfg) const override; Rect GetWindowMetrics() const override; + bool HandleErrorOutput(const std::string &message) override; #ifdef SUPPORT_AUDIO AudioInterface& GetAudio() override; diff --git a/src/platform/switch/main.cpp b/src/platform/switch/main.cpp index d3685cb8be..8ad2881c10 100644 --- a/src/platform/switch/main.cpp +++ b/src/platform/switch/main.cpp @@ -43,12 +43,27 @@ static void LogCallback(LogLevel lvl, std::string const& msg, LogCallbackUserDat } } +void SwitchExit() { + romfsExit(); + + // Close debug log + if (nxlinkSocket >= 0) { + close(nxlinkSocket); + socketExit(); + nxlinkSocket = -1; + } + + // HOS will close us immediately afterwards, if requested by home menu. + // So no further cleanup possible. + appletUnlockExit(); +} + int main(int argc, char* argv[]) { std::vector args(argv, argv + argc); appletLockExit(); - // yuzu/nso + // suyu/nso is_nro = envHasArgv(); Output::SetLogCallback(LogCallback); @@ -85,21 +100,13 @@ int main(int argc, char* argv[]) { } } + // Setup platform teardown code + atexit(SwitchExit); + // Run Player Player::Init(std::move(args)); Player::Run(); - romfsExit(); - - // Close debug log - if (nxlinkSocket >= 0) { - close(nxlinkSocket); - socketExit(); - nxlinkSocket = -1; - } - - // HOS will close us immediately afterwards, if requested by home menu. - // So no further cleanup possible. - appletUnlockExit(); - return EXIT_SUCCESS; + // Close + return Player::exit_code; } diff --git a/src/platform/wii/main.cpp b/src/platform/wii/main.cpp index 13e33fdaaf..2f3d2808b0 100644 --- a/src/platform/wii/main.cpp +++ b/src/platform/wii/main.cpp @@ -114,5 +114,6 @@ extern "C" int main(int argc, char* argv[]) { Player::Init(std::move(args)); Player::Run(); - return EXIT_SUCCESS; + // Close + return Player::exit_code; } diff --git a/src/player.cpp b/src/player.cpp index 5f69eec6ab..d9bd785f9a 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -106,9 +106,9 @@ namespace Player { int menu_offset_y = (screen_height - MENU_HEIGHT) / 2; int message_box_offset_x = (screen_width - MENU_WIDTH) / 2; bool has_custom_resolution = false; - - bool exit_flag; - bool reset_flag; + int exit_code = EXIT_SUCCESS; + bool exit_flag = false; + bool reset_flag = false; bool debug_flag; bool hide_title_flag; int load_game_id; diff --git a/src/player.h b/src/player.h index bf220f91fc..ed6d8022ce 100644 --- a/src/player.h +++ b/src/player.h @@ -312,6 +312,9 @@ namespace Player { /** Set the desired rendering frames per second */ void SetTargetFps(int fps); + /** Exit code (optionally indicting an error) when program terminates. */ + extern int exit_code; + /** Exit flag, if true will exit application on next Player::Update. */ extern bool exit_flag;