From c9f68901b75c963e816d8421d012c45194a3998b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sat, 1 Apr 2023 10:57:06 +0200 Subject: [PATCH 1/4] Extract `InitNetworkClient` method --- src/engine/client/client.cpp | 84 +++++++++++++++++++----------------- src/engine/client/client.h | 1 + 2 files changed, 45 insertions(+), 40 deletions(-) diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index a4ca7d332..45caf6d00 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -3024,46 +3024,8 @@ void CClient::Run() #endif #ifndef CONF_WEBASM - // open socket - { - NETADDR BindAddr; - if(g_Config.m_Bindaddr[0] == '\0') - { - mem_zero(&BindAddr, sizeof(BindAddr)); - } - else if(net_host_lookup(g_Config.m_Bindaddr, &BindAddr, NETTYPE_ALL) != 0) - { - dbg_msg("client", "The configured bindaddr '%s' cannot be resolved", g_Config.m_Bindaddr); - return; - } - BindAddr.type = NETTYPE_ALL; - for(unsigned int i = 0; i < std::size(m_aNetClient); i++) - { - int &PortRef = i == CONN_MAIN ? g_Config.m_ClPort : i == CONN_DUMMY ? g_Config.m_ClDummyPort : g_Config.m_ClContactPort; - if(PortRef < 1024) // Reject users setting ports that we don't want to use - { - PortRef = 0; - } - BindAddr.port = PortRef; - unsigned RemainingAttempts = 25; - while(BindAddr.port == 0 || !m_aNetClient[i].Open(BindAddr)) - { - if(BindAddr.port != 0) - { - --RemainingAttempts; - if(RemainingAttempts == 0) - { - if(g_Config.m_Bindaddr[0]) - dbg_msg("client", "Could not open network client, try changing or unsetting the bindaddr '%s'", g_Config.m_Bindaddr); - else - dbg_msg("client", "Could not open network client"); - return; - } - } - BindAddr.port = (secure_rand() % 64511) + 1024; - } - } - } + if(!InitNetworkClient()) + return; #endif // init font rendering @@ -3421,6 +3383,48 @@ void CClient::Run() delete m_pEditor; } +bool CClient::InitNetworkClient() +{ + NETADDR BindAddr; + if(g_Config.m_Bindaddr[0] == '\0') + { + mem_zero(&BindAddr, sizeof(BindAddr)); + } + else if(net_host_lookup(g_Config.m_Bindaddr, &BindAddr, NETTYPE_ALL) != 0) + { + dbg_msg("client", "The configured bindaddr '%s' cannot be resolved", g_Config.m_Bindaddr); + return false; + } + BindAddr.type = NETTYPE_ALL; + for(unsigned int i = 0; i < std::size(m_aNetClient); i++) + { + int &PortRef = i == CONN_MAIN ? g_Config.m_ClPort : i == CONN_DUMMY ? g_Config.m_ClDummyPort : g_Config.m_ClContactPort; + if(PortRef < 1024) // Reject users setting ports that we don't want to use + { + PortRef = 0; + } + BindAddr.port = PortRef; + unsigned RemainingAttempts = 25; + while(BindAddr.port == 0 || !m_aNetClient[i].Open(BindAddr)) + { + if(BindAddr.port != 0) + { + --RemainingAttempts; + if(RemainingAttempts == 0) + { + if(g_Config.m_Bindaddr[0]) + dbg_msg("client", "Could not open network client, try changing or unsetting the bindaddr '%s'", g_Config.m_Bindaddr); + else + dbg_msg("client", "Could not open network client"); + return false; + } + } + BindAddr.port = (secure_rand() % 64511) + 1024; + } + } + return true; +} + bool CClient::CtrlShiftKey(int Key, bool &Last) { if(Input()->ModifierIsPressed() && Input()->ShiftIsPressed() && !Last && Input()->KeyIsPressed(Key)) diff --git a/src/engine/client/client.h b/src/engine/client/client.h index df2f034b6..c446d3b76 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -425,6 +425,7 @@ public: void Run(); + bool InitNetworkClient(); bool CtrlShiftKey(int Key, bool &Last); static void Con_Connect(IConsole::IResult *pResult, void *pUserData); From 00b7bc5bfd8c0cbb47486ccced3d594854b7738d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Thu, 4 May 2023 19:46:40 +0200 Subject: [PATCH 2/4] Add `IClient::ShowMessageBox` To show an error/warning/information message popup with variable title and message. This uses the SDL function `SDL_ShowSimpleMessageBox` to show the message box, because it is simpler than implementing this ourself in the base system, especially because we would have to add an additional explicit dependency on GTK3 to show a message dialog on Linux. This function can be used without SDL being initialized. --- src/engine/client.h | 8 ++++++++ src/engine/client/client.cpp | 20 ++++++++++++++++++++ src/engine/client/client.h | 2 ++ 3 files changed, 30 insertions(+) diff --git a/src/engine/client.h b/src/engine/client.h index 466e9e00a..5ae3cac5b 100644 --- a/src/engine/client.h +++ b/src/engine/client.h @@ -285,6 +285,14 @@ public: virtual void ShellRegister() = 0; virtual void ShellUnregister() = 0; #endif + + enum EMessageBoxType + { + MESSAGE_BOX_TYPE_ERROR, + MESSAGE_BOX_TYPE_WARNING, + MESSAGE_BOX_TYPE_INFO, + }; + virtual void ShowMessageBox(const char *pTitle, const char *pMessage, EMessageBoxType Type = MESSAGE_BOX_TYPE_ERROR) = 0; }; class IGameClient : public IInterface diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 45caf6d00..f769d4c82 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -4960,3 +4960,23 @@ void CClient::ShellUnregister() shell_update(); } #endif + +static Uint32 GetSdlMessageBoxFlags(IClient::EMessageBoxType Type) +{ + switch(Type) + { + case IClient::MESSAGE_BOX_TYPE_ERROR: + return SDL_MESSAGEBOX_ERROR; + case IClient::MESSAGE_BOX_TYPE_WARNING: + return SDL_MESSAGEBOX_WARNING; + case IClient::MESSAGE_BOX_TYPE_INFO: + return SDL_MESSAGEBOX_INFORMATION; + } + dbg_assert(false, "Type invalid"); + return 0; +} + +void CClient::ShowMessageBox(const char *pTitle, const char *pMessage, EMessageBoxType Type) +{ + SDL_ShowSimpleMessageBox(GetSdlMessageBoxFlags(Type), pTitle, pMessage, nullptr); +} diff --git a/src/engine/client/client.h b/src/engine/client/client.h index c446d3b76..80013e22c 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -550,6 +550,8 @@ public: void ShellRegister() override; void ShellUnregister() override; #endif + + void ShowMessageBox(const char *pTitle, const char *pMessage, EMessageBoxType Type = MESSAGE_BOX_TYPE_ERROR) override; }; #endif From ccfca141d40c0d96236af2e34f051f30b8289883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Wed, 3 May 2023 20:28:37 +0200 Subject: [PATCH 3/4] Show error message popup on assertion error in client Add assertion handler function to base system. Set handler in client to show a message box on assertion errors. --- src/base/system.cpp | 17 ++++++++++++++++- src/base/system.h | 3 +++ src/engine/client/client.cpp | 7 +++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/base/system.cpp b/src/base/system.cpp index 47528f825..1f4059860 100644 --- a/src/base/system.cpp +++ b/src/base/system.cpp @@ -169,6 +169,7 @@ static NETSOCKET_INTERNAL invalid_socket = {NETTYPE_INVALID, -1, -1, -1}; #define AF_WEBSOCKET_INET (0xee) std::atomic_bool dbg_assert_failing = false; +DBG_ASSERT_HANDLER dbg_assert_handler; bool dbg_assert_has_failed() { @@ -179,8 +180,17 @@ void dbg_assert_imp(const char *filename, int line, int test, const char *msg) { if(!test) { + const bool already_failing = dbg_assert_has_failed(); dbg_assert_failing.store(true, std::memory_order_release); - dbg_msg("assert", "%s(%d): %s", filename, line, msg); + char error[256]; + str_format(error, sizeof(error), "%s(%d): %s", filename, line, msg); + dbg_msg("assert", "%s", error); + if(!already_failing) + { + DBG_ASSERT_HANDLER handler = dbg_assert_handler; + if(handler) + handler(error); + } log_global_logger_finish(); dbg_break(); } @@ -195,6 +205,11 @@ void dbg_break() #endif } +void dbg_assert_set_handler(DBG_ASSERT_HANDLER handler) +{ + dbg_assert_handler = std::move(handler); +} + void dbg_msg(const char *sys, const char *fmt, ...) { va_list args; diff --git a/src/base/system.h b/src/base/system.h index 765c822f4..7a6b1e5f3 100644 --- a/src/base/system.h +++ b/src/base/system.h @@ -108,6 +108,9 @@ bool dbg_assert_has_failed(); void dbg_break(); +typedef std::function DBG_ASSERT_HANDLER; +void dbg_assert_set_handler(DBG_ASSERT_HANDLER handler); + /** * Prints a debug message. * diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index f769d4c82..ee7381940 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -4534,6 +4534,7 @@ int main(int argc, const char **argv) CWindowsComLifecycle WindowsComLifecycle(true); #endif CCmdlineFix CmdlineFix(&argc, &argv); + bool Silent = false; bool RandInitFailed = false; @@ -4582,6 +4583,12 @@ int main(int argc, const char **argv) pKernel->RegisterInterface(pClient, false); pClient->RegisterInterfaces(); + dbg_assert_set_handler([pClient](const char *pMsg) { + char aMessage[256]; + str_format(aMessage, sizeof(aMessage), "An assertion error occured. Please write down or take a screenshot of the following information and report this error.\n\n%s", pMsg); + pClient->ShowMessageBox("Assertion Error", aMessage); + }); + // create the components IEngine *pEngine = CreateEngine(GAME_NAME, pFutureConsoleLogger, 2); IConsole *pConsole = CreateConsole(CFGFLAG_CLIENT).release(); From 3981f7ffe0025cf15a6fd9f15122b039de936430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Wed, 3 May 2023 20:29:58 +0200 Subject: [PATCH 4/4] Show error message popup when client fails to launch --- src/engine/client/client.cpp | 28 +++++++++++++++++++++------- src/engine/client/client.h | 2 +- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index ee7381940..223862129 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -3007,6 +3007,7 @@ void CClient::Run() if(RegisterFail || m_pGraphics->Init() != 0) { dbg_msg("client", "couldn't init graphics"); + ShowMessageBox("Graphics Error", "The graphics could not be initialized."); return; } } @@ -3024,8 +3025,13 @@ void CClient::Run() #endif #ifndef CONF_WEBASM - if(!InitNetworkClient()) + char aNetworkError[256]; + if(!InitNetworkClient(aNetworkError, sizeof(aNetworkError))) + { + dbg_msg("client", "%s", aNetworkError); + ShowMessageBox("Network Error", aNetworkError); return; + } #endif // init font rendering @@ -3383,7 +3389,7 @@ void CClient::Run() delete m_pEditor; } -bool CClient::InitNetworkClient() +bool CClient::InitNetworkClient(char *pError, size_t ErrorSize) { NETADDR BindAddr; if(g_Config.m_Bindaddr[0] == '\0') @@ -3392,7 +3398,7 @@ bool CClient::InitNetworkClient() } else if(net_host_lookup(g_Config.m_Bindaddr, &BindAddr, NETTYPE_ALL) != 0) { - dbg_msg("client", "The configured bindaddr '%s' cannot be resolved", g_Config.m_Bindaddr); + str_format(pError, ErrorSize, "The configured bindaddr '%s' cannot be resolved.", g_Config.m_Bindaddr); return false; } BindAddr.type = NETTYPE_ALL; @@ -3413,9 +3419,9 @@ bool CClient::InitNetworkClient() if(RemainingAttempts == 0) { if(g_Config.m_Bindaddr[0]) - dbg_msg("client", "Could not open network client, try changing or unsetting the bindaddr '%s'", g_Config.m_Bindaddr); + str_format(pError, ErrorSize, "Could not open the network client, try changing or unsetting the bindaddr '%s'.", g_Config.m_Bindaddr); else - dbg_msg("client", "Could not open network client"); + str_format(pError, ErrorSize, "Could not open the network client."); return false; } } @@ -4614,7 +4620,9 @@ int main(int argc, const char **argv) if(RandInitFailed) { - dbg_msg("secure", "could not initialize secure RNG"); + const char *pError = "Failed to initialize the secure RNG."; + dbg_msg("secure", "%s", pError); + pClient->ShowMessageBox("Secure RNG Error", pError); return -1; } @@ -4646,6 +4654,9 @@ int main(int argc, const char **argv) if(RegisterFail) { + const char *pError = "Failed to register an interface."; + dbg_msg("client", "%s", pError); + pClient->ShowMessageBox("Kernel Error", pError); delete pKernel; pClient->~CClient(); free(pClient); @@ -4729,7 +4740,10 @@ int main(int argc, const char **argv) // init SDL if(SDL_Init(0) < 0) { - dbg_msg("client", "unable to init SDL base: %s", SDL_GetError()); + char aError[256]; + str_format(aError, sizeof(aError), "Unable to initialize SDL base: %s", SDL_GetError()); + dbg_msg("client", "%s", aError); + pClient->ShowMessageBox("SDL Error", aError); return -1; } diff --git a/src/engine/client/client.h b/src/engine/client/client.h index 80013e22c..70201d8c9 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -425,7 +425,7 @@ public: void Run(); - bool InitNetworkClient(); + bool InitNetworkClient(char *pError, size_t ErrorSize); bool CtrlShiftKey(int Key, bool &Last); static void Con_Connect(IConsole::IResult *pResult, void *pUserData);