Просмотр исходного кода

Merge pull request #3665 from bunnei/device-save

FS: Improve emulation of device saves
bunnei 6 лет назад
Родитель
Сommit
65010607b7

+ 4 - 0
src/core/file_sys/control_metadata.cpp

@@ -95,6 +95,10 @@ u32 NACP::GetSupportedLanguages() const {
     return raw.supported_languages;
 }
 
+u64 NACP::GetDeviceSaveDataSize() const {
+    return raw.device_save_data_size;
+}
+
 std::vector<u8> NACP::GetRawBytes() const {
     std::vector<u8> out(sizeof(RawNACP));
     std::memcpy(out.data(), &raw, sizeof(RawNACP));

+ 1 - 0
src/core/file_sys/control_metadata.h

@@ -113,6 +113,7 @@ public:
     u32 GetSupportedLanguages() const;
     std::vector<u8> GetRawBytes() const;
     bool GetUserAccountSwitchLock() const;
+    u64 GetDeviceSaveDataSize() const;
 
 private:
     RawNACP raw{};

+ 6 - 3
src/core/file_sys/savedata_factory.cpp

@@ -57,7 +57,8 @@ void PrintSaveDataDescriptorWarnings(SaveDataDescriptor meta) {
 bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataDescriptor& desc) {
     return desc.type == SaveDataType::CacheStorage || desc.type == SaveDataType::TemporaryStorage ||
            (space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User
-            desc.type == SaveDataType::SaveData && desc.title_id == 0 && desc.save_id == 0);
+            (desc.type == SaveDataType::SaveData || desc.type == SaveDataType::DeviceSaveData) &&
+            desc.title_id == 0 && desc.save_id == 0);
 }
 
 } // Anonymous namespace
@@ -139,8 +140,10 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
                                          u128 user_id, u64 save_id) {
     // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
     // be interpreted as the title id of the current process.
-    if (type == SaveDataType::SaveData && title_id == 0) {
-        title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
+    if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) {
+        if (title_id == 0) {
+            title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
+        }
     }
 
     std::string out = GetSaveDataSpaceIdPath(space);

+ 37 - 1
src/core/hle/service/filesystem/fsp_srv.cpp

@@ -767,7 +767,7 @@ FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter)
         {1014, nullptr, "OutputMultiProgramTagAccessLog"},
         {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
         {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
-        {1200, nullptr, "OpenMultiCommitManager"},
+        {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"},
         {1300, nullptr, "OpenBisWiper"},
     };
     // clang-format on
@@ -988,4 +988,40 @@ void FSP_SRV::GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx) {
     rb.Push(access_log_program_index);
 }
 
+class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
+public:
+    explicit IMultiCommitManager() : ServiceFramework("IMultiCommitManager") {
+        static const FunctionInfo functions[] = {
+            {1, &IMultiCommitManager::Add, "Add"},
+            {2, &IMultiCommitManager::Commit, "Commit"},
+        };
+        RegisterHandlers(functions);
+    }
+
+private:
+    FileSys::VirtualFile backend;
+
+    void Add(Kernel::HLERequestContext& ctx) {
+        LOG_WARNING(Service_FS, "(STUBBED) called");
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(RESULT_SUCCESS);
+    }
+
+    void Commit(Kernel::HLERequestContext& ctx) {
+        LOG_WARNING(Service_FS, "(STUBBED) called");
+
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(RESULT_SUCCESS);
+    }
+};
+
+void FSP_SRV::OpenMultiCommitManager(Kernel::HLERequestContext& ctx) {
+    LOG_DEBUG(Service_FS, "called");
+
+    IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+    rb.Push(RESULT_SUCCESS);
+    rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>());
+}
+
 } // namespace Service::FileSystem

+ 1 - 0
src/core/hle/service/filesystem/fsp_srv.h

@@ -50,6 +50,7 @@ private:
     void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
     void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx);
     void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx);
+    void OpenMultiCommitManager(Kernel::HLERequestContext& ctx);
 
     FileSystemController& fsc;
 

+ 4 - 4
src/yuzu/game_list.cpp

@@ -488,11 +488,11 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, std::string pat
     auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
     navigate_to_gamedb_entry->setVisible(it != compatibility_list.end() && program_id != 0);
 
-    connect(open_save_location, &QAction::triggered, [this, program_id]() {
-        emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData);
+    connect(open_save_location, &QAction::triggered, [this, program_id, path]() {
+        emit OpenFolderRequested(GameListOpenTarget::SaveData, path);
     });
-    connect(open_lfs_location, &QAction::triggered, [this, program_id]() {
-        emit OpenFolderRequested(program_id, GameListOpenTarget::ModData);
+    connect(open_lfs_location, &QAction::triggered, [this, program_id, path]() {
+        emit OpenFolderRequested(GameListOpenTarget::ModData, path);
     });
     connect(open_transferable_shader_cache, &QAction::triggered,
             [this, program_id]() { emit OpenTransferableShaderCacheRequested(program_id); });

+ 1 - 1
src/yuzu/game_list.h

@@ -73,7 +73,7 @@ public:
 signals:
     void GameChosen(QString game_path);
     void ShouldCancelWorker();
-    void OpenFolderRequested(u64 program_id, GameListOpenTarget target);
+    void OpenFolderRequested(GameListOpenTarget target, const std::string& game_path);
     void OpenTransferableShaderCacheRequested(u64 program_id);
     void DumpRomFSRequested(u64 program_id, const std::string& game_path);
     void CopyTIDRequested(u64 program_id);

+ 43 - 21
src/yuzu/main.cpp

@@ -1155,39 +1155,61 @@ void GMainWindow::OnGameListLoadFile(QString game_path) {
     BootGame(game_path);
 }
 
-void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target) {
+void GMainWindow::OnGameListOpenFolder(GameListOpenTarget target, const std::string& game_path) {
     std::string path;
     QString open_target;
+
+    const auto v_file = Core::GetGameFileFromPath(vfs, game_path);
+    const auto loader = Loader::GetLoader(v_file);
+    FileSys::NACP control{};
+    u64 program_id{};
+
+    loader->ReadControlData(control);
+    loader->ReadProgramId(program_id);
+
+    const bool has_user_save{control.GetDefaultNormalSaveSize() > 0};
+    const bool has_device_save{control.GetDeviceSaveDataSize() > 0};
+
+    ASSERT_MSG(has_user_save != has_device_save, "Game uses both user and device savedata?");
+
     switch (target) {
     case GameListOpenTarget::SaveData: {
         open_target = tr("Save Data");
         const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir);
         ASSERT(program_id != 0);
 
-        const auto select_profile = [this] {
-            QtProfileSelectionDialog dialog(this);
-            dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
-                                  Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
-            dialog.setWindowModality(Qt::WindowModal);
+        if (has_user_save) {
+            // User save data
+            const auto select_profile = [this] {
+                QtProfileSelectionDialog dialog(this);
+                dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
+                                      Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
+                dialog.setWindowModality(Qt::WindowModal);
 
-            if (dialog.exec() == QDialog::Rejected) {
-                return -1;
-            }
+                if (dialog.exec() == QDialog::Rejected) {
+                    return -1;
+                }
 
-            return dialog.GetIndex();
-        };
+                return dialog.GetIndex();
+            };
 
-        const auto index = select_profile();
-        if (index == -1) {
-            return;
-        }
+            const auto index = select_profile();
+            if (index == -1) {
+                return;
+            }
 
-        Service::Account::ProfileManager manager;
-        const auto user_id = manager.GetUser(static_cast<std::size_t>(index));
-        ASSERT(user_id);
-        path = nand_dir + FileSys::SaveDataFactory::GetFullPath(FileSys::SaveDataSpaceId::NandUser,
-                                                                FileSys::SaveDataType::SaveData,
-                                                                program_id, user_id->uuid, 0);
+            Service::Account::ProfileManager manager;
+            const auto user_id = manager.GetUser(static_cast<std::size_t>(index));
+            ASSERT(user_id);
+            path = nand_dir + FileSys::SaveDataFactory::GetFullPath(
+                                  FileSys::SaveDataSpaceId::NandUser,
+                                  FileSys::SaveDataType::SaveData, program_id, user_id->uuid, 0);
+        } else {
+            // Device save data
+            path = nand_dir + FileSys::SaveDataFactory::GetFullPath(
+                                  FileSys::SaveDataSpaceId::NandUser,
+                                  FileSys::SaveDataType::SaveData, program_id, {}, 0);
+        }
 
         if (!FileUtil::Exists(path)) {
             FileUtil::CreateFullPath(path);

+ 1 - 1
src/yuzu/main.h

@@ -183,7 +183,7 @@ private slots:
     void OnMenuReportCompatibility();
     /// Called whenever a user selects a game in the game list widget.
     void OnGameListLoadFile(QString game_path);
-    void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target);
+    void OnGameListOpenFolder(GameListOpenTarget target, const std::string& game_path);
     void OnTransferableShaderCacheOpenFile(u64 program_id);
     void OnGameListDumpRomFS(u64 program_id, const std::string& game_path);
     void OnGameListCopyTID(u64 program_id);