From 560ed5eebda0c8e54c3c029a9bf54000e52a2933 Mon Sep 17 00:00:00 2001
From: Logan Stromberg <loganstromberg@gmail.com>
Date: Mon, 29 Nov 2021 10:21:27 -0800
Subject: [PATCH] Don't blow up everything if a DLC file is moved or renamed.
 (#2867)

* Don't blow up everything if a DLC file is missing

* change comment

* More correctly setting the "enabled" check box on dlc dialog for the add-on NSP based on the enabled state of all NCAs in the package.

* Update Ryujinx.HLE/HOS/ApplicationLoader.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

Co-authored-by: Logan Stromberg <lostromb@microsoft.com>
Co-authored-by: Ac_K <Acoustik666@gmail.com>
---
 Ryujinx.HLE/HOS/ApplicationLoader.cs |  9 ++++++-
 Ryujinx/Ui/Windows/DlcWindow.cs      | 36 ++++++++++++++++++----------
 2 files changed, 32 insertions(+), 13 deletions(-)

diff --git a/Ryujinx.HLE/HOS/ApplicationLoader.cs b/Ryujinx.HLE/HOS/ApplicationLoader.cs
index f794d199e5..767496d213 100644
--- a/Ryujinx.HLE/HOS/ApplicationLoader.cs
+++ b/Ryujinx.HLE/HOS/ApplicationLoader.cs
@@ -335,7 +335,14 @@ namespace Ryujinx.HLE.HOS
                 {
                     foreach (DlcNca dlcNca in dlcContainer.DlcNcaList)
                     {
-                        _device.Configuration.ContentManager.AddAocItem(dlcNca.TitleId, dlcContainer.Path, dlcNca.Path, dlcNca.Enabled);
+                        if (File.Exists(dlcContainer.Path))
+                        {
+                            _device.Configuration.ContentManager.AddAocItem(dlcNca.TitleId, dlcContainer.Path, dlcNca.Path, dlcNca.Enabled);
+                        }
+                        else
+                        {
+                            Logger.Warning?.Print(LogClass.Application, $"Cannot find AddOnContent file {dlcContainer.Path}. It may have been moved or renamed.");
+                        }
                     }
                 }
             }
diff --git a/Ryujinx/Ui/Windows/DlcWindow.cs b/Ryujinx/Ui/Windows/DlcWindow.cs
index ee9bea6bef..bda4d167ea 100644
--- a/Ryujinx/Ui/Windows/DlcWindow.cs
+++ b/Ryujinx/Ui/Windows/DlcWindow.cs
@@ -75,22 +75,34 @@ namespace Ryujinx.Ui.Windows
 
             foreach (DlcContainer dlcContainer in _dlcContainerList)
             {
-                TreeIter parentIter = ((TreeStore)_dlcTreeView.Model).AppendValues(false, "", dlcContainer.Path);
-
-                using FileStream containerFile = File.OpenRead(dlcContainer.Path);
-                PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage());
-                _virtualFileSystem.ImportTickets(pfs);
-
-                foreach (DlcNca dlcNca in dlcContainer.DlcNcaList)
+                if (File.Exists(dlcContainer.Path))
                 {
-                    pfs.OpenFile(out IFile ncaFile, dlcNca.Path.ToU8Span(), OpenMode.Read).ThrowIfFailure();
-                    Nca nca = TryCreateNca(ncaFile.AsStorage(), dlcContainer.Path);
-                    
-                    if (nca != null)
+                    // The parent tree item has its own "enabled" check box, but it's the actual
+                    // nca entries that store the enabled / disabled state. A bit of a UI inconsistency.
+                    // Maybe a tri-state check box would be better, but for now we check the parent
+                    // "enabled" box if all child NCAs are enabled. Usually fine since each nsp has only one nca.
+                    bool areAllContentPacksEnabled = dlcContainer.DlcNcaList.TrueForAll((nca) => nca.Enabled);
+                    TreeIter parentIter = ((TreeStore)_dlcTreeView.Model).AppendValues(areAllContentPacksEnabled, "", dlcContainer.Path);
+                    using FileStream containerFile = File.OpenRead(dlcContainer.Path);
+                    PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage());
+                    _virtualFileSystem.ImportTickets(pfs);
+
+                    foreach (DlcNca dlcNca in dlcContainer.DlcNcaList)
                     {
-                        ((TreeStore)_dlcTreeView.Model).AppendValues(parentIter, dlcNca.Enabled, nca.Header.TitleId.ToString("X16"), dlcNca.Path);
+                        pfs.OpenFile(out IFile ncaFile, dlcNca.Path.ToU8Span(), OpenMode.Read).ThrowIfFailure();
+                        Nca nca = TryCreateNca(ncaFile.AsStorage(), dlcContainer.Path);
+
+                        if (nca != null)
+                        {
+                            ((TreeStore)_dlcTreeView.Model).AppendValues(parentIter, dlcNca.Enabled, nca.Header.TitleId.ToString("X16"), dlcNca.Path);
+                        }
                     }
                 }
+                else
+                {
+                    // DLC file moved or renamed. Allow the user to remove it without crashing the whole dialog.
+                    TreeIter parentIter = ((TreeStore)_dlcTreeView.Model).AppendValues(false, "", $"(MISSING) {dlcContainer.Path}");
+                }
             }
         }