diff --git a/Penumbra/Import/Models/ModelManager.cs b/Penumbra/Import/Models/ModelManager.cs index bae9569f..f099a0e0 100644 --- a/Penumbra/Import/Models/ModelManager.cs +++ b/Penumbra/Import/Models/ModelManager.cs @@ -37,7 +37,12 @@ public sealed class ModelManager(IFramework framework, ActiveCollections collect public Task ImportGltf(string inputPath) { var action = new ImportGltfAction(inputPath); - return Enqueue(action).ContinueWith(_ => action.Out); + return Enqueue(action).ContinueWith(task => + { + if (task.IsFaulted && task.Exception != null) + throw task.Exception; + return action.Out; + }); } /// Try to find the .sklb paths for a .mdl file. /// .mdl file to look up the skeletons for. diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.MdlTab.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.MdlTab.cs index f9e19599..d52bf3f1 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.MdlTab.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.MdlTab.cs @@ -18,9 +18,9 @@ public partial class ModEditWindow public List? GamePaths { get; private set; } public int GamePathIndex; - private bool _dirty; - public bool PendingIo { get; private set; } - public string? IoException { get; private set; } + private bool _dirty; + public bool PendingIo { get; private set; } + public List IoExceptions { get; private set; } = []; public MdlTab(ModEditWindow edit, byte[] bytes, string path) { @@ -85,7 +85,7 @@ public partial class ModEditWindow task.ContinueWith(t => { - IoException = t.Exception?.ToString(); + RecordIoExceptions(t.Exception); GamePaths = t.Result; PendingIo = false; }); @@ -120,7 +120,7 @@ public partial class ModEditWindow } catch (Exception exception) { - IoException = exception.ToString(); + RecordIoExceptions(exception); return; } @@ -128,7 +128,7 @@ public partial class ModEditWindow _edit._models.ExportToGltf(Mdl, skeletons, outputPath) .ContinueWith(task => { - IoException = task.Exception?.ToString(); + RecordIoExceptions(task.Exception); PendingIo = false; }); } @@ -141,7 +141,7 @@ public partial class ModEditWindow _edit._models.ImportGltf(inputPath) .ContinueWith(task => { - IoException = task.Exception?.ToString(); + RecordIoExceptions(task.Exception); if (task is { IsCompletedSuccessfully: true, Result: not null }) { Initialize(task.Result); @@ -151,6 +151,15 @@ public partial class ModEditWindow }); } + private void RecordIoExceptions(Exception? exception) + { + IoExceptions = exception switch { + null => [], + AggregateException ae => ae.Flatten().InnerExceptions.ToList(), + Exception other => [other], + }; + } + /// Read a .sklb from the active collection or game. /// Game path to the .sklb to load. private SklbFile ReadSklb(string sklbPath) diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs index 4f9303f8..28f41936 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs @@ -7,6 +7,7 @@ using Penumbra.GameData; using Penumbra.GameData.Files; using Penumbra.Import.Models; using Penumbra.String.Classes; +using Penumbra.UI.Classes; namespace Penumbra.UI.AdvancedWindow; @@ -61,8 +62,7 @@ public partial class ModEditWindow ImGui.SameLine(); DrawExport(tab, childSize, disabled); - if (tab.IoException != null) - ImGuiUtil.TextWrapped(tab.IoException); + DrawIoExceptions(tab); } private void DrawImport(MdlTab tab, Vector2 size, bool _1) @@ -99,10 +99,10 @@ public partial class ModEditWindow if (tab.GamePaths == null) { - if (tab.IoException == null) + if (tab.IoExceptions.Count == 0) ImGui.TextUnformatted("Resolving model game paths."); else - ImGuiUtil.TextWrapped(tab.IoException); + ImGui.TextUnformatted("Failed to resolve model game paths."); return; } @@ -126,6 +126,30 @@ public partial class ModEditWindow false ); } + + private void DrawIoExceptions(MdlTab tab) + { + if (tab.IoExceptions.Count == 0) + return; + + var size = new Vector2(ImGui.GetContentRegionAvail().X, 0); + using var frame = ImRaii.FramedGroup("Exceptions", size, headerPreIcon: FontAwesomeIcon.TimesCircle, borderColor: Colors.RegexWarningBorder); + + var spaceAvail = ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X - 100; + foreach (var exception in tab.IoExceptions) + { + var message = $"{exception.GetType().Name}: {exception.Message} {exception.Message}"; + var textSize = ImGui.CalcTextSize(message).X; + if (textSize > spaceAvail) + message = message.Substring(0, (int)Math.Floor(message.Length * (spaceAvail / textSize))) + "..."; + + using (var exceptionNode = ImRaii.TreeNode(message)) + { + if (exceptionNode) + ImGuiUtil.TextWrapped(exception.ToString()); + } + } + } private void DrawGamePathCombo(MdlTab tab) {