diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/file_sys/control_metadata.cpp | 4 | ||||
| -rw-r--r-- | src/core/file_sys/control_metadata.h | 1 | ||||
| -rw-r--r-- | src/core/file_sys/savedata_factory.cpp | 9 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/fsp_srv.cpp | 38 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/fsp_srv.h | 1 | ||||
| -rw-r--r-- | src/yuzu/game_list.cpp | 8 | ||||
| -rw-r--r-- | src/yuzu/game_list.h | 2 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 64 | ||||
| -rw-r--r-- | src/yuzu/main.h | 2 |
9 files changed, 98 insertions, 31 deletions
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index f155a1341..63cd2eead 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp | |||
| @@ -95,6 +95,10 @@ u32 NACP::GetSupportedLanguages() const { | |||
| 95 | return raw.supported_languages; | 95 | return raw.supported_languages; |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | u64 NACP::GetDeviceSaveDataSize() const { | ||
| 99 | return raw.device_save_data_size; | ||
| 100 | } | ||
| 101 | |||
| 98 | std::vector<u8> NACP::GetRawBytes() const { | 102 | std::vector<u8> NACP::GetRawBytes() const { |
| 99 | std::vector<u8> out(sizeof(RawNACP)); | 103 | std::vector<u8> out(sizeof(RawNACP)); |
| 100 | std::memcpy(out.data(), &raw, sizeof(RawNACP)); | 104 | std::memcpy(out.data(), &raw, sizeof(RawNACP)); |
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index 2d8c251ac..e37b2fadf 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h | |||
| @@ -113,6 +113,7 @@ public: | |||
| 113 | u32 GetSupportedLanguages() const; | 113 | u32 GetSupportedLanguages() const; |
| 114 | std::vector<u8> GetRawBytes() const; | 114 | std::vector<u8> GetRawBytes() const; |
| 115 | bool GetUserAccountSwitchLock() const; | 115 | bool GetUserAccountSwitchLock() const; |
| 116 | u64 GetDeviceSaveDataSize() const; | ||
| 116 | 117 | ||
| 117 | private: | 118 | private: |
| 118 | RawNACP raw{}; | 119 | RawNACP raw{}; |
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index f3def93ab..adfd2c1a4 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp | |||
| @@ -57,7 +57,8 @@ void PrintSaveDataDescriptorWarnings(SaveDataDescriptor meta) { | |||
| 57 | bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataDescriptor& desc) { | 57 | bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataDescriptor& desc) { |
| 58 | return desc.type == SaveDataType::CacheStorage || desc.type == SaveDataType::TemporaryStorage || | 58 | return desc.type == SaveDataType::CacheStorage || desc.type == SaveDataType::TemporaryStorage || |
| 59 | (space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User | 59 | (space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User |
| 60 | desc.type == SaveDataType::SaveData && desc.title_id == 0 && desc.save_id == 0); | 60 | (desc.type == SaveDataType::SaveData || desc.type == SaveDataType::DeviceSaveData) && |
| 61 | desc.title_id == 0 && desc.save_id == 0); | ||
| 61 | } | 62 | } |
| 62 | 63 | ||
| 63 | } // Anonymous namespace | 64 | } // Anonymous namespace |
| @@ -139,8 +140,10 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ | |||
| 139 | u128 user_id, u64 save_id) { | 140 | u128 user_id, u64 save_id) { |
| 140 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should | 141 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should |
| 141 | // be interpreted as the title id of the current process. | 142 | // be interpreted as the title id of the current process. |
| 142 | if (type == SaveDataType::SaveData && title_id == 0) { | 143 | if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { |
| 143 | title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); | 144 | if (title_id == 0) { |
| 145 | title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); | ||
| 146 | } | ||
| 144 | } | 147 | } |
| 145 | 148 | ||
| 146 | std::string out = GetSaveDataSpaceIdPath(space); | 149 | std::string out = GetSaveDataSpaceIdPath(space); |
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index f6503fe2f..20c331b77 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -767,7 +767,7 @@ FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter) | |||
| 767 | {1014, nullptr, "OutputMultiProgramTagAccessLog"}, | 767 | {1014, nullptr, "OutputMultiProgramTagAccessLog"}, |
| 768 | {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, | 768 | {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, |
| 769 | {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, | 769 | {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, |
| 770 | {1200, nullptr, "OpenMultiCommitManager"}, | 770 | {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"}, |
| 771 | {1300, nullptr, "OpenBisWiper"}, | 771 | {1300, nullptr, "OpenBisWiper"}, |
| 772 | }; | 772 | }; |
| 773 | // clang-format on | 773 | // clang-format on |
| @@ -988,4 +988,40 @@ void FSP_SRV::GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx) { | |||
| 988 | rb.Push(access_log_program_index); | 988 | rb.Push(access_log_program_index); |
| 989 | } | 989 | } |
| 990 | 990 | ||
| 991 | class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> { | ||
| 992 | public: | ||
| 993 | explicit IMultiCommitManager() : ServiceFramework("IMultiCommitManager") { | ||
| 994 | static const FunctionInfo functions[] = { | ||
| 995 | {1, &IMultiCommitManager::Add, "Add"}, | ||
| 996 | {2, &IMultiCommitManager::Commit, "Commit"}, | ||
| 997 | }; | ||
| 998 | RegisterHandlers(functions); | ||
| 999 | } | ||
| 1000 | |||
| 1001 | private: | ||
| 1002 | FileSys::VirtualFile backend; | ||
| 1003 | |||
| 1004 | void Add(Kernel::HLERequestContext& ctx) { | ||
| 1005 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 1006 | |||
| 1007 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1008 | rb.Push(RESULT_SUCCESS); | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | void Commit(Kernel::HLERequestContext& ctx) { | ||
| 1012 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 1013 | |||
| 1014 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1015 | rb.Push(RESULT_SUCCESS); | ||
| 1016 | } | ||
| 1017 | }; | ||
| 1018 | |||
| 1019 | void FSP_SRV::OpenMultiCommitManager(Kernel::HLERequestContext& ctx) { | ||
| 1020 | LOG_DEBUG(Service_FS, "called"); | ||
| 1021 | |||
| 1022 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 1023 | rb.Push(RESULT_SUCCESS); | ||
| 1024 | rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>()); | ||
| 1025 | } | ||
| 1026 | |||
| 991 | } // namespace Service::FileSystem | 1027 | } // namespace Service::FileSystem |
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index d52b55999..dfb3e395b 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h | |||
| @@ -50,6 +50,7 @@ private: | |||
| 50 | void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); | 50 | void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); |
| 51 | void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx); | 51 | void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx); |
| 52 | void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx); | 52 | void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx); |
| 53 | void OpenMultiCommitManager(Kernel::HLERequestContext& ctx); | ||
| 53 | 54 | ||
| 54 | FileSystemController& fsc; | 55 | FileSystemController& fsc; |
| 55 | 56 | ||
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index dccbabcbf..bfb600df0 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -488,11 +488,11 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, std::string pat | |||
| 488 | auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); | 488 | auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); |
| 489 | navigate_to_gamedb_entry->setVisible(it != compatibility_list.end() && program_id != 0); | 489 | navigate_to_gamedb_entry->setVisible(it != compatibility_list.end() && program_id != 0); |
| 490 | 490 | ||
| 491 | connect(open_save_location, &QAction::triggered, [this, program_id]() { | 491 | connect(open_save_location, &QAction::triggered, [this, program_id, path]() { |
| 492 | emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData); | 492 | emit OpenFolderRequested(GameListOpenTarget::SaveData, path); |
| 493 | }); | 493 | }); |
| 494 | connect(open_lfs_location, &QAction::triggered, [this, program_id]() { | 494 | connect(open_lfs_location, &QAction::triggered, [this, program_id, path]() { |
| 495 | emit OpenFolderRequested(program_id, GameListOpenTarget::ModData); | 495 | emit OpenFolderRequested(GameListOpenTarget::ModData, path); |
| 496 | }); | 496 | }); |
| 497 | connect(open_transferable_shader_cache, &QAction::triggered, | 497 | connect(open_transferable_shader_cache, &QAction::triggered, |
| 498 | [this, program_id]() { emit OpenTransferableShaderCacheRequested(program_id); }); | 498 | [this, program_id]() { emit OpenTransferableShaderCacheRequested(program_id); }); |
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 878d94413..a38cb2fc3 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h | |||
| @@ -73,7 +73,7 @@ public: | |||
| 73 | signals: | 73 | signals: |
| 74 | void GameChosen(QString game_path); | 74 | void GameChosen(QString game_path); |
| 75 | void ShouldCancelWorker(); | 75 | void ShouldCancelWorker(); |
| 76 | void OpenFolderRequested(u64 program_id, GameListOpenTarget target); | 76 | void OpenFolderRequested(GameListOpenTarget target, const std::string& game_path); |
| 77 | void OpenTransferableShaderCacheRequested(u64 program_id); | 77 | void OpenTransferableShaderCacheRequested(u64 program_id); |
| 78 | void DumpRomFSRequested(u64 program_id, const std::string& game_path); | 78 | void DumpRomFSRequested(u64 program_id, const std::string& game_path); |
| 79 | void CopyTIDRequested(u64 program_id); | 79 | void CopyTIDRequested(u64 program_id); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index dd6e5173e..0b291c7d0 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -1155,39 +1155,61 @@ void GMainWindow::OnGameListLoadFile(QString game_path) { | |||
| 1155 | BootGame(game_path); | 1155 | BootGame(game_path); |
| 1156 | } | 1156 | } |
| 1157 | 1157 | ||
| 1158 | void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target) { | 1158 | void GMainWindow::OnGameListOpenFolder(GameListOpenTarget target, const std::string& game_path) { |
| 1159 | std::string path; | 1159 | std::string path; |
| 1160 | QString open_target; | 1160 | QString open_target; |
| 1161 | |||
| 1162 | const auto v_file = Core::GetGameFileFromPath(vfs, game_path); | ||
| 1163 | const auto loader = Loader::GetLoader(v_file); | ||
| 1164 | FileSys::NACP control{}; | ||
| 1165 | u64 program_id{}; | ||
| 1166 | |||
| 1167 | loader->ReadControlData(control); | ||
| 1168 | loader->ReadProgramId(program_id); | ||
| 1169 | |||
| 1170 | const bool has_user_save{control.GetDefaultNormalSaveSize() > 0}; | ||
| 1171 | const bool has_device_save{control.GetDeviceSaveDataSize() > 0}; | ||
| 1172 | |||
| 1173 | ASSERT_MSG(has_user_save != has_device_save, "Game uses both user and device savedata?"); | ||
| 1174 | |||
| 1161 | switch (target) { | 1175 | switch (target) { |
| 1162 | case GameListOpenTarget::SaveData: { | 1176 | case GameListOpenTarget::SaveData: { |
| 1163 | open_target = tr("Save Data"); | 1177 | open_target = tr("Save Data"); |
| 1164 | const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); | 1178 | const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); |
| 1165 | ASSERT(program_id != 0); | 1179 | ASSERT(program_id != 0); |
| 1166 | 1180 | ||
| 1167 | const auto select_profile = [this] { | 1181 | if (has_user_save) { |
| 1168 | QtProfileSelectionDialog dialog(this); | 1182 | // User save data |
| 1169 | dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | | 1183 | const auto select_profile = [this] { |
| 1170 | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); | 1184 | QtProfileSelectionDialog dialog(this); |
| 1171 | dialog.setWindowModality(Qt::WindowModal); | 1185 | dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | |
| 1186 | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); | ||
| 1187 | dialog.setWindowModality(Qt::WindowModal); | ||
| 1172 | 1188 | ||
| 1173 | if (dialog.exec() == QDialog::Rejected) { | 1189 | if (dialog.exec() == QDialog::Rejected) { |
| 1174 | return -1; | 1190 | return -1; |
| 1175 | } | 1191 | } |
| 1176 | 1192 | ||
| 1177 | return dialog.GetIndex(); | 1193 | return dialog.GetIndex(); |
| 1178 | }; | 1194 | }; |
| 1179 | 1195 | ||
| 1180 | const auto index = select_profile(); | 1196 | const auto index = select_profile(); |
| 1181 | if (index == -1) { | 1197 | if (index == -1) { |
| 1182 | return; | 1198 | return; |
| 1183 | } | 1199 | } |
| 1184 | 1200 | ||
| 1185 | Service::Account::ProfileManager manager; | 1201 | Service::Account::ProfileManager manager; |
| 1186 | const auto user_id = manager.GetUser(static_cast<std::size_t>(index)); | 1202 | const auto user_id = manager.GetUser(static_cast<std::size_t>(index)); |
| 1187 | ASSERT(user_id); | 1203 | ASSERT(user_id); |
| 1188 | path = nand_dir + FileSys::SaveDataFactory::GetFullPath(FileSys::SaveDataSpaceId::NandUser, | 1204 | path = nand_dir + FileSys::SaveDataFactory::GetFullPath( |
| 1189 | FileSys::SaveDataType::SaveData, | 1205 | FileSys::SaveDataSpaceId::NandUser, |
| 1190 | program_id, user_id->uuid, 0); | 1206 | FileSys::SaveDataType::SaveData, program_id, user_id->uuid, 0); |
| 1207 | } else { | ||
| 1208 | // Device save data | ||
| 1209 | path = nand_dir + FileSys::SaveDataFactory::GetFullPath( | ||
| 1210 | FileSys::SaveDataSpaceId::NandUser, | ||
| 1211 | FileSys::SaveDataType::SaveData, program_id, {}, 0); | ||
| 1212 | } | ||
| 1191 | 1213 | ||
| 1192 | if (!FileUtil::Exists(path)) { | 1214 | if (!FileUtil::Exists(path)) { |
| 1193 | FileUtil::CreateFullPath(path); | 1215 | FileUtil::CreateFullPath(path); |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 4bff4330c..4f4c8ddbe 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -183,7 +183,7 @@ private slots: | |||
| 183 | void OnMenuReportCompatibility(); | 183 | void OnMenuReportCompatibility(); |
| 184 | /// Called whenever a user selects a game in the game list widget. | 184 | /// Called whenever a user selects a game in the game list widget. |
| 185 | void OnGameListLoadFile(QString game_path); | 185 | void OnGameListLoadFile(QString game_path); |
| 186 | void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target); | 186 | void OnGameListOpenFolder(GameListOpenTarget target, const std::string& game_path); |
| 187 | void OnTransferableShaderCacheOpenFile(u64 program_id); | 187 | void OnTransferableShaderCacheOpenFile(u64 program_id); |
| 188 | void OnGameListDumpRomFS(u64 program_id, const std::string& game_path); | 188 | void OnGameListDumpRomFS(u64 program_id, const std::string& game_path); |
| 189 | void OnGameListCopyTID(u64 program_id); | 189 | void OnGameListCopyTID(u64 program_id); |