diff options
35 files changed, 195 insertions, 57 deletions
| diff --git a/.ci/templates/build-msvc.yml b/.ci/templates/build-msvc.yml index 2a1bf93bc..a2ee71bd8 100644 --- a/.ci/templates/build-msvc.yml +++ b/.ci/templates/build-msvc.yml @@ -9,7 +9,7 @@ parameters:  steps:  - script: choco install vulkan-sdk    displayName: 'Install vulkan-sdk' -- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release .. && cd .. +- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 17 2022" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release .. && cd ..    displayName: 'Configure CMake'  - task: MSBuild@1    displayName: 'Build' diff --git a/.ci/yuzu-mainline-step2.yml b/.ci/yuzu-mainline-step2.yml index 0e99f43fa..b294827f4 100644 --- a/.ci/yuzu-mainline-step2.yml +++ b/.ci/yuzu-mainline-step2.yml @@ -50,7 +50,7 @@ stages:      timeoutInMinutes: 120      displayName: 'msvc'      pool: -      vmImage: windows-2019 +      vmImage: windows-2022      steps:      - template: ./templates/sync-source.yml        parameters: diff --git a/.ci/yuzu-patreon-step2.yml b/.ci/yuzu-patreon-step2.yml index 33c081c53..5d5b140fd 100644 --- a/.ci/yuzu-patreon-step2.yml +++ b/.ci/yuzu-patreon-step2.yml @@ -15,7 +15,7 @@ stages:      timeoutInMinutes: 120      displayName: 'windows-msvc'      pool: -      vmImage: windows-2019 +      vmImage: windows-2022      steps:      - template: ./templates/sync-source.yml        parameters: diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 9a973ee0c..733a52764 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -71,7 +71,7 @@ jobs:    build-msvc:      name: 'test build (windows, msvc)'      needs: format -    runs-on: windows-2019 +    runs-on: windows-2022      steps:        - name: Set up cache          uses: actions/cache@v3 diff --git a/src/common/announce_multiplayer_room.h b/src/common/announce_multiplayer_room.h index cb004e0eb..4a3100fa4 100644 --- a/src/common/announce_multiplayer_room.h +++ b/src/common/announce_multiplayer_room.h @@ -16,6 +16,7 @@ namespace AnnounceMultiplayerRoom {  struct GameInfo {      std::string name{""};      u64 id{0}; +    std::string version{""};  };  struct Member { diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4137ec9a7..806e7ff6c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -2,8 +2,6 @@  # SPDX-License-Identifier: GPL-2.0-or-later  add_library(core STATIC -    announce_multiplayer_session.cpp -    announce_multiplayer_session.h      arm/arm_interface.h      arm/arm_interface.cpp      arm/dynarmic/arm_dynarmic_32.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index ea32a4a8d..e651ce100 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -319,10 +319,19 @@ struct System::Impl {          if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {              LOG_ERROR(Core, "Failed to read title for ROM (Error {})", load_result);          } + +        std::string title_version; +        const FileSys::PatchManager pm(program_id, system.GetFileSystemController(), +                                       system.GetContentProvider()); +        const auto metadata = pm.GetControlMetadata(); +        if (metadata.first != nullptr) { +            title_version = metadata.first->GetVersionString(); +        }          if (auto room_member = room_network.GetRoomMember().lock()) {              Network::GameInfo game_info;              game_info.name = name;              game_info.id = program_id; +            game_info.version = title_version;              room_member->SendGameInfo(game_info);          } diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index def105832..bb838e285 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -534,7 +534,7 @@ public:  private:      void CheckAvailability(Kernel::HLERequestContext& ctx) { -        LOG_WARNING(Service_ACC, "(STUBBED) called"); +        LOG_DEBUG(Service_ACC, "(STUBBED) called");          IPC::ResponseBuilder rb{ctx, 3};          rb.Push(ResultSuccess);          rb.Push(false); // TODO: Check when this is supposed to return true and when not diff --git a/src/core/hle/service/ldn/ldn_types.h b/src/core/hle/service/ldn/ldn_types.h index 0c07a7397..6231e936d 100644 --- a/src/core/hle/service/ldn/ldn_types.h +++ b/src/core/hle/service/ldn/ldn_types.h @@ -113,7 +113,7 @@ enum class LinkLevel : s8 {      Bad,      Low,      Good, -    Excelent, +    Excellent,  };  struct NodeLatestUpdate { @@ -145,11 +145,19 @@ struct NetworkId {  static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size");  struct Ssid { -    u8 length; -    std::array<char, SsidLengthMax + 1> raw; +    u8 length{}; +    std::array<char, SsidLengthMax + 1> raw{}; + +    Ssid() = default; + +    explicit Ssid(std::string_view data) { +        length = static_cast<u8>(std::min(data.size(), SsidLengthMax)); +        data.copy(raw.data(), length); +        raw[length] = 0; +    }      std::string GetStringValue() const { -        return std::string(raw.data(), length); +        return std::string(raw.data());      }  };  static_assert(sizeof(Ssid) == 0x22, "Ssid is an invalid size"); diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index e08c3cb67..cc679cc81 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -933,7 +933,11 @@ BSD::BSD(Core::System& system_, const char* name)      }  } -BSD::~BSD() = default; +BSD::~BSD() { +    if (auto room_member = room_network.GetRoomMember().lock()) { +        room_member->Unbind(proxy_packet_received); +    } +}  BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} {      // clang-format off diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp index 49d067f4c..0c746bd82 100644 --- a/src/core/internal_network/socket_proxy.cpp +++ b/src/core/internal_network/socket_proxy.cpp @@ -26,6 +26,12 @@ void ProxySocket::HandleProxyPacket(const ProxyPacket& packet) {          closed) {          return;      } + +    if (!broadcast && packet.broadcast) { +        LOG_INFO(Network, "Received broadcast packet, but not configured for broadcast mode"); +        return; +    } +      std::lock_guard guard(packets_mutex);      received_packets.push(packet);  } @@ -203,7 +209,7 @@ std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, const std::vector<u8>& mess      packet.local_endpoint = local_endpoint;      packet.remote_endpoint = *addr;      packet.protocol = protocol; -    packet.broadcast = broadcast; +    packet.broadcast = broadcast && packet.remote_endpoint.ip[3] == 255;      auto& ip = local_endpoint.ip;      auto ipv4 = Network::GetHostIPv4Address(); diff --git a/src/dedicated_room/CMakeLists.txt b/src/dedicated_room/CMakeLists.txt index b674b915b..737aedbe4 100644 --- a/src/dedicated_room/CMakeLists.txt +++ b/src/dedicated_room/CMakeLists.txt @@ -10,7 +10,7 @@ add_executable(yuzu-room  create_target_directory_groups(yuzu-room) -target_link_libraries(yuzu-room PRIVATE common core network) +target_link_libraries(yuzu-room PRIVATE common network)  if (ENABLE_WEB_SERVICE)      target_compile_definitions(yuzu-room PRIVATE -DENABLE_WEB_SERVICE)      target_link_libraries(yuzu-room PRIVATE web_service) diff --git a/src/dedicated_room/yuzu_room.cpp b/src/dedicated_room/yuzu_room.cpp index 482e772fb..7b6deba41 100644 --- a/src/dedicated_room/yuzu_room.cpp +++ b/src/dedicated_room/yuzu_room.cpp @@ -27,8 +27,8 @@  #include "common/scm_rev.h"  #include "common/settings.h"  #include "common/string_util.h" -#include "core/announce_multiplayer_session.h"  #include "core/core.h" +#include "network/announce_multiplayer_session.h"  #include "network/network.h"  #include "network/room.h"  #include "network/verify_user.h" @@ -75,6 +75,12 @@ static constexpr char BanListMagic[] = "YuzuRoom-BanList-1";  static constexpr char token_delimiter{':'}; +static void PadToken(std::string& token) { +    while (token.size() % 4 != 0) { +        token.push_back('='); +    } +} +  static std::string UsernameFromDisplayToken(const std::string& display_token) {      std::size_t outlen; @@ -300,6 +306,7 @@ int main(int argc, char** argv) {          if (username.empty()) {              LOG_INFO(Network, "Hosting a public room");              Settings::values.web_api_url = web_api_url; +            PadToken(token);              Settings::values.yuzu_username = UsernameFromDisplayToken(token);              username = Settings::values.yuzu_username.GetValue();              Settings::values.yuzu_token = TokenFromDisplayToken(token); diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 312f79b68..6f8ca4b90 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -2,6 +2,8 @@  # SPDX-License-Identifier: GPL-3.0-or-later  add_library(network STATIC +    announce_multiplayer_session.cpp +    announce_multiplayer_session.h      network.cpp      network.h      packet.cpp @@ -17,3 +19,7 @@ add_library(network STATIC  create_target_directory_groups(network)  target_link_libraries(network PRIVATE common enet Boost::boost) +if (ENABLE_WEB_SERVICE) +    target_compile_definitions(network PRIVATE -DENABLE_WEB_SERVICE) +    target_link_libraries(network PRIVATE web_service) +endif() diff --git a/src/core/announce_multiplayer_session.cpp b/src/network/announce_multiplayer_session.cpp index 6737ce85a..6737ce85a 100644 --- a/src/core/announce_multiplayer_session.cpp +++ b/src/network/announce_multiplayer_session.cpp diff --git a/src/core/announce_multiplayer_session.h b/src/network/announce_multiplayer_session.h index db790f7d2..db790f7d2 100644 --- a/src/core/announce_multiplayer_session.h +++ b/src/network/announce_multiplayer_session.h diff --git a/src/network/room.cpp b/src/network/room.cpp index b06797bf1..8c63b255b 100644 --- a/src/network/room.cpp +++ b/src/network/room.cpp @@ -221,7 +221,7 @@ public:       * Extracts the game name from a received ENet packet and broadcasts it.       * @param event The ENet event that was received.       */ -    void HandleGameNamePacket(const ENetEvent* event); +    void HandleGameInfoPacket(const ENetEvent* event);      /**       * Removes the client from the members list if it was in it and announces the change @@ -234,7 +234,7 @@ public:  void Room::RoomImpl::ServerLoop() {      while (state != State::Closed) {          ENetEvent event; -        if (enet_host_service(server, &event, 50) > 0) { +        if (enet_host_service(server, &event, 5) > 0) {              switch (event.type) {              case ENET_EVENT_TYPE_RECEIVE:                  switch (event.packet->data[0]) { @@ -242,7 +242,7 @@ void Room::RoomImpl::ServerLoop() {                      HandleJoinRequest(&event);                      break;                  case IdSetGameInfo: -                    HandleGameNamePacket(&event); +                    HandleGameInfoPacket(&event);                      break;                  case IdProxyPacket:                      HandleProxyPacket(&event); @@ -778,6 +778,7 @@ void Room::RoomImpl::BroadcastRoomInformation() {              packet.Write(member.fake_ip);              packet.Write(member.game_info.name);              packet.Write(member.game_info.id); +            packet.Write(member.game_info.version);              packet.Write(member.user_data.username);              packet.Write(member.user_data.display_name);              packet.Write(member.user_data.avatar_url); @@ -817,6 +818,7 @@ void Room::RoomImpl::HandleProxyPacket(const ENetEvent* event) {      in_packet.IgnoreBytes(sizeof(u16)); // Port      in_packet.IgnoreBytes(sizeof(u8)); // Protocol +      bool broadcast;      in_packet.Read(broadcast); // Broadcast @@ -909,7 +911,7 @@ void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) {      }  } -void Room::RoomImpl::HandleGameNamePacket(const ENetEvent* event) { +void Room::RoomImpl::HandleGameInfoPacket(const ENetEvent* event) {      Packet in_packet;      in_packet.Append(event->packet->data, event->packet->dataLength); @@ -917,6 +919,7 @@ void Room::RoomImpl::HandleGameNamePacket(const ENetEvent* event) {      GameInfo game_info;      in_packet.Read(game_info.name);      in_packet.Read(game_info.id); +    in_packet.Read(game_info.version);      {          std::lock_guard lock(member_mutex); @@ -935,7 +938,8 @@ void Room::RoomImpl::HandleGameNamePacket(const ENetEvent* event) {              if (game_info.name.empty()) {                  LOG_INFO(Network, "{} is not playing", display_name);              } else { -                LOG_INFO(Network, "{} is playing {}", display_name, game_info.name); +                LOG_INFO(Network, "{} is playing {} ({})", display_name, game_info.name, +                         game_info.version);              }          }      } diff --git a/src/network/room_member.cpp b/src/network/room_member.cpp index 9f08bf611..06818af78 100644 --- a/src/network/room_member.cpp +++ b/src/network/room_member.cpp @@ -103,7 +103,7 @@ public:      /**       * Extracts a ProxyPacket from a received ENet packet. -     * @param event The  ENet event that was received. +     * @param event The ENet event that was received.       */      void HandleProxyPackets(const ENetEvent* event); @@ -159,7 +159,7 @@ void RoomMember::RoomMemberImpl::MemberLoop() {      while (IsConnected()) {          std::lock_guard lock(network_mutex);          ENetEvent event; -        if (enet_host_service(client, &event, 100) > 0) { +        if (enet_host_service(client, &event, 5) > 0) {              switch (event.type) {              case ENET_EVENT_TYPE_RECEIVE:                  switch (event.packet->data[0]) { @@ -315,6 +315,7 @@ void RoomMember::RoomMemberImpl::HandleRoomInformationPacket(const ENetEvent* ev          packet.Read(member.fake_ip);          packet.Read(member.game_info.name);          packet.Read(member.game_info.id); +        packet.Read(member.game_info.version);          packet.Read(member.username);          packet.Read(member.display_name);          packet.Read(member.avatar_url); @@ -622,6 +623,7 @@ void RoomMember::SendGameInfo(const GameInfo& game_info) {      packet.Write(static_cast<u8>(IdSetGameInfo));      packet.Write(game_info.name);      packet.Write(game_info.id); +    packet.Write(game_info.version);      room_member_impl->Send(std::move(packet));  } diff --git a/src/network/room_member.h b/src/network/room_member.h index 4252b7146..f578f7f6a 100644 --- a/src/network/room_member.h +++ b/src/network/room_member.h @@ -146,7 +146,7 @@ public:                const std::string& password = "", const std::string& token = "");      /** -     * Sends a WiFi packet to the room. +     * Sends a Proxy packet to the room.       * @param packet The WiFi packet to send.       */      void SendProxyPacket(const ProxyPacket& packet); diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index e16d127a8..04d397750 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -14,7 +14,7 @@  #include "yuzu/uisettings.h"  ConfigureDebug::ConfigureDebug(const Core::System& system_, QWidget* parent) -    : QWidget(parent), ui{std::make_unique<Ui::ConfigureDebug>()}, system{system_} { +    : QScrollArea(parent), ui{std::make_unique<Ui::ConfigureDebug>()}, system{system_} {      ui->setupUi(this);      SetConfiguration(); diff --git a/src/yuzu/configuration/configure_debug.h b/src/yuzu/configuration/configure_debug.h index 64d68ab8f..42d30f170 100644 --- a/src/yuzu/configuration/configure_debug.h +++ b/src/yuzu/configuration/configure_debug.h @@ -4,7 +4,7 @@  #pragma once  #include <memory> -#include <QWidget> +#include <QScrollArea>  namespace Core {  class System; @@ -14,7 +14,7 @@ namespace Ui {  class ConfigureDebug;  } -class ConfigureDebug : public QWidget { +class ConfigureDebug : public QScrollArea {      Q_OBJECT  public: diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index 4c16274fc..47b8b80f1 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui @@ -1,7 +1,11 @@  <?xml version="1.0" encoding="UTF-8"?>  <ui version="4.0">   <class>ConfigureDebug</class> - <widget class="QWidget" name="ConfigureDebug"> + <widget class="QScrollArea" name="ConfigureDebug"> +  <property name="widgetResizable"> +   <bool>true</bool> +  </property> + <widget class="QWidget">    <layout class="QVBoxLayout" name="verticalLayout_1">      <item>        <layout class="QVBoxLayout" name="verticalLayout_2"> @@ -322,6 +326,7 @@     </item>    </layout>   </widget> + </widget>   <tabstops>    <tabstop>log_filter_edit</tabstop>    <tabstop>toggle_console</tabstop> diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e103df977..a85adc072 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -860,7 +860,7 @@ void GMainWindow::InitializeWidgets() {      });      multiplayer_state = new MultiplayerState(this, game_list->GetModel(), ui->action_Leave_Room, -                                             ui->action_Show_Room, system->GetRoomNetwork()); +                                             ui->action_Show_Room, *system);      multiplayer_state->setVisible(false);      // Create status bar diff --git a/src/yuzu/multiplayer/chat_room.cpp b/src/yuzu/multiplayer/chat_room.cpp index 1968a3c75..9e672f82e 100644 --- a/src/yuzu/multiplayer/chat_room.cpp +++ b/src/yuzu/multiplayer/chat_room.cpp @@ -16,7 +16,7 @@  #include <QUrl>  #include <QtConcurrent/QtConcurrentRun>  #include "common/logging/log.h" -#include "core/announce_multiplayer_session.h" +#include "network/announce_multiplayer_session.h"  #include "ui_chat_room.h"  #include "yuzu/game_list_p.h"  #include "yuzu/multiplayer/chat_room.h" @@ -122,19 +122,22 @@ public:      static const int UsernameRole = Qt::UserRole + 2;      static const int AvatarUrlRole = Qt::UserRole + 3;      static const int GameNameRole = Qt::UserRole + 4; +    static const int GameVersionRole = Qt::UserRole + 5;      PlayerListItem() = default;      explicit PlayerListItem(const std::string& nickname, const std::string& username, -                            const std::string& avatar_url, const std::string& game_name) { +                            const std::string& avatar_url, +                            const AnnounceMultiplayerRoom::GameInfo& game_info) {          setEditable(false);          setData(QString::fromStdString(nickname), NicknameRole);          setData(QString::fromStdString(username), UsernameRole);          setData(QString::fromStdString(avatar_url), AvatarUrlRole); -        if (game_name.empty()) { +        if (game_info.name.empty()) {              setData(QObject::tr("Not playing a game"), GameNameRole);          } else { -            setData(QString::fromStdString(game_name), GameNameRole); +            setData(QString::fromStdString(game_info.name), GameNameRole);          } +        setData(QString::fromStdString(game_info.version), GameVersionRole);      }      QVariant data(int role) const override { @@ -149,7 +152,13 @@ public:          } else {              name = QStringLiteral("%1 (%2)").arg(nickname, username);          } -        return QStringLiteral("%1\n      %2").arg(name, data(GameNameRole).toString()); +        const QString version = data(GameVersionRole).toString(); +        QString version_string; +        if (!version.isEmpty()) { +            version_string = QStringLiteral("(%1)").arg(version); +        } +        return QStringLiteral("%1\n      %2 %3") +            .arg(name, data(GameNameRole).toString(), version_string);      }  }; @@ -167,6 +176,10 @@ ChatRoom::ChatRoom(QWidget* parent) : QWidget(parent), ui(std::make_unique<Ui::C      ui->chat_history->document()->setMaximumBlockCount(max_chat_lines); +    auto font = ui->chat_history->font(); +    font.setPointSizeF(10); +    ui->chat_history->setFont(font); +      // register the network structs to use in slots and signals      qRegisterMetaType<Network::ChatEntry>();      qRegisterMetaType<Network::StatusMessageEntry>(); @@ -366,7 +379,7 @@ void ChatRoom::SetPlayerList(const Network::RoomMember::MemberList& member_list)          if (member.nickname.empty())              continue;          QStandardItem* name_item = new PlayerListItem(member.nickname, member.username, -                                                      member.avatar_url, member.game_info.name); +                                                      member.avatar_url, member.game_info);  #ifdef ENABLE_WEB_SERVICE          if (!icon_cache.count(member.avatar_url) && !member.avatar_url.empty()) { diff --git a/src/yuzu/multiplayer/client_room.cpp b/src/yuzu/multiplayer/client_room.cpp index 86baafbf0..b34a8d004 100644 --- a/src/yuzu/multiplayer/client_room.cpp +++ b/src/yuzu/multiplayer/client_room.cpp @@ -10,7 +10,7 @@  #include <QTime>  #include <QtConcurrent/QtConcurrentRun>  #include "common/logging/log.h" -#include "core/announce_multiplayer_session.h" +#include "network/announce_multiplayer_session.h"  #include "ui_client_room.h"  #include "yuzu/game_list_p.h"  #include "yuzu/multiplayer/client_room.h" diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp index 4c0ea0a6b..017063074 100644 --- a/src/yuzu/multiplayer/direct_connect.cpp +++ b/src/yuzu/multiplayer/direct_connect.cpp @@ -8,6 +8,8 @@  #include <QString>  #include <QtConcurrent/QtConcurrentRun>  #include "common/settings.h" +#include "core/core.h" +#include "core/internal_network/network_interface.h"  #include "network/network.h"  #include "ui_direct_connect.h"  #include "yuzu/main.h" @@ -20,9 +22,10 @@  enum class ConnectionType : u8 { TraversalServer, IP }; -DirectConnectWindow::DirectConnectWindow(Network::RoomNetwork& room_network_, QWidget* parent) +DirectConnectWindow::DirectConnectWindow(Core::System& system_, QWidget* parent)      : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), -      ui(std::make_unique<Ui::DirectConnect>()), room_network{room_network_} { +      ui(std::make_unique<Ui::DirectConnect>()), system{system_}, room_network{ +                                                                      system.GetRoomNetwork()} {      ui->setupUi(this); @@ -53,10 +56,20 @@ void DirectConnectWindow::RetranslateUi() {  }  void DirectConnectWindow::Connect() { +    if (!Network::GetSelectedNetworkInterface()) { +        NetworkMessage::ErrorManager::ShowError( +            NetworkMessage::ErrorManager::NO_INTERFACE_SELECTED); +        return; +    }      if (!ui->nickname->hasAcceptableInput()) {          NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::USERNAME_NOT_VALID);          return;      } +    if (system.IsPoweredOn()) { +        if (!NetworkMessage::WarnGameRunning()) { +            return; +        } +    }      if (const auto member = room_network.GetRoomMember().lock()) {          // Prevent the user from trying to join a room while they are already joining.          if (member->GetState() == Network::RoomMember::State::Joining) { diff --git a/src/yuzu/multiplayer/direct_connect.h b/src/yuzu/multiplayer/direct_connect.h index 4e1043053..e39dd1e0d 100644 --- a/src/yuzu/multiplayer/direct_connect.h +++ b/src/yuzu/multiplayer/direct_connect.h @@ -12,11 +12,15 @@ namespace Ui {  class DirectConnect;  } +namespace Core { +class System; +} +  class DirectConnectWindow : public QDialog {      Q_OBJECT  public: -    explicit DirectConnectWindow(Network::RoomNetwork& room_network_, QWidget* parent = nullptr); +    explicit DirectConnectWindow(Core::System& system_, QWidget* parent = nullptr);      ~DirectConnectWindow();      void RetranslateUi(); @@ -39,5 +43,6 @@ private:      QFutureWatcher<void>* watcher;      std::unique_ptr<Ui::DirectConnect> ui;      Validation validation; +    Core::System& system;      Network::RoomNetwork& room_network;  }; diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp index d70a9a3c8..0c6adfd04 100644 --- a/src/yuzu/multiplayer/host_room.cpp +++ b/src/yuzu/multiplayer/host_room.cpp @@ -12,7 +12,9 @@  #include <QtConcurrent/QtConcurrentRun>  #include "common/logging/log.h"  #include "common/settings.h" -#include "core/announce_multiplayer_session.h" +#include "core/core.h" +#include "core/internal_network/network_interface.h" +#include "network/announce_multiplayer_session.h"  #include "ui_host_room.h"  #include "yuzu/game_list_p.h"  #include "yuzu/main.h" @@ -27,10 +29,11 @@  HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list,                                 std::shared_ptr<Core::AnnounceMultiplayerSession> session, -                               Network::RoomNetwork& room_network_) +                               Core::System& system_)      : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),        ui(std::make_unique<Ui::HostRoom>()), -      announce_multiplayer_session(session), room_network{room_network_} { +      announce_multiplayer_session(session), system{system_}, room_network{ +                                                                  system.GetRoomNetwork()} {      ui->setupUi(this);      // set up validation for all of the fields @@ -105,6 +108,11 @@ std::unique_ptr<Network::VerifyUser::Backend> HostRoomWindow::CreateVerifyBacken  }  void HostRoomWindow::Host() { +    if (!Network::GetSelectedNetworkInterface()) { +        NetworkMessage::ErrorManager::ShowError( +            NetworkMessage::ErrorManager::NO_INTERFACE_SELECTED); +        return; +    }      if (!ui->username->hasAcceptableInput()) {          NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::USERNAME_NOT_VALID);          return; @@ -121,6 +129,11 @@ void HostRoomWindow::Host() {          NetworkMessage::ErrorManager::ShowError(NetworkMessage::ErrorManager::GAME_NOT_SELECTED);          return;      } +    if (system.IsPoweredOn()) { +        if (!NetworkMessage::WarnGameRunning()) { +            return; +        } +    }      if (auto member = room_network.GetRoomMember().lock()) {          if (member->GetState() == Network::RoomMember::State::Joining) {              return; diff --git a/src/yuzu/multiplayer/host_room.h b/src/yuzu/multiplayer/host_room.h index a968042d0..034cb2eef 100644 --- a/src/yuzu/multiplayer/host_room.h +++ b/src/yuzu/multiplayer/host_room.h @@ -17,8 +17,9 @@ class HostRoom;  }  namespace Core { +class System;  class AnnounceMultiplayerSession; -} +} // namespace Core  class ConnectionError;  class ComboBoxProxyModel; @@ -35,7 +36,7 @@ class HostRoomWindow : public QDialog {  public:      explicit HostRoomWindow(QWidget* parent, QStandardItemModel* list,                              std::shared_ptr<Core::AnnounceMultiplayerSession> session, -                            Network::RoomNetwork& room_network_); +                            Core::System& system_);      ~HostRoomWindow();      /** @@ -54,6 +55,7 @@ private:      QStandardItemModel* game_list;      ComboBoxProxyModel* proxy;      Validation validation; +    Core::System& system;      Network::RoomNetwork& room_network;  }; diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp index 1cc518279..107d40547 100644 --- a/src/yuzu/multiplayer/lobby.cpp +++ b/src/yuzu/multiplayer/lobby.cpp @@ -6,6 +6,8 @@  #include <QtConcurrent/QtConcurrentRun>  #include "common/logging/log.h"  #include "common/settings.h" +#include "core/core.h" +#include "core/internal_network/network_interface.h"  #include "network/network.h"  #include "ui_lobby.h"  #include "yuzu/game_list_p.h" @@ -22,11 +24,11 @@  #endif  Lobby::Lobby(QWidget* parent, QStandardItemModel* list, -             std::shared_ptr<Core::AnnounceMultiplayerSession> session, -             Network::RoomNetwork& room_network_) +             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), room_network{room_network_} { +      announce_multiplayer_session(session), system{system_}, room_network{ +                                                                  system.GetRoomNetwork()} {      ui->setupUi(this);      // setup the watcher for background connections @@ -114,6 +116,18 @@ void Lobby::OnExpandRoom(const QModelIndex& index) {  }  void Lobby::OnJoinRoom(const QModelIndex& source) { +    if (!Network::GetSelectedNetworkInterface()) { +        NetworkMessage::ErrorManager::ShowError( +            NetworkMessage::ErrorManager::NO_INTERFACE_SELECTED); +        return; +    } + +    if (system.IsPoweredOn()) { +        if (!NetworkMessage::WarnGameRunning()) { +            return; +        } +    } +      if (const auto member = room_network.GetRoomMember().lock()) {          // Prevent the user from trying to join a room while they are already joining.          if (member->GetState() == Network::RoomMember::State::Joining) { diff --git a/src/yuzu/multiplayer/lobby.h b/src/yuzu/multiplayer/lobby.h index 82744ca94..2696aec21 100644 --- a/src/yuzu/multiplayer/lobby.h +++ b/src/yuzu/multiplayer/lobby.h @@ -9,7 +9,7 @@  #include <QSortFilterProxyModel>  #include <QStandardItemModel>  #include "common/announce_multiplayer_room.h" -#include "core/announce_multiplayer_session.h" +#include "network/announce_multiplayer_session.h"  #include "network/network.h"  #include "yuzu/multiplayer/validation.h" @@ -20,6 +20,10 @@ class Lobby;  class LobbyModel;  class LobbyFilterProxyModel; +namespace Core { +class System; +} +  /**   * 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. @@ -30,7 +34,7 @@ class Lobby : public QDialog {  public:      explicit Lobby(QWidget* parent, QStandardItemModel* list,                     std::shared_ptr<Core::AnnounceMultiplayerSession> session, -                   Network::RoomNetwork& room_network_); +                   Core::System& system_);      ~Lobby() override;      /** @@ -94,6 +98,7 @@ private:      std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session;      QFutureWatcher<void>* watcher;      Validation validation; +    Core::System& system;      Network::RoomNetwork& room_network;  }; diff --git a/src/yuzu/multiplayer/message.cpp b/src/yuzu/multiplayer/message.cpp index 94d7a38b8..758b5b731 100644 --- a/src/yuzu/multiplayer/message.cpp +++ b/src/yuzu/multiplayer/message.cpp @@ -49,6 +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."));  static bool WarnMessage(const std::string& title, const std::string& text) {      return QMessageBox::Ok == QMessageBox::warning(nullptr, QObject::tr(title.c_str()), @@ -60,6 +63,13 @@ void ErrorManager::ShowError(const ConnectionError& e) {      QMessageBox::critical(nullptr, tr("Error"), tr(e.GetString().c_str()));  } +bool WarnGameRunning() { +    return WarnMessage( +        QT_TR_NOOP("Game already running"), +        QT_TR_NOOP("Joining a room when the game is already running is discouraged " +                   "and can cause the room feature not to work correctly.\nProceed anyway?")); +} +  bool WarnCloseRoom() {      return WarnMessage(          QT_TR_NOOP("Leave Room"), diff --git a/src/yuzu/multiplayer/message.h b/src/yuzu/multiplayer/message.h index 812495c72..f038b9a1f 100644 --- a/src/yuzu/multiplayer/message.h +++ b/src/yuzu/multiplayer/message.h @@ -43,11 +43,20 @@ public:      static const ConnectionError IP_COLLISION;      static const ConnectionError PERMISSION_DENIED;      static const ConnectionError NO_SUCH_USER; +    static const ConnectionError NO_INTERFACE_SELECTED;      /**       *  Shows a standard QMessageBox with a error message       */      static void ShowError(const ConnectionError& e);  }; + +/** + * Show a standard QMessageBox with a warning message about joining a room when + * the game is already running + * return true if the user wants to close the network connection + */ +bool WarnGameRunning(); +  /**   * Show a standard QMessageBox with a warning message about leaving the room   * return true if the user wants to close the network connection diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp index dba76b22b..66e098296 100644 --- a/src/yuzu/multiplayer/state.cpp +++ b/src/yuzu/multiplayer/state.cpp @@ -8,6 +8,7 @@  #include <QStandardItemModel>  #include "common/announce_multiplayer_room.h"  #include "common/logging/log.h" +#include "core/core.h"  #include "yuzu/game_list.h"  #include "yuzu/multiplayer/client_room.h"  #include "yuzu/multiplayer/direct_connect.h" @@ -19,10 +20,9 @@  #include "yuzu/util/clickable_label.h"  MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_list_model_, -                                   QAction* leave_room_, QAction* show_room_, -                                   Network::RoomNetwork& room_network_) +                                   QAction* leave_room_, QAction* show_room_, Core::System& system_)      : QWidget(parent), game_list_model(game_list_model_), leave_room(leave_room_), -      show_room(show_room_), room_network{room_network_} { +      show_room(show_room_), system{system_}, room_network{system.GetRoomNetwork()} {      if (auto member = room_network.GetRoomMember().lock()) {          // register the network structs to use in slots and signals          state_callback_handle = member->BindOnStateChanged( @@ -208,15 +208,14 @@ static void BringWidgetToFront(QWidget* widget) {  void MultiplayerState::OnViewLobby() {      if (lobby == nullptr) { -        lobby = new Lobby(this, game_list_model, announce_multiplayer_session, room_network); +        lobby = new Lobby(this, game_list_model, announce_multiplayer_session, system);      }      BringWidgetToFront(lobby);  }  void MultiplayerState::OnCreateRoom() {      if (host_room == nullptr) { -        host_room = -            new HostRoomWindow(this, game_list_model, announce_multiplayer_session, room_network); +        host_room = new HostRoomWindow(this, game_list_model, announce_multiplayer_session, system);      }      BringWidgetToFront(host_room);  } @@ -279,7 +278,7 @@ void MultiplayerState::OnOpenNetworkRoom() {  void MultiplayerState::OnDirectConnectToRoom() {      if (direct_connect == nullptr) { -        direct_connect = new DirectConnectWindow(room_network, this); +        direct_connect = new DirectConnectWindow(system, this);      }      BringWidgetToFront(direct_connect);  } diff --git a/src/yuzu/multiplayer/state.h b/src/yuzu/multiplayer/state.h index 9c60712d5..c92496413 100644 --- a/src/yuzu/multiplayer/state.h +++ b/src/yuzu/multiplayer/state.h @@ -4,7 +4,7 @@  #pragma once  #include <QWidget> -#include "core/announce_multiplayer_session.h" +#include "network/announce_multiplayer_session.h"  #include "network/network.h"  class QStandardItemModel; @@ -14,12 +14,16 @@ class ClientRoomWindow;  class DirectConnectWindow;  class ClickableLabel; +namespace Core { +class System; +} +  class MultiplayerState : public QWidget {      Q_OBJECT;  public:      explicit MultiplayerState(QWidget* parent, QStandardItemModel* game_list, QAction* leave_room, -                              QAction* show_room, Network::RoomNetwork& room_network_); +                              QAction* show_room, Core::System& system_);      ~MultiplayerState();      /** @@ -86,6 +90,7 @@ private:      Network::RoomMember::CallbackHandle<Network::RoomMember::Error> error_callback_handle;      bool show_notification = false; +    Core::System& system;      Network::RoomNetwork& room_network;  }; | 
