From 1c3bade6982f689eb47e15f2292901beb8cebf7c Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Wed, 28 Nov 2018 14:01:09 -0500
Subject: [PATCH] patch_manager: Obey disabled add-ons list when patching game

---
 src/core/file_sys/patch_manager.cpp | 56 +++++++++++++++++++++++------
 src/core/file_sys/patch_manager.h   |  5 +++
 2 files changed, 50 insertions(+), 11 deletions(-)

diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 6b14e08bef..ecdc21c87b 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -56,6 +56,10 @@ PatchManager::PatchManager(u64 title_id) : title_id(title_id) {}
 
 PatchManager::~PatchManager() = default;
 
+u64 PatchManager::GetTitleID() const {
+    return title_id;
+}
+
 VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
     LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id);
 
@@ -73,11 +77,15 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
 
     const auto installed = Service::FileSystem::GetUnionContents();
 
+    const auto& disabled = Settings::values.disabled_addons[title_id];
+    const auto update_disabled =
+        std::find(disabled.begin(), disabled.end(), "Update") != disabled.end();
+
     // Game Updates
     const auto update_tid = GetUpdateTitleID(title_id);
     const auto update = installed.GetEntry(update_tid, ContentRecordType::Program);
 
-    if (update != nullptr && update->GetExeFS() != nullptr &&
+    if (!update_disabled && update != nullptr && update->GetExeFS() != nullptr &&
         update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
         LOG_INFO(Loader, "    ExeFS: Update ({}) applied successfully",
                  FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
@@ -95,6 +103,9 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
         std::vector<VirtualDir> layers;
         layers.reserve(patch_dirs.size() + 1);
         for (const auto& subdir : patch_dirs) {
+            if (std::find(disabled.begin(), disabled.end(), subdir->GetName()) != disabled.end())
+                continue;
+
             auto exefs_dir = subdir->GetSubdirectory("exefs");
             if (exefs_dir != nullptr)
                 layers.push_back(std::move(exefs_dir));
@@ -111,11 +122,16 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
     return exefs;
 }
 
-static std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
-                                               const std::string& build_id) {
+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];
+
     std::vector<VirtualFile> out;
     out.reserve(patch_dirs.size());
     for (const auto& subdir : patch_dirs) {
+        if (std::find(disabled.begin(), disabled.end(), subdir->GetName()) != disabled.end())
+            continue;
+
         auto exefs_dir = subdir->GetSubdirectory("exefs");
         if (exefs_dir != nullptr) {
             for (const auto& file : exefs_dir->GetFiles()) {
@@ -228,6 +244,7 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
         return;
     }
 
+    const auto& disabled = Settings::values.disabled_addons[title_id];
     auto patch_dirs = load_dir->GetSubdirectories();
     std::sort(patch_dirs.begin(), patch_dirs.end(),
               [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
@@ -237,6 +254,9 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
     layers.reserve(patch_dirs.size() + 1);
     layers_ext.reserve(patch_dirs.size() + 1);
     for (const auto& subdir : patch_dirs) {
+        if (std::find(disabled.begin(), disabled.end(), subdir->GetName()) != disabled.end())
+            continue;
+
         auto romfs_dir = subdir->GetSubdirectory("romfs");
         if (romfs_dir != nullptr)
             layers.push_back(std::move(romfs_dir));
@@ -282,7 +302,12 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
     // Game Updates
     const auto update_tid = GetUpdateTitleID(title_id);
     const auto update = installed.GetEntryRaw(update_tid, type);
-    if (update != nullptr) {
+
+    const auto& disabled = Settings::values.disabled_addons[title_id];
+    const auto update_disabled =
+        std::find(disabled.begin(), disabled.end(), "Update") != disabled.end();
+
+    if (!update_disabled && update != nullptr) {
         const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset);
         if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
             new_nca->GetRomFS() != nullptr) {
@@ -290,7 +315,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
                      FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
             romfs = new_nca->GetRomFS();
         }
-    } else if (update_raw != nullptr) {
+    } else if (!update_disabled && update_raw != nullptr) {
         const auto new_nca = std::make_shared<NCA>(update_raw, romfs, ivfc_offset);
         if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
             new_nca->GetRomFS() != nullptr) {
@@ -320,25 +345,30 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
     VirtualFile update_raw) const {
     std::map<std::string, std::string, std::less<>> out;
     const auto installed = Service::FileSystem::GetUnionContents();
+    const auto& disabled = Settings::values.disabled_addons[title_id];
 
     // Game Updates
     const auto update_tid = GetUpdateTitleID(title_id);
     PatchManager update{update_tid};
     auto [nacp, discard_icon_file] = update.GetControlMetadata();
 
+    const auto update_disabled =
+        std::find(disabled.begin(), disabled.end(), "Update") != disabled.end();
+    const auto update_label = update_disabled ? "[D] Update" : "Update";
+
     if (nacp != nullptr) {
-        out.insert_or_assign("Update", nacp->GetVersionString());
+        out.insert_or_assign(update_label, nacp->GetVersionString());
     } else {
         if (installed.HasEntry(update_tid, ContentRecordType::Program)) {
             const auto meta_ver = installed.GetEntryVersion(update_tid);
             if (meta_ver.value_or(0) == 0) {
-                out.insert_or_assign("Update", "");
+                out.insert_or_assign(update_label, "");
             } else {
                 out.insert_or_assign(
-                    "Update", FormatTitleVersion(*meta_ver, TitleVersionFormat::ThreeElements));
+                    update_label, FormatTitleVersion(*meta_ver, TitleVersionFormat::ThreeElements));
             }
         } else if (update_raw != nullptr) {
-            out.insert_or_assign("Update", "PACKED");
+            out.insert_or_assign(update_label, "PACKED");
         }
     }
 
@@ -378,7 +408,9 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
             if (types.empty())
                 continue;
 
-            out.insert_or_assign(mod->GetName(), types);
+            const auto mod_disabled =
+                std::find(disabled.begin(), disabled.end(), mod->GetName()) != disabled.end();
+            out.insert_or_assign(mod_disabled ? "[D] " + mod->GetName() : mod->GetName(), types);
         }
     }
 
@@ -401,7 +433,9 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
 
         list += fmt::format("{}", dlc_match.back().title_id & 0x7FF);
 
-        out.insert_or_assign("DLC", std::move(list));
+        const auto dlc_disabled =
+            std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end();
+        out.insert_or_assign(dlc_disabled ? "[D] DLC" : "DLC", std::move(list));
     }
 
     return out;
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index 7d168837f8..b8a1652fd5 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -30,6 +30,8 @@ public:
     explicit PatchManager(u64 title_id);
     ~PatchManager();
 
+    u64 GetTitleID() const;
+
     // Currently tracked ExeFS patches:
     // - Game Updates
     VirtualDir PatchExeFS(VirtualDir exefs) const;
@@ -63,6 +65,9 @@ public:
     std::pair<std::unique_ptr<NACP>, VirtualFile> ParseControlNCA(const NCA& nca) const;
 
 private:
+    std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
+                                            const std::string& build_id) const;
+
     u64 title_id;
 };