#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 #include 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("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("

Attorney Online %1

" "The courtroom drama simulator." "

Source code: " "" "https://github.com/AttorneyOnline/AO2-Client" "

Major development:
" "OmniTroid, stonedDiscord, longbyte1, gameboyprinter, Cerapter, " "Crystalwarrior, Iamgoofball, in1tiate" "

Client development:
" "Cents02, windrammer, skyedeving, TrickyLeifa, Salanto, lambdcalculus" "

QA testing:
" "CaseyCazy, CedricDewitt, Chewable Tablets, CrazyJC, Fantos, " "Fury McFlurry, Geck, Gin-Gi, Jamania, Minx, Pandae, " "Robotic Overlord, Shadowlions (aka Shali), Sierra, SomeGuy, " "Veritas, Wiso" "

Translations:
" "k-emiko (Русский), Pyraq (Polski), scatterflower (日本語), vintprox " "(Русский), " "windrammer (Español, Português)" "

Special thanks:
" "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!" "

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." "

Running on Qt version %2 with the BASS audio engine.
" "APNG plugin loaded: %3" "

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 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 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 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 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", "
").replace(QRegularExpression("\\b(https?://\\S+\\.\\S+)\\b"), "\\1"); ui_server_description_text->insertHtml(result); } Lobby::~Lobby() {}