diff options
| -rw-r--r-- | src/core/core.cpp | 13 | ||||
| -rw-r--r-- | src/core/core.h | 2 | ||||
| -rw-r--r-- | src/core/file_sys/card_image.cpp | 18 | ||||
| -rw-r--r-- | src/core/file_sys/card_image.h | 3 | ||||
| -rw-r--r-- | src/core/file_sys/submission_package.cpp | 71 | ||||
| -rw-r--r-- | src/core/file_sys/submission_package.h | 11 | ||||
| -rw-r--r-- | src/core/loader/loader.cpp | 13 | ||||
| -rw-r--r-- | src/core/loader/loader.h | 13 | ||||
| -rw-r--r-- | src/core/loader/nsp.cpp | 34 | ||||
| -rw-r--r-- | src/core/loader/nsp.h | 4 | ||||
| -rw-r--r-- | src/core/loader/xci.cpp | 14 | ||||
| -rw-r--r-- | src/core/loader/xci.h | 3 | ||||
| -rw-r--r-- | src/yuzu/game_list.cpp | 8 | ||||
| -rw-r--r-- | src/yuzu/game_list.h | 5 | ||||
| -rw-r--r-- | src/yuzu/game_list_worker.cpp | 44 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 17 | ||||
| -rw-r--r-- | src/yuzu/main.h | 6 |
17 files changed, 171 insertions, 108 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index 406320ed6..15226cf41 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -216,9 +216,9 @@ struct System::Impl { | |||
| 216 | } | 216 | } |
| 217 | 217 | ||
| 218 | ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath, | 218 | ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath, |
| 219 | std::size_t program_index) { | 219 | u64 program_id, std::size_t program_index) { |
| 220 | app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath), | 220 | app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath), |
| 221 | program_index); | 221 | program_id, program_index); |
| 222 | 222 | ||
| 223 | if (!app_loader) { | 223 | if (!app_loader) { |
| 224 | LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); | 224 | LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); |
| @@ -269,11 +269,10 @@ struct System::Impl { | |||
| 269 | } | 269 | } |
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | u64 title_id{0}; | 272 | if (app_loader->ReadProgramId(program_id) != Loader::ResultStatus::Success) { |
| 273 | if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) { | ||
| 274 | LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", load_result); | 273 | LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", load_result); |
| 275 | } | 274 | } |
| 276 | perf_stats = std::make_unique<PerfStats>(title_id); | 275 | perf_stats = std::make_unique<PerfStats>(program_id); |
| 277 | // Reset counters and set time origin to current frame | 276 | // Reset counters and set time origin to current frame |
| 278 | GetAndResetPerfStats(); | 277 | GetAndResetPerfStats(); |
| 279 | perf_stats->BeginSystemFrame(); | 278 | perf_stats->BeginSystemFrame(); |
| @@ -459,8 +458,8 @@ void System::Shutdown() { | |||
| 459 | } | 458 | } |
| 460 | 459 | ||
| 461 | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, | 460 | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, |
| 462 | std::size_t program_index) { | 461 | u64 program_id, std::size_t program_index) { |
| 463 | return impl->Load(*this, emu_window, filepath, program_index); | 462 | return impl->Load(*this, emu_window, filepath, program_id, program_index); |
| 464 | } | 463 | } |
| 465 | 464 | ||
| 466 | bool System::IsPoweredOn() const { | 465 | bool System::IsPoweredOn() const { |
diff --git a/src/core/core.h b/src/core/core.h index 8b93ba998..b93c32e60 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -175,7 +175,7 @@ public: | |||
| 175 | * @returns ResultStatus code, indicating if the operation succeeded. | 175 | * @returns ResultStatus code, indicating if the operation succeeded. |
| 176 | */ | 176 | */ |
| 177 | [[nodiscard]] ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath, | 177 | [[nodiscard]] ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath, |
| 178 | std::size_t program_index = 0); | 178 | u64 program_id = 0, std::size_t program_index = 0); |
| 179 | 179 | ||
| 180 | /** | 180 | /** |
| 181 | * Indicates if the emulated system is powered on (all subsystems initialized and able to run an | 181 | * Indicates if the emulated system is powered on (all subsystems initialized and able to run an |
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index db2f6a955..755d3303e 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp | |||
| @@ -29,7 +29,7 @@ constexpr std::array partition_names{ | |||
| 29 | "logo", | 29 | "logo", |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | XCI::XCI(VirtualFile file_, std::size_t program_index) | 32 | XCI::XCI(VirtualFile file_, u64 program_id, size_t program_index) |
| 33 | : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA}, | 33 | : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA}, |
| 34 | partitions(partition_names.size()), | 34 | partitions(partition_names.size()), |
| 35 | partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} { | 35 | partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} { |
| @@ -63,12 +63,12 @@ XCI::XCI(VirtualFile file_, std::size_t program_index) | |||
| 63 | 63 | ||
| 64 | secure_partition = std::make_shared<NSP>( | 64 | secure_partition = std::make_shared<NSP>( |
| 65 | main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]), | 65 | main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]), |
| 66 | program_index); | 66 | program_id, program_index); |
| 67 | 67 | ||
| 68 | ncas = secure_partition->GetNCAsCollapsed(); | 68 | ncas = secure_partition->GetNCAsCollapsed(); |
| 69 | program = | 69 | program = |
| 70 | secure_partition->GetNCA(secure_partition->GetProgramTitleID(), ContentRecordType::Program); | 70 | secure_partition->GetNCA(secure_partition->GetProgramTitleID(), ContentRecordType::Program); |
| 71 | program_nca_status = secure_partition->GetProgramStatus(secure_partition->GetProgramTitleID()); | 71 | program_nca_status = secure_partition->GetProgramStatus(); |
| 72 | if (program_nca_status == Loader::ResultStatus::ErrorNSPMissingProgramNCA) { | 72 | if (program_nca_status == Loader::ResultStatus::ErrorNSPMissingProgramNCA) { |
| 73 | program_nca_status = Loader::ResultStatus::ErrorXCIMissingProgramNCA; | 73 | program_nca_status = Loader::ResultStatus::ErrorXCIMissingProgramNCA; |
| 74 | } | 74 | } |
| @@ -174,6 +174,10 @@ u64 XCI::GetProgramTitleID() const { | |||
| 174 | return secure_partition->GetProgramTitleID(); | 174 | return secure_partition->GetProgramTitleID(); |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | std::vector<u64> XCI::GetProgramTitleIDs() const { | ||
| 178 | return secure_partition->GetProgramTitleIDs(); | ||
| 179 | } | ||
| 180 | |||
| 177 | u32 XCI::GetSystemUpdateVersion() { | 181 | u32 XCI::GetSystemUpdateVersion() { |
| 178 | const auto update = GetPartition(XCIPartition::Update); | 182 | const auto update = GetPartition(XCIPartition::Update); |
| 179 | if (update == nullptr) { | 183 | if (update == nullptr) { |
| @@ -229,9 +233,11 @@ const std::vector<std::shared_ptr<NCA>>& XCI::GetNCAs() const { | |||
| 229 | } | 233 | } |
| 230 | 234 | ||
| 231 | std::shared_ptr<NCA> XCI::GetNCAByType(NCAContentType type) const { | 235 | std::shared_ptr<NCA> XCI::GetNCAByType(NCAContentType type) const { |
| 232 | const auto iter = | 236 | const auto program_id = secure_partition->GetProgramTitleID(); |
| 233 | std::find_if(ncas.begin(), ncas.end(), | 237 | const auto iter = std::find_if( |
| 234 | [type](const std::shared_ptr<NCA>& nca) { return nca->GetType() == type; }); | 238 | ncas.begin(), ncas.end(), [this, type, program_id](const std::shared_ptr<NCA>& nca) { |
| 239 | return nca->GetType() == type && nca->GetTitleId() == program_id; | ||
| 240 | }); | ||
| 235 | return iter == ncas.end() ? nullptr : *iter; | 241 | return iter == ncas.end() ? nullptr : *iter; |
| 236 | } | 242 | } |
| 237 | 243 | ||
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h index 4960e90fe..0fd9fa87c 100644 --- a/src/core/file_sys/card_image.h +++ b/src/core/file_sys/card_image.h | |||
| @@ -78,7 +78,7 @@ enum class XCIPartition : u8 { Update, Normal, Secure, Logo }; | |||
| 78 | 78 | ||
| 79 | class XCI : public ReadOnlyVfsDirectory { | 79 | class XCI : public ReadOnlyVfsDirectory { |
| 80 | public: | 80 | public: |
| 81 | explicit XCI(VirtualFile file, std::size_t program_index = 0); | 81 | explicit XCI(VirtualFile file, u64 program_id = 0, size_t program_index = 0); |
| 82 | ~XCI() override; | 82 | ~XCI() override; |
| 83 | 83 | ||
| 84 | Loader::ResultStatus GetStatus() const; | 84 | Loader::ResultStatus GetStatus() const; |
| @@ -104,6 +104,7 @@ public: | |||
| 104 | VirtualFile GetLogoPartitionRaw() const; | 104 | VirtualFile GetLogoPartitionRaw() const; |
| 105 | 105 | ||
| 106 | u64 GetProgramTitleID() const; | 106 | u64 GetProgramTitleID() const; |
| 107 | std::vector<u64> GetProgramTitleIDs() const; | ||
| 107 | u32 GetSystemUpdateVersion(); | 108 | u32 GetSystemUpdateVersion(); |
| 108 | u64 GetSystemUpdateTitleID() const; | 109 | u64 GetSystemUpdateTitleID() const; |
| 109 | 110 | ||
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp index d51d469e3..f192dffa5 100644 --- a/src/core/file_sys/submission_package.cpp +++ b/src/core/file_sys/submission_package.cpp | |||
| @@ -20,8 +20,9 @@ | |||
| 20 | 20 | ||
| 21 | namespace FileSys { | 21 | namespace FileSys { |
| 22 | 22 | ||
| 23 | NSP::NSP(VirtualFile file_, std::size_t program_index_) | 23 | NSP::NSP(VirtualFile file_, u64 title_id_, std::size_t program_index_) |
| 24 | : file(std::move(file_)), program_index(program_index_), status{Loader::ResultStatus::Success}, | 24 | : file(std::move(file_)), expected_program_id(title_id_), |
| 25 | program_index(program_index_), status{Loader::ResultStatus::Success}, | ||
| 25 | pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} { | 26 | pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} { |
| 26 | if (pfs->GetStatus() != Loader::ResultStatus::Success) { | 27 | if (pfs->GetStatus() != Loader::ResultStatus::Success) { |
| 27 | status = pfs->GetStatus(); | 28 | status = pfs->GetStatus(); |
| @@ -46,60 +47,59 @@ Loader::ResultStatus NSP::GetStatus() const { | |||
| 46 | return status; | 47 | return status; |
| 47 | } | 48 | } |
| 48 | 49 | ||
| 49 | Loader::ResultStatus NSP::GetProgramStatus(u64 title_id) const { | 50 | Loader::ResultStatus NSP::GetProgramStatus() const { |
| 50 | if (IsExtractedType() && GetExeFS() != nullptr && FileSys::IsDirectoryExeFS(GetExeFS())) { | 51 | if (IsExtractedType() && GetExeFS() != nullptr && FileSys::IsDirectoryExeFS(GetExeFS())) { |
| 51 | return Loader::ResultStatus::Success; | 52 | return Loader::ResultStatus::Success; |
| 52 | } | 53 | } |
| 53 | 54 | ||
| 54 | const auto iter = program_status.find(title_id); | 55 | const auto iter = program_status.find(GetProgramTitleID()); |
| 55 | if (iter == program_status.end()) | 56 | if (iter == program_status.end()) |
| 56 | return Loader::ResultStatus::ErrorNSPMissingProgramNCA; | 57 | return Loader::ResultStatus::ErrorNSPMissingProgramNCA; |
| 57 | return iter->second; | 58 | return iter->second; |
| 58 | } | 59 | } |
| 59 | 60 | ||
| 60 | u64 NSP::GetFirstTitleID() const { | ||
| 61 | if (IsExtractedType()) { | ||
| 62 | return GetProgramTitleID(); | ||
| 63 | } | ||
| 64 | |||
| 65 | if (program_status.empty()) | ||
| 66 | return 0; | ||
| 67 | return program_status.begin()->first; | ||
| 68 | } | ||
| 69 | |||
| 70 | u64 NSP::GetProgramTitleID() const { | 61 | u64 NSP::GetProgramTitleID() const { |
| 71 | if (IsExtractedType()) { | 62 | if (IsExtractedType()) { |
| 72 | if (GetExeFS() == nullptr || !IsDirectoryExeFS(GetExeFS())) { | 63 | return GetExtractedTitleID() + program_index; |
| 73 | return 0; | 64 | } |
| 74 | } | ||
| 75 | 65 | ||
| 76 | ProgramMetadata meta; | 66 | auto program_id = expected_program_id; |
| 77 | if (meta.Load(GetExeFS()->GetFile("main.npdm")) == Loader::ResultStatus::Success) { | 67 | if (program_id == 0) { |
| 78 | return meta.GetTitleID(); | 68 | if (!program_status.empty()) { |
| 79 | } else { | 69 | program_id = program_status.begin()->first; |
| 80 | return 0; | ||
| 81 | } | 70 | } |
| 82 | } | 71 | } |
| 83 | 72 | ||
| 84 | const auto out = GetFirstTitleID(); | 73 | program_id = program_id + program_index; |
| 85 | if ((out & 0x800) == 0) | 74 | if (program_status.find(program_id) != program_status.end()) { |
| 86 | return out; | 75 | return program_id; |
| 76 | } | ||
| 87 | 77 | ||
| 88 | const auto ids = GetTitleIDs(); | 78 | const auto ids = GetProgramTitleIDs(); |
| 89 | const auto iter = | 79 | const auto iter = |
| 90 | std::find_if(ids.begin(), ids.end(), [](u64 tid) { return (tid & 0x800) == 0; }); | 80 | std::find_if(ids.begin(), ids.end(), [](u64 tid) { return (tid & 0x800) == 0; }); |
| 91 | return iter == ids.end() ? out : *iter; | 81 | return iter == ids.end() ? 0 : *iter; |
| 82 | } | ||
| 83 | |||
| 84 | u64 NSP::GetExtractedTitleID() const { | ||
| 85 | if (GetExeFS() == nullptr || !IsDirectoryExeFS(GetExeFS())) { | ||
| 86 | return 0; | ||
| 87 | } | ||
| 88 | |||
| 89 | ProgramMetadata meta; | ||
| 90 | if (meta.Load(GetExeFS()->GetFile("main.npdm")) == Loader::ResultStatus::Success) { | ||
| 91 | return meta.GetTitleID(); | ||
| 92 | } else { | ||
| 93 | return 0; | ||
| 94 | } | ||
| 92 | } | 95 | } |
| 93 | 96 | ||
| 94 | std::vector<u64> NSP::GetTitleIDs() const { | 97 | std::vector<u64> NSP::GetProgramTitleIDs() const { |
| 95 | if (IsExtractedType()) { | 98 | if (IsExtractedType()) { |
| 96 | return {GetProgramTitleID()}; | 99 | return {GetExtractedTitleID()}; |
| 97 | } | 100 | } |
| 98 | 101 | ||
| 99 | std::vector<u64> out; | 102 | std::vector<u64> out{program_ids.cbegin(), program_ids.cend()}; |
| 100 | out.reserve(ncas.size()); | ||
| 101 | for (const auto& kv : ncas) | ||
| 102 | out.push_back(kv.first); | ||
| 103 | return out; | 103 | return out; |
| 104 | } | 104 | } |
| 105 | 105 | ||
| @@ -146,7 +146,7 @@ std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType | |||
| 146 | if (extracted) | 146 | if (extracted) |
| 147 | LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); | 147 | LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); |
| 148 | 148 | ||
| 149 | const auto title_id_iter = ncas.find(title_id + program_index); | 149 | const auto title_id_iter = ncas.find(title_id); |
| 150 | if (title_id_iter == ncas.end()) | 150 | if (title_id_iter == ncas.end()) |
| 151 | return nullptr; | 151 | return nullptr; |
| 152 | 152 | ||
| @@ -160,7 +160,7 @@ std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType | |||
| 160 | VirtualFile NSP::GetNCAFile(u64 title_id, ContentRecordType type, TitleType title_type) const { | 160 | VirtualFile NSP::GetNCAFile(u64 title_id, ContentRecordType type, TitleType title_type) const { |
| 161 | if (extracted) | 161 | if (extracted) |
| 162 | LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); | 162 | LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); |
| 163 | const auto nca = GetNCA(title_id, type); | 163 | const auto nca = GetNCA(title_id, type, title_type); |
| 164 | if (nca != nullptr) | 164 | if (nca != nullptr) |
| 165 | return nca->GetBaseFile(); | 165 | return nca->GetBaseFile(); |
| 166 | return nullptr; | 166 | return nullptr; |
| @@ -286,6 +286,7 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) { | |||
| 286 | 286 | ||
| 287 | if (next_nca->GetType() == NCAContentType::Program) { | 287 | if (next_nca->GetType() == NCAContentType::Program) { |
| 288 | program_status[next_nca->GetTitleId()] = next_nca->GetStatus(); | 288 | program_status[next_nca->GetTitleId()] = next_nca->GetStatus(); |
| 289 | program_ids.insert(next_nca->GetTitleId() & 0xFFFFFFFFFFFFF000); | ||
| 289 | } | 290 | } |
| 290 | 291 | ||
| 291 | if (next_nca->GetStatus() != Loader::ResultStatus::Success && | 292 | if (next_nca->GetStatus() != Loader::ResultStatus::Success && |
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h index ecb3b6f15..030f36c09 100644 --- a/src/core/file_sys/submission_package.h +++ b/src/core/file_sys/submission_package.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <map> | 7 | #include <map> |
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | #include <set> | ||
| 9 | #include <vector> | 10 | #include <vector> |
| 10 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 11 | #include "core/file_sys/vfs.h" | 12 | #include "core/file_sys/vfs.h" |
| @@ -27,15 +28,15 @@ enum class ContentRecordType : u8; | |||
| 27 | 28 | ||
| 28 | class NSP : public ReadOnlyVfsDirectory { | 29 | class NSP : public ReadOnlyVfsDirectory { |
| 29 | public: | 30 | public: |
| 30 | explicit NSP(VirtualFile file_, std::size_t program_index_ = 0); | 31 | explicit NSP(VirtualFile file_, u64 title_id = 0, std::size_t program_index_ = 0); |
| 31 | ~NSP() override; | 32 | ~NSP() override; |
| 32 | 33 | ||
| 33 | Loader::ResultStatus GetStatus() const; | 34 | Loader::ResultStatus GetStatus() const; |
| 34 | Loader::ResultStatus GetProgramStatus(u64 title_id) const; | 35 | Loader::ResultStatus GetProgramStatus() const; |
| 35 | // Should only be used when one title id can be assured. | 36 | // Should only be used when one title id can be assured. |
| 36 | u64 GetFirstTitleID() const; | ||
| 37 | u64 GetProgramTitleID() const; | 37 | u64 GetProgramTitleID() const; |
| 38 | std::vector<u64> GetTitleIDs() const; | 38 | u64 GetExtractedTitleID() const; |
| 39 | std::vector<u64> GetProgramTitleIDs() const; | ||
| 39 | 40 | ||
| 40 | bool IsExtractedType() const; | 41 | bool IsExtractedType() const; |
| 41 | 42 | ||
| @@ -69,6 +70,7 @@ private: | |||
| 69 | 70 | ||
| 70 | VirtualFile file; | 71 | VirtualFile file; |
| 71 | 72 | ||
| 73 | const u64 expected_program_id; | ||
| 72 | const std::size_t program_index; | 74 | const std::size_t program_index; |
| 73 | 75 | ||
| 74 | bool extracted = false; | 76 | bool extracted = false; |
| @@ -78,6 +80,7 @@ private: | |||
| 78 | std::shared_ptr<PartitionFilesystem> pfs; | 80 | std::shared_ptr<PartitionFilesystem> pfs; |
| 79 | // Map title id -> {map type -> NCA} | 81 | // Map title id -> {map type -> NCA} |
| 80 | std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas; | 82 | std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas; |
| 83 | std::set<u64> program_ids; | ||
| 81 | std::vector<VirtualFile> ticket_files; | 84 | std::vector<VirtualFile> ticket_files; |
| 82 | 85 | ||
| 83 | Core::Crypto::KeyManager& keys; | 86 | Core::Crypto::KeyManager& keys; |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 228dc6389..199e69e89 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -206,7 +206,8 @@ AppLoader::~AppLoader() = default; | |||
| 206 | * @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type | 206 | * @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type |
| 207 | */ | 207 | */ |
| 208 | static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file, | 208 | static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file, |
| 209 | FileType type, std::size_t program_index) { | 209 | FileType type, u64 program_id, |
| 210 | std::size_t program_index) { | ||
| 210 | switch (type) { | 211 | switch (type) { |
| 211 | // Standard ELF file format. | 212 | // Standard ELF file format. |
| 212 | case FileType::ELF: | 213 | case FileType::ELF: |
| @@ -227,7 +228,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V | |||
| 227 | // NX XCI (nX Card Image) file format. | 228 | // NX XCI (nX Card Image) file format. |
| 228 | case FileType::XCI: | 229 | case FileType::XCI: |
| 229 | return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(), | 230 | return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(), |
| 230 | system.GetContentProvider(), program_index); | 231 | system.GetContentProvider(), program_id, |
| 232 | program_index); | ||
| 231 | 233 | ||
| 232 | // NX NAX (NintendoAesXts) file format. | 234 | // NX NAX (NintendoAesXts) file format. |
| 233 | case FileType::NAX: | 235 | case FileType::NAX: |
| @@ -236,7 +238,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V | |||
| 236 | // NX NSP (Nintendo Submission Package) file format | 238 | // NX NSP (Nintendo Submission Package) file format |
| 237 | case FileType::NSP: | 239 | case FileType::NSP: |
| 238 | return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(), | 240 | return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(), |
| 239 | system.GetContentProvider(), program_index); | 241 | system.GetContentProvider(), program_id, |
| 242 | program_index); | ||
| 240 | 243 | ||
| 241 | // NX KIP (Kernel Internal Process) file format | 244 | // NX KIP (Kernel Internal Process) file format |
| 242 | case FileType::KIP: | 245 | case FileType::KIP: |
| @@ -252,7 +255,7 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V | |||
| 252 | } | 255 | } |
| 253 | 256 | ||
| 254 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, | 257 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, |
| 255 | std::size_t program_index) { | 258 | u64 program_id, std::size_t program_index) { |
| 256 | FileType type = IdentifyFile(file); | 259 | FileType type = IdentifyFile(file); |
| 257 | const FileType filename_type = GuessFromFilename(file->GetName()); | 260 | const FileType filename_type = GuessFromFilename(file->GetName()); |
| 258 | 261 | ||
| @@ -266,7 +269,7 @@ std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile | |||
| 266 | 269 | ||
| 267 | LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type)); | 270 | LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type)); |
| 268 | 271 | ||
| 269 | return GetFileLoader(system, std::move(file), type, program_index); | 272 | return GetFileLoader(system, std::move(file), type, program_id, program_index); |
| 270 | } | 273 | } |
| 271 | 274 | ||
| 272 | } // namespace Loader | 275 | } // namespace Loader |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index edc8bb257..7b1bac3f7 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -227,6 +227,17 @@ public: | |||
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | /** | 229 | /** |
| 230 | * Get the program ids of the application | ||
| 231 | * | ||
| 232 | * @param[out] out_program_ids Reference to store program ids into | ||
| 233 | * | ||
| 234 | * @return ResultStatus result of function | ||
| 235 | */ | ||
| 236 | virtual ResultStatus ReadProgramIds(std::vector<u64>& out_program_ids) { | ||
| 237 | return ResultStatus::ErrorNotImplemented; | ||
| 238 | } | ||
| 239 | |||
| 240 | /** | ||
| 230 | * Get the RomFS of the application | 241 | * Get the RomFS of the application |
| 231 | * Since the RomFS can be huge, we return a file reference instead of copying to a buffer | 242 | * Since the RomFS can be huge, we return a file reference instead of copying to a buffer |
| 232 | * | 243 | * |
| @@ -324,6 +335,6 @@ protected: | |||
| 324 | * @return the best loader for this file. | 335 | * @return the best loader for this file. |
| 325 | */ | 336 | */ |
| 326 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, | 337 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, |
| 327 | std::size_t program_index = 0); | 338 | u64 program_id = 0, std::size_t program_index = 0); |
| 328 | 339 | ||
| 329 | } // namespace Loader | 340 | } // namespace Loader |
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index d815a7cd3..8b167ad3c 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp | |||
| @@ -23,10 +23,9 @@ namespace Loader { | |||
| 23 | 23 | ||
| 24 | AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_, | 24 | AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_, |
| 25 | const Service::FileSystem::FileSystemController& fsc, | 25 | const Service::FileSystem::FileSystemController& fsc, |
| 26 | const FileSys::ContentProvider& content_provider, | 26 | const FileSys::ContentProvider& content_provider, u64 program_id, |
| 27 | std::size_t program_index) | 27 | std::size_t program_index) |
| 28 | : AppLoader(file_), nsp(std::make_unique<FileSys::NSP>(file_, program_index)), | 28 | : AppLoader(file_), nsp(std::make_unique<FileSys::NSP>(file_, program_id, program_index)) { |
| 29 | title_id(nsp->GetProgramTitleID()) { | ||
| 30 | 29 | ||
| 31 | if (nsp->GetStatus() != ResultStatus::Success) { | 30 | if (nsp->GetStatus() != ResultStatus::Success) { |
| 32 | return; | 31 | return; |
| @@ -46,12 +45,8 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_, | |||
| 46 | return pm.ParseControlNCA(*control_nca); | 45 | return pm.ParseControlNCA(*control_nca); |
| 47 | }(); | 46 | }(); |
| 48 | 47 | ||
| 49 | if (title_id == 0) { | ||
| 50 | return; | ||
| 51 | } | ||
| 52 | |||
| 53 | secondary_loader = std::make_unique<AppLoader_NCA>( | 48 | secondary_loader = std::make_unique<AppLoader_NCA>( |
| 54 | nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program)); | 49 | nsp->GetNCAFile(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Program)); |
| 55 | } | 50 | } |
| 56 | } | 51 | } |
| 57 | 52 | ||
| @@ -68,10 +63,11 @@ FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& nsp_file) { | |||
| 68 | } | 63 | } |
| 69 | 64 | ||
| 70 | // Non-Extracted Type case | 65 | // Non-Extracted Type case |
| 66 | const auto program_id = nsp.GetProgramTitleID(); | ||
| 71 | if (!nsp.IsExtractedType() && | 67 | if (!nsp.IsExtractedType() && |
| 72 | nsp.GetNCA(nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program) != nullptr && | 68 | nsp.GetNCA(program_id, FileSys::ContentRecordType::Program) != nullptr && |
| 73 | AppLoader_NCA::IdentifyType(nsp.GetNCAFile( | 69 | AppLoader_NCA::IdentifyType( |
| 74 | nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program)) == FileType::NCA) { | 70 | nsp.GetNCAFile(program_id, FileSys::ContentRecordType::Program)) == FileType::NCA) { |
| 75 | return FileType::NSP; | 71 | return FileType::NSP; |
| 76 | } | 72 | } |
| 77 | } | 73 | } |
| @@ -84,6 +80,8 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::S | |||
| 84 | return {ResultStatus::ErrorAlreadyLoaded, {}}; | 80 | return {ResultStatus::ErrorAlreadyLoaded, {}}; |
| 85 | } | 81 | } |
| 86 | 82 | ||
| 83 | const auto title_id = nsp->GetProgramTitleID(); | ||
| 84 | |||
| 87 | if (!nsp->IsExtractedType() && title_id == 0) { | 85 | if (!nsp->IsExtractedType() && title_id == 0) { |
| 88 | return {ResultStatus::ErrorNSPMissingProgramNCA, {}}; | 86 | return {ResultStatus::ErrorNSPMissingProgramNCA, {}}; |
| 89 | } | 87 | } |
| @@ -93,7 +91,7 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::S | |||
| 93 | return {nsp_status, {}}; | 91 | return {nsp_status, {}}; |
| 94 | } | 92 | } |
| 95 | 93 | ||
| 96 | const auto nsp_program_status = nsp->GetProgramStatus(title_id); | 94 | const auto nsp_program_status = nsp->GetProgramStatus(); |
| 97 | if (nsp_program_status != ResultStatus::Success) { | 95 | if (nsp_program_status != ResultStatus::Success) { |
| 98 | return {nsp_program_status, {}}; | 96 | return {nsp_program_status, {}}; |
| 99 | } | 97 | } |
| @@ -134,8 +132,8 @@ ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& out_file) { | |||
| 134 | return ResultStatus::ErrorNoPackedUpdate; | 132 | return ResultStatus::ErrorNoPackedUpdate; |
| 135 | } | 133 | } |
| 136 | 134 | ||
| 137 | const auto read = | 135 | const auto read = nsp->GetNCAFile(FileSys::GetUpdateTitleID(nsp->GetProgramTitleID()), |
| 138 | nsp->GetNCAFile(FileSys::GetUpdateTitleID(title_id), FileSys::ContentRecordType::Program); | 136 | FileSys::ContentRecordType::Program); |
| 139 | 137 | ||
| 140 | if (read == nullptr) { | 138 | if (read == nullptr) { |
| 141 | return ResultStatus::ErrorNoPackedUpdate; | 139 | return ResultStatus::ErrorNoPackedUpdate; |
| @@ -151,11 +149,15 @@ ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& out_file) { | |||
| 151 | } | 149 | } |
| 152 | 150 | ||
| 153 | ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) { | 151 | ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) { |
| 154 | if (title_id == 0) { | 152 | out_program_id = nsp->GetProgramTitleID(); |
| 153 | if (out_program_id == 0) { | ||
| 155 | return ResultStatus::ErrorNotInitialized; | 154 | return ResultStatus::ErrorNotInitialized; |
| 156 | } | 155 | } |
| 156 | return ResultStatus::Success; | ||
| 157 | } | ||
| 157 | 158 | ||
| 158 | out_program_id = title_id; | 159 | ResultStatus AppLoader_NSP::ReadProgramIds(std::vector<u64>& out_program_ids) { |
| 160 | out_program_ids = nsp->GetProgramTitleIDs(); | ||
| 159 | return ResultStatus::Success; | 161 | return ResultStatus::Success; |
| 160 | } | 162 | } |
| 161 | 163 | ||
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h index 644c0ff58..50406a92e 100644 --- a/src/core/loader/nsp.h +++ b/src/core/loader/nsp.h | |||
| @@ -28,7 +28,7 @@ class AppLoader_NSP final : public AppLoader { | |||
| 28 | public: | 28 | public: |
| 29 | explicit AppLoader_NSP(FileSys::VirtualFile file_, | 29 | explicit AppLoader_NSP(FileSys::VirtualFile file_, |
| 30 | const Service::FileSystem::FileSystemController& fsc, | 30 | const Service::FileSystem::FileSystemController& fsc, |
| 31 | const FileSys::ContentProvider& content_provider, | 31 | const FileSys::ContentProvider& content_provider, u64 program_id, |
| 32 | std::size_t program_index); | 32 | std::size_t program_index); |
| 33 | ~AppLoader_NSP() override; | 33 | ~AppLoader_NSP() override; |
| 34 | 34 | ||
| @@ -51,6 +51,7 @@ public: | |||
| 51 | u64 ReadRomFSIVFCOffset() const override; | 51 | u64 ReadRomFSIVFCOffset() const override; |
| 52 | ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override; | 52 | ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override; |
| 53 | ResultStatus ReadProgramId(u64& out_program_id) override; | 53 | ResultStatus ReadProgramId(u64& out_program_id) override; |
| 54 | ResultStatus ReadProgramIds(std::vector<u64>& out_program_ids) override; | ||
| 54 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; | 55 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; |
| 55 | ResultStatus ReadTitle(std::string& title) override; | 56 | ResultStatus ReadTitle(std::string& title) override; |
| 56 | ResultStatus ReadControlData(FileSys::NACP& nacp) override; | 57 | ResultStatus ReadControlData(FileSys::NACP& nacp) override; |
| @@ -67,7 +68,6 @@ private: | |||
| 67 | 68 | ||
| 68 | FileSys::VirtualFile icon_file; | 69 | FileSys::VirtualFile icon_file; |
| 69 | std::unique_ptr<FileSys::NACP> nacp_file; | 70 | std::unique_ptr<FileSys::NACP> nacp_file; |
| 70 | u64 title_id; | ||
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| 73 | } // namespace Loader | 73 | } // namespace Loader |
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 635d6ae15..269603eef 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp | |||
| @@ -22,9 +22,9 @@ namespace Loader { | |||
| 22 | 22 | ||
| 23 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file_, | 23 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file_, |
| 24 | const Service::FileSystem::FileSystemController& fsc, | 24 | const Service::FileSystem::FileSystemController& fsc, |
| 25 | const FileSys::ContentProvider& content_provider, | 25 | const FileSys::ContentProvider& content_provider, u64 program_id, |
| 26 | std::size_t program_index) | 26 | std::size_t program_index) |
| 27 | : AppLoader(file_), xci(std::make_unique<FileSys::XCI>(file_, program_index)), | 27 | : AppLoader(file_), xci(std::make_unique<FileSys::XCI>(file_, program_id, program_index)), |
| 28 | nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { | 28 | nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { |
| 29 | if (xci->GetStatus() != ResultStatus::Success) { | 29 | if (xci->GetStatus() != ResultStatus::Success) { |
| 30 | return; | 30 | return; |
| @@ -121,6 +121,11 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) { | |||
| 121 | return nca_loader->ReadProgramId(out_program_id); | 121 | return nca_loader->ReadProgramId(out_program_id); |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | ResultStatus AppLoader_XCI::ReadProgramIds(std::vector<u64>& out_program_ids) { | ||
| 125 | out_program_ids = xci->GetProgramTitleIDs(); | ||
| 126 | return ResultStatus::Success; | ||
| 127 | } | ||
| 128 | |||
| 124 | ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) { | 129 | ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) { |
| 125 | if (icon_file == nullptr) { | 130 | if (icon_file == nullptr) { |
| 126 | return ResultStatus::ErrorNoControl; | 131 | return ResultStatus::ErrorNoControl; |
| @@ -149,8 +154,9 @@ ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) { | |||
| 149 | } | 154 | } |
| 150 | 155 | ||
| 151 | ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& out_file) { | 156 | ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& out_file) { |
| 152 | const auto nca = xci->GetSecurePartitionNSP()->GetNCA(xci->GetProgramTitleID(), | 157 | const auto nca = |
| 153 | FileSys::ContentRecordType::HtmlDocument); | 158 | xci->GetSecurePartitionNSP()->GetNCA(xci->GetSecurePartitionNSP()->GetProgramTitleID(), |
| 159 | FileSys::ContentRecordType::HtmlDocument); | ||
| 154 | if (xci->GetStatus() != ResultStatus::Success || nca == nullptr) { | 160 | if (xci->GetStatus() != ResultStatus::Success || nca == nullptr) { |
| 155 | return ResultStatus::ErrorXCIMissingPartition; | 161 | return ResultStatus::ErrorXCIMissingPartition; |
| 156 | } | 162 | } |
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 708155c30..30caaf90e 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h | |||
| @@ -28,7 +28,7 @@ class AppLoader_XCI final : public AppLoader { | |||
| 28 | public: | 28 | public: |
| 29 | explicit AppLoader_XCI(FileSys::VirtualFile file_, | 29 | explicit AppLoader_XCI(FileSys::VirtualFile file_, |
| 30 | const Service::FileSystem::FileSystemController& fsc, | 30 | const Service::FileSystem::FileSystemController& fsc, |
| 31 | const FileSys::ContentProvider& content_provider, | 31 | const FileSys::ContentProvider& content_provider, u64 program_id, |
| 32 | std::size_t program_index); | 32 | std::size_t program_index); |
| 33 | ~AppLoader_XCI() override; | 33 | ~AppLoader_XCI() override; |
| 34 | 34 | ||
| @@ -51,6 +51,7 @@ public: | |||
| 51 | u64 ReadRomFSIVFCOffset() const override; | 51 | u64 ReadRomFSIVFCOffset() const override; |
| 52 | ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override; | 52 | ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override; |
| 53 | ResultStatus ReadProgramId(u64& out_program_id) override; | 53 | ResultStatus ReadProgramId(u64& out_program_id) override; |
| 54 | ResultStatus ReadProgramIds(std::vector<u64>& out_program_ids) override; | ||
| 54 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; | 55 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; |
| 55 | ResultStatus ReadTitle(std::string& title) override; | 56 | ResultStatus ReadTitle(std::string& title) override; |
| 56 | ResultStatus ReadControlData(FileSys::NACP& control) override; | 57 | ResultStatus ReadControlData(FileSys::NACP& control) override; |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 218b4782b..76c063c97 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -404,9 +404,11 @@ void GameList::ValidateEntry(const QModelIndex& item) { | |||
| 404 | return; | 404 | return; |
| 405 | } | 405 | } |
| 406 | 406 | ||
| 407 | const auto title_id = selected.data(GameListItemPath::ProgramIdRole).toULongLong(); | ||
| 408 | |||
| 407 | // Users usually want to run a different game after closing one | 409 | // Users usually want to run a different game after closing one |
| 408 | search_field->clear(); | 410 | search_field->clear(); |
| 409 | emit GameChosen(file_path); | 411 | emit GameChosen(file_path, title_id); |
| 410 | break; | 412 | break; |
| 411 | } | 413 | } |
| 412 | case GameListItemType::AddDir: | 414 | case GameListItemType::AddDir: |
| @@ -548,10 +550,10 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri | |||
| 548 | emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path); | 550 | emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path); |
| 549 | }); | 551 | }); |
| 550 | connect(start_game, &QAction::triggered, [this, path]() { | 552 | connect(start_game, &QAction::triggered, [this, path]() { |
| 551 | emit BootGame(QString::fromStdString(path), 0, StartGameType::Normal); | 553 | emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Normal); |
| 552 | }); | 554 | }); |
| 553 | connect(start_game_global, &QAction::triggered, [this, path]() { | 555 | connect(start_game_global, &QAction::triggered, [this, path]() { |
| 554 | emit BootGame(QString::fromStdString(path), 0, StartGameType::Global); | 556 | emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Global); |
| 555 | }); | 557 | }); |
| 556 | connect(open_mod_location, &QAction::triggered, [this, program_id, path]() { | 558 | connect(open_mod_location, &QAction::triggered, [this, program_id, path]() { |
| 557 | emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path); | 559 | emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path); |
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 50402da51..c9a9f4654 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h | |||
| @@ -88,8 +88,9 @@ public: | |||
| 88 | static const QStringList supported_file_extensions; | 88 | static const QStringList supported_file_extensions; |
| 89 | 89 | ||
| 90 | signals: | 90 | signals: |
| 91 | void BootGame(const QString& game_path, std::size_t program_index, StartGameType type); | 91 | void BootGame(const QString& game_path, u64 program_id, std::size_t program_index, |
| 92 | void GameChosen(const QString& game_path); | 92 | StartGameType type); |
| 93 | void GameChosen(const QString& game_path, const u64 title_id = 0); | ||
| 93 | void ShouldCancelWorker(); | 94 | void ShouldCancelWorker(); |
| 94 | void OpenFolderRequested(u64 program_id, GameListOpenTarget target, | 95 | void OpenFolderRequested(u64 program_id, GameListOpenTarget target, |
| 95 | const std::string& game_path); | 96 | const std::string& game_path); |
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index 33cc90d5a..2d5492157 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp | |||
| @@ -336,18 +336,44 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa | |||
| 336 | } | 336 | } |
| 337 | } | 337 | } |
| 338 | } else { | 338 | } else { |
| 339 | std::vector<u8> icon; | 339 | std::vector<u64> program_ids; |
| 340 | [[maybe_unused]] const auto res1 = loader->ReadIcon(icon); | 340 | loader->ReadProgramIds(program_ids); |
| 341 | |||
| 342 | if (res2 == Loader::ResultStatus::Success && program_ids.size() > 1 && | ||
| 343 | (file_type == Loader::FileType::XCI || file_type == Loader::FileType::NSP)) { | ||
| 344 | for (const auto id : program_ids) { | ||
| 345 | loader = Loader::GetLoader(system, file, id); | ||
| 346 | if (!loader) { | ||
| 347 | continue; | ||
| 348 | } | ||
| 349 | |||
| 350 | std::vector<u8> icon; | ||
| 351 | [[maybe_unused]] const auto res1 = loader->ReadIcon(icon); | ||
| 341 | 352 | ||
| 342 | std::string name = " "; | 353 | std::string name = " "; |
| 343 | [[maybe_unused]] const auto res3 = loader->ReadTitle(name); | 354 | [[maybe_unused]] const auto res3 = loader->ReadTitle(name); |
| 344 | 355 | ||
| 345 | const FileSys::PatchManager patch{program_id, system.GetFileSystemController(), | 356 | const FileSys::PatchManager patch{id, system.GetFileSystemController(), |
| 346 | system.GetContentProvider()}; | 357 | system.GetContentProvider()}; |
| 358 | |||
| 359 | emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, id, | ||
| 360 | compatibility_list, patch), | ||
| 361 | parent_dir); | ||
| 362 | } | ||
| 363 | } else { | ||
| 364 | std::vector<u8> icon; | ||
| 365 | [[maybe_unused]] const auto res1 = loader->ReadIcon(icon); | ||
| 347 | 366 | ||
| 348 | emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, program_id, | 367 | std::string name = " "; |
| 349 | compatibility_list, patch), | 368 | [[maybe_unused]] const auto res3 = loader->ReadTitle(name); |
| 350 | parent_dir); | 369 | |
| 370 | const FileSys::PatchManager patch{program_id, system.GetFileSystemController(), | ||
| 371 | system.GetContentProvider()}; | ||
| 372 | |||
| 373 | emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, | ||
| 374 | program_id, compatibility_list, patch), | ||
| 375 | parent_dir); | ||
| 376 | } | ||
| 351 | } | 377 | } |
| 352 | } else if (is_dir) { | 378 | } else if (is_dir) { |
| 353 | watch_list.append(QString::fromStdString(physical_name)); | 379 | watch_list.append(QString::fromStdString(physical_name)); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index b7fd33ae7..03a909d17 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -1221,7 +1221,7 @@ void GMainWindow::AllowOSSleep() { | |||
| 1221 | #endif | 1221 | #endif |
| 1222 | } | 1222 | } |
| 1223 | 1223 | ||
| 1224 | bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) { | 1224 | bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t program_index) { |
| 1225 | // Shutdown previous session if the emu thread is still active... | 1225 | // Shutdown previous session if the emu thread is still active... |
| 1226 | if (emu_thread != nullptr) | 1226 | if (emu_thread != nullptr) |
| 1227 | ShutdownGame(); | 1227 | ShutdownGame(); |
| @@ -1244,7 +1244,7 @@ bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) { | |||
| 1244 | }); | 1244 | }); |
| 1245 | 1245 | ||
| 1246 | const Core::System::ResultStatus result{ | 1246 | const Core::System::ResultStatus result{ |
| 1247 | system.Load(*render_window, filename.toStdString(), program_index)}; | 1247 | system.Load(*render_window, filename.toStdString(), program_id, program_index)}; |
| 1248 | 1248 | ||
| 1249 | const auto drd_callout = (UISettings::values.callout_flags.GetValue() & | 1249 | const auto drd_callout = (UISettings::values.callout_flags.GetValue() & |
| 1250 | static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0; | 1250 | static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0; |
| @@ -1331,7 +1331,8 @@ void GMainWindow::SelectAndSetCurrentUser() { | |||
| 1331 | Settings::values.current_user = dialog.GetIndex(); | 1331 | Settings::values.current_user = dialog.GetIndex(); |
| 1332 | } | 1332 | } |
| 1333 | 1333 | ||
| 1334 | void GMainWindow::BootGame(const QString& filename, std::size_t program_index, StartGameType type) { | 1334 | void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t program_index, |
| 1335 | StartGameType type) { | ||
| 1335 | LOG_INFO(Frontend, "yuzu starting..."); | 1336 | LOG_INFO(Frontend, "yuzu starting..."); |
| 1336 | StoreRecentFile(filename); // Put the filename on top of the list | 1337 | StoreRecentFile(filename); // Put the filename on top of the list |
| 1337 | 1338 | ||
| @@ -1341,7 +1342,7 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index, S | |||
| 1341 | 1342 | ||
| 1342 | auto& system = Core::System::GetInstance(); | 1343 | auto& system = Core::System::GetInstance(); |
| 1343 | const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); | 1344 | const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); |
| 1344 | const auto loader = Loader::GetLoader(system, v_file, program_index); | 1345 | const auto loader = Loader::GetLoader(system, v_file, program_id, program_index); |
| 1345 | 1346 | ||
| 1346 | if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success && | 1347 | if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success && |
| 1347 | type == StartGameType::Normal) { | 1348 | type == StartGameType::Normal) { |
| @@ -1369,7 +1370,7 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index, S | |||
| 1369 | SelectAndSetCurrentUser(); | 1370 | SelectAndSetCurrentUser(); |
| 1370 | } | 1371 | } |
| 1371 | 1372 | ||
| 1372 | if (!LoadROM(filename, program_index)) | 1373 | if (!LoadROM(filename, program_id, program_index)) |
| 1373 | return; | 1374 | return; |
| 1374 | 1375 | ||
| 1375 | // Create and start the emulation thread | 1376 | // Create and start the emulation thread |
| @@ -1548,8 +1549,8 @@ void GMainWindow::UpdateRecentFiles() { | |||
| 1548 | ui.menu_recent_files->setEnabled(num_recent_files != 0); | 1549 | ui.menu_recent_files->setEnabled(num_recent_files != 0); |
| 1549 | } | 1550 | } |
| 1550 | 1551 | ||
| 1551 | void GMainWindow::OnGameListLoadFile(QString game_path) { | 1552 | void GMainWindow::OnGameListLoadFile(QString game_path, u64 program_id) { |
| 1552 | BootGame(game_path); | 1553 | BootGame(game_path, program_id); |
| 1553 | } | 1554 | } |
| 1554 | 1555 | ||
| 1555 | void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, | 1556 | void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, |
| @@ -2450,7 +2451,7 @@ void GMainWindow::OnLoadComplete() { | |||
| 2450 | 2451 | ||
| 2451 | void GMainWindow::OnExecuteProgram(std::size_t program_index) { | 2452 | void GMainWindow::OnExecuteProgram(std::size_t program_index) { |
| 2452 | ShutdownGame(); | 2453 | ShutdownGame(); |
| 2453 | BootGame(last_filename_booted, program_index); | 2454 | BootGame(last_filename_booted, 0, program_index); |
| 2454 | } | 2455 | } |
| 2455 | 2456 | ||
| 2456 | void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { | 2457 | void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 45c8310e1..a50e5b9fe 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -186,8 +186,8 @@ private: | |||
| 186 | void PreventOSSleep(); | 186 | void PreventOSSleep(); |
| 187 | void AllowOSSleep(); | 187 | void AllowOSSleep(); |
| 188 | 188 | ||
| 189 | bool LoadROM(const QString& filename, std::size_t program_index); | 189 | bool LoadROM(const QString& filename, u64 program_id, std::size_t program_index); |
| 190 | void BootGame(const QString& filename, std::size_t program_index = 0, | 190 | void BootGame(const QString& filename, u64 program_id = 0, std::size_t program_index = 0, |
| 191 | StartGameType with_config = StartGameType::Normal); | 191 | StartGameType with_config = StartGameType::Normal); |
| 192 | void ShutdownGame(); | 192 | void ShutdownGame(); |
| 193 | 193 | ||
| @@ -238,7 +238,7 @@ private slots: | |||
| 238 | void OnOpenQuickstartGuide(); | 238 | void OnOpenQuickstartGuide(); |
| 239 | void OnOpenFAQ(); | 239 | void OnOpenFAQ(); |
| 240 | /// Called whenever a user selects a game in the game list widget. | 240 | /// Called whenever a user selects a game in the game list widget. |
| 241 | void OnGameListLoadFile(QString game_path); | 241 | void OnGameListLoadFile(QString game_path, u64 program_id); |
| 242 | void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, | 242 | void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, |
| 243 | const std::string& game_path); | 243 | const std::string& game_path); |
| 244 | void OnTransferableShaderCacheOpenFile(u64 program_id); | 244 | void OnTransferableShaderCacheOpenFile(u64 program_id); |