[vfs] remove usage of 'dynamic_cast', use ankerl::map for files (#3594)
Do I need to writeout everything wrong with `dynamic_cast`? Also the usual std::map -> `ankerl::unordered_dense::map` conversion, seems to work just fine - but of course test that updates/DLCs/mods/cheats/etc are still being applied :) Signed-off-by: lizzie <lizzie@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3594 Reviewed-by: DraVee <dravee@eden-emu.dev> Reviewed-by: MaranBr <maranbr@eden-emu.dev> Co-authored-by: lizzie <lizzie@eden-emu.dev> Co-committed-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
parent
b6238d6df7
commit
bfc720152a
|
|
@ -806,10 +806,6 @@ void System::RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
|
|||
impl->content_provider->SetSlot(slot, provider);
|
||||
}
|
||||
|
||||
void System::ClearContentProvider(FileSys::ContentProviderUnionSlot slot) {
|
||||
impl->content_provider->ClearSlot(slot);
|
||||
}
|
||||
|
||||
const Reporter& System::GetReporter() const {
|
||||
return impl->reporter;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
||||
|
|
@ -358,10 +358,7 @@ public:
|
|||
[[nodiscard]] Service::FileSystem::FileSystemController& GetFileSystemController();
|
||||
[[nodiscard]] const Service::FileSystem::FileSystemController& GetFileSystemController() const;
|
||||
|
||||
void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
|
||||
FileSys::ContentProvider* provider);
|
||||
|
||||
void ClearContentProvider(FileSys::ContentProviderUnionSlot slot);
|
||||
void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot, FileSys::ContentProvider* provider);
|
||||
|
||||
[[nodiscard]] const Reporter& GetReporter() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -37,6 +40,7 @@ enum class ContentRecordType : u8 {
|
|||
HtmlDocument = 4,
|
||||
LegalInformation = 5,
|
||||
DeltaFragment = 6,
|
||||
Count,
|
||||
};
|
||||
|
||||
struct ContentRecord {
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
|||
bool checked_external = false;
|
||||
bool checked_manual = false;
|
||||
|
||||
const auto* content_union = dynamic_cast<const ContentProviderUnion*>(&content_provider);
|
||||
const auto* content_union = static_cast<const ContentProviderUnion*>(&content_provider);
|
||||
const auto update_tid = GetUpdateTitleID(title_id);
|
||||
|
||||
if (content_union) {
|
||||
|
|
@ -167,7 +167,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
|||
|
||||
// Also check ManualContentProvider (for Android)
|
||||
if (!checked_external) {
|
||||
const auto* manual_provider = dynamic_cast<const ManualContentProvider*>(
|
||||
const auto* manual_provider = static_cast<const ManualContentProvider*>(
|
||||
content_union->GetSlotProvider(ContentProviderUnionSlot::FrontendManual));
|
||||
if (manual_provider) {
|
||||
const auto manual_update_versions = manual_provider->ListUpdateVersions(update_tid);
|
||||
|
|
@ -243,7 +243,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
|||
|
||||
// Also try ManualContentProvider
|
||||
if (update == nullptr) {
|
||||
const auto* manual_provider = dynamic_cast<const ManualContentProvider*>(
|
||||
const auto* manual_provider = static_cast<const ManualContentProvider*>(
|
||||
content_union->GetSlotProvider(ContentProviderUnionSlot::FrontendManual));
|
||||
if (manual_provider) {
|
||||
auto file = manual_provider->GetEntryForVersion(update_tid, ContentRecordType::Program, *enabled_version);
|
||||
|
|
@ -570,7 +570,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
|
|||
bool checked_external = false;
|
||||
bool checked_manual = false;
|
||||
|
||||
const auto* content_union = dynamic_cast<const ContentProviderUnion*>(&content_provider);
|
||||
const auto* content_union = static_cast<const ContentProviderUnion*>(&content_provider);
|
||||
if (content_union) {
|
||||
// First, check ExternalContentProvider
|
||||
const auto* external_provider = content_union->GetExternalProvider();
|
||||
|
|
@ -592,7 +592,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
|
|||
}
|
||||
|
||||
if (!checked_external) {
|
||||
const auto* manual_provider = dynamic_cast<const ManualContentProvider*>(
|
||||
const auto* manual_provider = static_cast<const ManualContentProvider*>(
|
||||
content_union->GetSlotProvider(ContentProviderUnionSlot::FrontendManual));
|
||||
if (manual_provider) {
|
||||
const auto manual_update_versions = manual_provider->ListUpdateVersions(update_tid);
|
||||
|
|
@ -690,7 +690,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
|
|||
|
||||
std::vector<Patch> external_update_patches;
|
||||
|
||||
const auto* content_union = dynamic_cast<const ContentProviderUnion*>(&content_provider);
|
||||
const auto* content_union = static_cast<const ContentProviderUnion*>(&content_provider);
|
||||
|
||||
if (content_union) {
|
||||
// First, check ExternalContentProvider for updates
|
||||
|
|
@ -721,7 +721,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
|
|||
}
|
||||
}
|
||||
|
||||
const auto* manual_provider = dynamic_cast<const ManualContentProvider*>(
|
||||
const auto* manual_provider = static_cast<const ManualContentProvider*>(
|
||||
content_union->GetSlotProvider(ContentProviderUnionSlot::FrontendManual));
|
||||
if (manual_provider && external_update_patches.empty()) {
|
||||
const auto manual_update_versions = manual_provider->ListUpdateVersions(update_tid);
|
||||
|
|
|
|||
|
|
@ -353,8 +353,7 @@ VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
|
|||
return file;
|
||||
}
|
||||
|
||||
static std::optional<NcaID> CheckMapForContentRecord(const std::map<u64, CNMT>& map, u64 title_id,
|
||||
ContentRecordType type) {
|
||||
static std::optional<NcaID> CheckMapForContentRecord(const ankerl::unordered_dense::map<u64, CNMT>& map, u64 title_id, ContentRecordType type) {
|
||||
const auto cmnt_iter = map.find(title_id);
|
||||
if (cmnt_iter == map.cend()) {
|
||||
return std::nullopt;
|
||||
|
|
@ -829,133 +828,96 @@ bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) {
|
|||
}
|
||||
}
|
||||
Refresh();
|
||||
return std::find_if(yuzu_meta.begin(), yuzu_meta.end(),
|
||||
[&cnmt](const std::pair<u64, CNMT>& kv) {
|
||||
return kv.second.GetType() == cnmt.GetType() &&
|
||||
kv.second.GetTitleID() == cnmt.GetTitleID();
|
||||
}) != yuzu_meta.end();
|
||||
return std::find_if(yuzu_meta.begin(), yuzu_meta.end(), [&cnmt](const std::pair<u64, CNMT>& kv) {
|
||||
return kv.second.GetType() == cnmt.GetType() && kv.second.GetTitleID() == cnmt.GetTitleID();
|
||||
}) != yuzu_meta.end();
|
||||
}
|
||||
|
||||
ContentProviderUnion::~ContentProviderUnion() = default;
|
||||
|
||||
void ContentProviderUnion::SetSlot(ContentProviderUnionSlot slot, ContentProvider* provider) {
|
||||
providers[slot] = provider;
|
||||
}
|
||||
|
||||
void ContentProviderUnion::ClearSlot(ContentProviderUnionSlot slot) {
|
||||
providers[slot] = nullptr;
|
||||
providers[size_t(slot)] = provider;
|
||||
}
|
||||
|
||||
void ContentProviderUnion::Refresh() {
|
||||
for (auto& provider : providers) {
|
||||
if (provider.second == nullptr)
|
||||
continue;
|
||||
|
||||
provider.second->Refresh();
|
||||
}
|
||||
for (auto e : providers)
|
||||
if (e != nullptr)
|
||||
e->Refresh();
|
||||
}
|
||||
|
||||
bool ContentProviderUnion::HasEntry(u64 title_id, ContentRecordType type) const {
|
||||
for (const auto& provider : providers) {
|
||||
if (provider.second == nullptr)
|
||||
continue;
|
||||
|
||||
if (provider.second->HasEntry(title_id, type))
|
||||
for (auto const e : providers)
|
||||
if (e && e->HasEntry(title_id, type))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<u32> ContentProviderUnion::GetEntryVersion(u64 title_id) const {
|
||||
for (const auto& provider : providers) {
|
||||
if (provider.second == nullptr)
|
||||
for (auto const e : providers) {
|
||||
if (e == nullptr)
|
||||
continue;
|
||||
|
||||
const auto res = provider.second->GetEntryVersion(title_id);
|
||||
if (res != std::nullopt)
|
||||
if (auto const res = e->GetEntryVersion(title_id); res != std::nullopt)
|
||||
return res;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
VirtualFile ContentProviderUnion::GetEntryUnparsed(u64 title_id, ContentRecordType type) const {
|
||||
for (const auto& provider : providers) {
|
||||
if (provider.second == nullptr)
|
||||
for (auto const e : providers) {
|
||||
if (e == nullptr)
|
||||
continue;
|
||||
|
||||
const auto res = provider.second->GetEntryUnparsed(title_id, type);
|
||||
if (res != nullptr)
|
||||
if (auto const res = e->GetEntryUnparsed(title_id, type); res != nullptr)
|
||||
return res;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VirtualFile ContentProviderUnion::GetEntryRaw(u64 title_id, ContentRecordType type) const {
|
||||
for (const auto& provider : providers) {
|
||||
if (provider.second == nullptr)
|
||||
for (auto const e : providers) {
|
||||
if (e == nullptr)
|
||||
continue;
|
||||
|
||||
const auto res = provider.second->GetEntryRaw(title_id, type);
|
||||
if (res != nullptr)
|
||||
if (auto const res = e->GetEntryRaw(title_id, type); res != nullptr)
|
||||
return res;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<NCA> ContentProviderUnion::GetEntry(u64 title_id, ContentRecordType type) const {
|
||||
for (const auto& provider : providers) {
|
||||
if (provider.second == nullptr)
|
||||
for (auto const e : providers) {
|
||||
if (e == nullptr)
|
||||
continue;
|
||||
|
||||
auto res = provider.second->GetEntry(title_id, type);
|
||||
if (res != nullptr)
|
||||
if (auto res = e->GetEntry(title_id, type); res != nullptr)
|
||||
return res;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<ContentProviderEntry> ContentProviderUnion::ListEntriesFilter(
|
||||
std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
|
||||
std::optional<u64> title_id) const {
|
||||
std::vector<ContentProviderEntry> ContentProviderUnion::ListEntriesFilter(std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type, std::optional<u64> title_id) const {
|
||||
std::vector<ContentProviderEntry> out;
|
||||
|
||||
for (const auto& provider : providers) {
|
||||
if (provider.second == nullptr)
|
||||
continue;
|
||||
|
||||
const auto vec = provider.second->ListEntriesFilter(title_type, record_type, title_id);
|
||||
std::copy(vec.begin(), vec.end(), std::back_inserter(out));
|
||||
for (auto const& e : providers) {
|
||||
if (e != nullptr) {
|
||||
auto const vec = e->ListEntriesFilter(title_type, record_type, title_id);
|
||||
std::copy(vec.begin(), vec.end(), std::back_inserter(out));
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(out.begin(), out.end());
|
||||
out.erase(std::unique(out.begin(), out.end()), out.end());
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>>
|
||||
ContentProviderUnion::ListEntriesFilterOrigin(std::optional<ContentProviderUnionSlot> origin,
|
||||
std::optional<TitleType> title_type,
|
||||
std::optional<ContentRecordType> record_type,
|
||||
std::optional<u64> title_id) const {
|
||||
std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>> ContentProviderUnion::ListEntriesFilterOrigin(std::optional<ContentProviderUnionSlot> origin, std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type, std::optional<u64> title_id) const {
|
||||
std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>> out;
|
||||
|
||||
for (const auto& provider : providers) {
|
||||
if (provider.second == nullptr)
|
||||
for (size_t i = 0; i < providers.size(); ++i) {
|
||||
auto const& e = providers[i];
|
||||
if (e == nullptr)
|
||||
continue;
|
||||
|
||||
if (origin.has_value() && *origin != provider.first)
|
||||
if (origin.has_value() && *origin != ContentProviderUnionSlot(i))
|
||||
continue;
|
||||
|
||||
const auto vec = provider.second->ListEntriesFilter(title_type, record_type, title_id);
|
||||
std::transform(vec.begin(), vec.end(), std::back_inserter(out),
|
||||
[&provider](const ContentProviderEntry& entry) {
|
||||
return std::make_pair(provider.first, entry);
|
||||
});
|
||||
auto const vec = e->ListEntriesFilter(title_type, record_type, title_id);
|
||||
std::transform(vec.begin(), vec.end(), std::back_inserter(out), [i](const ContentProviderEntry& entry) {
|
||||
return std::make_pair(ContentProviderUnionSlot(i), entry);
|
||||
});
|
||||
}
|
||||
|
||||
std::sort(out.begin(), out.end());
|
||||
|
|
@ -963,40 +925,22 @@ ContentProviderUnion::ListEntriesFilterOrigin(std::optional<ContentProviderUnion
|
|||
return out;
|
||||
}
|
||||
|
||||
std::optional<ContentProviderUnionSlot> ContentProviderUnion::GetSlotForEntry(
|
||||
u64 title_id, ContentRecordType type) const {
|
||||
const auto iter =
|
||||
std::find_if(providers.begin(), providers.end(), [title_id, type](const auto& provider) {
|
||||
return provider.second != nullptr && provider.second->HasEntry(title_id, type);
|
||||
});
|
||||
|
||||
if (iter == providers.end()) {
|
||||
return std::nullopt;
|
||||
std::optional<ContentProviderUnionSlot> ContentProviderUnion::GetSlotForEntry(u64 title_id, ContentRecordType type) const {
|
||||
for (size_t i = 0; i < providers.size(); ++i) {
|
||||
auto const& e = providers[i];
|
||||
if (e != nullptr && e->HasEntry(title_id, type))
|
||||
return {ContentProviderUnionSlot(i)};
|
||||
}
|
||||
|
||||
return iter->first;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const ExternalContentProvider* ContentProviderUnion::GetExternalProvider() const {
|
||||
auto it = providers.find(ContentProviderUnionSlot::External);
|
||||
if (it != providers.end() && it->second != nullptr) {
|
||||
return dynamic_cast<const ExternalContentProvider*>(it->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ContentProvider* ContentProviderUnion::GetSlotProvider(ContentProviderUnionSlot slot) const {
|
||||
auto it = providers.find(slot);
|
||||
if (it != providers.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
return static_cast<const ExternalContentProvider*>(providers[size_t(ContentProviderUnionSlot::External)]);
|
||||
}
|
||||
|
||||
ManualContentProvider::~ManualContentProvider() = default;
|
||||
|
||||
void ManualContentProvider::AddEntry(TitleType title_type, ContentRecordType content_type,
|
||||
u64 title_id, VirtualFile file) {
|
||||
void ManualContentProvider::AddEntry(TitleType title_type, ContentRecordType content_type, u64 title_id, VirtualFile file) {
|
||||
entries.insert_or_assign({title_type, content_type, title_id}, file);
|
||||
}
|
||||
|
||||
|
|
@ -1004,14 +948,13 @@ void ManualContentProvider::AddEntryWithVersion(TitleType title_type, ContentRec
|
|||
u64 title_id, u32 version,
|
||||
const std::string& version_string, VirtualFile file) {
|
||||
if (title_type == TitleType::Update) {
|
||||
auto it = std::find_if(multi_version_entries.begin(), multi_version_entries.end(),
|
||||
[title_id, version](const ExternalUpdateEntry& entry) {
|
||||
return entry.title_id == title_id && entry.version == version;
|
||||
});
|
||||
auto it = std::find_if(multi_version_entries.begin(), multi_version_entries.end(), [title_id, version](const ExternalUpdateEntry& entry) {
|
||||
return entry.title_id == title_id && entry.version == version;
|
||||
});
|
||||
|
||||
if (it != multi_version_entries.end()) {
|
||||
// Update existing entry
|
||||
it->files[content_type] = file;
|
||||
it->files[size_t(content_type)] = file;
|
||||
if (!version_string.empty()) {
|
||||
it->version_string = version_string;
|
||||
}
|
||||
|
|
@ -1021,7 +964,7 @@ void ManualContentProvider::AddEntryWithVersion(TitleType title_type, ContentRec
|
|||
new_entry.title_id = title_id;
|
||||
new_entry.version = version;
|
||||
new_entry.version_string = version_string;
|
||||
new_entry.files[content_type] = file;
|
||||
new_entry.files[size_t(content_type)] = file;
|
||||
multi_version_entries.push_back(new_entry);
|
||||
}
|
||||
|
||||
|
|
@ -1118,26 +1061,19 @@ std::vector<ExternalUpdateEntry> ManualContentProvider::ListUpdateVersions(u64 t
|
|||
VirtualFile ManualContentProvider::GetEntryForVersion(u64 title_id, ContentRecordType type, u32 version) const {
|
||||
for (const auto& entry : multi_version_entries) {
|
||||
if (entry.title_id == title_id && entry.version == version) {
|
||||
auto it = entry.files.find(type);
|
||||
if (it != entry.files.end()) {
|
||||
return it->second;
|
||||
}
|
||||
if (auto const p = entry.files[size_t(type)])
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ManualContentProvider::HasMultipleVersions(u64 title_id, ContentRecordType type) const {
|
||||
int count = 0;
|
||||
for (const auto& entry : multi_version_entries) {
|
||||
if (entry.title_id == title_id && entry.files.count(type) > 0) {
|
||||
count++;
|
||||
if (count > 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
size_t count = 0;
|
||||
for (const auto& entry : multi_version_entries)
|
||||
if (entry.title_id == title_id && entry.files[size_t(type)])
|
||||
++count;
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
ExternalContentProvider::ExternalContentProvider(std::vector<VirtualDir> load_directories)
|
||||
|
|
@ -1256,7 +1192,7 @@ void ExternalContentProvider::ProcessNSP(const VirtualFile& file) {
|
|||
}
|
||||
}
|
||||
|
||||
std::map<std::pair<u64, u32>, std::map<ContentRecordType, VirtualFile>> version_files;
|
||||
std::map<std::pair<u64, u32>, std::array<VirtualFile, size_t(ContentRecordType::Count)>> version_files;
|
||||
|
||||
for (const auto& [title_id, nca_map] : ncas) {
|
||||
for (const auto& [type_pair, nca] : nca_map) {
|
||||
|
|
@ -1277,7 +1213,7 @@ void ExternalContentProvider::ProcessNSP(const VirtualFile& file) {
|
|||
version = ver_it->second;
|
||||
}
|
||||
|
||||
version_files[{title_id, version}][content_type] = nca_file;
|
||||
version_files[{title_id, version}][size_t(content_type)] = nca_file;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Service_FS, "Added entry - Title ID: {:016X}, Type: {}, Content: {}",
|
||||
|
|
@ -1298,9 +1234,7 @@ void ExternalContentProvider::ProcessNSP(const VirtualFile& file) {
|
|||
bool version_exists = false;
|
||||
for (auto& existing : multi_version_entries) {
|
||||
if (existing.title_id == title_id && existing.version == version) {
|
||||
for (const auto& [content_type, _file] : files_map) {
|
||||
existing.files[content_type] = _file;
|
||||
}
|
||||
existing.files = files_map;
|
||||
if (existing.version_string.empty() && !ver_str.empty()) {
|
||||
existing.version_string = ver_str;
|
||||
}
|
||||
|
|
@ -1383,7 +1317,7 @@ void ExternalContentProvider::ProcessXCI(const VirtualFile& file) {
|
|||
}
|
||||
}
|
||||
|
||||
std::map<std::pair<u64, u32>, std::map<ContentRecordType, VirtualFile>> version_files;
|
||||
std::map<std::pair<u64, u32>, std::array<VirtualFile, size_t(ContentRecordType::Count)>> version_files;
|
||||
|
||||
for (const auto& [title_id, nca_map] : ncas) {
|
||||
for (const auto& [type_pair, nca] : nca_map) {
|
||||
|
|
@ -1404,7 +1338,7 @@ void ExternalContentProvider::ProcessXCI(const VirtualFile& file) {
|
|||
version = ver_it->second;
|
||||
}
|
||||
|
||||
version_files[{title_id, version}][content_type] = nca_file;
|
||||
version_files[{title_id, version}][size_t(content_type)] = nca_file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1422,9 +1356,7 @@ void ExternalContentProvider::ProcessXCI(const VirtualFile& file) {
|
|||
bool version_exists = false;
|
||||
for (auto& existing : multi_version_entries) {
|
||||
if (existing.title_id == title_id && existing.version == version) {
|
||||
for (const auto& [content_type, _file] : files_map) {
|
||||
existing.files[content_type] = _file;
|
||||
}
|
||||
existing.files = files_map;
|
||||
if (existing.version_string.empty() && !ver_str.empty()) {
|
||||
existing.version_string = ver_str;
|
||||
}
|
||||
|
|
@ -1529,28 +1461,19 @@ std::vector<ExternalUpdateEntry> ExternalContentProvider::ListUpdateVersions(u64
|
|||
}
|
||||
|
||||
VirtualFile ExternalContentProvider::GetEntryForVersion(u64 title_id, ContentRecordType type, u32 version) const {
|
||||
for (const auto& entry : multi_version_entries) {
|
||||
if (entry.title_id == title_id && entry.version == version) {
|
||||
auto it = entry.files.find(type);
|
||||
if (it != entry.files.end()) {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto& entry : multi_version_entries)
|
||||
if (entry.title_id == title_id && entry.version == version)
|
||||
if (auto const p = entry.files[size_t(type)])
|
||||
return p;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ExternalContentProvider::HasMultipleVersions(u64 title_id, ContentRecordType type) const {
|
||||
size_t count = 0;
|
||||
for (const auto& entry : multi_version_entries) {
|
||||
if (entry.title_id == title_id && entry.files.count(type) > 0) {
|
||||
count++;
|
||||
if (count > 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
for (const auto& entry : multi_version_entries)
|
||||
if (entry.title_id == title_id && entry.files[size_t(type)])
|
||||
++count;
|
||||
return count > 1;
|
||||
}
|
||||
|
||||
} // namespace FileSys
|
||||
|
|
|
|||
|
|
@ -11,19 +11,19 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ankerl/unordered_dense.h>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
#include "core/file_sys/nca_metadata.h"
|
||||
|
||||
namespace FileSys {
|
||||
class ExternalContentProvider;
|
||||
class CNMT;
|
||||
class ExternalContentProvider;
|
||||
class CNMT;
|
||||
class NCA;
|
||||
class NSP;
|
||||
class XCI;
|
||||
|
||||
enum class ContentRecordType : u8;
|
||||
enum class NCAContentType : u8;
|
||||
enum class TitleType : u8;
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ struct ExternalUpdateEntry {
|
|||
u64 title_id;
|
||||
u32 version;
|
||||
std::string version_string;
|
||||
std::map<ContentRecordType, VirtualFile> files;
|
||||
std::array<VirtualFile, size_t(ContentRecordType::Count)> files;
|
||||
};
|
||||
|
||||
constexpr u64 GetUpdateTitleID(u64 base_title_id) {
|
||||
|
|
@ -207,11 +207,11 @@ private:
|
|||
ContentProviderParsingFunction parser;
|
||||
|
||||
// maps tid -> NcaID of meta
|
||||
std::map<u64, NcaID> meta_id;
|
||||
ankerl::unordered_dense::map<u64, NcaID> meta_id;
|
||||
// maps tid -> meta
|
||||
std::map<u64, CNMT> meta;
|
||||
ankerl::unordered_dense::map<u64, CNMT> meta;
|
||||
// maps tid -> meta for CNMT in yuzu_meta
|
||||
std::map<u64, CNMT> yuzu_meta;
|
||||
ankerl::unordered_dense::map<u64, CNMT> yuzu_meta;
|
||||
};
|
||||
|
||||
enum class ContentProviderUnionSlot {
|
||||
|
|
@ -220,6 +220,7 @@ enum class ContentProviderUnionSlot {
|
|||
SDMC, ///< SD Card
|
||||
FrontendManual, ///< Frontend-defined game list or similar
|
||||
External, ///< External content from NSP/XCI files in configured directories
|
||||
Count,
|
||||
};
|
||||
|
||||
// Combines multiple ContentProvider(s) (i.e. SysNAND, UserNAND, SDMC) into one interface.
|
||||
|
|
@ -228,8 +229,6 @@ public:
|
|||
~ContentProviderUnion() override;
|
||||
|
||||
void SetSlot(ContentProviderUnionSlot slot, ContentProvider* provider);
|
||||
void ClearSlot(ContentProviderUnionSlot slot);
|
||||
|
||||
void Refresh() override;
|
||||
bool HasEntry(u64 title_id, ContentRecordType type) const override;
|
||||
std::optional<u32> GetEntryVersion(u64 title_id) const override;
|
||||
|
|
@ -241,18 +240,18 @@ public:
|
|||
std::optional<u64> title_id) const override;
|
||||
|
||||
const ExternalContentProvider* GetExternalProvider() const;
|
||||
const ContentProvider* GetSlotProvider(ContentProviderUnionSlot slot) const;
|
||||
[[nodiscard]] inline const ContentProvider* GetSlotProvider(ContentProviderUnionSlot slot) const {
|
||||
return providers[size_t(slot)];
|
||||
}
|
||||
|
||||
std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>> ListEntriesFilterOrigin(
|
||||
std::optional<ContentProviderUnionSlot> origin = {},
|
||||
std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
|
||||
std::optional<u64> title_id = {}) const;
|
||||
|
||||
std::optional<ContentProviderUnionSlot> GetSlotForEntry(u64 title_id,
|
||||
ContentRecordType type) const;
|
||||
|
||||
std::optional<ContentProviderUnionSlot> GetSlotForEntry(u64 title_id, ContentRecordType type) const;
|
||||
private:
|
||||
std::map<ContentProviderUnionSlot, ContentProvider*> providers;
|
||||
std::array<ContentProvider*, size_t(ContentProviderUnionSlot::Count)> providers;
|
||||
};
|
||||
|
||||
class ManualContentProvider : public ContentProvider {
|
||||
|
|
@ -312,8 +311,8 @@ private:
|
|||
void ProcessXCI(const VirtualFile& file);
|
||||
|
||||
std::vector<VirtualDir> load_dirs;
|
||||
std::map<std::tuple<u64, ContentRecordType, TitleType>, VirtualFile> entries;
|
||||
std::map<u64, u32> versions;
|
||||
ankerl::unordered_dense::map<std::tuple<u64, ContentRecordType, TitleType>, VirtualFile> entries;
|
||||
ankerl::unordered_dense::map<u64, u32> versions;
|
||||
std::vector<ExternalUpdateEntry> multi_version_entries;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ public:
|
|||
}
|
||||
|
||||
void SwapBuffers() override {
|
||||
if (auto window = dynamic_cast<QWindow*>(surface)) {
|
||||
if (auto window = static_cast<QWindow*>(surface)) {
|
||||
if (!window->isExposed()) {
|
||||
LOG_DEBUG(Frontend, "SwapBuffers ignored: window not exposed");
|
||||
return;
|
||||
|
|
|
|||
Loading…
Reference in New Issue