RigsofRods
Soft-body Physics Simulation
GUI_MultiplayerClientList.cpp
Go to the documentation of this file.
1 /*
2  This source file is part of Rigs of Rods
3  Copyright 2005-2012 Pierre-Michel Ricordel
4  Copyright 2007-2012 Thomas Fischer
5  Copyright 2013-2020 Petr Ohlidal
6 
7  For more information, see http://www.rigsofrods.org/
8 
9  Rigs of Rods is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License version 3, as
11  published by the Free Software Foundation.
12 
13  Rigs of Rods is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
25 
27 
28 
30 
31 #include "Application.h"
32 #include "ActorManager.h"
33 #include "GameContext.h"
34 #include "GUIManager.h"
35 #include "GUIUtils.h"
36 #include "Language.h"
37 #include "Network.h"
38 
39 #include <vector>
40 
41 using namespace RoR;
42 using namespace GUI;
43 using namespace Ogre;
44 
46 {
47 #if USE_SOCKETW
48  m_users = App::GetNetwork()->GetUserInfos();
49  m_users.insert(m_users.begin(), App::GetNetwork()->GetLocalUserData());
50 #endif // USE_SOCKETW
51 }
52 
54 {
55 #if USE_SOCKETW
56  if (m_users.empty())
57  return; // UpdateClients() wasn't called yet.
58 
59  if (!m_icons_cached)
60  {
61  this->CacheIcons();
62  }
63 
65 
66  ImGuiWindowFlags flags = ImGuiWindowFlags_NoCollapse |
67  ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar;
68  const float content_width = 200.f;
69  ImGui::SetNextWindowContentWidth(content_width);
70  ImGui::SetNextWindowPos(ImVec2(
71  ImGui::GetIO().DisplaySize.x - (content_width + (2*ImGui::GetStyle().WindowPadding.x) + theme.screen_edge_padding.x),
72  theme.screen_edge_padding.y));
73 
74  int y = 20 + (ImGui::GetTextLineHeightWithSpacing() * m_users.size());
75 
76  if (App::GetNetwork()->GetNetQuality() != 0)
77  {
78  y += 20;
79  }
80 
81  ImGui::SetNextWindowSize(ImVec2((content_width + (2*ImGui::GetStyle().WindowPadding.x)), y));
82  ImGui::PushStyleColor(ImGuiCol_WindowBg, theme.semitransparent_window_bg);
83  ImGui::Begin("Peers", nullptr, flags);
84 
85  const RoRnet::UserInfo& local_user = m_users[0]; // See `UpdateClients()`
86  for (RoRnet::UserInfo const& user: m_users)
87  {
88  // Icon sizes: flag(16x11), auth(16x16), up(16x16), down(16x16)
89  bool hovered = false;
90  Ogre::TexturePtr flag_tex;
91  Ogre::TexturePtr auth_tex;
92  Ogre::TexturePtr down_tex;
93  Ogre::TexturePtr up_tex;
94 
95  // Stream state indicators
96  if (user.uniqueid != local_user.uniqueid &&
98  {
99  switch (App::GetGameContext()->GetActorManager()->CheckNetworkStreamsOk(user.uniqueid))
100  {
101  case 0: down_tex = m_icon_arrow_down_red; break;
102  case 1: down_tex = m_icon_arrow_down; break;
103  case 2: down_tex = m_icon_arrow_down_grey; break;
104  default:;
105  }
106 
107 
108  switch (App::GetGameContext()->GetActorManager()->CheckNetRemoteStreamsOk(user.uniqueid))
109  {
110  case 0: up_tex = m_icon_arrow_up_red; break;
111  case 1: up_tex = m_icon_arrow_up; break;
112  case 2: up_tex = m_icon_arrow_up_grey; break;
113  default:;
114  }
115  }
116  // Always invoke to keep usernames aligned
117  hovered |= this->DrawIcon(down_tex, ImVec2(8.f, ImGui::GetTextLineHeight()));
118  hovered |= this->DrawIcon(up_tex, ImVec2(8.f, ImGui::GetTextLineHeight()));
119 
120  // Auth icon
121  if (user.authstatus & RoRnet::AUTH_ADMIN ) { auth_tex = m_icon_flag_red; }
122  else if (user.authstatus & RoRnet::AUTH_MOD ) { auth_tex = m_icon_flag_blue; }
123  else if (user.authstatus & RoRnet::AUTH_RANKED) { auth_tex = m_icon_flag_green; }
124 
125  hovered |= this->DrawIcon(auth_tex, ImVec2(14.f, ImGui::GetTextLineHeight()));
126 
127  // Country flag
128  StringVector parts = StringUtil::split(user.language, "_");
129  if (parts.size() == 2)
130  {
131  StringUtil::toLowerCase(parts[1]);
132  flag_tex = FetchIcon((parts[1] + ".png").c_str());
133  hovered |= this->DrawIcon(flag_tex, ImVec2(16.f, ImGui::GetTextLineHeight()));
134  }
135 
136  // Player name
137  ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().ItemSpacing.x); // Some extra padding
138  ColourValue col = App::GetNetwork()->GetPlayerColor(user.colournum);
139  ImGui::TextColored(ImVec4(col.r, col.g, col.b, col.a), "%s", user.username);
140  hovered |= ImGui::IsItemHovered();
141 
142  // Tooltip
143  if (hovered)
144  {
145  ImGui::BeginTooltip();
146 
147  // TextDisabled() are captions, Text() are values
148 
149  ImGui::TextDisabled("%s: ",_LC("MultiplayerClientList", "user name"));
150  ImGui::SameLine();
151  ImGui::TextColored(ImVec4(col.r, col.g, col.b, col.a), "%s", user.username);
152  ImGui::Separator();
153 
154  ImGui::TextDisabled("%s: ",_LC("MultiplayerClientList", "user uid"));
155  ImGui::SameLine();
156  ImGui::Text("%d", user.uniqueid);
157 
158  ImGui::TextDisabled("%s", _LC("MultiplayerClientList", "user language: "));
159  ImGui::SameLine();
160  ImGui::Text("%s", parts[0].c_str());
161 
162  ImGui::TextDisabled("%s", _LC("MultiplayerClientList", "user country: "));
163  ImGui::SameLine();
164  ImGui::Text("%s", parts[1].c_str());
165  if (flag_tex)
166  {
167  ImGui::SameLine();
168  ImGui::Image(reinterpret_cast<ImTextureID>(flag_tex->getHandle()),
169  ImVec2(flag_tex->getWidth(), flag_tex->getHeight()));
170  }
171 
172  ImGui::Separator();
173  ImGui::TextDisabled("%s", _LC("MultiplayerClientList", "user authentication level"));
174  if (auth_tex)
175  {
176  ImGui::Image(reinterpret_cast<ImTextureID>(auth_tex->getHandle()),
177  ImVec2(auth_tex->getWidth(), auth_tex->getHeight()));
178  ImGui::SameLine();
179  }
180 
181  ImGui::Text("%s", App::GetNetwork()->UserAuthToStringLong(user).c_str());
182 
183  // Stream state
184  if (user.uniqueid != local_user.uniqueid &&
186  {
187  ImGui::Separator();
188  ImGui::TextDisabled("%s", _LC("MultiplayerClientList", "truck loading state"));
189  if (down_tex)
190  {
191  ImGui::Image(reinterpret_cast<ImTextureID>(down_tex->getHandle()),
192  ImVec2(down_tex->getWidth(), down_tex->getHeight()));
193  ImGui::SameLine();
194  }
195  switch (App::GetGameContext()->GetActorManager()->CheckNetworkStreamsOk(user.uniqueid))
196  {
197  case 0: ImGui::Text("%s", _LC("MultiplayerClientList", "Truck loading errors")); break;
198  case 1: ImGui::Text("%s", _LC("MultiplayerClientList", "Truck loaded correctly, no errors")); break;
199  case 2: ImGui::Text("%s", _LC("MultiplayerClientList", "no truck loaded")); break;
200  default:; // never happens
201  }
202 
203  ImGui::TextDisabled("%s", _LC("MultiplayerClientList", "remote truck loading state"));
204  if (up_tex)
205  {
206  ImGui::Image(reinterpret_cast<ImTextureID>(up_tex->getHandle()),
207  ImVec2(up_tex->getWidth(), up_tex->getHeight()));
208  ImGui::SameLine();
209  }
210  switch (App::GetGameContext()->GetActorManager()->CheckNetRemoteStreamsOk(user.uniqueid))
211  {
212  case 0: ImGui::Text("%s", _LC("MultiplayerClientList", "Remote Truck loading errors")); break;
213  case 1: ImGui::Text("%s", _LC("MultiplayerClientList", "Remote Truck loaded correctly, no errors")); break;
214  case 2: ImGui::Text("%s", _LC("MultiplayerClientList", "No Trucks loaded")); break;
215  default:; // never happens
216  }
217  }
218 
219  ImGui::EndTooltip();
220  }
221  }
222 
223  if (App::GetNetwork()->GetNetQuality() != 0)
224  {
225  ImGui::Separator();
226  ImGui::Image(reinterpret_cast<ImTextureID>(m_icon_warn_triangle->getHandle()),
227  ImVec2(m_icon_warn_triangle->getWidth(), m_icon_warn_triangle->getHeight()));
228  ImGui::SameLine();
229  ImGui::TextColored(App::GetGuiManager()->GetTheme().error_text_color, "%s", _LC("MultiplayerClientList", "Slow Network Download"));
230  }
231 
232  ImGui::End();
233  ImGui::PopStyleColor(1); // WindowBg
234 #endif // USE_SOCKETW
235 }
236 
237 bool MpClientList::DrawIcon(Ogre::TexturePtr tex, ImVec2 reference_box)
238 {
239  ImVec2 orig_pos = ImGui::GetCursorPos();
240  bool hovered = false;
241  if (tex)
242  {
243  // TODO: moving the cursor somehow deforms the image
244  // ImGui::SetCursorPosX(orig_pos.x + (reference_box.x - tex->getWidth()) / 2.f);
245  // ImGui::SetCursorPosY(orig_pos.y + (reference_box.y - tex->getHeight()) / 2.f);
246  ImGui::Image(reinterpret_cast<ImTextureID>(tex->getHandle()), ImVec2(16, 16));
247  hovered = ImGui::IsItemHovered();
248  }
249  ImGui::SetCursorPosX(orig_pos.x + reference_box.x + ImGui::GetStyle().ItemSpacing.x);
250  ImGui::SetCursorPosY(orig_pos.y);
251  return hovered;
252 }
253 
255 {
256  m_icon_arrow_down = FetchIcon("arrow_down.png");
257  m_icon_arrow_down_grey = FetchIcon("arrow_down_grey.png");
258  m_icon_arrow_down_red = FetchIcon("arrow_down_red.png");
259  m_icon_arrow_up = FetchIcon("arrow_up.png");
260  m_icon_arrow_up_grey = FetchIcon("arrow_up_grey.png");
261  m_icon_arrow_up_red = FetchIcon("arrow_up_red.png");
262  m_icon_flag_red = FetchIcon("flag_red.png");
263  m_icon_flag_blue = FetchIcon("flag_blue.png");
264  m_icon_flag_green = FetchIcon("flag_green.png");
265  m_icon_warn_triangle = FetchIcon("error.png");
266 
267  m_icons_cached = true;
268 }
GameContext.h
Game state manager and message-queue provider.
GUI_MultiplayerClientList.h
RoR::App::GetNetwork
Network * GetNetwork()
Definition: Application.cpp:284
y
float y
Definition: (ValueTypes) quaternion.h:6
RoR::Network::GetUserInfos
std::vector< RoRnet::UserInfo > GetUserInfos()
Definition: Network.cpp:703
RoR::FetchIcon
Ogre::TexturePtr FetchIcon(const char *name)
Definition: GUIUtils.cpp:343
RoR::GUIManager::GuiTheme
Definition: GUIManager.h:70
RoR::App::GetGuiManager
GUIManager * GetGuiManager()
Definition: Application.cpp:269
RoRnet::UserInfo
Definition: RoRnet.h:168
RoR::AppState::MAIN_MENU
@ MAIN_MENU
GUIUtils.h
RoR::AppState
AppState
Definition: Application.h:159
RoRnet::AUTH_ADMIN
@ AUTH_ADMIN
admin on the server
Definition: RoRnet.h:76
RoR::GUI::MpClientList::CacheIcons
void CacheIcons()
Definition: GUI_MultiplayerClientList.cpp:254
Language.h
RoR::GUIManager::GuiTheme::semitransparent_window_bg
ImVec4 semitransparent_window_bg
Definition: GUIManager.h:83
GUIManager.h
ActorManager.h
RoR::GUIManager::GetTheme
GuiTheme & GetTheme()
Definition: GUIManager.h:158
RoRnet::AUTH_MOD
@ AUTH_MOD
moderator status
Definition: RoRnet.h:78
RoR::App::app_state
CVar * app_state
Definition: Application.cpp:79
RoR::Network::GetNetQuality
int GetNetQuality()
Definition: Network.cpp:117
Application.h
Central state/object manager and communications hub.
RoR::Network::GetLocalUserData
RoRnet::UserInfo GetLocalUserData()
Definition: Network.cpp:697
RoR::App::GetGameContext
GameContext * GetGameContext()
Definition: Application.cpp:280
RoR::CVar::getEnum
T getEnum() const
Definition: CVar.h:99
RoRnet::AUTH_RANKED
@ AUTH_RANKED
ranked status
Definition: RoRnet.h:77
_LC
#define _LC(ctx, str)
Definition: Language.h:42
RoR::Network::GetPlayerColor
Ogre::ColourValue GetPlayerColor(int color_num)
Definition: Network.cpp:94
RoR::GUIManager::GuiTheme::screen_edge_padding
ImVec2 screen_edge_padding
Definition: GUIManager.h:87
RoRnet::UserInfo::uniqueid
uint32_t uniqueid
user unique id
Definition: RoRnet.h:170
RoR::GUI::MpClientList::DrawIcon
bool DrawIcon(Ogre::TexturePtr tex, ImVec2 reference_box)
Definition: GUI_MultiplayerClientList.cpp:237
RoR::GUI::MpClientList::UpdateClients
void UpdateClients()
Definition: GUI_MultiplayerClientList.cpp:45
Ogre
Definition: ExtinguishableFireAffector.cpp:35
RoR
Definition: AppContext.h:36
Network.h
RoR::GUI::MpClientList::Draw
void Draw()
Definition: GUI_MultiplayerClientList.cpp:53