The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
lobby_info.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2017 by Tomasz Sniatowski <kailoran@gmail.com>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
16 
17 #include "formula/string_utils.hpp"
18 #include "gettext.hpp"
19 #include "log.hpp"
20 #include "map/exception.hpp"
21 #include "map/map.hpp"
22 #include "mp_ui_alerts.hpp"
23 #include "preferences/game.hpp"
24 #include "wesnothd_connection.hpp"
25 #include "wml_exception.hpp"
26 
27 #include <iterator>
28 
29 static lg::log_domain log_engine("engine");
30 #define WRN_NG LOG_STREAM(warn, log_engine)
31 
32 static lg::log_domain log_lobby("lobby");
33 #define DBG_LB LOG_STREAM(debug, log_lobby)
34 #define WRN_LB LOG_STREAM(warn, log_lobby)
35 #define ERR_LB LOG_STREAM(err, log_lobby)
36 #define SCOPE_LB log_scope2(log_lobby, __func__)
37 
38 namespace mp
39 {
40 lobby_info::lobby_info(const config& game_config, const std::vector<std::string>& installed_addons)
41  : game_config_(game_config)
42  , installed_addons_(installed_addons)
43  , gamelist_()
44  , gamelist_initialized_(false)
45  , rooms_()
46  , games_by_id_()
47  , games_()
48  , users_()
49  , users_sorted_()
50  , whispers_()
51  , game_filters_()
52  , game_filter_invert_(false)
53  , games_visibility_()
54 {
55 }
56 
57 void do_notify(notify_mode mode, const std::string& sender, const std::string& message)
58 {
59  switch(mode) {
60  case NOTIFY_WHISPER:
62  case NOTIFY_OWN_NICK:
63  mp_ui_alerts::private_message(true, sender, message);
64  break;
66  mp_ui_alerts::friend_message(true, sender, message);
67  break;
69  mp_ui_alerts::server_message(true, sender, message);
70  break;
71  case NOTIFY_LOBBY_QUIT:
73  break;
74  case NOTIFY_LOBBY_JOIN:
76  break;
77  case NOTIFY_MESSAGE:
78  mp_ui_alerts::public_message(true, sender, message);
79  break;
80  default:
81  break;
82  }
83 }
84 
85 namespace
86 {
87 std::string dump_games_map(const lobby_info::game_info_map& games)
88 {
89  std::stringstream ss;
90  for(const auto& v : games) {
91  const game_info& game = v.second;
92  ss << "G" << game.id << "(" << game.name << ") " << game.display_status_string() << " ";
93  }
94 
95  ss << "\n";
96  return ss.str();
97 }
98 
99 std::string dump_games_config(const config& gamelist)
100 {
101  std::stringstream ss;
102  for(const auto& c : gamelist.child_range("game")) {
103  ss << "g" << c["id"] << "(" << c["name"] << ") " << c[config::diff_track_attribute] << " ";
104  }
105 
106  ss << "\n";
107  return ss.str();
108 }
109 
110 } // end anonymous namespace
111 
113 {
114  SCOPE_LB;
115 
116  gamelist_ = data;
117  gamelist_initialized_ = true;
118 
119  games_by_id_.clear();
120 
121  for(const auto& c : gamelist_.child("gamelist").child_range("game")) {
123  games_by_id_.emplace(game.id, std::move(game));
124  }
125 
126  DBG_LB << dump_games_map(games_by_id_);
127  DBG_LB << dump_games_config(gamelist_.child("gamelist"));
128 
130 }
131 
133 {
134  SCOPE_LB;
135  if(!gamelist_initialized_) {
136  return false;
137  }
138 
139  DBG_LB << "prediff " << dump_games_config(gamelist_.child("gamelist"));
140 
141  try {
142  gamelist_.apply_diff(data, true);
143  } catch(config::error& e) {
144  ERR_LB << "Error while applying the gamelist diff: '" << e.message << "' Getting a new gamelist.\n";
145  return false;
146  }
147 
148  DBG_LB << "postdiff " << dump_games_config(gamelist_.child("gamelist"));
149  DBG_LB << dump_games_map(games_by_id_);
150 
151  for(config& c : gamelist_.child("gamelist").child_range("game")) {
152  DBG_LB << "data process: " << c["id"] << " (" << c[config::diff_track_attribute] << ")\n";
153 
154  const int game_id = c["id"];
155  if(game_id == 0) {
156  ERR_LB << "game with id 0 in gamelist config" << std::endl;
157  return false;
158  }
159 
160  auto current_i = games_by_id_.find(game_id);
161 
162  const std::string& diff_result = c[config::diff_track_attribute];
163 
164  if(diff_result == "new" || diff_result == "modified") {
165  if(current_i == games_by_id_.end()) {
166  games_by_id_.emplace(game_id, game_info(c, game_config_, installed_addons_));
167  continue;
168  }
169 
170  // Had a game with that id, so update it and mark it as such
171  current_i->second = game_info(c, game_config_, installed_addons_);
172  current_i->second.display_status = game_info::UPDATED;
173  } else if(diff_result == "deleted") {
174  if(current_i == games_by_id_.end()) {
175  WRN_LB << "Would have to delete a game that I don't have: " << game_id << std::endl;
176  continue;
177  }
178 
179  if(current_i->second.display_status == game_info::NEW) {
180  // This means the game never made it through to the user interface,
181  // so just deleting it is fine.
182  games_by_id_.erase(current_i);
183  } else {
184  current_i->second.display_status = game_info::DELETED;
185  }
186  }
187  }
188 
189  DBG_LB << dump_games_map(games_by_id_);
190 
191  try {
193  } catch(config::error& e) {
194  ERR_LB << "Error while applying the gamelist diff (2): '" << e.message << "' Getting a new gamelist.\n";
195  return false;
196  }
197 
198  DBG_LB << "postclean " << dump_games_config(gamelist_.child("gamelist"));
199 
201  return true;
202 }
203 
205 {
206  SCOPE_LB;
207 
208  users_.clear();
209  for(const auto& c : gamelist_.child_range("user")) {
210  users_.emplace_back(c);
211  }
212 
213  users_sorted_.reserve(users_.size());
214  users_sorted_.clear();
215 
216  for(auto& u : users_) {
217  users_sorted_.push_back(&u);
218  }
219 
220  for(auto& ui : users_) {
221  if(ui.game_id == 0) {
222  continue;
223  }
224 
225  game_info* g = get_game_by_id(ui.game_id);
226  if(!g) {
227  WRN_NG << "User " << ui.name << " has unknown game_id: " << ui.game_id << std::endl;
228  continue;
229  }
230 
231  switch(ui.relation) {
232  case user_info::FRIEND:
233  g->has_friends = true;
234  break;
235  case user_info::IGNORED:
236  g->has_ignored = true;
237  break;
238  default:
239  break;
240  }
241  }
242 }
243 
245 {
246  DBG_LB << "lobby_info::sync_games_display_status";
247  DBG_LB << "games_by_id_ size: " << games_by_id_.size();
248 
249  auto i = games_by_id_.begin();
250 
251  while(i != games_by_id_.end()) {
252  if(i->second.display_status == game_info::DELETED) {
253  i = games_by_id_.erase(i);
254  } else {
255  i->second.display_status = game_info::CLEAN;
256  ++i;
257  }
258  }
259 
260  DBG_LB << " -> " << games_by_id_.size() << std::endl;
261 
263 }
264 
266 {
267  auto i = games_by_id_.find(id);
268  return i == games_by_id_.end() ? nullptr : &i->second;
269 }
270 
272 {
273  auto i = games_by_id_.find(id);
274  return i == games_by_id_.end() ? nullptr : &i->second;
275 }
276 
278 {
279  for(auto& r : rooms_) {
280  if(r.name() == name) {
281  return &r;
282  }
283  }
284 
285  return nullptr;
286 }
287 
289 {
290  for(const auto& r : rooms_) {
291  if(r.name() == name) {
292  return &r;
293  }
294  }
295 
296  return nullptr;
297 }
298 
300 {
301  return get_room(name) != nullptr;
302 }
303 
305 {
306  for(auto& user : users_) {
307  if(user.name == name) {
308  return &user;
309  }
310  }
311 
312  return nullptr;
313 }
314 
316 {
317  if(!has_room(name)) {
318  rooms_.emplace_back(name);
319  }
320 }
321 
323 {
324  DBG_LB << "lobby info: closing room " << name << std::endl;
325 
326  if(room_info* r = get_room(name)) {
327  rooms_.erase(rooms_.begin() + (r - &rooms_[0]));
328  }
329 }
330 
332 {
333  games_.reserve(games_by_id_.size());
334  games_.clear();
335 
336  for(auto& v : games_by_id_) {
337  games_.push_back(&v.second);
338  }
339 
340  // Reset the visibility mask. Its size should then match games_'s and all its bits be true.
341  games_visibility_.resize(games_.size());
342  games_visibility_.reset();
343  games_visibility_.flip();
344 }
345 
347 {
348  // Since games_visibility_ is a visibility mask over games_,
349  // they need to be the same size or we'll end up with issues.
350  assert(games_visibility_.size() == games_.size());
351 
352  for(unsigned i = 0; i < games_.size(); ++i) {
353  bool show = true;
354 
355  for(const auto& filter_func : game_filters_) {
356  show = filter_func(*games_[i]);
357 
358  if(!show) {
359  break;
360  }
361  }
362 
363  if(game_filter_invert_) {
364  show = !show;
365  }
366 
368  }
369 }
370 
371 void lobby_info::update_user_statuses(int game_id, const room_info* room)
372 {
373  for(auto& user : users_) {
374  user.update_state(game_id, room);
375  }
376 }
377 
378 void lobby_info::sort_users(bool by_name, bool by_relation)
379 {
380  std::sort(users_sorted_.begin(), users_sorted_.end(), [&](const user_info* u1, const user_info* u2) {
381  if(by_name && by_relation) {
382  return u1->relation < u2->relation ||
383  (u1->relation == u2->relation && translation::icompare(u1->name, u2->name) < 0);
384  }
385 
386  return (by_name && translation::icompare(u1->name, u2->name) < 0) || (by_relation && u1->relation < u2->relation);
387  });
388 }
389 
390 } // end namespace mp
#define SCOPE_LB
Definition: lobby_info.cpp:36
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:400
std::vector< char_t > string
user_info * get_user(const std::string &name)
Returns info on the user with the given name, or nullptr if they don't eixst.
Definition: lobby_info.cpp:304
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
static lg::log_domain log_engine("engine")
This class represents the info a client has about a game on the server.
Definition: lobby_data.hpp:137
#define DBG_LB
Definition: lobby_info.cpp:33
child_itors child_range(config_key_type key)
Definition: config.cpp:343
std::map< int, game_info > game_info_map
Definition: lobby_info.hpp:35
void update_user_statuses(int game_id, const room_info *room)
Definition: lobby_info.cpp:371
std::vector< room_info > rooms_
Definition: lobby_info.hpp:163
void clear_diff_track(const config &diff)
Clear any tracking info from a previous apply_diff call with tracking.
Definition: config.cpp:1058
std::vector< game_filter_func > game_filters_
Definition: lobby_info.hpp:174
void process_gamelist(const config &data)
Process a full game list.
Definition: lobby_info.cpp:112
void apply_game_filter()
Generates a new list of games that match the current filter functions and inversion setting...
Definition: lobby_info.cpp:346
bool has_room(const std::string &name) const
Returns whether a room with the given name has been opened.
Definition: lobby_info.cpp:299
room_info * get_room(const std::string &name)
Returns info on room with the given name, or nullptr if it doesn't exist.
Definition: lobby_info.cpp:277
game_info * get_game_by_id(int id)
Returns info on a game with the given game ID.
Definition: lobby_info.cpp:265
void make_games_vector()
Generates a new vector of game pointers from the ID/game map.
Definition: lobby_info.cpp:331
Pubic entry points for the MP workflow.
Definition: lobby_data.cpp:48
void friend_message(bool is_lobby, const std::string &sender, const std::string &message)
void do_notify(notify_mode mode, const std::string &sender, const std::string &message)
Definition: lobby_info.cpp:57
const std::vector< std::string > & installed_addons_
Definition: lobby_info.hpp:157
#define WRN_LB
Definition: lobby_info.cpp:34
void private_message(bool is_lobby, const std::string &sender, const std::string &message)
boost::dynamic_bitset games_visibility_
Definition: lobby_info.hpp:178
void sync_games_display_status()
Definition: lobby_info.cpp:244
static lg::log_domain log_lobby("lobby")
std::vector< std::string > installed_addons()
Retrieves the names of all installed add-ons.
Definition: manager.cpp:148
game_info_map games_by_id_
Definition: lobby_info.hpp:165
void apply_diff(const config &diff, bool track=false)
A function to apply a diff config onto this config object.
Definition: config.cpp:995
bool gamelist_initialized_
Definition: lobby_info.hpp:161
std::string name
Definition: lobby_data.hpp:126
#define WRN_NG
Definition: lobby_info.cpp:30
Game configuration data as global variables.
Definition: build_info.cpp:53
void public_message(bool is_lobby, const std::string &sender, const std::string &message)
double g
Definition: astarsearch.cpp:64
std::vector< user_info * > users_sorted_
Definition: lobby_info.hpp:170
size_t i
Definition: function.cpp:933
This class represents the information a client has about a room.
Definition: lobby_data.hpp:66
void server_message(bool is_lobby, const std::string &sender, const std::string &message)
bool game_filter_invert_
Definition: lobby_info.hpp:176
static int sort(lua_State *L)
Definition: ltablib.cpp:411
bool process_gamelist_diff(const config &data)
Process a gamelist diff.
Definition: lobby_info.cpp:132
void process_userlist()
Definition: lobby_info.cpp:204
void player_leaves(bool is_lobby)
This class represents the information a client has about another player.
Definition: lobby_data.hpp:103
static const char * diff_track_attribute
The name of the attribute used for tracking diff changes.
Definition: config.hpp:687
lobby_info(const config &game_config, const std::vector< std::string > &installed_addons)
Definition: lobby_info.cpp:40
void close_room(const std::string &name)
Close the chat room with the given name.
Definition: lobby_info.cpp:322
int icompare(const std::string &s1, const std::string &s2)
Case-insensitive lexicographical comparison.
void player_joins(bool is_lobby)
Standard logging facilities (interface).
std::string message
Definition: exceptions.hpp:31
static const char * name(const std::vector< SDL_Joystick * > &joysticks, const size_t index)
Definition: joystick.cpp:48
notify_mode
Definition: lobby_info.hpp:181
#define e
const config & game_config_
Definition: lobby_info.hpp:155
void sort_users(bool by_name, bool by_relation)
Sorts the user list by the given parameters.
Definition: lobby_info.cpp:378
#define ERR_LB
Definition: lobby_info.cpp:35
user_relation relation
Definition: lobby_data.hpp:128
void open_room(const std::string &name)
Open a new chat room with the given name.
Definition: lobby_info.cpp:315
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
std::vector< user_info > users_
Definition: lobby_info.hpp:169
std::vector< game_info * > games_
Definition: lobby_info.hpp:167
mock_char c
void show(const std::string &window_id, const t_string &message, const point &mouse, const SDL_Rect &source_rect)
Shows a tip.
Definition: tooltip.cpp:154