From b4a22e2feeab15c87630402e3a20cd7bb7926faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Tue, 6 Feb 2024 21:41:59 +0100 Subject: [PATCH] Refactor client state handling in menus Split menu rendering explicitly by client state. This makes the code more readable by not mixing code for rendering different states together as much and fixes issues where the menu was being rendered inconsistently for one frame when the state is changed, at the cost of some additional duplicated code. The fullscreen popups shown when in the connecting and loading client states are now hard-coded for these states, instead of being mixed together with the other fullscreen popups, which can be shown when offline, ingame or during demo playback. As a side effect of rendering the demo controls like the regular menu, the UI color will now also affect the demo controls menu background. Move `CBackground::ChangePosition` calls inside functions to reduce duplicate code and improve readability. Remove unnecessary `CMenus::m_ActivePage` variable. Closes #7834. --- src/game/client/components/menus.cpp | 604 ++++++++++-------- src/game/client/components/menus.h | 6 +- src/game/client/components/menus_browser.cpp | 20 + src/game/client/components/menus_demo.cpp | 2 + src/game/client/components/menus_settings.cpp | 4 + src/game/client/components/menus_start.cpp | 2 + 6 files changed, 365 insertions(+), 273 deletions(-) diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index e27df0a70..b4454c4ae 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -56,7 +56,6 @@ float CMenus::ms_ListheaderHeight = 17.0f; CMenus::CMenus() { m_Popup = POPUP_NONE; - m_ActivePage = PAGE_INTERNET; m_MenuPage = 0; m_GamePage = PAGE_GAME; @@ -543,18 +542,17 @@ int CMenus::DoKeyReader(const void *pId, const CUIRect *pRect, int Key, int Modi return NewKey; } -void CMenus::RenderMenubar(CUIRect Box) +void CMenus::RenderMenubar(CUIRect Box, IClient::EClientState ClientState) { CUIRect Button; - m_ActivePage = m_MenuPage; int NewPage = -1; + int ActivePage = -1; - if(Client()->State() != IClient::STATE_OFFLINE) - m_ActivePage = m_GamePage; - - if(Client()->State() == IClient::STATE_OFFLINE) + if(ClientState == IClient::STATE_OFFLINE) { + ActivePage = m_MenuPage; + Box.VSplitLeft(33.0f, &Button, &Box); TextRender()->SetFontPreset(EFontPreset::ICON_FONT); @@ -596,7 +594,7 @@ void CMenus::RenderMenubar(CUIRect Box) Box.VSplitLeft(10.0f, nullptr, &Box); Box.VSplitLeft(75.0f, &Button, &Box); static CButtonContainer s_InternetButton; - if(DoButton_MenuTab(&s_InternetButton, FONT_ICON_EARTH_AMERICAS, m_ActivePage == PAGE_INTERNET, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIG_TAB_INTERNET])) + if(DoButton_MenuTab(&s_InternetButton, FONT_ICON_EARTH_AMERICAS, ActivePage == PAGE_INTERNET, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIG_TAB_INTERNET])) { if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_INTERNET) { @@ -610,7 +608,7 @@ void CMenus::RenderMenubar(CUIRect Box) Box.VSplitLeft(75.0f, &Button, &Box); static CButtonContainer s_LanButton; - if(DoButton_MenuTab(&s_LanButton, FONT_ICON_NETWORK_WIRED, m_ActivePage == PAGE_LAN, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIG_TAB_LAN])) + if(DoButton_MenuTab(&s_LanButton, FONT_ICON_NETWORK_WIRED, ActivePage == PAGE_LAN, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIG_TAB_LAN])) { if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_LAN) ServerBrowser()->Refresh(IServerBrowser::TYPE_LAN); @@ -620,7 +618,7 @@ void CMenus::RenderMenubar(CUIRect Box) Box.VSplitLeft(75.0f, &Button, &Box); static CButtonContainer s_FavoritesButton; - if(DoButton_MenuTab(&s_FavoritesButton, FONT_ICON_STAR, m_ActivePage == PAGE_FAVORITES, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIG_TAB_FAVORITES])) + if(DoButton_MenuTab(&s_FavoritesButton, FONT_ICON_STAR, ActivePage == PAGE_FAVORITES, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIG_TAB_FAVORITES])) { if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_FAVORITES) { @@ -641,7 +639,7 @@ void CMenus::RenderMenubar(CUIRect Box) { Box.VSplitLeft(75.0f, &Button, &Box); const int Page = PAGE_FAVORITE_COMMUNITY_1 + FavoriteCommunityIndex; - if(DoButton_MenuTab(&s_aFavoriteCommunityButtons[FavoriteCommunityIndex], FONT_ICON_ELLIPSIS, m_ActivePage == Page, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIT_TAB_FAVORITE_COMMUNITY_1 + FavoriteCommunityIndex], nullptr, nullptr, nullptr, 10.0f, FindCommunityIcon(pCommunity->Id()))) + if(DoButton_MenuTab(&s_aFavoriteCommunityButtons[FavoriteCommunityIndex], FONT_ICON_ELLIPSIS, ActivePage == Page, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIT_TAB_FAVORITE_COMMUNITY_1 + FavoriteCommunityIndex], nullptr, nullptr, nullptr, 10.0f, FindCommunityIcon(pCommunity->Id()))) { const int BrowserType = IServerBrowser::TYPE_FAVORITE_COMMUNITY_1 + FavoriteCommunityIndex; if(ServerBrowser()->GetCurrentType() != BrowserType) @@ -662,48 +660,52 @@ void CMenus::RenderMenubar(CUIRect Box) TextRender()->SetRenderFlags(0); TextRender()->SetFontPreset(EFontPreset::DEFAULT_FONT); } - else + else if(ClientState == IClient::STATE_ONLINE) { + ActivePage = m_GamePage; + // online menus Box.VSplitLeft(90.0f, &Button, &Box); static CButtonContainer s_GameButton; - if(DoButton_MenuTab(&s_GameButton, Localize("Game"), m_ActivePage == PAGE_GAME, &Button, IGraphics::CORNER_TL)) + if(DoButton_MenuTab(&s_GameButton, Localize("Game"), ActivePage == PAGE_GAME, &Button, IGraphics::CORNER_TL)) NewPage = PAGE_GAME; Box.VSplitLeft(90.0f, &Button, &Box); static CButtonContainer s_PlayersButton; - if(DoButton_MenuTab(&s_PlayersButton, Localize("Players"), m_ActivePage == PAGE_PLAYERS, &Button, IGraphics::CORNER_NONE)) + if(DoButton_MenuTab(&s_PlayersButton, Localize("Players"), ActivePage == PAGE_PLAYERS, &Button, IGraphics::CORNER_NONE)) NewPage = PAGE_PLAYERS; Box.VSplitLeft(130.0f, &Button, &Box); static CButtonContainer s_ServerInfoButton; - if(DoButton_MenuTab(&s_ServerInfoButton, Localize("Server info"), m_ActivePage == PAGE_SERVER_INFO, &Button, IGraphics::CORNER_NONE)) + if(DoButton_MenuTab(&s_ServerInfoButton, Localize("Server info"), ActivePage == PAGE_SERVER_INFO, &Button, IGraphics::CORNER_NONE)) NewPage = PAGE_SERVER_INFO; Box.VSplitLeft(90.0f, &Button, &Box); static CButtonContainer s_NetworkButton; - if(DoButton_MenuTab(&s_NetworkButton, Localize("Browser"), m_ActivePage == PAGE_NETWORK, &Button, IGraphics::CORNER_NONE)) + if(DoButton_MenuTab(&s_NetworkButton, Localize("Browser"), ActivePage == PAGE_NETWORK, &Button, IGraphics::CORNER_NONE)) NewPage = PAGE_NETWORK; + if(GameClient()->m_GameInfo.m_Race) { + Box.VSplitLeft(90.0f, &Button, &Box); static CButtonContainer s_GhostButton; - if(GameClient()->m_GameInfo.m_Race) - { - Box.VSplitLeft(90.0f, &Button, &Box); - if(DoButton_MenuTab(&s_GhostButton, Localize("Ghost"), m_ActivePage == PAGE_GHOST, &Button, IGraphics::CORNER_NONE)) - NewPage = PAGE_GHOST; - } + if(DoButton_MenuTab(&s_GhostButton, Localize("Ghost"), ActivePage == PAGE_GHOST, &Button, IGraphics::CORNER_NONE)) + NewPage = PAGE_GHOST; } Box.VSplitLeft(100.0f, &Button, &Box); Box.VSplitLeft(4.0f, nullptr, &Box); static CButtonContainer s_CallVoteButton; - if(DoButton_MenuTab(&s_CallVoteButton, Localize("Call vote"), m_ActivePage == PAGE_CALLVOTE, &Button, IGraphics::CORNER_TR)) + if(DoButton_MenuTab(&s_CallVoteButton, Localize("Call vote"), ActivePage == PAGE_CALLVOTE, &Button, IGraphics::CORNER_TR)) { NewPage = PAGE_CALLVOTE; m_ControlPageOpening = true; } } + else + { + dbg_assert(false, "Client state invalid for RenderMenubar"); + } TextRender()->SetFontPreset(EFontPreset::ICON_FONT); TextRender()->SetRenderFlags(ETextRenderFlags::TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags::TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT | ETextRenderFlags::TEXT_RENDER_FLAG_NO_OVERSIZE); @@ -727,7 +729,7 @@ void CMenus::RenderMenubar(CUIRect Box) Box.VSplitRight(10.0f, &Box, nullptr); Box.VSplitRight(33.0f, &Box, &Button); static CButtonContainer s_SettingsButton; - if(DoButton_MenuTab(&s_SettingsButton, FONT_ICON_GEAR, m_ActivePage == PAGE_SETTINGS, &Button, IGraphics::CORNER_T, &m_aAnimatorsSmallPage[SMALL_TAB_SETTINGS])) + if(DoButton_MenuTab(&s_SettingsButton, FONT_ICON_GEAR, ActivePage == PAGE_SETTINGS, &Button, IGraphics::CORNER_T, &m_aAnimatorsSmallPage[SMALL_TAB_SETTINGS])) { NewPage = PAGE_SETTINGS; } @@ -742,12 +744,12 @@ void CMenus::RenderMenubar(CUIRect Box) } GameClient()->m_Tooltips.DoToolTip(&s_EditorButton, &Button, Localize("Editor")); - if(Client()->State() == IClient::STATE_OFFLINE) + if(ClientState == IClient::STATE_OFFLINE) { Box.VSplitRight(10.0f, &Box, nullptr); Box.VSplitRight(33.0f, &Box, &Button); static CButtonContainer s_DemoButton; - if(DoButton_MenuTab(&s_DemoButton, FONT_ICON_CLAPPERBOARD, m_ActivePage == PAGE_DEMOS, &Button, IGraphics::CORNER_T, &m_aAnimatorsSmallPage[SMALL_TAB_DEMOBUTTON])) + if(DoButton_MenuTab(&s_DemoButton, FONT_ICON_CLAPPERBOARD, ActivePage == PAGE_DEMOS, &Button, IGraphics::CORNER_T, &m_aAnimatorsSmallPage[SMALL_TAB_DEMOBUTTON])) { NewPage = PAGE_DEMOS; } @@ -759,7 +761,7 @@ void CMenus::RenderMenubar(CUIRect Box) if(NewPage != -1) { - if(Client()->State() == IClient::STATE_OFFLINE) + if(ClientState == IClient::STATE_OFFLINE) SetMenuPage(NewPage); else m_GamePage = NewPage; @@ -819,6 +821,8 @@ void CMenus::RenderLoading(const char *pCaption, const char *pContent, int Incre void CMenus::RenderNews(CUIRect MainView) { + m_pBackground->ChangePosition(CMenuBackground::POS_NEWS); + g_Config.m_UiUnreadNews = false; MainView.Draw(ms_ColorTabbarActive, IGraphics::CORNER_B, 10.0f); @@ -998,12 +1002,6 @@ bool CMenus::CanDisplayWarning() const void CMenus::Render() { - if(Client()->State() == IClient::STATE_DEMOPLAYBACK && m_Popup == POPUP_NONE) - return; - - CUIRect Screen = *Ui()->Screen(); - Screen.Margin(10.0f, &Screen); - Ui()->MapScreen(); Ui()->ResetMouseSlow(); @@ -1023,21 +1021,40 @@ void CMenus::Render() UpdateCommunityIcons(); } - // Initially add DDNet as favorite community and select its tab. - // This must be delayed until the DDNet info is available. - if(m_CreateDefaultFavoriteCommunities && ServerBrowser()->DDNetInfoAvailable()) + if(ServerBrowser()->DDNetInfoAvailable()) { - m_CreateDefaultFavoriteCommunities = false; - if(ServerBrowser()->Community(IServerBrowser::COMMUNITY_DDNET) != nullptr) + // Initially add DDNet as favorite community and select its tab. + // This must be delayed until the DDNet info is available. + if(m_CreateDefaultFavoriteCommunities) { - ServerBrowser()->FavoriteCommunitiesFilter().Clear(); - ServerBrowser()->FavoriteCommunitiesFilter().Add(IServerBrowser::COMMUNITY_DDNET); - SetMenuPage(PAGE_FAVORITE_COMMUNITY_1); - ServerBrowser()->Refresh(IServerBrowser::TYPE_FAVORITE_COMMUNITY_1); + m_CreateDefaultFavoriteCommunities = false; + if(ServerBrowser()->Community(IServerBrowser::COMMUNITY_DDNET) != nullptr) + { + ServerBrowser()->FavoriteCommunitiesFilter().Clear(); + ServerBrowser()->FavoriteCommunitiesFilter().Add(IServerBrowser::COMMUNITY_DDNET); + SetMenuPage(PAGE_FAVORITE_COMMUNITY_1); + ServerBrowser()->Refresh(IServerBrowser::TYPE_FAVORITE_COMMUNITY_1); + } + } + + if(m_JoinTutorial && m_Popup == POPUP_NONE && !ServerBrowser()->IsGettingServerlist()) + { + m_JoinTutorial = false; + // This is only reached on first launch, when the DDNet community tab has been created and + // activated by default, so the server info for the tutorial server should be available. + const char *pAddr = ServerBrowser()->GetTutorialServer(); + if(pAddr) + { + Client()->Connect(pAddr); + } } } - if(Client()->State() == IClient::STATE_ONLINE || Client()->State() == IClient::STATE_DEMOPLAYBACK) + // Determine the client state once before rendering because it can change + // while rendering which causes frames with broken user interface. + const IClient::EClientState ClientState = Client()->State(); + + if(ClientState == IClient::STATE_ONLINE || ClientState == IClient::STATE_DEMOPLAYBACK) { ms_ColorTabbarInactive = ms_ColorTabbarInactiveIngame; ms_ColorTabbarActive = ms_ColorTabbarActiveIngame; @@ -1054,23 +1071,34 @@ void CMenus::Render() ms_ColorTabbarHover = ms_ColorTabbarHoverOutgame; } - if(m_Popup == POPUP_NONE) + CUIRect Screen = *Ui()->Screen(); + if(Client()->State() != IClient::STATE_DEMOPLAYBACK || m_Popup != POPUP_NONE) { - if(m_JoinTutorial && ServerBrowser()->DDNetInfoAvailable() && !ServerBrowser()->IsGettingServerlist()) - { - m_JoinTutorial = false; - // This is only reached on first launch, when the DDNet community tab has been created and - // activated by default, so the server info for the tutorial server should be available. - const char *pAddr = ServerBrowser()->GetTutorialServer(); - if(pAddr) - { - Client()->Connect(pAddr); - } - } + Screen.Margin(10.0f, &Screen); + } - if(m_ShowStart && Client()->State() == IClient::STATE_OFFLINE) + switch(ClientState) + { + case IClient::STATE_QUITTING: + case IClient::STATE_RESTARTING: + // Render nothing except menu background. This should not happen for more than one frame. + return; + + case IClient::STATE_CONNECTING: + RenderPopupConnecting(Screen); + break; + + case IClient::STATE_LOADING: + RenderPopupLoading(Screen); + break; + + case IClient::STATE_OFFLINE: + if(m_Popup != POPUP_NONE) + { + RenderPopupFullscreen(Screen); + } + else if(m_ShowStart) { - m_pBackground->ChangePosition(CMenuBackground::POS_START); RenderStartMenu(Screen); } else @@ -1078,93 +1106,95 @@ void CMenus::Render() CUIRect TabBar, MainView; Screen.HSplitTop(24.0f, &TabBar, &MainView); - // render news - if(m_MenuPage < PAGE_NEWS || m_MenuPage > PAGE_SETTINGS || (Client()->State() == IClient::STATE_OFFLINE && m_MenuPage >= PAGE_GAME && m_MenuPage <= PAGE_CALLVOTE)) + if(m_MenuPage == PAGE_NEWS) { - ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET); - SetMenuPage(PAGE_INTERNET); - } - - // render current page - if(Client()->State() != IClient::STATE_OFFLINE) - { - if(m_GamePage == PAGE_GAME) - { - RenderGame(MainView); - RenderIngameHint(); - } - else if(m_GamePage == PAGE_PLAYERS) - { - RenderPlayers(MainView); - } - else if(m_GamePage == PAGE_SERVER_INFO) - { - RenderServerInfo(MainView); - } - else if(m_GamePage == PAGE_NETWORK) - { - RenderInGameNetwork(MainView); - } - else if(m_GamePage == PAGE_GHOST) - { - RenderGhost(MainView); - } - else if(m_GamePage == PAGE_CALLVOTE) - { - RenderServerControl(MainView); - } - else if(m_GamePage == PAGE_SETTINGS) - { - RenderSettings(MainView); - } - } - else if(m_MenuPage == PAGE_NEWS) - { - m_pBackground->ChangePosition(CMenuBackground::POS_NEWS); RenderNews(MainView); } - else if(m_MenuPage == PAGE_INTERNET) + else if(m_MenuPage >= PAGE_INTERNET && m_MenuPage <= PAGE_FAVORITE_COMMUNITY_3) { - m_pBackground->ChangePosition(CMenuBackground::POS_BROWSER_INTERNET); - RenderServerbrowser(MainView); - } - else if(m_MenuPage == PAGE_LAN) - { - m_pBackground->ChangePosition(CMenuBackground::POS_BROWSER_LAN); RenderServerbrowser(MainView); } else if(m_MenuPage == PAGE_DEMOS) { - m_pBackground->ChangePosition(CMenuBackground::POS_DEMOS); RenderDemoBrowser(MainView); } - else if(m_MenuPage == PAGE_FAVORITES) - { - m_pBackground->ChangePosition(CMenuBackground::POS_BROWSER_FAVORITES); - RenderServerbrowser(MainView); - } - else if(m_MenuPage >= PAGE_FAVORITE_COMMUNITY_1 && m_MenuPage <= PAGE_FAVORITE_COMMUNITY_3) - { - m_pBackground->ChangePosition(m_MenuPage - PAGE_FAVORITE_COMMUNITY_1 + CMenuBackground::POS_BROWSER_CUSTOM0); - RenderServerbrowser(MainView); - } else if(m_MenuPage == PAGE_SETTINGS) { RenderSettings(MainView); } + else + { + dbg_assert(false, "m_MenuPage invalid"); + } - RenderMenubar(TabBar); + RenderMenubar(TabBar, ClientState); } - } - else - { - RenderPopupFullscreen(Screen); + break; + + case IClient::STATE_ONLINE: + if(m_Popup != POPUP_NONE) + { + RenderPopupFullscreen(Screen); + } + else + { + CUIRect TabBar, MainView; + Screen.HSplitTop(24.0f, &TabBar, &MainView); + + if(m_GamePage == PAGE_GAME) + { + RenderGame(MainView); + RenderIngameHint(); + } + else if(m_GamePage == PAGE_PLAYERS) + { + RenderPlayers(MainView); + } + else if(m_GamePage == PAGE_SERVER_INFO) + { + RenderServerInfo(MainView); + } + else if(m_GamePage == PAGE_NETWORK) + { + RenderInGameNetwork(MainView); + } + else if(m_GamePage == PAGE_GHOST) + { + RenderGhost(MainView); + } + else if(m_GamePage == PAGE_CALLVOTE) + { + RenderServerControl(MainView); + } + else if(m_GamePage == PAGE_SETTINGS) + { + RenderSettings(MainView); + } + else + { + dbg_assert(false, "m_GamePage invalid"); + } + + RenderMenubar(TabBar, ClientState); + } + break; + + case IClient::STATE_DEMOPLAYBACK: + if(m_Popup != POPUP_NONE) + { + RenderPopupFullscreen(Screen); + } + else + { + RenderDemoPlayer(Screen); + } + break; } Ui()->RenderPopupMenus(); // Handle this escape hotkey after popup menus - if(!m_ShowStart && Client()->State() == IClient::STATE_OFFLINE && Ui()->ConsumeHotkey(CUi::HOTKEY_ESCAPE)) + if(!m_ShowStart && ClientState == IClient::STATE_OFFLINE && Ui()->ConsumeHotkey(CUi::HOTKEY_ESCAPE)) { m_ShowStart = true; } @@ -1177,7 +1207,6 @@ void CMenus::RenderPopupFullscreen(CUIRect Screen) const char *pExtraText = ""; const char *pButtonText = ""; bool TopAlign = false; - bool UseIpLabel = false; ColorRGBA BgColor = ColorRGBA(0.0f, 0.0f, 0.0f, 0.5f); if(m_Popup == POPUP_MESSAGE || m_Popup == POPUP_CONFIRM) @@ -1186,63 +1215,6 @@ void CMenus::RenderPopupFullscreen(CUIRect Screen) pExtraText = m_aPopupMessage; TopAlign = true; } - else if(m_Popup == POPUP_CONNECTING) - { - pTitle = Localize("Connecting to"); - UseIpLabel = true; - pButtonText = Localize("Abort"); - if(Client()->State() == IClient::STATE_CONNECTING && time_get() - Client()->StateStartTime() > time_freq()) - { - int Connectivity = Client()->UdpConnectivity(Client()->ConnectNetTypes()); - switch(Connectivity) - { - case IClient::CONNECTIVITY_UNKNOWN: - break; - case IClient::CONNECTIVITY_CHECKING: - pExtraText = Localize("Trying to determine UDP connectivity..."); - break; - case IClient::CONNECTIVITY_UNREACHABLE: - pExtraText = Localize("UDP seems to be filtered."); - break; - case IClient::CONNECTIVITY_DIFFERING_UDP_TCP_IP_ADDRESSES: - pExtraText = Localize("UDP and TCP IP addresses seem to be different. Try disabling VPN, proxy or network accelerators."); - break; - case IClient::CONNECTIVITY_REACHABLE: - pExtraText = Localize("No answer from server yet."); - break; - } - } - else if(Client()->MapDownloadTotalsize() > 0) - { - str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Downloading map"), Client()->MapDownloadName()); - pTitle = aBuf; - UseIpLabel = false; - } - else if(Client()->State() == IClient::STATE_LOADING) - { - UseIpLabel = false; - if(Client()->LoadingStateDetail() == IClient::LOADING_STATE_DETAIL_INITIAL) - { - pTitle = Localize("Connected"); - pExtraText = Localize("Getting game info"); - } - else if(Client()->LoadingStateDetail() == IClient::LOADING_STATE_DETAIL_LOADING_MAP) - { - pTitle = Localize("Connected"); - pExtraText = Localize("Loading map file from storage"); - } - else if(Client()->LoadingStateDetail() == IClient::LOADING_STATE_DETAIL_SENDING_READY) - { - pTitle = Localize("Connected"); - pExtraText = Localize("Requesting to join the game"); - } - else if(Client()->LoadingStateDetail() == IClient::LOADING_STATE_DETAIL_GETTING_READY) - { - pTitle = Localize("Connected"); - pExtraText = Localize("Sending initial client info"); - } - } - } else if(m_Popup == POPUP_DISCONNECTED) { pTitle = Localize("Disconnected"); @@ -1350,16 +1322,6 @@ void CMenus::RenderPopupFullscreen(CUIRect Screen) float FontSize = m_Popup == POPUP_FIRST_LAUNCH ? 16.0f : 20.f; - if(UseIpLabel) - { - SLabelProperties IpLabelProps; - IpLabelProps.m_MaxWidth = Part.w; - IpLabelProps.m_EllipsisAtEnd = true; - Ui()->DoLabel(&Part, Client()->ConnectAddressString(), FontSize, TEXTALIGN_MC, IpLabelProps); - Box.HSplitTop(20.f, &Part, &Box); - Box.HSplitTop(24.f, &Part, &Box); - } - Props.m_MaxWidth = (int)Part.w; if(TopAlign) Ui()->DoLabel(&Part, pExtraText, FontSize, TEXTALIGN_TL, Props); @@ -1477,73 +1439,6 @@ void CMenus::RenderPopupFullscreen(CUIRect Screen) Ui()->DoLabel(&Label, Localize("Password"), 18.0f, TEXTALIGN_ML); Ui()->DoClearableEditBox(&m_PasswordInput, &TextBox, 12.0f); } - else if(m_Popup == POPUP_CONNECTING) - { - Box = Screen; - Box.Margin(150.0f, &Box); - Box.HSplitBottom(20.f, &Box, &Part); - Box.HSplitBottom(24.f, &Box, &Part); - Part.VMargin(120.0f, &Part); - - static CButtonContainer s_Button; - if(DoButton_Menu(&s_Button, pButtonText, 0, &Part) || Ui()->ConsumeHotkey(CUi::HOTKEY_ESCAPE)) - { - Client()->Disconnect(); - m_Popup = POPUP_NONE; - RefreshBrowserTab(g_Config.m_UiPage); - } - - if(Client()->MapDownloadTotalsize() > 0) - { - int64_t Now = time_get(); - if(Now - m_DownloadLastCheckTime >= time_freq()) - { - if(m_DownloadLastCheckSize > Client()->MapDownloadAmount()) - { - // map downloaded restarted - m_DownloadLastCheckSize = 0; - } - - // update download speed - float Diff = (Client()->MapDownloadAmount() - m_DownloadLastCheckSize) / ((int)((Now - m_DownloadLastCheckTime) / time_freq())); - float StartDiff = m_DownloadLastCheckSize - 0.0f; - if(StartDiff + Diff > 0.0f) - m_DownloadSpeed = (Diff / (StartDiff + Diff)) * (Diff / 1.0f) + (StartDiff / (Diff + StartDiff)) * m_DownloadSpeed; - else - m_DownloadSpeed = 0.0f; - m_DownloadLastCheckTime = Now; - m_DownloadLastCheckSize = Client()->MapDownloadAmount(); - } - - Box.HSplitTop(64.f, 0, &Box); - Box.HSplitTop(24.f, &Part, &Box); - str_format(aBuf, sizeof(aBuf), "%d/%d KiB (%.1f KiB/s)", Client()->MapDownloadAmount() / 1024, Client()->MapDownloadTotalsize() / 1024, m_DownloadSpeed / 1024.0f); - Ui()->DoLabel(&Part, aBuf, 20.f, TEXTALIGN_MC); - - // time left - int TimeLeft = maximum(1, m_DownloadSpeed > 0.0f ? static_cast((Client()->MapDownloadTotalsize() - Client()->MapDownloadAmount()) / m_DownloadSpeed) : 1); - if(TimeLeft >= 60) - { - TimeLeft /= 60; - str_format(aBuf, sizeof(aBuf), TimeLeft == 1 ? Localize("%i minute left") : Localize("%i minutes left"), TimeLeft); - } - else - { - str_format(aBuf, sizeof(aBuf), TimeLeft == 1 ? Localize("%i second left") : Localize("%i seconds left"), TimeLeft); - } - Box.HSplitTop(20.f, 0, &Box); - Box.HSplitTop(24.f, &Part, &Box); - Ui()->DoLabel(&Part, aBuf, 20.f, TEXTALIGN_MC); - - // progress bar - Box.HSplitTop(20.f, 0, &Box); - Box.HSplitTop(24.f, &Part, &Box); - Part.VMargin(40.0f, &Part); - Part.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, 5.0f); - Part.w = maximum(10.0f, (Part.w * Client()->MapDownloadAmount()) / Client()->MapDownloadTotalsize()); - Part.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f), IGraphics::CORNER_ALL, 5.0f); - } - } else if(m_Popup == POPUP_LANGUAGE) { CUIRect Button; @@ -1711,7 +1606,6 @@ void CMenus::RenderPopupFullscreen(CUIRect Screen) const char *pPaused = m_StartPaused ? Localize("(paused)") : ""; str_format(aBuffer, sizeof(aBuffer), "%s: ×%g %s", Localize("Speed"), g_aSpeeds[m_Speed], pPaused); Ui()->DoLabel(&Row, aBuffer, 12.8f, TEXTALIGN_ML); - Box.HSplitBottom(16.0f, &Box, nullptr); Box.HSplitBottom(24.0f, &Box, &Row); @@ -1868,6 +1762,187 @@ void CMenus::RenderPopupFullscreen(CUIRect Screen) Ui()->SetActiveItem(nullptr); } +void CMenus::RenderPopupConnecting(CUIRect Screen) +{ + const float FontSize = 20.0f; + + CUIRect Box, Label; + Screen.Margin(150.0f, &Box); + Box.Draw(ColorRGBA(0.0f, 0.0f, 0.0f, 0.5f), IGraphics::CORNER_ALL, 15.0f); + Box.Margin(20.0f, &Box); + + Box.HSplitTop(24.0f, &Label, &Box); + Ui()->DoLabel(&Label, Localize("Connecting to"), 24.0f, TEXTALIGN_MC); + + Box.HSplitTop(20.0f, nullptr, &Box); + Box.HSplitTop(24.0f, &Label, &Box); + SLabelProperties Props; + Props.m_MaxWidth = Label.w; + Props.m_EllipsisAtEnd = true; + Ui()->DoLabel(&Label, Client()->ConnectAddressString(), FontSize, TEXTALIGN_MC, Props); + + if(time_get() - Client()->StateStartTime() > time_freq()) + { + const char *pConnectivityLabel = ""; + switch(Client()->UdpConnectivity(Client()->ConnectNetTypes())) + { + case IClient::CONNECTIVITY_UNKNOWN: + break; + case IClient::CONNECTIVITY_CHECKING: + pConnectivityLabel = Localize("Trying to determine UDP connectivity..."); + break; + case IClient::CONNECTIVITY_UNREACHABLE: + pConnectivityLabel = Localize("UDP seems to be filtered."); + break; + case IClient::CONNECTIVITY_DIFFERING_UDP_TCP_IP_ADDRESSES: + pConnectivityLabel = Localize("UDP and TCP IP addresses seem to be different. Try disabling VPN, proxy or network accelerators."); + break; + case IClient::CONNECTIVITY_REACHABLE: + pConnectivityLabel = Localize("No answer from server yet."); + break; + } + if(pConnectivityLabel[0] != '\0') + { + Box.HSplitTop(20.0f, nullptr, &Box); + Box.HSplitTop(24.0f, &Label, &Box); + SLabelProperties ConnectivityLabelProps; + ConnectivityLabelProps.m_MaxWidth = Label.w; + if(TextRender()->TextWidth(FontSize, pConnectivityLabel) > Label.w) + Ui()->DoLabel(&Label, pConnectivityLabel, FontSize, TEXTALIGN_ML, ConnectivityLabelProps); + else + Ui()->DoLabel(&Label, pConnectivityLabel, FontSize, TEXTALIGN_MC); + } + } + + CUIRect Button; + Box.HSplitBottom(24.0f, &Box, &Button); + Button.VMargin(100.0f, &Button); + + static CButtonContainer s_Button; + if(DoButton_Menu(&s_Button, Localize("Abort"), 0, &Button) || Ui()->ConsumeHotkey(CUi::HOTKEY_ESCAPE)) + { + Client()->Disconnect(); + Ui()->SetActiveItem(nullptr); + RefreshBrowserTab(g_Config.m_UiPage); + } +} + +void CMenus::RenderPopupLoading(CUIRect Screen) +{ + char aTitle[256]; + char aLabel1[128]; + char aLabel2[128]; + if(Client()->MapDownloadTotalsize() > 0) + { + const int64_t Now = time_get(); + if(Now - m_DownloadLastCheckTime >= time_freq()) + { + if(m_DownloadLastCheckSize > Client()->MapDownloadAmount()) + { + // map downloaded restarted + m_DownloadLastCheckSize = 0; + } + + // update download speed + const float Diff = (Client()->MapDownloadAmount() - m_DownloadLastCheckSize) / ((int)((Now - m_DownloadLastCheckTime) / time_freq())); + const float StartDiff = m_DownloadLastCheckSize - 0.0f; + if(StartDiff + Diff > 0.0f) + m_DownloadSpeed = (Diff / (StartDiff + Diff)) * (Diff / 1.0f) + (StartDiff / (Diff + StartDiff)) * m_DownloadSpeed; + else + m_DownloadSpeed = 0.0f; + m_DownloadLastCheckTime = Now; + m_DownloadLastCheckSize = Client()->MapDownloadAmount(); + } + + str_format(aTitle, sizeof(aTitle), "%s: %s", Localize("Downloading map"), Client()->MapDownloadName()); + + str_format(aLabel1, sizeof(aLabel1), "%d/%d KiB (%.1f KiB/s)", Client()->MapDownloadAmount() / 1024, Client()->MapDownloadTotalsize() / 1024, m_DownloadSpeed / 1024.0f); + + const int SecondsLeft = maximum(1, m_DownloadSpeed > 0.0f ? static_cast((Client()->MapDownloadTotalsize() - Client()->MapDownloadAmount()) / m_DownloadSpeed) : 1); + const int MinutesLeft = SecondsLeft / 60; + if(MinutesLeft > 0) + { + str_format(aLabel2, sizeof(aLabel2), MinutesLeft == 1 ? Localize("%i minute left") : Localize("%i minutes left"), MinutesLeft); + } + else + { + str_format(aLabel2, sizeof(aLabel2), SecondsLeft == 1 ? Localize("%i second left") : Localize("%i seconds left"), SecondsLeft); + } + } + else + { + str_copy(aTitle, Localize("Connected")); + switch(Client()->LoadingStateDetail()) + { + case IClient::LOADING_STATE_DETAIL_INITIAL: + str_copy(aLabel1, Localize("Getting game info")); + break; + case IClient::LOADING_STATE_DETAIL_LOADING_MAP: + str_copy(aLabel1, Localize("Loading map file from storage")); + break; + case IClient::LOADING_STATE_DETAIL_SENDING_READY: + str_copy(aLabel1, Localize("Requesting to join the game")); + break; + case IClient::LOADING_STATE_DETAIL_GETTING_READY: + str_copy(aLabel1, Localize("Sending initial client info")); + break; + default: + dbg_assert(false, "Invalid loading state for RenderPopupLoading"); + break; + } + aLabel2[0] = '\0'; + } + + const float FontSize = 20.0f; + + CUIRect Box, Label; + Screen.Margin(150.0f, &Box); + Box.Draw(ColorRGBA(0.0f, 0.0f, 0.0f, 0.5f), IGraphics::CORNER_ALL, 15.0f); + Box.Margin(20.0f, &Box); + + Box.HSplitTop(24.0f, &Label, &Box); + Ui()->DoLabel(&Label, aTitle, 24.0f, TEXTALIGN_MC); + + Box.HSplitTop(20.0f, nullptr, &Box); + Box.HSplitTop(24.0f, &Label, &Box); + Ui()->DoLabel(&Label, aLabel1, FontSize, TEXTALIGN_MC); + + if(aLabel2[0] != '\0') + { + Box.HSplitTop(20.0f, nullptr, &Box); + Box.HSplitTop(24.0f, &Label, &Box); + SLabelProperties ExtraTextProps; + ExtraTextProps.m_MaxWidth = Label.w; + if(TextRender()->TextWidth(FontSize, aLabel2) > Label.w) + Ui()->DoLabel(&Label, aLabel2, FontSize, TEXTALIGN_ML, ExtraTextProps); + else + Ui()->DoLabel(&Label, aLabel2, FontSize, TEXTALIGN_MC); + } + + if(Client()->MapDownloadTotalsize() > 0) + { + CUIRect ProgressBar; + Box.HSplitTop(20.0f, nullptr, &Box); + Box.HSplitTop(24.0f, &ProgressBar, &Box); + ProgressBar.VMargin(20.0f, &ProgressBar); + ProgressBar.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, 5.0f); + ProgressBar.w = maximum(10.0f, (ProgressBar.w * Client()->MapDownloadAmount()) / Client()->MapDownloadTotalsize()); + ProgressBar.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f), IGraphics::CORNER_ALL, 5.0f); + } + + CUIRect Button; + Box.HSplitBottom(24.0f, &Box, &Button); + Button.VMargin(100.0f, &Button); + + static CButtonContainer s_Button; + if(DoButton_Menu(&s_Button, Localize("Abort"), 0, &Button) || Ui()->ConsumeHotkey(CUi::HOTKEY_ESCAPE)) + { + Client()->Disconnect(); + Ui()->SetActiveItem(nullptr); + RefreshBrowserTab(g_Config.m_UiPage); + } +} + #if defined(CONF_VIDEORECORDER) void CMenus::PopupConfirmDemoReplaceVideo() { @@ -2055,15 +2130,10 @@ void CMenus::OnStateChange(int NewState, int OldState) } else if(NewState == IClient::STATE_LOADING) { - m_Popup = POPUP_CONNECTING; m_DownloadLastCheckTime = time_get(); m_DownloadLastCheckSize = 0; m_DownloadSpeed = 0.0f; } - else if(NewState == IClient::STATE_CONNECTING) - { - m_Popup = POPUP_CONNECTING; - } else if(NewState == IClient::STATE_ONLINE || NewState == IClient::STATE_DEMOPLAYBACK) { if(m_Popup != POPUP_WARNING) @@ -2086,12 +2156,6 @@ void CMenus::OnRender() if(Client()->State() != IClient::STATE_ONLINE && Client()->State() != IClient::STATE_DEMOPLAYBACK) SetActive(true); - if(Client()->State() == IClient::STATE_DEMOPLAYBACK) - { - Ui()->MapScreen(); - RenderDemoPlayer(*Ui()->Screen()); - } - if(Client()->State() == IClient::STATE_ONLINE && m_pClient->m_ServerMode == CGameClient::SERVERMODE_PUREMOD) { Client()->Disconnect(); diff --git a/src/game/client/components/menus.h b/src/game/client/components/menus.h index a0b7e8d0d..9c2cef052 100644 --- a/src/game/client/components/menus.h +++ b/src/game/client/components/menus.h @@ -164,7 +164,6 @@ protected: int m_MenuPage; int m_GamePage; int m_Popup; - int m_ActivePage; bool m_ShowStart; bool m_MenuActive; @@ -421,10 +420,12 @@ protected: // found in menus.cpp void Render(); void RenderPopupFullscreen(CUIRect Screen); + void RenderPopupConnecting(CUIRect Screen); + void RenderPopupLoading(CUIRect Screen); #if defined(CONF_VIDEORECORDER) void PopupConfirmDemoReplaceVideo(); #endif - void RenderMenubar(CUIRect Box); + void RenderMenubar(CUIRect Box, IClient::EClientState ClientState); void RenderNews(CUIRect MainView); static void ConchainUpdateMusicState(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); void UpdateMusicState(); @@ -748,7 +749,6 @@ public: POPUP_CONFIRM, // generic confirmation popup (two buttons) POPUP_FIRST_LAUNCH, POPUP_POINTS, - POPUP_CONNECTING, POPUP_DISCONNECTED, POPUP_LANGUAGE, POPUP_RENAME_DEMO, diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp index 1eab9762a..962576ed5 100644 --- a/src/game/client/components/menus_browser.cpp +++ b/src/game/client/components/menus_browser.cpp @@ -1704,6 +1704,26 @@ void CMenus::RenderServerbrowser(CUIRect MainView) { UpdateCommunityCache(false); + switch(g_Config.m_UiPage) + { + case PAGE_INTERNET: + m_pBackground->ChangePosition(CMenuBackground::POS_BROWSER_INTERNET); + break; + case PAGE_LAN: + m_pBackground->ChangePosition(CMenuBackground::POS_BROWSER_LAN); + break; + case PAGE_FAVORITES: + m_pBackground->ChangePosition(CMenuBackground::POS_BROWSER_FAVORITES); + break; + case PAGE_FAVORITE_COMMUNITY_1: + case PAGE_FAVORITE_COMMUNITY_2: + case PAGE_FAVORITE_COMMUNITY_3: + m_pBackground->ChangePosition(g_Config.m_UiPage - PAGE_FAVORITE_COMMUNITY_1 + CMenuBackground::POS_BROWSER_CUSTOM0); + break; + default: + dbg_assert(false, "ui_page invalid for RenderServerbrowser"); + } + /* +---------------------------+ +---communities---+ | | | | diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index e314ae600..45fba889c 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -1060,6 +1060,8 @@ void CMenus::FetchAllHeaders() void CMenus::RenderDemoBrowser(CUIRect MainView) { + m_pBackground->ChangePosition(CMenuBackground::POS_DEMOS); + CUIRect ListView, DetailsView, ButtonsView; MainView.Draw(ms_ColorTabbarActive, IGraphics::CORNER_B, 10.0f); MainView.Margin(10.0f, &MainView); diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index 535c822d7..fbc5b2b28 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -2105,6 +2105,10 @@ void CMenus::RenderSettings(CUIRect MainView) m_pBackground->ChangePosition(CMenuBackground::POS_SETTINGS_ASSETS); RenderSettingsCustom(MainView); } + else + { + dbg_assert(false, "ui_settings_page invalid"); + } if(m_NeedRestartGraphics || m_NeedRestartSound || m_NeedRestartUpdate) { diff --git a/src/game/client/components/menus_start.cpp b/src/game/client/components/menus_start.cpp index f646811ef..fed08e550 100644 --- a/src/game/client/components/menus_start.cpp +++ b/src/game/client/components/menus_start.cpp @@ -19,6 +19,8 @@ void CMenus::RenderStartMenu(CUIRect MainView) { + m_pBackground->ChangePosition(CMenuBackground::POS_START); + // render logo Graphics()->TextureSet(g_pData->m_aImages[IMAGE_BANNER].m_Id); Graphics()->QuadsBegin();