16 #define GETTEXT_DOMAIN "wesnoth-lib"
55 #define DBG_LB LOG_STREAM(debug, log_lobby)
56 #define LOG_LB LOG_STREAM(info, log_lobby)
57 #define ERR_LB LOG_STREAM(err, log_lobby)
58 #define SCOPE_LB log_scope2(log_lobby, __func__)
66 return show_prompt(
_(
"Do you really want to log out?"));
72 , gamelistbox_(nullptr)
75 , filter_friends_(register_bool(
"filter_with_friends",
77 []() {
return prefs::get().fi_friends_in_game();},
78 [](
bool v) {
prefs::get().set_fi_friends_in_game(v);},
80 , filter_ignored_(register_bool(
"filter_with_ignored",
82 []() {
return prefs::get().fi_blocked_in_game();},
83 [](
bool v) {
prefs::get().set_fi_blocked_in_game(v);},
85 , filter_slots_(register_bool(
"filter_vacant_slots",
88 [](
bool v) {
prefs::get().set_fi_vacant_slots(v);},
90 , filter_invert_(register_bool(
"filter_invert",
95 , filter_auto_hosted_(
false)
96 , filter_text_(
nullptr)
99 , player_list_dirty_(
true)
100 , gamelist_dirty_(
true)
101 , last_lobby_update_(0)
102 , gamelist_diff_update_(
true)
103 , network_connection_(connection)
104 , lobby_update_timer_(0)
105 , gamelist_id_at_row_()
106 , delay_playerlist_update_(
false)
107 , delay_gamelist_update_(
false)
108 , joined_game_id_(joined_game)
110 set_show_even_without_video(
true);
111 set_allow_plugin_skip(
false);
112 set_always_save_fields(
true);
146 for(
const auto& v : map) {
147 const std::string& key = v.first;
160 for(
const auto & vv : strmap) {
161 if(vv.first ==
"label") {
162 c->set_label(vv.second);
163 }
else if(vv.first ==
"tooltip") {
164 c->set_tooltip(vv.second);
170 bool handle_addon_requirements_gui(
const std::vector<mp::game_info::required_addon>& reqs,
mp::game_info::addon_req addon_outcome)
173 std::string e_title =
_(
"Incompatible User-made Content");
174 std::string err_msg =
_(
"This game cannot be joined because the host has out-of-date add-ons that are incompatible with your version. You might wish to suggest that the host's add-ons be updated.");
177 err_msg +=
_(
"Details:");
189 std::string e_title =
_(
"Missing User-made Content");
190 std::string err_msg =
_(
"This game requires one or more user-made addons to be installed or updated in order to join.\nDo you want to try to install them?");
193 err_msg +=
_(
"Details:");
196 std::vector<std::string> needs_download;
201 needs_download.push_back(a.addon_id);
205 assert(needs_download.size() > 0);
241 LOG_LB <<
"Adding game to listbox (1)" <<
game.id;
265 int list_rows_deleted = 0;
269 std::vector<int> next_gamelist_id_at_row;
280 LOG_LB <<
"Adding game to listbox " <<
game.id;
284 DBG_LB <<
"Added a game listbox row not at the end" << list_i
295 next_gamelist_id_at_row.push_back(
game.id);
298 ERR_LB <<
"Ran out of listbox items -- triggering a full refresh";
304 ERR_LB <<
"gamelist_id_at_row_ overflow! " << list_i <<
" + "
307 <<
" -- triggering a full refresh";
313 if(
game.id != listbox_game_id) {
314 ERR_LB <<
"Listbox game id does not match expected id "
315 << listbox_game_id <<
" " <<
game.id <<
" (row " << list_i <<
")";
321 LOG_LB <<
"Modifying game in listbox " <<
game.id <<
" (row " << list_i <<
")";
326 next_gamelist_id_at_row.push_back(
game.id);
328 LOG_LB <<
"Deleting game from listbox " <<
game.id <<
" (row "
334 LOG_LB <<
"Clean game in listbox " <<
game.id <<
" (row " << list_i <<
")";
335 next_gamelist_id_at_row.push_back(
game.id);
341 for(
unsigned i = 0;
i < next_gamelist_id_at_row.size(); ++
i) {
349 ERR_LB <<
"Would select a row beyond the listbox" << select_row <<
" "
367 const std::string games_string =
VGETTEXT(
"Games: showing $num_shown out of $num_total", {
372 find_widget<label>(
gamelistbox_,
"map",
false).set_label(games_string);
382 item[
"use_markup"] =
"true";
385 if(
game.vacant_slots > 0) {
389 const std::string scenario_text =
VGETTEXT(
"$game_name (Era: $era_name)", {
390 {
"game_name",
game.scenario},
391 {
"era_name",
game.era}
408 find_widget<styled_widget>(
grid,
"name",
false).set_use_markup(
true);
409 find_widget<styled_widget>(
grid,
"status",
false).set_use_markup(
true);
416 std::ostringstream ss;
418 const auto mark_missing = [&ss]() {
431 auto mods =
game.mod_info;
434 ss <<
_(
"active_modifications^None") <<
"\n";
436 for(
const auto& mod : mods) {
448 const auto yes_or_no = [](
bool val) {
return val ?
_(
"yes") :
_(
"no"); };
451 ss <<
_(
"Experience modifier:") <<
" " <<
game.xp <<
"\n";
452 ss <<
_(
"Gold per village:") <<
" " <<
game.gold <<
"\n";
453 ss <<
_(
"Map size:") <<
" " <<
game.map_size_info <<
"\n";
454 ss <<
_(
"Reloaded:") <<
" " << yes_or_no(
game.reloaded) <<
"\n";
455 ss <<
_(
"Shared vision:") <<
" " <<
game.vision <<
"\n";
456 ss <<
_(
"Shuffle sides:") <<
" " << yes_or_no(
game.shuffle_sides) <<
"\n";
457 ss <<
_(
"Time limit:") <<
" " <<
game.time_limit <<
"\n";
458 ss <<
_(
"Use map settings:") <<
" " << yes_or_no(
game.use_map_settings);
460 image& info_icon = find_widget<image>(
grid,
"game_info",
false);
462 if(!
game.have_era || !
game.have_all_mods || !
game.required_addons.empty()) {
463 info_icon.
set_label(
"icons/icon-info-error.png");
465 ss <<
"\n\n<span color='#f00' size='x-large'>! </span>";
466 ss <<
_(
"One or more add-ons need to be installed\nin order to join this game.");
468 info_icon.
set_label(
"icons/icon-info.png");
476 image& password_icon = find_widget<image>(
grid,
"needs_password",
false);
478 if(
game.password_required) {
487 image& observer_icon = find_widget<image>(
grid,
"observer_icon",
false);
493 observer_icon.
set_label(
"misc/no_observer.png");
500 minimap& map = find_widget<minimap>(
grid,
"minimap",
false);
514 DBG_LB <<
"mp_lobby::update_gamelist_filter";
539 bool can_join =
false, can_observe =
false;
543 can_observe =
game.can_observe();
544 can_join =
game.can_join();
550 find_widget<button>(
get_window(),
"observe_global",
false).set_active(can_observe);
551 find_widget<button>(
get_window(),
"join_global",
false).set_active(can_join);
584 find_widget<button>(&
window,
"create",
false).set_retval(
CREATE);
587 find_widget<button>(&
window,
"show_preferences",
false),
591 find_widget<button>(&
window,
"join_global",
false),
594 find_widget<button>(&
window,
"join_global",
false).set_active(
false);
597 find_widget<button>(&
window,
"observe_global",
false),
601 find_widget<button>(&
window,
"server_info",
false),
604 find_widget<button>(&
window,
"observe_global",
false).set_active(
false);
606 menu_button& replay_options = find_widget<menu_button>(&
window,
"replay_options",
false);
644 if(
auto* profile_panel = find_widget<panel>(&
window,
"profile",
false,
false)) {
646 [](
const auto& u) { return u.get_relation() == mp::user_info::user_relation::ME; });
649 find_widget<label>(profile_panel,
"username",
false).set_label(your_info->name);
651 auto& profile_button = find_widget<button>(profile_panel,
"view_profile",
false);
654 auto& history_button = find_widget<button>(profile_panel,
"view_match_history",
false);
659 listbox& tab_bar = find_widget<listbox>(&
window,
"games_list_tab_bar",
false);
721 LOG_LB <<
"caught wesnothd_error in network_handler: " <<
e.message;
751 if(
auto error =
data.optional_child(
"error")) {
753 }
else if(
data.has_child(
"gamelist")) {
755 }
else if(
auto gamelist_diff =
data.optional_child(
"gamelist_diff")) {
757 }
else if(
auto info =
data.optional_child(
"message")) {
758 if(
info[
"type"] ==
"server_info") {
761 }
else if(
info[
"type"] ==
"announcements") {
775 DBG_LB <<
"Received gamelist";
785 DBG_LB <<
"Received gamelist diff";
788 ERR_LB <<
"process_gamelist_diff failed!";
791 const int joined =
data.child_count(
"insert_child");
792 const int left =
data.child_count(
"remove_child");
793 if(joined > 0 || left > 0) {
806 if(!
game.can_join()) {
807 ERR_LB <<
"Attempted to join a game with no vacant slots";
813 if(!
game.can_observe()) {
814 ERR_LB <<
"Attempted to observe a game with observers disabled";
820 if(
game.can_join()) {
822 }
else if(
game.can_observe()) {
825 DBG_LB <<
"Cannot join or observe a game.";
846 if(
game.required_addons.empty()) {
847 gui2::show_error_message(
_(
"Something is wrong with the addon version check database supporting the multiplayer lobby. Please report this at https://bugs.wesnoth.org."));
851 if(!handle_addon_requirements_gui(
game.required_addons,
game.addons_outcome)) {
864 join_data[
"id"] = std::to_string(
game.id);
865 join_data[
"observe"] = try_obsv;
871 }
else if(!join_data.
empty() &&
game.password_required) {
872 std::string password;
874 if(!gui2::dialogs::mp_join_game_password_prompt::execute(password)) {
878 join_data[
"password"] = password;
892 }
catch(
const std::out_of_range&) {
894 ERR_LB <<
"Attempted to join/observe a game with index out of range: " <<
index <<
". "
904 ERR_LB <<
"Attempted to join/observe a game with an invalid id: " << game_id;
928 gui2::dialogs::preferences_dialog::display();
944 if(!info.match_string_filter(s)) {
953 return filter_friends_->get_widget_value() ?
info.has_friends ==
true :
true;
960 return filter_ignored_->get_widget_value() ==
false ?
info.has_ignored ==
false :
true;
964 return filter_slots_->get_widget_value() ?
info.vacant_slots > 0 :
true;
968 return info.auto_hosted == filter_auto_hosted_;
971 lobby_info_.set_game_filter_invert(
972 [
this](
bool val) {
return filter_invert_->get_widget_value() ? !val : val; });
977 if(key == SDLK_RETURN || key == SDLK_KP_ENTER) {
1008 const int value = find_widget<menu_button>(
get_window(),
"replay_options",
false).get_value();
1010 prefs::get().set_blindfold_replay(value == 2);
std::map< std::string, chatroom_log > default_chat_log
A config object defines a single node in a WML file, with access to child nodes.
bool has_attribute(config_key_type key) const
config & add_child(config_key_type key)
lobby_chat_window * room_window_open(const std::string &room, const bool open_new, const bool allow_close=true)
Check if a room window for "room" is open, if open_new is true then it will be created if not found.
virtual void send_chat_message(const std::string &message, bool allies_only) override
Inherited form chat_handler.
lobby_chat_window * whisper_window_open(const std::string &name, bool open_new)
Check if a whisper window for user "name" is open, if open_new is true then it will be created if not...
void switch_to_window(lobby_chat_window *t)
Switch to the window given by a valid pointer (e.g.
void process_network_data(const ::config &data)
void set_active_window_changed_callback(const std::function< void(void)> &f)
void load_log(std::map< std::string, chatroom_log > &log, bool show_lobby)
void active_window_changed()
bool result_open_whisper() const
@ yes_no_buttons
Shows a yes and no button.
@ auto_close
Enables auto close.
Abstract base class for all modal dialogs.
bool show(const unsigned auto_close_time=0)
Shows the window.
window * get_window()
Returns a pointer to the dialog's window.
void enter_selected_game(JOIN_MODE mode)
Enter game by index, where index is the selected game listbox row.
void show_help_callback()
void process_gamelist(const config &data)
void update_visible_games()
void update_selected_game()
mp::lobby_info & lobby_info_
lobby_player_list_helper player_list_
void skip_replay_changed_callback()
static std::string announcements_
virtual void pre_show(window &window) override
Actions to be taken before showing the window.
bool delay_gamelist_update_
wesnothd_connection & network_connection_
void open_match_history()
void update_gamelist_filter()
bool gamelist_diff_update_
virtual void post_show(window &window) override
Actions to be taken after the window has been shown.
bool delay_playerlist_update_
void process_network_data(const config &data)
widget_data make_game_row_data(const mp::game_info &game)
void game_filter_keypress_callback(const SDL_Keycode key)
void enter_game_by_id(const int game_id, JOIN_MODE mode)
Entry wrapper for enter_game, where game is located by game id.
void update_gamelist_diff()
void show_preferences_button_callback()
unsigned last_lobby_update_
static std::string server_information_
void enter_game(const mp::game_info &game, JOIN_MODE mode)
Exits the lobby and enters the given game.
void user_dialog_callback(const mp::user_info *info)
void tab_switch_callback()
mp_lobby(mp::lobby_info &info, wesnothd_connection &connection, int &joined_game)
void process_gamelist_diff(const config &data)
std::size_t lobby_update_timer_
Timer for updating the lobby.
void adjust_game_row_contents(const mp::game_info &game, grid *grid, bool add_callbacks=true)
std::vector< int > gamelist_id_at_row_
void network_handler()
Network polling callback.
void enter_game_by_index(const int index, JOIN_MODE mode)
Entry wrapper for enter_game, where game is located by index.
static void display(const std::string &player_name, wesnothd_connection &connection, bool wait_for_response=true)
The display function.
std::unique_ptr< plugins_context > plugins_context_
static void display(const std::string &info, const std::string &announcements)
The display function.
void register_hotkey(const hotkey::HOTKEY_COMMAND id, const hotkey_function &function)
Registers a hotkey.
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
void set_row_shown(const unsigned row, const bool shown)
Makes a row visible or invisible.
grid & add_row(const widget_item &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
bool select_row(const unsigned row, const bool select=true)
Selects a row.
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
void clear()
Removes all the rows in the listbox, clearing it.
int get_selected_row() const
Returns the first selected row.
unsigned get_item_count() const
Returns the number of items in the listbox.
const mp::user_info * get_selected_info() const
void update(const std::vector< mp::user_info > &user_info, int focused_game)
Updates the tree contents based on the given user data.
void set_map_data(const std::string &map_data)
std::string get_value() const
base class of top level items, the only item which needs to store the final canvases to draw on.
void set_enter_disabled(const bool enter_disabled)
Disable the enter key.
void set_retval(const int retval, const bool close_window=true)
Sets there return value of the window.
show_mode mode() const
Returns the dialog mode for this window.
void keyboard_capture(widget *widget)
void set_exit_hook(exit_hook mode, std::function< bool(window &)> func)
Sets the window's exit hook.
This class represents the collective information the client has about the players and games on the se...
void add_game_filter(game_filter_func func)
Adds a new filter function to be considered when apply_game_filter is called.
bool is_game_visible(const game_info &)
Returns whether the game would be visible after the game filters are applied.
void clear_game_filters()
Clears all game filter functions.
const config & gamelist() const
Returns the raw game list config data.
void process_gamelist(const config &data)
Process a full game list.
bool process_gamelist_diff(const config &data)
Process a gamelist diff.
std::function< void()> begin_state_sync()
Updates the game pointer list and returns a second stage cleanup function to be called after any acti...
game_info * get_game_by_id(int id)
Returns info on a game with the given game ID.
bool gamelist_initialized() const
const std::vector< game_info * > & games() const
void apply_game_filter()
Generates a new list of games that match the current filter functions and inversion setting.
const boost::dynamic_bitset & games_visibility() const
const std::vector< user_info > & users() const
Implements a quit confirmation dialog.
static bool quit()
Shows the quit confirmation if needed.
A class that represents a TCP/IP connection to the wesnothd server.
bool receive_data(config &result)
Receives the next pending data pack from the server, if available.
Networked add-ons (campaignd) client interface.
Implements some helper classes to ease adding fields to a dialog and hide the synchronization needed.
static std::string _(const char *str)
static lg::log_domain log_lobby("lobby")
bool ad_hoc_addon_fetch_session(const std::vector< std::string > &addon_ids)
Conducts an ad-hoc add-ons server connection to download an add-on with a particular id and all it's ...
bool open_object([[maybe_unused]] const std::string &path_or_url)
const color_t YELLOW_COLOR
const color_t TITLE_COLOR
const std::string unicode_bullet
std::string span_color(const color_t &color)
Returns a Pango formatting string using the provided color_t object.
unsigned lobby_network_timer
REGISTER_DIALOG(editor_edit_unit)
void connect_signal_pre_key_press(dispatcher &dispatcher, const signal_keyboard &signal)
Connects the signal for 'snooping' on the keypress.
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification &signal)
Connects a signal handler for getting a notification upon modification.
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal &signal)
Connects a signal handler for a left mouse button click.
void connect_signal_mouse_left_double_click(dispatcher &dispatcher, const signal &signal)
Connects a signal handler for a left mouse button double click.
std::size_t add_timer(const uint32_t interval, const std::function< void(std::size_t id)> &callback, const bool repeat)
Adds a new timer.
std::map< std::string, widget_item > widget_data
std::map< std::string, t_string > widget_item
void show_error_message(const std::string &msg, bool message_use_markup)
Shows an error message to the user.
bool remove_timer(const std::size_t id)
Removes a timer.
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
@ OK
Dialog was closed with the OK button.
@ CANCEL
Dialog was closed with the CANCEL button.
void show_help(const std::string &show_topic, int xloc, int yloc)
Open the help browser, show topic with id show_topic.
std::pair< std::string, unsigned > item
Functions to load and save images from/to disk.
void do_notify(notify_mode mode, const std::string &sender, const std::string &message)
void send_to_server(const config &data)
Attempts to send given data to server if a connection is open.
std::string get_profile_link(int user_id)
Gets the forum profile link for the given user.
bool logged_in_as_moderator()
Gets whether the currently logged-in user is a moderator.
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
std::vector< std::string > split(const config_attribute_value &val)
Desktop environment interaction functions.
The basic class for representing 8-bit RGB or RGBA colour values.
lobby_delay_gamelist_update_guard(mp_lobby &l)
~lobby_delay_gamelist_update_guard()
This class represents the info a client has about a game on the server.
This class represents the information a client has about another player.
An error occurred during when trying to communicate with the wesnothd server.
static map_location::DIRECTION s
Contains the gui2 timer routines.