Fixup, complete, and enable the lobby's game history viewer.
At some point in the future I'd like to come back and add some search parameters - right now it shows the game history of the currently selected player in the lobby, but ideally it would instead have options for player name, era, scenario, etc.
This commit is contained in:
parent
c6b9ceb61e
commit
6fe2627048
12 changed files with 710 additions and 73 deletions
|
@ -33,6 +33,7 @@ test_gui2/modal_dialog_test_hotkey_bind
|
|||
test_gui2/modal_dialog_test_install_dependencies
|
||||
test_gui2/modal_dialog_test_language_selection
|
||||
test_gui2/modal_dialog_test_mp_lobby
|
||||
test_gui2/modal_dialog_test_mp_match_history_dialog
|
||||
test_gui2/modal_dialog_test_mp_report
|
||||
test_gui2/modal_dialog_test_lobby_player_info
|
||||
test_gui2/modal_dialog_test_log_settings
|
||||
|
|
|
@ -1,11 +1,42 @@
|
|||
#textdomain wesnoth-lib
|
||||
|
||||
#define _GUI_HORIZONTAL_TAB ID
|
||||
[row]
|
||||
|
||||
[column]
|
||||
horizontal_grow = true
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[label]
|
||||
id = "{ID}_game_name"
|
||||
definition = "default"
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
#enddef
|
||||
|
||||
#define _GUI_MATCH_HISTORY_LIST
|
||||
{GUI_FORCE_WIDGET_MINIMUM_SIZE 600 400 (
|
||||
[listbox]
|
||||
id = "history"
|
||||
definition = "default"
|
||||
|
||||
vertical_scrollbar_mode = "auto"
|
||||
horizontal_scrollbar_mode = "never"
|
||||
|
||||
[list_definition]
|
||||
|
@ -17,14 +48,193 @@
|
|||
|
||||
[toggle_panel]
|
||||
definition = "default"
|
||||
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
horizontal_grow = true
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[label]
|
||||
id = "game_name"
|
||||
definition = "gold_large"
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
[spacer]
|
||||
[/spacer]
|
||||
grow_factor = 1
|
||||
horizontal_grow = true
|
||||
vertical_alignment = top
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
horizontal_grow = true
|
||||
vertical_alignment = top
|
||||
|
||||
[grid]
|
||||
linked_group = "data_columns"
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[label]
|
||||
id = "scenario_name"
|
||||
definition = "default_small"
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[label]
|
||||
id = "game_start"
|
||||
definition = "default_small"
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[button]
|
||||
id = "replay_download"
|
||||
definition = "default_small"
|
||||
label = _ "Download"
|
||||
[/button]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[label]
|
||||
id = "players"
|
||||
definition = "default"
|
||||
label = _ "None"
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[label]
|
||||
id = "modifications"
|
||||
definition = "default"
|
||||
label = _ "None"
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
horizontal_grow = true
|
||||
vertical_alignment = top
|
||||
|
||||
[grid]
|
||||
linked_group = "data_columns"
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[label]
|
||||
id = "era_name"
|
||||
definition = "default_small"
|
||||
use_markup = yes
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[label]
|
||||
id = "version"
|
||||
definition = "default_small"
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
@ -40,6 +250,7 @@
|
|||
[/list_definition]
|
||||
|
||||
[/listbox]
|
||||
)}
|
||||
#enddef
|
||||
|
||||
[window]
|
||||
|
@ -64,10 +275,20 @@
|
|||
id = "tooltip"
|
||||
[/helptip]
|
||||
|
||||
[linked_group]
|
||||
id = "tabs"
|
||||
fixed_width = true
|
||||
fixed_height = true
|
||||
[/linked_group]
|
||||
|
||||
[linked_group]
|
||||
id = "data_columns"
|
||||
fixed_width = true
|
||||
[/linked_group]
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
horizontal_grow = true
|
||||
|
@ -77,6 +298,7 @@
|
|||
[label]
|
||||
id = "title"
|
||||
definition = "title"
|
||||
label = _ "Match History"
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
@ -84,11 +306,120 @@
|
|||
[/row]
|
||||
|
||||
[row]
|
||||
grow_factor = 1
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
border = all
|
||||
border_size = 5
|
||||
|
||||
[horizontal_listbox]
|
||||
id = "tab_bar"
|
||||
horizontal_scrollbar_mode = "never"
|
||||
vertical_scrollbar_mode = "never"
|
||||
|
||||
[list_definition]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
|
||||
[toggle_panel]
|
||||
linked_group = "tabs"
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
border = all
|
||||
border_size = 5
|
||||
|
||||
[spacer][/spacer]
|
||||
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
border = all
|
||||
border_size = 5
|
||||
|
||||
[label]
|
||||
id = "tab_label"
|
||||
wrap = true
|
||||
[/label]
|
||||
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
border = all
|
||||
border_size = 5
|
||||
|
||||
[spacer][/spacer]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/toggle_panel]
|
||||
[/column]
|
||||
[/row]
|
||||
[/list_definition]
|
||||
|
||||
[list_data]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
|
||||
[widget]
|
||||
id = "tab_label"
|
||||
label = _ "Info"
|
||||
[/widget]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
|
||||
[widget]
|
||||
id = "tab_label"
|
||||
label = _ "Players"
|
||||
[/widget]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
|
||||
[widget]
|
||||
id = "tab_label"
|
||||
label = _ "Modifications"
|
||||
[/widget]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/list_data]
|
||||
[/horizontal_listbox]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
horizontal_grow = true
|
||||
border = "all"
|
||||
border_size = 5
|
||||
|
||||
{_GUI_MATCH_HISTORY_LIST}
|
||||
|
||||
|
@ -97,10 +428,48 @@
|
|||
[/row]
|
||||
|
||||
[row]
|
||||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
grow_factor = 1
|
||||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
horizontal_alignment = right
|
||||
border = "all"
|
||||
border_size = 5
|
||||
|
||||
[button]
|
||||
id = "newer_history"
|
||||
definition = "left_arrow_short_ornate"
|
||||
[/button]
|
||||
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
horizontal_alignment = right
|
||||
border = "all"
|
||||
border_size = 5
|
||||
|
||||
[button]
|
||||
id = "older_history"
|
||||
definition = "right_arrow_short_ornate"
|
||||
[/button]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
horizontal_alignment = right
|
||||
border = "all"
|
||||
border_size = 5
|
||||
|
@ -122,3 +491,4 @@
|
|||
[/window]
|
||||
|
||||
#undef _GUI_MATCH_HISTORY_LIST
|
||||
#undef _GUI_HORIZONTAL_TAB
|
||||
|
|
|
@ -149,6 +149,7 @@
|
|||
4685124C24AE1A0B005B6EB1 /* game_config_view.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4685124824AE1535005B6EB1 /* game_config_view.cpp */; };
|
||||
4685124D24AE1A15005B6EB1 /* game_config_view.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4685124824AE1535005B6EB1 /* game_config_view.cpp */; };
|
||||
4685A5FB25B4501E006FD3A1 /* match_history.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4685A5F925B4501E006FD3A1 /* match_history.cpp */; };
|
||||
900000000000000000000009 /* match_history.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4685A5F925B4501E006FD3A1 /* match_history.cpp */; };
|
||||
4685A60225B45064006FD3A1 /* game_history.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4685A60025B45064006FD3A1 /* game_history.cpp */; };
|
||||
4685A60325B45064006FD3A1 /* game_history.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4685A60025B45064006FD3A1 /* game_history.cpp */; };
|
||||
468A5B93258CD3B5004A80EF /* libboost_chrono-mt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 468A5B85258CD3B4004A80EF /* libboost_chrono-mt.dylib */; };
|
||||
|
@ -6153,6 +6154,7 @@
|
|||
1234567890ABCDEF12345679 /* file_progress.cpp in Sources */,
|
||||
000000000000000000000007 /* achievements.cpp in Sources */,
|
||||
000000000000000000000008 /* achievements_dialog.cpp in Sources */,
|
||||
900000000000000000000009 /* match_history.cpp in Sources */,
|
||||
91E3570B1CACC9B200774252 /* singleplayer.cpp in Sources */,
|
||||
4649B88B20288EEF00827CFB /* surface.cpp in Sources */,
|
||||
46F92DB02174F6A300602C1C /* campaign_selection.cpp in Sources */,
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "gui/widgets/toggle_panel.hpp"
|
||||
#include "gui/widgets/stacked_widget.hpp"
|
||||
#include "gui/dialogs/server_info_dialog.hpp"
|
||||
#include "gui/dialogs/multiplayer/match_history.hpp"
|
||||
|
||||
#include "addon/client.hpp"
|
||||
#include "addon/manager_ui.hpp"
|
||||
|
@ -654,8 +655,8 @@ void mp_lobby::pre_show(window& window)
|
|||
auto& profile_button = find_widget<button>(profile_panel, "view_profile", false);
|
||||
connect_signal_mouse_left_click(profile_button, std::bind(&mp_lobby::open_profile_url, this));
|
||||
|
||||
// TODO: implement
|
||||
find_widget<button>(profile_panel, "view_match_history", false).set_active(false);
|
||||
auto& history_button = find_widget<button>(profile_panel, "view_match_history", false);
|
||||
connect_signal_mouse_left_click(history_button, std::bind(&mp_lobby::open_match_history, this));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -705,6 +706,14 @@ void mp_lobby::post_show(window& /*window*/)
|
|||
plugins_context_.reset();
|
||||
}
|
||||
|
||||
void mp_lobby::open_match_history()
|
||||
{
|
||||
const mp::user_info* info = player_list_.get_selected_info();
|
||||
if(info) {
|
||||
mp_match_history::display(info->name, network_connection_);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_lobby::network_handler()
|
||||
{
|
||||
try {
|
||||
|
|
|
@ -115,6 +115,8 @@ private:
|
|||
|
||||
void open_profile_url();
|
||||
|
||||
void open_match_history();
|
||||
|
||||
void tab_switch_callback();
|
||||
|
||||
void refresh_lobby();
|
||||
|
|
|
@ -14,32 +14,231 @@
|
|||
|
||||
#include "gui/dialogs/multiplayer/match_history.hpp"
|
||||
|
||||
#include "desktop/open.hpp"
|
||||
#include "formula/string_utils.hpp"
|
||||
#include "game_initialization/lobby_data.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "gui/auxiliary/find_widget.hpp"
|
||||
#include "gui/widgets/button.hpp"
|
||||
#include "gui/widgets/label.hpp"
|
||||
#include "gui/widgets/listbox.hpp"
|
||||
#include "gui/widgets/window.hpp"
|
||||
#include "wesnothd_connection.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static lg::log_domain log_network("network");
|
||||
#define DBG_NW LOG_STREAM(debug, log_network)
|
||||
#define ERR_NW LOG_STREAM(err, log_network)
|
||||
|
||||
// TODO: put close button outside of scrollbar area
|
||||
|
||||
namespace gui2::dialogs
|
||||
{
|
||||
REGISTER_DIALOG(mp_match_history)
|
||||
|
||||
mp_match_history::mp_match_history(mp::user_info& info, wesnothd_connection& connection)
|
||||
mp_match_history::mp_match_history(const std::string& player_name, wesnothd_connection& connection, bool wait_for_response)
|
||||
: modal_dialog(window_id())
|
||||
, info_(info)
|
||||
, player_name_(player_name)
|
||||
, connection_(connection)
|
||||
, offset_(0)
|
||||
, wait_for_response_(wait_for_response)
|
||||
{
|
||||
register_label("title", true, VGETTEXT("Match History — $player", {{"player", info_.name}}));
|
||||
register_label("title", true, VGETTEXT("Match History — $player", {{"player", player_name_}}));
|
||||
}
|
||||
|
||||
void mp_match_history::pre_show(window& /*window*/)
|
||||
void mp_match_history::pre_show(window& win)
|
||||
{
|
||||
request_history(0);
|
||||
button& newer_history = find_widget<button>(&win, "newer_history", false);
|
||||
button& older_history = find_widget<button>(&win, "older_history", false);
|
||||
connect_signal_mouse_left_click(newer_history, std::bind(&mp_match_history::newer_history_offset, this));
|
||||
connect_signal_mouse_left_click(older_history, std::bind(&mp_match_history::older_history_offset, this));
|
||||
|
||||
update_display();
|
||||
}
|
||||
|
||||
void mp_match_history::request_history(int offset)
|
||||
void mp_match_history::newer_history_offset()
|
||||
{
|
||||
connection_.send_data({ "game_history_request", config { "offset", offset } });
|
||||
offset_ -= 10;
|
||||
// display update failed, set the offset back to what it was before
|
||||
if(!update_display()) {
|
||||
offset_ += 10;
|
||||
}
|
||||
}
|
||||
|
||||
void mp_match_history::older_history_offset()
|
||||
{
|
||||
offset_ += 10;
|
||||
// display update failed, set the offset back to what it was before
|
||||
if(!update_display()) {
|
||||
offset_ -= 10;
|
||||
}
|
||||
}
|
||||
|
||||
bool mp_match_history::update_display()
|
||||
{
|
||||
const config history = request_history(offset_);
|
||||
|
||||
// request failed, nothing to do
|
||||
if(history.child_count("game_history_result") == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
listbox* history_box = find_widget<listbox>(get_window(), "history", false, true);
|
||||
history_box->clear();
|
||||
|
||||
listbox* tab_bar = find_widget<listbox>(get_window(), "tab_bar", false, true);
|
||||
connect_signal_notify_modified(*tab_bar, std::bind(&mp_match_history::tab_switch_callback, this));
|
||||
|
||||
int i = 0;
|
||||
for(const config& game : history.child_range("game_history_result")) {
|
||||
widget_data row;
|
||||
grid& history_grid = history_box->add_row(row);
|
||||
|
||||
dynamic_cast<label*>(history_grid.find("game_name", false))->set_label(game["game_name"].str());
|
||||
dynamic_cast<label*>(history_grid.find("scenario_name", false))->set_label(game["scenario_name"].str());
|
||||
dynamic_cast<label*>(history_grid.find("era_name", false))->set_label("<span color='#baac7d'>"+_("Era: ")+"</span>"+game["era_name"].str());
|
||||
dynamic_cast<label*>(history_grid.find("game_start", false))->set_label(game["game_start"].str()+_(" UTC+0"));
|
||||
dynamic_cast<label*>(history_grid.find("version", false))->set_label(game["version"].str());
|
||||
|
||||
button* replay_download = dynamic_cast<button*>(history_grid.find("replay_download", false));
|
||||
std::string replay_url = game["replay_url"].str();
|
||||
if(!replay_url.empty()) {
|
||||
connect_signal_mouse_left_click(*replay_download, std::bind(&desktop::open_object, game["replay_url"].str()));
|
||||
} else {
|
||||
replay_download->set_active(false);
|
||||
}
|
||||
|
||||
std::vector<std::string> player_list;
|
||||
for(const config& player : game.child_range("player")) {
|
||||
player_list.emplace_back(player["name"].str()+": "+player["faction"].str());
|
||||
}
|
||||
label* players = dynamic_cast<label*>(history_grid.find("players", false));
|
||||
players->set_label(utils::join(player_list, "\n"));
|
||||
players->set_visible(gui2::widget::visibility::invisible);
|
||||
|
||||
label* modifications = dynamic_cast<label*>(history_grid.find("modifications", false));
|
||||
const auto& children = game.child_range("modification");
|
||||
if(!children.empty()) {
|
||||
std::vector<std::string> modifications_list;
|
||||
|
||||
for(const config& modification : game.child_range("modification")) {
|
||||
modifications_list.emplace_back(modification["name"].str());
|
||||
}
|
||||
|
||||
modifications->set_label(utils::join(modifications_list, "\n"));
|
||||
}
|
||||
modifications->set_visible(gui2::widget::visibility::invisible);
|
||||
|
||||
i++;
|
||||
if(i == 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// this is already the most recent history, can't get anything newer
|
||||
if(offset_ == 0) {
|
||||
button* newer_history = find_widget<button>(get_window(), "newer_history", false, true);
|
||||
newer_history->set_active(false);
|
||||
} else {
|
||||
button* newer_history = find_widget<button>(get_window(), "newer_history", false, true);
|
||||
newer_history->set_active(true);
|
||||
}
|
||||
|
||||
// the server returns up to 11 and the client displays at most 10
|
||||
// if fewer than 11 rows are returned, then there are no older rows left to get next
|
||||
if(history.child_count("game_history_result") < 11) {
|
||||
button* older_history = find_widget<button>(get_window(), "older_history", false, true);
|
||||
older_history->set_active(false);
|
||||
} else {
|
||||
button* older_history = find_widget<button>(get_window(), "older_history", false, true);
|
||||
older_history->set_active(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const config mp_match_history::request_history(int offset)
|
||||
{
|
||||
config request;
|
||||
config& child = request.add_child("game_history_request");
|
||||
child["offset"] = offset;
|
||||
child["search_for"] = player_name_;
|
||||
DBG_NW << request.debug();
|
||||
connection_.send_data(request);
|
||||
|
||||
int times_waited = 0;
|
||||
while(true) {
|
||||
config response;
|
||||
|
||||
// I'm not really sure why this works to be honest
|
||||
// I would've expected that there would be a risk of regular lobby responses showing up here since it's a reference to the lobby's network connection
|
||||
// however testing has resulted in showing that this is not the case
|
||||
// lobby responses are received in the lobby's network_handler() method when this method is not running
|
||||
// lobby responses are not received while this method is running, and are handled in the lobby after it completes
|
||||
// history results are never received in the lobby
|
||||
if(connection_.receive_data(response)) {
|
||||
if(response.child_count("game_history_result") == 0) {
|
||||
DBG_NW << "Received non-history data: " << response.debug();
|
||||
if(!response["error"].str().empty()) {
|
||||
DBG_NW << "Received error from server: " << response["error"].str();
|
||||
return {};
|
||||
}
|
||||
} else {
|
||||
DBG_NW << "Received history data: " << response.debug();
|
||||
return response;
|
||||
}
|
||||
} else {
|
||||
DBG_NW << "Received no data";
|
||||
}
|
||||
|
||||
if(times_waited > 20 || !wait_for_response_) {
|
||||
ERR_NW << "Timed out waiting for history data, returning nothing";
|
||||
return {};
|
||||
}
|
||||
|
||||
times_waited++;
|
||||
std::this_thread::sleep_for(250ms);
|
||||
}
|
||||
|
||||
DBG_NW << "Something else happened while waiting for history data, returning nothing";
|
||||
return {};
|
||||
}
|
||||
|
||||
void mp_match_history::tab_switch_callback()
|
||||
{
|
||||
listbox* history_box = find_widget<listbox>(get_window(), "history", false, true);
|
||||
listbox* tab_bar = find_widget<listbox>(get_window(), "tab_bar", false, true);
|
||||
int tab = tab_bar->get_selected_row();
|
||||
|
||||
for(int i = 0; i < 10; i++) {
|
||||
grid* history_grid = history_box->get_row_grid(i);
|
||||
if(tab == 0) {
|
||||
dynamic_cast<label*>(history_grid->find("scenario_name", false))->set_visible(gui2::widget::visibility::visible);
|
||||
dynamic_cast<label*>(history_grid->find("era_name", false))->set_visible(gui2::widget::visibility::visible);
|
||||
dynamic_cast<label*>(history_grid->find("game_start", false))->set_visible(gui2::widget::visibility::visible);
|
||||
dynamic_cast<label*>(history_grid->find("version", false))->set_visible(gui2::widget::visibility::visible);
|
||||
dynamic_cast<button*>(history_grid->find("replay_download", false))->set_visible(gui2::widget::visibility::visible);
|
||||
dynamic_cast<label*>(history_grid->find("players", false))->set_visible(gui2::widget::visibility::invisible);
|
||||
dynamic_cast<label*>(history_grid->find("modifications", false))->set_visible(gui2::widget::visibility::invisible);
|
||||
} else if(tab == 1) {
|
||||
dynamic_cast<label*>(history_grid->find("scenario_name", false))->set_visible(gui2::widget::visibility::invisible);
|
||||
dynamic_cast<label*>(history_grid->find("era_name", false))->set_visible(gui2::widget::visibility::invisible);
|
||||
dynamic_cast<label*>(history_grid->find("game_start", false))->set_visible(gui2::widget::visibility::invisible);
|
||||
dynamic_cast<label*>(history_grid->find("version", false))->set_visible(gui2::widget::visibility::invisible);
|
||||
dynamic_cast<button*>(history_grid->find("replay_download", false))->set_visible(gui2::widget::visibility::invisible);
|
||||
dynamic_cast<label*>(history_grid->find("players", false))->set_visible(gui2::widget::visibility::visible);
|
||||
dynamic_cast<label*>(history_grid->find("modifications", false))->set_visible(gui2::widget::visibility::invisible);
|
||||
} else if(tab == 2) {
|
||||
dynamic_cast<label*>(history_grid->find("scenario_name", false))->set_visible(gui2::widget::visibility::invisible);
|
||||
dynamic_cast<label*>(history_grid->find("era_name", false))->set_visible(gui2::widget::visibility::invisible);
|
||||
dynamic_cast<label*>(history_grid->find("game_start", false))->set_visible(gui2::widget::visibility::invisible);
|
||||
dynamic_cast<label*>(history_grid->find("version", false))->set_visible(gui2::widget::visibility::invisible);
|
||||
dynamic_cast<button*>(history_grid->find("replay_download", false))->set_visible(gui2::widget::visibility::invisible);
|
||||
dynamic_cast<label*>(history_grid->find("players", false))->set_visible(gui2::widget::visibility::invisible);
|
||||
dynamic_cast<label*>(history_grid->find("modifications", false))->set_visible(gui2::widget::visibility::visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dialogs
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
#include "gui/dialogs/modal_dialog.hpp"
|
||||
|
||||
namespace mp { struct user_info; }
|
||||
|
||||
class wesnothd_connection;
|
||||
|
||||
namespace gui2
|
||||
|
@ -29,25 +27,70 @@ namespace dialogs
|
|||
class mp_match_history : public modal_dialog
|
||||
{
|
||||
public:
|
||||
mp_match_history(mp::user_info& info, wesnothd_connection& connection);
|
||||
/**
|
||||
* Creates a dialog to view a player's history 10 games at a time.
|
||||
*
|
||||
* @param player_name The username of the player whose history is being viewed
|
||||
* @param connection A reference to the lobby's network connection to wesnothd
|
||||
* @param wait_for_response Whether to wait a few seconds for a response or not.
|
||||
*/
|
||||
mp_match_history(const std::string& player_name, wesnothd_connection& connection, bool wait_for_response = true);
|
||||
|
||||
/**
|
||||
* The display function.
|
||||
*
|
||||
* See @ref modal_dialog for more information.
|
||||
*/
|
||||
DEFINE_SIMPLE_DISPLAY_WRAPPER(mp_match_history)
|
||||
static void display(const std::string& player_name, wesnothd_connection& connection, bool wait_for_response = true)
|
||||
{
|
||||
mp_match_history(player_name, connection, wait_for_response).show();
|
||||
}
|
||||
|
||||
private:
|
||||
virtual const std::string& window_id() const override;
|
||||
|
||||
virtual void pre_show(window& window) override;
|
||||
|
||||
void request_history(int offset);
|
||||
/**
|
||||
* Requests game history from the server based on the offset.
|
||||
* 11 rows are returned and 10 displayed - the presence of the 11th indicates whether incrementing the offset again would return any data.
|
||||
* A request can time out if the server takes too long to respond so that a failure by the server to respond at all doesn't lock the game indefinitely.
|
||||
*
|
||||
* @param offset
|
||||
* @return A config containing the game history information or an empty config if either the request times out or returns with an error
|
||||
*/
|
||||
const config request_history(int offset);
|
||||
|
||||
mp::user_info& info_;
|
||||
/**
|
||||
* Updates the dialog with the information returned by the server.
|
||||
* This is called on dialog open as well as when incrementing or decrementing the offset.
|
||||
*
|
||||
* @return Whether the game history information was returned by the server or not.
|
||||
*/
|
||||
bool update_display();
|
||||
|
||||
/**
|
||||
* Handles changing the selected horizontal listbox item for the specified game history row.
|
||||
*/
|
||||
void tab_switch_callback();
|
||||
|
||||
/** Increments the offset to use for querying data by 10 and updates the information displayed by the dialog. */
|
||||
void newer_history_offset();
|
||||
/** Decrements the offset to use for querying data by 10 and updates the information displayed by the dialog. */
|
||||
void older_history_offset();
|
||||
|
||||
/** The username of the player whose history is being viewed */
|
||||
std::string player_name_;
|
||||
/** A reference to the lobby's network connection to wesnothd */
|
||||
wesnothd_connection& connection_;
|
||||
/** The offset to start retrieving history data at - should be increments of 10 */
|
||||
int offset_;
|
||||
/**
|
||||
* Whether to wait a few seconds for a response or not.
|
||||
* True for the regular client.
|
||||
* False for the boost unit tests, since otherwise the gui2 test times out waiting for the request to the dummy wesnothd_connection to fail.
|
||||
*/
|
||||
bool wait_for_response_;
|
||||
};
|
||||
|
||||
} // namespace dialogs
|
||||
|
|
|
@ -123,20 +123,23 @@ std::unique_ptr<simple_wml::document> dbconn::get_game_history(int player_id, in
|
|||
{
|
||||
std::string game_history_query = "select "
|
||||
" game.GAME_NAME, "
|
||||
" game.RELOAD, "
|
||||
" game.START_TIME, "
|
||||
" GROUP_CONCAT(CONCAT(player.USER_NAME, ':', player.FACTION)) as PLAYERS, "
|
||||
" IFNULL(scenario.NAME, '') as SCENARIO_NAME, "
|
||||
" IFNULL(scenario.ID, '') as SCENARIO_ID, "
|
||||
" IFNULL(era.NAME, '') as ERA_NAME, "
|
||||
" IFNULL(era.ID, '') as ERA_ID, "
|
||||
" IFNULL(GROUP_CONCAT(distinct mods.NAME, '') as MODIFICATION_NAMES, "
|
||||
" IFNULL(GROUP_CONCAT(distinct mods.ID), '') as MODIFICATION_IDS, "
|
||||
" IFNULL(GROUP_CONCAT(distinct mods.NAME), '') as MODIFICATION_NAMES, "
|
||||
" case "
|
||||
" when game.PUBLIC = 1 "
|
||||
" when game.PUBLIC = 1 and game.INSTANCE_VERSION != 'trunk' "
|
||||
" then concat('https://replays.wesnoth.org/', substring(game.INSTANCE_VERSION, 1, 4), '/', year(game.END_TIME), '/', lpad(month(game.END_TIME), 2, '0'), '/', lpad(day(game.END_TIME), 2, '0'), '/', game.REPLAY_NAME) "
|
||||
" when game.PUBLIC = 1 and game.INSTANCE_VERSION = 'trunk' "
|
||||
" then concat('https://replays.wesnoth.org/', game.INSTANCE_VERSION, '/', year(game.END_TIME), '/', lpad(month(game.END_TIME), 2, '0'), '/', lpad(day(game.END_TIME), 2, '0'), '/', game.REPLAY_NAME) "
|
||||
" else '' "
|
||||
" end as REPLAY_URL "
|
||||
" end as REPLAY_URL, "
|
||||
" case "
|
||||
" when game.INSTANCE_VERSION != 'trunk' "
|
||||
" then SUBSTRING(game.INSTANCE_VERSION, 1, 4) "
|
||||
" else 'trunk' "
|
||||
" end as VERSION "
|
||||
"from "+db_game_info_table_+" game "
|
||||
"inner join "+db_game_player_info_table_+" player "
|
||||
" on exists "
|
||||
|
|
|
@ -27,12 +27,9 @@ void game_history::read(mariadb::result_set_ref rslt)
|
|||
{
|
||||
result r;
|
||||
r.game_name = rslt->get_string("GAME_NAME");
|
||||
r.reload = rslt->get_boolean("RELOAD");
|
||||
r.game_start = rslt->get_date_time("START_TIME").str();
|
||||
r.scenario_name = rslt->get_string("SCENARIO_NAME");
|
||||
r.scenario_id = rslt->get_string("SCENARIO_ID");
|
||||
r.era_name = rslt->get_string("ERA_NAME");
|
||||
r.era_id = rslt->get_string("ERA_ID");
|
||||
for(const auto& player_info : utils::split(rslt->get_string("PLAYERS")))
|
||||
{
|
||||
std::vector<std::string> info = utils::split(player_info, ':');
|
||||
|
@ -46,8 +43,8 @@ void game_history::read(mariadb::result_set_ref rslt)
|
|||
}
|
||||
}
|
||||
r.modification_names = utils::split(rslt->get_string("MODIFICATION_NAMES"));
|
||||
r.modification_ids = utils::split(rslt->get_string("MODIFICATION_IDS"));
|
||||
r.replay_url = rslt->get_string("REPLAY_URL");
|
||||
r.version = rslt->get_string("VERSION");
|
||||
results.push_back(std::move(r));
|
||||
}
|
||||
}
|
||||
|
@ -59,12 +56,11 @@ std::unique_ptr<simple_wml::document> game_history::to_doc()
|
|||
{
|
||||
simple_wml::node& ghr = doc->root().add_child("game_history_result");
|
||||
ghr.set_attr_dup("game_name", result.game_name.c_str());
|
||||
ghr.set_attr_int("reload", result.reload);
|
||||
ghr.set_attr_dup("game_start", result.game_start.c_str());
|
||||
ghr.set_attr_dup("scenario_name", result.scenario_name.c_str());
|
||||
ghr.set_attr_dup("scenario_id", result.scenario_id.c_str());
|
||||
ghr.set_attr_dup("era_name", result.era_name.c_str());
|
||||
ghr.set_attr_dup("era_id", result.era_id.c_str());
|
||||
ghr.set_attr_dup("replay_url", result.replay_url.c_str());
|
||||
ghr.set_attr_dup("version", result.version.c_str());
|
||||
for(const auto& player : result.players)
|
||||
{
|
||||
simple_wml::node& p = ghr.add_child("player");
|
||||
|
@ -76,11 +72,6 @@ std::unique_ptr<simple_wml::document> game_history::to_doc()
|
|||
simple_wml::node& m = ghr.add_child("modification");
|
||||
m.set_attr_dup("name", mod.c_str());
|
||||
}
|
||||
for(const auto& mod : result.modification_ids)
|
||||
{
|
||||
simple_wml::node& m = ghr.add_child("modification");
|
||||
m.set_attr_dup("id", mod.c_str());
|
||||
}
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
|
|
|
@ -32,16 +32,13 @@ class game_history : public rs_base
|
|||
struct result
|
||||
{
|
||||
std::string game_name;
|
||||
int reload;
|
||||
std::string game_start;
|
||||
std::string scenario_name;
|
||||
std::string scenario_id;
|
||||
std::string era_name;
|
||||
std::string era_id;
|
||||
std::vector<player> players;
|
||||
std::vector<std::string> modification_names;
|
||||
std::vector<std::string> modification_ids;
|
||||
std::string replay_url;
|
||||
std::string version;
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
|
@ -1139,6 +1139,34 @@ void server::handle_player_in_lobby(player_iterator player, simple_wml::document
|
|||
handle_join_game(player, *join);
|
||||
return;
|
||||
}
|
||||
|
||||
if(simple_wml::node* request = data.child("game_history_request")) {
|
||||
if(user_handler_) {
|
||||
int offset = request->attr("offset").to_int();
|
||||
int player_id = 0;
|
||||
|
||||
// if no search_for attribute -> get the requestor's forum id
|
||||
// if search_for attribute for offline player -> query the forum database for the forum id
|
||||
// if search_for attribute for online player -> get the forum id from wesnothd's player info
|
||||
if(!request->has_attr("search_for")) {
|
||||
player_id = player->info().config_address()->attr("forum_id").to_int();
|
||||
} else {
|
||||
std::string player_name = request->attr("search_for").to_string();
|
||||
auto player_ptr = player_connections_.get<name_t>().find(player_name);
|
||||
if(player_ptr == player_connections_.get<name_t>().end()) {
|
||||
player_id = user_handler_->get_forum_id(player_name);
|
||||
} else {
|
||||
player_id = player_ptr->info().config_address()->attr("forum_id").to_int();
|
||||
}
|
||||
}
|
||||
|
||||
if(player_id != 0) {
|
||||
LOG_SERVER << "Querying game history requested by player `" << player->info().name() << "` for player id `" << player_id << "`.";
|
||||
user_handler_->async_get_and_send_game_history(io_service_, *this, player, player_id, offset);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void server::handle_whisper(player_iterator player, simple_wml::node& whisper)
|
||||
|
@ -1867,32 +1895,6 @@ void server::handle_player_in_game(player_iterator p, simple_wml::document& data
|
|||
} else if(data.child("stop_updates")) {
|
||||
g.send_data(data, p);
|
||||
return;
|
||||
} else if(simple_wml::node* request = data.child("game_history_request")) {
|
||||
if(user_handler_) {
|
||||
int offset = request->attr("offset").to_int();
|
||||
int player_id = 0;
|
||||
|
||||
// if no search_for attribute -> get the requestor's forum id
|
||||
// if search_for attribute for offline player -> query the forum database for the forum id
|
||||
// if search_for attribute for online player -> get the forum id from wesnothd's player info
|
||||
if(!request->has_attr("search_for")) {
|
||||
player_id = player.config_address()->attr("forum_id").to_int();
|
||||
} else {
|
||||
std::string player_name = request->attr("search_for").to_string();
|
||||
auto player_ptr = player_connections_.get<name_t>().find(player_name);
|
||||
if(player_ptr == player_connections_.get<name_t>().end()) {
|
||||
player_id = user_handler_->get_forum_id(player_name);
|
||||
} else {
|
||||
player_id = player_ptr->info().config_address()->attr("forum_id").to_int();
|
||||
}
|
||||
}
|
||||
|
||||
if(player_id != 0) {
|
||||
LOG_SERVER << "Querying game history requested by player `" << player.name() << "` for player id `" << player_id << "`.";
|
||||
user_handler_->async_get_and_send_game_history(io_service_, *this, p, player_id, offset);
|
||||
}
|
||||
}
|
||||
return;
|
||||
// Data to ignore.
|
||||
} else if(
|
||||
data.child("error") ||
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
#include "gui/dialogs/multiplayer/mp_join_game.hpp"
|
||||
#include "gui/dialogs/multiplayer/mp_join_game_password_prompt.hpp"
|
||||
#include "gui/dialogs/multiplayer/mp_login.hpp"
|
||||
#include "gui/dialogs/multiplayer/match_history.hpp"
|
||||
#include "gui/dialogs/multiplayer/mp_method_selection.hpp"
|
||||
#include "gui/dialogs/multiplayer/mp_report.hpp"
|
||||
#include "gui/dialogs/multiplayer/mp_staging.hpp"
|
||||
|
@ -600,6 +601,10 @@ BOOST_AUTO_TEST_CASE(modal_dialog_test_achievements_dialog)
|
|||
{
|
||||
test<achievements_dialog>();
|
||||
}
|
||||
BOOST_AUTO_TEST_CASE(modal_dialog_test_mp_match_history_dialog)
|
||||
{
|
||||
test<mp_match_history>();
|
||||
}
|
||||
BOOST_AUTO_TEST_CASE(modeless_dialog_test_debug_clock)
|
||||
{
|
||||
test_popup<debug_clock>();
|
||||
|
@ -983,6 +988,19 @@ struct dialog_tester<mp_lobby>
|
|||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct dialog_tester<mp_match_history>
|
||||
{
|
||||
wesnothd_connection connection;
|
||||
dialog_tester() : connection("", "")
|
||||
{
|
||||
}
|
||||
mp_match_history* create()
|
||||
{
|
||||
return new mp_match_history("", connection, false);
|
||||
}
|
||||
};
|
||||
|
||||
class fake_chat_handler : public events::chat_handler {
|
||||
void add_chat_message(const std::time_t&,
|
||||
const std::string&, int, const std::string&,
|
||||
|
|
Loading…
Add table
Reference in a new issue