Browse Source

fix version display + loading

fs_external_dlcupdates
unknown 2 months ago
committed by crueter
parent
commit
695ae6a71f
  1. 189
      src/core/file_sys/patch_manager.cpp
  2. 4
      src/yuzu/game_list_worker.cpp

189
src/core/file_sys/patch_manager.cpp

@ -9,6 +9,8 @@
#include <cstddef>
#include <cstring>
#include <set>
#include <string>
#include <vector>
#include "common/hex_util.h"
#include "common/logging/log.h"
@ -65,6 +67,30 @@ std::string FormatTitleVersion(u32 version,
return fmt::format("v{}.{}.{}", bytes[3], bytes[2], bytes[1]);
}
static std::array<int, 4> ParseVersionComponents(std::string_view label) {
std::array<int, 4> out{0, 0, 0, 0};
if (!label.empty() && (label.front() == 'v' || label.front() == 'V')) {
label.remove_prefix(1);
}
size_t part = 0;
size_t start = 0;
std::string s(label);
while (part < out.size() && start < s.size()) {
size_t dot = s.find('.', start);
auto token = s.substr(start, dot == std::string::npos ? std::string::npos : dot - start);
try {
out[part] = std::stoi(token);
} catch (...) {
out[part] = 0;
}
++part;
if (dot == std::string::npos)
break;
start = dot + 1;
}
return out;
}
// Returns a directory with name matching name case-insensitive. Returns nullptr if directory
// doesn't have a directory with name.
VirtualDir FindSubdirectoryCaseless(const VirtualDir dir, std::string_view name) {
@ -563,6 +589,30 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
} else {
LOG_WARNING(Loader, " RomFS: Update NCA is not valid");
}
} else if (!update_disabled && base_nca != nullptr) {
ContentRecordType alt_type = type;
if (type == ContentRecordType::Program) {
alt_type = ContentRecordType::Data;
} else if (type == ContentRecordType::Data) {
alt_type = ContentRecordType::Program;
}
if (alt_type != type) {
const auto alt_update_raw =
content_provider.GetEntryRaw(*selected_update_tid, alt_type);
if (alt_update_raw != nullptr) {
const auto new_nca = std::make_shared<NCA>(alt_update_raw, base_nca);
if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
new_nca->GetRomFS() != nullptr) {
LOG_INFO(Loader, " RomFS: Update (fallback {}) applied successfully",
alt_type == ContentRecordType::Data ? "DATA" : "PROGRAM");
romfs = new_nca->GetRomFS();
} else {
LOG_WARNING(Loader, " RomFS: Update (fallback) NCA is not valid");
}
}
}
} else if (!update_disabled && packed_update_raw != nullptr && base_nca != nullptr) {
const auto new_nca = std::make_shared<NCA>(packed_update_raw, base_nca);
if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
@ -590,74 +640,87 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
std::vector<Patch> out;
const auto& disabled = Settings::values.disabled_addons[title_id];
// Game Updates (default latest)
const auto update_tid = GetUpdateTitleID(title_id);
PatchManager update{update_tid, fs_controller, content_provider};
const auto metadata = update.GetControlMetadata();
const auto update_disabled =
std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend();
Patch update_patch = {.enabled = !update_disabled,
.name = "Update",
.version = "",
.type = PatchType::Update,
.program_id = title_id,
.title_id = title_id};
auto variant_tids =
EnumerateUpdateVariants(content_provider, title_id, ContentRecordType::Program);
{
auto data_tids =
EnumerateUpdateVariants(content_provider, title_id, ContentRecordType::Data);
variant_tids.insert(variant_tids.end(), data_tids.begin(), data_tids.end());
auto control_tids =
EnumerateUpdateVariants(content_provider, title_id, ContentRecordType::Control);
variant_tids.insert(variant_tids.end(), control_tids.begin(), control_tids.end());
std::sort(variant_tids.begin(), variant_tids.end());
variant_tids.erase(std::unique(variant_tids.begin(), variant_tids.end()),
variant_tids.end());
}
if (!variant_tids.empty()) {
const auto update_disabled =
std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend();
out.push_back({.enabled = !update_disabled,
.name = "Update",
.version = "",
.type = PatchType::Update,
.program_id = title_id,
.title_id = title_id});
std::optional<u64> selected_variant_tid;
if (!update_disabled) {
const bool has_pref = HasVariantPreference(Settings::values.disabled_addons[title_id]);
if (has_pref) {
selected_variant_tid = ChooseUpdateVariant(
content_provider, title_id, ContentRecordType::Program, fs_controller);
} else {
selected_variant_tid = GetUpdateTitleID(title_id);
}
}
out.push_back(update_patch);
std::vector<std::pair<std::string, u64>> variant_labels;
variant_labels.reserve(variant_tids.size());
std::optional<u64> selected_variant_tid;
if (!update_disabled) {
const bool has_pref = HasVariantPreference(Settings::values.disabled_addons[title_id]);
if (has_pref) {
selected_variant_tid = ChooseUpdateVariant(content_provider, title_id,
ContentRecordType::Program, fs_controller);
} else {
selected_variant_tid = GetUpdateTitleID(title_id);
for (const auto tid : variant_tids) {
variant_labels.emplace_back(GetUpdateVersionLabel(tid, fs_controller, content_provider),
tid);
}
}
const auto variant_tids =
EnumerateUpdateVariants(content_provider, title_id, ContentRecordType::Program);
std::vector<std::pair<std::string, u64>> variant_labels;
variant_labels.reserve(variant_tids.size());
for (const auto tid : variant_tids) {
variant_labels.emplace_back(GetUpdateVersionLabel(tid, fs_controller, content_provider),
tid);
}
std::sort(variant_labels.begin(), variant_labels.end(), [this](auto const& a, auto const& b) {
const auto va = content_provider.GetEntryVersion(a.second).value_or(0);
const auto vb = content_provider.GetEntryVersion(b.second).value_or(0);
if (va != vb)
return va > vb;
return a.first < b.first;
});
std::set<std::string> seen_versions;
if (!out.empty() && !out.back().version.empty()) {
auto ver = out.back().version;
if (!ver.empty() && (ver.front() == 'v' || ver.front() == 'V')) {
ver.erase(ver.begin());
}
seen_versions.insert(std::move(ver));
}
for (const auto& [label, tid] : variant_labels) {
std::string version = label;
if (!version.empty() && (version.front() == 'v' || version.front() == 'V')) {
version.erase(version.begin());
}
if (seen_versions.find(version) != seen_versions.end()) {
continue;
std::sort(variant_labels.begin(), variant_labels.end(),
[this](auto const& a, auto const& b) {
const auto va = content_provider.GetEntryVersion(a.second).value_or(0);
const auto vb = content_provider.GetEntryVersion(b.second).value_or(0);
if (va != vb)
return va > vb;
const auto ca = ParseVersionComponents(a.first);
const auto cb = ParseVersionComponents(b.first);
if (ca != cb)
return ca > cb;
return a.first > b.first;
});
std::set<std::string> seen_versions;
for (const auto& [label, tid] : variant_labels) {
std::string version = label;
if (!version.empty() && (version.front() == 'v' || version.front() == 'V')) {
version.erase(version.begin());
}
if (seen_versions.find(version) != seen_versions.end()) {
continue;
}
const bool is_selected =
selected_variant_tid.has_value() && tid == *selected_variant_tid;
const bool variant_disabled = update_disabled || !is_selected;
out.push_back({.enabled = !variant_disabled,
.name = "Update",
.version = version,
.type = PatchType::Update,
.program_id = title_id,
.title_id = tid});
seen_versions.insert(version);
}
const auto toggle_name = fmt::format("Update {}", label);
const bool is_selected = selected_variant_tid.has_value() && tid == *selected_variant_tid;
const bool variant_disabled = update_disabled || !is_selected;
out.push_back({.enabled = !variant_disabled,
.name = "Update",
.version = version,
.type = PatchType::Update,
.program_id = title_id,
.title_id = tid});
seen_versions.insert(version);
}
// General Mods (LayeredFS and IPS)

4
src/yuzu/game_list_worker.cpp

@ -173,6 +173,10 @@ QString FormatPatchNameVersions(const FileSys::PatchManager& patch_manager,
continue;
}
if (is_update && patch.version.empty()) {
continue;
}
const QString type =
QString::fromStdString(patch.enabled ? patch.name : "[D] " + patch.name);

Loading…
Cancel
Save