diff --git a/source/main/Application.h b/source/main/Application.h index 28aeff713d..4a9c9f73ea 100644 --- a/source/main/Application.h +++ b/source/main/Application.h @@ -93,6 +93,7 @@ enum MsgType MSG_GUI_CLOSE_MENU_REQUESTED, MSG_GUI_OPEN_SELECTOR_REQUESTED, //!< Payload = LoaderType* (owner), Description = GUID | empty MSG_GUI_CLOSE_SELECTOR_REQUESTED, + MSG_GUI_MP_CLIENTS_REFRESH, // Editing MSG_EDI_MODIFY_GROUNDMODEL_REQUESTED, //!< Payload = ground_model_t* (weak) MSG_EDI_ENTER_TERRN_EDITOR_REQUESTED, diff --git a/source/main/gui/GUIManager.cpp b/source/main/gui/GUIManager.cpp index 347b03e4c5..f408202e8d 100644 --- a/source/main/gui/GUIManager.cpp +++ b/source/main/gui/GUIManager.cpp @@ -147,6 +147,7 @@ GUI::TopMenubar* GUIManager::GetTopMenubar() { return &m_impl- GUI::SurveyMap* GUIManager::GetSurveyMap() { return &m_impl->panel_SurveyMap ; } GUI::SimActorStats* GUIManager::GetSimActorStats() { return &m_impl->panel_SimActorStats ; } GUI::DirectionArrow* GUIManager::GetDirectionArrow() { return &m_impl->panel_DirectionArrow ; } +GUI::MpClientList* GUIManager::GetMpClientList() { return &m_impl->panel_MpClientList ; } GUIManager::GUIManager() { diff --git a/source/main/gui/GUIManager.h b/source/main/gui/GUIManager.h index 0b11e2d8ff..b3d5c91c14 100644 --- a/source/main/gui/GUIManager.h +++ b/source/main/gui/GUIManager.h @@ -118,6 +118,7 @@ class GUIManager: public ZeroedMemoryAllocator GUI::SurveyMap* GetSurveyMap(); GUI::SimActorStats* GetSimActorStats(); GUI::DirectionArrow* GetDirectionArrow(); + GUI::MpClientList* GetMpClientList(); // GUI manipulation void ShowMessageBox(const char* title, const char* text, bool allow_close = true, const char* btn1_text = "OK", const char* btn2_text = nullptr); diff --git a/source/main/gui/panels/GUI_MultiplayerClientList.cpp b/source/main/gui/panels/GUI_MultiplayerClientList.cpp index 300b31d703..a01f520b7f 100644 --- a/source/main/gui/panels/GUI_MultiplayerClientList.cpp +++ b/source/main/gui/panels/GUI_MultiplayerClientList.cpp @@ -41,6 +41,12 @@ using namespace RoR; using namespace GUI; using namespace Ogre; +void MpClientList::UpdateClients() +{ + m_users = App::GetNetwork()->GetUserInfos(); + m_users.insert(m_users.begin(), App::GetNetwork()->GetLocalUserData()); +} + void MpClientList::Draw() { GUIManager::GuiTheme const& theme = App::GetGuiManager()->GetTheme(); @@ -53,15 +59,14 @@ void MpClientList::Draw() ImGui::GetIO().DisplaySize.x - (content_width + (2*ImGui::GetStyle().WindowPadding.x) + theme.screen_edge_padding.x), theme.screen_edge_padding.y)); - std::vector users = App::GetNetwork()->GetUserInfos(); - users.insert(users.begin(), App::GetNetwork()->GetLocalUserData()); - int y = 20 + (ImGui::GetTextLineHeightWithSpacing() * users.size()); + int y = 20 + (ImGui::GetTextLineHeightWithSpacing() * m_users.size()); ImGui::SetNextWindowSize(ImVec2((content_width + (2*ImGui::GetStyle().WindowPadding.x)), y)); ImGui::PushStyleColor(ImGuiCol_WindowBg, theme.semitransparent_window_bg); ImGui::Begin("Peers", nullptr, flags); - for (RoRnet::UserInfo const& user: users) + const RoRnet::UserInfo& local_user = m_users[0]; // See `UpdateClients()` + for (RoRnet::UserInfo const& user: m_users) { // Icon sizes: flag(16x11), auth(16x16), up(16x16), down(16x16) bool hovered = false; @@ -71,7 +76,7 @@ void MpClientList::Draw() Ogre::TexturePtr up_tex; // Stream state indicators - if (user.uniqueid != App::GetNetwork()->GetLocalUserData().uniqueid && + if (user.uniqueid != local_user.uniqueid && App::app_state->GetEnum() != AppState::MAIN_MENU) { switch (App::GetGameContext()->GetActorManager()->CheckNetworkStreamsOk(user.uniqueid)) @@ -155,7 +160,7 @@ void MpClientList::Draw() ImGui::Text("%s", App::GetNetwork()->UserAuthToStringLong(user).c_str()); // Stream state - if (user.uniqueid != App::GetNetwork()->GetLocalUserData().uniqueid && + if (user.uniqueid != local_user.uniqueid && App::app_state->GetEnum() != AppState::MAIN_MENU) { ImGui::Separator(); diff --git a/source/main/gui/panels/GUI_MultiplayerClientList.h b/source/main/gui/panels/GUI_MultiplayerClientList.h index d6f932d95e..b20d89a2dc 100644 --- a/source/main/gui/panels/GUI_MultiplayerClientList.h +++ b/source/main/gui/panels/GUI_MultiplayerClientList.h @@ -27,6 +27,8 @@ #pragma once +#include "RoRnet.h" + #include #include @@ -37,9 +39,13 @@ class MpClientList { public: void Draw(); + void UpdateClients(); + private: Ogre::TexturePtr FetchIcon(const char* name); bool DrawIcon(Ogre::TexturePtr tex, ImVec2 reference_box); // Returns true if hovered + + std::vector m_users; // only updated on demand to reduce mutex locking and vector allocating overhead. }; } // namespace GUI diff --git a/source/main/main.cpp b/source/main/main.cpp index f2ec3c21f0..20298ec833 100644 --- a/source/main/main.cpp +++ b/source/main/main.cpp @@ -37,6 +37,7 @@ #include "GUI_LoadingWindow.h" #include "GUI_MainSelector.h" #include "GUI_MultiplayerSelector.h" +#include "GUI_MultiplayerClientList.h" #include "GUI_SimActorStats.h" #include "InputEngine.h" #include "Language.h" @@ -646,6 +647,10 @@ int main(int argc, char *argv[]) App::GetGuiManager()->GetMainSelector()->Close(); break; + case MSG_GUI_MP_CLIENTS_REFRESH: + App::GetGuiManager()->GetMpClientList()->UpdateClients(); + break; + // -- Editing events -- case MSG_EDI_MODIFY_GROUNDMODEL_REQUESTED: diff --git a/source/main/network/Network.cpp b/source/main/network/Network.cpp index b8d1ac7b00..b8ab97fdb1 100644 --- a/source/main/network/Network.cpp +++ b/source/main/network/Network.cpp @@ -300,6 +300,7 @@ void Network::RecvThread() bool was_kick = (std::strstr(buffer, "disconnected on request") == nullptr); // FIXME: Add a reason code to MSG2_USER_LEAVE, this is ugly! PushNetMessage((was_kick) ? MSG_NET_SERVER_KICK : MSG_NET_USER_DISCONNECT, msg.str()); + App::GetGameContext()->PushMessage(Message(MSG_GUI_MP_CLIENTS_REFRESH)); Message m((was_kick) ? MSG_NET_USER_DISCONNECT : MSG_NET_SERVER_KICK); } @@ -313,6 +314,7 @@ void Network::RecvThread() Str<300> text; text << _L("left the game"); App::GetConsole()->putNetMessage(user->uniqueid, Console::CONSOLE_SYSTEM_NOTICE, text.ToCStr()); + App::GetGameContext()->PushMessage(Message(MSG_GUI_MP_CLIENTS_REFRESH)); LOG_THREAD(text); m_disconnected_users.push_back(*user); // Copy @@ -328,6 +330,7 @@ void Network::RecvThread() memcpy(&m_userdata, buffer, sizeof(RoRnet::UserInfo)); m_authlevel = m_userdata.authstatus; m_username = Ogre::UTFString(m_userdata.username); + App::GetGameContext()->PushMessage(Message(MSG_GUI_MP_CLIENTS_REFRESH)); // TODO: Update the global variable 'mp_player_name' in a threadsafe way. } else @@ -346,6 +349,7 @@ void Network::RecvThread() // NB: Console is threadsafe App::GetConsole()->putNetMessage( user_info.uniqueid, Console::CONSOLE_SYSTEM_NOTICE, text.ToCStr()); + App::GetGameContext()->PushMessage(Message(MSG_GUI_MP_CLIENTS_REFRESH)); // Lock and update userlist std::lock_guard lock(m_users_mutex); m_users.push_back(user_info);