00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "gui/dialogs/lobby/lobby_info.hpp"
00017
00018 #include "config.hpp"
00019 #include "game_preferences.hpp"
00020 #include "filesystem.hpp"
00021 #include "foreach.hpp"
00022 #include "formula_string_utils.hpp"
00023 #include "gettext.hpp"
00024 #include "network.hpp"
00025 #include "log.hpp"
00026 #include "map.hpp"
00027 #include "map_exception.hpp"
00028 #include "wml_exception.hpp"
00029
00030 #include <iterator>
00031
00032 static lg::log_domain log_config("config");
00033 #define ERR_CF LOG_STREAM(err, log_config)
00034 static lg::log_domain log_engine("engine");
00035 #define WRN_NG LOG_STREAM(warn, log_engine)
00036
00037 static lg::log_domain log_lobby("lobby");
00038 #define DBG_LB LOG_STREAM(debug, log_lobby)
00039 #define LOG_LB LOG_STREAM(info, log_lobby)
00040 #define WRN_LB LOG_STREAM(warn, log_lobby)
00041 #define ERR_LB LOG_STREAM(err, log_lobby)
00042 #define SCOPE_LB log_scope2(log_lobby, __func__)
00043
00044
00045 lobby_info::lobby_info(const config& game_config)
00046 : game_config_(game_config)
00047 , gamelist_()
00048 , gamelist_initialized_(false)
00049 , rooms_()
00050 , games_by_id_()
00051 , games_()
00052 , games_filtered_()
00053 , users_()
00054 , users_sorted_()
00055 , whispers_()
00056 , game_filter_()
00057 , game_filter_invert_(false)
00058 , games_visibility_()
00059 {
00060 }
00061
00062 lobby_info::~lobby_info()
00063 {
00064 delete_games();
00065 }
00066
00067 void lobby_info::delete_games()
00068 {
00069 foreach (const game_info_map::value_type& v, games_by_id_) {
00070 delete v.second;
00071 }
00072 }
00073
00074 namespace {
00075
00076 std::string dump_games_map(const lobby_info::game_info_map& games)
00077 {
00078 std::stringstream ss;
00079 foreach (const lobby_info::game_info_map::value_type& v, games) {
00080 const game_info& game = *v.second;
00081 ss << "G" << game.id << "(" << game.name << ") " << game.display_status_string() << " ";
00082 }
00083 ss << "\n";
00084 return ss.str();
00085 }
00086
00087 std::string dump_games_config(const config& gamelist)
00088 {
00089 std::stringstream ss;
00090 foreach (const config& c, gamelist.child_range("game")) {
00091 ss << "g" << c["id"] << "(" << c["name"] << ") " << c[config::diff_track_attribute] << " ";
00092 }
00093 ss << "\n";
00094 return ss.str();
00095 }
00096
00097 }
00098
00099 void lobby_info::process_gamelist(const config &data)
00100 {
00101 SCOPE_LB;
00102 gamelist_ = data;
00103 gamelist_initialized_ = true;
00104 delete_games();
00105 games_by_id_.clear();
00106 foreach (const config& c, gamelist_.child("gamelist").child_range("game")) {
00107 game_info* game = new game_info(c, game_config_);
00108 games_by_id_[game->id] = game;
00109 }
00110 DBG_LB << dump_games_map(games_by_id_);
00111 DBG_LB << dump_games_config(gamelist_.child("gamelist"));
00112 process_userlist();
00113 }
00114
00115
00116 bool lobby_info::process_gamelist_diff(const config &data)
00117 {
00118 SCOPE_LB;
00119 if (!gamelist_initialized_) return false;
00120 DBG_LB << "prediff " << dump_games_config(gamelist_.child("gamelist"));
00121 try {
00122 gamelist_.apply_diff(data, true);
00123 } catch(config::error& e) {
00124 ERR_LB << "Error while applying the gamelist diff: '"
00125 << e.message << "' Getting a new gamelist.\n";
00126 network::send_data(config("refresh_lobby"), 0);
00127 return false;
00128 }
00129 DBG_LB << "postdiff " << dump_games_config(gamelist_.child("gamelist"));
00130 DBG_LB << dump_games_map(games_by_id_);
00131 config::child_itors range = gamelist_.child("gamelist").child_range("game");
00132 for (config::child_iterator i = range.first; i != range.second; ++i) {
00133 config& c = *i;
00134 DBG_LB << "data process: " << c["id"] << " (" << c[config::diff_track_attribute] << ")\n";
00135 int game_id = c["id"];
00136 if (game_id == 0) {
00137 ERR_LB << "game with id 0 in gamelist config\n";
00138 network::send_data(config("refresh_lobby"), 0);
00139 return false;
00140 }
00141 game_info_map::iterator current_i = games_by_id_.find(game_id);
00142 const std::string& diff_result = c[config::diff_track_attribute];
00143 if (diff_result == "new" || diff_result == "modified") {
00144 if (current_i == games_by_id_.end()) {
00145 games_by_id_.insert(std::make_pair(game_id, new game_info(c, game_config_)));
00146 } else {
00147
00148 *(current_i->second) = game_info(c, game_config_);
00149 current_i->second->display_status = game_info::UPDATED;
00150 }
00151 } else if (diff_result == "deleted") {
00152 if (current_i == games_by_id_.end()) {
00153 WRN_LB << "Would have to delete a game that I don't have: " << game_id << "\n";
00154 } else {
00155 if (current_i->second->display_status == game_info::NEW) {
00156
00157
00158 games_by_id_.erase(current_i);
00159 } else {
00160 current_i->second->display_status = game_info::DELETED;
00161 }
00162 }
00163 }
00164 }
00165 DBG_LB << dump_games_map(games_by_id_);
00166 try {
00167 gamelist_.clear_diff_track(data);
00168 } catch(config::error& e) {
00169 ERR_LB << "Error while applying the gamelist diff (2): '"
00170 << e.message << "' Getting a new gamelist.\n";
00171 network::send_data(config("refresh_lobby"), 0);
00172 return false;
00173 }
00174 DBG_LB << "postclean " << dump_games_config(gamelist_.child("gamelist"));
00175 process_userlist();
00176 return true;
00177 }
00178
00179 void lobby_info::process_userlist()
00180 {
00181 SCOPE_LB;
00182 users_.clear();
00183 foreach (const config& c, gamelist_.child_range("user")) {
00184 users_.push_back(user_info(c));
00185 }
00186 foreach (user_info& ui, users_) {
00187 if (ui.game_id != 0) {
00188 game_info* g = get_game_by_id(ui.game_id);
00189 if (g == NULL) {
00190 WRN_NG << "User " << ui.name << " has unknown game_id: " << ui.game_id << "\n";
00191 } else {
00192 switch (ui.relation) {
00193 case user_info::FRIEND:
00194 g->has_friends = true;
00195 break;
00196 case user_info::IGNORED:
00197 g->has_ignored = true;
00198 break;
00199 default:
00200 break;
00201 }
00202 }
00203 }
00204 }
00205 }
00206
00207 void lobby_info::sync_games_display_status()
00208 {
00209 DBG_LB << "lobby_info::sync_games_display_status";
00210 DBG_LB << "games_by_id_ size: " << games_by_id_.size();
00211 game_info_map::iterator i = games_by_id_.begin();
00212 while (i != games_by_id_.end()) {
00213 if (i->second->display_status == game_info::DELETED) {
00214 games_by_id_.erase(i++);
00215 } else {
00216 i->second->display_status = game_info::CLEAN;
00217 ++i;
00218 }
00219 }
00220 DBG_LB << " -> " << games_by_id_.size() << "\n";
00221 make_games_vector();
00222 }
00223
00224 game_info* lobby_info::get_game_by_id(int id)
00225 {
00226 std::map<int, game_info*>::iterator i = games_by_id_.find(id);
00227 return i == games_by_id_.end() ? NULL : i->second;
00228 }
00229
00230 const game_info* lobby_info::get_game_by_id(int id) const
00231 {
00232 std::map<int, game_info*>::const_iterator i = games_by_id_.find(id);
00233 return i == games_by_id_.end() ? NULL : i->second;
00234 }
00235
00236 room_info* lobby_info::get_room(const std::string &name)
00237 {
00238 foreach (room_info& r, rooms_) {
00239 if (r.name() == name) return &r;
00240 }
00241 return NULL;
00242 }
00243
00244 const room_info* lobby_info::get_room(const std::string &name) const
00245 {
00246 foreach (const room_info& r, rooms_) {
00247 if (r.name() == name) return &r;
00248 }
00249 return NULL;
00250 }
00251
00252 bool lobby_info::has_room(const std::string &name) const
00253 {
00254 return get_room(name) != NULL;
00255 }
00256
00257 chat_log& lobby_info::get_whisper_log(const std::string &name)
00258 {
00259 return whispers_[name];
00260 }
00261
00262 void lobby_info::open_room(const std::string &name)
00263 {
00264 if (!has_room(name)) {
00265 rooms_.push_back(room_info(name));
00266 }
00267 }
00268
00269 void lobby_info::close_room(const std::string &name)
00270 {
00271 room_info* r = get_room(name);
00272 DBG_LB << "lobby info: closing room " << name
00273 << " " << static_cast<void*>(r) << "\n";
00274 if (r) {
00275 rooms_.erase(rooms_.begin() + (r - &rooms_[0]));
00276 }
00277 }
00278
00279 const std::vector<game_info*>& lobby_info::games_filtered() const
00280 {
00281 return games_filtered_;
00282 }
00283
00284 void lobby_info::add_game_filter(game_filter_base *f)
00285 {
00286 game_filter_.append(f);
00287 }
00288
00289 void lobby_info::clear_game_filter()
00290 {
00291 game_filter_.clear();
00292 }
00293
00294 void lobby_info::set_game_filter_invert(bool value)
00295 {
00296 game_filter_invert_ = value;
00297 }
00298
00299 void lobby_info::make_games_vector()
00300 {
00301 games_filtered_.clear();
00302 games_visibility_.clear();
00303 games_.clear();
00304 foreach (const game_info_map::value_type& v, games_by_id_) {
00305 games_.push_back(v.second);
00306 }
00307 }
00308
00309 void lobby_info::apply_game_filter()
00310 {
00311 games_filtered_.clear();
00312 games_visibility_.clear();
00313 foreach (game_info* g, games_) {
00314 game_info& gi = *g;
00315 bool show = game_filter_.match(gi);
00316 if (game_filter_invert_) {
00317 show = !show;
00318 }
00319 games_visibility_.push_back(show);
00320 if (show) {
00321 games_filtered_.push_back(&gi);
00322 }
00323 }
00324 }
00325
00326 void lobby_info::update_user_statuses(int game_id, const room_info *room)
00327 {
00328 foreach (user_info& user, users_) {
00329 user.update_state(game_id, room);
00330 }
00331 }
00332
00333
00334 struct user_sorter_name
00335 {
00336 bool operator()(const user_info& u1, const user_info& u2) {
00337 return u1.name < u2.name;
00338 }
00339 bool operator()(const user_info* u1, const user_info* u2) {
00340 return operator()(*u1, *u2);
00341 }
00342 };
00343
00344 struct user_sorter_relation
00345 {
00346 bool operator()(const user_info& u1, const user_info& u2) {
00347 return static_cast<int>(u1.relation) < static_cast<int>(u2.relation);
00348 }
00349 bool operator()(const user_info* u1, const user_info* u2) {
00350 return operator()(*u1, *u2);
00351 }
00352 };
00353
00354 struct user_sorter_relation_name
00355 {
00356 bool operator()(const user_info& u1, const user_info& u2) {
00357 return static_cast<int>(u1.relation) < static_cast<int>(u2.relation)
00358 || (u1.relation == u2.relation && u1.name < u2.name);
00359 }
00360 bool operator()(const user_info* u1, const user_info* u2) {
00361 return operator()(*u1, *u2);
00362 }
00363 };
00364
00365 void lobby_info::sort_users(bool by_name, bool by_relation)
00366 {
00367 users_sorted_.clear();
00368 foreach (user_info& u, users_) {
00369 users_sorted_.push_back(&u);
00370 }
00371 if (by_name) {
00372 if (by_relation) {
00373 std::sort(users_sorted_.begin(), users_sorted_.end(), user_sorter_relation_name());
00374 } else {
00375 std::sort(users_sorted_.begin(), users_sorted_.end(), user_sorter_name());
00376 }
00377 } else if (by_relation) {
00378 std::sort(users_sorted_.begin(), users_sorted_.end(), user_sorter_relation());
00379 }
00380 }
00381
00382 const std::vector<user_info*>& lobby_info::users_sorted() const
00383 {
00384 return users_sorted_;
00385 }