diff options
Diffstat (limited to 'src/yuzu')
| -rw-r--r-- | src/yuzu/main.cpp | 63 | ||||
| -rw-r--r-- | src/yuzu/main.h | 1 | ||||
| -rw-r--r-- | src/yuzu/main.ui | 24 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/chat_room.cpp | 12 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/client_room.cpp | 3 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/direct_connect.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/direct_connect.h | 1 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/host_room.cpp | 1 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/host_room.h | 3 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/lobby.cpp | 67 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/lobby.h | 8 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/lobby_p.h | 18 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/message.cpp | 6 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/state.cpp | 80 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/state.h | 14 | ||||
| -rw-r--r-- | src/yuzu/uisettings.h | 2 | 
16 files changed, 217 insertions, 88 deletions
| diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e2c2b9292..c63ce3a30 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -105,12 +105,12 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual  #include "core/hle/kernel/k_process.h"  #include "core/hle/service/am/am.h"  #include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/nfp/nfp.h"  #include "core/hle/service/sm/sm.h"  #include "core/loader/loader.h"  #include "core/perf_stats.h"  #include "core/telemetry_session.h"  #include "input_common/drivers/tas_input.h" +#include "input_common/drivers/virtual_amiibo.h"  #include "input_common/main.h"  #include "ui_main.h"  #include "util/overlay_dialog.h" @@ -899,8 +899,8 @@ void GMainWindow::InitializeWidgets() {      }      // TODO (flTobi): Add the widget when multiplayer is fully implemented -    // statusBar()->addPermanentWidget(multiplayer_state->GetStatusText(), 0); -    // statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon(), 0); +    statusBar()->addPermanentWidget(multiplayer_state->GetStatusText(), 0); +    statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon(), 0);      tas_label = new QLabel();      tas_label->setObjectName(QStringLiteral("TASlabel")); @@ -1299,6 +1299,7 @@ void GMainWindow::ConnectMenuEvents() {              &MultiplayerState::OnDirectConnectToRoom);      connect(ui->action_Show_Room, &QAction::triggered, multiplayer_state,              &MultiplayerState::OnOpenNetworkRoom); +    connect(multiplayer_state, &MultiplayerState::SaveConfig, this, &GMainWindow::OnSaveConfig);      // Tools      connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this, @@ -1339,6 +1340,8 @@ void GMainWindow::UpdateMenuState() {      } else {          ui->action_Pause->setText(tr("&Pause"));      } + +    multiplayer_state->UpdateNotificationStatus();  }  void GMainWindow::OnDisplayTitleBars(bool show) { @@ -2770,6 +2773,11 @@ void GMainWindow::OnExit() {      OnStopGame();  } +void GMainWindow::OnSaveConfig() { +    system->ApplySettings(); +    config->Save(); +} +  void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) {      OverlayDialog dialog(render_window, *system, error_code, error_text, QString{}, tr("OK"),                           Qt::AlignLeft | Qt::AlignVCenter); @@ -3211,21 +3219,16 @@ void GMainWindow::OnLoadAmiibo() {          return;      } -    Service::SM::ServiceManager& sm = system->ServiceManager(); -    auto nfc = sm.GetService<Service::NFP::Module::Interface>("nfp:user"); -    if (nfc == nullptr) { -        QMessageBox::warning(this, tr("Error"), tr("The current game is not looking for amiibos")); -        return; -    } -    const auto nfc_state = nfc->GetCurrentState(); -    if (nfc_state == Service::NFP::DeviceState::TagFound || -        nfc_state == Service::NFP::DeviceState::TagMounted) { -        nfc->CloseAmiibo(); +    auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); + +    // Remove amiibo if one is connected +    if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::AmiiboIsOpen) { +        virtual_amiibo->CloseAmiibo();          QMessageBox::warning(this, tr("Amiibo"), tr("The current amiibo has been removed"));          return;      } -    if (nfc_state != Service::NFP::DeviceState::SearchingForTag) { +    if (virtual_amiibo->GetCurrentState() != InputCommon::VirtualAmiibo::State::WaitingForAmiibo) {          QMessageBox::warning(this, tr("Error"), tr("The current game is not looking for amiibos"));          return;      } @@ -3244,24 +3247,30 @@ void GMainWindow::OnLoadAmiibo() {  }  void GMainWindow::LoadAmiibo(const QString& filename) { -    Service::SM::ServiceManager& sm = system->ServiceManager(); -    auto nfc = sm.GetService<Service::NFP::Module::Interface>("nfp:user"); -    if (nfc == nullptr) { -        return; -    } - +    auto* virtual_amiibo = input_subsystem->GetVirtualAmiibo(); +    const QString title = tr("Error loading Amiibo data");      // Remove amiibo if one is connected -    const auto nfc_state = nfc->GetCurrentState(); -    if (nfc_state == Service::NFP::DeviceState::TagFound || -        nfc_state == Service::NFP::DeviceState::TagMounted) { -        nfc->CloseAmiibo(); +    if (virtual_amiibo->GetCurrentState() == InputCommon::VirtualAmiibo::State::AmiiboIsOpen) { +        virtual_amiibo->CloseAmiibo();          QMessageBox::warning(this, tr("Amiibo"), tr("The current amiibo has been removed"));          return;      } -    if (!nfc->LoadAmiibo(filename.toStdString())) { -        QMessageBox::warning(this, tr("Error loading Amiibo data"), -                             tr("Unable to load Amiibo data.")); +    switch (virtual_amiibo->LoadAmiibo(filename.toStdString())) { +    case InputCommon::VirtualAmiibo::Info::NotAnAmiibo: +        QMessageBox::warning(this, title, tr("The selected file is not a valid amiibo")); +        break; +    case InputCommon::VirtualAmiibo::Info::UnableToLoad: +        QMessageBox::warning(this, title, tr("The selected file is already on use")); +        break; +    case InputCommon::VirtualAmiibo::Info::WrongDeviceState: +        QMessageBox::warning(this, title, tr("The current game is not looking for amiibos")); +        break; +    case InputCommon::VirtualAmiibo::Info::Unknown: +        QMessageBox::warning(this, title, tr("An unkown error occured")); +        break; +    default: +        break;      }  } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 716aef063..f7aa8e417 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -169,6 +169,7 @@ public slots:      void OnLoadComplete();      void OnExecuteProgram(std::size_t program_index);      void OnExit(); +    void OnSaveConfig();      void ControllerSelectorReconfigureControllers(          const Core::Frontend::ControllerParameters& parameters);      void SoftwareKeyboardInitialize( diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index cdf31b417..74d49dbd4 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui @@ -120,6 +120,20 @@      <addaction name="menu_Reset_Window_Size"/>      <addaction name="menu_View_Debugging"/>     </widget> +   <widget class="QMenu" name="menu_Multiplayer"> +    <property name="enabled"> +     <bool>true</bool> +    </property> +    <property name="title"> +     <string>&Multiplayer</string> +    </property> +    <addaction name="action_View_Lobby"/> +    <addaction name="action_Start_Room"/> +    <addaction name="action_Connect_To_Room"/> +    <addaction name="separator"/> +    <addaction name="action_Show_Room"/> +    <addaction name="action_Leave_Room"/> +   </widget>     <widget class="QMenu" name="menu_Tools">      <property name="title">       <string>&Tools</string> @@ -251,7 +265,7 @@      <bool>true</bool>     </property>     <property name="text"> -    <string>Browse Public Game Lobby</string> +    <string>&Browse Public Game Lobby</string>     </property>    </action>    <action name="action_Start_Room"> @@ -259,7 +273,7 @@      <bool>true</bool>     </property>     <property name="text"> -    <string>Create Room</string> +    <string>&Create Room</string>     </property>    </action>    <action name="action_Leave_Room"> @@ -267,12 +281,12 @@      <bool>false</bool>     </property>     <property name="text"> -    <string>Leave Room</string> +    <string>&Leave Room</string>     </property>    </action>    <action name="action_Connect_To_Room">     <property name="text"> -    <string>Direct Connect to Room</string> +    <string>&Direct Connect to Room</string>     </property>    </action>    <action name="action_Show_Room"> @@ -280,7 +294,7 @@      <bool>false</bool>     </property>     <property name="text"> -    <string>Show Current Room</string> +    <string>&Show Current Room</string>     </property>    </action>    <action name="action_Fullscreen"> diff --git a/src/yuzu/multiplayer/chat_room.cpp b/src/yuzu/multiplayer/chat_room.cpp index 9e672f82e..dec9696c1 100644 --- a/src/yuzu/multiplayer/chat_room.cpp +++ b/src/yuzu/multiplayer/chat_room.cpp @@ -61,7 +61,10 @@ public:      /// Format the message using the players color      QString GetPlayerChatMessage(u16 player) const { -        auto color = player_color[player % 16]; +        const bool is_dark_theme = QIcon::themeName().contains(QStringLiteral("dark")) || +                                   QIcon::themeName().contains(QStringLiteral("midnight")); +        auto color = +            is_dark_theme ? player_color_dark[player % 16] : player_color_default[player % 16];          QString name;          if (username.isEmpty() || username == nickname) {              name = nickname; @@ -84,9 +87,12 @@ public:      }  private: -    static constexpr std::array<const char*, 16> player_color = { +    static constexpr std::array<const char*, 16> player_color_default = {          {"#0000FF", "#FF0000", "#8A2BE2", "#FF69B4", "#1E90FF", "#008000", "#00FF7F", "#B22222", -         "#DAA520", "#FF4500", "#2E8B57", "#5F9EA0", "#D2691E", "#9ACD32", "#FF7F50", "FFFF00"}}; +         "#DAA520", "#FF4500", "#2E8B57", "#5F9EA0", "#D2691E", "#9ACD32", "#FF7F50", "#FFFF00"}}; +    static constexpr std::array<const char*, 16> player_color_dark = { +        {"#559AD1", "#4EC9A8", "#D69D85", "#C6C923", "#B975B5", "#D81F1F", "#7EAE39", "#4F8733", +         "#F7CD8A", "#6FCACF", "#CE4897", "#8A2BE2", "#D2691E", "#9ACD32", "#FF7F50", "#152ccd"}};      static constexpr char ping_color[] = "#FFFF00";      QString timestamp; diff --git a/src/yuzu/multiplayer/client_room.cpp b/src/yuzu/multiplayer/client_room.cpp index b34a8d004..caf34a414 100644 --- a/src/yuzu/multiplayer/client_room.cpp +++ b/src/yuzu/multiplayer/client_room.cpp @@ -97,8 +97,9 @@ void ClientRoomWindow::UpdateView() {              auto memberlist = member->GetMemberInformation();              ui->chat->SetPlayerList(memberlist);              const auto information = member->GetRoomInformation(); -            setWindowTitle(QString(tr("%1 (%2/%3 members) - connected")) +            setWindowTitle(QString(tr("%1 - %2 (%3/%4 members) - connected"))                                 .arg(QString::fromStdString(information.name)) +                               .arg(QString::fromStdString(information.preferred_game.name))                                 .arg(memberlist.size())                                 .arg(information.member_slots));              ui->description->setText(QString::fromStdString(information.description)); diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp index 017063074..10bf0a4fb 100644 --- a/src/yuzu/multiplayer/direct_connect.cpp +++ b/src/yuzu/multiplayer/direct_connect.cpp @@ -106,6 +106,8 @@ void DirectConnectWindow::Connect() {          UISettings::values.multiplayer_port = UISettings::values.multiplayer_port.GetDefault();      } +    emit SaveConfig(); +      // attempt to connect in a different thread      QFuture<void> f = QtConcurrent::run([&] {          if (auto room_member = room_network.GetRoomMember().lock()) { diff --git a/src/yuzu/multiplayer/direct_connect.h b/src/yuzu/multiplayer/direct_connect.h index e39dd1e0d..b8f66cfb2 100644 --- a/src/yuzu/multiplayer/direct_connect.h +++ b/src/yuzu/multiplayer/direct_connect.h @@ -31,6 +31,7 @@ signals:       * connections that it might have.       */      void Closed(); +    void SaveConfig();  private slots:      void OnConnection(); diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp index 0c6adfd04..a8faa5b24 100644 --- a/src/yuzu/multiplayer/host_room.cpp +++ b/src/yuzu/multiplayer/host_room.cpp @@ -232,6 +232,7 @@ void HostRoomWindow::Host() {          }          UISettings::values.multiplayer_room_description = ui->room_description->toPlainText();          ui->host->setEnabled(true); +        emit SaveConfig();          close();      }  } diff --git a/src/yuzu/multiplayer/host_room.h b/src/yuzu/multiplayer/host_room.h index 034cb2eef..ae816e2e0 100644 --- a/src/yuzu/multiplayer/host_room.h +++ b/src/yuzu/multiplayer/host_room.h @@ -46,6 +46,9 @@ public:      void UpdateGameList(QStandardItemModel* list);      void RetranslateUi(); +signals: +    void SaveConfig(); +  private:      void Host();      std::unique_ptr<Network::VerifyUser::Backend> CreateVerifyBackend(bool use_validation) const; diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp index 107d40547..08c275696 100644 --- a/src/yuzu/multiplayer/lobby.cpp +++ b/src/yuzu/multiplayer/lobby.cpp @@ -7,6 +7,7 @@  #include "common/logging/log.h"  #include "common/settings.h"  #include "core/core.h" +#include "core/hle/service/acc/profile_manager.h"  #include "core/internal_network/network_interface.h"  #include "network/network.h"  #include "ui_lobby.h" @@ -26,9 +27,9 @@  Lobby::Lobby(QWidget* parent, QStandardItemModel* list,               std::shared_ptr<Core::AnnounceMultiplayerSession> session, Core::System& system_)      : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), -      ui(std::make_unique<Ui::Lobby>()), -      announce_multiplayer_session(session), system{system_}, room_network{ -                                                                  system.GetRoomNetwork()} { +      ui(std::make_unique<Ui::Lobby>()), announce_multiplayer_session(session), +      profile_manager(std::make_unique<Service::Account::ProfileManager>()), system{system_}, +      room_network{system.GetRoomNetwork()} {      ui->setupUi(this);      // setup the watcher for background connections @@ -60,9 +61,17 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,      ui->nickname->setValidator(validation.GetNickname());      ui->nickname->setText(UISettings::values.multiplayer_nickname.GetValue()); -    if (ui->nickname->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) { -        // Use yuzu Web Service user name as nickname by default -        ui->nickname->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue())); + +    // Try find the best nickname by default +    if (ui->nickname->text().isEmpty() || ui->nickname->text() == QStringLiteral("yuzu")) { +        if (!Settings::values.yuzu_username.GetValue().empty()) { +            ui->nickname->setText( +                QString::fromStdString(Settings::values.yuzu_username.GetValue())); +        } else if (!GetProfileUsername().empty()) { +            ui->nickname->setText(QString::fromStdString(GetProfileUsername())); +        } else { +            ui->nickname->setText(QStringLiteral("yuzu")); +        }      }      // UI Buttons @@ -76,12 +85,6 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,      // Actions      connect(&room_list_watcher, &QFutureWatcher<AnnounceMultiplayerRoom::RoomList>::finished, this,              &Lobby::OnRefreshLobby); - -    // manually start a refresh when the window is opening -    // TODO(jroweboy): if this refresh is slow for people with bad internet, then don't do it as -    // part of the constructor, but offload the refresh until after the window shown. perhaps emit a -    // refreshroomlist signal from places that open the lobby -    RefreshLobby();  }  Lobby::~Lobby() = default; @@ -96,6 +99,7 @@ void Lobby::UpdateGameList(QStandardItemModel* list) {      }      if (proxy)          proxy->UpdateGameList(game_list); +    ui->room_list->sortByColumn(Column::GAME_NAME, Qt::AscendingOrder);  }  void Lobby::RetranslateUi() { @@ -117,6 +121,11 @@ void Lobby::OnExpandRoom(const QModelIndex& index) {  void Lobby::OnJoinRoom(const QModelIndex& source) {      if (!Network::GetSelectedNetworkInterface()) { +        LOG_INFO(WebService, "Automatically selected network interface for room network."); +        Network::SelectFirstNetworkInterface(); +    } + +    if (!Network::GetSelectedNetworkInterface()) {          NetworkMessage::ErrorManager::ShowError(              NetworkMessage::ErrorManager::NO_INTERFACE_SELECTED);          return; @@ -197,16 +206,16 @@ void Lobby::OnJoinRoom(const QModelIndex& source) {          proxy->data(connection_index, LobbyItemHost::HostIPRole).toString();      UISettings::values.multiplayer_port =          proxy->data(connection_index, LobbyItemHost::HostPortRole).toInt(); +    emit SaveConfig();  }  void Lobby::ResetModel() {      model->clear();      model->insertColumns(0, Column::TOTAL); -    model->setHeaderData(Column::EXPAND, Qt::Horizontal, QString(), Qt::DisplayRole); +    model->setHeaderData(Column::MEMBER, Qt::Horizontal, tr("Players"), Qt::DisplayRole);      model->setHeaderData(Column::ROOM_NAME, Qt::Horizontal, tr("Room Name"), Qt::DisplayRole);      model->setHeaderData(Column::GAME_NAME, Qt::Horizontal, tr("Preferred Game"), Qt::DisplayRole);      model->setHeaderData(Column::HOST, Qt::Horizontal, tr("Host"), Qt::DisplayRole); -    model->setHeaderData(Column::MEMBER, Qt::Horizontal, tr("Players"), Qt::DisplayRole);  }  void Lobby::RefreshLobby() { @@ -229,6 +238,7 @@ void Lobby::OnRefreshLobby() {          for (int r = 0; r < game_list->rowCount(); ++r) {              auto index = game_list->index(r, 0);              auto game_id = game_list->data(index, GameListItemPath::ProgramIdRole).toULongLong(); +              if (game_id != 0 && room.information.preferred_game.id == game_id) {                  smdh_icon = game_list->data(index, Qt::DecorationRole).value<QPixmap>();              } @@ -243,17 +253,16 @@ void Lobby::OnRefreshLobby() {              members.append(var);          } -        auto first_item = new LobbyItem(); +        auto first_item = new LobbyItemGame( +            room.information.preferred_game.id, +            QString::fromStdString(room.information.preferred_game.name), smdh_icon);          auto row = QList<QStandardItem*>({              first_item,              new LobbyItemName(room.has_password, QString::fromStdString(room.information.name)), -            new LobbyItemGame(room.information.preferred_game.id, -                              QString::fromStdString(room.information.preferred_game.name), -                              smdh_icon), +            new LobbyItemMemberList(members, room.information.member_slots),              new LobbyItemHost(QString::fromStdString(room.information.host_username),                                QString::fromStdString(room.ip), room.information.port,                                QString::fromStdString(room.verify_uid)), -            new LobbyItemMemberList(members, room.information.member_slots),          });          model->appendRow(row);          // To make the rows expandable, add the member data as a child of the first column of the @@ -283,6 +292,26 @@ void Lobby::OnRefreshLobby() {              ui->room_list->setFirstColumnSpanned(j, proxy->index(i, 0), true);          }      } + +    ui->room_list->sortByColumn(Column::GAME_NAME, Qt::AscendingOrder); +} + +std::string Lobby::GetProfileUsername() { +    const auto& current_user = profile_manager->GetUser(Settings::values.current_user.GetValue()); +    Service::Account::ProfileBase profile{}; + +    if (!current_user.has_value()) { +        return ""; +    } + +    if (!profile_manager->GetProfileBase(*current_user, profile)) { +        return ""; +    } + +    const auto text = Common::StringFromFixedZeroTerminatedBuffer( +        reinterpret_cast<const char*>(profile.username.data()), profile.username.size()); + +    return text;  }  LobbyFilterProxyModel::LobbyFilterProxyModel(QWidget* parent, QStandardItemModel* list) diff --git a/src/yuzu/multiplayer/lobby.h b/src/yuzu/multiplayer/lobby.h index 2696aec21..300dad13e 100644 --- a/src/yuzu/multiplayer/lobby.h +++ b/src/yuzu/multiplayer/lobby.h @@ -24,6 +24,10 @@ namespace Core {  class System;  } +namespace Service::Account { +class ProfileManager; +} +  /**   * Listing of all public games pulled from services. The lobby should be simple enough for users to   * find the game they want to play, and join it. @@ -75,8 +79,11 @@ private slots:  signals:      void StateChanged(const Network::RoomMember::State&); +    void SaveConfig();  private: +    std::string GetProfileUsername(); +      /**       * Removes all entries in the Lobby before refreshing.       */ @@ -96,6 +103,7 @@ private:      QFutureWatcher<AnnounceMultiplayerRoom::RoomList> room_list_watcher;      std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session; +    std::unique_ptr<Service::Account::ProfileManager> profile_manager;      QFutureWatcher<void>* watcher;      Validation validation;      Core::System& system; diff --git a/src/yuzu/multiplayer/lobby_p.h b/src/yuzu/multiplayer/lobby_p.h index 8071cede4..068c95aca 100644 --- a/src/yuzu/multiplayer/lobby_p.h +++ b/src/yuzu/multiplayer/lobby_p.h @@ -11,11 +11,10 @@  namespace Column {  enum List { -    EXPAND, -    ROOM_NAME,      GAME_NAME, -    HOST, +    ROOM_NAME,      MEMBER, +    HOST,      TOTAL,  };  } @@ -91,6 +90,8 @@ public:          setData(game_name, GameNameRole);          if (!smdh_icon.isNull()) {              setData(smdh_icon, GameIconRole); +        } else { +            setData(QIcon::fromTheme(QStringLiteral("chip")).pixmap(32), GameIconRole);          }      } @@ -98,7 +99,12 @@ public:          if (role == Qt::DecorationRole) {              auto val = data(GameIconRole);              if (val.isValid()) { -                val = val.value<QPixmap>().scaled(16, 16, Qt::KeepAspectRatio); +                val = val.value<QPixmap>().scaled(32, 32, Qt::KeepAspectRatio, +                                                  Qt::TransformationMode::SmoothTransformation); +            } else { +                auto blank_image = QPixmap(32, 32); +                blank_image.fill(Qt::black); +                val = blank_image;              }              return val;          } else if (role != Qt::DisplayRole) { @@ -191,8 +197,8 @@ public:              return LobbyItem::data(role);          }          auto members = data(MemberListRole).toList(); -        return QStringLiteral("%1 / %2").arg(QString::number(members.size()), -                                             data(MaxPlayerRole).toString()); +        return QStringLiteral("%1 / %2 ") +            .arg(QString::number(members.size()), data(MaxPlayerRole).toString());      }      bool operator<(const QStandardItem& other) const override { diff --git a/src/yuzu/multiplayer/message.cpp b/src/yuzu/multiplayer/message.cpp index 758b5b731..6d8f18274 100644 --- a/src/yuzu/multiplayer/message.cpp +++ b/src/yuzu/multiplayer/message.cpp @@ -49,9 +49,9 @@ const ConnectionError ErrorManager::PERMISSION_DENIED(      QT_TR_NOOP("You do not have enough permission to perform this action."));  const ConnectionError ErrorManager::NO_SUCH_USER(QT_TR_NOOP(      "The user you are trying to kick/ban could not be found.\nThey may have left the room.")); -const ConnectionError ErrorManager::NO_INTERFACE_SELECTED( -    QT_TR_NOOP("No network interface is selected.\nPlease go to Configure -> System -> Network and " -               "make a selection.")); +const ConnectionError ErrorManager::NO_INTERFACE_SELECTED(QT_TR_NOOP( +    "No valid network interface is selected.\nPlease go to Configure -> System -> Network and " +    "make a selection."));  static bool WarnMessage(const std::string& title, const std::string& text) {      return QMessageBox::Ok == QMessageBox::warning(nullptr, QObject::tr(title.c_str()), diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp index 66e098296..ae2738ad4 100644 --- a/src/yuzu/multiplayer/state.cpp +++ b/src/yuzu/multiplayer/state.cpp @@ -44,9 +44,6 @@ MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_lis      status_text = new ClickableLabel(this);      status_icon = new ClickableLabel(this); -    status_text->setToolTip(tr("Current connection status")); -    status_text->setText(tr("Not Connected. Click here to find a room!")); -    status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("disconnected")).pixmap(16));      connect(status_text, &ClickableLabel::clicked, this, &MultiplayerState::OnOpenNetworkRoom);      connect(status_icon, &ClickableLabel::clicked, this, &MultiplayerState::OnOpenNetworkRoom); @@ -57,6 +54,8 @@ MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_lis                      HideNotification();                  }              }); + +    retranslateUi();  }  MultiplayerState::~MultiplayerState() = default; @@ -90,14 +89,7 @@ void MultiplayerState::Close() {  void MultiplayerState::retranslateUi() {      status_text->setToolTip(tr("Current connection status")); -    if (current_state == Network::RoomMember::State::Uninitialized) { -        status_text->setText(tr("Not Connected. Click here to find a room!")); -    } else if (current_state == Network::RoomMember::State::Joined || -               current_state == Network::RoomMember::State::Moderator) { -        status_text->setText(tr("Connected")); -    } else { -        status_text->setText(tr("Not Connected")); -    } +    UpdateNotificationStatus();      if (lobby) {          lobby->RetranslateUi(); @@ -113,21 +105,55 @@ void MultiplayerState::retranslateUi() {      }  } +void MultiplayerState::SetNotificationStatus(NotificationStatus status) { +    notification_status = status; +    UpdateNotificationStatus(); +} + +void MultiplayerState::UpdateNotificationStatus() { +    switch (notification_status) { +    case NotificationStatus::Unitialized: +        status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("disconnected")).pixmap(16)); +        status_text->setText(tr("Not Connected. Click here to find a room!")); +        leave_room->setEnabled(false); +        show_room->setEnabled(false); +        break; +    case NotificationStatus::Disconnected: +        status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("disconnected")).pixmap(16)); +        status_text->setText(tr("Not Connected")); +        leave_room->setEnabled(false); +        show_room->setEnabled(false); +        break; +    case NotificationStatus::Connected: +        status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected")).pixmap(16)); +        status_text->setText(tr("Connected")); +        leave_room->setEnabled(true); +        show_room->setEnabled(true); +        break; +    case NotificationStatus::Notification: +        status_icon->setPixmap( +            QIcon::fromTheme(QStringLiteral("connected_notification")).pixmap(16)); +        status_text->setText(tr("New Messages Received")); +        leave_room->setEnabled(true); +        show_room->setEnabled(true); +        break; +    } + +    // Clean up status bar if game is running +    if (system.IsPoweredOn()) { +        status_text->clear(); +    } +} +  void MultiplayerState::OnNetworkStateChanged(const Network::RoomMember::State& state) {      LOG_DEBUG(Frontend, "Network State: {}", Network::GetStateStr(state));      if (state == Network::RoomMember::State::Joined ||          state == Network::RoomMember::State::Moderator) {          OnOpenNetworkRoom(); -        status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected")).pixmap(16)); -        status_text->setText(tr("Connected")); -        leave_room->setEnabled(true); -        show_room->setEnabled(true); +        SetNotificationStatus(NotificationStatus::Connected);      } else { -        status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("disconnected")).pixmap(16)); -        status_text->setText(tr("Not Connected")); -        leave_room->setEnabled(false); -        show_room->setEnabled(false); +        SetNotificationStatus(NotificationStatus::Disconnected);      }      current_state = state; @@ -185,6 +211,10 @@ void MultiplayerState::OnAnnounceFailed(const WebService::WebResult& result) {                           QMessageBox::Ok);  } +void MultiplayerState::OnSaveConfig() { +    emit SaveConfig(); +} +  void MultiplayerState::UpdateThemedIcons() {      if (show_notification) {          status_icon->setPixmap( @@ -209,13 +239,16 @@ static void BringWidgetToFront(QWidget* widget) {  void MultiplayerState::OnViewLobby() {      if (lobby == nullptr) {          lobby = new Lobby(this, game_list_model, announce_multiplayer_session, system); +        connect(lobby, &Lobby::SaveConfig, this, &MultiplayerState::OnSaveConfig);      } +    lobby->RefreshLobby();      BringWidgetToFront(lobby);  }  void MultiplayerState::OnCreateRoom() {      if (host_room == nullptr) {          host_room = new HostRoomWindow(this, game_list_model, announce_multiplayer_session, system); +        connect(host_room, &HostRoomWindow::SaveConfig, this, &MultiplayerState::OnSaveConfig);      }      BringWidgetToFront(host_room);  } @@ -249,14 +282,13 @@ void MultiplayerState::ShowNotification() {          return; // Do not show notification if the chat window currently has focus      show_notification = true;      QApplication::alert(nullptr); -    status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected_notification")).pixmap(16)); -    status_text->setText(tr("New Messages Received")); +    QApplication::beep(); +    SetNotificationStatus(NotificationStatus::Notification);  }  void MultiplayerState::HideNotification() {      show_notification = false; -    status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected")).pixmap(16)); -    status_text->setText(tr("Connected")); +    SetNotificationStatus(NotificationStatus::Connected);  }  void MultiplayerState::OnOpenNetworkRoom() { @@ -279,6 +311,8 @@ void MultiplayerState::OnOpenNetworkRoom() {  void MultiplayerState::OnDirectConnectToRoom() {      if (direct_connect == nullptr) {          direct_connect = new DirectConnectWindow(system, this); +        connect(direct_connect, &DirectConnectWindow::SaveConfig, this, +                &MultiplayerState::OnSaveConfig);      }      BringWidgetToFront(direct_connect);  } diff --git a/src/yuzu/multiplayer/state.h b/src/yuzu/multiplayer/state.h index c92496413..5d681c5c6 100644 --- a/src/yuzu/multiplayer/state.h +++ b/src/yuzu/multiplayer/state.h @@ -22,6 +22,13 @@ class MultiplayerState : public QWidget {      Q_OBJECT;  public: +    enum class NotificationStatus { +        Unitialized, +        Disconnected, +        Connected, +        Notification, +    }; +      explicit MultiplayerState(QWidget* parent, QStandardItemModel* game_list, QAction* leave_room,                                QAction* show_room, Core::System& system_);      ~MultiplayerState(); @@ -31,6 +38,10 @@ public:       */      void Close(); +    void SetNotificationStatus(NotificationStatus state); + +    void UpdateNotificationStatus(); +      ClickableLabel* GetStatusText() const {          return status_text;      } @@ -64,6 +75,7 @@ public slots:      void OnOpenNetworkRoom();      void OnDirectConnectToRoom();      void OnAnnounceFailed(const WebService::WebResult&); +    void OnSaveConfig();      void UpdateThemedIcons();      void ShowNotification();      void HideNotification(); @@ -72,6 +84,7 @@ signals:      void NetworkStateChanged(const Network::RoomMember::State&);      void NetworkError(const Network::RoomMember::Error&);      void AnnounceFailed(const WebService::WebResult&); +    void SaveConfig();  private:      Lobby* lobby = nullptr; @@ -85,6 +98,7 @@ private:      QAction* show_room;      std::shared_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session;      Network::RoomMember::State current_state = Network::RoomMember::State::Uninitialized; +    NotificationStatus notification_status = NotificationStatus::Unitialized;      bool has_mod_perms = false;      Network::RoomMember::CallbackHandle<Network::RoomMember::State> state_callback_handle;      Network::RoomMember::CallbackHandle<Network::RoomMember::Error> error_callback_handle; diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index e12d414d9..753797efc 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -102,7 +102,7 @@ struct Values {      Settings::Setting<uint32_t> callout_flags{0, "calloutFlags"};      // multiplayer settings -    Settings::Setting<QString> multiplayer_nickname{QStringLiteral("yuzu"), "nickname"}; +    Settings::Setting<QString> multiplayer_nickname{{}, "nickname"};      Settings::Setting<QString> multiplayer_ip{{}, "ip"};      Settings::SwitchableSetting<uint, true> multiplayer_port{24872, 0, UINT16_MAX, "port"};      Settings::Setting<QString> multiplayer_room_nickname{{}, "room_nickname"}; | 
