diff --git a/src/spice2x/avs/core.cpp b/src/spice2x/avs/core.cpp index 8dc9948..b52d623 100644 --- a/src/spice2x/avs/core.cpp +++ b/src/spice2x/avs/core.cpp @@ -1503,7 +1503,8 @@ namespace avs { " * Do NOT copy over random DLLs from another game installation; DLL must match game version\n" "\n" , DLL_NAME, MODULE_PATH.string()) }; - log_fatal("avs-ea3", "{}", info_str); + log_warning("avs-ea3", "{}", info_str); + log_fatal("avs-ea3", "Failed to find critical avs DLL on disk (avs2-core.dll OR {})", DLL_NAME); } } diff --git a/src/spice2x/avs/ea3.cpp b/src/spice2x/avs/ea3.cpp index 2c804c5..acaa37e 100644 --- a/src/spice2x/avs/ea3.cpp +++ b/src/spice2x/avs/ea3.cpp @@ -150,7 +150,9 @@ namespace avs { " * Do NOT copy over random DLLs from another game installation; DLL must match game version\n" "\n" , DLL_NAME, MODULE_PATH.string()) }; - log_fatal("avs-ea3", "{}", info_str); + + log_warning("avs-ea3", "{}", info_str); + log_fatal("avs-ea3", "Failed to find critical ea3 DLL on disk (avs2-ea3.dll OR {})", DLL_NAME); } } diff --git a/src/spice2x/avs/game.cpp b/src/spice2x/avs/game.cpp index adefa8f..084347e 100644 --- a/src/spice2x/avs/game.cpp +++ b/src/spice2x/avs/game.cpp @@ -98,7 +98,7 @@ namespace avs { // ddr gamemdx.dll user error if (avs::game::is_model("MDX") && DLL_NAME == "gamemdx.dll") { - log_fatal( + log_warning( "ddr", "BAD GAME DLL ERROR\n\n" "!!! !!!\n" @@ -107,6 +107,7 @@ namespace avs { "!!! remove -exec argument and try again. !!!\n" "!!! !!!\n" ); + log_fatal("ddr", "BAD GAME DLL ERROR (don't use -exec gamemdx.dll, that's the wrong DLL)"); } // file not found on disk diff --git a/src/spice2x/games/ddr/ddr.cpp b/src/spice2x/games/ddr/ddr.cpp index 6018c71..ec59dd8 100644 --- a/src/spice2x/games/ddr/ddr.cpp +++ b/src/spice2x/games/ddr/ddr.cpp @@ -125,7 +125,7 @@ namespace games::ddr { void DDRGame::pre_attach() { if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("TDX")) { - log_fatal( + log_warning( "ddr", "BAD MODEL NAME ERROR\n\n\n" "!!! model name set to TDX, this is WRONG and will break your game !!!\n" @@ -136,6 +136,8 @@ namespace games::ddr { "!!! !!!\n" "!!! model name set to TDX, this is WRONG and will break your game !!!\n\n\n" ); + + log_fatal("ddr", "BAD MODEL NAME ERROR - TDX specified, should be MDX instead"); } if (!cfg::CONFIGURATOR_STANDALONE && avs::game::DEST[0] == 'U') { diff --git a/src/spice2x/games/iidx/iidx.cpp b/src/spice2x/games/iidx/iidx.cpp index b0372af..9a193f4 100644 --- a/src/spice2x/games/iidx/iidx.cpp +++ b/src/spice2x/games/iidx/iidx.cpp @@ -428,7 +428,7 @@ namespace games::iidx { // check bad model name if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("TDJ")) { - log_fatal( + log_warning( "iidx", "BAD MODEL NAME ERROR\n\n\n" "!!! model name set to TDJ, this is WRONG and will break your game !!!\n" @@ -446,6 +446,8 @@ namespace games::iidx { "!!! !!!\n" "!!! model name set to TDJ, this is WRONG and will break your game !!!\n\n\n" ); + + log_fatal("iidx", "BAD MODEL NAME ERROR - TDJ specified, must be LDJ instead"); } } diff --git a/src/spice2x/games/jb/jb.cpp b/src/spice2x/games/jb/jb.cpp index 7f8fe26..3182f13 100644 --- a/src/spice2x/games/jb/jb.cpp +++ b/src/spice2x/games/jb/jb.cpp @@ -169,7 +169,7 @@ namespace games::jb { const auto current_path = std::filesystem::current_path(); log_misc("jubeat", "current working directory: {}", current_path.string()); if (current_path.parent_path() == current_path.root_path()) { - log_fatal( + log_warning( "jubeat", "\n\nInvalid path error; jubeat cannot run from a directory in the drive root\n" "The game will overflow the stack and silently fail to boot\n\n" @@ -179,6 +179,10 @@ namespace games::jb { "To fix this, create a new directory and move ALL game files there.\n\n" "Your current working directory: {}\n", current_path.string()); + + log_fatal( + "jubeat", + "Invalid path error; jubeat cannot run from a directory in the drive root"); } } } diff --git a/src/spice2x/games/sdvx/sdvx.cpp b/src/spice2x/games/sdvx/sdvx.cpp index ef82d5a..006f572 100644 --- a/src/spice2x/games/sdvx/sdvx.cpp +++ b/src/spice2x/games/sdvx/sdvx.cpp @@ -268,7 +268,7 @@ namespace games::sdvx { AUTO_INSERT_CARD_COOLDOWN = 15.f; // check bad model name if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("UFC")) { - log_fatal( + log_warning( "sdvx", "BAD MODEL NAME ERROR\n\n\n" "!!! model name set to UFC, this is WRONG and will break your game !!!\n" @@ -278,6 +278,9 @@ namespace games::sdvx { "!!! !!!\n" "!!! model name set to UFC, this is WRONG and will break your game !!!\n\n\n" ); + log_fatal( + "sdvx", + "BAD MODEL NAME ERROR - model name set to UFC, must be KFC instead"); } } diff --git a/src/spice2x/launcher/launcher.cpp b/src/spice2x/launcher/launcher.cpp index 7586968..3fc02f3 100644 --- a/src/spice2x/launcher/launcher.cpp +++ b/src/spice2x/launcher/launcher.cpp @@ -299,22 +299,6 @@ int main_implementation(int argc, char *argv[]) { cfg::CONFIGURATOR_TYPE = cfg::ConfigType::Config; cfg_run = true; } - - if (options[launcher::Options::EAmusementEmulation].value_bool() && - options[launcher::Options::ServiceURL].is_active() && - !cfg::CONFIGURATOR_STANDALONE) { - log_fatal( - "launcher", - "BAD EAMUSE SETTINGS ERROR\n\n\n" - "-------------------------------------------------------------------\n" - "WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n" - "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" - "A service URL is set **AND** E-Amusement emulation is enabled.\n" - "Either remove the service URL, or disable E-Amusement emulation.\n" - "Otherwise you may experience problems logging in.\n" - "-------------------------------------------------------------------\n\n\n" - ); - } if (options[launcher::Options::EAmusementEmulation].value_bool()) { avs::ea3::URL_SLASH = 1; easrv_port = 8080; @@ -1318,6 +1302,25 @@ int main_implementation(int argc, char *argv[]) { ); } + if (options[launcher::Options::EAmusementEmulation].value_bool() && + options[launcher::Options::ServiceURL].is_active() && + !cfg::CONFIGURATOR_STANDALONE) { + log_warning( + "launcher", + "BAD EAMUSE SETTINGS ERROR\n\n\n" + "-------------------------------------------------------------------\n" + "WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + "A service URL is set **AND** E-Amusement emulation is enabled.\n" + "Either remove the service URL, or disable E-Amusement emulation.\n" + "Otherwise you may experience problems logging in.\n" + "-------------------------------------------------------------------\n\n\n" + ); + log_fatal( + "launcher", + "BAD EAMUSE SETTINGS ERROR: both -ea and -url are set"); + } + if (options[launcher::Options::FullscreenResolution].is_active()) { std::pair result; if (parse_width_height(options[launcher::Options::FullscreenResolution].value_text(), result)) { @@ -1817,7 +1820,7 @@ int main_implementation(int argc, char *argv[]) { // usage error if (!cfg::CONFIGURATOR_STANDALONE && (!CHECK_DLL_IGNORE_ARCH)) { - log_fatal( + log_warning( "launcher", "module auto detection failed!\n\n" "This usually means one of the following:\n\n" @@ -1825,6 +1828,8 @@ int main_implementation(int argc, char *argv[]) { " 2. XML files in prop directory are malformed or missing, or\n" " 3. You passed in invalid options (usually, path overrides like -exec)\n\n" ); + + log_fatal("launcher", "module auto detection failed, see log.txt for troubleshooting"); } break; diff --git a/src/spice2x/launcher/signal.cpp b/src/spice2x/launcher/signal.cpp index 0ee9146..a0eebe5 100644 --- a/src/spice2x/launcher/signal.cpp +++ b/src/spice2x/launcher/signal.cpp @@ -175,17 +175,8 @@ static LONG WINAPI TopLevelExceptionFilter(struct _EXCEPTION_POINTERS *Exception log_warning("signal", "minidump creation function not available, skipping"); } - // reduce sleep time since we will wait for the user to acknowledge the popup - LOG_FATAL_SLEEP = 1; - - // in 30 seconds, shut down (in case user can't dismiss popup) - const auto f = std::async(std::launch::async, [] { - std::this_thread::sleep_for(std::chrono::seconds(30)); - log_fatal("signal", "end"); - }); - // this will stall all UI threads for this process - deferredlogs::show_popup_for_crash(); + show_popup_for_crash(); log_fatal("signal", "end"); } diff --git a/src/spice2x/util/deferlog.cpp b/src/spice2x/util/deferlog.cpp index 284b1d0..a9f165d 100644 --- a/src/spice2x/util/deferlog.cpp +++ b/src/spice2x/util/deferlog.cpp @@ -2,7 +2,6 @@ #include #include "build/defs.h" -#include "hooks/graphics/graphics.h" #include "deferlog.h" #include "util/logging.h" @@ -73,32 +72,4 @@ namespace deferredlogs { log_warning("troubleshooter", "{}", msg); }); } - - void show_popup_for_crash() { - static std::once_flag shown; - std::call_once(shown, []() { - - // minimize all windows - // only needed because in multi-monitor full screen games, MessageBox fails to show above the game - for (auto &hwnd : GRAPHICS_WINDOWS) { - ShowWindow(hwnd, SW_FORCEMINIMIZE); - } - - const std::string title = "spice2x (" + to_string(VERSION_STRING_CFG) + ") - crash handler"; - std::string text; - text += "Game has crashed.\n\n"; - text += "Check log.txt and look for error messages near the end of file.\n\n"; - text += "Unsure what to do next?\n"; - text += " * update spice2x to the latest version\n"; - text += " * check the FAQ on spice2x wiki on github\n"; - text += " * do NOT screenshot this, instead, share log.txt with someone and ask for help\n\n"; - text += "Press Enter, Esc, Alt+F4, or click OK to exit. Otherwise, game will close in 30 seconds."; - - MessageBox( - nullptr, - text.c_str(), - title.c_str(), - MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST); - }); - } } diff --git a/src/spice2x/util/deferlog.h b/src/spice2x/util/deferlog.h index dd86ab9..1679aa2 100644 --- a/src/spice2x/util/deferlog.h +++ b/src/spice2x/util/deferlog.h @@ -11,5 +11,4 @@ namespace deferredlogs { void defer_error_messages(std::initializer_list messages); void dump_to_logger(bool is_crash=false); - void show_popup_for_crash(); } diff --git a/src/spice2x/util/libutils.cpp b/src/spice2x/util/libutils.cpp index 2cfbaf4..fd31fe2 100644 --- a/src/spice2x/util/libutils.cpp +++ b/src/spice2x/util/libutils.cpp @@ -43,7 +43,8 @@ static inline void load_library_fail(const std::string &file_name, bool fatal) { " b. http://www.dependencywalker.com/ (for old OS) \n" , file_name) }; if (fatal) { - log_fatal("libutils", "{}", info_str); + log_warning("libutils", "{}", info_str); + log_fatal("libutils", "DLL failed to load: {}, see log.txt for troubleshooting", file_name); } else { log_warning("libutils", "{}", info_str); } diff --git a/src/spice2x/util/logging.cpp b/src/spice2x/util/logging.cpp index 7affcaf..6d7e8ac 100644 --- a/src/spice2x/util/logging.cpp +++ b/src/spice2x/util/logging.cpp @@ -1,6 +1,10 @@ -#include "logging.h" +#include +#include +#include -DWORD LOG_FATAL_SLEEP = 10000; +#include "logging.h" +#include "build/defs.h" +#include "hooks/graphics/graphics.h" std::string_view log_get_datetime() { return log_get_datetime(time(nullptr)); @@ -14,3 +18,66 @@ std::string_view log_get_datetime(std::time_t now) { return buf; } + +static void show_popup(const std::string text) { + static std::once_flag shown; + std::call_once(shown, [text]() { + + // minimize all windows + // only needed because in multi-monitor full screen games, MessageBox fails to show above the game + for (auto &hwnd : GRAPHICS_WINDOWS) { + ShowWindow(hwnd, SW_FORCEMINIMIZE); + } + + // schedule a worker to terminate the game in 30 seconds in case user can't dismiss UI + std::atomic_bool cancel_popup = false; + auto worker = std::async(std::launch::async, [&cancel_popup]{ + for (int ms = 300; ms > 0; ms--) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + if (cancel_popup) { + return; + } + } + launcher::stop_subsystems(); + launcher::kill(); + std::terminate(); + }); + + // MessageBox will block until user presses OK + const std::string title = "spice2x (" + to_string(VERSION_STRING_CFG) + ")"; + MessageBox( + nullptr, + text.c_str(), + title.c_str(), + MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST); + + // cancel the worker since the user acknowledged the popup + cancel_popup = true; + }); +} + +void show_popup_for_crash() { + std::string text; + text += "Game has crashed.\n\n"; + text += "Check log.txt and look for error messages near the end of file.\n\n"; + text += "Unsure what to do next?\n"; + text += " * update spice2x to the latest version\n"; + text += " * check the FAQ on spice2x github wiki\n"; + text += " * do NOT screenshot this, instead, share log.txt with someone and ask for help\n\n"; + text += "Press Enter, Esc, Alt+F4, or click OK to exit. Otherwise, game will close in 30 seconds."; + show_popup(text); +} + +void show_popup_for_fatal_error(std::string message) { + std::string text; + text += "A fatal error was encountered. For details, check log.txt.\n\n"; + text += "----------------------------------------------------------\n"; + text += message; + text += "----------------------------------------------------------\n\n"; + text += "Unsure what to do next?\n"; + text += " * update spice2x to the latest version\n"; + text += " * check the FAQ on spice2x github wiki\n"; + text += " * do NOT screenshot this, instead, share log.txt with someone and ask for help\n\n"; + text += "Press Enter, Esc, Alt+F4, or click OK to exit. Otherwise, game will close in 30 seconds."; + show_popup(text); +} \ No newline at end of file diff --git a/src/spice2x/util/logging.h b/src/spice2x/util/logging.h index 402857c..4a059bd 100644 --- a/src/spice2x/util/logging.h +++ b/src/spice2x/util/logging.h @@ -71,22 +71,28 @@ struct fmt::formatter { } }; -extern DWORD LOG_FATAL_SLEEP; +void show_popup_for_crash(); +void show_popup_for_fatal_error(std::string message); // misc log #define LOG_FORMAT(level, module, fmt_str, ...) fmt::format(FMT_COMPILE("{}" fmt_str "\n"), \ fmt_log { std::time(nullptr), level, module }, ## __VA_ARGS__) + +#define LOG_FORMAT_POPUP(module, fmt_str, ...) fmt::format(FMT_COMPILE("{}: " fmt_str "\n"), module, ## __VA_ARGS__) + #define log_misc(module, format_str, ...) logger::push( \ LOG_FORMAT("M", module, format_str, ## __VA_ARGS__), logger::Style::GREY) + #define log_info(module, format_str, ...) logger::push( \ LOG_FORMAT("I", module, format_str, ## __VA_ARGS__), logger::Style::DEFAULT) + #define log_warning(module, format_str, ...) logger::push( \ LOG_FORMAT("W", module, format_str, ## __VA_ARGS__), logger::Style::YELLOW) + #define log_fatal(module, format_str, ...) { \ logger::push(LOG_FORMAT("F", module, format_str, ## __VA_ARGS__), logger::Style::RED); \ - logger::push(LOG_FORMAT("F", "spice", "encountered a fatal error, you can close the window or press ctrl + c"), logger::Style::RED); \ + show_popup_for_fatal_error(LOG_FORMAT_POPUP(module, format_str, ## __VA_ARGS__)); \ launcher::stop_subsystems(); \ - Sleep(LOG_FATAL_SLEEP); \ launcher::kill(); \ std::terminate(); \ } ((void) 0 )