|
|
@ -9,6 +9,7 @@ |
|
|
#include <cstddef>
|
|
|
#include <cstddef>
|
|
|
#include <cstring>
|
|
|
#include <cstring>
|
|
|
|
|
|
|
|
|
|
|
|
#include "common/assert.h"
|
|
|
#include "common/hex_util.h"
|
|
|
#include "common/hex_util.h"
|
|
|
#include "common/logging.h"
|
|
|
#include "common/logging.h"
|
|
|
#include "common/settings.h"
|
|
|
#include "common/settings.h"
|
|
|
@ -156,12 +157,15 @@ std::string GetUpdateVersionStringFromSlot(const ContentProvider* provider, u64 |
|
|
NACP nacp{nacp_file}; |
|
|
NACP nacp{nacp_file}; |
|
|
return nacp.GetVersionString(); |
|
|
return nacp.GetVersionString(); |
|
|
} |
|
|
} |
|
|
|
|
|
YUZU_NO_INLINE std::optional<u64> GetParentApplicationId(const ContentProvider* provider, u64 title_id) { |
|
|
|
|
|
return provider == nullptr ? std::nullopt : provider->GetParentApplicationId(title_id); |
|
|
|
|
|
} |
|
|
} // Anonymous namespace
|
|
|
} // Anonymous namespace
|
|
|
|
|
|
|
|
|
PatchManager::PatchManager(u64 title_id_, |
|
|
PatchManager::PatchManager(u64 title_id_, |
|
|
const Service::FileSystem::FileSystemController& fs_controller_, |
|
|
const Service::FileSystem::FileSystemController& fs_controller_, |
|
|
const ContentProvider& content_provider_) |
|
|
const ContentProvider& content_provider_) |
|
|
: title_id{title_id_}, fs_controller{fs_controller_}, content_provider{content_provider_} {} |
|
|
|
|
|
|
|
|
: title_id{title_id_}, parent_title_id{GetParentApplicationId(std::addressof(content_provider_), title_id_)}, fs_controller{fs_controller_}, content_provider{content_provider_} {} |
|
|
|
|
|
|
|
|
PatchManager::~PatchManager() = default; |
|
|
PatchManager::~PatchManager() = default; |
|
|
|
|
|
|
|
|
@ -169,13 +173,35 @@ u64 PatchManager::GetTitleID() const { |
|
|
return title_id; |
|
|
return title_id; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
VirtualDir PatchManager::GetModificationLoadRoot(bool sdmc) const { |
|
|
|
|
|
const auto get_root = [&](u64 id) { |
|
|
|
|
|
return sdmc ? fs_controller.GetSDMCModificationLoadRoot(id) : fs_controller.GetModificationLoadRoot(id); |
|
|
|
|
|
}; |
|
|
|
|
|
auto root = get_root(title_id); |
|
|
|
|
|
if (!parent_title_id) { |
|
|
|
|
|
return root; |
|
|
|
|
|
} |
|
|
|
|
|
std::vector<VirtualDir> roots{std::move(root), get_root(*parent_title_id)}; |
|
|
|
|
|
std::erase(roots, nullptr); |
|
|
|
|
|
return LayeredVfsDirectory::MakeLayeredDirectory(std::move(roots)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> PatchManager::GetDisabledAddons() const { |
|
|
|
|
|
auto disabled = Settings::values.disabled_addons[title_id]; |
|
|
|
|
|
if (parent_title_id) { |
|
|
|
|
|
const auto& shared = Settings::values.disabled_addons[*parent_title_id]; |
|
|
|
|
|
disabled.insert(disabled.end(), shared.begin(), shared.end()); |
|
|
|
|
|
} |
|
|
|
|
|
return disabled; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { |
|
|
VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { |
|
|
LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id); |
|
|
LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id); |
|
|
|
|
|
|
|
|
if (exefs == nullptr) |
|
|
if (exefs == nullptr) |
|
|
return exefs; |
|
|
return exefs; |
|
|
|
|
|
|
|
|
const auto& disabled = Settings::values.disabled_addons[title_id]; |
|
|
|
|
|
|
|
|
const auto disabled = GetDisabledAddons(); |
|
|
|
|
|
|
|
|
bool update_disabled = true; |
|
|
bool update_disabled = true; |
|
|
std::optional<u32> enabled_version; |
|
|
std::optional<u32> enabled_version; |
|
|
@ -303,8 +329,8 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// LayeredExeFS
|
|
|
// LayeredExeFS
|
|
|
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); |
|
|
|
|
|
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); |
|
|
|
|
|
|
|
|
const auto load_dir = GetModificationLoadRoot(); |
|
|
|
|
|
const auto sdmc_load_dir = GetModificationLoadRoot(true); |
|
|
|
|
|
|
|
|
std::vector<VirtualDir> patch_dirs = {sdmc_load_dir}; |
|
|
std::vector<VirtualDir> patch_dirs = {sdmc_load_dir}; |
|
|
if (load_dir != nullptr) { |
|
|
if (load_dir != nullptr) { |
|
|
@ -346,7 +372,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualDir>& patch_dirs, const std::string& build_id) const { |
|
|
std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualDir>& patch_dirs, const std::string& build_id) const { |
|
|
const auto& disabled = Settings::values.disabled_addons[title_id]; |
|
|
|
|
|
|
|
|
const auto disabled = GetDisabledAddons(); |
|
|
const auto nso_build_id = fmt::format("{:0<64}", build_id); |
|
|
const auto nso_build_id = fmt::format("{:0<64}", build_id); |
|
|
|
|
|
|
|
|
std::vector<VirtualFile> out; |
|
|
std::vector<VirtualFile> out; |
|
|
@ -405,7 +431,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st |
|
|
|
|
|
|
|
|
LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id); |
|
|
LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id); |
|
|
|
|
|
|
|
|
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); |
|
|
|
|
|
|
|
|
const auto load_dir = GetModificationLoadRoot(); |
|
|
if (load_dir == nullptr) { |
|
|
if (load_dir == nullptr) { |
|
|
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); |
|
|
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); |
|
|
return nso; |
|
|
return nso; |
|
|
@ -448,7 +474,7 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_, std::string_view name) |
|
|
|
|
|
|
|
|
LOG_INFO(Loader, "Querying NSO patch existence for build_id={}, name={}", build_id, name); |
|
|
LOG_INFO(Loader, "Querying NSO patch existence for build_id={}, name={}", build_id, name); |
|
|
|
|
|
|
|
|
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); |
|
|
|
|
|
|
|
|
const auto load_dir = GetModificationLoadRoot(); |
|
|
if (load_dir == nullptr) { |
|
|
if (load_dir == nullptr) { |
|
|
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); |
|
|
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); |
|
|
return false; |
|
|
return false; |
|
|
@ -462,13 +488,13 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_, std::string_view name) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildID& build_id_) const { |
|
|
std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildID& build_id_) const { |
|
|
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); |
|
|
|
|
|
|
|
|
const auto load_dir = GetModificationLoadRoot(); |
|
|
if (load_dir == nullptr) { |
|
|
if (load_dir == nullptr) { |
|
|
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); |
|
|
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); |
|
|
return {}; |
|
|
return {}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const auto& disabled = Settings::values.disabled_addons[title_id]; |
|
|
|
|
|
|
|
|
const auto disabled = GetDisabledAddons(); |
|
|
auto patch_dirs = load_dir->GetSubdirectories(); |
|
|
auto patch_dirs = load_dir->GetSubdirectories(); |
|
|
std::sort(patch_dirs.begin(), patch_dirs.end(), [](auto const& l, auto const& r) { return l->GetName() < r->GetName(); }); |
|
|
std::sort(patch_dirs.begin(), patch_dirs.end(), [](auto const& l, auto const& r) { return l->GetName() < r->GetName(); }); |
|
|
|
|
|
|
|
|
@ -502,17 +528,16 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildI |
|
|
return out; |
|
|
return out; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type, |
|
|
|
|
|
const Service::FileSystem::FileSystemController& fs_controller) { |
|
|
|
|
|
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); |
|
|
|
|
|
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); |
|
|
|
|
|
|
|
|
void PatchManager::ApplyLayeredFS(VirtualFile& romfs, ContentRecordType type) const { |
|
|
|
|
|
const auto load_dir = GetModificationLoadRoot(); |
|
|
|
|
|
const auto sdmc_load_dir = GetModificationLoadRoot(true); |
|
|
if ((type != ContentRecordType::Program && type != ContentRecordType::Data && |
|
|
if ((type != ContentRecordType::Program && type != ContentRecordType::Data && |
|
|
type != ContentRecordType::HtmlDocument) || |
|
|
type != ContentRecordType::HtmlDocument) || |
|
|
(load_dir == nullptr && sdmc_load_dir == nullptr)) { |
|
|
(load_dir == nullptr && sdmc_load_dir == nullptr)) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const auto& disabled = Settings::values.disabled_addons[title_id]; |
|
|
|
|
|
|
|
|
const auto disabled = GetDisabledAddons(); |
|
|
std::vector<VirtualDir> patch_dirs = load_dir->GetSubdirectories(); |
|
|
std::vector<VirtualDir> patch_dirs = load_dir->GetSubdirectories(); |
|
|
if (std::find(disabled.cbegin(), disabled.cend(), "SDMC") == disabled.cend()) { |
|
|
if (std::find(disabled.cbegin(), disabled.cend(), "SDMC") == disabled.cend()) { |
|
|
patch_dirs.push_back(sdmc_load_dir); |
|
|
patch_dirs.push_back(sdmc_load_dir); |
|
|
@ -591,7 +616,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs |
|
|
|
|
|
|
|
|
// Game Updates
|
|
|
// Game Updates
|
|
|
const auto update_tid = GetUpdateTitleID(title_id); |
|
|
const auto update_tid = GetUpdateTitleID(title_id); |
|
|
const auto& disabled = Settings::values.disabled_addons[title_id]; |
|
|
|
|
|
|
|
|
const auto disabled = GetDisabledAddons(); |
|
|
|
|
|
|
|
|
bool update_disabled = true; |
|
|
bool update_disabled = true; |
|
|
std::optional<u32> enabled_version; |
|
|
std::optional<u32> enabled_version; |
|
|
@ -698,7 +723,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs |
|
|
|
|
|
|
|
|
// LayeredFS
|
|
|
// LayeredFS
|
|
|
if (apply_layeredfs) { |
|
|
if (apply_layeredfs) { |
|
|
ApplyLayeredFS(romfs, title_id, type, fs_controller); |
|
|
|
|
|
|
|
|
ApplyLayeredFS(romfs, type); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return romfs; |
|
|
return romfs; |
|
|
@ -1072,15 +1097,22 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const { |
|
|
std::optional<u32> PatchManager::GetGameVersion() const { |
|
|
std::optional<u32> PatchManager::GetGameVersion() const { |
|
|
const auto update_tid = GetUpdateTitleID(title_id); |
|
|
const auto update_tid = GetUpdateTitleID(title_id); |
|
|
if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) { |
|
|
if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) { |
|
|
return content_provider.GetEntryVersion(update_tid); |
|
|
|
|
|
|
|
|
const auto version = content_provider.GetEntryVersion(update_tid); |
|
|
|
|
|
return version || !parent_title_id ? version : content_provider.GetEntryVersion(GetUpdateTitleID(*parent_title_id)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return content_provider.GetEntryVersion(title_id); |
|
|
|
|
|
|
|
|
const auto version = content_provider.GetEntryVersion(title_id); |
|
|
|
|
|
return version || !parent_title_id ? version : content_provider.GetEntryVersion(*parent_title_id); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
PatchManager::Metadata PatchManager::GetControlMetadata() const { |
|
|
PatchManager::Metadata PatchManager::GetControlMetadata() const { |
|
|
const auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control); |
|
|
const auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control); |
|
|
if (base_control_nca == nullptr) { |
|
|
if (base_control_nca == nullptr) { |
|
|
|
|
|
if (parent_title_id) { |
|
|
|
|
|
const auto control_id = content_provider.HasEntry(*parent_title_id, ContentRecordType::Control) ? *parent_title_id : GetUpdateTitleID(*parent_title_id); |
|
|
|
|
|
const PatchManager parent{control_id, fs_controller, content_provider}; |
|
|
|
|
|
return parent.GetControlMetadata(); |
|
|
|
|
|
} |
|
|
return {}; |
|
|
return {}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|