atrooney-online-2/src/lobby.cpp
Leifa efd2571459
Remove TCP entry point (#1007)
* Remove TCP entry point

Resolve #987

* Remove TCP entry point
  * Servers that do not support WebSocket will be marked as `Legacy`
  * Removal of TCP connection from the master will follow later.

* Tweaked error message
2024-07-09 13:07:30 +02:00

578 lines
17 KiB
C++

#include "lobby.h"
#include "aoapplication.h"
#include "demoserver.h"
#include "gui_utils.h"
#include "networkmanager.h"
#include "widgets/direct_connect_dialog.h"
#include "widgets/server_editor_dialog.h"
#include <QImageReader>
#include <QUiLoader>
Lobby::Lobby(AOApplication *p_ao_app, NetworkManager *p_net_manager)
: QMainWindow()
{
ao_app = p_ao_app;
net_manager = p_net_manager;
reloadUi();
}
void Lobby::on_tab_changed(int index)
{
switch (index)
{
case SERVER:
current_page = SERVER;
ui_add_to_favorite_button->setVisible(true);
ui_remove_from_favorites_button->setVisible(false);
ui_add_server_button->setVisible(false);
ui_edit_favorite_button->setVisible(false);
ui_direct_connect_button->setVisible(true);
reset_selection();
break;
case FAVORITES:
current_page = FAVORITES;
ui_add_to_favorite_button->setVisible(false);
ui_remove_from_favorites_button->setVisible(true);
ui_add_server_button->setVisible(true);
ui_edit_favorite_button->setVisible(true);
ui_direct_connect_button->setVisible(false);
reset_selection();
break;
case DEMOS:
current_page = DEMOS;
ui_add_to_favorite_button->setVisible(false);
ui_add_server_button->setVisible(false);
ui_remove_from_favorites_button->setVisible(false);
ui_edit_favorite_button->setVisible(false);
ui_direct_connect_button->setVisible(false);
reset_selection();
break;
default:
break;
}
}
int Lobby::get_selected_server()
{
switch (ui_connections_tabview->currentIndex())
{
case SERVER:
if (auto item = ui_serverlist_tree->currentItem())
{
return item->text(0).toInt();
}
break;
case FAVORITES:
if (auto item = ui_favorites_tree->currentItem())
{
return item->text(0).toInt();
}
break;
default:
break;
}
return -1;
}
int Lobby::pageSelected()
{
return current_page;
}
void Lobby::reset_selection()
{
last_index = -1;
ui_server_player_count_lbl->setText(tr("Offline"));
ui_server_description_text->clear();
ui_edit_favorite_button->setEnabled(false);
ui_remove_from_favorites_button->setEnabled(false);
ui_connect_button->setEnabled(false);
}
void Lobby::loadUI()
{
this->setWindowTitle(tr("Attorney Online %1").arg(ao_app->applicationVersion()));
this->setWindowIcon(QIcon(":/logo.png"));
this->setWindowFlags((this->windowFlags() | Qt::CustomizeWindowHint));
QUiLoader l_loader(this);
QFile l_uiFile(Options::getInstance().getUIAsset(DEFAULT_UI));
if (!l_uiFile.open(QFile::ReadOnly))
{
qCritical() << "Unable to open file " << l_uiFile.fileName();
return;
}
l_loader.load(&l_uiFile, this);
FROM_UI(QLabel, game_version_lbl);
ui_game_version_lbl->setText(tr("Version: %1").arg(ao_app->get_version_string()));
FROM_UI(QPushButton, settings_button);
connect(ui_settings_button, &QPushButton::clicked, this, &Lobby::onSettingsRequested);
FROM_UI(QPushButton, about_button);
connect(ui_about_button, &QPushButton::clicked, this, &Lobby::on_about_clicked);
// Serverlist elements
FROM_UI(QTabWidget, connections_tabview);
ui_connections_tabview->tabBar()->setExpanding(true);
connect(ui_connections_tabview, &QTabWidget::currentChanged, this, &Lobby::on_tab_changed);
FROM_UI(QTreeWidget, serverlist_tree);
FROM_UI(QLineEdit, serverlist_search);
connect(ui_serverlist_tree, &QTreeWidget::itemClicked, this, &Lobby::on_server_list_clicked);
connect(ui_serverlist_tree, &QTreeWidget::itemDoubleClicked, this, &Lobby::on_list_doubleclicked);
connect(ui_serverlist_search, &QLineEdit::textChanged, this, &Lobby::on_server_search_edited);
FROM_UI(QTreeWidget, favorites_tree);
connect(ui_favorites_tree, &QTreeWidget::itemClicked, this, &Lobby::on_favorite_tree_clicked);
connect(ui_favorites_tree, &QTreeWidget::itemDoubleClicked, this, &Lobby::on_list_doubleclicked);
FROM_UI(QTreeWidget, demo_tree);
connect(ui_demo_tree, &QTreeWidget::itemClicked, this, &Lobby::on_demo_clicked);
connect(ui_demo_tree, &QTreeWidget::itemDoubleClicked, this, &Lobby::on_list_doubleclicked);
FROM_UI(QPushButton, refresh_button);
connect(ui_refresh_button, &QPushButton::released, this, &Lobby::on_refresh_released);
FROM_UI(QPushButton, direct_connect_button);
connect(ui_direct_connect_button, &QPushButton::released, this, &Lobby::on_direct_connect_released);
FROM_UI(QPushButton, add_to_favorite_button);
connect(ui_add_to_favorite_button, &QPushButton::released, this, &Lobby::on_add_to_fav_released);
FROM_UI(QPushButton, add_server_button);
ui_add_server_button->setVisible(false);
connect(ui_add_server_button, &QPushButton::released, this, &Lobby::on_add_server_to_fave_released);
FROM_UI(QPushButton, edit_favorite_button);
ui_edit_favorite_button->setVisible(false);
connect(ui_edit_favorite_button, &QPushButton::released, this, &Lobby::on_edit_favorite_released);
FROM_UI(QPushButton, remove_from_favorites_button);
ui_remove_from_favorites_button->setVisible(false);
connect(ui_remove_from_favorites_button, &QPushButton::released, this, &Lobby::on_remove_from_fav_released);
FROM_UI(QLabel, server_player_count_lbl);
FROM_UI(QTextBrowser, server_description_text);
FROM_UI(QPushButton, connect_button);
connect(ui_connect_button, &QPushButton::released, net_manager, &NetworkManager::join_to_server);
connect(ui_connect_button, &QPushButton::released, this, [=] { ui_server_player_count_lbl->setText(tr("Joining Server...")); });
connect(net_manager, &NetworkManager::server_connected, ui_connect_button, &QPushButton::setEnabled);
FROM_UI(QTextBrowser, motd_text);
FROM_UI(QTextBrowser, game_changelog_text);
if (ui_game_changelog_text != nullptr)
{
QString l_changelog_text = "No changelog found.";
QFile l_changelog(get_base_path() + "changelog.md");
if (!l_changelog.open(QFile::ReadOnly))
{
qDebug() << "Unable to locate changelog file. Does it even exist?";
ui_game_changelog_text->setMarkdown(l_changelog_text);
return;
}
ui_game_changelog_text->setMarkdown(l_changelog.readAll());
l_changelog.close();
QTabWidget *l_tabbar = findChild<QTabWidget *>("motd_changelog_tab");
if (l_tabbar != nullptr)
{
l_tabbar->tabBar()->setExpanding(true);
}
}
}
void Lobby::reloadUi()
{
loadUI();
list_servers();
list_favorites();
list_demos();
get_motd();
check_for_updates();
reset_selection();
}
void Lobby::on_refresh_released()
{
net_manager->get_server_list();
get_motd();
list_favorites();
}
void Lobby::on_direct_connect_released()
{
DirectConnectDialog connect_dialog(net_manager);
connect_dialog.exec();
}
void Lobby::on_add_to_fav_released()
{
int selection = get_selected_server();
if (selection > -1)
{
Options::getInstance().addFavorite(ao_app->get_server_list().at(selection));
list_favorites();
}
}
void Lobby::on_add_server_to_fave_released()
{
ServerEditorDialog dialog;
if (dialog.exec())
{
Options::getInstance().addFavorite(dialog.currentServerInfo());
list_favorites();
reset_selection();
}
}
void Lobby::on_edit_favorite_released()
{
const int index = get_selected_server();
ServerEditorDialog dialog(Options::getInstance().favorites().at(index));
if (dialog.exec())
{
Options::getInstance().updateFavorite(dialog.currentServerInfo(), index);
list_favorites();
reset_selection();
}
}
void Lobby::on_remove_from_fav_released()
{
int selection = get_selected_server();
if (selection >= 0)
{
Options::getInstance().removeFavorite(selection);
list_favorites();
}
}
void Lobby::on_about_clicked()
{
const bool hasApng = QImageReader::supportedImageFormats().contains("apng");
QString msg = tr("<h2>Attorney Online %1</h2>"
"The courtroom drama simulator."
"<p><b>Source code:</b> "
"<a href='https://github.com/AttorneyOnline/AO2-Client'>"
"https://github.com/AttorneyOnline/AO2-Client</a>"
"<p><b>Major development:</b><br>"
"OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, "
"Crystalwarrior, Iamgoofball, in1tiate"
"<p><b>Client development:</b><br>"
"Cents02, windrammer, skyedeving, TrickyLeifa, Salanto, lambdcalculus"
"<p><b>QA testing:</b><br>"
"CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, "
"Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, "
"Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, "
"Veritas, Wiso"
"<p><b>Translations:</b><br>"
"k-emiko (Русский), Pyraq (Polski), scatterflower (日本語), vintprox "
"(Русский), "
"windrammer (Español, Português)"
"<p><b>Special thanks:</b><br>"
"Wiso, dyviacat (2.10 release); "
"CrazyJC (2.8 release director) and MaximumVolty (2.8 release "
"promotion); "
"Remy, Hibiki, court-records.net (sprites); Qubrick (webAO); "
"Rue (website); Draxirch (UI design); "
"Lewdton and Argoneus (tsuserver); "
"Fiercy, Noevain, Cronnicossy, and FanatSors (AO1); "
"server hosts, game masters, case makers, content creators, "
"and the whole AO2 community!"
"<p>The Attorney Online networked visual novel project "
"is copyright (c) 2016-2022 Attorney Online developers. Open-source "
"licenses apply. All other assets are the property of their "
"respective owners."
"<p>Running on Qt version %2 with the BASS audio engine.<br>"
"APNG plugin loaded: %3"
"<p>Built on %4")
.arg(ao_app->get_version_string())
.arg(QLatin1String(QT_VERSION_STR))
.arg(hasApng ? tr("Yes") : tr("No"))
.arg(QLatin1String(__DATE__));
QMessageBox::about(this, tr("About"), msg);
}
// clicked on an item in the serverlist
void Lobby::on_server_list_clicked(QTreeWidgetItem *p_item, int column)
{
column = 0;
ServerInfo f_server;
int n_server = p_item->text(column).toInt();
if (n_server == last_index)
{
return;
}
last_index = n_server;
if (n_server < 0)
{
return;
}
QVector<ServerInfo> f_server_list = ao_app->get_server_list();
if (n_server >= f_server_list.size())
{
return;
}
f_server = f_server_list.at(n_server);
set_server_description(f_server.description);
ui_server_description_text->moveCursor(QTextCursor::Start);
ui_server_description_text->ensureCursorVisible();
ui_server_player_count_lbl->setText(tr("Connecting..."));
ui_connect_button->setEnabled(false);
net_manager->connect_to_server(f_server);
}
// doubleclicked on an item in the serverlist so we'll connect right away
void Lobby::on_list_doubleclicked(QTreeWidgetItem *p_item, int column)
{
Q_UNUSED(p_item)
Q_UNUSED(column)
ui_server_player_count_lbl->setText(tr("Joining Server..."));
net_manager->join_to_server();
}
void Lobby::on_favorite_tree_clicked(QTreeWidgetItem *p_item, int column)
{
column = 0;
ServerInfo f_server;
int n_server = p_item->text(column).toInt();
if (n_server == last_index)
{
return;
}
last_index = n_server;
if (n_server < 0)
{
return;
}
ui_add_server_button->setEnabled(true);
ui_edit_favorite_button->setEnabled(true);
ui_remove_from_favorites_button->setEnabled(true);
QVector<ServerInfo> f_server_list = Options::getInstance().favorites();
if (n_server >= f_server_list.size())
{
return;
}
f_server = f_server_list.at(n_server);
set_server_description(f_server.description);
ui_server_description_text->moveCursor(QTextCursor::Start);
ui_server_description_text->ensureCursorVisible();
ui_server_player_count_lbl->setText(tr("Connecting..."));
ui_connect_button->setEnabled(false);
net_manager->connect_to_server(f_server);
}
void Lobby::on_server_search_edited(QString p_text)
{
// Iterate through all QTreeWidgetItem items
QTreeWidgetItemIterator it(ui_serverlist_tree);
while (*it)
{
(*it)->setHidden(p_text != "");
++it;
}
if (p_text != "")
{
// Search in metadata
QList<QTreeWidgetItem *> clist = ui_serverlist_tree->findItems(ui_serverlist_search->text(), Qt::MatchContains | Qt::MatchRecursive, 1);
foreach (QTreeWidgetItem *item, clist)
{
if (item->parent() != nullptr) // So the category shows up too
{
item->parent()->setHidden(false);
}
item->setHidden(false);
}
}
}
void Lobby::on_demo_clicked(QTreeWidgetItem *item, int column)
{
Q_UNUSED(column)
if (item == nullptr)
{
return;
}
QString l_filepath = (get_app_path() + "/logs/%1/%2").arg(item->data(0, Qt::DisplayRole).toString(), item->data(1, Qt::DisplayRole).toString());
ao_app->demo_server->start_server();
ServerInfo demo_server;
demo_server.address = "127.0.0.1";
demo_server.port = ao_app->demo_server->port();
ao_app->demo_server->set_demo_file(l_filepath);
net_manager->connect_to_server(demo_server);
}
void Lobby::onReloadThemeRequested()
{
// This is destructive to the active widget data.
// Whatever, this is lobby. Nothing here is worth saving.
delete centralWidget();
reloadUi();
}
void Lobby::onSettingsRequested()
{
AOOptionsDialog options(ao_app);
connect(&options, &AOOptionsDialog::reloadThemeRequest, this, &Lobby::onReloadThemeRequested);
options.exec();
}
void Lobby::list_servers()
{
ui_serverlist_tree->setSortingEnabled(false);
ui_serverlist_tree->clear();
ui_serverlist_search->setText("");
int i = 0;
for (const ServerInfo &i_server : qAsConst(ao_app->get_server_list()))
{
QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_serverlist_tree);
treeItem->setData(0, Qt::DisplayRole, i);
if (i_server.legacy)
{
treeItem->setText(1, "(Legacy) " + i_server.name);
treeItem->setBackground(0, Qt::darkRed);
treeItem->setBackground(1, Qt::darkRed);
QString tooltip = tr("Unable to connect to server. Server is missing WebSocket support.");
treeItem->setToolTip(0, tooltip);
treeItem->setToolTip(1, tooltip);
}
else
{
treeItem->setText(1, i_server.name);
}
i++;
}
ui_serverlist_tree->setSortingEnabled(true);
ui_serverlist_tree->sortItems(0, Qt::SortOrder::AscendingOrder);
ui_serverlist_tree->resizeColumnToContents(0);
}
void Lobby::list_favorites()
{
ui_favorites_tree->setSortingEnabled(false);
ui_favorites_tree->clear();
int i = 0;
for (const ServerInfo &i_server : Options::getInstance().favorites())
{
QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_favorites_tree);
treeItem->setData(0, Qt::DisplayRole, i);
if (i_server.legacy)
{
treeItem->setText(1, "(Legacy) " + i_server.name);
treeItem->setBackground(0, Qt::darkRed);
treeItem->setBackground(1, Qt::darkRed);
QString tooltip = tr("Unable to connect to server. Server is missing WebSocket support.");
treeItem->setToolTip(0, tooltip);
treeItem->setToolTip(1, tooltip);
}
else
{
treeItem->setText(1, i_server.name);
}
i++;
}
ui_favorites_tree->setSortingEnabled(true);
ui_favorites_tree->sortItems(0, Qt::SortOrder::AscendingOrder);
ui_favorites_tree->resizeColumnToContents(0);
}
void Lobby::list_demos()
{
ui_demo_tree->setSortingEnabled(false);
ui_demo_tree->clear();
QMultiMap<QString, QString> m_demo_entries = ao_app->load_demo_logs_list();
for (auto &l_key : m_demo_entries.uniqueKeys())
{
for (const QString &l_entry : m_demo_entries.values(l_key))
{
QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui_demo_tree);
treeItem->setData(0, Qt::DisplayRole, l_key);
treeItem->setData(1, Qt::DisplayRole, l_entry);
}
}
ui_demo_tree->setSortingEnabled(true);
ui_demo_tree->sortItems(0, Qt::SortOrder::AscendingOrder);
ui_demo_tree->resizeColumnToContents(0);
}
void Lobby::get_motd()
{
net_manager->request_document(MSDocumentType::Motd, [this](QString document) {
if (document.isEmpty())
{
document = tr("Couldn't get the message of the day.");
}
ui_motd_text->setHtml(document);
});
}
void Lobby::check_for_updates()
{
net_manager->request_document(MSDocumentType::ClientVersion, [this](QString version) {
const QString current_version = ao_app->get_version_string();
if (!version.isEmpty() && version != current_version)
{
ui_game_version_lbl->setText(tr("Version: %1 (!)").arg(current_version));
ui_game_version_lbl->setToolTip(tr("New version available: %1").arg(version));
}
});
}
void Lobby::set_player_count(int players_online, int max_players)
{
QString f_string = tr("Online: %1/%2").arg(QString::number(players_online), QString::number(max_players));
ui_server_player_count_lbl->setText(f_string);
}
void Lobby::set_server_description(const QString &server_description)
{
ui_server_description_text->clear();
QString result = server_description.toHtmlEscaped().replace("\n", "<br>").replace(QRegularExpression("\\b(https?://\\S+\\.\\S+)\\b"), "<a href='\\1'>\\1</a>");
ui_server_description_text->insertHtml(result);
}
Lobby::~Lobby()
{}