From b61005d3e74a31ee995c081d4fb5c511ec65cdaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sat, 27 Jul 2024 22:34:53 +0200 Subject: [PATCH] Improve dummy connecting button and error handling Track whether the dummy is currently connecting separately so the dummy being disconnected due to errors can be detected. Show an error message as echo in the chat when the dummy could not be connected, e.g. when the server is full. Use the global time for limiting the dummy connecting delay instead of using game ticks, so the delay also works correctly when having connection problems (i.e., when ticks do not advance). Handle the dummy connecting being delayed separately from the dummy currently connecting. Add tooltips for the "Connect dummy"-button when it's disable due to dummy not being allow on the server or when connecting is delayed. Add console error messages for `dummy_connect` command. --- src/engine/client.h | 1 + src/engine/client/client.cpp | 85 +++++++++++++-------- src/engine/client/client.h | 4 +- src/game/client/components/menus_ingame.cpp | 17 +++-- 4 files changed, 69 insertions(+), 38 deletions(-) diff --git a/src/engine/client.h b/src/engine/client.h index 69bd871b1..d942c469b 100644 --- a/src/engine/client.h +++ b/src/engine/client.h @@ -163,6 +163,7 @@ public: virtual void DummyConnect() = 0; virtual bool DummyConnected() const = 0; virtual bool DummyConnecting() const = 0; + virtual bool DummyConnectingDelayed() const = 0; virtual bool DummyAllowed() const = 0; virtual void Restart() = 0; diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index a10a6f157..16ce374d1 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -260,7 +260,7 @@ void CClient::SendInput() // fetch input for(int Dummy = 0; Dummy < NUM_DUMMIES; Dummy++) { - if(!m_DummyConnected && Dummy != 0) + if(!DummyConnected() && Dummy != 0) { break; } @@ -396,7 +396,7 @@ void CClient::OnEnterGame(bool Dummy) if(!Dummy) { - m_LastDummyConnectTime = 0; + m_LastDummyConnectTime = 0.0f; } GameClient()->OnEnterGame(); @@ -621,38 +621,51 @@ bool CClient::DummyConnected() const bool CClient::DummyConnecting() const { - return !m_DummyConnected && m_LastDummyConnectTime > 0 && m_LastDummyConnectTime + GameTickSpeed() * 5 > GameTick(g_Config.m_ClDummy); + return m_DummyConnecting; +} + +bool CClient::DummyConnectingDelayed() const +{ + return !DummyConnected() && !DummyConnecting() && m_LastDummyConnectTime > 0.0f && m_LastDummyConnectTime + 5.0f > GlobalTime(); } void CClient::DummyConnect() { - if(m_LastDummyConnectTime > 0 && m_LastDummyConnectTime + GameTickSpeed() * 5 > GameTick(g_Config.m_ClDummy)) - return; - if(m_aNetClient[CONN_MAIN].State() != NETSTATE_ONLINE) + { + log_info("client", "Not online."); return; + } - if(m_DummyConnected || !DummyAllowed()) + if(!DummyAllowed()) + { + log_info("client", "Dummy is not allowed on this server."); return; + } + if(DummyConnected() || DummyConnecting()) + { + log_info("client", "Dummy is already connected/connecting."); + return; + } + if(DummyConnectingDelayed()) + { + log_info("client", "Wait before connecting dummy again."); + return; + } - m_LastDummyConnectTime = GameTick(g_Config.m_ClDummy); - + m_LastDummyConnectTime = GlobalTime(); m_aRconAuthed[1] = 0; - m_DummySendConnInfo = true; g_Config.m_ClDummyCopyMoves = 0; g_Config.m_ClDummyHammer = 0; - // connect to the server + m_DummyConnecting = true; m_aNetClient[CONN_DUMMY].Connect(m_aNetClient[CONN_MAIN].ServerAddress(), 1); } void CClient::DummyDisconnect(const char *pReason) { - if(!m_DummyConnected) - return; - m_aNetClient[CONN_DUMMY].Disconnect(pReason); g_Config.m_ClDummy = 0; @@ -666,6 +679,7 @@ void CClient::DummyDisconnect(const char *pReason) m_aapSnapshots[1][SNAP_PREV] = 0; m_aReceivedSnapshots[1] = 0; m_DummyConnected = false; + m_DummyConnecting = false; GameClient()->OnDummyDisconnect(); } @@ -1526,6 +1540,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket, int Conn, bool Dummy) else if(Conn == CONN_DUMMY && Msg == NETMSG_CON_READY) { m_DummyConnected = true; + m_DummyConnecting = false; g_Config.m_ClDummy = 1; Rcon("crashmeplx"); if(m_aRconAuthed[0]) @@ -2269,25 +2284,33 @@ void CClient::PumpNetwork() if(State() != IClient::STATE_DEMOPLAYBACK) { - // check for errors - if(State() != IClient::STATE_OFFLINE && State() < IClient::STATE_QUITTING && m_aNetClient[CONN_MAIN].State() == NETSTATE_OFFLINE) + // check for errors of main and dummy + if(State() != IClient::STATE_OFFLINE && State() < IClient::STATE_QUITTING) { - Disconnect(); - char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "offline error='%s'", m_aNetClient[CONN_MAIN].ErrorString()); - m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf, gs_ClientNetworkErrPrintColor); + if(m_aNetClient[CONN_MAIN].State() == NETSTATE_OFFLINE) + { + // This will also disconnect the dummy, so the branch below is an `else if` + Disconnect(); + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "offline error='%s'", m_aNetClient[CONN_MAIN].ErrorString()); + m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf, gs_ClientNetworkErrPrintColor); + } + else if((DummyConnecting() || DummyConnected()) && m_aNetClient[CONN_DUMMY].State() == NETSTATE_OFFLINE) + { + const bool WasConnecting = DummyConnecting(); + DummyDisconnect(nullptr); + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "offline dummy error='%s'", m_aNetClient[CONN_DUMMY].ErrorString()); + m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf, gs_ClientNetworkErrPrintColor); + if(WasConnecting) + { + str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Could not connect dummy"), m_aNetClient[CONN_DUMMY].ErrorString()); + GameClient()->Echo(aBuf); + } + } } - if(State() != IClient::STATE_OFFLINE && State() < IClient::STATE_QUITTING && m_DummyConnected && - m_aNetClient[CONN_DUMMY].State() == NETSTATE_OFFLINE) - { - DummyDisconnect(0); - char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "offline dummy error='%s'", m_aNetClient[CONN_DUMMY].ErrorString()); - m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf, gs_ClientNetworkErrPrintColor); - } - - // + // check if main was connected if(State() == IClient::STATE_CONNECTING && m_aNetClient[CONN_MAIN].State() == NETSTATE_ONLINE) { // we switched to online @@ -3164,7 +3187,7 @@ void CClient::Con_DummyConnect(IConsole::IResult *pResult, void *pUserData) void CClient::Con_DummyDisconnect(IConsole::IResult *pResult, void *pUserData) { CClient *pSelf = (CClient *)pUserData; - pSelf->DummyDisconnect(0); + pSelf->DummyDisconnect(nullptr); } void CClient::Con_DummyResetInput(IConsole::IResult *pResult, void *pUserData) diff --git a/src/engine/client/client.h b/src/engine/client/client.h index d8080ae69..526bd1b4d 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -178,8 +178,9 @@ class CClient : public IClient, public CDemoPlayer::IListener int m_aCurrentInput[NUM_DUMMIES] = {0, 0}; bool m_LastDummy = false; bool m_DummySendConnInfo = false; + bool m_DummyConnecting = false; bool m_DummyConnected = false; - int m_LastDummyConnectTime = 0; + float m_LastDummyConnectTime = 0.0f; // graphs CGraph m_InputtimeMarginGraph; @@ -316,6 +317,7 @@ public: void DummyConnect() override; bool DummyConnected() const override; bool DummyConnecting() const override; + bool DummyConnectingDelayed() const override; bool DummyAllowed() const override; void GetServerInfo(CServerInfo *pServerInfo) const override; diff --git a/src/game/client/components/menus_ingame.cpp b/src/game/client/components/menus_ingame.cpp index d9bb98b09..53f0a3a74 100644 --- a/src/game/client/components/menus_ingame.cpp +++ b/src/game/client/components/menus_ingame.cpp @@ -72,13 +72,18 @@ void CMenus::RenderGame(CUIRect MainView) ButtonBar.VSplitRight(5.0f, &ButtonBar, 0); ButtonBar.VSplitRight(170.0f, &ButtonBar, &Button); - bool DummyConnecting = Client()->DummyConnecting(); static CButtonContainer s_DummyButton; if(!Client()->DummyAllowed()) { DoButton_Menu(&s_DummyButton, Localize("Connect Dummy"), 1, &Button); + GameClient()->m_Tooltips.DoToolTip(&s_DummyButton, &Button, Localize("Dummy is not allowed on this server.")); } - else if(DummyConnecting) + else if(Client()->DummyConnectingDelayed()) + { + DoButton_Menu(&s_DummyButton, Localize("Connect Dummy"), 1, &Button); + GameClient()->m_Tooltips.DoToolTip(&s_DummyButton, &Button, Localize("Please wait…")); + } + else if(Client()->DummyConnecting()) { DoButton_Menu(&s_DummyButton, Localize("Connecting dummy"), 1, &Button); } @@ -131,7 +136,7 @@ void CMenus::RenderGame(CUIRect MainView) { ButtonBar.VSplitLeft(5.0f, 0, &ButtonBar); ButtonBar.VSplitLeft(120.0f, &Button, &ButtonBar); - if(!DummyConnecting && DoButton_Menu(&s_SpectateButton, Localize("Spectate"), 0, &Button)) + if(!Client()->DummyConnecting() && DoButton_Menu(&s_SpectateButton, Localize("Spectate"), 0, &Button)) { if(g_Config.m_ClDummy == 0 || Client()->DummyConnected()) { @@ -148,7 +153,7 @@ void CMenus::RenderGame(CUIRect MainView) ButtonBar.VSplitLeft(5.0f, 0, &ButtonBar); ButtonBar.VSplitLeft(120.0f, &Button, &ButtonBar); static CButtonContainer s_JoinRedButton; - if(!DummyConnecting && DoButton_Menu(&s_JoinRedButton, Localize("Join red"), 0, &Button)) + if(!Client()->DummyConnecting() && DoButton_Menu(&s_JoinRedButton, Localize("Join red"), 0, &Button)) { m_pClient->SendSwitchTeam(TEAM_RED); SetActive(false); @@ -160,7 +165,7 @@ void CMenus::RenderGame(CUIRect MainView) ButtonBar.VSplitLeft(5.0f, 0, &ButtonBar); ButtonBar.VSplitLeft(120.0f, &Button, &ButtonBar); static CButtonContainer s_JoinBlueButton; - if(!DummyConnecting && DoButton_Menu(&s_JoinBlueButton, Localize("Join blue"), 0, &Button)) + if(!Client()->DummyConnecting() && DoButton_Menu(&s_JoinBlueButton, Localize("Join blue"), 0, &Button)) { m_pClient->SendSwitchTeam(TEAM_BLUE); SetActive(false); @@ -173,7 +178,7 @@ void CMenus::RenderGame(CUIRect MainView) { ButtonBar.VSplitLeft(5.0f, 0, &ButtonBar); ButtonBar.VSplitLeft(120.0f, &Button, &ButtonBar); - if(!DummyConnecting && DoButton_Menu(&s_SpectateButton, Localize("Join game"), 0, &Button)) + if(!Client()->DummyConnecting() && DoButton_Menu(&s_SpectateButton, Localize("Join game"), 0, &Button)) { m_pClient->SendSwitchTeam(0); SetActive(false);