diff options
Diffstat (limited to 'src/yuzu')
| -rw-r--r-- | src/yuzu/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/yuzu/data_dialog.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/game_list.cpp | 5 | ||||
| -rw-r--r-- | src/yuzu/game_list.h | 1 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 61 | ||||
| -rw-r--r-- | src/yuzu/main.h | 3 | ||||
| -rw-r--r-- | src/yuzu/migration_worker.cpp | 9 | ||||
| -rw-r--r-- | src/yuzu/migration_worker.h | 6 | ||||
| -rw-r--r-- | src/yuzu/ryujinx_dialog.cpp | 40 | ||||
| -rw-r--r-- | src/yuzu/ryujinx_dialog.h | 32 | ||||
| -rw-r--r-- | src/yuzu/ryujinx_dialog.ui | 81 |
11 files changed, 233 insertions, 8 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 4b1e87b6ed..d6082dd00b 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -236,6 +236,7 @@ add_executable(yuzu data_dialog.h data_dialog.cpp data_dialog.ui data_widget.ui + ryujinx_dialog.h ryujinx_dialog.cpp ryujinx_dialog.ui ) set_target_properties(yuzu PROPERTIES OUTPUT_NAME "eden") diff --git a/src/yuzu/data_dialog.cpp b/src/yuzu/data_dialog.cpp index dc3e06f89f..008e810eae 100644 --- a/src/yuzu/data_dialog.cpp +++ b/src/yuzu/data_dialog.cpp @@ -95,7 +95,7 @@ void DataWidget::open() user_id = selectProfile(); } QDesktopServices::openUrl(QUrl::fromLocalFile( - QString::fromStdString(FrontendCommon::DataManager::GetDataDir(m_dir, user_id)))); + QString::fromStdString(FrontendCommon::DataManager::GetDataDirString(m_dir, user_id)))); } void DataWidget::upload() diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 875e794181..ae8e4688b4 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -542,6 +542,7 @@ void GameList::PopupContextMenu(const QPoint& menu_location) { } void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::string& path) { + // TODO(crueter): Refactor this and make it less bad QAction* favorite = context_menu.addAction(tr("Favorite")); context_menu.addSeparator(); QAction* start_game = context_menu.addAction(tr("Start Game")); @@ -581,6 +582,7 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri #endif context_menu.addSeparator(); QAction* properties = context_menu.addAction(tr("Configure Game")); + QAction* ryujinx = context_menu.addAction(tr("Link to Ryujinx")); favorite->setVisible(program_id != 0); favorite->setCheckable(true); @@ -662,6 +664,9 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri #endif connect(properties, &QAction::triggered, [this, path]() { emit OpenPerGameGeneralRequested(path); }); + + connect(ryujinx, &QAction::triggered, [this, program_id]() { emit LinkToRyujinxRequested(program_id); + }); }; void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) { diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index b4cdf61f0d..0b3ac7fcde 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -113,6 +113,7 @@ signals: void NavigateToGamedbEntryRequested(u64 program_id, const CompatibilityList& compatibility_list); void OpenPerGameGeneralRequested(const std::string& file); + void LinkToRyujinxRequested(const u64 &program_id); void OpenDirectory(const QString& directory); void AddDirectory(); void ShowList(bool show); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 8fb5575b41..849ffa84de 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -6,10 +6,12 @@ #include "core/tools/renderdoc.h" #include "frontend_common/firmware_manager.h" #include "qt_common/qt_common.h" +#include "qt_common/abstract/frontend.h" #include "qt_common/util/content.h" #include "qt_common/util/game.h" #include "qt_common/util/meta.h" #include "qt_common/util/path.h" +#include "qt_common/util/fs.h" #include <clocale> #include <cmath> #include <memory> @@ -108,6 +110,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "common/detached_tasks.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "common/fs/ryujinx_compat.h" #include "common/literals.h" #include "common/logging/backend.h" #include "common/logging/log.h" @@ -160,6 +163,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/debugger/wait_tree.h" #include "yuzu/data_dialog.h" #include "yuzu/deps_dialog.h" +#include "yuzu/ryujinx_dialog.h" #include "qt_common/discord/discord.h" #include "yuzu/game_list.h" #include "yuzu/game_list_p.h" @@ -1597,6 +1601,8 @@ void GMainWindow::ConnectWidgetEvents() { connect(game_list, &GameList::OpenPerGameGeneralRequested, this, &GMainWindow::OnGameListOpenPerGameProperties); + connect(game_list, &GameList::LinkToRyujinxRequested, this, + &GMainWindow::OnLinkToRyujinx); connect(this, &GMainWindow::UpdateInstallProgress, this, &GMainWindow::IncrementInstallProgress); @@ -2875,6 +2881,61 @@ void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) { OpenPerGameConfiguration(title_id, file); } +std::string GMainWindow::GetProfileID() +{ + const auto select_profile = [this] { + const Core::Frontend::ProfileSelectParameters parameters{ + .mode = Service::AM::Frontend::UiMode::UserSelector, + .invalid_uid_list = {}, + .display_options = {}, + .purpose = Service::AM::Frontend::UserSelectionPurpose::General, + }; + QtProfileSelectionDialog dialog(*QtCommon::system, this, parameters); + dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint + | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); + dialog.setWindowModality(Qt::WindowModal); + + if (dialog.exec() == QDialog::Rejected) { + return -1; + } + + return dialog.GetIndex(); + }; + + const auto index = select_profile(); + if (index == -1) { + return ""; + } + + const auto uuid = QtCommon::system->GetProfileManager().GetUser(static_cast<std::size_t>(index)); + ASSERT(uuid); + + const auto user_id = uuid->AsU128(); + + return fmt::format("{:016X}{:016X}", user_id[1], user_id[0]); +} + +void GMainWindow::OnLinkToRyujinx(const u64& program_id) +{ + u64 save_id = QtCommon::FS::GetRyujinxSaveID(program_id); + if (save_id == (u64) -1) + return; + + const std::string user_id = GetProfileID(); + + auto paths = QtCommon::FS::GetEmuPaths(program_id, save_id, user_id); + if (!paths) + return; + + auto eden_dir = paths.value().first; + auto ryu_dir = paths.value().second; + + if (!QtCommon::FS::CheckUnlink(eden_dir, ryu_dir)) { + RyujinxDialog dialog(eden_dir, ryu_dir, this); + dialog.exec(); + } +} + void GMainWindow::OnMenuLoadFile() { if (is_load_file_select_active) { return; diff --git a/src/yuzu/main.h b/src/yuzu/main.h index ce04d6d152..ae5d74215a 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -358,6 +358,7 @@ private slots: void OnGameListAddDirectory(); void OnGameListShowList(bool show); void OnGameListOpenPerGameProperties(const std::string& file); + void OnLinkToRyujinx(const u64& program_id); void OnMenuLoadFile(); void OnMenuLoadFolder(); void IncrementInstallProgress(); @@ -470,6 +471,8 @@ private: QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No), QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); + std::string GetProfileID(); + std::unique_ptr<Ui::MainWindow> ui; std::unique_ptr<DiscordRPC::DiscordInterface> discord_rpc; diff --git a/src/yuzu/migration_worker.cpp b/src/yuzu/migration_worker.cpp index b39bd22584..50b6d1ebd4 100644 --- a/src/yuzu/migration_worker.cpp +++ b/src/yuzu/migration_worker.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "migration_worker.h" +#include "common/fs/symlink.h" #include <QMap> #include <boost/algorithm/string/predicate.hpp> @@ -37,7 +38,7 @@ void MigrationWorker::process() try { fs::remove_all(eden_dir); } catch (fs::filesystem_error &_) { - // ignore because linux does stupid crap sometimes. + // ignore because linux does stupid crap sometimes } switch (strategy) { @@ -46,7 +47,7 @@ void MigrationWorker::process() // Windows 11 has random permission nonsense to deal with. try { - fs::create_directory_symlink(legacy_user_dir, eden_dir); + Common::FS::CreateSymlink(legacy_user_dir, eden_dir); } catch (const fs::filesystem_error &e) { emit error(tr("Linking the old directory failed. You may need to re-run with " "administrative privileges on Windows.\nOS gave error: %1") @@ -58,11 +59,11 @@ void MigrationWorker::process() // are already children of the root directory #ifndef WIN32 if (fs::is_directory(legacy_config_dir)) { - fs::create_directory_symlink(legacy_config_dir, config_dir); + Common::FS::CreateSymlink(legacy_config_dir, config_dir); } if (fs::is_directory(legacy_cache_dir)) { - fs::create_directory_symlink(legacy_cache_dir, cache_dir); + Common::FS::CreateSymlink(legacy_cache_dir, cache_dir); } #endif diff --git a/src/yuzu/migration_worker.h b/src/yuzu/migration_worker.h index 5f9e400db0..2ff6e8c481 100644 --- a/src/yuzu/migration_worker.h +++ b/src/yuzu/migration_worker.h @@ -12,9 +12,9 @@ using namespace Common::FS; typedef struct Emulator { const char *m_name; - LegacyPath e_user_dir; - LegacyPath e_config_dir; - LegacyPath e_cache_dir; + EmuPath e_user_dir; + EmuPath e_config_dir; + EmuPath e_cache_dir; const std::string get_user_dir() const { return Common::FS::GetLegacyPath(e_user_dir).string(); diff --git a/src/yuzu/ryujinx_dialog.cpp b/src/yuzu/ryujinx_dialog.cpp new file mode 100644 index 0000000000..db10c06d93 --- /dev/null +++ b/src/yuzu/ryujinx_dialog.cpp @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "ryujinx_dialog.h" +#include "qt_common/util/fs.h" +#include "ui_ryujinx_dialog.h" +#include <filesystem> + +namespace fs = std::filesystem; + +RyujinxDialog::RyujinxDialog(std::filesystem::path eden_path, + std::filesystem::path ryu_path, + QWidget *parent) + : QDialog(parent) + , ui(new Ui::RyujinxDialog) + , m_eden(eden_path.make_preferred()) + , m_ryu(ryu_path.make_preferred()) +{ + ui->setupUi(this); + + connect(ui->eden, &QPushButton::clicked, this, &RyujinxDialog::fromEden); + connect(ui->ryujinx, &QPushButton::clicked, this, &RyujinxDialog::fromRyujinx); +} + +RyujinxDialog::~RyujinxDialog() +{ + delete ui; +} + +void RyujinxDialog::fromEden() +{ + accept(); + QtCommon::FS::LinkRyujinx(m_eden, m_ryu); +} + +void RyujinxDialog::fromRyujinx() +{ + accept(); + QtCommon::FS::LinkRyujinx(m_ryu, m_eden); +} diff --git a/src/yuzu/ryujinx_dialog.h b/src/yuzu/ryujinx_dialog.h new file mode 100644 index 0000000000..63cebe483c --- /dev/null +++ b/src/yuzu/ryujinx_dialog.h @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RYUJINX_DIALOG_H +#define RYUJINX_DIALOG_H + +#include <QDialog> +#include <filesystem> + +namespace Ui { +class RyujinxDialog; +} + +class RyujinxDialog : public QDialog +{ + Q_OBJECT + +public: + explicit RyujinxDialog(std::filesystem::path eden_path, std::filesystem::path ryu_path, QWidget *parent = nullptr); + ~RyujinxDialog(); + +private slots: + void fromEden(); + void fromRyujinx(); + +private: + Ui::RyujinxDialog *ui; + std::filesystem::path m_eden; + std::filesystem::path m_ryu; +}; + +#endif // RYUJINX_DIALOG_H diff --git a/src/yuzu/ryujinx_dialog.ui b/src/yuzu/ryujinx_dialog.ui new file mode 100644 index 0000000000..c4fb5ae51f --- /dev/null +++ b/src/yuzu/ryujinx_dialog.ui @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>RyujinxDialog</class> + <widget class="QDialog" name="RyujinxDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>404</width> + <height>170</height> + </rect> + </property> + <property name="windowTitle"> + <string>Ryujinx Link</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Linking save data to Ryujinx lets both Ryujinx and Eden reference the same save files for your games. + +By selecting "From Eden", previous save data stored in Ryujinx will be deleted, and vice versa for "From Ryujinx".</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="eden"> + <property name="text"> + <string>From Eden</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="ryujinx"> + <property name="text"> + <string>From Ryujinx</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cancel"> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>cancel</sender> + <signal>clicked()</signal> + <receiver>RyujinxDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>331</x> + <y>147</y> + </hint> + <hint type="destinationlabel"> + <x>201</x> + <y>84</y> + </hint> + </hints> + </connection> + </connections> +</ui> |
