mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-18 22:18:19 +00:00
Merge #6559
6559: Show error message popup on assertion error in client and when client fails to launch r=def- a=Robyt3 Alternative to #6493. Closes #6482. ## Checklist - [X] Tested the change ingame - [ ] Provided screenshots if it is a visual change - [ ] Tested in combination with possibly related configuration options - [ ] Written a unit test (especially base/) or added coverage to integration test - [ ] Considered possible null pointers and out of bounds array indexing - [ ] Changed no physics that affect existing maps - [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) Co-authored-by: Robert Müller <robytemueller@gmail.com>
This commit is contained in:
commit
cfd003d9c5
|
@ -169,6 +169,7 @@ static NETSOCKET_INTERNAL invalid_socket = {NETTYPE_INVALID, -1, -1, -1};
|
||||||
#define AF_WEBSOCKET_INET (0xee)
|
#define AF_WEBSOCKET_INET (0xee)
|
||||||
|
|
||||||
std::atomic_bool dbg_assert_failing = false;
|
std::atomic_bool dbg_assert_failing = false;
|
||||||
|
DBG_ASSERT_HANDLER dbg_assert_handler;
|
||||||
|
|
||||||
bool dbg_assert_has_failed()
|
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)
|
if(!test)
|
||||||
{
|
{
|
||||||
|
const bool already_failing = dbg_assert_has_failed();
|
||||||
dbg_assert_failing.store(true, std::memory_order_release);
|
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();
|
log_global_logger_finish();
|
||||||
dbg_break();
|
dbg_break();
|
||||||
}
|
}
|
||||||
|
@ -195,6 +205,11 @@ void dbg_break()
|
||||||
#endif
|
#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, ...)
|
void dbg_msg(const char *sys, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
|
@ -108,6 +108,9 @@ bool dbg_assert_has_failed();
|
||||||
void
|
void
|
||||||
dbg_break();
|
dbg_break();
|
||||||
|
|
||||||
|
typedef std::function<void(const char *message)> DBG_ASSERT_HANDLER;
|
||||||
|
void dbg_assert_set_handler(DBG_ASSERT_HANDLER handler);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints a debug message.
|
* Prints a debug message.
|
||||||
*
|
*
|
||||||
|
|
|
@ -285,6 +285,14 @@ public:
|
||||||
virtual void ShellRegister() = 0;
|
virtual void ShellRegister() = 0;
|
||||||
virtual void ShellUnregister() = 0;
|
virtual void ShellUnregister() = 0;
|
||||||
#endif
|
#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
|
class IGameClient : public IInterface
|
||||||
|
|
|
@ -3007,6 +3007,7 @@ void CClient::Run()
|
||||||
if(RegisterFail || m_pGraphics->Init() != 0)
|
if(RegisterFail || m_pGraphics->Init() != 0)
|
||||||
{
|
{
|
||||||
dbg_msg("client", "couldn't init graphics");
|
dbg_msg("client", "couldn't init graphics");
|
||||||
|
ShowMessageBox("Graphics Error", "The graphics could not be initialized.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3024,45 +3025,12 @@ void CClient::Run()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef CONF_WEBASM
|
#ifndef CONF_WEBASM
|
||||||
// open socket
|
char aNetworkError[256];
|
||||||
|
if(!InitNetworkClient(aNetworkError, sizeof(aNetworkError)))
|
||||||
{
|
{
|
||||||
NETADDR BindAddr;
|
dbg_msg("client", "%s", aNetworkError);
|
||||||
if(g_Config.m_Bindaddr[0] == '\0')
|
ShowMessageBox("Network Error", aNetworkError);
|
||||||
{
|
return;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -3421,6 +3389,48 @@ void CClient::Run()
|
||||||
delete m_pEditor;
|
delete m_pEditor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CClient::InitNetworkClient(char *pError, size_t ErrorSize)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
str_format(pError, ErrorSize, "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])
|
||||||
|
str_format(pError, ErrorSize, "Could not open the network client, try changing or unsetting the bindaddr '%s'.", g_Config.m_Bindaddr);
|
||||||
|
else
|
||||||
|
str_format(pError, ErrorSize, "Could not open the network client.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BindAddr.port = (secure_rand() % 64511) + 1024;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CClient::CtrlShiftKey(int Key, bool &Last)
|
bool CClient::CtrlShiftKey(int Key, bool &Last)
|
||||||
{
|
{
|
||||||
if(Input()->ModifierIsPressed() && Input()->ShiftIsPressed() && !Last && Input()->KeyIsPressed(Key))
|
if(Input()->ModifierIsPressed() && Input()->ShiftIsPressed() && !Last && Input()->KeyIsPressed(Key))
|
||||||
|
@ -4530,6 +4540,7 @@ int main(int argc, const char **argv)
|
||||||
CWindowsComLifecycle WindowsComLifecycle(true);
|
CWindowsComLifecycle WindowsComLifecycle(true);
|
||||||
#endif
|
#endif
|
||||||
CCmdlineFix CmdlineFix(&argc, &argv);
|
CCmdlineFix CmdlineFix(&argc, &argv);
|
||||||
|
|
||||||
bool Silent = false;
|
bool Silent = false;
|
||||||
bool RandInitFailed = false;
|
bool RandInitFailed = false;
|
||||||
|
|
||||||
|
@ -4578,6 +4589,12 @@ int main(int argc, const char **argv)
|
||||||
pKernel->RegisterInterface(pClient, false);
|
pKernel->RegisterInterface(pClient, false);
|
||||||
pClient->RegisterInterfaces();
|
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
|
// create the components
|
||||||
IEngine *pEngine = CreateEngine(GAME_NAME, pFutureConsoleLogger, 2);
|
IEngine *pEngine = CreateEngine(GAME_NAME, pFutureConsoleLogger, 2);
|
||||||
IConsole *pConsole = CreateConsole(CFGFLAG_CLIENT).release();
|
IConsole *pConsole = CreateConsole(CFGFLAG_CLIENT).release();
|
||||||
|
@ -4603,7 +4620,9 @@ int main(int argc, const char **argv)
|
||||||
|
|
||||||
if(RandInitFailed)
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4635,6 +4654,9 @@ int main(int argc, const char **argv)
|
||||||
|
|
||||||
if(RegisterFail)
|
if(RegisterFail)
|
||||||
{
|
{
|
||||||
|
const char *pError = "Failed to register an interface.";
|
||||||
|
dbg_msg("client", "%s", pError);
|
||||||
|
pClient->ShowMessageBox("Kernel Error", pError);
|
||||||
delete pKernel;
|
delete pKernel;
|
||||||
pClient->~CClient();
|
pClient->~CClient();
|
||||||
free(pClient);
|
free(pClient);
|
||||||
|
@ -4718,7 +4740,10 @@ int main(int argc, const char **argv)
|
||||||
// init SDL
|
// init SDL
|
||||||
if(SDL_Init(0) < 0)
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4956,3 +4981,23 @@ void CClient::ShellUnregister()
|
||||||
shell_update();
|
shell_update();
|
||||||
}
|
}
|
||||||
#endif
|
#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);
|
||||||
|
}
|
||||||
|
|
|
@ -425,6 +425,7 @@ public:
|
||||||
|
|
||||||
void Run();
|
void Run();
|
||||||
|
|
||||||
|
bool InitNetworkClient(char *pError, size_t ErrorSize);
|
||||||
bool CtrlShiftKey(int Key, bool &Last);
|
bool CtrlShiftKey(int Key, bool &Last);
|
||||||
|
|
||||||
static void Con_Connect(IConsole::IResult *pResult, void *pUserData);
|
static void Con_Connect(IConsole::IResult *pResult, void *pUserData);
|
||||||
|
@ -549,6 +550,8 @@ public:
|
||||||
void ShellRegister() override;
|
void ShellRegister() override;
|
||||||
void ShellUnregister() override;
|
void ShellUnregister() override;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void ShowMessageBox(const char *pTitle, const char *pMessage, EMessageBoxType Type = MESSAGE_BOX_TYPE_ERROR) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue