From efd66fd3f87b5b5a452cdc47b304a2a35eaae99f Mon Sep 17 00:00:00 2001 From: goaaats Date: Wed, 26 Nov 2025 01:43:01 +0100 Subject: [PATCH 1/4] Handle errors in Window draw events by displaying an error message --- Dalamud/Interface/Windowing/Window.cs | 71 ++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/Dalamud/Interface/Windowing/Window.cs b/Dalamud/Interface/Windowing/Window.cs index d4f0070db..44ff62199 100644 --- a/Dalamud/Interface/Windowing/Window.cs +++ b/Dalamud/Interface/Windowing/Window.cs @@ -55,6 +55,9 @@ public abstract class Window private Vector2 fadeOutSize = Vector2.Zero; private Vector2 fadeOutOrigin = Vector2.Zero; + private bool hasError = false; + private Exception? lastError; + /// /// Initializes a new instance of the class. /// @@ -458,14 +461,24 @@ public abstract class Window this.presetDirty = true; } - // Draw the actual window contents - try + if (this.hasError) { - this.Draw(); + this.DrawErrorMessage(); } - catch (Exception ex) + else { - Log.Error(ex, "Error during Draw(): {WindowName}", this.WindowName); + // Draw the actual window contents + try + { + this.Draw(); + } + catch (Exception ex) + { + Log.Error(ex, "Error during Draw(): {WindowName}", this.WindowName); + + this.hasError = true; + this.lastError = ex; + } } } @@ -793,7 +806,7 @@ public abstract class Window hovered = true; // We can't use ImGui native functions here, because they don't work with clickthrough - if ((global::Windows.Win32.PInvoke.GetKeyState((int)VirtualKey.LBUTTON) & 0x8000) != 0) + if ((Windows.Win32.PInvoke.GetKeyState((int)VirtualKey.LBUTTON) & 0x8000) != 0) { held = true; pressed = true; @@ -871,6 +884,52 @@ public abstract class Window ImGui.End(); } + private void DrawErrorMessage() + { + // TODO: Once window systems are services, offer to reload the plugin + ImGui.TextColoredWrapped(ImGuiColors.DalamudRed,Loc.Localize("WindowSystemErrorOccurred", "An error occurred while rendering this window. Please contact the developer for details.")); + + ImGuiHelpers.ScaledDummy(5); + + if (ImGui.Button(Loc.Localize("WindowSystemErrorRecoverButton", "Attempt to retry"))) + { + this.hasError = false; + this.lastError = null; + } + + ImGui.SameLine(); + + if (ImGui.Button(Loc.Localize("WindowSystemErrorClose", "Close Window"))) + { + this.IsOpen = false; + this.hasError = false; + this.lastError = null; + } + + ImGuiHelpers.ScaledDummy(10); + + if (this.lastError != null) + { + using var child = ImRaii.Child("##ErrorDetails", new Vector2(0, 200 * ImGuiHelpers.GlobalScale), true); + using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudGrey)) + { + ImGui.TextWrapped(Loc.Localize("WindowSystemErrorDetails", "Error Details:")); + ImGui.Separator(); + ImGui.TextWrapped(this.lastError.ToString()); + } + + var childWindowSize = ImGui.GetWindowSize(); + var copyText = Loc.Localize("WindowSystemErrorCopy", "Copy"); + var buttonWidth = ImGuiComponents.GetIconButtonWithTextWidth(FontAwesomeIcon.Copy, copyText); + ImGui.SetCursorPos(new Vector2(childWindowSize.X - buttonWidth - ImGui.GetStyle().FramePadding.X, + ImGui.GetStyle().FramePadding.Y)); + if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Copy, copyText)) + { + ImGui.SetClipboardText(this.lastError.ToString()); + } + } + } + /// /// Structure detailing the size constraints of a window. /// From 9e5195492eb34171b6751c017ee67557ec181a1d Mon Sep 17 00:00:00 2001 From: goaaats Date: Wed, 26 Nov 2025 21:07:49 +0100 Subject: [PATCH 2/4] Get active track from env var, instead of git branch --- Dalamud/Interface/Internal/DalamudInterface.cs | 2 +- .../Internal/Windows/BranchSwitcherWindow.cs | 10 ++++++---- Dalamud/Utility/Util.cs | 16 +++++++++++++--- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs index f2ffc7a4c..202334580 100644 --- a/Dalamud/Interface/Internal/DalamudInterface.cs +++ b/Dalamud/Interface/Internal/DalamudInterface.cs @@ -1060,7 +1060,7 @@ internal class DalamudInterface : IInternalDisposableService { ImGui.PushFont(InterfaceManager.MonoFont); - ImGui.BeginMenu(Util.GetBranch() ?? "???", false); + ImGui.BeginMenu($"{Util.GetActiveTrack() ?? "???"} on {Util.GetGitBranch() ?? "???"}", false); ImGui.BeginMenu($"{Util.GetScmVersion()}", false); ImGui.BeginMenu(this.FrameCount.ToString("000000"), false); ImGui.BeginMenu(ImGui.GetIO().Framerate.ToString("000"), false); diff --git a/Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs b/Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs index da6217aca..51ff3bdcd 100644 --- a/Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs +++ b/Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs @@ -46,10 +46,12 @@ public class BranchSwitcherWindow : Window this.branches = await client.GetFromJsonAsync>(BranchInfoUrl); Debug.Assert(this.branches != null, "this.branches != null"); - var branch = Util.GetBranch(); - this.selectedBranchIndex = this.branches!.Any(x => x.Value.Track == branch) ? - this.branches.TakeWhile(x => x.Value.Track != branch).Count() - : 0; + var trackName = Util.GetActiveTrack(); + this.selectedBranchIndex = this.branches.IndexOf(x => x.Value.Track != trackName); + if (this.selectedBranchIndex == -1) + { + this.selectedBranchIndex = 0; + } }); base.OnOpen(); diff --git a/Dalamud/Utility/Util.cs b/Dalamud/Utility/Util.cs index 2a3733303..19610ef64 100644 --- a/Dalamud/Utility/Util.cs +++ b/Dalamud/Utility/Util.cs @@ -140,10 +140,10 @@ public static partial class Util } /// - /// Gets the Dalamud branch name this version of Dalamud was built from, or null, if this is a Debug build. + /// Gets the Git branch name this version of Dalamud was built from, or null, if this is a Debug build. /// /// The branch name. - public static string? GetBranch() + public static string? GetGitBranch() { if (branchInternal != null) return branchInternal; @@ -155,7 +155,17 @@ public static partial class Util if (gitBranch == null) return null; - return branchInternal = gitBranch == "master" ? "release" : gitBranch; + return branchInternal = gitBranch; + } + + /// + /// Gets the active Dalamud track, if this instance was launched through XIVLauncher and used a version + /// downloaded from webservices. + /// + /// The name of the track, or null. + internal static string? GetActiveTrack() + { + return Environment.GetEnvironmentVariable("DALAMUD_BRANCH"); } /// From c6b173dd63b89f13c1621a08557261bf0ebcae9a Mon Sep 17 00:00:00 2001 From: goaaats Date: Wed, 26 Nov 2025 21:22:59 +0100 Subject: [PATCH 3/4] build: 13.0.0.11 --- Dalamud/Dalamud.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index b5062438a..ce140b8c9 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -6,7 +6,7 @@ XIV Launcher addon framework - 13.0.0.10 + 13.0.0.11 $(DalamudVersion) $(DalamudVersion) $(DalamudVersion) From c136934aa838fd1376e874117f39df0ce6702a61 Mon Sep 17 00:00:00 2001 From: goaaats Date: Wed, 26 Nov 2025 21:46:07 +0100 Subject: [PATCH 4/4] Always pass a key, even for release Fixes an issue wherein the XL commandline parser wouldn't like the empty argument and error out --- Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs b/Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs index 51ff3bdcd..4e95b718e 100644 --- a/Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs +++ b/Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs @@ -105,7 +105,7 @@ public class BranchSwitcherWindow : Window }; ps.ArgumentList.Add($"--dalamud-beta-kind={config.DalamudBetaKind}"); - ps.ArgumentList.Add($"--dalamud-beta-key={config.DalamudBetaKey}"); + ps.ArgumentList.Add($"--dalamud-beta-key={(config.DalamudBetaKey.IsNullOrEmpty() ? "invalid" : config.DalamudBetaKey)}"); Process.Start(ps); Environment.Exit(0);